@@ -100,6 +100,85 @@ async function getCollaboratorsFromReadme() {
100100 return returnedArray ;
101101}
102102
103+ async function moveCollaboratorToEmeritus ( peopleToMove ) {
104+ const readmeText = readline . createInterface ( {
105+ input : fs . createReadStream ( new URL ( '../README.md' , import . meta. url ) ) ,
106+ crlfDelay : Infinity ,
107+ } ) ;
108+ let fileContents = '' ;
109+ let inCollaboratorsSection = false ;
110+ let inCollaboratorEmeritusSection = false ;
111+ let collaboratorFirstLine = '' ;
112+ const textToMove = [ ] ;
113+ for await ( const line of readmeText ) {
114+ // If we've been processing collaborator emeriti and we reach the end of
115+ // the list, print out the remaining entries to be moved because they come
116+ // alphabetically after the last item.
117+ if ( inCollaboratorEmeritusSection && line === '' &&
118+ fileContents . endsWith ( '>\n' ) ) {
119+ while ( textToMove . length ) {
120+ fileContents += textToMove . pop ( ) ;
121+ }
122+ }
123+
124+ // If we've found the collaborator heading already, stop processing at the
125+ // next heading.
126+ if ( line . startsWith ( '#' ) ) {
127+ inCollaboratorsSection = false ;
128+ inCollaboratorEmeritusSection = false ;
129+ }
130+
131+ const isCollaborator = inCollaboratorsSection && line . length ;
132+ const isCollaboratorEmeritus = inCollaboratorEmeritusSection && line . length ;
133+
134+ if ( line === '### Collaborators' ) {
135+ inCollaboratorsSection = true ;
136+ }
137+ if ( line === '### Collaborator emeriti' ) {
138+ inCollaboratorEmeritusSection = true ;
139+ }
140+
141+ if ( isCollaborator ) {
142+ if ( line . startsWith ( '* ' ) ) {
143+ collaboratorFirstLine = line ;
144+ } else if ( line . startsWith ( '**' ) ) {
145+ const [ , name , email ] = / ^ \* \* ( [ ^ * ] + ) \* \* & l t ; ( .+ ) & g t ; / . exec ( line ) ;
146+ if ( peopleToMove . some ( ( entry ) => {
147+ return entry . name === name && entry . email === email ;
148+ } ) ) {
149+ textToMove . push ( `${ collaboratorFirstLine } \n${ line } \n` ) ;
150+ } else {
151+ fileContents += `${ collaboratorFirstLine } \n${ line } \n` ;
152+ }
153+ } else {
154+ fileContents += `${ line } \n` ;
155+ }
156+ }
157+
158+ if ( isCollaboratorEmeritus ) {
159+ if ( line . startsWith ( '* ' ) ) {
160+ collaboratorFirstLine = line ;
161+ } else if ( line . startsWith ( '**' ) ) {
162+ const currentLine = `${ collaboratorFirstLine } \n${ line } \n` ;
163+ // If textToMove is empty, this still works because when undefined is
164+ // used in a comparison with <, the result is always false.
165+ while ( textToMove [ 0 ] < currentLine ) {
166+ fileContents += textToMove . shift ( ) ;
167+ }
168+ fileContents += currentLine ;
169+ } else {
170+ fileContents += `${ line } \n` ;
171+ }
172+ }
173+
174+ if ( ! isCollaborator && ! isCollaboratorEmeritus ) {
175+ fileContents += `${ line } \n` ;
176+ }
177+ }
178+
179+ return fileContents ;
180+ }
181+
103182// Get list of current collaborators from README.md.
104183const collaborators = await getCollaboratorsFromReadme ( ) ;
105184
@@ -113,9 +192,13 @@ const inactive = collaborators.filter((collaborator) =>
113192 ! authors . has ( collaborator . mailmap ) &&
114193 ! landers . has ( collaborator . mailmap ) &&
115194 ! approvingReviewers . has ( collaborator . name )
116- ) . map ( ( collaborator ) => collaborator . name ) ;
195+ ) ;
117196
118197if ( inactive . length ) {
119198 console . log ( '\nInactive collaborators:\n' ) ;
120- console . log ( inactive . map ( ( name ) => `* ${ name } ` ) . join ( '\n' ) ) ;
199+ console . log ( inactive . map ( ( entry ) => `* ${ entry . name } ` ) . join ( '\n' ) ) ;
200+ console . log ( '\nGenerating new README.md file...' ) ;
201+ const newReadmeText = await moveCollaboratorToEmeritus ( inactive ) ;
202+ fs . writeFileSync ( new URL ( '../README.md' , import . meta. url ) , newReadmeText ) ;
203+ console . log ( 'Updated README.md generated. Please commit these changes.' ) ;
121204}
0 commit comments