@ricsam/quickjs-test-utils 1.0.1 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -36,7 +36,7 @@ __export(exports_fetch_context, {
36
36
  });
37
37
  module.exports = __toCommonJS(exports_fetch_context);
38
38
  var import_quickjs_fetch = require("@ricsam/quickjs-fetch");
39
- var import_context = require("./context.ts");
39
+ var import_context = require("./context.cjs");
40
40
  async function createFetchTestContext(options) {
41
41
  const base = await import_context.createTestContext();
42
42
  const fetchHandle = import_quickjs_fetch.setupFetch(base.context, {
@@ -86,4 +86,4 @@ function useFetchTestContext() {
86
86
  }
87
87
  })
88
88
 
89
- //# debugId=63D6126825B82DA964756E2164756E21
89
+ //# debugId=FA850BE027AB3DDF64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/fetch-context.ts"],
4
4
  "sourcesContent": [
5
- "import { setupFetch, type FetchHandle, type SetupFetchOptions } from \"@ricsam/quickjs-fetch\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.ts\";\n\nexport interface FetchTestContext extends TestContext {\n fetchHandle: FetchHandle;\n}\n\nexport interface CreateFetchTestContextOptions {\n /** Handler for outbound fetch() calls from QuickJS */\n onFetch?: SetupFetchOptions[\"onFetch\"];\n}\n\nexport async function createFetchTestContext(\n options?: CreateFetchTestContextOptions\n): Promise<FetchTestContext> {\n const base = await createTestContext();\n const fetchHandle = setupFetch(base.context, {\n coreHandle: base.coreHandle,\n onFetch: options?.onFetch,\n });\n\n return { ...base, fetchHandle };\n}\n\nexport function disposeFetchTestContext(ctx: FetchTestContext): void {\n ctx.fetchHandle.dispose();\n disposeTestContext(ctx);\n}\n\n/**\n * Helper for use with beforeEach/afterEach for fetch tests\n *\n * @example\n * const testCtx = useFetchTestContext();\n *\n * beforeEach(async () => {\n * await testCtx.setup();\n * });\n *\n * afterEach(() => {\n * testCtx.teardown();\n * });\n *\n * test(\"headers test\", () => {\n * const result = evalCode(testCtx.context, `\n * const headers = new Headers({ \"Content-Type\": \"application/json\" });\n * headers.get(\"content-type\");\n * `);\n * expect(result).toBe(\"application/json\");\n * });\n */\nexport function useFetchTestContext() {\n let ctx: FetchTestContext | undefined;\n\n return {\n async setup() {\n ctx = await createFetchTestContext();\n return ctx;\n },\n teardown() {\n if (ctx) {\n disposeFetchTestContext(ctx);\n ctx = undefined;\n }\n },\n get context() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.context;\n },\n get runtime() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.runtime;\n },\n get coreHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.coreHandle;\n },\n get fetchHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.fetchHandle;\n },\n };\n}\n"
5
+ "import { setupFetch, type FetchHandle, type SetupFetchOptions } from \"@ricsam/quickjs-fetch\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.cjs\";\n\nexport interface FetchTestContext extends TestContext {\n fetchHandle: FetchHandle;\n}\n\nexport interface CreateFetchTestContextOptions {\n /** Handler for outbound fetch() calls from QuickJS */\n onFetch?: SetupFetchOptions[\"onFetch\"];\n}\n\nexport async function createFetchTestContext(\n options?: CreateFetchTestContextOptions\n): Promise<FetchTestContext> {\n const base = await createTestContext();\n const fetchHandle = setupFetch(base.context, {\n coreHandle: base.coreHandle,\n onFetch: options?.onFetch,\n });\n\n return { ...base, fetchHandle };\n}\n\nexport function disposeFetchTestContext(ctx: FetchTestContext): void {\n ctx.fetchHandle.dispose();\n disposeTestContext(ctx);\n}\n\n/**\n * Helper for use with beforeEach/afterEach for fetch tests\n *\n * @example\n * const testCtx = useFetchTestContext();\n *\n * beforeEach(async () => {\n * await testCtx.setup();\n * });\n *\n * afterEach(() => {\n * testCtx.teardown();\n * });\n *\n * test(\"headers test\", () => {\n * const result = evalCode(testCtx.context, `\n * const headers = new Headers({ \"Content-Type\": \"application/json\" });\n * headers.get(\"content-type\");\n * `);\n * expect(result).toBe(\"application/json\");\n * });\n */\nexport function useFetchTestContext() {\n let ctx: FetchTestContext | undefined;\n\n return {\n async setup() {\n ctx = await createFetchTestContext();\n return ctx;\n },\n teardown() {\n if (ctx) {\n disposeFetchTestContext(ctx);\n ctx = undefined;\n }\n },\n get context() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.context;\n },\n get runtime() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.runtime;\n },\n get coreHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.coreHandle;\n },\n get fetchHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.fetchHandle;\n },\n };\n}\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAqE,IAArE;AAKO,IAJP;AAeA,eAAsB,sBAAsB,CAC1C,SAC2B;AAAA,EAC3B,MAAM,OAAO,MAAM,iCAAkB;AAAA,EACrC,MAAM,cAAc,gCAAW,KAAK,SAAS;AAAA,IAC3C,YAAY,KAAK;AAAA,IACjB,SAAS,SAAS;AAAA,EACpB,CAAC;AAAA,EAED,OAAO,KAAK,MAAM,YAAY;AAAA;AAGzB,SAAS,uBAAuB,CAAC,KAA6B;AAAA,EACnE,IAAI,YAAY,QAAQ;AAAA,EACxB,kCAAmB,GAAG;AAAA;AAyBjB,SAAS,mBAAmB,GAAG;AAAA,EACpC,IAAI;AAAA,EAEJ,OAAO;AAAA,SACC,MAAK,GAAG;AAAA,MACZ,MAAM,MAAM,uBAAuB;AAAA,MACnC,OAAO;AAAA;AAAA,IAET,QAAQ,GAAG;AAAA,MACT,IAAI,KAAK;AAAA,QACP,wBAAwB,GAAG;AAAA,QAC3B,MAAM;AAAA,MACR;AAAA;AAAA,QAEE,OAAO,GAAG;AAAA,MACZ,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,QAET,OAAO,GAAG;AAAA,MACZ,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,QAET,UAAU,GAAG;AAAA,MACf,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,QAET,WAAW,GAAG;AAAA,MAChB,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,EAEf;AAAA;",
8
- "debugId": "63D6126825B82DA964756E2164756E21",
8
+ "debugId": "FA850BE027AB3DDF64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -35,7 +35,7 @@ __export(exports_fs_context, {
35
35
  });
36
36
  module.exports = __toCommonJS(exports_fs_context);
37
37
  var import_quickjs_fs = require("@ricsam/quickjs-fs");
38
- var import_context = require("./context.ts");
38
+ var import_context = require("./context.cjs");
39
39
  async function createFsTestContext(options) {
40
40
  const base = await import_context.createTestContext();
41
41
  const memFs = import_quickjs_fs.createMemoryDirectoryHandle(options?.initialFiles);
@@ -51,4 +51,4 @@ function disposeFsTestContext(ctx) {
51
51
  }
52
52
  })
53
53
 
54
- //# debugId=1EE240687003E38364756E2164756E21
54
+ //# debugId=B6652A8E376AF31D64756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/fs-context.ts"],
4
4
  "sourcesContent": [
5
- "import {\n setupFs,\n createMemoryDirectoryHandle,\n type FsHandle,\n type HostDirectoryHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.ts\";\n\nexport interface FsTestContext extends TestContext {\n fsHandle: FsHandle;\n memFs: HostDirectoryHandle;\n}\n\nexport interface CreateFsTestContextOptions {\n /** Initial files to populate the in-memory filesystem */\n initialFiles?: Record<string, string | Uint8Array>;\n}\n\nexport async function createFsTestContext(\n options?: CreateFsTestContextOptions\n): Promise<FsTestContext> {\n const base = await createTestContext();\n const memFs = createMemoryDirectoryHandle(options?.initialFiles);\n const fsHandle = setupFs(base.context, {\n coreHandle: base.coreHandle,\n getDirectory: async () => memFs,\n });\n\n return { ...base, fsHandle, memFs };\n}\n\nexport function disposeFsTestContext(ctx: FsTestContext): void {\n ctx.fsHandle.dispose();\n disposeTestContext(ctx);\n}\n"
5
+ "import {\n setupFs,\n createMemoryDirectoryHandle,\n type FsHandle,\n type HostDirectoryHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.cjs\";\n\nexport interface FsTestContext extends TestContext {\n fsHandle: FsHandle;\n memFs: HostDirectoryHandle;\n}\n\nexport interface CreateFsTestContextOptions {\n /** Initial files to populate the in-memory filesystem */\n initialFiles?: Record<string, string | Uint8Array>;\n}\n\nexport async function createFsTestContext(\n options?: CreateFsTestContextOptions\n): Promise<FsTestContext> {\n const base = await createTestContext();\n const memFs = createMemoryDirectoryHandle(options?.initialFiles);\n const fsHandle = setupFs(base.context, {\n coreHandle: base.coreHandle,\n getDirectory: async () => memFs,\n });\n\n return { ...base, fsHandle, memFs };\n}\n\nexport function disposeFsTestContext(ctx: FsTestContext): void {\n ctx.fsHandle.dispose();\n disposeTestContext(ctx);\n}\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKO,IALP;AAUO,IAJP;AAgBA,eAAsB,mBAAmB,CACvC,SACwB;AAAA,EACxB,MAAM,OAAO,MAAM,iCAAkB;AAAA,EACrC,MAAM,QAAQ,8CAA4B,SAAS,YAAY;AAAA,EAC/D,MAAM,WAAW,0BAAQ,KAAK,SAAS;AAAA,IACrC,YAAY,KAAK;AAAA,IACjB,cAAc,YAAY;AAAA,EAC5B,CAAC;AAAA,EAED,OAAO,KAAK,MAAM,UAAU,MAAM;AAAA;AAG7B,SAAS,oBAAoB,CAAC,KAA0B;AAAA,EAC7D,IAAI,SAAS,QAAQ;AAAA,EACrB,kCAAmB,GAAG;AAAA;",
8
- "debugId": "1EE240687003E38364756E2164756E21",
8
+ "debugId": "B6652A8E376AF31D64756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -47,12 +47,12 @@ __export(exports_src, {
47
47
  CORE_TYPES: () => import_quickjs_types.CORE_TYPES
48
48
  });
49
49
  module.exports = __toCommonJS(exports_src);
50
- var import_context = require("./context.ts");
51
- var import_fetch_context = require("./fetch-context.ts");
52
- var import_eval = require("./eval.ts");
53
- var import_integration_server = require("./integration-server.ts");
54
- var import_typecheck = require("./typecheck.ts");
55
- var import_quickjs_types = require("./quickjs-types.ts");
50
+ var import_context = require("./context.cjs");
51
+ var import_fetch_context = require("./fetch-context.cjs");
52
+ var import_eval = require("./eval.cjs");
53
+ var import_integration_server = require("./integration-server.cjs");
54
+ var import_typecheck = require("./typecheck.cjs");
55
+ var import_quickjs_types = require("./quickjs-types.cjs");
56
56
  })
57
57
 
58
- //# debugId=6163F5C604565B7564756E2164756E21
58
+ //# debugId=58D73AEF6D5595F264756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "export {\n createTestContext,\n disposeTestContext,\n useTestContext,\n type TestContext,\n} from \"./context.ts\";\n\nexport {\n createFetchTestContext,\n disposeFetchTestContext,\n useFetchTestContext,\n type FetchTestContext,\n type CreateFetchTestContextOptions,\n} from \"./fetch-context.ts\";\n\nexport { evalCode, evalCodeAsync } from \"./eval.ts\";\n\nexport {\n startIntegrationServer,\n type IntegrationTestServer,\n type StartIntegrationServerOptions,\n} from \"./integration-server.ts\";\n\nexport {\n typecheckQuickJSCode,\n formatTypecheckErrors,\n type TypecheckResult,\n type TypecheckError,\n type TypecheckOptions,\n} from \"./typecheck.ts\";\n\nexport {\n CORE_TYPES,\n FETCH_TYPES,\n FS_TYPES,\n TYPE_DEFINITIONS,\n type TypeDefinitionKey,\n} from \"./quickjs-types.ts\";\n\n// For fs and runtime contexts, import from subpaths:\n// import { createFsTestContext } from \"@ricsam/quickjs-test-utils/fs\";\n// import { createRuntimeTestContext } from \"@ricsam/quickjs-test-utils/runtime\";\n"
5
+ "export {\n createTestContext,\n disposeTestContext,\n useTestContext,\n type TestContext,\n} from \"./context.cjs\";\n\nexport {\n createFetchTestContext,\n disposeFetchTestContext,\n useFetchTestContext,\n type FetchTestContext,\n type CreateFetchTestContextOptions,\n} from \"./fetch-context.cjs\";\n\nexport { evalCode, evalCodeAsync } from \"./eval.cjs\";\n\nexport {\n startIntegrationServer,\n type IntegrationTestServer,\n type StartIntegrationServerOptions,\n} from \"./integration-server.cjs\";\n\nexport {\n typecheckQuickJSCode,\n formatTypecheckErrors,\n type TypecheckResult,\n type TypecheckError,\n type TypecheckOptions,\n} from \"./typecheck.cjs\";\n\nexport {\n CORE_TYPES,\n FETCH_TYPES,\n FS_TYPES,\n TYPE_DEFINITIONS,\n type TypeDefinitionKey,\n} from \"./quickjs-types.cjs\";\n\n// For fs and runtime contexts, import from subpaths:\n// import { createFsTestContext } from \"@ricsam/quickjs-test-utils/fs\";\n// import { createRuntimeTestContext } from \"@ricsam/quickjs-test-utils/runtime\";\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAKO,IALP;AAaO,IANP;AAQwC,IAAxC;AAMO,IAJP;AAYO,IANP;AAcO,IANP;",
8
- "debugId": "6163F5C604565B7564756E2164756E21",
8
+ "debugId": "58D73AEF6D5595F264756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-utils",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "commonjs"
5
5
  }
@@ -35,7 +35,7 @@ __export(exports_typecheck, {
35
35
  });
36
36
  module.exports = __toCommonJS(exports_typecheck);
37
37
  var import_ts_morph = require("ts-morph");
38
- var import_quickjs_types = require("./quickjs-types.ts");
38
+ var import_quickjs_types = require("./quickjs-types.cjs");
39
39
  function getMessageText(messageText) {
40
40
  if (typeof messageText === "string") {
41
41
  return messageText;
@@ -105,4 +105,4 @@ function formatTypecheckErrors(result) {
105
105
  }
106
106
  })
107
107
 
108
- //# debugId=A19F710B20870D7C64756E2164756E21
108
+ //# debugId=F7ABA26F8C307CC164756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/typecheck.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Type-checking utility for QuickJS user code using ts-morph.\n *\n * This utility allows you to validate TypeScript code strings against\n * the QuickJS global type definitions before running them in the sandbox.\n *\n * @example\n * import { typecheckQuickJSCode } from \"@ricsam/quickjs-test-utils\";\n *\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * if (!result.success) {\n * console.error(\"Type errors:\", result.errors);\n * }\n */\n\nimport { Project, ts } from \"ts-morph\";\nimport { TYPE_DEFINITIONS, type TypeDefinitionKey } from \"./quickjs-types.ts\";\n\n/**\n * Result of type-checking QuickJS code.\n */\nexport interface TypecheckResult {\n /**\n * Whether the code passed type checking.\n */\n success: boolean;\n\n /**\n * Array of type errors found in the code.\n */\n errors: TypecheckError[];\n}\n\n/**\n * A single type-checking error.\n */\nexport interface TypecheckError {\n /**\n * The error message from TypeScript.\n */\n message: string;\n\n /**\n * The line number where the error occurred (1-indexed).\n */\n line?: number;\n\n /**\n * The column number where the error occurred (1-indexed).\n */\n column?: number;\n\n /**\n * The TypeScript error code.\n */\n code?: number;\n}\n\n/**\n * Options for type-checking QuickJS code.\n */\nexport interface TypecheckOptions {\n /**\n * Which package types to include.\n * @default [\"core\", \"fetch\", \"fs\"]\n */\n include?: Array<\"core\" | \"fetch\" | \"fs\">;\n\n /**\n * Additional compiler options to pass to TypeScript.\n */\n compilerOptions?: Partial<ts.CompilerOptions>;\n}\n\n/**\n * Get the message text from a TypeScript diagnostic message.\n * Handles both string messages and DiagnosticMessageChain objects.\n */\nfunction getMessageText(messageText: unknown): string {\n if (typeof messageText === \"string\") {\n return messageText;\n }\n\n // Handle ts-morph DiagnosticMessageChain wrapper\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"getMessageText\" in messageText &&\n typeof (messageText as { getMessageText: unknown }).getMessageText ===\n \"function\"\n ) {\n return (messageText as { getMessageText: () => string }).getMessageText();\n }\n\n // Handle raw TypeScript DiagnosticMessageChain\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"messageText\" in messageText\n ) {\n return String((messageText as { messageText: unknown }).messageText);\n }\n\n return String(messageText);\n}\n\n\n/**\n * Type-check QuickJS user code against the package type definitions.\n *\n * @param code - The TypeScript/JavaScript code to check\n * @param options - Configuration options\n * @returns The result of type checking\n *\n * @example\n * // Check code that uses the fetch API\n * const result = typecheckQuickJSCode(`\n * const response = await fetch(\"https://api.example.com/data\");\n * const data = await response.json();\n * `, { include: [\"core\", \"fetch\"] });\n *\n * @example\n * // Check code that uses serve()\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * @example\n * // Check code that uses the file system API\n * const result = typecheckQuickJSCode(`\n * const root = await fs.getDirectory(\"/data\");\n * const file = await root.getFileHandle(\"config.json\");\n * `, { include: [\"core\", \"fs\"] });\n */\nexport function typecheckQuickJSCode(\n code: string,\n options?: TypecheckOptions\n): TypecheckResult {\n const include = options?.include ?? [\"core\", \"fetch\", \"fs\"];\n\n // Create a project with in-memory file system\n const project = new Project({\n useInMemoryFileSystem: true,\n compilerOptions: {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext,\n lib: [\"lib.esnext.d.ts\", \"lib.dom.d.ts\"],\n strict: true,\n noEmit: true,\n skipLibCheck: true,\n ...options?.compilerOptions,\n },\n });\n\n // Add type definition files from embedded strings\n for (const pkg of include) {\n const content = TYPE_DEFINITIONS[pkg as TypeDefinitionKey];\n if (content) {\n project.createSourceFile(`${pkg}.d.ts`, content);\n }\n }\n\n // Add the user code\n const sourceFile = project.createSourceFile(\"usercode.ts\", code);\n\n // Get diagnostics\n const diagnostics = sourceFile.getPreEmitDiagnostics();\n\n // Convert diagnostics to our error format\n const errors: TypecheckError[] = diagnostics.map((diagnostic) => {\n const start = diagnostic.getStart();\n const sourceFile = diagnostic.getSourceFile();\n\n let line: number | undefined;\n let column: number | undefined;\n\n if (start !== undefined && sourceFile) {\n const lineAndChar = sourceFile.getLineAndColumnAtPos(start);\n line = lineAndChar.line;\n column = lineAndChar.column;\n }\n\n return {\n message: getMessageText(diagnostic.getMessageText()),\n line,\n column,\n code: diagnostic.getCode(),\n };\n });\n\n return {\n success: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Format type-check errors for display.\n *\n * @param result - The type-check result\n * @returns A formatted string of errors\n *\n * @example\n * const result = typecheckQuickJSCode(code);\n * if (!result.success) {\n * console.error(formatTypecheckErrors(result));\n * }\n */\nexport function formatTypecheckErrors(result: TypecheckResult): string {\n if (result.success) {\n return \"No type errors found.\";\n }\n\n return result.errors\n .map((error) => {\n const location =\n error.line !== undefined ? `:${error.line}:${error.column ?? 1}` : \"\";\n const code = error.code ? ` (TS${error.code})` : \"\";\n return `usercode.ts${location}${code}: ${error.message}`;\n })\n .join(\"\\n\");\n}\n"
5
+ "/**\n * Type-checking utility for QuickJS user code using ts-morph.\n *\n * This utility allows you to validate TypeScript code strings against\n * the QuickJS global type definitions before running them in the sandbox.\n *\n * @example\n * import { typecheckQuickJSCode } from \"@ricsam/quickjs-test-utils\";\n *\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * if (!result.success) {\n * console.error(\"Type errors:\", result.errors);\n * }\n */\n\nimport { Project, ts } from \"ts-morph\";\nimport { TYPE_DEFINITIONS, type TypeDefinitionKey } from \"./quickjs-types.cjs\";\n\n/**\n * Result of type-checking QuickJS code.\n */\nexport interface TypecheckResult {\n /**\n * Whether the code passed type checking.\n */\n success: boolean;\n\n /**\n * Array of type errors found in the code.\n */\n errors: TypecheckError[];\n}\n\n/**\n * A single type-checking error.\n */\nexport interface TypecheckError {\n /**\n * The error message from TypeScript.\n */\n message: string;\n\n /**\n * The line number where the error occurred (1-indexed).\n */\n line?: number;\n\n /**\n * The column number where the error occurred (1-indexed).\n */\n column?: number;\n\n /**\n * The TypeScript error code.\n */\n code?: number;\n}\n\n/**\n * Options for type-checking QuickJS code.\n */\nexport interface TypecheckOptions {\n /**\n * Which package types to include.\n * @default [\"core\", \"fetch\", \"fs\"]\n */\n include?: Array<\"core\" | \"fetch\" | \"fs\">;\n\n /**\n * Additional compiler options to pass to TypeScript.\n */\n compilerOptions?: Partial<ts.CompilerOptions>;\n}\n\n/**\n * Get the message text from a TypeScript diagnostic message.\n * Handles both string messages and DiagnosticMessageChain objects.\n */\nfunction getMessageText(messageText: unknown): string {\n if (typeof messageText === \"string\") {\n return messageText;\n }\n\n // Handle ts-morph DiagnosticMessageChain wrapper\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"getMessageText\" in messageText &&\n typeof (messageText as { getMessageText: unknown }).getMessageText ===\n \"function\"\n ) {\n return (messageText as { getMessageText: () => string }).getMessageText();\n }\n\n // Handle raw TypeScript DiagnosticMessageChain\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"messageText\" in messageText\n ) {\n return String((messageText as { messageText: unknown }).messageText);\n }\n\n return String(messageText);\n}\n\n\n/**\n * Type-check QuickJS user code against the package type definitions.\n *\n * @param code - The TypeScript/JavaScript code to check\n * @param options - Configuration options\n * @returns The result of type checking\n *\n * @example\n * // Check code that uses the fetch API\n * const result = typecheckQuickJSCode(`\n * const response = await fetch(\"https://api.example.com/data\");\n * const data = await response.json();\n * `, { include: [\"core\", \"fetch\"] });\n *\n * @example\n * // Check code that uses serve()\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * @example\n * // Check code that uses the file system API\n * const result = typecheckQuickJSCode(`\n * const root = await fs.getDirectory(\"/data\");\n * const file = await root.getFileHandle(\"config.json\");\n * `, { include: [\"core\", \"fs\"] });\n */\nexport function typecheckQuickJSCode(\n code: string,\n options?: TypecheckOptions\n): TypecheckResult {\n const include = options?.include ?? [\"core\", \"fetch\", \"fs\"];\n\n // Create a project with in-memory file system\n const project = new Project({\n useInMemoryFileSystem: true,\n compilerOptions: {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext,\n lib: [\"lib.esnext.d.ts\", \"lib.dom.d.ts\"],\n strict: true,\n noEmit: true,\n skipLibCheck: true,\n ...options?.compilerOptions,\n },\n });\n\n // Add type definition files from embedded strings\n for (const pkg of include) {\n const content = TYPE_DEFINITIONS[pkg as TypeDefinitionKey];\n if (content) {\n project.createSourceFile(`${pkg}.d.ts`, content);\n }\n }\n\n // Add the user code\n const sourceFile = project.createSourceFile(\"usercode.ts\", code);\n\n // Get diagnostics\n const diagnostics = sourceFile.getPreEmitDiagnostics();\n\n // Convert diagnostics to our error format\n const errors: TypecheckError[] = diagnostics.map((diagnostic) => {\n const start = diagnostic.getStart();\n const sourceFile = diagnostic.getSourceFile();\n\n let line: number | undefined;\n let column: number | undefined;\n\n if (start !== undefined && sourceFile) {\n const lineAndChar = sourceFile.getLineAndColumnAtPos(start);\n line = lineAndChar.line;\n column = lineAndChar.column;\n }\n\n return {\n message: getMessageText(diagnostic.getMessageText()),\n line,\n column,\n code: diagnostic.getCode(),\n };\n });\n\n return {\n success: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Format type-check errors for display.\n *\n * @param result - The type-check result\n * @returns A formatted string of errors\n *\n * @example\n * const result = typecheckQuickJSCode(code);\n * if (!result.success) {\n * console.error(formatTypecheckErrors(result));\n * }\n */\nexport function formatTypecheckErrors(result: TypecheckResult): string {\n if (result.success) {\n return \"No type errors found.\";\n }\n\n return result.errors\n .map((error) => {\n const location =\n error.line !== undefined ? `:${error.line}:${error.column ?? 1}` : \"\";\n const code = error.code ? ` (TS${error.code})` : \"\";\n return `usercode.ts${location}${code}: ${error.message}`;\n })\n .join(\"\\n\");\n}\n"
6
6
  ],
7
7
  "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAsB4B,IAA5B;AACyD,IAAzD;AA8DA,SAAS,cAAc,CAAC,aAA8B;AAAA,EACpD,IAAI,OAAO,gBAAgB,UAAU;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EAGA,IACE,eACA,OAAO,gBAAgB,YACvB,oBAAoB,eACpB,OAAQ,YAA4C,mBAClD,YACF;AAAA,IACA,OAAQ,YAAiD,eAAe;AAAA,EAC1E;AAAA,EAGA,IACE,eACA,OAAO,gBAAgB,YACvB,iBAAiB,aACjB;AAAA,IACA,OAAO,OAAQ,YAAyC,WAAW;AAAA,EACrE;AAAA,EAEA,OAAO,OAAO,WAAW;AAAA;AAmCpB,SAAS,oBAAoB,CAClC,MACA,SACiB;AAAA,EACjB,MAAM,UAAU,SAAS,WAAW,CAAC,QAAQ,SAAS,IAAI;AAAA,EAG1D,MAAM,UAAU,IAAI,wBAAQ;AAAA,IAC1B,uBAAuB;AAAA,IACvB,iBAAiB;AAAA,MACf,QAAQ,mBAAG,aAAa;AAAA,MACxB,QAAQ,mBAAG,WAAW;AAAA,MACtB,KAAK,CAAC,mBAAmB,cAAc;AAAA,MACvC,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,cAAc;AAAA,SACX,SAAS;AAAA,IACd;AAAA,EACF,CAAC;AAAA,EAGD,WAAW,OAAO,SAAS;AAAA,IACzB,MAAM,UAAU,sCAAiB;AAAA,IACjC,IAAI,SAAS;AAAA,MACX,QAAQ,iBAAiB,GAAG,YAAY,OAAO;AAAA,IACjD;AAAA,EACF;AAAA,EAGA,MAAM,aAAa,QAAQ,iBAAiB,eAAe,IAAI;AAAA,EAG/D,MAAM,cAAc,WAAW,sBAAsB;AAAA,EAGrD,MAAM,SAA2B,YAAY,IAAI,CAAC,eAAe;AAAA,IAC/D,MAAM,QAAQ,WAAW,SAAS;AAAA,IAClC,MAAM,cAAa,WAAW,cAAc;AAAA,IAE5C,IAAI;AAAA,IACJ,IAAI;AAAA,IAEJ,IAAI,UAAU,aAAa,aAAY;AAAA,MACrC,MAAM,cAAc,YAAW,sBAAsB,KAAK;AAAA,MAC1D,OAAO,YAAY;AAAA,MACnB,SAAS,YAAY;AAAA,IACvB;AAAA,IAEA,OAAO;AAAA,MACL,SAAS,eAAe,WAAW,eAAe,CAAC;AAAA,MACnD;AAAA,MACA;AAAA,MACA,MAAM,WAAW,QAAQ;AAAA,IAC3B;AAAA,GACD;AAAA,EAED,OAAO;AAAA,IACL,SAAS,OAAO,WAAW;AAAA,IAC3B;AAAA,EACF;AAAA;AAeK,SAAS,qBAAqB,CAAC,QAAiC;AAAA,EACrE,IAAI,OAAO,SAAS;AAAA,IAClB,OAAO;AAAA,EACT;AAAA,EAEA,OAAO,OAAO,OACX,IAAI,CAAC,UAAU;AAAA,IACd,MAAM,WACJ,MAAM,SAAS,YAAY,IAAI,MAAM,QAAQ,MAAM,UAAU,MAAM;AAAA,IACrE,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM,UAAU;AAAA,IACjD,OAAO,cAAc,WAAW,SAAS,MAAM;AAAA,GAChD,EACA,KAAK;AAAA,CAAI;AAAA;",
8
- "debugId": "A19F710B20870D7C64756E2164756E21",
8
+ "debugId": "F7ABA26F8C307CC164756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -4,7 +4,7 @@ import { setupFetch } from "@ricsam/quickjs-fetch";
4
4
  import {
5
5
  createTestContext,
6
6
  disposeTestContext
7
- } from "./context.ts";
7
+ } from "./context.mjs";
8
8
  async function createFetchTestContext(options) {
9
9
  const base = await createTestContext();
10
10
  const fetchHandle = setupFetch(base.context, {
@@ -58,4 +58,4 @@ export {
58
58
  createFetchTestContext
59
59
  };
60
60
 
61
- //# debugId=2201FD7D87D68FCD64756E2164756E21
61
+ //# debugId=CF92F143B1423A8864756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/fetch-context.ts"],
4
4
  "sourcesContent": [
5
- "import { setupFetch, type FetchHandle, type SetupFetchOptions } from \"@ricsam/quickjs-fetch\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.ts\";\n\nexport interface FetchTestContext extends TestContext {\n fetchHandle: FetchHandle;\n}\n\nexport interface CreateFetchTestContextOptions {\n /** Handler for outbound fetch() calls from QuickJS */\n onFetch?: SetupFetchOptions[\"onFetch\"];\n}\n\nexport async function createFetchTestContext(\n options?: CreateFetchTestContextOptions\n): Promise<FetchTestContext> {\n const base = await createTestContext();\n const fetchHandle = setupFetch(base.context, {\n coreHandle: base.coreHandle,\n onFetch: options?.onFetch,\n });\n\n return { ...base, fetchHandle };\n}\n\nexport function disposeFetchTestContext(ctx: FetchTestContext): void {\n ctx.fetchHandle.dispose();\n disposeTestContext(ctx);\n}\n\n/**\n * Helper for use with beforeEach/afterEach for fetch tests\n *\n * @example\n * const testCtx = useFetchTestContext();\n *\n * beforeEach(async () => {\n * await testCtx.setup();\n * });\n *\n * afterEach(() => {\n * testCtx.teardown();\n * });\n *\n * test(\"headers test\", () => {\n * const result = evalCode(testCtx.context, `\n * const headers = new Headers({ \"Content-Type\": \"application/json\" });\n * headers.get(\"content-type\");\n * `);\n * expect(result).toBe(\"application/json\");\n * });\n */\nexport function useFetchTestContext() {\n let ctx: FetchTestContext | undefined;\n\n return {\n async setup() {\n ctx = await createFetchTestContext();\n return ctx;\n },\n teardown() {\n if (ctx) {\n disposeFetchTestContext(ctx);\n ctx = undefined;\n }\n },\n get context() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.context;\n },\n get runtime() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.runtime;\n },\n get coreHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.coreHandle;\n },\n get fetchHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.fetchHandle;\n },\n };\n}\n"
5
+ "import { setupFetch, type FetchHandle, type SetupFetchOptions } from \"@ricsam/quickjs-fetch\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.mjs\";\n\nexport interface FetchTestContext extends TestContext {\n fetchHandle: FetchHandle;\n}\n\nexport interface CreateFetchTestContextOptions {\n /** Handler for outbound fetch() calls from QuickJS */\n onFetch?: SetupFetchOptions[\"onFetch\"];\n}\n\nexport async function createFetchTestContext(\n options?: CreateFetchTestContextOptions\n): Promise<FetchTestContext> {\n const base = await createTestContext();\n const fetchHandle = setupFetch(base.context, {\n coreHandle: base.coreHandle,\n onFetch: options?.onFetch,\n });\n\n return { ...base, fetchHandle };\n}\n\nexport function disposeFetchTestContext(ctx: FetchTestContext): void {\n ctx.fetchHandle.dispose();\n disposeTestContext(ctx);\n}\n\n/**\n * Helper for use with beforeEach/afterEach for fetch tests\n *\n * @example\n * const testCtx = useFetchTestContext();\n *\n * beforeEach(async () => {\n * await testCtx.setup();\n * });\n *\n * afterEach(() => {\n * testCtx.teardown();\n * });\n *\n * test(\"headers test\", () => {\n * const result = evalCode(testCtx.context, `\n * const headers = new Headers({ \"Content-Type\": \"application/json\" });\n * headers.get(\"content-type\");\n * `);\n * expect(result).toBe(\"application/json\");\n * });\n */\nexport function useFetchTestContext() {\n let ctx: FetchTestContext | undefined;\n\n return {\n async setup() {\n ctx = await createFetchTestContext();\n return ctx;\n },\n teardown() {\n if (ctx) {\n disposeFetchTestContext(ctx);\n ctx = undefined;\n }\n },\n get context() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.context;\n },\n get runtime() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.runtime;\n },\n get coreHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.coreHandle;\n },\n get fetchHandle() {\n if (!ctx) throw new Error(\"FetchTestContext not initialized. Call setup() first.\");\n return ctx.fetchHandle;\n },\n };\n}\n"
6
6
  ],
7
7
  "mappings": ";;AAAA;AACA;AAAA;AAAA;AAAA;AAeA,eAAsB,sBAAsB,CAC1C,SAC2B;AAAA,EAC3B,MAAM,OAAO,MAAM,kBAAkB;AAAA,EACrC,MAAM,cAAc,WAAW,KAAK,SAAS;AAAA,IAC3C,YAAY,KAAK;AAAA,IACjB,SAAS,SAAS;AAAA,EACpB,CAAC;AAAA,EAED,OAAO,KAAK,MAAM,YAAY;AAAA;AAGzB,SAAS,uBAAuB,CAAC,KAA6B;AAAA,EACnE,IAAI,YAAY,QAAQ;AAAA,EACxB,mBAAmB,GAAG;AAAA;AAyBjB,SAAS,mBAAmB,GAAG;AAAA,EACpC,IAAI;AAAA,EAEJ,OAAO;AAAA,SACC,MAAK,GAAG;AAAA,MACZ,MAAM,MAAM,uBAAuB;AAAA,MACnC,OAAO;AAAA;AAAA,IAET,QAAQ,GAAG;AAAA,MACT,IAAI,KAAK;AAAA,QACP,wBAAwB,GAAG;AAAA,QAC3B,MAAM;AAAA,MACR;AAAA;AAAA,QAEE,OAAO,GAAG;AAAA,MACZ,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,QAET,OAAO,GAAG;AAAA,MACZ,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,QAET,UAAU,GAAG;AAAA,MACf,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,QAET,WAAW,GAAG;AAAA,MAChB,IAAI,CAAC;AAAA,QAAK,MAAM,IAAI,MAAM,uDAAuD;AAAA,MACjF,OAAO,IAAI;AAAA;AAAA,EAEf;AAAA;",
8
- "debugId": "2201FD7D87D68FCD64756E2164756E21",
8
+ "debugId": "CF92F143B1423A8864756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  createTestContext,
9
9
  disposeTestContext
10
- } from "./context.ts";
10
+ } from "./context.mjs";
11
11
  async function createFsTestContext(options) {
12
12
  const base = await createTestContext();
13
13
  const memFs = createMemoryDirectoryHandle(options?.initialFiles);
@@ -26,4 +26,4 @@ export {
26
26
  createFsTestContext
27
27
  };
28
28
 
29
- //# debugId=74ACBE63115AB11C64756E2164756E21
29
+ //# debugId=D2BFBDE97DC9750964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/fs-context.ts"],
4
4
  "sourcesContent": [
5
- "import {\n setupFs,\n createMemoryDirectoryHandle,\n type FsHandle,\n type HostDirectoryHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.ts\";\n\nexport interface FsTestContext extends TestContext {\n fsHandle: FsHandle;\n memFs: HostDirectoryHandle;\n}\n\nexport interface CreateFsTestContextOptions {\n /** Initial files to populate the in-memory filesystem */\n initialFiles?: Record<string, string | Uint8Array>;\n}\n\nexport async function createFsTestContext(\n options?: CreateFsTestContextOptions\n): Promise<FsTestContext> {\n const base = await createTestContext();\n const memFs = createMemoryDirectoryHandle(options?.initialFiles);\n const fsHandle = setupFs(base.context, {\n coreHandle: base.coreHandle,\n getDirectory: async () => memFs,\n });\n\n return { ...base, fsHandle, memFs };\n}\n\nexport function disposeFsTestContext(ctx: FsTestContext): void {\n ctx.fsHandle.dispose();\n disposeTestContext(ctx);\n}\n"
5
+ "import {\n setupFs,\n createMemoryDirectoryHandle,\n type FsHandle,\n type HostDirectoryHandle,\n} from \"@ricsam/quickjs-fs\";\nimport {\n createTestContext,\n disposeTestContext,\n type TestContext,\n} from \"./context.mjs\";\n\nexport interface FsTestContext extends TestContext {\n fsHandle: FsHandle;\n memFs: HostDirectoryHandle;\n}\n\nexport interface CreateFsTestContextOptions {\n /** Initial files to populate the in-memory filesystem */\n initialFiles?: Record<string, string | Uint8Array>;\n}\n\nexport async function createFsTestContext(\n options?: CreateFsTestContextOptions\n): Promise<FsTestContext> {\n const base = await createTestContext();\n const memFs = createMemoryDirectoryHandle(options?.initialFiles);\n const fsHandle = setupFs(base.context, {\n coreHandle: base.coreHandle,\n getDirectory: async () => memFs,\n });\n\n return { ...base, fsHandle, memFs };\n}\n\nexport function disposeFsTestContext(ctx: FsTestContext): void {\n ctx.fsHandle.dispose();\n disposeTestContext(ctx);\n}\n"
6
6
  ],
7
7
  "mappings": ";;AAAA;AAAA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAgBA,eAAsB,mBAAmB,CACvC,SACwB;AAAA,EACxB,MAAM,OAAO,MAAM,kBAAkB;AAAA,EACrC,MAAM,QAAQ,4BAA4B,SAAS,YAAY;AAAA,EAC/D,MAAM,WAAW,QAAQ,KAAK,SAAS;AAAA,IACrC,YAAY,KAAK;AAAA,IACjB,cAAc,YAAY;AAAA,EAC5B,CAAC;AAAA,EAED,OAAO,KAAK,MAAM,UAAU,MAAM;AAAA;AAG7B,SAAS,oBAAoB,CAAC,KAA0B;AAAA,EAC7D,IAAI,SAAS,QAAQ;AAAA,EACrB,mBAAmB,GAAG;AAAA;",
8
- "debugId": "74ACBE63115AB11C64756E2164756E21",
8
+ "debugId": "D2BFBDE97DC9750964756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -4,26 +4,26 @@ import {
4
4
  createTestContext,
5
5
  disposeTestContext,
6
6
  useTestContext
7
- } from "./context.ts";
7
+ } from "./context.mjs";
8
8
  import {
9
9
  createFetchTestContext,
10
10
  disposeFetchTestContext,
11
11
  useFetchTestContext
12
- } from "./fetch-context.ts";
13
- import { evalCode, evalCodeAsync } from "./eval.ts";
12
+ } from "./fetch-context.mjs";
13
+ import { evalCode, evalCodeAsync } from "./eval.mjs";
14
14
  import {
15
15
  startIntegrationServer
16
- } from "./integration-server.ts";
16
+ } from "./integration-server.mjs";
17
17
  import {
18
18
  typecheckQuickJSCode,
19
19
  formatTypecheckErrors
20
- } from "./typecheck.ts";
20
+ } from "./typecheck.mjs";
21
21
  import {
22
22
  CORE_TYPES,
23
23
  FETCH_TYPES,
24
24
  FS_TYPES,
25
25
  TYPE_DEFINITIONS
26
- } from "./quickjs-types.ts";
26
+ } from "./quickjs-types.mjs";
27
27
  export {
28
28
  useTestContext,
29
29
  useFetchTestContext,
@@ -42,4 +42,4 @@ export {
42
42
  CORE_TYPES
43
43
  };
44
44
 
45
- //# debugId=FD8F45F39BD927E164756E2164756E21
45
+ //# debugId=E7F326004DCE839564756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/index.ts"],
4
4
  "sourcesContent": [
5
- "export {\n createTestContext,\n disposeTestContext,\n useTestContext,\n type TestContext,\n} from \"./context.ts\";\n\nexport {\n createFetchTestContext,\n disposeFetchTestContext,\n useFetchTestContext,\n type FetchTestContext,\n type CreateFetchTestContextOptions,\n} from \"./fetch-context.ts\";\n\nexport { evalCode, evalCodeAsync } from \"./eval.ts\";\n\nexport {\n startIntegrationServer,\n type IntegrationTestServer,\n type StartIntegrationServerOptions,\n} from \"./integration-server.ts\";\n\nexport {\n typecheckQuickJSCode,\n formatTypecheckErrors,\n type TypecheckResult,\n type TypecheckError,\n type TypecheckOptions,\n} from \"./typecheck.ts\";\n\nexport {\n CORE_TYPES,\n FETCH_TYPES,\n FS_TYPES,\n TYPE_DEFINITIONS,\n type TypeDefinitionKey,\n} from \"./quickjs-types.ts\";\n\n// For fs and runtime contexts, import from subpaths:\n// import { createFsTestContext } from \"@ricsam/quickjs-test-utils/fs\";\n// import { createRuntimeTestContext } from \"@ricsam/quickjs-test-utils/runtime\";\n"
5
+ "export {\n createTestContext,\n disposeTestContext,\n useTestContext,\n type TestContext,\n} from \"./context.mjs\";\n\nexport {\n createFetchTestContext,\n disposeFetchTestContext,\n useFetchTestContext,\n type FetchTestContext,\n type CreateFetchTestContextOptions,\n} from \"./fetch-context.mjs\";\n\nexport { evalCode, evalCodeAsync } from \"./eval.mjs\";\n\nexport {\n startIntegrationServer,\n type IntegrationTestServer,\n type StartIntegrationServerOptions,\n} from \"./integration-server.mjs\";\n\nexport {\n typecheckQuickJSCode,\n formatTypecheckErrors,\n type TypecheckResult,\n type TypecheckError,\n type TypecheckOptions,\n} from \"./typecheck.mjs\";\n\nexport {\n CORE_TYPES,\n FETCH_TYPES,\n FS_TYPES,\n TYPE_DEFINITIONS,\n type TypeDefinitionKey,\n} from \"./quickjs-types.mjs\";\n\n// For fs and runtime contexts, import from subpaths:\n// import { createFsTestContext } from \"@ricsam/quickjs-test-utils/fs\";\n// import { createRuntimeTestContext } from \"@ricsam/quickjs-test-utils/runtime\";\n"
6
6
  ],
7
7
  "mappings": ";;AAAA;AAAA;AAAA;AAAA;AAAA;AAOA;AAAA;AAAA;AAAA;AAAA;AAQA;AAEA;AAAA;AAAA;AAMA;AAAA;AAAA;AAAA;AAQA;AAAA;AAAA;AAAA;AAAA;AAAA;",
8
- "debugId": "FD8F45F39BD927E164756E2164756E21",
8
+ "debugId": "E7F326004DCE839564756E2164756E21",
9
9
  "names": []
10
10
  }
@@ -1,5 +1,5 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-utils",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "type": "module"
5
5
  }
@@ -1,7 +1,7 @@
1
1
  // @bun
2
2
  // packages/test-utils/src/typecheck.ts
3
3
  import { Project, ts } from "ts-morph";
4
- import { TYPE_DEFINITIONS } from "./quickjs-types.ts";
4
+ import { TYPE_DEFINITIONS } from "./quickjs-types.mjs";
5
5
  function getMessageText(messageText) {
6
6
  if (typeof messageText === "string") {
7
7
  return messageText;
@@ -74,4 +74,4 @@ export {
74
74
  formatTypecheckErrors
75
75
  };
76
76
 
77
- //# debugId=5D284798E24F133564756E2164756E21
77
+ //# debugId=922DAD5DB1B8442964756E2164756E21
@@ -2,9 +2,9 @@
2
2
  "version": 3,
3
3
  "sources": ["../../src/typecheck.ts"],
4
4
  "sourcesContent": [
5
- "/**\n * Type-checking utility for QuickJS user code using ts-morph.\n *\n * This utility allows you to validate TypeScript code strings against\n * the QuickJS global type definitions before running them in the sandbox.\n *\n * @example\n * import { typecheckQuickJSCode } from \"@ricsam/quickjs-test-utils\";\n *\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * if (!result.success) {\n * console.error(\"Type errors:\", result.errors);\n * }\n */\n\nimport { Project, ts } from \"ts-morph\";\nimport { TYPE_DEFINITIONS, type TypeDefinitionKey } from \"./quickjs-types.ts\";\n\n/**\n * Result of type-checking QuickJS code.\n */\nexport interface TypecheckResult {\n /**\n * Whether the code passed type checking.\n */\n success: boolean;\n\n /**\n * Array of type errors found in the code.\n */\n errors: TypecheckError[];\n}\n\n/**\n * A single type-checking error.\n */\nexport interface TypecheckError {\n /**\n * The error message from TypeScript.\n */\n message: string;\n\n /**\n * The line number where the error occurred (1-indexed).\n */\n line?: number;\n\n /**\n * The column number where the error occurred (1-indexed).\n */\n column?: number;\n\n /**\n * The TypeScript error code.\n */\n code?: number;\n}\n\n/**\n * Options for type-checking QuickJS code.\n */\nexport interface TypecheckOptions {\n /**\n * Which package types to include.\n * @default [\"core\", \"fetch\", \"fs\"]\n */\n include?: Array<\"core\" | \"fetch\" | \"fs\">;\n\n /**\n * Additional compiler options to pass to TypeScript.\n */\n compilerOptions?: Partial<ts.CompilerOptions>;\n}\n\n/**\n * Get the message text from a TypeScript diagnostic message.\n * Handles both string messages and DiagnosticMessageChain objects.\n */\nfunction getMessageText(messageText: unknown): string {\n if (typeof messageText === \"string\") {\n return messageText;\n }\n\n // Handle ts-morph DiagnosticMessageChain wrapper\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"getMessageText\" in messageText &&\n typeof (messageText as { getMessageText: unknown }).getMessageText ===\n \"function\"\n ) {\n return (messageText as { getMessageText: () => string }).getMessageText();\n }\n\n // Handle raw TypeScript DiagnosticMessageChain\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"messageText\" in messageText\n ) {\n return String((messageText as { messageText: unknown }).messageText);\n }\n\n return String(messageText);\n}\n\n\n/**\n * Type-check QuickJS user code against the package type definitions.\n *\n * @param code - The TypeScript/JavaScript code to check\n * @param options - Configuration options\n * @returns The result of type checking\n *\n * @example\n * // Check code that uses the fetch API\n * const result = typecheckQuickJSCode(`\n * const response = await fetch(\"https://api.example.com/data\");\n * const data = await response.json();\n * `, { include: [\"core\", \"fetch\"] });\n *\n * @example\n * // Check code that uses serve()\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * @example\n * // Check code that uses the file system API\n * const result = typecheckQuickJSCode(`\n * const root = await fs.getDirectory(\"/data\");\n * const file = await root.getFileHandle(\"config.json\");\n * `, { include: [\"core\", \"fs\"] });\n */\nexport function typecheckQuickJSCode(\n code: string,\n options?: TypecheckOptions\n): TypecheckResult {\n const include = options?.include ?? [\"core\", \"fetch\", \"fs\"];\n\n // Create a project with in-memory file system\n const project = new Project({\n useInMemoryFileSystem: true,\n compilerOptions: {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext,\n lib: [\"lib.esnext.d.ts\", \"lib.dom.d.ts\"],\n strict: true,\n noEmit: true,\n skipLibCheck: true,\n ...options?.compilerOptions,\n },\n });\n\n // Add type definition files from embedded strings\n for (const pkg of include) {\n const content = TYPE_DEFINITIONS[pkg as TypeDefinitionKey];\n if (content) {\n project.createSourceFile(`${pkg}.d.ts`, content);\n }\n }\n\n // Add the user code\n const sourceFile = project.createSourceFile(\"usercode.ts\", code);\n\n // Get diagnostics\n const diagnostics = sourceFile.getPreEmitDiagnostics();\n\n // Convert diagnostics to our error format\n const errors: TypecheckError[] = diagnostics.map((diagnostic) => {\n const start = diagnostic.getStart();\n const sourceFile = diagnostic.getSourceFile();\n\n let line: number | undefined;\n let column: number | undefined;\n\n if (start !== undefined && sourceFile) {\n const lineAndChar = sourceFile.getLineAndColumnAtPos(start);\n line = lineAndChar.line;\n column = lineAndChar.column;\n }\n\n return {\n message: getMessageText(diagnostic.getMessageText()),\n line,\n column,\n code: diagnostic.getCode(),\n };\n });\n\n return {\n success: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Format type-check errors for display.\n *\n * @param result - The type-check result\n * @returns A formatted string of errors\n *\n * @example\n * const result = typecheckQuickJSCode(code);\n * if (!result.success) {\n * console.error(formatTypecheckErrors(result));\n * }\n */\nexport function formatTypecheckErrors(result: TypecheckResult): string {\n if (result.success) {\n return \"No type errors found.\";\n }\n\n return result.errors\n .map((error) => {\n const location =\n error.line !== undefined ? `:${error.line}:${error.column ?? 1}` : \"\";\n const code = error.code ? ` (TS${error.code})` : \"\";\n return `usercode.ts${location}${code}: ${error.message}`;\n })\n .join(\"\\n\");\n}\n"
5
+ "/**\n * Type-checking utility for QuickJS user code using ts-morph.\n *\n * This utility allows you to validate TypeScript code strings against\n * the QuickJS global type definitions before running them in the sandbox.\n *\n * @example\n * import { typecheckQuickJSCode } from \"@ricsam/quickjs-test-utils\";\n *\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * if (!result.success) {\n * console.error(\"Type errors:\", result.errors);\n * }\n */\n\nimport { Project, ts } from \"ts-morph\";\nimport { TYPE_DEFINITIONS, type TypeDefinitionKey } from \"./quickjs-types.mjs\";\n\n/**\n * Result of type-checking QuickJS code.\n */\nexport interface TypecheckResult {\n /**\n * Whether the code passed type checking.\n */\n success: boolean;\n\n /**\n * Array of type errors found in the code.\n */\n errors: TypecheckError[];\n}\n\n/**\n * A single type-checking error.\n */\nexport interface TypecheckError {\n /**\n * The error message from TypeScript.\n */\n message: string;\n\n /**\n * The line number where the error occurred (1-indexed).\n */\n line?: number;\n\n /**\n * The column number where the error occurred (1-indexed).\n */\n column?: number;\n\n /**\n * The TypeScript error code.\n */\n code?: number;\n}\n\n/**\n * Options for type-checking QuickJS code.\n */\nexport interface TypecheckOptions {\n /**\n * Which package types to include.\n * @default [\"core\", \"fetch\", \"fs\"]\n */\n include?: Array<\"core\" | \"fetch\" | \"fs\">;\n\n /**\n * Additional compiler options to pass to TypeScript.\n */\n compilerOptions?: Partial<ts.CompilerOptions>;\n}\n\n/**\n * Get the message text from a TypeScript diagnostic message.\n * Handles both string messages and DiagnosticMessageChain objects.\n */\nfunction getMessageText(messageText: unknown): string {\n if (typeof messageText === \"string\") {\n return messageText;\n }\n\n // Handle ts-morph DiagnosticMessageChain wrapper\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"getMessageText\" in messageText &&\n typeof (messageText as { getMessageText: unknown }).getMessageText ===\n \"function\"\n ) {\n return (messageText as { getMessageText: () => string }).getMessageText();\n }\n\n // Handle raw TypeScript DiagnosticMessageChain\n if (\n messageText &&\n typeof messageText === \"object\" &&\n \"messageText\" in messageText\n ) {\n return String((messageText as { messageText: unknown }).messageText);\n }\n\n return String(messageText);\n}\n\n\n/**\n * Type-check QuickJS user code against the package type definitions.\n *\n * @param code - The TypeScript/JavaScript code to check\n * @param options - Configuration options\n * @returns The result of type checking\n *\n * @example\n * // Check code that uses the fetch API\n * const result = typecheckQuickJSCode(`\n * const response = await fetch(\"https://api.example.com/data\");\n * const data = await response.json();\n * `, { include: [\"core\", \"fetch\"] });\n *\n * @example\n * // Check code that uses serve()\n * const result = typecheckQuickJSCode(`\n * serve({\n * fetch(request, server) {\n * return new Response(\"Hello!\");\n * }\n * });\n * `, { include: [\"fetch\"] });\n *\n * @example\n * // Check code that uses the file system API\n * const result = typecheckQuickJSCode(`\n * const root = await fs.getDirectory(\"/data\");\n * const file = await root.getFileHandle(\"config.json\");\n * `, { include: [\"core\", \"fs\"] });\n */\nexport function typecheckQuickJSCode(\n code: string,\n options?: TypecheckOptions\n): TypecheckResult {\n const include = options?.include ?? [\"core\", \"fetch\", \"fs\"];\n\n // Create a project with in-memory file system\n const project = new Project({\n useInMemoryFileSystem: true,\n compilerOptions: {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext,\n lib: [\"lib.esnext.d.ts\", \"lib.dom.d.ts\"],\n strict: true,\n noEmit: true,\n skipLibCheck: true,\n ...options?.compilerOptions,\n },\n });\n\n // Add type definition files from embedded strings\n for (const pkg of include) {\n const content = TYPE_DEFINITIONS[pkg as TypeDefinitionKey];\n if (content) {\n project.createSourceFile(`${pkg}.d.ts`, content);\n }\n }\n\n // Add the user code\n const sourceFile = project.createSourceFile(\"usercode.ts\", code);\n\n // Get diagnostics\n const diagnostics = sourceFile.getPreEmitDiagnostics();\n\n // Convert diagnostics to our error format\n const errors: TypecheckError[] = diagnostics.map((diagnostic) => {\n const start = diagnostic.getStart();\n const sourceFile = diagnostic.getSourceFile();\n\n let line: number | undefined;\n let column: number | undefined;\n\n if (start !== undefined && sourceFile) {\n const lineAndChar = sourceFile.getLineAndColumnAtPos(start);\n line = lineAndChar.line;\n column = lineAndChar.column;\n }\n\n return {\n message: getMessageText(diagnostic.getMessageText()),\n line,\n column,\n code: diagnostic.getCode(),\n };\n });\n\n return {\n success: errors.length === 0,\n errors,\n };\n}\n\n/**\n * Format type-check errors for display.\n *\n * @param result - The type-check result\n * @returns A formatted string of errors\n *\n * @example\n * const result = typecheckQuickJSCode(code);\n * if (!result.success) {\n * console.error(formatTypecheckErrors(result));\n * }\n */\nexport function formatTypecheckErrors(result: TypecheckResult): string {\n if (result.success) {\n return \"No type errors found.\";\n }\n\n return result.errors\n .map((error) => {\n const location =\n error.line !== undefined ? `:${error.line}:${error.column ?? 1}` : \"\";\n const code = error.code ? ` (TS${error.code})` : \"\";\n return `usercode.ts${location}${code}: ${error.message}`;\n })\n .join(\"\\n\");\n}\n"
6
6
  ],
7
7
  "mappings": ";;AAsBA;AACA;AA8DA,SAAS,cAAc,CAAC,aAA8B;AAAA,EACpD,IAAI,OAAO,gBAAgB,UAAU;AAAA,IACnC,OAAO;AAAA,EACT;AAAA,EAGA,IACE,eACA,OAAO,gBAAgB,YACvB,oBAAoB,eACpB,OAAQ,YAA4C,mBAClD,YACF;AAAA,IACA,OAAQ,YAAiD,eAAe;AAAA,EAC1E;AAAA,EAGA,IACE,eACA,OAAO,gBAAgB,YACvB,iBAAiB,aACjB;AAAA,IACA,OAAO,OAAQ,YAAyC,WAAW;AAAA,EACrE;AAAA,EAEA,OAAO,OAAO,WAAW;AAAA;AAmCpB,SAAS,oBAAoB,CAClC,MACA,SACiB;AAAA,EACjB,MAAM,UAAU,SAAS,WAAW,CAAC,QAAQ,SAAS,IAAI;AAAA,EAG1D,MAAM,UAAU,IAAI,QAAQ;AAAA,IAC1B,uBAAuB;AAAA,IACvB,iBAAiB;AAAA,MACf,QAAQ,GAAG,aAAa;AAAA,MACxB,QAAQ,GAAG,WAAW;AAAA,MACtB,KAAK,CAAC,mBAAmB,cAAc;AAAA,MACvC,QAAQ;AAAA,MACR,QAAQ;AAAA,MACR,cAAc;AAAA,SACX,SAAS;AAAA,IACd;AAAA,EACF,CAAC;AAAA,EAGD,WAAW,OAAO,SAAS;AAAA,IACzB,MAAM,UAAU,iBAAiB;AAAA,IACjC,IAAI,SAAS;AAAA,MACX,QAAQ,iBAAiB,GAAG,YAAY,OAAO;AAAA,IACjD;AAAA,EACF;AAAA,EAGA,MAAM,aAAa,QAAQ,iBAAiB,eAAe,IAAI;AAAA,EAG/D,MAAM,cAAc,WAAW,sBAAsB;AAAA,EAGrD,MAAM,SAA2B,YAAY,IAAI,CAAC,eAAe;AAAA,IAC/D,MAAM,QAAQ,WAAW,SAAS;AAAA,IAClC,MAAM,cAAa,WAAW,cAAc;AAAA,IAE5C,IAAI;AAAA,IACJ,IAAI;AAAA,IAEJ,IAAI,UAAU,aAAa,aAAY;AAAA,MACrC,MAAM,cAAc,YAAW,sBAAsB,KAAK;AAAA,MAC1D,OAAO,YAAY;AAAA,MACnB,SAAS,YAAY;AAAA,IACvB;AAAA,IAEA,OAAO;AAAA,MACL,SAAS,eAAe,WAAW,eAAe,CAAC;AAAA,MACnD;AAAA,MACA;AAAA,MACA,MAAM,WAAW,QAAQ;AAAA,IAC3B;AAAA,GACD;AAAA,EAED,OAAO;AAAA,IACL,SAAS,OAAO,WAAW;AAAA,IAC3B;AAAA,EACF;AAAA;AAeK,SAAS,qBAAqB,CAAC,QAAiC;AAAA,EACrE,IAAI,OAAO,SAAS;AAAA,IAClB,OAAO;AAAA,EACT;AAAA,EAEA,OAAO,OAAO,OACX,IAAI,CAAC,UAAU;AAAA,IACd,MAAM,WACJ,MAAM,SAAS,YAAY,IAAI,MAAM,QAAQ,MAAM,UAAU,MAAM;AAAA,IACrE,MAAM,OAAO,MAAM,OAAO,OAAO,MAAM,UAAU;AAAA,IACjD,OAAO,cAAc,WAAW,SAAS,MAAM;AAAA,GAChD,EACA,KAAK;AAAA,CAAI;AAAA;",
8
- "debugId": "5D284798E24F133564756E2164756E21",
8
+ "debugId": "922DAD5DB1B8442964756E2164756E21",
9
9
  "names": []
10
10
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ricsam/quickjs-test-utils",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "main": "./dist/cjs/index.cjs",
5
5
  "types": "./dist/types/index.d.ts",
6
6
  "exports": {
@@ -20,10 +20,10 @@
20
20
  },
21
21
  "peerDependencies": {
22
22
  "quickjs-emscripten": "^0.31.0",
23
- "@ricsam/quickjs-core": "^0.2.1",
24
- "@ricsam/quickjs-fetch": "^0.2.1",
25
- "@ricsam/quickjs-fs": "^0.2.1",
26
- "@ricsam/quickjs-runtime": "^0.2.1"
23
+ "@ricsam/quickjs-core": "^0.2.2",
24
+ "@ricsam/quickjs-fetch": "^0.2.2",
25
+ "@ricsam/quickjs-fs": "^0.2.2",
26
+ "@ricsam/quickjs-runtime": "^0.2.2"
27
27
  },
28
28
  "peerDependenciesMeta": {
29
29
  "@ricsam/quickjs-fs": {