@@ -6,29 +6,105 @@ import * as Protocol from '../src/index';
66
77const OUT_DIR = path . resolve ( __dirname , '../json-schema' ) ;
88
9+ // Retry and delay configuration
10+ const RETRY_DELAY_BASE_MS = 100 ; // Base delay in ms, multiplied by retry attempt number
11+ const FS_SYNC_DELAY_MS = 50 ; // Delay after rmSync to ensure filesystem consistency
12+ const MAX_RETRIES = 3 ; // Maximum number of retry attempts
13+
14+ /**
15+ * Synchronous sleep utility using a busy-wait loop
16+ * Only use for short delays in build scripts where blocking is acceptable
17+ *
18+ * Note: This blocks the event loop and consumes CPU. For production code,
19+ * use async/await with setTimeout. For build scripts, this simple synchronous
20+ * approach is acceptable as we need to ensure filesystem operations complete
21+ * before proceeding.
22+ */
23+ function sleepSync ( ms : number ) : void {
24+ const end = Date . now ( ) + ms ;
25+ while ( Date . now ( ) < end ) {
26+ // Busy wait
27+ }
28+ }
29+
30+ /**
31+ * Safely ensure directory exists with retry logic
32+ */
33+ function ensureDir ( dirPath : string , retries = MAX_RETRIES ) : void {
34+ for ( let i = 0 ; i < retries ; i ++ ) {
35+ try {
36+ if ( ! fs . existsSync ( dirPath ) ) {
37+ fs . mkdirSync ( dirPath , { recursive : true } ) ;
38+ }
39+ // Verify the directory was created successfully
40+ if ( fs . existsSync ( dirPath ) && fs . statSync ( dirPath ) . isDirectory ( ) ) {
41+ return ;
42+ }
43+ } catch ( error ) {
44+ if ( i === retries - 1 ) {
45+ throw new Error ( `Failed to create directory ${ dirPath } : ${ error } ` ) ;
46+ }
47+ // Wait a bit before retrying with exponential backoff
48+ const delay = RETRY_DELAY_BASE_MS * ( i + 1 ) ;
49+ sleepSync ( delay ) ;
50+ }
51+ }
52+ }
53+
54+ /**
55+ * Safely write file with retry logic
56+ */
57+ function writeFileWithRetry ( filePath : string , content : string , retries = MAX_RETRIES ) : void {
58+ for ( let i = 0 ; i < retries ; i ++ ) {
59+ try {
60+ // Ensure the parent directory exists
61+ const dir = path . dirname ( filePath ) ;
62+ ensureDir ( dir ) ;
63+
64+ fs . writeFileSync ( filePath , content ) ;
65+ return ;
66+ } catch ( error ) {
67+ if ( i === retries - 1 ) {
68+ throw new Error ( `Failed to write file ${ filePath } : ${ error } ` ) ;
69+ }
70+ // Wait a bit before retrying with exponential backoff
71+ const delay = RETRY_DELAY_BASE_MS * ( i + 1 ) ;
72+ sleepSync ( delay ) ;
73+ }
74+ }
75+ }
76+
977// Clean output directory ensures no stale files remain
1078if ( fs . existsSync ( OUT_DIR ) ) {
1179 console . log ( `Cleaning output directory: ${ OUT_DIR } ` ) ;
12- fs . rmSync ( OUT_DIR , { recursive : true , force : true , maxRetries : 3 , retryDelay : 100 } ) ;
80+ fs . rmSync ( OUT_DIR , { recursive : true , force : true , maxRetries : MAX_RETRIES , retryDelay : RETRY_DELAY_BASE_MS } ) ;
81+
82+ // Wait a bit to ensure file system has synced
83+ // This prevents ENOENT errors on some file systems, particularly in CI environments
84+ sleepSync ( FS_SYNC_DELAY_MS ) ;
1385}
1486
1587// Ensure output directory exists
16- if ( ! fs . existsSync ( OUT_DIR ) ) {
17- fs . mkdirSync ( OUT_DIR , { recursive : true } ) ;
18- }
88+ ensureDir ( OUT_DIR ) ;
1989
2090console . log ( `Generating JSON Schemas to ${ OUT_DIR } ...` ) ;
2191
2292let count = 0 ;
93+ let errorCount = 0 ;
2394
2495// Protocol now exports namespaces (Data, UI, System, AI, API)
2596// We need to iterate through each namespace
2697for ( const [ namespaceName , namespaceExports ] of Object . entries ( Protocol ) ) {
2798 if ( typeof namespaceExports === 'object' && namespaceExports !== null ) {
2899 // Create category subdirectory (e.g., data, ui, system, ai, api)
29100 const categoryDir = path . join ( OUT_DIR , namespaceName . toLowerCase ( ) ) ;
30- if ( ! fs . existsSync ( categoryDir ) ) {
31- fs . mkdirSync ( categoryDir , { recursive : true } ) ;
101+
102+ try {
103+ ensureDir ( categoryDir ) ;
104+ } catch ( error ) {
105+ console . error ( `Failed to create directory for namespace ${ namespaceName } :` , error ) ;
106+ errorCount ++ ;
107+ continue ;
32108 }
33109
34110 console . log ( `\n[${ namespaceName } ]` ) ;
@@ -39,21 +115,33 @@ for (const [namespaceName, namespaceExports] of Object.entries(Protocol)) {
39115 if ( value instanceof z . ZodType ) {
40116 const schemaName = key . endsWith ( 'Schema' ) ? key . replace ( 'Schema' , '' ) : key ;
41117
42- // Convert to JSON Schema
43- const jsonSchema = zodToJsonSchema ( value , {
44- name : schemaName ,
45- $refStrategy : "none" // We want self-contained schemas for now
46- } ) ;
47-
48- const fileName = `${ schemaName } .json` ;
49- const filePath = path . join ( categoryDir , fileName ) ;
50-
51- fs . writeFileSync ( filePath , JSON . stringify ( jsonSchema , null , 2 ) ) ;
52- console . log ( `✓ ${ namespaceName . toLowerCase ( ) } /${ fileName } ` ) ;
53- count ++ ;
118+ try {
119+ // Convert to JSON Schema
120+ const jsonSchema = zodToJsonSchema ( value , {
121+ name : schemaName ,
122+ $refStrategy : "none" // We want self-contained schemas for now
123+ } ) ;
124+
125+ const fileName = `${ schemaName } .json` ;
126+ const filePath = path . join ( categoryDir , fileName ) ;
127+
128+ writeFileWithRetry ( filePath , JSON . stringify ( jsonSchema , null , 2 ) ) ;
129+ console . log ( `✓ ${ namespaceName . toLowerCase ( ) } /${ fileName } ` ) ;
130+ count ++ ;
131+ } catch ( error ) {
132+ console . error ( `Failed to generate schema for ${ namespaceName } .${ key } :` , error ) ;
133+ errorCount ++ ;
134+ }
54135 }
55136 }
56137 }
57138}
58139
59- console . log ( `\nSuccessfully generated ${ count } schemas.` ) ;
140+ if ( errorCount > 0 ) {
141+ console . error ( `\n❌ Completed with ${ errorCount } error(s). ${ count } schemas generated successfully.` ) ;
142+ console . error ( `\nNote: Partial schema generation occurred. Some schemas may be missing.` ) ;
143+ console . error ( `This typically indicates a Zod schema definition error or file system issue.` ) ;
144+ process . exit ( 1 ) ;
145+ }
146+
147+ console . log ( `\n✅ Successfully generated ${ count } schemas.` ) ;
0 commit comments