1+ import { readdir , readFile } from "node:fs/promises" ;
2+ import type { Dirent } from "node:fs" ;
3+ import path from "node:path" ;
4+
15/**
26 * Cached reference to the witValidator interface from the WASM component module.
37 * The jco-transpiled module self-initializes via top-level await,
48 * so the module is ready to use once the dynamic import resolves.
59 */
610let witValidatorApi : typeof import ( "wit-bindgen-wasm" ) . witValidator | null = null ;
711
12+ interface PreparedSourceContext {
13+ sourcePath ?: string ;
14+ sourceFilesJson ?: string ;
15+ }
16+
17+ function normalizeSourcePath ( sourcePath ?: string ) : string | undefined {
18+ const trimmedPath = sourcePath ?. trim ( ) ;
19+ if ( ! trimmedPath ) {
20+ return undefined ;
21+ }
22+
23+ return path . resolve ( trimmedPath ) ;
24+ }
25+
26+ function isErrnoException ( error : unknown ) : error is NodeJS . ErrnoException {
27+ return error instanceof Error && "code" in error ;
28+ }
29+
30+ async function readDirectoryEntries ( directoryPath : string ) : Promise < Array < Dirent < string > > > {
31+ try {
32+ return await readdir ( directoryPath , { encoding : "utf8" , withFileTypes : true } ) ;
33+ } catch ( error : unknown ) {
34+ if ( isErrnoException ( error ) && error . code === "ENOENT" ) {
35+ return [ ] ;
36+ }
37+
38+ throw error ;
39+ }
40+ }
41+
42+ async function collectWitFilesRecursively ( directoryPath : string , sourceFiles : Record < string , string > ) : Promise < void > {
43+ for ( const entry of await readDirectoryEntries ( directoryPath ) ) {
44+ const entryPath = path . join ( directoryPath , entry . name ) ;
45+ if ( entry . isDirectory ( ) ) {
46+ await collectWitFilesRecursively ( entryPath , sourceFiles ) ;
47+ continue ;
48+ }
49+
50+ if ( entry . isFile ( ) && entry . name . toLowerCase ( ) . endsWith ( ".wit" ) ) {
51+ sourceFiles [ entryPath ] = await readFile ( entryPath , "utf8" ) ;
52+ }
53+ }
54+ }
55+
56+ async function collectWitContext ( sourceDirectory : string ) : Promise < Record < string , string > > {
57+ const sourceFiles : Record < string , string > = { } ;
58+
59+ for ( const entry of await readDirectoryEntries ( sourceDirectory ) ) {
60+ const entryPath = path . join ( sourceDirectory , entry . name ) ;
61+ if ( entry . isDirectory ( ) ) {
62+ if ( entry . name === "deps" ) {
63+ await collectWitFilesRecursively ( entryPath , sourceFiles ) ;
64+ }
65+ continue ;
66+ }
67+
68+ if ( entry . isFile ( ) && entry . name . toLowerCase ( ) . endsWith ( ".wit" ) ) {
69+ sourceFiles [ entryPath ] = await readFile ( entryPath , "utf8" ) ;
70+ }
71+ }
72+
73+ return sourceFiles ;
74+ }
75+
76+ async function prepareSourceContext ( content : string , sourcePath ?: string ) : Promise < PreparedSourceContext > {
77+ const normalizedSourcePath = normalizeSourcePath ( sourcePath ) ;
78+ if ( ! normalizedSourcePath ) {
79+ return { } ;
80+ }
81+
82+ const sourceFiles = await collectWitContext ( path . dirname ( normalizedSourcePath ) ) ;
83+ sourceFiles [ normalizedSourcePath ] = content ;
84+
85+ return {
86+ sourcePath : normalizedSourcePath ,
87+ sourceFilesJson : JSON . stringify ( sourceFiles ) ,
88+ } ;
89+ }
90+
891/**
992 * Initialize the WASM module by dynamically importing it.
1093 * The jco-transpiled component handles WASM loading internally.
@@ -68,9 +151,10 @@ export async function isWitFileExtensionFromWasm(filename: string): Promise<bool
68151 * @param content - The WIT content to validate
69152 * @returns Promise that resolves to true if the syntax is valid
70153 */
71- export async function validateWitSyntaxFromWasm ( content : string ) : Promise < boolean > {
154+ export async function validateWitSyntaxFromWasm ( content : string , sourcePath ?: string ) : Promise < boolean > {
72155 const api = await getApi ( ) ;
73- return api . validateWitSyntax ( content ) ;
156+ const preparedSource = await prepareSourceContext ( content , sourcePath ) ;
157+ return api . validateWitSyntax ( content , preparedSource . sourcePath , preparedSource . sourceFilesJson ) ;
74158}
75159
76160/**
@@ -122,11 +206,19 @@ export async function extractInterfacesFromWasm(content: string): Promise<string
122206export async function generateBindingsFromWasm (
123207 content : string ,
124208 language : string ,
125- worldName ?: string
209+ worldName ?: string ,
210+ sourcePath ?: string
126211) : Promise < Record < string , string > > {
127212 const api = await getApi ( ) ;
128- const jsonResult = api . generateBindings ( content , language , worldName ) ;
129- return JSON . parse ( jsonResult ) ;
213+ const preparedSource = await prepareSourceContext ( content , sourcePath ) ;
214+ const jsonResult = api . generateBindings (
215+ content ,
216+ language ,
217+ worldName ,
218+ preparedSource . sourcePath ,
219+ preparedSource . sourceFilesJson
220+ ) ;
221+ return JSON . parse ( jsonResult ) as Record < string , string > ;
130222}
131223
132224/**
@@ -143,8 +235,16 @@ export interface WitValidationResult {
143235 * @param content - The WIT content to validate
144236 * @returns Promise that resolves to detailed validation results
145237 */
146- export async function validateWitSyntaxDetailedFromWasm ( content : string ) : Promise < WitValidationResult > {
238+ export async function validateWitSyntaxDetailedFromWasm (
239+ content : string ,
240+ sourcePath ?: string
241+ ) : Promise < WitValidationResult > {
147242 const api = await getApi ( ) ;
148- const resultJson = api . validateWitSyntaxDetailed ( content ) ;
149- return JSON . parse ( resultJson ) ;
243+ const preparedSource = await prepareSourceContext ( content , sourcePath ) ;
244+ const resultJson = api . validateWitSyntaxDetailed (
245+ content ,
246+ preparedSource . sourcePath ,
247+ preparedSource . sourceFilesJson
248+ ) ;
249+ return JSON . parse ( resultJson ) as WitValidationResult ;
150250}
0 commit comments