@@ -9,6 +9,57 @@ import { difference, isEqual } from 'lodash-es'
99
1010import { allVersions } from '#src/versions/lib/all-versions.js'
1111import getApplicableVersions from '#src/versions/lib/get-applicable-versions.js'
12+ import type { MarkdownFrontmatter } from '@/types'
13+
14+ // Type definitions - extending existing type to add missing fields and make most fields optional
15+ type FrontmatterData = Partial < MarkdownFrontmatter > & {
16+ autogenerated ?: string
17+ [ key : string ] : any
18+ }
19+
20+ type SourceContentItem = {
21+ data : FrontmatterData
22+ content : string
23+ }
24+
25+ type SourceContent = {
26+ [ key : string ] : SourceContentItem
27+ }
28+
29+ type IndexOrder = {
30+ [ key : string ] : {
31+ startsWith ?: string [ ]
32+ }
33+ }
34+
35+ type UpdateContentDirectoryOptions = {
36+ targetDirectory : string
37+ sourceContent : SourceContent
38+ frontmatter : FrontmatterData
39+ indexOrder ?: IndexOrder
40+ }
41+
42+ type UpdateDirectoryOptions = {
43+ rootDirectoryOnly ?: boolean
44+ shortTitle ?: boolean
45+ indexOrder ?: IndexOrder
46+ }
47+
48+ type ChildUpdates = {
49+ itemsToAdd : string [ ]
50+ itemsToRemove : string [ ]
51+ }
52+
53+ type DirectoryInfo = {
54+ directoryContents : string [ ]
55+ directoryFiles : string [ ]
56+ childDirectories : string [ ]
57+ }
58+
59+ type ChildrenComparison = {
60+ childrenOnDisk : string [ ]
61+ indexChildren : string [ ]
62+ }
1263
1364const ROOT_INDEX_FILE = 'content/index.md'
1465export const MARKDOWN_COMMENT = '\n<!-- Content after this section is automatically generated -->\n'
@@ -20,15 +71,19 @@ export async function updateContentDirectory({
2071 sourceContent,
2172 frontmatter,
2273 indexOrder,
23- } ) {
74+ } : UpdateContentDirectoryOptions ) : Promise < void > {
2475 const sourceFiles = Object . keys ( sourceContent )
2576 await createDirectory ( targetDirectory )
2677 await removeMarkdownFiles ( targetDirectory , sourceFiles , frontmatter . autogenerated )
2778 await updateMarkdownFiles ( targetDirectory , sourceContent , frontmatter , indexOrder )
2879}
2980
3081// Remove markdown files that are no longer in the source data
31- async function removeMarkdownFiles ( targetDirectory , sourceFiles , autogeneratedType ) {
82+ async function removeMarkdownFiles (
83+ targetDirectory : string ,
84+ sourceFiles : string [ ] ,
85+ autogeneratedType : string | undefined ,
86+ ) : Promise < void > {
3287 // Copy the autogenerated Markdown files to the target directory
3388 const autogeneratedFiles = await getAutogeneratedFiles ( targetDirectory , autogeneratedType )
3489 // If the first array contains items that the second array does not,
@@ -42,29 +97,37 @@ async function removeMarkdownFiles(targetDirectory, sourceFiles, autogeneratedTy
4297
4398// Gets a list of all files under targetDirectory that have the
4499// `autogenerated` frontmatter set to `autogeneratedType`.
45- async function getAutogeneratedFiles ( targetDirectory , autogeneratedType ) {
100+ async function getAutogeneratedFiles (
101+ targetDirectory : string ,
102+ autogeneratedType : string | undefined ,
103+ ) : Promise < string [ ] > {
46104 const files = walk ( targetDirectory , {
47105 includeBasePath : true ,
48- childDirectories : false ,
106+ directories : false ,
49107 globs : [ '**/*.md' ] ,
50108 ignore : [ '**/README.md' , '**/index.md' ] ,
51109 } )
52110 return (
53111 await Promise . all (
54- files . map ( async ( file ) => {
112+ files . map ( async ( file : string ) => {
55113 const { data } = matter ( await readFile ( file , 'utf-8' ) )
56114 if ( data . autogenerated === autogeneratedType ) {
57115 return file
58116 }
59117 } ) ,
60118 )
61- ) . filter ( Boolean )
119+ ) . filter ( Boolean ) as string [ ]
62120}
63121
64122// The `sourceContent` object contains the new content and target file
65123// path for the Markdown files. Ex:
66124// { <targetFile>: { data: <frontmatter>, content: <markdownContent> } }
67- async function updateMarkdownFiles ( targetDirectory , sourceContent , frontmatter , indexOrder = { } ) {
125+ async function updateMarkdownFiles (
126+ targetDirectory : string ,
127+ sourceContent : SourceContent ,
128+ frontmatter : FrontmatterData ,
129+ indexOrder : IndexOrder = { } ,
130+ ) : Promise < void > {
68131 for ( const [ file , newContent ] of Object . entries ( sourceContent ) ) {
69132 await updateMarkdownFile ( file , newContent . data , newContent . content )
70133 }
@@ -82,11 +145,11 @@ async function updateMarkdownFiles(targetDirectory, sourceContent, frontmatter,
82145// edit the modifiable content of the file. If the Markdown file doesn't
83146// exists, we create a new Markdown file.
84147async function updateMarkdownFile (
85- file ,
86- sourceData ,
87- sourceContent ,
88- commentDelimiter = MARKDOWN_COMMENT ,
89- ) {
148+ file : string ,
149+ sourceData : FrontmatterData ,
150+ sourceContent : string ,
151+ commentDelimiter : string = MARKDOWN_COMMENT ,
152+ ) : Promise < void > {
90153 if ( existsSync ( file ) ) {
91154 // update only the versions property of the file, assuming
92155 // the other properties have already been added and edited
@@ -132,10 +195,10 @@ async function updateMarkdownFile(
132195// ensure that the Markdown files have been updated and any files
133196// that need to be deleted have been removed.
134197async function updateDirectory (
135- directory ,
136- frontmatter ,
137- { rootDirectoryOnly = false , shortTitle = false , indexOrder = { } } = { } ,
138- ) {
198+ directory : string ,
199+ frontmatter : FrontmatterData ,
200+ { rootDirectoryOnly = false , shortTitle = false , indexOrder = { } } : UpdateDirectoryOptions = { } ,
201+ ) : Promise < void > {
139202 const initialDirectoryListing = await getDirectoryInfo ( directory )
140203 // If there are no children on disk, remove the directory
141204 if ( initialDirectoryListing . directoryContents . length === 0 && ! rootDirectoryOnly ) {
@@ -162,7 +225,7 @@ async function updateDirectory(
162225 const { childrenOnDisk, indexChildren } = getChildrenToCompare (
163226 indexFile ,
164227 directoryContents ,
165- data . children ,
228+ data . children || [ ] ,
166229 )
167230
168231 const itemsToAdd = difference ( childrenOnDisk , indexChildren )
@@ -199,12 +262,16 @@ async function updateDirectory(
199262// Children properties include a leading slash except when the
200263// index.md file is the root index.md file. We also want to
201264// remove the file extension from the files on disk.
202- function getChildrenToCompare ( indexFile , directoryContents , fmChildren ) {
265+ function getChildrenToCompare (
266+ indexFile : string ,
267+ directoryContents : string [ ] ,
268+ fmChildren : string [ ] | undefined ,
269+ ) : ChildrenComparison {
203270 if ( ! fmChildren ) {
204271 throw new Error ( `No children property found in ${ indexFile } ` )
205272 }
206273
207- const isEarlyAccess = ( item ) => isRootIndexFile ( indexFile ) && item === 'early-access'
274+ const isEarlyAccess = ( item : string ) => isRootIndexFile ( indexFile ) && item === 'early-access'
208275
209276 // Get the list of children from the directory contents
210277 const childrenOnDisk = directoryContents
@@ -233,18 +300,24 @@ function getChildrenToCompare(indexFile, directoryContents, fmChildren) {
233300//
234301// 3. If the index file is not autogenerated, we leave the ordering
235302// as is and append new children to the end.
236- function updateIndexChildren ( data , childUpdates , indexFile , indexOrder , rootIndex = false ) {
303+ function updateIndexChildren (
304+ data : FrontmatterData ,
305+ childUpdates : ChildUpdates ,
306+ indexFile : string ,
307+ indexOrder : IndexOrder ,
308+ rootIndex : boolean = false ,
309+ ) : FrontmatterData {
237310 const { itemsToAdd, itemsToRemove } = childUpdates
238311 const childPrefix = rootIndex ? '' : '/'
239312
240313 // Get a new list of children with added and removed items
241- const children = [ ...data . children ]
314+ const children = [ ...( data . children || [ ] ) ]
242315 // remove the '/' prefix used in index.md children
243316 . map ( ( item ) => item . replace ( childPrefix , '' ) )
244317 . filter ( ( item ) => ! itemsToRemove . includes ( item ) )
245318 children . push ( ...itemsToAdd )
246319
247- const orderedIndexChildren = [ ]
320+ const orderedIndexChildren : string [ ] = [ ]
248321
249322 // Only used for tests. During testing, the content directory is
250323 // in a temp directory so the paths are not relative to
@@ -280,7 +353,11 @@ function updateIndexChildren(data, childUpdates, indexFile, indexOrder, rootInde
280353
281354// Gets the contents of the index.md file from disk if it exits or
282355// creates a new index.md file with the default frontmatter.
283- async function getIndexFileContents ( indexFile , frontmatter , shortTitle = false ) {
356+ async function getIndexFileContents (
357+ indexFile : string ,
358+ frontmatter : FrontmatterData ,
359+ shortTitle : boolean = false ,
360+ ) : Promise < { data : FrontmatterData ; content : string } > {
284361 const directory = path . dirname ( indexFile )
285362 const indexFileContent = {
286363 data : {
@@ -300,8 +377,11 @@ async function getIndexFileContents(indexFile, frontmatter, shortTitle = false)
300377// Builds the index.md versions frontmatter by consolidating
301378// the versions from each Markdown file in the directory + the
302379// index.md files in any subdirectories of directory.
303- async function getIndexFileVersions ( directory , files ) {
304- const versions = new Set ( )
380+ async function getIndexFileVersions (
381+ directory : string ,
382+ files : string [ ] ,
383+ ) : Promise < { [ key : string ] : string } > {
384+ const versions = new Set < string > ( )
305385 await Promise . all (
306386 files . map ( async ( file ) => {
307387 const filepath = path . join ( directory , file )
@@ -319,7 +399,7 @@ async function getIndexFileVersions(directory, files) {
319399 throw new Error ( `Frontmatter in ${ filepath } does not contain versions.` )
320400 }
321401 const fmVersions = getApplicableVersions ( data . versions )
322- fmVersions . forEach ( ( version ) => versions . add ( version ) )
402+ fmVersions . forEach ( ( version : string ) => versions . add ( version ) )
323403 } ) ,
324404 )
325405 const versionArray = [ ...versions ]
@@ -343,9 +423,11 @@ and returns the frontmatter equivalent JSON:
343423 ghes: '*'
344424}
345425*/
346- export async function convertVersionsToFrontmatter ( versions ) {
347- const frontmatterVersions = { }
348- const numberedReleases = { }
426+ export async function convertVersionsToFrontmatter (
427+ versions : string [ ] ,
428+ ) : Promise < { [ key : string ] : string } > {
429+ const frontmatterVersions : { [ key : string ] : string } = { }
430+ const numberedReleases : { [ key : string ] : { availableReleases : ( string | undefined ) [ ] } } = { }
349431
350432 // Currently, only GHES is numbered. Number releases have to be
351433 // handled differently because they use semantic versioning.
@@ -362,7 +444,9 @@ export async function convertVersionsToFrontmatter(versions) {
362444 // a release is no longer supported.
363445 const i = docsVersion . releases . indexOf ( docsVersion . currentRelease )
364446 if ( ! numberedReleases [ docsVersion . shortName ] ) {
365- const availableReleases = Array ( docsVersion . releases . length ) . fill ( undefined )
447+ const availableReleases : ( string | undefined ) [ ] = Array ( docsVersion . releases . length ) . fill (
448+ undefined ,
449+ )
366450 availableReleases [ i ] = docsVersion . currentRelease
367451 numberedReleases [ docsVersion . shortName ] = {
368452 availableReleases,
@@ -388,7 +472,7 @@ export async function convertVersionsToFrontmatter(versions) {
388472 . join ( ' || ' )
389473 frontmatterVersions [ key ] = semVer
390474 } else {
391- const semVer = [ ]
475+ const semVer : string [ ] = [ ]
392476 if ( ! availableReleases [ availableReleases . length - 1 ] ) {
393477 const startVersion = availableReleases . filter ( Boolean ) . pop ( )
394478 semVer . push ( `>=${ startVersion } ` )
@@ -402,7 +486,7 @@ export async function convertVersionsToFrontmatter(versions) {
402486 } )
403487 const sortedFrontmatterVersions = Object . keys ( frontmatterVersions )
404488 . sort ( )
405- . reduce ( ( acc , key ) => {
489+ . reduce ( ( acc : { [ key : string ] : string } , key ) => {
406490 acc [ key ] = frontmatterVersions [ key ]
407491 return acc
408492 } , { } )
@@ -412,7 +496,7 @@ export async function convertVersionsToFrontmatter(versions) {
412496// This is uncommon, but we potentially could have the case where an
413497// article was versioned for say 3.2, not for 3.3, and then again
414498// versioned for 3.4. This will result in a custom semantic version range
415- function checkVersionContinuity ( versions ) {
499+ function checkVersionContinuity ( versions : ( string | undefined ) [ ] ) : boolean {
416500 const availableVersions = [ ...versions ]
417501
418502 // values at the beginning or end of the array are not gaps but normal
@@ -427,18 +511,18 @@ function checkVersionContinuity(versions) {
427511}
428512
429513// Returns true if the indexFile is the root index.md file
430- function isRootIndexFile ( indexFile ) {
514+ function isRootIndexFile ( indexFile : string ) : boolean {
431515 return indexFile === ROOT_INDEX_FILE
432516}
433517
434518// Creates a new directory if it doesn't exist
435- async function createDirectory ( targetDirectory ) {
519+ async function createDirectory ( targetDirectory : string ) : Promise < void > {
436520 if ( ! existsSync ( targetDirectory ) ) {
437521 await mkdirp ( targetDirectory )
438522 }
439523}
440524
441- async function getDirectoryInfo ( directory ) {
525+ async function getDirectoryInfo ( directory : string ) : Promise < DirectoryInfo > {
442526 if ( ! existsSync ( directory ) ) {
443527 throw new Error ( `Directory ${ directory } did not exist when attempting to get directory info.` )
444528 }
@@ -454,7 +538,7 @@ async function getDirectoryInfo(directory) {
454538 return { directoryContents, directoryFiles, childDirectories }
455539}
456540
457- function appendVersionComment ( stringifiedContent ) {
541+ function appendVersionComment ( stringifiedContent : string ) : string {
458542 return stringifiedContent . replace (
459543 '\nversions:\n' ,
460544 `\nversions: # DO NOT MANUALLY EDIT. CHANGES WILL BE OVERWRITTEN BY A 🤖\n` ,
0 commit comments