diff --git a/preload.ts b/preload.ts index e0d9a9a..5b4279d 100644 --- a/preload.ts +++ b/preload.ts @@ -6,18 +6,29 @@ const config: HyperImportConfig = (await import(`${cwd}/bunfig.toml`)).default.h debugLog(config.debug, 3, "registering loaders..."); -for (const loader of config.loaders ?? []) { - await import(`./src/loaders/${loader}.ts`).then(async l => { +/** + * Register a plugin + * @param loader + * @param path A path to register + * @param custom Whether it is a custom plugin + */ +async function register(loader, path: string, custom: boolean) { + const isCustom = custom ? "[CUSTOM] " : ""; + + try { + const l = await import(path); const plugin = await new l.default(cwd).toPlugin(); - Bun.plugin(plugin); - debugLog(config.debug, 2, plugin.name, "has been registered."); - }).catch(() => debugLog(config.debug, 1, "loader not found:", loader)); -} -for (const loader of config.custom ?? []) { - await import(`${cwd}/${loader}`).then(async l => { - const plugin = await new l.default(cwd).toPlugin(); Bun.plugin(plugin); - debugLog(config.debug, 2, "[CUSTOM]", plugin.name, "has been registered."); - }).catch(() => debugLog(config.debug, 1, "[CUSTOM] loader not found:", loader)); -} \ No newline at end of file + debugLog(config.debug, 2, isCustom + plugin.name, "has been registered."); + } catch (e) { + debugLog(config.debug, 1, isCustom + "loader not found:", loader); + } + +// Register default loader +for (const loader of config.loaders ?? []) + register(loader, `./src/loaders/${loader}.ts`, false); + +// Register custom loader +for (const loader of config.custom ?? []) + register(loader, `${cwd}/${loader}`, true); diff --git a/src/loader.ts b/src/loader.ts index e59ef3f..37cb448 100644 --- a/src/loader.ts +++ b/src/loader.ts @@ -31,9 +31,16 @@ export default class { * By default asks for the build command and output directory from the user on importing the source file for the first time. */ async initConfigPre() { - console.log(`\x1b[33m[HYPERIMPORT]\x1b[39m: ${this.name}\nNo configuration was found for "${this.config.importPath}"\nEnter the build command and output directory to configure it.\nPress enter to use the default values.\n`); + console.log( + `\x1b[33m[HYPERIMPORT]\x1b[39m: ${this.name}\n` + + `No configuration was found for "${this.config.importPath}"\n` + + `Enter the build command and output directory to configure it.\n` + + `Press enter to use the default values.\n` + ); + this.config.buildCommand = prompt("build command: (default)")?.split(" ") ?? this.config.buildCommand; this.config.outDir = prompt(`output directory: (${this.config.outDir})`) ?? this.config.outDir; + mkdirSync(this.config.outDir, { recursive: true }); } @@ -42,20 +49,33 @@ export default class { */ async initConfigTypes() { const filename = basename(this.config.importPath); - mkdirSync(`${this.cwd}/@types/${filename}`, { recursive: true }); - Bun.write(`${this.cwd}/@types/${filename}/lastModified`, lastModified(this.config.importPath)); - const configWriter = Bun.file(`${this.cwd}/@types/${filename}/config.ts`).writer(); - configWriter.write(`import { LoaderConfig, T } from "hyperimport";\nexport default {\n\tbuildCommand: ${JSON.stringify(this.config.buildCommand)},\n\toutDir: "${this.config.outDir}",\n\tsymbols: {`); - for (const symbol of nm(this.config.libPath)) { + const targetFile = `${this.cwd}/@types/${filename}`; + const configFile = `${targetFile}/config.ts`; + + mkdirSync(targetFile, { recursive: true }); + Bun.write(`${targetFile}/lastModified`, lastModified(this.config.importPath)); + + const configWriter = Bun.file(configFile).writer(); + + configWriter.write( + `import { LoaderConfig, T } from "hyperimport";\n` + + `export default {\n\tbuildCommand: ${JSON.stringify(this.config.buildCommand)},\n\toutDir: "${this.config.outDir}",\n\tsymbols: {` + ); + + for (const symbol of nm(this.config.libPath)) configWriter.write(`\n\t\t${symbol}: {\n\t\t\targs: [],\n\t\t\treturns: T.void\n\t\t},`); - } + configWriter.write(`\n\t}\n} satisfies LoaderConfig.Main;`); configWriter.end(); + Bun.write( - `${this.cwd}/@types/${filename}/types.d.ts`, + `${targetFile}/types.d.ts`, `declare module "*/${filename}" {\n\tconst symbols: import("bun:ffi").ConvertFns;\n\texport = symbols;\n}` ); - console.log(`\n\x1b[32mConfig file has been generated at "${this.cwd}/@types/${filename}/config.ts"\x1b[39m\nEdit the config.ts and set the argument and return types, then rerun the script.`); + console.log( + `\n\x1b[32mConfig file has been generated at "${configFile}"\x1b[39m\n` + + `Edit the config.ts and set the argument and return types, then rerun the script.` + ); } /** @@ -63,8 +83,10 @@ export default class { */ async initConfig() { await this.initConfigPre(); + console.log("\nBuilding the source file..."); await this.build(); + console.log("The source file has been built."); await this.initConfigTypes(); } @@ -75,6 +97,7 @@ export default class { async ifSourceModify() { const lm = lastModified(this.config.importPath); const lmfile = `${this.cwd}/@types/${basename(this.config.importPath)}/lastModified`; + if (lm !== await Bun.file(lmfile).text()) { await this.build(); Bun.write(lmfile, lm); @@ -110,20 +133,19 @@ export default class { * @returns A `BunPlugin` instance. */ async toPlugin(): Promise { - const parentThis = this; return { - name: parentThis.name, - setup(build) { - build.onLoad({ filter: new RegExp(`\.(${parentThis._config.extension})$`) }, async args => { - parentThis.config.importPath = args.path; - await parentThis.preload(); + name: this.name, + setup: build => { + build.onLoad({ filter: new RegExp(`\.(${this._config.extension})$`) }, async args => { + this.config.importPath = args.path; + await this.preload(); + return { - exports: dlopen(parentThis.config.libPath, await parentThis.getSymbols()).symbols, + exports: dlopen(this.config.libPath, await this.getSymbols()).symbols, loader: "object" }; }); } }; } - -} \ No newline at end of file +}