mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-24 06:14:01 +08:00
* Expand static three.js workflows and host integration * Preserve JavaScript class state in static three.js workflows * Preserve inferred JavaScript behavior across static workflows * Preserve inferred callables and native compatibility boundaries * Retain annotated JavaScript factory exports and bootstrap-safe call spreads * Preserve Buffer and child callback identities in static packages * Clarify JavaScript symbol spread support
86 lines
4.8 KiB
TypeScript
86 lines
4.8 KiB
TypeScript
import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
import { tmpdir } from "node:os";
|
|
import { join } from "node:path";
|
|
import { expect, test } from "vitest";
|
|
import { analyze } from "../src/index.js";
|
|
|
|
test.each([
|
|
["assignment", 'let key = Symbol.for("x"); key = Symbol.for("y"); class C { [key] = true; }'],
|
|
["shorthand assignment", 'var key = Symbol.for("x"); ({ key } = { key: Symbol.for("y") }); class C { [key] = true; }'],
|
|
["array assignment", 'var key = Symbol.for("x"); [key] = [Symbol.for("y")]; class C { [key] = true; }'],
|
|
["redeclaration", 'var key = Symbol.for("x"); var key = Symbol.for("y"); class C { [key] = true; }'],
|
|
["early class key", 'class C { [key] = true; } var key = Symbol.for("x");'],
|
|
["early hoisted call", 'read(); var key = Symbol.for("x"); function read() { return key; } class C { [key] = true; }'],
|
|
["early shorthand call", 'const callbacks = { read }; callbacks.read(); var key = Symbol.for("x"); function read() { return key; } class C { [key] = true; }'],
|
|
["for-of assignment", 'var key = Symbol.for("x"); for (key of [Symbol.for("y")]) {} class C { [key] = true; }'],
|
|
["runtime registry name", 'function text() { return "x"; } const key = Symbol.for(text()); class C { [key] = true; }'],
|
|
["local symbol", 'class C { constructor() { const key = Symbol("x"); this[key] = true; } }'],
|
|
["distinct symbol collision", 'const key = Symbol("x"); const other = Symbol.for("x"); class C { [key] = true; [other] = false; }'],
|
|
])("refuses symbol fields with %s", (_name, source) => {
|
|
const dir = mkdtempSync(join(tmpdir(), "scriptc-symbol-fields-"));
|
|
try {
|
|
const entry = join(dir, "main.cjs");
|
|
writeFileSync(entry, source + "\nnew C();\n");
|
|
const { coverage } = analyze(entry);
|
|
const diagnostics = [...coverage.diagnostics, ...(coverage.runtimeFences ?? [])];
|
|
expect(diagnostics.some((d) => d.code === "SC1090" && /symbol|computed class fields/i.test(d.message)), JSON.stringify(coverage, null, 2)).toBe(true);
|
|
expect(coverage.stats.statementsIsland).toBe(0);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test.each([
|
|
["constant registry name", 'const text = "x"; const key = Symbol.for(text); class C { [key] = true; }'],
|
|
["uninitialized JavaScript field", 'const key = Symbol.for("x"); class C { [key]; }'],
|
|
])("accepts symbol fields with %s", (_name, source) => {
|
|
const dir = mkdtempSync(join(tmpdir(), "scriptc-symbol-fields-"));
|
|
try {
|
|
const entry = join(dir, "main.cjs");
|
|
writeFileSync(entry, source + "\nnew C();\n");
|
|
const { coverage } = analyze(entry);
|
|
expect(coverage.preflightFailed).toBe(false);
|
|
expect([...coverage.diagnostics, ...(coverage.runtimeFences ?? [])]).toEqual([]);
|
|
expect(coverage.stats.statementsIsland).toBe(0);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test.each([
|
|
["rest declaration", "const { name, ...copy } = value; console.log(copy);"],
|
|
["rest assignment", "let copy = {}; let name; ({ name, ...copy } = value); console.log(copy);"],
|
|
["Object.assign", "const copy = Object.assign({}, value); console.log(copy);"],
|
|
["Object.assign with several sources", "const copy = Object.assign({}, value, { extra: 1 }); console.log(copy);"],
|
|
["Object.assign with spread sources", "const copy = Object.assign({}, ...[value]); console.log(copy);"],
|
|
])("refuses %s copies of symbol fields", (_name, copy) => {
|
|
const dir = mkdtempSync(join(tmpdir(), "scriptc-symbol-copy-"));
|
|
try {
|
|
const entry = join(dir, "main.cjs");
|
|
writeFileSync(entry, `const key = Symbol.for("x"); class Base { [key] = true; name = "base"; } class C extends Base {} const value = new C(); ${copy}`);
|
|
const { coverage } = analyze(entry);
|
|
const diagnostics = [...coverage.diagnostics, ...(coverage.runtimeFences ?? [])];
|
|
expect(diagnostics.some((d) => /rest bindings|copying class instances|object spread/.test(d.message)), JSON.stringify(coverage, null, 2)).toBe(true);
|
|
expect(coverage.stats.statementsIsland).toBe(0);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|
|
|
|
test.each([
|
|
["spread", "const copy = { ...value }; console.log(copy[key]);"],
|
|
["computed-key spread", 'let name = "extra"; const copy = { [name]: 1, ...value }; console.log(copy[key]);'],
|
|
])("accepts %s copies of symbol fields", (_name, copy) => {
|
|
const dir = mkdtempSync(join(tmpdir(), "scriptc-symbol-copy-"));
|
|
try {
|
|
const entry = join(dir, "main.cjs");
|
|
writeFileSync(entry, `const key = Symbol.for("x"); class Base { [key] = true; name = "base"; } class C extends Base {} const value = new C(); ${copy}`);
|
|
const { coverage } = analyze(entry);
|
|
expect(coverage.preflightFailed).toBe(false);
|
|
expect([...coverage.diagnostics, ...(coverage.runtimeFences ?? [])]).toEqual([]);
|
|
expect(coverage.stats.statementsIsland).toBe(0);
|
|
} finally {
|
|
rmSync(dir, { recursive: true, force: true });
|
|
}
|
|
});
|