import { assertEquals, assertGreater, assertStringIncludes } from "@std/assert";
import { validateSource } from "./utils.ts";
import type { TransformationDiagnostic } from "../src/mod.ts";
import { COMMONFABRIC_TYPES } from "./commonfabric-test-types.ts";
/**
* Extracts JSON schema literals from transformed output.
* Schemas appear as either:
* - `{ type: "object", ... } as const satisfies __cfHelpers.JSONSchema`
* - `true as const satisfies __cfHelpers.JSONSchema`
* - `false as const satisfies __cfHelpers.JSONSchema`
* Returns them in order of appearance.
*/
function extractSchemas(output: string): string[] {
const schemas: string[] = [];
const marker = "as const satisfies __cfHelpers.JSONSchema";
let searchFrom = 0;
while (true) {
const markerIdx = output.indexOf(marker, searchFrom);
if (markerIdx === -1) break;
// Walk backwards from marker to find the schema literal.
let start = markerIdx - 1;
// Skip whitespace before marker
while (start >= 0 && /\s/.test(output[start]!)) start--;
let schemaText: string | undefined;
if (output[start] === "}") {
let depth = 1;
start--;
while (start >= 0 && depth > 0) {
if (output[start] === "}") depth++;
else if (output[start] === "{") depth--;
start--;
}
start++; // back to the opening brace
schemaText = output.slice(start, markerIdx).trim();
} else {
let tokenStart = start;
while (tokenStart >= 0 && /[A-Za-z]/.test(output[tokenStart]!)) {
tokenStart--;
}
tokenStart++;
const token = output.slice(tokenStart, start + 1).trim();
if (token === "true" || token === "false") {
schemaText = token;
}
}
if (!schemaText) {
searchFrom = markerIdx + marker.length;
continue;
}
schemas.push(schemaText);
searchFrom = markerIdx + marker.length;
}
return schemas;
}
function getErrors(diagnostics: readonly TransformationDiagnostic[]) {
return diagnostics.filter((d) => d.severity === "error");
}
Deno.test("Schema Shrink Validation", async (t) => {
await t.step(
"errors when parameter is 'unknown' but code accesses properties",
async () => {
const source = [
'import { pattern } from "commonfabric";',
"",
"export default pattern((state: unknown) => {",
" const x = state.foo;",
" const y = state.bar;",
" return { x, y };",
"});",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertGreater(
shrinkErrors.length,
0,
"Expected at least one schema:unknown-type-access error",
);
assertEquals(shrinkErrors[0]!.type, "schema:unknown-type-access");
},
);
await t.step(
"errors when declared type is missing an accessed property",
async () => {
const source = [
'import { pattern } from "commonfabric";',
"",
"export default pattern((state: { a: string }) => {",
" const x = state.a;",
" const y = state.b;",
" return { x, y };",
"});",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:path-not-in-type",
);
assertGreater(
shrinkErrors.length,
0,
"Expected at least one schema:path-not-in-type error",
);
assertEquals(shrinkErrors[0]!.type, "schema:path-not-in-type");
},
);
await t.step(
"errors on interprocedural unknown-type access in lift callback",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"const helper = (x: unknown) => (x as any).foo;",
"",
"const fn = lift((state: unknown) => helper(state));",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertGreater(
shrinkErrors.length,
0,
"Expected schema:unknown-type-access from interprocedural lift",
);
},
);
await t.step(
"errors on interprocedural path-not-in-type via as-any cast in lift callback",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"const helper = (x: { a: string }) => (x as any).b;",
"",
"const fn = lift((state: { a: string }) => helper(state));",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:path-not-in-type",
);
assertGreater(
shrinkErrors.length,
0,
"Expected schema:path-not-in-type from interprocedural as-any cast",
);
},
);
await t.step(
"errors when unknown parameter is passed to opaque function in lift",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"const fn = lift((state: unknown) => console.log(state));",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertGreater(
shrinkErrors.length,
0,
"Expected schema:unknown-type-access for unknown param passed to opaque function",
);
},
);
await t.step(
"no error when any parameter is passed to opaque function in lift",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"const fn = lift((state: any) => console.log(state));",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no schema:unknown-type-access for 'any' but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when unknown parameter is passed to equals in lift",
async () => {
const source = [
"/// ",
'import { equals, lift } from "commonfabric";',
"",
"const fn = lift((state: unknown) => equals(state, state));",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no schema:unknown-type-access for equals(identity) but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when concrete type is passed to opaque function in lift",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"const fn = lift((state: { a: string }) => console.log(state));",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no errors for concrete type but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"errors when unknown parameter is passed to opaque function in pattern",
async () => {
const source = [
'import { pattern } from "commonfabric";',
"",
"export default pattern((state: unknown) => {",
" console.log(state);",
" return {};",
"});",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertGreater(
shrinkErrors.length,
0,
"Expected schema:unknown-type-access for unknown param in pattern passed to opaque function",
);
},
);
await t.step(
"errors when interface property is typed unknown in handler",
async () => {
const source = [
'import { handler } from "commonfabric";',
"",
"interface BatchEvent {",
" amounts?: unknown;",
" note?: unknown;",
"}",
"",
"export const h = handler(",
" (event: BatchEvent) => {",
" const x = event.amounts;",
" return {};",
" },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertGreater(
shrinkErrors.length,
0,
"Expected schema:unknown-type-access for unknown-typed property in interface",
);
},
);
await t.step(
"errors when interface property is typed unknown in pattern",
async () => {
const source = [
'import { pattern } from "commonfabric";',
"",
"interface State {",
" data?: unknown;",
"}",
"",
"export default pattern((state: State) => {",
" const x = state.data;",
" return { x };",
"});",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertGreater(
shrinkErrors.length,
0,
"Expected schema:unknown-type-access for unknown-typed property in pattern",
);
},
);
await t.step(
"no error when interface property is typed any (not unknown)",
async () => {
const source = [
'import { handler } from "commonfabric";',
"",
"interface BatchEvent {",
" amounts?: any;",
"}",
"",
"export const h = handler(",
" (event: BatchEvent) => {",
" const x = event.amounts;",
" return {};",
" },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no schema:unknown-type-access for 'any'-typed property but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when interface property is typed with concrete type",
async () => {
const source = [
'import { handler } from "commonfabric";',
"",
"interface BatchEvent {",
" amounts?: number[];",
" note?: string;",
"}",
"",
"export const h = handler(",
" (event: BatchEvent) => {",
" const x = event.amounts;",
" return {};",
" },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:unknown-type-access",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no schema:unknown-type-access for concrete-typed properties but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when handler parameter type is a type alias",
async () => {
const source = [
'import { handler } from "commonfabric";',
"",
"type Req = { item: string };",
"",
"export const h = handler(",
" (args) => { console.log(args.item); },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors for type alias but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no diagnostic when declared type matches all accessed paths",
async () => {
const source = [
'import { pattern } from "commonfabric";',
"",
"export default pattern((state: { a: string; b: number }) => {",
" const x = state.a;",
" const y = state.b;",
" return { x, y };",
"});",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when handler parameter is T | undefined",
async () => {
const source = [
'import { handler } from "commonfabric";',
"",
"export const h = handler<{ amount?: number } | undefined, {}>(",
" (args) => { console.log(args.amount); },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors for T | undefined but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when handler parameter is a multi-member union",
async () => {
const source = [
'import { handler } from "commonfabric";',
"",
"export const h = handler<{ value?: number } | number | undefined, {}>(",
" (args) => { console.log(args.value); },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors for multi-member union but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when handler parameter is TypeAlias | undefined",
async () => {
const source = [
'import { handler } from "commonfabric";',
"",
"interface Req { item: string }",
"",
"export const h = handler(",
" (args) => { console.log(args.item); },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors for TypeAlias | undefined but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when lift accesses numeric index on array",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"const fn = lift((items: number[]) => items[0]);",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors for array index access but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"no error when lift accesses .length on array type alias",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"type Items = Array<{ name: string }>;",
"const hasItems = lift(",
" (items) => items && items.length > 0,",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors for .length on array type alias but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
await t.step(
"errors when lift accesses .length on numeric index signature object",
async () => {
const source = [
'import { lift } from "commonfabric";',
"",
"type Indexed = { [index: number]: string };",
"const hasItems = lift(",
" (items) => items.length > 0,",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) => e.type === "schema:path-not-in-type",
);
assertGreater(
shrinkErrors.length,
0,
`Expected schema:path-not-in-type for numeric index signature .length access but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
},
);
await t.step(
"no error when handler without type args has SomeType | undefined param",
async () => {
// Reproduces pattern-ingredient-scaler: handler() without type args
// where the callback param is SomeType | undefined and accesses a property.
const source = [
'import { type Cell, handler } from "commonfabric";',
"",
"interface ServingsEvent { servings?: number; delta?: number }",
"",
"const setServings = handler(",
" (event: ServingsEvent | undefined, context: { desiredServings: Cell }) => {",
" context.desiredServings.set(event?.servings ?? 1);",
" },",
");",
].join("\n");
const { diagnostics } = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(diagnostics);
const shrinkErrors = errors.filter(
(e) =>
e.type === "schema:unknown-type-access" ||
e.type === "schema:path-not-in-type",
);
assertEquals(
shrinkErrors.length,
0,
`Expected no shrink errors for handler with SomeType | undefined but got: ${
shrinkErrors.map((e) => e.message).join("; ")
}`,
);
},
);
// =========================================================================
// Type-arg form vs inline form: schemas must be identical
// =========================================================================
await t.step(
"handler generates same schemas as handler((e: E, t: T) => ...)",
async () => {
const sourceTypeArgs = [
'import { type Cell, handler } from "commonfabric";',
"",
"export const h = handler<{ amount: number }, { total: Cell }>(",
" (event, ctx) => { ctx.total.set(event.amount); },",
");",
].join("\n");
const sourceInline = [
'import { type Cell, handler } from "commonfabric";',
"",
"export const h = handler(",
" (event: { amount: number }, ctx: { total: Cell }) => {",
" ctx.total.set(event.amount);",
" },",
");",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`handler form had shrink errors: ${fmtErrors(rTA.diagnostics)}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`handler inline form had shrink errors: ${
fmtErrors(rInline.diagnostics)
}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
assertEquals(
schemasTA,
schemasInline,
"handler schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"handler preserves | undefined in both forms",
async () => {
// Both forms preserve `| undefined` in the event schema.
// Remaining divergence: optional property encoding differs
// (type-arg: {type:"number"}, inline: {anyOf:[{type:"number"},{type:"undefined"}]}).
const sourceTypeArgs = [
'import { type Cell, handler } from "commonfabric";',
"",
"export const h = handler<{ amount?: number } | undefined, { total: Cell }>(",
" (event, ctx) => { ctx.total.set(event?.amount ?? 0); },",
");",
].join("\n");
const sourceInline = [
'import { type Cell, handler } from "commonfabric";',
"",
"export const h = handler(",
" (event: { amount?: number } | undefined, ctx: { total: Cell }) => {",
" ctx.total.set(event?.amount ?? 0);",
" },",
");",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`handler had shrink errors: ${
fmtErrors(rTA.diagnostics)
}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`handler inline union form had shrink errors: ${
fmtErrors(rInline.diagnostics)
}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
// Both event schemas should contain "undefined" (not stripped)
assertEquals(
schemasTA[0]!.includes('"undefined"'),
true,
"type-arg event schema should preserve undefined",
);
assertEquals(
schemasInline[0]!.includes('"undefined"'),
true,
"inline event schema should preserve undefined",
);
// State schemas (second schema) should match exactly
assertEquals(
schemasTA[1],
schemasInline[1],
"handler state schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"handler preserves | undefined in both forms",
async () => {
const sourceTypeArgs = [
'import { type Cell, handler } from "commonfabric";',
"",
"interface ScaleEvent { servings?: number; delta?: number }",
"interface ScaleState { desiredServings: Cell }",
"",
"export const h = handler(",
" (event, ctx) => { ctx.desiredServings.set(event?.servings ?? 1); },",
");",
].join("\n");
const sourceInline = [
'import { type Cell, handler } from "commonfabric";',
"",
"interface ScaleEvent { servings?: number; delta?: number }",
"interface ScaleState { desiredServings: Cell }",
"",
"export const h = handler(",
" (event: ScaleEvent | undefined, ctx: ScaleState) => {",
" ctx.desiredServings.set(event?.servings ?? 1);",
" },",
");",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`handler had shrink errors: ${fmtErrors(rTA.diagnostics)}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`handler inline alias form had shrink errors: ${
fmtErrors(rInline.diagnostics)
}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
// Both event schemas should contain "undefined" (not stripped)
assertEquals(
schemasTA[0]!.includes('"undefined"'),
true,
"type-arg event schema should preserve undefined",
);
assertEquals(
schemasInline[0]!.includes('"undefined"'),
true,
"inline event schema should preserve undefined",
);
// State schemas (second schema) should match exactly
assertEquals(
schemasTA[1],
schemasInline[1],
"handler state schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"lift generates same schemas as lift((x: T): R => ...)",
async () => {
const sourceTypeArgs = [
'import { lift } from "commonfabric";',
"",
"const fn = lift<{ count: number }, string>(",
" (state) => `count: ${state.count}`,",
");",
].join("\n");
const sourceInline = [
'import { lift } from "commonfabric";',
"",
"const fn = lift(",
" (state: { count: number }): string => `count: ${state.count}`,",
");",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`lift had shrink errors: ${fmtErrors(rTA.diagnostics)}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`lift inline had shrink errors: ${fmtErrors(rInline.diagnostics)}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
assertEquals(
schemasTA,
schemasInline,
"lift schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"lift preserves | undefined in both forms",
async () => {
// Both forms now preserve `| undefined` in the input schema.
const sourceTypeArgs = [
'import { lift } from "commonfabric";',
"",
"const fn = lift<{ count: number } | undefined, number>(",
" (state) => state?.count ?? 0,",
");",
].join("\n");
const sourceInline = [
'import { lift } from "commonfabric";',
"",
"const fn = lift(",
" (state: { count: number } | undefined): number => state?.count ?? 0,",
");",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`lift had shrink errors: ${fmtErrors(rTA.diagnostics)}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`lift inline union had shrink errors: ${
fmtErrors(rInline.diagnostics)
}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
// Both input schemas should contain "undefined" (not stripped)
assertEquals(
schemasTA[0]!.includes('"undefined"'),
true,
"type-arg input schema should preserve undefined",
);
assertEquals(
schemasInline[0]!.includes('"undefined"'),
true,
"inline input schema should preserve undefined",
);
// Result schemas (second schema) should match exactly
assertEquals(
schemasTA[1],
schemasInline[1],
"lift result schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"lift generates same schemas as lift with inline alias",
async () => {
const sourceTypeArgs = [
'import { lift } from "commonfabric";',
"",
"interface Item { name: string; price: number }",
"",
"const fn = lift- (",
" (item) => `${item.name}: $${item.price}`,",
");",
].join("\n");
const sourceInline = [
'import { lift } from "commonfabric";',
"",
"interface Item { name: string; price: number }",
"",
"const fn = lift(",
" (item: Item): string => `${item.name}: $${item.price}`,",
");",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`lift had shrink errors: ${fmtErrors(rTA.diagnostics)}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`lift inline alias had shrink errors: ${
fmtErrors(rInline.diagnostics)
}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
assertEquals(
schemasTA,
schemasInline,
"lift type-alias schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"pattern and inline destructured form produce identical schemas",
async () => {
const sourceTypeArgs = [
'import { pattern } from "commonfabric";',
"",
"export default pattern<{ name: string; count: number }>(({ name, count }) => {",
" return { name, count };",
"});",
].join("\n");
const sourceInline = [
'import { pattern } from "commonfabric";',
"",
"export default pattern(({ name, count }: { name: string; count: number }) => {",
" return { name, count };",
"});",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`pattern had shrink errors: ${fmtErrors(rTA.diagnostics)}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`pattern inline had shrink errors: ${fmtErrors(rInline.diagnostics)}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
assertGreater(
schemasTA.length,
0,
"type-arg form should produce schemas",
);
assertGreater(
schemasInline.length,
0,
"inline form should produce schemas",
);
assertEquals(
schemasTA,
schemasInline,
"pattern schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"pattern and inline destructured alias form produce identical schemas",
async () => {
const sourceTypeArgs = [
'import { pattern } from "commonfabric";',
"",
"interface Args { name: string; count: number }",
"",
"export default pattern(({ name, count }) => {",
" return { name, count };",
"});",
].join("\n");
const sourceInline = [
'import { pattern } from "commonfabric";',
"",
"interface Args { name: string; count: number }",
"",
"export default pattern(({ name, count }: Args) => {",
" return { name, count };",
"});",
].join("\n");
const rTA = await validateSource(sourceTypeArgs, {
types: COMMONFABRIC_TYPES,
});
const rInline = await validateSource(sourceInline, {
types: COMMONFABRIC_TYPES,
});
assertEquals(
getShrinkErrors(rTA.diagnostics).length,
0,
`pattern had shrink errors: ${fmtErrors(rTA.diagnostics)}`,
);
assertEquals(
getShrinkErrors(rInline.diagnostics).length,
0,
`pattern inline alias had shrink errors: ${
fmtErrors(rInline.diagnostics)
}`,
);
const schemasTA = extractSchemas(rTA.output);
const schemasInline = extractSchemas(rInline.output);
assertGreater(
schemasTA.length,
0,
"type-arg form should produce schemas",
);
assertGreater(
schemasInline.length,
0,
"inline form should produce schemas",
);
assertEquals(
schemasTA,
schemasInline,
"pattern schemas should be identical between type-arg and inline forms",
);
},
);
await t.step(
"lift object-literal input preserves property schemas",
async () => {
const source = [
'import { cell, lift } from "commonfabric";',
"",
'const stage = cell("initial");',
"const attemptCount = cell(0);",
"const acceptedCount = cell(0);",
"const rejectedCount = cell(0);",
"",
"const normalizedStage = lift((value: string) => value)(stage);",
"const attempts = lift((count: number) => count)(attemptCount);",
"const accepted = lift((count: number) => count)(acceptedCount);",
"const rejected = lift((count: number) => count)(rejectedCount);",
"",
"const _summary = lift((snapshot) =>",
" `stage:${snapshot.stage} attempts:${snapshot.attempts}` +",
" ` accepted:${snapshot.accepted} rejected:${snapshot.rejected}`",
")(",
" {",
" stage: normalizedStage,",
" attempts: attempts,",
" accepted: accepted,",
" rejected: rejected,",
" },",
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
assertStringIncludes(result.output, "stage: {");
assertStringIncludes(result.output, "attempts: {");
assertStringIncludes(result.output, "accepted: {");
assertStringIncludes(result.output, "rejected: {");
assertEquals(result.output.includes("stage: true"), false);
assertEquals(result.output.includes("attempts: true"), false);
assertEquals(result.output.includes("accepted: true"), false);
assertEquals(result.output.includes("rejected: true"), false);
},
);
await t.step(
"lift validates direct array parameters against item fields used in for...of loops",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type AssetRecord = {",
" id: string;",
" stage: string;",
" owner: string;",
" unused: { nested: string };",
"};",
"type StageBucket = { id: string; stage: string; owner: string };",
"const toBuckets = lift((entries: AssetRecord[]): StageBucket[] => {",
" const buckets: StageBucket[] = [];",
" for (const entry of entries) {",
" buckets.push({",
" id: entry.id,",
" stage: entry.stage,",
" owner: entry.owner,",
" });",
" }",
" return buckets;",
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "id");
assertStringIncludes(inputSchema, "stage");
assertStringIncludes(inputSchema, "owner");
assertEquals(inputSchema.includes("unused"), false);
assertEquals(inputSchema.includes("nested"), false);
},
);
await t.step(
"lift validates array unions against item fields used after ?? fallback",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type LeadScoreSummary = {",
" id: string;",
" score: number;",
" unused: string;",
"};",
"const liftScoreByLead = lift((list: LeadScoreSummary[] | undefined) => {",
" const record: Record = {};",
" for (const entry of list ?? []) {",
" record[entry.id] = entry.score;",
" }",
" return record;",
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "id");
assertStringIncludes(inputSchema, "score");
},
);
await t.step(
"lift preserves inherited interface fields used after ?? fallback",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"interface LeadState {",
" id: string;",
" name: string;",
"}",
"interface LeadScoreSummary extends LeadState {",
" score: number;",
" unused: string;",
"}",
"const liftScoreByLead = lift((list: LeadScoreSummary[] | undefined) => {",
" const record: Record = {};",
" for (const entry of list ?? []) {",
" record[entry.id] = entry.score;",
" }",
" return record;",
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "id");
assertStringIncludes(inputSchema, "score");
assertEquals(inputSchema.includes("name"), false);
assertEquals(inputSchema.includes("unused"), false);
},
);
await t.step(
"lift preserves plain array callback item fields in shrunk schemas",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type Route = { id: string; label: string; capacity: number; unused: string };",
"const liftLoadMetrics = lift((input: { routeList: Route[] }) =>",
" input.routeList.map((route) => ({",
" route: route.id,",
" label: route.label,",
" capacity: route.capacity,",
" }))",
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "id");
assertStringIncludes(inputSchema, "label");
assertStringIncludes(inputSchema, "capacity");
assertEquals(inputSchema.includes("unused"), false);
},
);
await t.step(
"lift preserves tracked values stored in local Map lookups",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type Component = { id: string; name: string; props: string[]; unused: string };",
"const liftNames = lift((input: { components: Component[]; ids: string[] }) => {",
" const componentMap = new Map();",
" input.components.forEach((component) => componentMap.set(component.id, component));",
" return input.ids.map((id) => componentMap.get(id)?.name ?? id);",
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "components");
assertStringIncludes(inputSchema, "id");
assertStringIncludes(inputSchema, "name");
assertEquals(inputSchema.includes("unused"), false);
},
);
await t.step(
"lift preserves tracked values stored in local arrays used by sort callbacks",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type Candidate = { id: string; age: number; site: string; unused: string };",
"type Result = { candidate: Candidate; eligible: boolean };",
"const liftIds = lift((input: { candidates: Candidate[] }) => {",
" const results: Result[] = [];",
" for (const candidate of input.candidates) {",
" results.push({ candidate, eligible: candidate.age >= 18 });",
" }",
" results.sort((left, right) => left.candidate.id.localeCompare(right.candidate.id));",
" return results.length;",
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "id");
assertStringIncludes(inputSchema, "age");
assertEquals(inputSchema.includes("unused"), false);
},
);
await t.step(
"lift preserves element bindings through filter-to-map chains",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type ScreeningResult = {",
" candidate: { id: string; site: string; unused: string };",
" eligible: boolean;",
"};",
"const liftEligibleIds = lift((input: { report: ScreeningResult[] }) =>",
" input.report",
" .filter((entry) => entry.eligible)",
" .map((entry) => entry.candidate.id)",
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "eligible");
assertStringIncludes(inputSchema, "candidate");
assertStringIncludes(inputSchema, "id");
assertEquals(inputSchema.includes("unused"), false);
},
);
await t.step(
"lift preserves properties read from find() result aliases",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type IncidentStep = {",
" id: string;",
" title: string;",
" owner: string;",
' status: "pending" | "in_progress";',
" expectedMinutes: number;",
" elapsedMinutes: number;",
"};",
"const liftActiveStepTitle = lift((input: { list: IncidentStep[]; active: string | null }) => {",
" const target = input.list.find((step) => step.id === input.active);",
' return target ? target.title : "idle";',
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "list");
assertStringIncludes(inputSchema, "id");
assertStringIncludes(inputSchema, "title");
assertStringIncludes(inputSchema, "active");
assertEquals(inputSchema.includes("owner"), false);
},
);
await t.step(
"lift preserves direct properties read from find() results",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type ParkingPerson = {",
" name: string;",
" priorityRank: number;",
" defaultSpot: string;",
"};",
"const liftPriority = lift((input: { people: ParkingPerson[] }) =>",
' input.people.find((person) => person.name === "Alice")?.priorityRank === 1',
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "people");
assertStringIncludes(inputSchema, "name");
assertStringIncludes(inputSchema, "priorityRank");
assertEquals(inputSchema.includes("defaultSpot"), false);
},
);
await t.step(
"lift keeps full receiver shape through unknown array methods",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type ParkingPerson = {",
" name: string;",
" priorityRank: number;",
" defaultSpot: string;",
" active: boolean;",
"};",
"const liftPriority = lift((input: { people: ParkingPerson[]; other: string }) =>",
' input.people.filter((person) => person.active).slice(0).find((person) => person.name === "Alice")?.priorityRank === 1',
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "people");
assertStringIncludes(inputSchema, "active");
assertStringIncludes(inputSchema, "name");
assertStringIncludes(inputSchema, "priorityRank");
assertStringIncludes(inputSchema, "defaultSpot");
assertEquals(inputSchema.includes("other"), false);
},
);
await t.step(
"lift preserves full receiver shape when identity use overlaps an unknown chain",
async () => {
const source = [
"/// ",
'import { equals, lift } from "commonfabric";',
"type ParkingPerson = {",
" active: boolean;",
" name: string;",
" priorityRank: number;",
" defaultSpot: string;",
"};",
"const samePeople = lift((input: { people: ParkingPerson[] }) =>",
" equals(",
" input.people,",
" input.people.filter((person) => person.active).slice(0),",
" )",
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "people");
assertStringIncludes(inputSchema, "active");
assertStringIncludes(inputSchema, "name");
assertStringIncludes(inputSchema, "priorityRank");
assertStringIncludes(inputSchema, "defaultSpot");
},
);
await t.step(
"lift shrinks item fields through right-hand ?? fallback aliases",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"type Note = { title: string; body: string };",
"const cached = undefined as Note[] | undefined;",
"const liftTitles = lift((input: { notes: Note[] }) => {",
" const items = cached ?? input.notes;",
" for (const item of items) {",
" return item.title;",
" }",
' return "";',
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "notes");
assertStringIncludes(inputSchema, "title");
assertEquals(inputSchema.includes("body"), false);
},
);
await t.step(
"lift preserves array item properties named key",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
'type ColumnKey = "backlog" | "inProgress" | "review" | "done";',
"interface KanbanTask { id: string; title: string; column: ColumnKey; points: number; }",
"interface ColumnSummary {",
" key: ColumnKey;",
" title: string;",
" limit: number;",
" count: number;",
" overloaded: boolean;",
" items: KanbanTask[];",
"}",
"const liftOverloadedColumns = lift((summaries: ColumnSummary[]) =>",
" summaries",
" .filter((summary) => summary.overloaded)",
" .map((summary) => summary.key)",
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "overloaded");
assertStringIncludes(inputSchema, "key");
assertEquals(inputSchema.includes("title"), false);
assertEquals(inputSchema.includes("limit"), false);
},
);
await t.step(
"lift preserves chained || fallback fields in object inputs",
async () => {
const source = [
"/// ",
'import { lift } from "commonfabric";',
"const liftFirstOption = lift(",
" (state: { name: string; firstItem: string | undefined }) =>",
' state.name || state.firstItem || "default",',
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "name");
assertStringIncludes(inputSchema, "firstItem");
},
);
await t.step(
"lift narrows cell wrappers when callback only uses .get() on inferred input",
async () => {
const source = [
"/// ",
'import { lift, type Writable } from "commonfabric";',
"const value = {} as Writable;",
"const doubled = lift((v) => v.get() * 2)(value);",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, 'asCell: ["readonly"]');
assertEquals(inputSchema.includes("asOpaque: true"), false);
},
);
await t.step(
"lift narrows cell wrappers when expression-bodied callback is a direct .get() call",
async () => {
const source = [
"/// ",
'import { lift, type Writable } from "commonfabric";',
"const value = {} as Writable;",
"const copy = lift((v) => v.get())(value);",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, 'asCell: ["readonly"]');
assertEquals(inputSchema.includes("asOpaque: true"), false);
},
);
await t.step(
"handler preserves explicit primitive-object union event schemas through typeof narrowing",
async () => {
const source = [
"/// ",
'import { type Cell, handler } from "commonfabric";',
"type AppendValueEvent = { value?: number } | number | undefined;",
"const appendValueToList = handler(",
" (event: AppendValueEvent, context: { values: Cell }) => {",
' const rawValue = typeof event === "number" ? event : event?.value;',
" if (rawValue === undefined) return;",
" context.values.push(rawValue);",
" },",
");",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertEquals(
inputSchema === "true",
false,
"event schema should not widen to true",
);
assertStringIncludes(inputSchema, '"undefined"');
assertStringIncludes(inputSchema, "value");
},
);
await t.step(
"lift shrinks aliased fixed-symbol destructuring without pulling unrelated fields",
async () => {
const source = [
"/// ",
'import { lift, NAME as CF_NAME } from "commonfabric";',
"type Piece = {",
" [CF_NAME]?: string;",
" metadata: { author: string; tags: string[] };",
"};",
"const piece = {} as Piece;",
'const label = lift(({ piece: { [CF_NAME]: name } }) => name ?? "")({ piece });',
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "$NAME");
assertEquals(inputSchema.includes("metadata"), false);
assertEquals(inputSchema.includes("author"), false);
},
);
await t.step(
"pattern preserves defaults for fixed-symbol destructuring aliases",
async () => {
const source = [
"/// ",
'import { NAME as CF_NAME, pattern, UI } from "commonfabric";',
"type Piece = {",
" [CF_NAME]?: string;",
" metadata: { author: string; tags: string[] };",
"};",
'const p = pattern(({ [CF_NAME]: name = "Untitled" }) => ({',
" [UI]:
{name}
,",
"}));",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, "$NAME");
assertStringIncludes(inputSchema, '"default": "Untitled"');
},
);
await t.step(
"lift preserves nullable cell wrappers for equals-only root inputs",
async () => {
const source = [
"/// ",
'import { lift, equals, type Writable } from "commonfabric";',
"const state = {} as (Writable | undefined);",
"const same = lift((state) => equals(state, state))(state);",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
const inputSchema = extractSchemas(result.output)[0] ?? "";
assertStringIncludes(inputSchema, 'type: "undefined"');
assertStringIncludes(inputSchema, 'asCell: ["comparable"]');
},
);
await t.step(
"lift wildcard usage keeps conservative full-shape input schema",
async () => {
const source = [
'import { lift, type Writable } from "commonfabric";',
"const input = {} as Writable<{ foo: string; bar: string }>;",
"const d = lift((v: Writable<{ foo: string; bar: string }>) => {",
' const foo = v.key("foo").get();',
" Object.keys(v.get());",
" return foo;",
"})(input);",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
assertStringIncludes(result.output, 'asCell: ["readonly"]');
assertStringIncludes(result.output, '"foo"');
assertStringIncludes(result.output, '"bar"');
},
);
await t.step(
"handler wildcard usage keeps conservative full-shape state schema",
async () => {
const source = [
'import { handler, type Writable } from "commonfabric";',
"const h = handler((event: { id: string }, state: Writable<{ foo: string; bar: string }>) => {",
' const foo = state.key("foo").get();',
" Object.keys(state.get());",
" return foo + event.id;",
"});",
].join("\n");
const result = await validateSource(source, {
types: COMMONFABRIC_TYPES,
});
const errors = getErrors(result.diagnostics);
assertEquals(
errors.length,
0,
`expected no validation errors but got: ${
errors.map((e) => `${e.type}: ${e.message}`).join("; ")
}`,
);
assertStringIncludes(result.output, 'asCell: ["readonly"]');
assertStringIncludes(result.output, '"foo"');
assertStringIncludes(result.output, '"bar"');
},
);
});
function getShrinkErrors(
diagnostics: readonly TransformationDiagnostic[],
): TransformationDiagnostic[] {
return diagnostics.filter(
(d) =>
d.severity === "error" &&
(d.type === "schema:unknown-type-access" ||
d.type === "schema:path-not-in-type"),
);
}
function fmtErrors(diagnostics: readonly TransformationDiagnostic[]): string {
return getShrinkErrors(diagnostics).map((e) => e.message).join("; ");
}