import { describe, it } from "vitest"; import { defineToolcraft, defineToolcraftCustomControlType, type ToolcraftBuiltInControlType, type ToolcraftControlSchema, } from "../index"; import type { ToolcraftControlRendererMap } from "../react/controls-panel/control-renderers"; import { DEFAULT_TOOLCRAFT_ORIENTATION_POSE } from "../state/orientation-pose"; import type { ToolcraftCollectionItemControlSchema } from "./control-schema-collections"; type UnionKeys = T extends unknown ? keyof T : never; // A newly added top-level field must also be explicitly accepted or forbidden on items. type UnclassifiedItemFields = Exclude< UnionKeys, UnionKeys >; const allFieldsClassified: UnclassifiedItemFields extends never ? true : never = true; void allFieldsClassified; /** Not invoked: real tsc checks authoring, Vitest must never execute negative inputs. */ function checkAuthoringBoundary() { const controls = { actions: { applicability: { mode: "always", }, type: "actions", target: "actions", }, anchorGrid: { applicability: { mode: "always", }, type: "anchorGrid", target: "anchor", defaultValue: "center", }, aspectRatio: { applicability: { mode: "always", }, type: "aspectRatio", target: "canvas.aspectRatio", }, channelMixer: { applicability: { mode: "always", }, type: "channelMixer", target: "channels", }, checkbox: { applicability: { mode: "always", }, type: "checkbox", target: "checked", defaultValue: true, }, code: { applicability: { mode: "always", }, type: "code", target: "code", defaultValue: "return 1", }, collectionActions: { applicability: { mode: "always", }, type: "collectionActions", target: "items", defaultValue: [1], itemControl: { type: "slider", defaultValue: 1 }, }, color: { applicability: { mode: "always", }, type: "color", target: "color", defaultValue: { hex: "#abc" }, }, colorOpacity: { applicability: { mode: "always", }, type: "colorOpacity", target: "tint", defaultValue: "#abc", }, curves: { applicability: { mode: "always", }, type: "curves", target: "curve", }, fileDrop: { applicability: { mode: "always", }, type: "fileDrop", target: "model", assetKind: "model", modelFormats: ["glb"], }, fontPicker: { applicability: { mode: "always", }, type: "fontPicker", target: "font", defaultValue: "inter", }, gradient: { applicability: { mode: "always", }, type: "gradient", target: "gradient", defaultValue: { angle: 0, gradientType: "linear", stops: [ { color: "#000", position: "0%" }, { color: "#fff", position: "100%" }, ], }, }, imagePicker: { applicability: { mode: "always", }, type: "imagePicker", target: "image", defaultValue: "a", items: [{ src: "/a.png", value: "a" }], }, orientationGizmo: { applicability: { mode: "always", }, type: "orientationGizmo", target: "pose", defaultValue: DEFAULT_TOOLCRAFT_ORIENTATION_POSE, }, palette: { applicability: { mode: "always", }, type: "palette", target: "palette", defaultValue: { family: "blue", shade: "500" }, }, panelActions: { applicability: { mode: "always", }, type: "panelActions", target: "panel.actions", actions: ["reset"], }, rangeInput: { applicability: { mode: "always", }, type: "rangeInput", target: "range", defaultValue: { start: "0", end: "1" }, }, rangeSlider: { applicability: { mode: "always", }, type: "rangeSlider", target: "handles", defaultValue: [0, 1, 2], }, segmented: { applicability: { mode: "always", }, type: "segmented", target: "mode", defaultValue: "a", options: [{ label: "A", value: "a" }], }, select: { applicability: { mode: "always", }, type: "select", target: "choice", defaultValue: "a", options: [{ label: "A", value: "a" }], }, settingsTransfer: { applicability: { mode: "always", }, type: "settingsTransfer", target: "settings", }, slider: { applicability: { mode: "always", }, type: "slider", target: "amount", defaultValue: 1, sliderValueKind: "continuous", }, sourceCollection: { applicability: { mode: "always", }, type: "sourceCollection", target: "source", defaultValue: ["#abc"], itemControl: { type: "color" }, }, switch: { applicability: { mode: "always", }, type: "switch", target: "enabled", defaultValue: false, }, tabs: { applicability: { mode: "always", }, type: "tabs", target: "tab", defaultValue: "a", options: [{ label: "A", value: "a" }], }, text: { applicability: { mode: "always", }, type: "text", target: "text", defaultValue: "hello", }, vector: { applicability: { mode: "always", }, type: "vector", target: "position", defaultValue: { x: "2.5", y: "-1" }, }, } satisfies { [K in ToolcraftBuiltInControlType]: Extract< ToolcraftControlSchema, { type: K; } >; }; const wrongDefault = { ...controls.slider, defaultValue: "wrong" }; // @ts-expect-error Numeric slider defaults are checked through variables. const invalidDefault: ToolcraftControlSchema = wrongDefault; const foreignField = { ...controls.slider, options: [{ label: "A", value: "a" }], }; // @ts-expect-error Choice-only fields are rejected through spreads. const invalidField: ToolcraftControlSchema = foreignField; const wrongItem = { ...controls.collectionActions, itemControl: { type: "slider" as const, defaultValue: "wrong" }, }; // @ts-expect-error Single collection item controls use the same strict defaults. const invalidItem: ToolcraftControlSchema = wrongItem; const wrongFields = { type: "collectionActions" as const, target: "items", itemControls: { amount: { type: "slider" as const, options: [{ label: "A", value: "a" }], }, }, }; // @ts-expect-error Compound item controls reject fields from another branch. const invalidItems: ToolcraftControlSchema = wrongFields; const itemModelFields = { type: "slider" as const, defaultValue: 1, modelFormats: ["glb"] as const, }; const nestedModel: ToolcraftControlSchema = { applicability: { mode: "always", }, type: "collectionActions", target: "items", // @ts-expect-error Model-only fields are forbidden in single item variables. itemControl: itemModelFields, }; const nestedModels: ToolcraftControlSchema = { applicability: { mode: "always", }, type: "collectionActions", target: "items", // @ts-expect-error Compound item spreads retain the same model-only field boundary. itemControls: { amount: { ...itemModelFields } }, }; const wrongModel = { ...controls.slider, modelFormats: ["glb"] as const }; // @ts-expect-error Model-only configuration is exclusive to model fileDrop. const invalidModel: ToolcraftControlSchema = wrongModel; const typo: ToolcraftControlSchema = { applicability: { mode: "always", }, // @ts-expect-error Unregistered/typo names cannot use the custom branch. type: "sldier", target: "amount", }; // @ts-expect-error Built-ins cannot be registered as custom controls. defineToolcraftCustomControlType("slider"); const broadName: string = "dynamic"; // @ts-expect-error A broad string needs a real validated parsing boundary. defineToolcraftCustomControlType(broadName); // @ts-expect-error Empty names cannot be registered. defineToolcraftCustomControlType(""); // @ts-expect-error Blank literals cannot be registered. defineToolcraftCustomControlType(" \t"); // @ts-expect-error Leading whitespace has the same compile-time and runtime policy. defineToolcraftCustomControlType(" glyph"); // @ts-expect-error Unicode trailing trim whitespace is rejected too. defineToolcraftCustomControlType("glyph\u00a0"); const glyphDensity = defineToolcraftCustomControlType("glyphDensityEditor"); const custom = { type: glyphDensity, target: "glyph.density", defaultValue: { items: [] }, label: "Density", orderRole: "primary", applicability: { mode: "always" }, } satisfies ToolcraftControlSchema; defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft fixture", }, canvas: { enabled: true }, panels: { controls: { title: "Controls", sections: [ { id: "fixture-section-1", controls: { // @ts-expect-error The public defineToolcraft entry never accepts a loose descriptor. invalid: foreignField, }, }, ], }, }, }, modules: [], }); defineToolcraft({ base: { identity: { id: "runtime-test", title: "Toolcraft fixture", }, canvas: { enabled: true }, panels: { controls: { title: "Controls", sections: [ { id: "fixture-section-2", controls: { amount: controls.slider, density: custom }, }, ], }, }, }, modules: [], }); // @ts-expect-error Renderer maps cannot override built-in names. const invalidRenderers: ToolcraftControlRendererMap = { slider: () => null }; return { controls, custom, invalidDefault, invalidField, invalidItem, invalidItems, invalidModel, nestedModel, nestedModels, typo, invalidRenderers, }; } void checkAuthoringBoundary; describe("strict control authoring compiler fixtures", () => { it("keeps the compiler-only boundary fixture uncalled", () => {}); });