import { describe, expect, it } from "vitest"; import type { ToolcraftControlSectionSchema } from "../schema/types"; import type { ToolcraftControlSectionModuleContribution, ToolcraftProductModuleContribution, } from "./contract/contribution"; import type { ToolcraftProductModuleDefinition, ToolcraftProductModuleRecord, } from "./contract/module-definition"; import { createTestToolcraftProductModuleDefinition } from "./testing/create-test-module-definition"; const ordinaryModuleRecord = { contractVersion: 2, contributions: [], defaultProviders: [], id: "image-export", portRequirements: [], provides: ["artifact.image-export"], requires: [], } as const satisfies ToolcraftProductModuleRecord; // @ts-expect-error Ordinary structural records do not carry the private module-definition brand. const ordinaryModuleDefinition: ToolcraftProductModuleDefinition = ordinaryModuleRecord; void ordinaryModuleDefinition; const illegalContributionKind = { id: "image-export.action", kind: "control-section", moduleId: "image-export", placement: { after: [], before: [], slot: "artifact-settings" }, runtimeSectionId: "runtime.image-export", section: { id: "test-section-1", controls: {}, layoutGroups: [], title: "Image Export", }, } as const; // @ts-expect-error Action contribution ids cannot identify control sections. const illegalKindContribution: ToolcraftProductModuleContribution = illegalContributionKind; void illegalKindContribution; const illegalContributionOwner = { id: "image-export.action", kind: "panel-action", moduleId: "video-export", role: "export-image", } as const; // @ts-expect-error Image action contributions belong only to the image-export module. const illegalOwnerContribution: ToolcraftProductModuleContribution = illegalContributionOwner; void illegalOwnerContribution; const illegalContributionRole = { id: "svg-export.action", kind: "panel-action", moduleId: "svg-export", role: "export-video", } as const; // @ts-expect-error SVG action contributions own only the export-svg role. const illegalRoleContribution: ToolcraftProductModuleContribution = illegalContributionRole; void illegalRoleContribution; const illegalCrossKindPlacement = { id: "image-export.settings", kind: "control-section", moduleId: "image-export", placement: { after: ["image-export.action"], before: [], slot: "artifact-settings", }, runtimeSectionId: "runtime.image-export", section: { id: "test-section-2", controls: {}, layoutGroups: [], title: "Image Export", }, } as const; // @ts-expect-error Artifact-settings placement can reference only artifact-settings contributions. const illegalPlacementContribution: ToolcraftProductModuleContribution = illegalCrossKindPlacement; void illegalPlacementContribution; const illegalSettingsOwner = { id: "video-export.settings", kind: "control-section", moduleId: "image-export", placement: { after: [], before: [], slot: "artifact-settings" }, runtimeSectionId: "runtime.video-export", section: { id: "test-section-3", controls: {}, layoutGroups: [], title: "Video Export", }, } as const; // @ts-expect-error Video settings contributions belong only to video-export. const illegalSettingsOwnerContribution: ToolcraftProductModuleContribution = illegalSettingsOwner; void illegalSettingsOwnerContribution; function assertDefinitionPayloadIsDeeplyReadonly( definition: ToolcraftProductModuleDefinition, ) { const settings = definition.contributions[0]; if (settings?.id !== "image-export.settings") { return; } const control = settings.section.controls.imageFormat; const layoutGroup = settings.section.layoutGroups[0]; if (control === undefined || layoutGroup === undefined) { return; } const canonicalSection: Omit = settings.section; void canonicalSection; // @ts-expect-error Artifact-settings control maps are readonly. settings.section.controls.imageFormat = control; // @ts-expect-error Artifact-settings controls are readonly. control.label = "Changed"; // @ts-expect-error Artifact-settings applicability records are readonly. control.applicability.mode = "always"; // @ts-expect-error Artifact-settings option arrays are readonly. control.options.push({ label: "Changed", value: "changed" }); // @ts-expect-error Artifact-settings option entries are readonly. control.options[0]!.label = "Changed"; // @ts-expect-error Artifact-settings layout-group arrays are readonly. settings.section.layoutGroups.push(layoutGroup); // @ts-expect-error Artifact-settings layout-group entries are readonly. layoutGroup.layout = "inline"; // @ts-expect-error Artifact-settings layout control arrays are readonly. layoutGroup.controls.push("changed"); } void assertDefinitionPayloadIsDeeplyReadonly; describe("Toolcraft product module definitions", () => { it("creates an immutable, alias-isolated image-export declaration", () => { const applicability: { mode: "always" } = { mode: "always" }; const formatOptions: { label: string; value: string }[] = [ { label: "PNG", value: "png" }, { label: "JPG", value: "jpg" }, ]; const formatControl: { applicability: { mode: "always" }; defaultValue: string; label: string; options: { label: string; value: string }[]; performanceRole: "responsiveness"; target: string; type: "select"; } = { applicability, defaultValue: "png", label: "Format", options: formatOptions, performanceRole: "responsiveness", target: "export.image.format", type: "select", }; const resolutionControl = { applicability: { mode: "always" as const } as const, defaultValue: "4k", label: "Resolution", options: [{ label: "4K", value: "4k" }], performanceRole: "workload" as const, target: "export.image.resolution", type: "select" as const, }; const controls = { imageFormat: formatControl, imageResolution: resolutionControl, }; const layoutGroup: { columns: 2; controls: string[]; layout: "inline"; } = { columns: 2, controls: ["imageFormat", "imageResolution"], layout: "inline", }; const layoutGroups = [layoutGroup]; const section = { controls, layoutGroups, title: "Image Export" }; const placementAfter: ( | "image-export.settings" | "video-export.settings" )[] = []; const placementBefore: ( | "image-export.settings" | "video-export.settings" )[] = ["video-export.settings"]; const placement: { after: ("image-export.settings" | "video-export.settings")[]; before: ("image-export.settings" | "video-export.settings")[]; slot: "artifact-settings"; } = { after: placementAfter, before: placementBefore, slot: "artifact-settings", }; const definition = createTestToolcraftProductModuleDefinition({ contributions: [ { id: "image-export.settings", kind: "control-section", moduleId: "image-export", placement, runtimeSectionId: "runtime.image-export", section, }, { id: "image-export.action", kind: "panel-action", moduleId: "image-export", role: "export-image", }, ], defaultProviders: [], id: "image-export", portRequirements: [ { applicability: "product-scene", id: "scene.rasterFrameRenderer", }, ], provides: ["artifact.image-export"], requires: [], }); expect(definition.contractVersion).toBe(2); expect(Object.isFrozen(definition)).toBe(true); expect(Object.isFrozen(definition.provides)).toBe(true); expect(Object.isFrozen(definition.requires)).toBe(true); expect(Object.isFrozen(definition.defaultProviders)).toBe(true); expect(Object.isFrozen(definition.portRequirements)).toBe(true); expect(definition.portRequirements.every(Object.isFrozen)).toBe(true); expect(Object.isFrozen(definition.contributions)).toBe(true); expect(definition.contributions.every(Object.isFrozen)).toBe(true); const settings = definition.contributions[0]; expect(settings?.kind).toBe("control-section"); if (settings?.id !== "image-export.settings") { return; } const frozenControl = settings.section.controls.imageFormat; const frozenLayoutGroup = settings.section.layoutGroups[0]; expect(frozenControl).toBeDefined(); expect(frozenLayoutGroup).toBeDefined(); if (frozenControl === undefined || frozenLayoutGroup === undefined) { return; } expect(Object.isFrozen(settings.placement)).toBe(true); expect(Object.isFrozen(settings.placement.after)).toBe(true); expect(Object.isFrozen(settings.placement.before)).toBe(true); expect(Object.isFrozen(settings.section)).toBe(true); expect(Object.isFrozen(settings.section.controls)).toBe(true); expect(Object.isFrozen(frozenControl)).toBe(true); expect(Object.isFrozen(frozenControl.applicability)).toBe(true); expect(Object.isFrozen(frozenControl.options)).toBe(true); expect(frozenControl.options.every(Object.isFrozen)).toBe(true); expect(frozenControl.performanceRole).toBe("responsiveness"); expect(Object.isFrozen(settings.section.layoutGroups)).toBe(true); expect(Object.isFrozen(frozenLayoutGroup)).toBe(true); expect(Object.isFrozen(frozenLayoutGroup.controls)).toBe(true); expect(settings.placement).not.toBe(placement); expect(settings.placement.after).not.toBe(placementAfter); expect(settings.placement.before).not.toBe(placementBefore); expect(settings.section).not.toBe(section); expect(settings.section.controls).not.toBe(controls); expect(frozenControl).not.toBe(formatControl); expect(frozenControl.applicability).not.toBe(applicability); expect(frozenControl.options).not.toBe(formatOptions); expect(frozenControl.options[0]).not.toBe(formatOptions[0]); expect(settings.section.layoutGroups).not.toBe(layoutGroups); expect(frozenLayoutGroup).not.toBe(layoutGroup); expect(frozenLayoutGroup.controls).not.toBe(layoutGroup.controls); formatControl.label = "Mutated Format"; formatOptions[0]!.label = "Mutated PNG"; formatOptions.push({ label: "GIF", value: "gif" }); controls.imageFormat = { ...formatControl, label: "Replacement Format", }; layoutGroup.controls[0] = "mutatedControl"; layoutGroups.push({ columns: 2, controls: ["replacement"], layout: "inline", }); placementAfter.push("image-export.settings"); placementBefore.push("image-export.settings"); section.title = "Mutated Image Export"; expect(frozenControl.label).toBe("Format"); expect(frozenControl.options).toEqual([ { label: "PNG", value: "png" }, { label: "JPG", value: "jpg" }, ]); expect(settings.section.controls.imageFormat).toBe(frozenControl); expect(frozenLayoutGroup.controls).toEqual([ "imageFormat", "imageResolution", ]); expect(settings.section.layoutGroups).toHaveLength(1); expect(settings.placement.after).toEqual([]); expect(settings.placement.before).toEqual(["video-export.settings"]); expect(settings.section.title).toBe("Image Export"); }); it("freezes a semantically valid timeline declaration", () => { const definition = createTestToolcraftProductModuleDefinition({ contributions: [ { id: "timeline.surface", kind: "panel-surface", moduleId: "timeline", surface: "timeline", configuration: { enabled: true, mode: "keyframes" }, }, { id: "timeline.persistence", kind: "persistence-requirement", moduleId: "timeline", slice: "timeline", }, ], defaultProviders: [], id: "timeline", portRequirements: [], provides: ["timeline.keyframes", "timeline.playback"], requires: [], }); expect(definition.contributions.every(Object.isFrozen)).toBe(true); const surface = definition.contributions[0]; expect(surface?.kind).toBe("panel-surface"); if (surface?.id === "timeline.surface") { expect(Object.isFrozen(surface.configuration)).toBe(true); } expect(definition.contributions[1]?.kind).toBe("persistence-requirement"); }); it("rejects a contribution owned by a different module before branding", () => { expect(() => createTestToolcraftProductModuleDefinition({ contributions: [ { id: "video-export.action", kind: "panel-action", moduleId: "video-export", role: "export-video", }, ], defaultProviders: [], id: "image-export", portRequirements: [], provides: ["artifact.image-export"], requires: [], }), ).toThrowError( 'Toolcraft product module "image-export" cannot include contribution "video-export.action" owned by "video-export".', ); }); });