From 8c3c9c8caff8c5235461d0d42b0c53d7a7df1711 Mon Sep 17 00:00:00 2001 From: Victor Adossi Date: Wed, 8 Oct 2025 02:13:05 +0900 Subject: [PATCH] fix: separate folder component path use Previously, when attempting to call `componentize()` on a with a `sourcePath` in a different directory, the call to Wizer would be generated with the incorrect *relative* path (path prefix stripping). This commit ensure that when Wizer is called with path prefix stripping, the path to the mapped file is correct. --- src/componentize.js | 9 ++++++++- test/api.js | 39 +++++++++++++++++++++++++++++++++++++++ test/util.js | 45 +++++++++++++++++++++++++++++++++++++++++++++ test/wasi.js | 41 ++--------------------------------------- 4 files changed, 94 insertions(+), 40 deletions(-) create mode 100644 test/api.js diff --git a/src/componentize.js b/src/componentize.js index 5bd6c0ee..46c0e0c2 100644 --- a/src/componentize.js +++ b/src/componentize.js @@ -5,7 +5,7 @@ import { fileURLToPath, URL } from 'node:url'; import { cwd, stdout, platform } from 'node:process'; import { spawnSync } from 'node:child_process'; import { tmpdir } from 'node:os'; -import { resolve, join, dirname } from 'node:path'; +import { resolve, join, dirname, relative } from 'node:path'; import { readFile, writeFile, mkdir, rm, stat } from 'node:fs/promises'; import { rmSync, existsSync } from 'node:fs'; import { createHash } from 'node:crypto'; @@ -249,11 +249,18 @@ export async function componentize( sourcePath = sourceName; } let currentDir = maybeWindowsPath(cwd()); + if (workspacePrefix.startsWith(currentDir)) { workspacePrefix = currentDir; sourcePath = sourcePath.slice(workspacePrefix.length + 1); } + // Ensure source path is relative to workspacePrefix for the args list, + // regardless of the directory + if (resolve(sourcePath).startsWith(resolve(workspacePrefix))) { + sourcePath = relative(workspacePrefix, sourcePath); + } + let args = `--initializer-script-path ${initializerPath} --strip-path-prefix ${workspacePrefix}/ ${sourcePath}`; runtimeArgs = runtimeArgs ? `${runtimeArgs} ${args}` : args; diff --git a/test/api.js b/test/api.js new file mode 100644 index 00000000..ac455b7d --- /dev/null +++ b/test/api.js @@ -0,0 +1,39 @@ +import { tmpdir } from 'node:os'; +import { join, resolve } from 'node:path'; +import { fileURLToPath, URL } from 'node:url'; +import { copyFile, mkdtemp } from 'node:fs/promises'; + +import { suite, test, assert } from 'vitest'; + +import { setupComponent } from "./util.js"; + +import { + DEBUG_TRACING_ENABLED, + DEBUG_TEST_ENABLED, +} from './util.js'; + +suite('API', () => { + // When using a different directory sourcePath as an arg to componentize() + // (called via setupComponent() in this test), wizer would fail to initialize the component + // due to a missing file -- the path prefix stripping was not correctly being resolved. + test('componentize() in a different dir', async () => { + const tmpDir = await mkdtemp(join(tmpdir(), 'componentize-diff-dir-')); + const outputPath = join(tmpDir, "index.js"); + await copyFile(resolve('./test/api/index.js'), outputPath); + const { instance } = await setupComponent({ + componentize: { + opts: { + sourcePath: outputPath, + witPath: fileURLToPath(new URL('./wit', import.meta.url)), + worldName: 'test1', + debugBuild: DEBUG_TEST_ENABLED, + }, + }, + transpile: { + opts: { + tracing: DEBUG_TRACING_ENABLED, + }, + }, + }); + }); +}); diff --git a/test/util.js b/test/util.js index b9028a61..13ddeac4 100644 --- a/test/util.js +++ b/test/util.js @@ -1,6 +1,11 @@ +import { join } from 'node:path'; import { env } from 'node:process'; +import { readFile, readdir, mkdir, writeFile, mkdtemp } from 'node:fs/promises'; import { createServer } from 'node:net'; +import { componentize } from '@bytecodealliance/componentize-js'; +import { transpile } from '@bytecodealliance/jco'; + export const DEBUG_TRACING_ENABLED = isEnabledEnvVar(env.DEBUG_TRACING); export const LOG_DEBUGGING_ENABLED = isEnabledEnvVar(env.LOG_DEBUGGING); export const DEBUG_TEST_ENABLED = isEnabledEnvVar(env.DEBUG_TEST); @@ -18,3 +23,43 @@ export function maybeLogging(disableFeatures) { } return disableFeatures; } + +export async function setupComponent(opts) { + const componentizeSrc = opts?.componentize?.src; + const componentizeOpts = opts?.componentize?.opts; + const transpileOpts = opts?.transpile?.opts; + + let component; + if (componentizeSrc) { + const srcBuild = await componentize(componentizeSrc, componentizeOpts); + component = srcBuild.component; + } else if (!componentizeSrc && componentizeOpts) { + const optsBuild = await componentize(componentizeOpts); + component = optsBuild.component; + } else { + throw new Error('no componentize options or src provided'); + } + + const outputDir = join('./test/output', 'wasi-test'); + await mkdir(outputDir, { recursive: true }); + + await writeFile(join(outputDir, 'wasi.component.wasm'), component); + + const { files } = await transpile(component, transpileOpts); + + const wasiDir = join(outputDir, 'wasi'); + const interfacesDir = join(wasiDir, 'interfaces'); + await mkdir(interfacesDir, { recursive: true }); + + for (const file of Object.keys(files)) { + await writeFile(join(wasiDir, file), files[file]); + } + + const componentJsPath = join(wasiDir, 'component.js'); + var instance = await import(componentJsPath); + + return { + instance, + outputDir, + }; +} diff --git a/test/wasi.js b/test/wasi.js index 94f57095..07155ade 100644 --- a/test/wasi.js +++ b/test/wasi.js @@ -9,6 +9,8 @@ import { transpile } from '@bytecodealliance/jco'; import { suite, test, assert } from 'vitest'; +import { setupComponent } from "./util.js"; + import { DEBUG_TRACING_ENABLED, DEBUG_TEST_ENABLED, @@ -85,42 +87,3 @@ suite('WASI', () => { }); }); -async function setupComponent(opts) { - const componentizeSrc = opts?.componentize?.src; - const componentizeOpts = opts?.componentize?.opts; - const transpileOpts = opts?.transpile?.opts; - - let component; - if (componentizeSrc) { - const srcBuild = await componentize(componentizeSrc, componentizeOpts); - component = srcBuild.component; - } else if (!componentizeSrc && componentizeOpts) { - const optsBuild = await componentize(componentizeOpts); - component = optsBuild.component; - } else { - throw new Error('no componentize options or src provided'); - } - - const outputDir = join('./test/output', 'wasi-test'); - await mkdir(outputDir, { recursive: true }); - - await writeFile(join(outputDir, 'wasi.component.wasm'), component); - - const { files } = await transpile(component, transpileOpts); - - const wasiDir = join(outputDir, 'wasi'); - const interfacesDir = join(wasiDir, 'interfaces'); - await mkdir(interfacesDir, { recursive: true }); - - for (const file of Object.keys(files)) { - await writeFile(join(wasiDir, file), files[file]); - } - - const componentJsPath = join(wasiDir, 'component.js'); - var instance = await import(componentJsPath); - - return { - instance, - outputDir, - }; -}