mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-11-02 07:43:42 +08:00
- A function body or class static block treats its top-level function declarations as var-scoped: duplicates are legal in strict code, and a let/const/class of the same name is SC0006. - Strictness is the code around a node: a function declaration's own "use strict" no longer makes its declaring context strict. - Every part of a class is strict; object literal methods and accessors are strict only by their own prologue or their surroundings, and an arrow function's block body can carry "use strict". - The bare compareArray reads b.length, then a.length, and a.length again before every element pair, converting it as the upstream `i < a.length` does, so a string length compares its elements. - Tests that relied on the old handling of undeclared names now use constructs that are still refused or still compile: the installed-entry diagnostics fixture reports a syntax error (a read of an undeclared name is now Node's run-time ReferenceError), and static-objects-order's loops.js stores from its for-in head into `undefined` instead of an undeclared name (a store into an undeclared name refuses its package with SC1091).
44 lines
1.9 KiB
TypeScript
44 lines
1.9 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 { checkPreflight, loadProgram } from "./program-node.js";
|
|
|
|
/** The preflight diagnostics of a CommonJS script (sloppy unless it says
|
|
* "use strict"). */
|
|
function diagnostics(source: string) {
|
|
const directory = mkdtempSync(join(tmpdir(), "scriptc-early-errors-"));
|
|
writeFileSync(join(directory, "main.cjs"), source);
|
|
const load = loadProgram(join(directory, "main.cjs"));
|
|
try {
|
|
return checkPreflight(load).map((diagnostic) => diagnostic.code);
|
|
} finally {
|
|
load.dispose();
|
|
rmSync(directory, { recursive: true, force: true });
|
|
}
|
|
}
|
|
|
|
test.for([
|
|
// A function body's top-level function declarations are var-scoped, so
|
|
// duplicates are legal in strict code too.
|
|
'function outer() { "use strict"; function d() {} function d() {} }\nouter();',
|
|
"class C { static { function s() {} function s() {} } }\nnew C();",
|
|
// Object literal methods and accessors are sloppy unless they say otherwise.
|
|
"var o = { m() { if (true) function f() {} } };\no.m();",
|
|
"var o = { get g() { { function h() {} function h() {} } return 1; } };\no.g;",
|
|
// A function's own directive makes its body strict, not the code declaring it.
|
|
'if (true) function k() { "use strict"; }',
|
|
'{ function z() { "use strict"; } function z() {} }',
|
|
])("Node accepts: %s", (source) => {
|
|
expect(diagnostics(source)).toEqual([]);
|
|
});
|
|
|
|
test.for([
|
|
["function outer() { let d; function d() {} }\nouter();", "SC0006"],
|
|
['(() => { "use strict"; if (true) function f() {} })();', "SC0007"],
|
|
["class C { m() { if (true) function f() {} } }\nnew C().m();", "SC0007"],
|
|
['var o = { m() { "use strict"; { function h() {} function h() {} } } };\no.m();', "SC0005"],
|
|
])("Node refuses: %s", ([source, code]) => {
|
|
expect(diagnostics(source!)).toContain(code);
|
|
});
|