1+ #!/usr/bin/env node
2+
3+ import { glob } from 'glob' ;
4+ import { readFile , writeFile , mkdir } from 'fs/promises' ;
5+ import { join , dirname } from 'path' ;
6+ import { fileURLToPath } from 'url' ;
7+ import { exec } from 'child_process' ;
8+ import { promisify } from 'util' ;
9+
10+ const execAsync = promisify ( exec ) ;
11+ const __dirname = dirname ( fileURLToPath ( import . meta. url ) ) ;
12+ const rootDir = join ( __dirname , '..' ) ;
13+ const tempDir = join ( rootDir , 'temp-validation' ) ;
14+
15+ // Find all markdown and mdx files
16+ const files = await glob ( 'src/pages/**/*.{md,mdx}' , { cwd : rootDir } ) ;
17+
18+ let hasErrors = false ;
19+ let totalBlocks = 0 ;
20+ let validatedBlocks = 0 ;
21+
22+ console . log ( '🔍 Validating Twoslash code blocks...\n' ) ;
23+
24+ // Create temp directory
25+ await mkdir ( tempDir , { recursive : true } ) ;
26+
27+ for ( const file of files ) {
28+ const filePath = join ( rootDir , file ) ;
29+ const content = await readFile ( filePath , 'utf-8' ) ;
30+
31+ // Match code blocks with twoslash
32+ const twoslashBlocks = content . match ( / ` ` ` (?: t y p e s c r i p t | t s | j a v a s c r i p t | j s ) \s + t w o s l a s h \n ( [ \s \S ] * ?) \n ` ` ` / g) ;
33+
34+ if ( ! twoslashBlocks ) continue ;
35+
36+ console . log ( `📄 Checking ${ file } ...` ) ;
37+
38+ for ( let i = 0 ; i < twoslashBlocks . length ; i ++ ) {
39+ totalBlocks ++ ;
40+ const block = twoslashBlocks [ i ] ;
41+
42+ // Extract the code content
43+ const codeMatch = block . match ( / ` ` ` (?: t y p e s c r i p t | t s | j a v a s c r i p t | j s ) \s + t w o s l a s h \n ( [ \s \S ] * ?) \n ` ` ` / ) ;
44+ if ( ! codeMatch ) continue ;
45+
46+ const code = codeMatch [ 1 ] ;
47+ const blockNumber = i + 1 ;
48+ const tempFileName = `${ file . replace ( / [ / \\ ] / g, '_' ) } _block_${ blockNumber } .ts` ;
49+ const tempFilePath = join ( tempDir , tempFileName ) ;
50+
51+ try {
52+ // Write code to temp file
53+ await writeFile ( tempFilePath , code ) ;
54+
55+ // Run TypeScript compiler
56+ try {
57+ await execAsync ( `npx tsc --project tsconfig.validation.json --noEmit "${ tempFilePath } "` , {
58+ cwd : rootDir ,
59+ env : { ...process . env , NODE_PATH : join ( rootDir , 'node_modules' ) }
60+ } ) ;
61+
62+ console . log ( `✅ ${ file } (block ${ blockNumber } ): Valid` ) ;
63+ validatedBlocks ++ ;
64+ } catch ( error ) {
65+ console . error ( `❌ ${ file } (block ${ blockNumber } ): TypeScript compilation failed` ) ;
66+ console . error ( ` ${ error . stdout || error . stderr || error . message } ` ) ;
67+ hasErrors = true ;
68+ }
69+ } catch ( error ) {
70+ console . error ( `❌ ${ file } (block ${ blockNumber } ): Validation error` ) ;
71+ console . error ( ` ${ error . message } ` ) ;
72+ hasErrors = true ;
73+ }
74+ }
75+ }
76+
77+ // Cleanup temp directory
78+ try {
79+ await execAsync ( `rm -rf "${ tempDir } "` ) ;
80+ } catch ( error ) {
81+ console . warn ( `Warning: Could not clean up temp directory: ${ error . message } ` ) ;
82+ }
83+
84+ console . log ( `\n📊 Validation Summary:` ) ;
85+ console . log ( ` Total blocks: ${ totalBlocks } ` ) ;
86+ console . log ( ` Valid blocks: ${ validatedBlocks } ` ) ;
87+ console . log ( ` Failed blocks: ${ totalBlocks - validatedBlocks } ` ) ;
88+
89+ if ( hasErrors ) {
90+ console . error ( '\n❌ Twoslash validation failed. Please fix the errors above.' ) ;
91+ process . exit ( 1 ) ;
92+ } else {
93+ console . log ( '\n✅ All Twoslash code blocks are valid!' ) ;
94+ process . exit ( 0 ) ;
95+ }
0 commit comments