diff --git a/build.ts b/build.ts index 7c8d7f8..8a5aa48 100644 --- a/build.ts +++ b/build.ts @@ -1,7 +1,8 @@ #!/usr/bin/env node -import { build, context, type BuildOptions } from 'esbuild'; +import { build, context, type BuildOptions, type PluginBuild } from 'esbuild'; import { execSync } from 'node:child_process'; import { cpSync, existsSync, mkdirSync } from 'node:fs'; +import { fileURLToPath } from 'node:url'; import { parseArgs } from 'node:util'; const { @@ -20,25 +21,51 @@ if (!existsSync('build')) { mkdirSync('build'); } -execSync('npx make-index commands -o build/index.json', { stdio: 'inherit' }); +cpSync('system', 'build/system', { recursive: true }); -cpSync('commands', 'build/system'); +const shared_config: BuildOptions = { + target: 'es2022', + keepNames: true, + bundle: true, + format: 'esm', + platform: 'browser', +}; + +const lib_config: BuildOptions & { entryPoints: { in: string; out: string }[] } = { + ...shared_config, + entryPoints: [], + outdir: outdir + '/system/lib', +}; + +for (const specifier of ['@zenfs/core', 'utilium', 'chalk', '@zenfs/core/path']) { + lib_config.entryPoints.push({ + in: fileURLToPath(import.meta.resolve(specifier)), + out: specifier, + }); +} const config: BuildOptions = { + ...shared_config, entryPoints: ['src/index.ts', 'src/index.html', 'src/styles.css'], - target: 'es2022', outdir, loader: { '.html': 'copy', }, sourcemap: true, - keepNames: true, - bundle: true, - format: 'esm', - platform: 'browser', logOverride: { 'direct-eval': 'info', }, + plugins: [ + { + name: 'build-libs', + setup({ onStart }: PluginBuild): void | Promise { + onStart(async () => { + await build(lib_config); + execSync('npx make-index build/system -o build/index.json -q', { stdio: 'inherit' }); + }); + }, + }, + ], }; switch (mode) { diff --git a/package-lock.json b/package-lock.json index 1d785f2..7de167d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,7 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/addon-web-links": "^0.11.0", "@xterm/xterm": "^5.5.0", - "@zenfs/core": "^1.0.8", + "@zenfs/core": "^1.0.10", "@zenfs/dom": "^0.2.17", "@zenfs/iso": "^0.3.0", "@zenfs/zip": "^0.5.1", @@ -1011,9 +1011,9 @@ "license": "MIT" }, "node_modules/@zenfs/core": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@zenfs/core/-/core-1.0.8.tgz", - "integrity": "sha512-TNfNmeFwwerc9M5dIQrb+F1MKM1Txk8byrBUIudi8xtdU3NANb1qAOxa0kwegkh/nF8rPMphzSHbAlLufXUnag==", + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@zenfs/core/-/core-1.0.10.tgz", + "integrity": "sha512-aUCOOjz/3qA6aGbD41F33U71DgPauJeirzg0HJtxE3h4lSJFs5+xeOFdO7yqAEliepMO24LIInWwlNKRRgfQag==", "license": "MIT", "dependencies": { "@types/node": "^20.16.10", @@ -1032,9 +1032,9 @@ } }, "node_modules/@zenfs/core/node_modules/@types/node": { - "version": "20.16.11", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.11.tgz", - "integrity": "sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==", + "version": "20.16.12", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.12.tgz", + "integrity": "sha512-LfPFB0zOeCeCNQV3i+67rcoVvoN5n0NVuR2vLG0O5ySQMgchuZlC4lgz546ZOJyDtj5KIgOxy+lacOimfqZAIA==", "license": "MIT", "dependencies": { "undici-types": "~6.19.2" diff --git a/package.json b/package.json index 476bb16..d2f03bf 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "@xterm/addon-fit": "^0.10.0", "@xterm/addon-web-links": "^0.11.0", "@xterm/xterm": "^5.5.0", - "@zenfs/core": "^1.0.8", + "@zenfs/core": "^1.0.10", "@zenfs/dom": "^0.2.17", "@zenfs/iso": "^0.3.0", "@zenfs/zip": "^0.5.1", diff --git a/src/common.ts b/src/common.ts index e9a82a0..9b4277c 100644 --- a/src/common.ts +++ b/src/common.ts @@ -8,7 +8,10 @@ await configure({ mounts: { '/': { backend: Overlay, - readable: Fetch.create({}), + readable: Fetch.create({ + baseUrl: '/system', + index: '/index.json', + }), writable: InMemory.create({ name: 'root-cow' }), }, }, diff --git a/src/shell.ts b/src/shell.ts index a692ef1..12cef28 100644 --- a/src/shell.ts +++ b/src/shell.ts @@ -1,3 +1,4 @@ +/* eslint-disable @typescript-eslint/only-throw-error */ import { FitAddon } from '@xterm/addon-fit'; import { WebLinksAddon } from '@xterm/addon-web-links'; import { Terminal } from '@xterm/xterm'; @@ -24,7 +25,7 @@ fitAddon.fit(); const AsyncFunction = async function () {}.constructor as (...args: string[]) => (...args: unknown[]) => Promise; -const import_regex = /import (?:\* as )?(\w+) from '([^']+)';/g; +const import_regex = /import (\* as )?(\w+) from '([^']+)';/g; /** * Handles linking and stuff @@ -36,13 +37,31 @@ async function parse_source(source: string): Promise<{ source: string; imports: const imports = Object.create(null) as Record; let match: RegExpExecArray | null; while ((match = import_regex.exec(source))) { - const [, binding, specifier] = match; + const [, isNamespace, binding, specifier] = match; - imports[binding] = await import(specifier); + const lib_path = `/lib/${specifier}.js`; - source = source.replace(match[0], ''); + if (!fs.existsSync(lib_path)) { + throw 'Could not locate library: ' + specifier; + } + + const lib_contents = fs.readFileSync(lib_path, 'utf-8'); + + const url = URL.createObjectURL(new Blob([lib_contents], { type: 'text/javascript' })); + + const _module = await import(url); + + if (specifier == 'chalk') { + _module.default.level = 2; + } + + imports[binding] = isNamespace ? _module : _module.default; + + URL.revokeObjectURL(url); } + source = source.replaceAll(import_regex, ''); + return { source, imports }; } @@ -69,6 +88,10 @@ export async function exec(line: string): Promise { const locals = { args, fs, terminal, __open, __editor_open, __mount_resolve, ...imports }; + if ($('#terminal input.debug').is(':checked')) { + console.debug('EXEC:\nlocals:', locals, '\nsource:', source); + } + await AsyncFunction(`{${Object.keys(locals).join(',')}}`, source)(locals); } @@ -84,7 +107,6 @@ const shell = createShell({ await exec(line).catch((error: Error | string) => { terminal.writeln('Error: ' + ((error as Error).message ?? error)); if ($('#terminal input.debug').is(':checked')) { - // eslint-disable-next-line @typescript-eslint/only-throw-error throw error; } }); diff --git a/commands/cat.js b/system/bin/cat.js similarity index 100% rename from commands/cat.js rename to system/bin/cat.js diff --git a/commands/cd.js b/system/bin/cd.js similarity index 100% rename from commands/cd.js rename to system/bin/cd.js diff --git a/commands/chmod.js b/system/bin/chmod.js similarity index 100% rename from commands/chmod.js rename to system/bin/chmod.js diff --git a/commands/cp.js b/system/bin/cp.js similarity index 100% rename from commands/cp.js rename to system/bin/cp.js diff --git a/commands/echo.js b/system/bin/echo.js similarity index 100% rename from commands/echo.js rename to system/bin/echo.js diff --git a/commands/help.js b/system/bin/help.js similarity index 100% rename from commands/help.js rename to system/bin/help.js diff --git a/commands/lib.d.ts b/system/bin/lib.d.ts similarity index 100% rename from commands/lib.d.ts rename to system/bin/lib.d.ts diff --git a/commands/ln.js b/system/bin/ln.js similarity index 100% rename from commands/ln.js rename to system/bin/ln.js diff --git a/commands/ls.js b/system/bin/ls.js similarity index 99% rename from commands/ls.js rename to system/bin/ls.js index b11b898..361541f 100644 --- a/commands/ls.js +++ b/system/bin/ls.js @@ -63,6 +63,7 @@ function colorize(text, stats) { } return colorize(text); } +console.log(colorize); const formatter = new Intl.DateTimeFormat('en-US', { month: 'short', diff --git a/commands/mkdir.js b/system/bin/mkdir.js similarity index 100% rename from commands/mkdir.js rename to system/bin/mkdir.js diff --git a/commands/mv.js b/system/bin/mv.js similarity index 100% rename from commands/mv.js rename to system/bin/mv.js diff --git a/commands/open-editor.js b/system/bin/open-editor.js similarity index 100% rename from commands/open-editor.js rename to system/bin/open-editor.js diff --git a/commands/pwd.js b/system/bin/pwd.js similarity index 100% rename from commands/pwd.js rename to system/bin/pwd.js diff --git a/commands/rm.js b/system/bin/rm.js similarity index 100% rename from commands/rm.js rename to system/bin/rm.js diff --git a/commands/stat.js b/system/bin/stat.js similarity index 100% rename from commands/stat.js rename to system/bin/stat.js diff --git a/commands/touch.js b/system/bin/touch.js similarity index 100% rename from commands/touch.js rename to system/bin/touch.js diff --git a/commands/tsconfig.json b/system/bin/tsconfig.json similarity index 100% rename from commands/tsconfig.json rename to system/bin/tsconfig.json