Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions packages/compiler/src/compat/url-profile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,16 +63,18 @@ export interface UrlCompatProfile {
const corpus = compatCorpus;

/** Most URL refusals are stdlib-surface fences (SC2020). Component WRITES
* are not: nothing claims the assignment, so it is refused as an
* unsupported expression shape (SC1090, 'assignment to non-variables').
* The fence code is per row, not per profile. */
* are not: the ambient `.d.ts` marks every component but pathname
* `readonly`, so the assignment never reaches the lowerer — it is a
* TypeScript type error (SC0001, 'Cannot assign ... because it is a
* read-only property'), probed by compiling one assignment per component
* rather than assumed. The fence code is per row, not per profile. */
const { staticEntry, unsupportedEntry, outOfScopeEntry } = compatEntries("SC2020");
const { unsupportedEntry: unsupportedShapeEntry } = compatEntries("SC1090");
const { unsupportedEntry: unsupportedShapeEntry } = compatEntries("SC0001");

const islandOnly =
"the emulated URL class inside the dynamic engine serves island and npm JS only; a compiled URL value exposes no lowering for this member in either tier";
const componentWrite =
"URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it";
"URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it";
const iteratorHandle =
"materialized iterator objects are not first-class handles; for-of over the params, or directly over keys()/values()/entries(), is the lowered iteration form";
const iteratorHelpers =
Expand Down
36 changes: 18 additions & 18 deletions packages/compiler/surface-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -4177,40 +4177,40 @@
"kind": "stdlib",
"name": "URL.hash (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.host",
"kind": "stdlib",
"name": "URL.host (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.hostname",
"kind": "stdlib",
"name": "URL.hostname (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.href",
"kind": "stdlib",
"name": "URL.href (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.password",
"kind": "stdlib",
"name": "URL.password (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.pathname",
Expand All @@ -4224,32 +4224,32 @@
"kind": "stdlib",
"name": "URL.port (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.protocol",
"kind": "stdlib",
"name": "URL.protocol (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.search",
"kind": "stdlib",
"name": "URL.search (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.setter.username",
"kind": "stdlib",
"name": "URL.username (setter)",
"status": "unsupported",
"code": "SC1090",
"note": "Node 24.15.0; URL components are read-only in the static tier: there is no component-assignment lowering and no native mutation path behind it"
"code": "SC0001",
"note": "Node 24.15.0; URL components are read-only in the static tier: the ambient .d.ts declares the member readonly, so the assignment is a TypeScript type error before the lowerer ever sees it — there is no component-assignment lowering and no native mutation path behind it"
},
{
"id": "stdlib.url.static.canParse",
Expand Down
12 changes: 9 additions & 3 deletions tests/harness/console-io.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,18 @@ import { createHash } from "node:crypto";
import { mkdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, test } from "vitest";
import { compile } from "@scriptc/compiler";
import { NODE_COMPAT_MATRIX, compile } from "@scriptc/compiler";
import { primaryOracleExecutable } from "./node-matrix.js";

const repoRoot = join(import.meta.dirname, "../..");
const fixtureDir = join(repoRoot, "tests/fixtures/console-io");
const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests");
const sanitize = process.env["SCRIPTC_SAN"] === "1";
// SEMANTIC oracle (differential.test.ts's rationale, node-matrix.ts's
// header): the probes must match ONE Node's fixed byte behavior, so this
// pins to the compat matrix primary rather than whichever `node` the
// PATH happens to resolve.
const oracleExecutable = primaryOracleExecutable(NODE_COMPAT_MATRIX);

interface ClosedChild {
stdout: Buffer;
Expand Down Expand Up @@ -131,7 +137,7 @@ describe(`console/process output visibility${sanitize ? " (sanitized)" : ""}`, (
const probe = await build("live-stdout");

const [nodeOut, nativeOut] = await Promise.all([
observeLiveStdout("node", [probe.sourceFile], expected),
observeLiveStdout(oracleExecutable, [probe.sourceFile], expected),
observeLiveStdout(probe.binary, [], expected),
]);
expect(nodeOut.subarray(0, expected.length)).toEqual(expected);
Expand All @@ -143,7 +149,7 @@ describe(`console/process output visibility${sanitize ? " (sanitized)" : ""}`, (
const probe = await build("sigkill-stdout");

const [nodeRes, nativeRes] = await Promise.all([
runToClose("node", [probe.sourceFile]),
runToClose(oracleExecutable, [probe.sourceFile]),
runToClose(probe.binary, []),
]);
expect(nodeRes.stdout).toEqual(expected);
Expand Down
12 changes: 10 additions & 2 deletions tests/harness/dgram.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,20 @@ import { createHash } from "node:crypto";
import { existsSync, globSync, mkdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, test } from "vitest";
import { compile } from "@scriptc/compiler";
import { NODE_COMPAT_MATRIX, compile } from "@scriptc/compiler";
import { primaryOracleExecutable } from "./node-matrix.js";

const repoRoot = join(import.meta.dirname, "../..");
const fixturesRoot = join(repoRoot, "tests/fixtures/dgram");
const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests");
const sanitize = process.env["SCRIPTC_SAN"] === "1";
// SEMANTIC oracle (differential.test.ts's rationale, node-matrix.ts's
// header, server.test.ts's identical pattern): the fixture's stdout/exit
// code must match ONE Node's fixed behavior, so this pins to the compat
// matrix primary rather than whichever `node` the PATH happens to
// resolve. The driver spawned inside runLane stays plain "node" — it is
// the identical fixed workload on both lanes, not an oracle subject.
const oracleExecutable = primaryOracleExecutable(NODE_COMPAT_MATRIX);

interface ProgramRun {
stdout: Buffer;
Expand Down Expand Up @@ -115,7 +123,7 @@ describe(`dgram differential (${cases.length} programs${sanitize ? ", sanitized"
const binary = await build(c.entry);
// Sequential, not parallel: both lanes bind ephemeral ports and drive
// real sockets — parallelism buys little and interleaves kernel state.
const nodeRes = await runLane("node", [c.entry], c.driver);
const nodeRes = await runLane(oracleExecutable, [c.entry], c.driver);
const nativeRes = await runLane(binary, [], c.driver);
expect(nativeRes.stdout.toString("utf8")).toBe(nodeRes.stdout.toString("utf8"));
if (!nodeRes.stdout.equals(nativeRes.stdout)) {
Expand Down
10 changes: 8 additions & 2 deletions tests/harness/event-loop.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,19 @@ import { createHash } from "node:crypto";
import { mkdirSync, readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, test } from "vitest";
import { compile } from "@scriptc/compiler";
import { NODE_COMPAT_MATRIX, compile } from "@scriptc/compiler";
import { eventLoopCases, type StdinScript } from "./event-loop-cases.js";
import { primaryOracleExecutable } from "./node-matrix.js";

const repoRoot = join(import.meta.dirname, "../..");
const fixtureDir = join(repoRoot, "tests/fixtures/event-loop");
const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests");
const sanitize = process.env["SCRIPTC_SAN"] === "1";
// SEMANTIC oracle (differential.test.ts's rationale, node-matrix.ts's
// header): stdout/exit code must match ONE Node's fixed behavior, so
// this pins to the compat matrix primary rather than whichever `node`
// the PATH happens to resolve.
const oracleExecutable = primaryOracleExecutable(NODE_COMPAT_MATRIX);

interface RunResult {
stdout: string;
Expand Down Expand Up @@ -76,7 +82,7 @@ async function compileFixture(name: string): Promise<string> {
async function differential(fixture: string, script: StdinScript): Promise<void> {
const binary = await compileFixture(fixture);
const [nodeRes, nativeRes] = await Promise.all([
runWithStdin("node", [join(fixtureDir, fixture)], script),
runWithStdin(oracleExecutable, [join(fixtureDir, fixture)], script),
runWithStdin(binary, [], script),
]);
expect(nativeRes.stdout).toBe(nodeRes.stdout);
Expand Down
Loading