fix(ts-core): resolve installed compiler and SQLite modules (#389)
- Resolve scriptc through npm package resolution so nested, hoisted, and global sibling installs work. - Generate a complete SQLite SDK module family and validate library imports against their actual directory. - Cover global compiler lookup, documented event imports, and generated-core loading with regressions.
This commit is contained in:
@@ -859,7 +859,10 @@ pub fn build(b: *std.Build) void {
|
||||
.{ .path = "packages/core/scripts/embed_markup_c.mjs", .pattern = "const unsigned char native_sdk_app_markup[]" },
|
||||
.{ .path = "build/app.zig", .pattern = "node_modules\", \"scriptc\", \"dist\", \"bootstrap.js\"" },
|
||||
.{ .path = "build/app.zig", .pattern = "setEnvironmentVariable(\"SCRIPTC_TIMING\", \"1\")" },
|
||||
.{ .path = "build/app.zig", .pattern = "node_modules\", \".bin\", if (builtin.os.tag == .windows) \"scriptc.cmd\" else \"scriptc\"" },
|
||||
.{ .path = "build/app.zig", .pattern = "service_compile.addArg(\"--compiler-package-origin\")" },
|
||||
.{ .path = "build/app.zig", .pattern = "compile.addArg(\"--compiler-package-origin\")" },
|
||||
.{ .path = "packages/core/scripts/run_external_core_compiler.mjs", .pattern = "publishedScriptcArgv(args[\"compiler-package-origin\"])" },
|
||||
.{ .path = "packages/core/scripts/run_external_service_compiler.mjs", .pattern = "publishedScriptcArgv(args[\"compiler-package-origin\"])" },
|
||||
.{ .path = "build/app.zig", .pattern = "addFileInput(dep.path(\"packages/core/scripts/compiler_command.mjs\"))" },
|
||||
.{ .path = "packages/core/scripts/run_external_core_compiler.mjs", .pattern = "compilerArgv(args.compiler)" },
|
||||
.{ .path = "packages/core/scripts/run_external_service_compiler.mjs", .pattern = "compilerArgv(args.compiler)" },
|
||||
|
||||
+20
-46
@@ -708,48 +708,6 @@ fn tsParseQuotedManifestValue(manifest_json: []const u8, comptime key: []const u
|
||||
return suffix;
|
||||
}
|
||||
|
||||
/// The external compiler's published `scriptc` binary entrypoint,
|
||||
/// resolved by node's ancestor node_modules walk from the SDK's
|
||||
/// packages/core — the same origin the frontend toolchain resolves from
|
||||
/// (tsAliasedCompilerVersion's walk, kept in lockstep). Repo checkouts
|
||||
/// install it there with `npm ci`; the npm-installed CLI carries the
|
||||
/// compiler as a regular dependency, nested under the package on global
|
||||
/// prefixes and hoisted to the project root on local ones.
|
||||
fn tsExternalCompilerBin(b: *std.Build, dep: *std.Build.Dependency) ?[]const u8 {
|
||||
const io = b.graph.io;
|
||||
const sdk_root = tsSdkRoot(b.allocator, io, dep);
|
||||
var dir: []const u8 = b.pathJoin(&.{ sdk_root, "packages", "core" });
|
||||
while (true) {
|
||||
if (!std.mem.eql(u8, std.fs.path.basename(dir), "node_modules")) {
|
||||
const candidate = b.pathJoin(&.{ dir, "node_modules", ".bin", if (builtin.os.tag == .windows) "scriptc.cmd" else "scriptc" });
|
||||
found: {
|
||||
std.Io.Dir.cwd().access(io, candidate, .{}) catch break :found;
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
dir = std.fs.path.dirname(dir) orelse return null;
|
||||
}
|
||||
}
|
||||
|
||||
fn requireTsExternalCompilerBin(b: *std.Build, dep: *std.Build.Dependency) []const u8 {
|
||||
return tsExternalCompilerBin(b, dep) orelse {
|
||||
const sdk_root = tsSdkRoot(dep.builder.allocator, dep.builder.graph.io, dep);
|
||||
std.debug.print(
|
||||
\\
|
||||
\\error: the external TypeScript compiler is not installed (cores and services
|
||||
\\compile through it). It ships as an exact-pinned dependency of the SDK's
|
||||
\\packages/core — install it once with:
|
||||
\\ cd {s}/packages/core && npm ci
|
||||
\\(or point NATIVE_SDK_CORE_COMPILER at the pinned release's command; an
|
||||
\\npm-installed @native-sdk/cli carries the compiler automatically — if it is
|
||||
\\missing there, the install is broken: reinstall @native-sdk/cli).
|
||||
\\
|
||||
\\
|
||||
, .{sdk_root});
|
||||
std.process.exit(1);
|
||||
};
|
||||
}
|
||||
|
||||
/// PR 166 adds both the published compile-cache bootstrap and the optional
|
||||
/// library-profile optimization field. The installed bootstrap is therefore
|
||||
/// the capability marker: keep older exact pins byte-for-byte compatible;
|
||||
@@ -934,6 +892,16 @@ fn tsCoreStage(
|
||||
sqlite_check.addFileArg(dep.path("packages/core/compile-surface/core.ts"));
|
||||
sqlite_check.addArg("--sdk-out");
|
||||
checked_sdk_core = sqlite_check.addOutputFileArg("core.ts");
|
||||
sqlite_check.addArg("--sdk-events-out");
|
||||
_ = sqlite_check.addOutputFileArg("events.ts");
|
||||
sqlite_check.addArg("--sdk-text-out");
|
||||
_ = sqlite_check.addOutputFileArg("text.ts");
|
||||
sqlite_check.addArg("--sdk-bytes-text-methods-out");
|
||||
_ = sqlite_check.addOutputFileArg("bytes_text_methods.d.ts");
|
||||
sqlite_check.addArg("--sdk-events-dts-out");
|
||||
_ = sqlite_check.addOutputFileArg("events.d.ts");
|
||||
sqlite_check.addArg("--sdk-text-dts-out");
|
||||
_ = sqlite_check.addOutputFileArg("text.d.ts");
|
||||
sqlite_check.addArg("--static-out");
|
||||
checked_static_core = sqlite_check.addOutputFileArg("core_static.ts");
|
||||
sqlite_check.addArg("--zig-out");
|
||||
@@ -946,6 +914,9 @@ fn tsCoreStage(
|
||||
}
|
||||
sqlite_check.addFileInput(dep.path("packages/core/src/sqlite_codegen.ts"));
|
||||
sqlite_check.addFileInput(dep.path("packages/core/src/sqlite_runtime_policy.ts"));
|
||||
for ([_][]const u8{ "events.ts", "text.ts", "bytes_text_methods.d.ts", "events.d.ts", "text.d.ts" }) |source| {
|
||||
sqlite_check.addFileInput(dep.path(b.fmt("packages/core/sdk/{s}", .{source})));
|
||||
}
|
||||
addAppSqlDirInputs(b, sqlite_check, appPath(b, app_root, "src"));
|
||||
}
|
||||
|
||||
@@ -1119,8 +1090,11 @@ fn tsCoreStage(
|
||||
if (b.graph.environ_map.get("NATIVE_SDK_CORE_COMPILER")) |override| {
|
||||
service_compile.addArgs(&.{ "--compiler", override });
|
||||
} else {
|
||||
const compiler_bin = requireTsExternalCompilerBin(b, dep);
|
||||
service_compile.addArgs(&.{ "--compiler", compiler_bin });
|
||||
// Let Node resolve the dependency from the SDK package origin:
|
||||
// this is npm's own nested/hoisted/global-sibling walk, and the
|
||||
// driver follows scriptc's published `bin` declaration.
|
||||
service_compile.addArg("--compiler-package-origin");
|
||||
service_compile.addFileArg(dep.path("packages/core/package.json"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1190,8 +1164,8 @@ fn tsCoreStage(
|
||||
// driver still refuses a release other than the SDK's pin.
|
||||
compile.addArgs(&.{ "--compiler", override });
|
||||
} else {
|
||||
const compiler_bin = requireTsExternalCompilerBin(b, dep);
|
||||
compile.addArgs(&.{ "--compiler", compiler_bin });
|
||||
compile.addArg("--compiler-package-origin");
|
||||
compile.addFileArg(dep.path("packages/core/package.json"));
|
||||
}
|
||||
|
||||
// The mirror, generated from the archive's OWN co-emitted contract.
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
// --out-sidecar <file>
|
||||
// [--host-platform <arch-os-abi> --target-platform <arch-os-abi>
|
||||
// --zig-exe <path>] [--android-ndk <dir>]
|
||||
// (--compiler <cmd> | --compiler-js <main.js>)
|
||||
// (--compiler <cmd> | --compiler-js <main.js> |
|
||||
// --compiler-package-origin <packages/core/package.json>)
|
||||
|
||||
import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { compilerArgv } from "./compiler_command.mjs";
|
||||
import { compilerArgv, publishedScriptcArgv } from "./compiler_command.mjs";
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = {};
|
||||
@@ -28,7 +29,7 @@ function parseArgs(argv) {
|
||||
const key = argv[i];
|
||||
const value = argv[i + 1];
|
||||
if (!key.startsWith("--") || value === undefined) {
|
||||
console.error("usage: run_external_core_compiler.mjs --stage <dir> --name <n> --manifest <package.json> --frontend-sidecar <file> --out-archive <file> --out-sidecar <file> [--host-platform <arch-os-abi> --target-platform <arch-os-abi> --zig-exe <path>] (--compiler <cmd> | --compiler-js <main.js>)");
|
||||
console.error("usage: run_external_core_compiler.mjs --stage <dir> --name <n> --manifest <package.json> --frontend-sidecar <file> --out-archive <file> --out-sidecar <file> [--host-platform <arch-os-abi> --target-platform <arch-os-abi> --zig-exe <path>] (--compiler <cmd> | --compiler-js <main.js> | --compiler-package-origin <package.json>)");
|
||||
process.exit(2);
|
||||
}
|
||||
args[key.slice(2)] = value;
|
||||
@@ -39,8 +40,9 @@ function parseArgs(argv) {
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
if (!args.compiler && !args["compiler-js"]) {
|
||||
console.error("run_external_core_compiler.mjs: supply --compiler <cmd> or --compiler-js <main.js>");
|
||||
const compilerModes = [args.compiler, args["compiler-js"], args["compiler-package-origin"]].filter(Boolean);
|
||||
if (compilerModes.length !== 1) {
|
||||
console.error("run_external_core_compiler.mjs: supply exactly one of --compiler <cmd>, --compiler-js <main.js>, or --compiler-package-origin <package.json>");
|
||||
process.exit(2);
|
||||
}
|
||||
if (Boolean(args["host-platform"]) !== Boolean(args["target-platform"])) {
|
||||
@@ -53,15 +55,23 @@ function parseArgs(argv) {
|
||||
const args = parseArgs(process.argv);
|
||||
// Every path argument resolves against the INVOCATION's cwd up front:
|
||||
// the compile itself runs from a scratch directory.
|
||||
for (const key of ["stage", "manifest", "frontend-sidecar", "out-archive", "out-sidecar", "compiler-js", "zig-exe", "android-ndk"]) {
|
||||
for (const key of ["stage", "manifest", "frontend-sidecar", "out-archive", "out-sidecar", "compiler-js", "compiler-package-origin", "zig-exe", "android-ndk"]) {
|
||||
if (key in args) args[key] = path.resolve(args[key]);
|
||||
}
|
||||
// --compiler is a COMMAND: a bare executable path (possibly containing
|
||||
// spaces) or an interpreter plus script ("node .../main.js"). The shared
|
||||
// resolver also unwraps npm's Windows .cmd shim to its declared JS bin.
|
||||
const argv0 = args.compiler
|
||||
? compilerArgv(args.compiler)
|
||||
: [process.execPath, args["compiler-js"]];
|
||||
let argv0;
|
||||
try {
|
||||
argv0 = args.compiler
|
||||
? compilerArgv(args.compiler)
|
||||
: args["compiler-js"]
|
||||
? [process.execPath, args["compiler-js"]]
|
||||
: publishedScriptcArgv(args["compiler-package-origin"]);
|
||||
} catch (error) {
|
||||
console.error(`the external TypeScript compiler is not installed or has no valid published bin: ${error instanceof Error ? error.message : String(error)} — reinstall @native-sdk/cli, or point NATIVE_SDK_CORE_COMPILER at the pinned release's command`);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// App and fixture build graphs state the host and target explicitly. A
|
||||
// differing target must compile the core archive through the same ScriptC
|
||||
|
||||
@@ -17,7 +17,7 @@ import { spawnSync } from "node:child_process";
|
||||
import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { compilerArgv } from "./compiler_command.mjs";
|
||||
import { compilerArgv, publishedScriptcArgv } from "./compiler_command.mjs";
|
||||
|
||||
function parseArgs(argv) {
|
||||
const args = {};
|
||||
@@ -25,7 +25,7 @@ function parseArgs(argv) {
|
||||
const key = argv[i];
|
||||
const value = argv[i + 1];
|
||||
if (!key?.startsWith("--") || value === undefined) {
|
||||
console.error("usage: run_external_service_compiler.mjs --stage <dir> --manifest <package.json> --contract <services.contract.json> (--out-exe <file> | --out-archive <file>) --host-platform <arch-os-abi> --target-platform <arch-os-abi> [--zig-exe <path>] [--android-ndk <dir>] (--compiler <cmd> | --compiler-js <main.js>)");
|
||||
console.error("usage: run_external_service_compiler.mjs --stage <dir> --manifest <package.json> --contract <services.contract.json> (--out-exe <file> | --out-archive <file>) --host-platform <arch-os-abi> --target-platform <arch-os-abi> [--zig-exe <path>] [--android-ndk <dir>] (--compiler <cmd> | --compiler-js <main.js> | --compiler-package-origin <package.json>)");
|
||||
process.exit(2);
|
||||
}
|
||||
args[key.slice(2)] = value;
|
||||
@@ -40,8 +40,9 @@ function parseArgs(argv) {
|
||||
console.error("run_external_service_compiler.mjs: supply --out-exe, --out-archive, or both");
|
||||
process.exit(2);
|
||||
}
|
||||
if (!args.compiler && !args["compiler-js"]) {
|
||||
console.error("run_external_service_compiler.mjs: supply --compiler or --compiler-js");
|
||||
const compilerModes = [args.compiler, args["compiler-js"], args["compiler-package-origin"]].filter(Boolean);
|
||||
if (compilerModes.length !== 1) {
|
||||
console.error("run_external_service_compiler.mjs: supply exactly one of --compiler, --compiler-js, or --compiler-package-origin");
|
||||
process.exit(2);
|
||||
}
|
||||
return args;
|
||||
@@ -140,12 +141,20 @@ if (args["out-archive"]) {
|
||||
process.exit(2);
|
||||
}
|
||||
}
|
||||
for (const key of ["stage", "manifest", "contract", "out-exe", "out-archive", "compiler-js", "zig-exe", "android-ndk"]) {
|
||||
for (const key of ["stage", "manifest", "contract", "out-exe", "out-archive", "compiler-js", "compiler-package-origin", "zig-exe", "android-ndk"]) {
|
||||
if (args[key]) args[key] = path.resolve(args[key]);
|
||||
}
|
||||
const argv0 = args.compiler
|
||||
? compilerArgv(args.compiler)
|
||||
: [process.execPath, args["compiler-js"]];
|
||||
let argv0;
|
||||
try {
|
||||
argv0 = args.compiler
|
||||
? compilerArgv(args.compiler)
|
||||
: args["compiler-js"]
|
||||
? [process.execPath, args["compiler-js"]]
|
||||
: publishedScriptcArgv(args["compiler-package-origin"]);
|
||||
} catch (error) {
|
||||
console.error(`the external TypeScript compiler is not installed or has no valid published bin: ${error instanceof Error ? error.message : String(error)} — reinstall @native-sdk/cli, or point NATIVE_SDK_CORE_COMPILER at the pinned release's command`);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
// Cross compiles hand the compiler its zig-cc lane: the target triple as
|
||||
// SCRIPTC_TARGET (the compiler's own mobile spellings for iOS/Android), and
|
||||
|
||||
@@ -83,7 +83,6 @@ export function resolveModuleGraph(
|
||||
const entryPath = path.resolve(entry);
|
||||
const boundary = path.dirname(entryPath);
|
||||
const servicesBoundary = path.join(boundary, "services");
|
||||
const sdkBoundary = path.dirname(coreModulePath);
|
||||
const diagnostics: SubsetDiagnostic[] = [];
|
||||
const files: string[] = [];
|
||||
const coreFiles: string[] = [];
|
||||
@@ -133,7 +132,12 @@ export function resolveModuleGraph(
|
||||
const text = fs.readFileSync(filePath, "utf8");
|
||||
const parsed = ts.createSourceFile(filePath, text, ts.ScriptTarget.ESNext, true);
|
||||
const isSdk = sdkFiles.has(filePath);
|
||||
const root = isSdk ? sdkBoundary : boundary;
|
||||
// A generated relational core may live under .native/cache while the
|
||||
// published library modules still resolve from the SDK package. Fence a
|
||||
// library module against its own module directory, not the generated
|
||||
// intrinsic core's directory; otherwise events.ts's valid ./text.ts
|
||||
// re-export is falsely diagnosed as escaping the SDK.
|
||||
const root = isSdk ? path.dirname(filePath) : boundary;
|
||||
|
||||
for (const edge of edgesOf(parsed)) {
|
||||
const spec = edge.specifier;
|
||||
|
||||
@@ -21,15 +21,25 @@ try {
|
||||
const sdkIn = args.get("sdk-in");
|
||||
const staticIn = args.get("static-in");
|
||||
const sdkOut = args.get("sdk-out");
|
||||
const sdkEventsOut = args.get("sdk-events-out");
|
||||
const sdkTextOut = args.get("sdk-text-out");
|
||||
const sdkBytesTextMethodsOut = args.get("sdk-bytes-text-methods-out");
|
||||
const sdkEventsDtsOut = args.get("sdk-events-dts-out");
|
||||
const sdkTextDtsOut = args.get("sdk-text-dts-out");
|
||||
const staticOut = args.get("static-out");
|
||||
const zigOut = args.get("zig-out");
|
||||
const metadataOut = args.get("metadata-out");
|
||||
const dtsOut = args.get("dts-out");
|
||||
const state = args.get("state");
|
||||
if (!zigOut) throw new Error("usage: sqlite_cli.ts --src <src> --zig-out <file> [--sdk-in <core.ts> --static-in <core.ts> --sdk-out <file> --static-out <file> --metadata-out <file>] [--state <file>]");
|
||||
const surfaceArgs = [sdkIn, staticIn, sdkOut, staticOut];
|
||||
const surfaceArgs = [
|
||||
sdkIn, staticIn, sdkOut, staticOut,
|
||||
sdkEventsOut, sdkTextOut, sdkBytesTextMethodsOut, sdkEventsDtsOut, sdkTextDtsOut,
|
||||
];
|
||||
const emitsSurface = surfaceArgs.every((value) => value !== undefined);
|
||||
if (!emitsSurface && surfaceArgs.some((value) => value !== undefined)) throw new Error("SQLite SDK generation requires --sdk-in, --static-in, --sdk-out, and --static-out together");
|
||||
if (!emitsSurface && surfaceArgs.some((value) => value !== undefined)) {
|
||||
throw new Error("SQLite SDK generation requires its core, static, and SDK sibling outputs together");
|
||||
}
|
||||
const analysis = analyzeSqlite(src);
|
||||
const diagnostics = [...analysis.diagnostics, ...(state ? checkMigrationState(analysis, state) : [])];
|
||||
for (const diagnostic of [...diagnostics, ...analysis.warnings]) console.error(formatSqliteDiagnostic(diagnostic));
|
||||
@@ -37,6 +47,16 @@ try {
|
||||
if (emitsSurface) {
|
||||
const sdkSource = generateCoreSurface(fs.readFileSync(sdkIn!, "utf8"), analysis);
|
||||
fs.writeFileSync(sdkOut!, sdkSource);
|
||||
const sdkDir = path.dirname(sdkIn!);
|
||||
for (const [source, destination] of [
|
||||
["events.ts", sdkEventsOut!],
|
||||
["text.ts", sdkTextOut!],
|
||||
["bytes_text_methods.d.ts", sdkBytesTextMethodsOut!],
|
||||
["events.d.ts", sdkEventsDtsOut!],
|
||||
["text.d.ts", sdkTextDtsOut!],
|
||||
] as const) {
|
||||
fs.copyFileSync(path.join(sdkDir, source), destination);
|
||||
}
|
||||
if (dtsOut) {
|
||||
const compilerOptions: ts.CompilerOptions = {
|
||||
strict: true,
|
||||
|
||||
@@ -7,6 +7,59 @@ import { test } from "node:test";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { scriptcPin } from "./helpers.ts";
|
||||
|
||||
test("the external core compile lane resolves a global-sibling scriptc package", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "native-core-global-scriptc-"));
|
||||
try {
|
||||
const globalModules = path.join(root, "lib", "node_modules");
|
||||
const sdkCore = path.join(globalModules, "@native-sdk", "cli", "packages", "core");
|
||||
const scriptcRoot = path.join(globalModules, "scriptc");
|
||||
const compiler = path.join(scriptcRoot, "dist", "bootstrap.js");
|
||||
const stage = path.join(root, "stage");
|
||||
fs.mkdirSync(sdkCore, { recursive: true });
|
||||
fs.mkdirSync(path.dirname(compiler), { recursive: true });
|
||||
fs.mkdirSync(stage);
|
||||
fs.writeFileSync(path.join(stage, "profile.json"), "{}\n");
|
||||
const manifest = path.join(sdkCore, "package.json");
|
||||
fs.writeFileSync(manifest, JSON.stringify({ dependencies: { scriptc: scriptcPin } }));
|
||||
fs.writeFileSync(path.join(scriptcRoot, "package.json"), JSON.stringify({
|
||||
name: "scriptc",
|
||||
version: scriptcPin,
|
||||
type: "module",
|
||||
bin: { scriptc: "dist/bootstrap.js" },
|
||||
}));
|
||||
fs.writeFileSync(compiler, `
|
||||
import fs from "node:fs";
|
||||
if (process.argv.includes("-v")) { console.log(${JSON.stringify(scriptcPin)}); process.exit(0); }
|
||||
const output = process.argv[process.argv.indexOf("-o") + 1];
|
||||
fs.writeFileSync(output + ".lib.a", "global sibling archive");
|
||||
fs.writeFileSync("core.contract.json", JSON.stringify({ build_id: "global-sibling", model_unbound: [], msg: { unbound: [] } }));
|
||||
`);
|
||||
const frontendSidecar = path.join(root, "frontend.contract.json");
|
||||
fs.writeFileSync(frontendSidecar, JSON.stringify({
|
||||
model_fingerprint: "0123456789abcdef",
|
||||
has_migrate: false,
|
||||
model_unbound: [],
|
||||
msg: { unbound: [] },
|
||||
}));
|
||||
const script = path.join(path.dirname(fileURLToPath(import.meta.url)), "..", "scripts", "run_external_core_compiler.mjs");
|
||||
const archive = path.join(root, "libfixture_core.a");
|
||||
const result = spawnSync(process.execPath, [
|
||||
script,
|
||||
"--stage", stage,
|
||||
"--name", "fixture_core",
|
||||
"--manifest", manifest,
|
||||
"--frontend-sidecar", frontendSidecar,
|
||||
"--out-archive", archive,
|
||||
"--out-sidecar", path.join(root, "compiled.contract.json"),
|
||||
"--compiler-package-origin", manifest,
|
||||
], { encoding: "utf8" });
|
||||
assert.equal(result.status, 0, `${result.stdout}${result.stderr}`);
|
||||
assert.equal(fs.readFileSync(archive, "utf8"), "global sibling archive");
|
||||
} finally {
|
||||
fs.rmSync(root, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("the external core compile lane uses the target-aware zig-cc environment", () => {
|
||||
const root = fs.mkdtempSync(path.join(os.tmpdir(), "native-core-cross-"));
|
||||
try {
|
||||
|
||||
@@ -61,7 +61,11 @@ test("a generated SQLite SDK surface and typed services share one checked progra
|
||||
try {
|
||||
fs.cpSync(path.join(packageDir, "sdk"), generatedDir, { recursive: true });
|
||||
const result = checkFiles({
|
||||
"core.ts": serviceCore,
|
||||
"core.ts": `
|
||||
import type { WindowDescriptor } from "@native-sdk/core/events";
|
||||
${serviceCore}
|
||||
export function windows(_model: Model): readonly WindowDescriptor[] { return []; }
|
||||
`,
|
||||
"services/feeds.ts": `export function parse(bytes: Uint8Array): Uint8Array { return bytes; }`,
|
||||
}, {
|
||||
contractEntry: "src/core.ts",
|
||||
|
||||
@@ -3,6 +3,8 @@ import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import test from "node:test";
|
||||
import { spawnSync } from "node:child_process";
|
||||
import { pathToFileURL, fileURLToPath } from "node:url";
|
||||
import { analyzeSqlite, checkMigrationState, generateCoreSurface, generateMigrationsZig } from "../src/sqlite_codegen.ts";
|
||||
import { inspectRelationalSql } from "../src/sqlite_runtime_policy.ts";
|
||||
|
||||
@@ -22,6 +24,43 @@ UPDATE note SET folder_id = :to WHERE id = :id;
|
||||
return root;
|
||||
}
|
||||
|
||||
test("the SQLite CLI emits a complete loadable SDK module directory", async () => {
|
||||
const src = fixture();
|
||||
const out = fs.mkdtempSync(path.join(os.tmpdir(), "native-sqlite-sdk-"));
|
||||
const packageDir = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
||||
try {
|
||||
const args = [
|
||||
path.join(packageDir, "src", "sqlite_cli.ts"),
|
||||
"--src", src,
|
||||
"--sdk-in", path.join(packageDir, "sdk", "core.ts"),
|
||||
"--static-in", path.join(packageDir, "compile-surface", "core.ts"),
|
||||
"--sdk-out", path.join(out, "core.ts"),
|
||||
"--dts-out", path.join(out, "core.d.ts"),
|
||||
"--static-out", path.join(out, "core_static.ts"),
|
||||
"--sdk-events-out", path.join(out, "events.ts"),
|
||||
"--sdk-text-out", path.join(out, "text.ts"),
|
||||
"--sdk-bytes-text-methods-out", path.join(out, "bytes_text_methods.d.ts"),
|
||||
"--sdk-events-dts-out", path.join(out, "events.d.ts"),
|
||||
"--sdk-text-dts-out", path.join(out, "text.d.ts"),
|
||||
"--zig-out", path.join(out, "migrations.zig"),
|
||||
"--metadata-out", path.join(out, "metadata.json"),
|
||||
];
|
||||
const run = spawnSync(process.execPath, args, { encoding: "utf8" });
|
||||
assert.equal(run.status, 0, `${run.stdout}${run.stderr}`);
|
||||
for (const file of [
|
||||
"core.ts", "core.d.ts", "core_static.ts", "events.ts", "text.ts",
|
||||
"bytes_text_methods.d.ts", "events.d.ts", "text.d.ts", "migrations.zig", "metadata.json",
|
||||
]) {
|
||||
assert.equal(fs.existsSync(path.join(out, file)), true, `${file} was not generated`);
|
||||
}
|
||||
const generated = await import(`${pathToFileURL(path.join(out, "core.ts")).href}?test=${Date.now()}`);
|
||||
assert.equal(typeof generated.windowDescriptor, "function");
|
||||
} finally {
|
||||
fs.rmSync(src, { recursive: true, force: true });
|
||||
fs.rmSync(out, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
|
||||
test("real SQLite validates migrations and emits typed query/live constructors", () => {
|
||||
const root = fixture();
|
||||
try {
|
||||
|
||||
+11
-7
@@ -480,13 +480,17 @@ pub fn generateSqliteSurface(
|
||||
errdefer allocator.free(sdk_out);
|
||||
var child = std.process.spawn(io, .{
|
||||
.argv = &.{
|
||||
"node", runner, sqlite_cli,
|
||||
"--src", "src", "--sdk-in",
|
||||
sdk_in, "--static-in", static_in,
|
||||
"--sdk-out", sdk_out, "--dts-out",
|
||||
".native/cache/sqlite/core.d.ts", "--static-out", ".native/cache/sqlite/core_static.ts",
|
||||
"--zig-out", ".native/cache/sqlite/migrations.zig", "--metadata-out",
|
||||
".native/cache/sqlite/metadata.json", "--state", "src/schema/migrations.lock.json",
|
||||
"node", runner, sqlite_cli,
|
||||
"--src", "src", "--sdk-in",
|
||||
sdk_in, "--static-in", static_in,
|
||||
"--sdk-out", sdk_out, "--dts-out",
|
||||
".native/cache/sqlite/core.d.ts", "--static-out", ".native/cache/sqlite/core_static.ts",
|
||||
"--sdk-events-out", ".native/cache/sqlite/events.ts", "--sdk-text-out",
|
||||
".native/cache/sqlite/text.ts", "--sdk-bytes-text-methods-out", ".native/cache/sqlite/bytes_text_methods.d.ts",
|
||||
"--sdk-events-dts-out", ".native/cache/sqlite/events.d.ts", "--sdk-text-dts-out",
|
||||
".native/cache/sqlite/text.d.ts", "--zig-out", ".native/cache/sqlite/migrations.zig",
|
||||
"--metadata-out", ".native/cache/sqlite/metadata.json", "--state",
|
||||
"src/schema/migrations.lock.json",
|
||||
},
|
||||
.stdin = .ignore,
|
||||
.stdout = .inherit,
|
||||
|
||||
Reference in New Issue
Block a user