33 * Update DOCUMENT_HASHES in documentation.internal.ts
44 *
55 * Target files:
6- * - ALL .md files (anywhere in the extension directory)
7- * - LICENSE (only non- .md exception, explicitly included )
6+ * - Extension: ALL .md files + LICENSE (anywhere in the extension directory)
7+ * - Monorepo root: ALL * .md files + LICENSE (auto-detected via glob )
88 *
9- * This ensures any new .md file is automatically detected.
9+ * Hash keys (CDN path based):
10+ * - Extension files: extensions/git-id-switcher/{relative_path}
11+ * - Monorepo root files: {filename} (e.g., README.md, CONTRIBUTING.md)
12+ *
13+ * This ensures DOCUMENT_HASHES keys match CDN paths exactly.
1014 *
1115 * Usage: node scripts/update-doc-hashes.mjs
1216 */
1317import { createHash } from 'node:crypto' ;
14- import { readFile , writeFile } from 'node:fs/promises' ;
18+ import { readFile , writeFile , access } from 'node:fs/promises' ;
1519import { glob } from 'glob' ;
1620
1721const HASH_FILE = 'src/documentation.internal.ts' ;
1822
23+ // Extension identifier for CDN path construction
24+ const EXTENSION_CDN_PREFIX = 'extensions/git-id-switcher' ;
25+
26+ // Monorepo root relative path (from extension directory)
27+ const MONOREPO_ROOT = '../..' ;
28+
1929/**
2030 * Compute SHA-256 hash of file content
2131 * @param {string } filePath - Path to file
@@ -26,9 +36,25 @@ async function computeSha256(filePath) {
2636 return createHash ( 'sha256' ) . update ( content ) . digest ( 'hex' ) ;
2737}
2838
39+ /**
40+ * Check if a file exists
41+ * @param {string } filePath - Path to check
42+ * @returns {Promise<boolean> } true if file exists
43+ */
44+ async function fileExists ( filePath ) {
45+ try {
46+ await access ( filePath ) ;
47+ return true ;
48+ } catch {
49+ return false ;
50+ }
51+ }
52+
2953async function main ( ) {
30- // Discover ALL .md files + LICENSE (the only non-.md exception)
31- const allFiles = await glob ( [
54+ // ========================================
55+ // 1. Discover extension files
56+ // ========================================
57+ const extensionFiles = await glob ( [
3258 '**/*.md' , // All .md files anywhere
3359 'LICENSE' , // Only non-.md exception
3460 ] , {
@@ -39,25 +65,68 @@ async function main() {
3965 ] ,
4066 } ) ;
4167
42- if ( allFiles . length === 0 ) {
43- console . error ( 'Error: No files found. Are you running from the correct directory?' ) ;
68+ if ( extensionFiles . length === 0 ) {
69+ console . error ( 'Error: No extension files found. Are you running from the correct directory?' ) ;
4470 process . exit ( 1 ) ;
4571 }
4672
47- // Compute hashes for all discovered files
73+ // ========================================
74+ // 2. Compute hashes for extension files
75+ // ========================================
4876 const hashes = { } ;
49- for ( const file of allFiles . sort ( ) ) {
50- hashes [ file ] = await computeSha256 ( file ) ;
77+
78+ for ( const file of extensionFiles . sort ( ) ) {
79+ // CDN key for extension files: extensions/git-id-switcher/{file}
80+ const cdnKey = `${ EXTENSION_CDN_PREFIX } /${ file } ` ;
81+ hashes [ cdnKey ] = await computeSha256 ( file ) ;
82+ }
83+
84+ console . log ( `Found ${ extensionFiles . length } extension files` ) ;
85+
86+ // ========================================
87+ // 3. Discover monorepo root files
88+ // ========================================
89+ const monorepoFiles = await glob ( [
90+ '*.md' , // All .md files at monorepo root (not recursive)
91+ 'LICENSE' , // LICENSE file
92+ ] , {
93+ cwd : MONOREPO_ROOT ,
94+ } ) ;
95+
96+ console . log ( `Found ${ monorepoFiles . length } monorepo root files` ) ;
97+
98+ // ========================================
99+ // 4. Compute hashes for monorepo root files
100+ // ========================================
101+ for ( const file of monorepoFiles . sort ( ) ) {
102+ const localPath = `${ MONOREPO_ROOT } /${ file } ` ;
103+
104+ // Verify file exists (defensive check)
105+ if ( ! ( await fileExists ( localPath ) ) ) {
106+ console . warn ( `Warning: Monorepo file not found: ${ file } ` ) ;
107+ continue ;
108+ }
109+
110+ // CDN key for monorepo root: just the filename
111+ hashes [ file ] = await computeSha256 ( localPath ) ;
51112 }
52113
53- // Generate DOCUMENT_HASHES entries
114+ // ========================================
115+ // 5. Generate DOCUMENT_HASHES block
116+ // ========================================
117+ const totalFiles = Object . keys ( hashes ) . length ;
118+
119+ // Sort entries by key for consistent diffs
54120 const entries = Object . entries ( hashes )
121+ . sort ( ( [ a ] , [ b ] ) => a . localeCompare ( b ) )
55122 . map ( ( [ path , hash ] ) => ` '${ path } ': '${ hash } ',` )
56123 . join ( '\n' ) ;
57124
58125 const hashBlock = `export const DOCUMENT_HASHES: Record<string, string> = {\n${ entries } \n};` ;
59126
60- // Read and update the file
127+ // ========================================
128+ // 6. Read and update the file
129+ // ========================================
61130 let content ;
62131 try {
63132 content = await readFile ( HASH_FILE , 'utf-8' ) ;
@@ -79,17 +148,38 @@ async function main() {
79148
80149 // Check if there are actual changes
81150 if ( content === originalContent ) {
82- console . log ( `DOCUMENT_HASHES is already up to date (${ Object . keys ( hashes ) . length } files)` ) ;
151+ console . log ( `\nDOCUMENT_HASHES is already up to date (${ totalFiles } files)` ) ;
83152 process . exit ( 0 ) ; // Success - no changes needed
84153 }
85154
86155 await writeFile ( HASH_FILE , content ) ;
87- console . log ( `Regenerated DOCUMENT_HASHES with ${ Object . keys ( hashes ) . length } files` ) ;
156+ console . log ( `\nRegenerated DOCUMENT_HASHES with ${ totalFiles } files` ) ;
88157
89- // List all files for verification
158+ // ========================================
159+ // 7. List all files for verification
160+ // ========================================
90161 console . log ( '\nFiles included:' ) ;
91- for ( const file of Object . keys ( hashes ) . sort ( ) ) {
92- console . log ( ` - ${ file } ` ) ;
162+
163+ // Separate extension and monorepo files for clarity
164+ const extensionKeys = Object . keys ( hashes )
165+ . filter ( k => k . startsWith ( EXTENSION_CDN_PREFIX ) )
166+ . sort ( ) ;
167+ const monorepoKeys = Object . keys ( hashes )
168+ . filter ( k => ! k . startsWith ( EXTENSION_CDN_PREFIX ) )
169+ . sort ( ) ;
170+
171+ if ( extensionKeys . length > 0 ) {
172+ console . log ( '\n [Extension files]' ) ;
173+ for ( const key of extensionKeys ) {
174+ console . log ( ` - ${ key } ` ) ;
175+ }
176+ }
177+
178+ if ( monorepoKeys . length > 0 ) {
179+ console . log ( '\n [Monorepo root files]' ) ;
180+ for ( const key of monorepoKeys ) {
181+ console . log ( ` - ${ key } ` ) ;
182+ }
93183 }
94184}
95185
0 commit comments