mirror of
https://github.com/vercel-labs/scriptc.git
synced 2026-10-28 06:53:42 +08:00
A union may now hold one promise beside data members (`T | Promise<T>`, `Promise<R | void> | R | void`). The union tag is the `instanceof Promise` test, and every operation keeps Node's microtask timing: `await` awaits the promise arm or takes the one non-thenable turn, an async `return` (block bodies, concise arrows, then handlers) adopts the promise arm after the function's own finally blocks, `Promise.resolve` returns the promise arm as is, and `typeof (u as any).then` reads the tag. Data arms that declare `then`, two promise arms, and function arms beside a promise stay refused with diagnostics. Inferred JavaScript literals that mix promises and values keep the checked-dynamic array. Rest parameters typed `unknown[]` or `any[]` in TypeScript use the checked-dynamic variadic ABI that JavaScript rest parameters already use, including spread forwarding (`(...args) => handler(...args)`). Functions are now Map values, Map keys and Set elements, compared by closure identity. Two pre-existing bugs in the same area are fixed: an async lambda in a `Promise<void> | void` slot got a `Promise<union>` ABI and threw when called through the slot, and `return cb()` of such a callback in an async function dropped the promise instead of adopting it. The retired-engine 2251 and 2790 diagnostics fixtures (tagged templates with `any[]` rest tags) now compile and match Node, so they move to the corpus as 6248 and 6249. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
// Functions as Map values, Map keys and Set elements: factory and listener
|
|
// registries keep each closure's identity, and a handler that captures its
|
|
// own registry is collected with it.
|
|
|
|
interface Extension {
|
|
name: string;
|
|
run(x: number): number;
|
|
}
|
|
type ExtensionFactory = (api: { log: (s: string) => void }) => Extension;
|
|
const factories = new Map<string, ExtensionFactory>();
|
|
factories.set("double", (api) => ({
|
|
name: "double",
|
|
run: (x) => {
|
|
api.log("double " + x);
|
|
return x * 2;
|
|
},
|
|
}));
|
|
factories.set("inc", () => ({ name: "inc", run: (x) => x + 1 }));
|
|
const lines: string[] = [];
|
|
const api = { log: (s: string) => lines.push(s) };
|
|
for (const [key, make] of factories) {
|
|
const ext = make(api);
|
|
console.log(key, ext.name, ext.run(10));
|
|
}
|
|
console.log(factories.get("missing") === undefined, typeof factories.get("inc"), factories.has("inc"));
|
|
const inc = factories.get("inc");
|
|
if (inc) console.log(inc(api).run(41));
|
|
factories.delete("inc");
|
|
console.log([...factories.keys()].join(","), factories.size, lines.join(";"));
|
|
|
|
type Listener = (v: string) => void;
|
|
const listeners = new Set<Listener>();
|
|
const a: Listener = (v) => console.log("a", v);
|
|
const b: Listener = (v) => console.log("b", v);
|
|
listeners.add(a);
|
|
listeners.add(b);
|
|
listeners.add(a);
|
|
console.log(listeners.size, listeners.has(a), listeners.has((v) => console.log(v)));
|
|
for (const l of listeners) l("x");
|
|
listeners.delete(a);
|
|
listeners.forEach((l) => l("y"));
|
|
|
|
const counts = new Map<Listener, number>();
|
|
counts.set(a, 1);
|
|
counts.set(b, 2);
|
|
counts.set(a, 3);
|
|
console.log(counts.size, counts.get(a), counts.get(b));
|
|
|
|
const registry = new Map<string, () => number>();
|
|
registry.set("self", () => registry.size);
|
|
registry.set("double", () => registry.size * 2);
|
|
console.log([...registry.values()].map((f) => f()).join(","));
|