@pixel-point/toolcraft 0.0.17 → 0.0.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/generate-test-doc-assertions.mjs +58 -68
- package/src/generate-test-doc-assertions.test.mjs +43 -0
- package/src/generate-test-doc-policy-assertions.mjs +92 -0
- package/src/generate-test-file-assertions.mjs +26 -75
- package/src/generate-test-product-iteration.test.mjs +17 -0
- package/src/generate-test-runtime-boundary-assertions.mjs +158 -0
- package/src/generate-test-standalone-assertions.mjs +10 -0
- package/templates/runtime/contracts/component-contracts.choices.test.ts +47 -3
- package/templates/runtime/contracts/component-contracts.choices.ts +48 -3
- package/templates/runtime/contracts/component-contracts.inputs.test.ts +6 -6
- package/templates/runtime/contracts/component-contracts.inputs.ts +6 -6
- package/templates/runtime/contracts/component-contracts.media-custom.test.ts +8 -2
- package/templates/runtime/contracts/component-contracts.media-custom.ts +8 -2
- package/templates/runtime/contracts/component-contracts.runtime-acceptance.test.ts +4 -4
- package/templates/runtime/contracts/component-contracts.runtime-labels.test.ts +7 -1
- package/templates/runtime/contracts/component-contracts.runtime-panels.test.ts +3 -0
- package/templates/runtime/contracts/component-contracts.runtime-shell.test.ts +3 -0
- package/templates/runtime/contracts/component-contracts.runtime.ts +12 -8
- package/templates/runtime/contracts/component-contracts.test.ts +2 -0
- package/templates/runtime/contracts/decision-contracts.test.ts +18 -0
- package/templates/runtime/contracts/decision-contracts.ts +10 -10
- package/templates/runtime/export/export-background.ts +0 -19
- package/templates/runtime/export/export.test.ts +45 -42
- package/templates/runtime/export/index.ts +44 -16
- package/templates/runtime/index.ts +2 -0
- package/templates/runtime/model-import/model-import-limits.ts +15 -4
- package/templates/runtime/react/app-shell/runtime-public-api.test.tsx +11 -1
- package/templates/runtime/react/app-shell/toolcraft-app.scene-export.test.tsx +29 -0
- package/templates/runtime/react/app-shell/toolcraft-app.tsx +18 -8
- package/templates/runtime/react/canvas/canvas-shell-rendering.test.tsx +76 -0
- package/templates/runtime/react/canvas/canvas-shell-test-utils.tsx +13 -1
- package/templates/runtime/react/canvas/canvas-shell.tsx +16 -1
- package/templates/runtime/react/canvas/product-scene-surface.test.tsx +195 -0
- package/templates/runtime/react/canvas/product-scene-surface.tsx +155 -0
- package/templates/runtime/react/canvas/runtime-scene-export.ts +1 -1
- package/templates/runtime/react/controls-panel/__tests__/control-conditions.test.ts +61 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.collection-actions.test.tsx +89 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.control-visibility.test.tsx +40 -19
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.scene-export-actions.test.tsx +1 -1
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-collection.test.tsx +62 -0
- package/templates/runtime/react/controls-panel/__tests__/controls-panel.source-color-bank.test.tsx +67 -0
- package/templates/runtime/react/controls-panel/actions/controls-panel-actions.ts +2 -4
- package/templates/runtime/react/controls-panel/actions/export-action-runner.ts +10 -4
- package/templates/runtime/react/controls-panel/conditions/control-conditions.ts +32 -119
- package/templates/runtime/react/controls-panel/layout/controls-panel-control-group.tsx +5 -2
- package/templates/runtime/react/controls-panel/layout/controls-panel-layout.tsx +10 -8
- package/templates/runtime/react/controls-panel/layout/controls-panel-section.tsx +3 -3
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.test.tsx +63 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-item-fields.tsx +138 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-items.tsx +104 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-collection-renderer.tsx +115 -236
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.test.tsx +95 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-file-drop-item-controls.tsx +82 -0
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.test.tsx +73 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-media-renderer.tsx +50 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.test.ts +1 -1
- package/templates/runtime/react/controls-panel/renderers/controls-panel-renderer-registry.ts +2 -1
- package/templates/runtime/react/controls-panel/values/controls-panel-collection-values.ts +38 -6
- package/templates/runtime/react/controls-panel/values/controls-panel-value-labels.ts +1 -0
- package/templates/runtime/react/index.ts +4 -0
- package/templates/runtime/react/model-rendering/model-export.ts +1 -1
- package/templates/runtime/react/orientation-gizmo/orientation-gizmo-selection.ts +5 -5
- package/templates/runtime/react/orientation-gizmo/use-toolcraft-orientation-control-selection.ts +2 -2
- package/templates/runtime/scene/scene-bounds.test.ts +23 -0
- package/templates/runtime/scene/scene-bounds.ts +31 -17
- package/templates/runtime/schema/app-capabilities.test.ts +4 -0
- package/templates/runtime/schema/collection-item-controls.ts +29 -0
- package/templates/runtime/schema/control-applicability.test.ts +127 -0
- package/templates/runtime/schema/control-applicability.ts +433 -0
- package/templates/runtime/schema/control-schema-normalization.ts +177 -11
- package/templates/runtime/schema/controls-panel-actions.ts +2 -2
- package/templates/runtime/schema/controls-panel-section-layout.ts +14 -9
- package/templates/runtime/schema/controls-panel-section-roundtrip.test.ts +59 -0
- package/templates/runtime/schema/define-toolcraft.collection-actions-item-controls.test.ts +127 -0
- package/templates/runtime/schema/define-toolcraft.control-sections.test.ts +10 -4
- package/templates/runtime/schema/define-toolcraft.file-drop-item-controls.test.ts +98 -0
- package/templates/runtime/schema/define-toolcraft.file-drop-normalization.test.ts +27 -0
- package/templates/runtime/schema/define-toolcraft.segmented-control-fit.test.ts +20 -2
- package/templates/runtime/schema/define-toolcraft.setup-canvas.test.ts +16 -3
- package/templates/runtime/schema/define-toolcraft.source-collection.test.ts +79 -0
- package/templates/runtime/schema/runtime-setup-section.ts +24 -5
- package/templates/runtime/schema/types.ts +68 -13
- package/templates/starter/AGENTS.md +12 -10
- package/templates/starter/docs/toolcraft/acceptance-testing.md +17 -31
- package/templates/starter/docs/toolcraft/agent-worklog.md +15 -0
- package/templates/starter/docs/toolcraft/assembly-workflow.md +10 -3
- package/templates/starter/docs/toolcraft/component-rules.md +8 -6
- package/templates/starter/docs/toolcraft/core/control-selection.md +9 -3
- package/templates/starter/docs/toolcraft/core/layout.md +7 -7
- package/templates/starter/docs/toolcraft/core/media-upload.md +2 -0
- package/templates/starter/docs/toolcraft/core/runtime-boundary.md +13 -2
- package/templates/starter/docs/toolcraft/core/setup-export.md +33 -7
- package/templates/starter/docs/toolcraft/custom-controls.md +6 -4
- package/templates/starter/docs/toolcraft/decision-contract.md +3 -1
- package/templates/starter/docs/toolcraft/renderer-technique.md +4 -0
- package/templates/starter/docs/toolcraft/schema-reference.md +21 -19
- package/templates/starter/e2e/app-browser-control-applicability-requirements.spec.ts +163 -0
- package/templates/starter/e2e/app-browser-infinity-canvas-evidence.spec.ts +7 -2
- package/templates/starter/e2e/app-browser-orientation-evidence.spec.ts +174 -21
- package/templates/starter/e2e/app-browser-runtime-requirements.spec.ts +1 -33
- package/templates/starter/e2e/app-browser-semantic-evidence.spec.ts +61 -15
- package/templates/starter/e2e/{browser-conditional-output-evidence-helpers.ts → browser-background-output-evidence.ts} +0 -68
- package/templates/starter/e2e/browser-control-applicability-evidence.ts +114 -0
- package/templates/starter/e2e/browser-infinity-canvas-evidence.ts +20 -11
- package/templates/starter/e2e/browser-orientation-gizmo-evidence-helpers.ts +4 -0
- package/templates/starter/e2e/browser-orientation-gizmo-live-preconditions.ts +86 -0
- package/templates/starter/e2e/browser-runtime-applicability-requirements.ts +84 -0
- package/templates/starter/e2e/browser-runtime-evidence-reporter.ts +9 -2
- package/templates/starter/e2e/browser-runtime-evidence-requirements.ts +29 -26
- package/templates/starter/e2e/browser-semantic-evidence-test-helpers.ts +25 -0
- package/templates/starter/scripts/toolcraft-contract-manifest.json +1 -0
- package/templates/starter/scripts/toolcraft-product-boundary-ast.mjs +85 -115
- package/templates/starter/scripts/toolcraft-product-boundary-module-policy.mjs +101 -0
- package/templates/starter/scripts/toolcraft-product-boundary.test.mjs +0 -72
- package/templates/starter/scripts/toolcraft-product-control-bindings.mjs +182 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.mjs +146 -0
- package/templates/starter/scripts/toolcraft-product-control-boundary.test.mjs +186 -0
- package/templates/starter/scripts/toolcraft-product-export-boundary.mjs +6 -17
- package/templates/starter/scripts/toolcraft-product-export-boundary.test.mjs +196 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence-structure.test.mjs +20 -0
- package/templates/starter/scripts/toolcraft-typescript-source-evidence.mjs +1 -0
- package/templates/starter/scripts/toolcraft-unavailable-resource-evidence-facade.test.mjs +2 -0
- package/templates/starter/src/app/acceptance/artifact-export-intent.ts +130 -0
- package/templates/starter/src/app/acceptance/conditions.ts +1 -1
- package/templates/starter/src/app/acceptance/control-acceptance-context.ts +2 -2
- package/templates/starter/src/app/acceptance/control-acceptance-coverage.ts +6 -20
- package/templates/starter/src/app/acceptance/control-acceptance-kind-rules.ts +24 -5
- package/templates/starter/src/app/acceptance/control-acceptance-policy.ts +2 -13
- package/templates/starter/src/app/acceptance/control-applicability-cases.test.ts +321 -0
- package/templates/starter/src/app/acceptance/control-applicability-cases.ts +290 -0
- package/templates/starter/src/app/acceptance/control-applicability.ts +332 -0
- package/templates/starter/src/app/acceptance/control-layout-dependency-rules.ts +20 -9
- package/templates/starter/src/app/acceptance/control-layout-entity-rules.ts +4 -6
- package/templates/starter/src/app/acceptance/control-layout-model.ts +4 -4
- package/templates/starter/src/app/acceptance/control-layout-section-rules.ts +3 -10
- package/templates/starter/src/app/acceptance/control-parts.ts +8 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.test.ts +215 -0
- package/templates/starter/src/app/acceptance/control-section-entity-cohesion.ts +132 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.test.ts +87 -0
- package/templates/starter/src/app/acceptance/control-section-inventory.ts +74 -44
- package/templates/starter/src/app/acceptance/custom-controls.ts +11 -3
- package/templates/starter/src/app/acceptance/inline-layout.ts +64 -9
- package/templates/starter/src/app/acceptance/media-upload.ts +5 -1
- package/templates/starter/src/app/acceptance/orientation-gizmo.ts +18 -11
- package/templates/starter/src/app/acceptance/output-background-rules.ts +2 -2
- package/templates/starter/src/app/acceptance/output-export-layout-rules.ts +18 -10
- package/templates/starter/src/app/acceptance/output-export-model.ts +54 -11
- package/templates/starter/src/app/acceptance/output-export.ts +22 -10
- package/templates/starter/src/app/acceptance/output-video-export-rules.ts +99 -0
- package/templates/starter/src/app/acceptance/types.ts +23 -8
- package/templates/starter/src/app/acceptance/validate-coverage.ts +19 -2
- package/templates/starter/src/app/starter-acceptance.artifact-export-intent.test.ts +239 -0
- package/templates/starter/src/app/starter-acceptance.background-export.test.ts +33 -0
- package/templates/starter/src/app/starter-acceptance.canvas-sizing.test.ts +16 -1
- package/templates/starter/src/app/starter-acceptance.compound-part-coverage.test.ts +65 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.test.ts +41 -0
- package/templates/starter/src/app/starter-acceptance.contract-fixtures.ts +112 -16
- package/templates/starter/src/app/starter-acceptance.control-applicability.test.ts +224 -0
- package/templates/starter/src/app/starter-acceptance.control-order.test.ts +58 -3
- package/templates/starter/src/app/starter-acceptance.control-state.test.ts +0 -111
- package/templates/starter/src/app/starter-acceptance.custom-control-collections.test.ts +3 -1
- package/templates/starter/src/app/starter-acceptance.custom-control-valid.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.export-test-utils.ts +22 -0
- package/templates/starter/src/app/{starter-acceptance.image-video-export-settings.test.ts → starter-acceptance.image-export-settings.test.ts} +37 -9
- package/templates/starter/src/app/starter-acceptance.interaction-ownership.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.media-upload.fixtures.ts +11 -1
- package/templates/starter/src/app/starter-acceptance.media-upload.test.ts +28 -0
- package/templates/starter/src/app/starter-acceptance.output-export-intent.test.ts +384 -0
- package/templates/starter/src/app/starter-acceptance.output-export-rules.test.ts +4 -0
- package/templates/starter/src/app/starter-acceptance.product-output-export.test.ts +112 -105
- package/templates/starter/src/app/starter-acceptance.product-readiness.test.ts +12 -0
- package/templates/starter/src/app/starter-acceptance.section-cohesion.test.ts +1 -1
- package/templates/starter/src/app/starter-acceptance.section-dependencies.test.ts +35 -24
- package/templates/starter/src/app/starter-acceptance.section-size.test.ts +72 -0
- package/templates/starter/src/app/starter-acceptance.ts +11 -2
- package/templates/starter/src/app/starter-acceptance.video-export-settings.test.ts +336 -0
- package/templates/starter/src/app/starter-acceptance.view-interaction.test.ts +8 -0
- package/templates/starter/src/app/test-evidence/browser-runtime-contract.ts +2 -2
- package/templates/starter/src/routes/index.tsx +1 -0
- package/templates/ui/components/composites/tabs.tsx +2 -2
- package/templates/ui/components/controls/collection-actions/collection-item-groups.test.tsx +38 -0
- package/templates/ui/components/controls/collection-actions/collection-item-groups.tsx +36 -0
- package/templates/ui/components/controls/collection-actions/index.ts +2 -0
- package/templates/ui/components/controls/file-drop/file-drop-collection-control.tsx +137 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.test.tsx +189 -0
- package/templates/ui/components/controls/file-drop/file-drop-control.tsx +81 -88
- package/templates/ui/components/controls/file-drop/file-drop-presentation.tsx +131 -9
- package/templates/ui/components/controls/file-drop/file-drop-types.ts +36 -22
- package/templates/ui/components/controls/file-drop/index.ts +1 -0
- package/templates/ui/components/controls/index.ts +3 -0
- package/templates/ui/components/controls/range-slider/range-slider-control.tsx +1 -1
- package/templates/ui/components/controls/range-slider/range-slider-value.test.ts +14 -0
- package/templates/ui/components/controls/range-slider/range-slider-value.ts +3 -2
- package/templates/starter/src/app/acceptance/condition-exclusivity.test.ts +0 -60
- package/templates/starter/src/app/acceptance/condition-exclusivity.ts +0 -221
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import test from "node:test";
|
|
3
|
+
|
|
4
|
+
import { evaluateToolcraftProductBoundary } from "./toolcraft-product-boundary.mjs";
|
|
5
|
+
import { createToolcraftProductBoundaryFixture as createFixture } from "./toolcraft-product-boundary-test-fixtures.mjs";
|
|
6
|
+
|
|
7
|
+
test("keeps artifact encoding and download mechanics runtime-owned", async (context) => {
|
|
8
|
+
const workspaceRuntimeExportSpecifier = [
|
|
9
|
+
"@repo",
|
|
10
|
+
"toolcraft-runtime",
|
|
11
|
+
"export",
|
|
12
|
+
"image-artifact-export",
|
|
13
|
+
].join("/");
|
|
14
|
+
const rootDir = await createFixture(context, {
|
|
15
|
+
"src/features/export-mechanics.ts": `
|
|
16
|
+
import { createToolcraftVideoEncoderBackend as createAliasBackend } from "@/toolcraft/runtime/export/video-encoding-backend";
|
|
17
|
+
import { exportToolcraftImageArtifact } from "${workspaceRuntimeExportSpecifier}";
|
|
18
|
+
import { downloadToolcraftArtifact } from "../toolcraft/runtime/export/artifact-download";
|
|
19
|
+
import { Output } from "mediabunny";
|
|
20
|
+
export function exportArtifact(canvas: HTMLCanvasElement) {
|
|
21
|
+
const recorder = new MediaRecorder(canvas.captureStream());
|
|
22
|
+
const encoder = new VideoEncoder({ error() {}, output() {} });
|
|
23
|
+
canvas.toBlob(() => undefined);
|
|
24
|
+
canvas.toDataURL();
|
|
25
|
+
URL.createObjectURL(new Blob());
|
|
26
|
+
void createAliasBackend;
|
|
27
|
+
void exportToolcraftImageArtifact;
|
|
28
|
+
void downloadToolcraftArtifact;
|
|
29
|
+
void Output;
|
|
30
|
+
void recorder;
|
|
31
|
+
void encoder;
|
|
32
|
+
}
|
|
33
|
+
`,
|
|
34
|
+
"src/features/safe-renderer.ts": `
|
|
35
|
+
import * as Runtime from "@/toolcraft/runtime";
|
|
36
|
+
import {
|
|
37
|
+
getToolcraftImageExportSize,
|
|
38
|
+
shouldIncludeToolcraftPreviewBackground,
|
|
39
|
+
validateToolcraftArtifactSize,
|
|
40
|
+
} from "@/toolcraft/runtime";
|
|
41
|
+
import type {
|
|
42
|
+
ToolcraftExportFrame,
|
|
43
|
+
ToolcraftProductExportRenderer,
|
|
44
|
+
} from "@/toolcraft/runtime";
|
|
45
|
+
export const renderFrame = ({ context }) => context.fillRect(0, 0, 1, 1);
|
|
46
|
+
void Runtime;
|
|
47
|
+
void getToolcraftImageExportSize;
|
|
48
|
+
void shouldIncludeToolcraftPreviewBackground;
|
|
49
|
+
void validateToolcraftArtifactSize;
|
|
50
|
+
void (null as unknown as ToolcraftExportFrame);
|
|
51
|
+
void (null as unknown as ToolcraftProductExportRenderer);
|
|
52
|
+
`,
|
|
53
|
+
"src/features/shadowed-globals.ts": `
|
|
54
|
+
export function localNames(MediaRecorder, VideoEncoder, URL) {
|
|
55
|
+
void new MediaRecorder();
|
|
56
|
+
void new VideoEncoder();
|
|
57
|
+
URL.createObjectURL();
|
|
58
|
+
}
|
|
59
|
+
`,
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const result = await evaluateToolcraftProductBoundary({ rootDir });
|
|
63
|
+
|
|
64
|
+
assert.equal(result.violations.length, 10);
|
|
65
|
+
assert.equal(
|
|
66
|
+
result.violations.every(
|
|
67
|
+
(violation) => violation.kind === "runtime-export-ownership",
|
|
68
|
+
),
|
|
69
|
+
true,
|
|
70
|
+
);
|
|
71
|
+
assert.equal(
|
|
72
|
+
result.violations.some((violation) =>
|
|
73
|
+
violation.repoPath.endsWith("shadowed-globals.ts"),
|
|
74
|
+
),
|
|
75
|
+
false,
|
|
76
|
+
);
|
|
77
|
+
assert.equal(
|
|
78
|
+
result.violations.some((violation) =>
|
|
79
|
+
violation.repoPath.endsWith("safe-renderer.ts"),
|
|
80
|
+
),
|
|
81
|
+
false,
|
|
82
|
+
);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("classifies every runtime export mechanics module reference once", async (context) => {
|
|
86
|
+
const workspaceRuntimeExportRoot = [
|
|
87
|
+
"@repo",
|
|
88
|
+
"toolcraft-runtime",
|
|
89
|
+
"export",
|
|
90
|
+
].join("/");
|
|
91
|
+
const rootDir = await createFixture(context, {
|
|
92
|
+
"src/features/dynamic-import.ts": `
|
|
93
|
+
export async function loadMedia() {
|
|
94
|
+
return import("mediabunny");
|
|
95
|
+
}
|
|
96
|
+
`,
|
|
97
|
+
"src/features/import-equals.ts": `
|
|
98
|
+
import Backend = require("@/toolcraft/runtime/export/video-encoding-backend");
|
|
99
|
+
void Backend;
|
|
100
|
+
`,
|
|
101
|
+
"src/features/import-type.ts": `
|
|
102
|
+
type Backend = import("@/toolcraft/runtime/export/video-encoding-backend").ToolcraftVideoEncoderBackend;
|
|
103
|
+
void (null as unknown as Backend);
|
|
104
|
+
`,
|
|
105
|
+
"src/features/regular-export.ts": `
|
|
106
|
+
export {
|
|
107
|
+
createToolcraftVideoEncoderBackend as createFirstBackend,
|
|
108
|
+
createToolcraftVideoEncoderBackend as createSecondBackend,
|
|
109
|
+
} from "@/toolcraft/runtime/export/video-encoding-backend";
|
|
110
|
+
`,
|
|
111
|
+
"src/features/regular-import.ts": `
|
|
112
|
+
import {
|
|
113
|
+
createToolcraftVideoEncoderBackend as createFirstBackend,
|
|
114
|
+
createToolcraftVideoEncoderBackend as createSecondBackend,
|
|
115
|
+
} from "@/toolcraft/runtime/export/video-encoding-backend";
|
|
116
|
+
void createFirstBackend;
|
|
117
|
+
void createSecondBackend;
|
|
118
|
+
`,
|
|
119
|
+
"src/features/require.ts": `
|
|
120
|
+
export const backend = require("${workspaceRuntimeExportRoot}/video-encoding-backend");
|
|
121
|
+
`,
|
|
122
|
+
"src/features/safe-root-type-import.ts": `
|
|
123
|
+
import type { ToolcraftExportFrame } from "@/toolcraft/runtime";
|
|
124
|
+
void (null as unknown as ToolcraftExportFrame);
|
|
125
|
+
`,
|
|
126
|
+
"src/features/side-effect-import.ts": `import "mediabunny";`,
|
|
127
|
+
"src/features/type-only-export.ts": `
|
|
128
|
+
export type {
|
|
129
|
+
ToolcraftImageArtifactExportRequest,
|
|
130
|
+
ToolcraftImageArtifactExportResult,
|
|
131
|
+
} from "${workspaceRuntimeExportRoot}/image-artifact-export";
|
|
132
|
+
`,
|
|
133
|
+
"src/features/type-only-import-equals.ts": `
|
|
134
|
+
import type Backend = require("@/toolcraft/runtime/export/video-encoding-backend");
|
|
135
|
+
void (null as unknown as Backend);
|
|
136
|
+
`,
|
|
137
|
+
"src/features/type-only-import.ts": `
|
|
138
|
+
import type {
|
|
139
|
+
ToolcraftVideoArtifactExportRequest,
|
|
140
|
+
ToolcraftVideoArtifactExportResult,
|
|
141
|
+
} from "${workspaceRuntimeExportRoot}/video-artifact-export";
|
|
142
|
+
void (null as unknown as ToolcraftVideoArtifactExportRequest);
|
|
143
|
+
void (null as unknown as ToolcraftVideoArtifactExportResult);
|
|
144
|
+
`,
|
|
145
|
+
"src/features/typeof-import-type.ts": `
|
|
146
|
+
type MediaBunny = typeof import("mediabunny");
|
|
147
|
+
void (null as unknown as MediaBunny);
|
|
148
|
+
`,
|
|
149
|
+
"src/features/export-boundary.test.ts": `
|
|
150
|
+
import type { ToolcraftVideoEncoderBackend } from "@/toolcraft/runtime/export/video-encoding-backend";
|
|
151
|
+
void (null as unknown as ToolcraftVideoEncoderBackend);
|
|
152
|
+
`,
|
|
153
|
+
"e2e/test-support/export-fixture.ts": `
|
|
154
|
+
export type { ToolcraftVideoEncoderBackend } from "@/toolcraft/runtime/export/video-encoding-backend";
|
|
155
|
+
`,
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
const result = await evaluateToolcraftProductBoundary({ rootDir });
|
|
159
|
+
|
|
160
|
+
assert.deepEqual(
|
|
161
|
+
result.violations.map(({ repoPath }) => repoPath).sort(),
|
|
162
|
+
[
|
|
163
|
+
"src/features/dynamic-import.ts",
|
|
164
|
+
"src/features/import-equals.ts",
|
|
165
|
+
"src/features/import-type.ts",
|
|
166
|
+
"src/features/regular-export.ts",
|
|
167
|
+
"src/features/regular-import.ts",
|
|
168
|
+
"src/features/require.ts",
|
|
169
|
+
"src/features/side-effect-import.ts",
|
|
170
|
+
"src/features/type-only-export.ts",
|
|
171
|
+
"src/features/type-only-import-equals.ts",
|
|
172
|
+
"src/features/type-only-import.ts",
|
|
173
|
+
"src/features/typeof-import-type.ts",
|
|
174
|
+
],
|
|
175
|
+
);
|
|
176
|
+
assert.equal(
|
|
177
|
+
new Set(result.violations.map(({ repoPath }) => repoPath)).size,
|
|
178
|
+
result.violations.length,
|
|
179
|
+
);
|
|
180
|
+
assert.equal(
|
|
181
|
+
result.violations.every(
|
|
182
|
+
(violation) => violation.kind === "runtime-export-ownership",
|
|
183
|
+
),
|
|
184
|
+
true,
|
|
185
|
+
);
|
|
186
|
+
assert.equal(
|
|
187
|
+
result.violations.some(({ repoPath }) =>
|
|
188
|
+
[
|
|
189
|
+
"src/features/export-boundary.test.ts",
|
|
190
|
+
"src/features/safe-root-type-import.ts",
|
|
191
|
+
"e2e/test-support/export-fixture.ts",
|
|
192
|
+
].includes(repoPath),
|
|
193
|
+
),
|
|
194
|
+
false,
|
|
195
|
+
);
|
|
196
|
+
});
|
|
@@ -41,4 +41,24 @@ test("keeps TypeScript parsing and boundary facts on one canonical path", async
|
|
|
41
41
|
assert.deepEqual(checkerOwners, [
|
|
42
42
|
"toolcraft-typescript-analysis.mjs",
|
|
43
43
|
]);
|
|
44
|
+
|
|
45
|
+
const productBoundarySource = await fs.readFile(
|
|
46
|
+
path.join(scriptsDir, "toolcraft-product-boundary-ast.mjs"),
|
|
47
|
+
"utf8",
|
|
48
|
+
);
|
|
49
|
+
const controlBoundarySource = await fs.readFile(
|
|
50
|
+
path.join(scriptsDir, "toolcraft-product-control-boundary.mjs"),
|
|
51
|
+
"utf8",
|
|
52
|
+
);
|
|
53
|
+
const modulePolicySource = await fs.readFile(
|
|
54
|
+
path.join(scriptsDir, "toolcraft-product-boundary-module-policy.mjs"),
|
|
55
|
+
"utf8",
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
assert.match(productBoundarySource, /createToolcraftProductControlInspector/u);
|
|
59
|
+
assert.match(
|
|
60
|
+
modulePolicySource,
|
|
61
|
+
/isToolcraftPrivateControlImplementationModule/u,
|
|
62
|
+
);
|
|
63
|
+
assert.doesNotMatch(controlBoundarySource, /(?:ts\.)?createSourceFile\(/u);
|
|
44
64
|
});
|
|
@@ -300,6 +300,7 @@ export async function createToolcraftTypeScriptSourceRecord({
|
|
|
300
300
|
inspectors.createToolcraftStaticStringResolver(sourceFile, checker);
|
|
301
301
|
const inspectorInput = {
|
|
302
302
|
absolutePath,
|
|
303
|
+
checker,
|
|
303
304
|
getNodeLocation,
|
|
304
305
|
repoPath,
|
|
305
306
|
resolveStaticString,
|
|
@@ -29,6 +29,7 @@ function createFiniteObservation(width, height) {
|
|
|
29
29
|
finiteControlSize: { height, width },
|
|
30
30
|
finiteControlsPresent: true,
|
|
31
31
|
overflow: "hidden",
|
|
32
|
+
productSceneStatus: null,
|
|
32
33
|
sceneRect: null,
|
|
33
34
|
viewportOffset: { x: 0, y: 0 },
|
|
34
35
|
};
|
|
@@ -42,6 +43,7 @@ function createInfiniteObservation() {
|
|
|
42
43
|
finiteControlSize: null,
|
|
43
44
|
finiteControlsPresent: false,
|
|
44
45
|
overflow: "visible",
|
|
46
|
+
productSceneStatus: "ready",
|
|
45
47
|
sceneRect: { height: 400, width: 640, x: -320, y: -200 },
|
|
46
48
|
viewportOffset: { x: 0, y: 0 },
|
|
47
49
|
};
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import type { ToolcraftArtifactExportIntent } from "./types";
|
|
2
|
+
|
|
3
|
+
export type ToolcraftArtifactExportDelivery = Readonly<{
|
|
4
|
+
imageEnabled: boolean;
|
|
5
|
+
videoEnabled: boolean;
|
|
6
|
+
}>;
|
|
7
|
+
|
|
8
|
+
export type ToolcraftArtifactExportSchemaFacts = Readonly<{
|
|
9
|
+
hasImageExportAction: boolean;
|
|
10
|
+
hasImageExportSection: boolean;
|
|
11
|
+
hasVideoExportAction: boolean;
|
|
12
|
+
hasVideoExportSection: boolean;
|
|
13
|
+
}>;
|
|
14
|
+
|
|
15
|
+
export type ToolcraftArtifactExportIntentValidation = Readonly<{
|
|
16
|
+
delivery: ToolcraftArtifactExportDelivery;
|
|
17
|
+
errors: readonly string[];
|
|
18
|
+
}>;
|
|
19
|
+
|
|
20
|
+
export function resolveToolcraftArtifactExportIntent(
|
|
21
|
+
intent: ToolcraftArtifactExportIntent,
|
|
22
|
+
): ToolcraftArtifactExportDelivery {
|
|
23
|
+
return Object.freeze({
|
|
24
|
+
imageEnabled: intent.image.mode !== "user-removed",
|
|
25
|
+
videoEnabled: intent.video.mode === "user-requested",
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getToolcraftArtifactExportIntentEvidenceErrors(
|
|
30
|
+
intent: ToolcraftArtifactExportIntent,
|
|
31
|
+
): readonly string[] {
|
|
32
|
+
const errors: string[] = [];
|
|
33
|
+
|
|
34
|
+
if (
|
|
35
|
+
intent.image.mode !== "toolcraft-default" &&
|
|
36
|
+
intent.image.evidence.trim() === ""
|
|
37
|
+
) {
|
|
38
|
+
errors.push(
|
|
39
|
+
`Image export ${intent.image.mode} intent requires non-empty evidence.`,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (
|
|
44
|
+
intent.video.mode === "user-requested" &&
|
|
45
|
+
intent.video.evidence.trim() === ""
|
|
46
|
+
) {
|
|
47
|
+
errors.push(
|
|
48
|
+
"Video export user-requested intent requires non-empty evidence.",
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return errors;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function getToolcraftArtifactCorrespondenceErrors({
|
|
56
|
+
actionRole,
|
|
57
|
+
artifact,
|
|
58
|
+
enabled,
|
|
59
|
+
hasAction,
|
|
60
|
+
hasSection,
|
|
61
|
+
intentMode,
|
|
62
|
+
sectionArticle,
|
|
63
|
+
sectionTitle,
|
|
64
|
+
}: Readonly<{
|
|
65
|
+
actionRole: "export-image" | "export-video";
|
|
66
|
+
artifact: "Image" | "Video";
|
|
67
|
+
enabled: boolean;
|
|
68
|
+
hasAction: boolean;
|
|
69
|
+
hasSection: boolean;
|
|
70
|
+
intentMode:
|
|
71
|
+
| ToolcraftArtifactExportIntent["image"]["mode"]
|
|
72
|
+
| ToolcraftArtifactExportIntent["video"]["mode"];
|
|
73
|
+
sectionArticle: "a" | "an";
|
|
74
|
+
sectionTitle: "Image Export" | "Video Export";
|
|
75
|
+
}>): string[] {
|
|
76
|
+
const errors: string[] = [];
|
|
77
|
+
const requirement = enabled ? "requires" : "must not have";
|
|
78
|
+
|
|
79
|
+
if (hasAction !== enabled) {
|
|
80
|
+
errors.push(
|
|
81
|
+
`${artifact} export intent "${intentMode}" ${requirement} an ${actionRole} panel action.`,
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if (hasSection !== enabled) {
|
|
86
|
+
errors.push(
|
|
87
|
+
`${artifact} export intent "${intentMode}" ${requirement} ${sectionArticle} "${sectionTitle}" section.`,
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
return errors;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export function validateToolcraftArtifactExportIntentCorrespondence({
|
|
95
|
+
hasImageExportAction,
|
|
96
|
+
hasImageExportSection,
|
|
97
|
+
hasVideoExportAction,
|
|
98
|
+
hasVideoExportSection,
|
|
99
|
+
intent,
|
|
100
|
+
}: ToolcraftArtifactExportSchemaFacts &
|
|
101
|
+
Readonly<{
|
|
102
|
+
intent: ToolcraftArtifactExportIntent;
|
|
103
|
+
}>): ToolcraftArtifactExportIntentValidation {
|
|
104
|
+
const delivery = resolveToolcraftArtifactExportIntent(intent);
|
|
105
|
+
const errors = [
|
|
106
|
+
...getToolcraftArtifactExportIntentEvidenceErrors(intent),
|
|
107
|
+
...getToolcraftArtifactCorrespondenceErrors({
|
|
108
|
+
actionRole: "export-image",
|
|
109
|
+
artifact: "Image",
|
|
110
|
+
enabled: delivery.imageEnabled,
|
|
111
|
+
hasAction: hasImageExportAction,
|
|
112
|
+
hasSection: hasImageExportSection,
|
|
113
|
+
intentMode: intent.image.mode,
|
|
114
|
+
sectionArticle: "an",
|
|
115
|
+
sectionTitle: "Image Export",
|
|
116
|
+
}),
|
|
117
|
+
...getToolcraftArtifactCorrespondenceErrors({
|
|
118
|
+
actionRole: "export-video",
|
|
119
|
+
artifact: "Video",
|
|
120
|
+
enabled: delivery.videoEnabled,
|
|
121
|
+
hasAction: hasVideoExportAction,
|
|
122
|
+
hasSection: hasVideoExportSection,
|
|
123
|
+
intentMode: intent.video.mode,
|
|
124
|
+
sectionArticle: "a",
|
|
125
|
+
sectionTitle: "Video Export",
|
|
126
|
+
}),
|
|
127
|
+
];
|
|
128
|
+
|
|
129
|
+
return { delivery, errors };
|
|
130
|
+
}
|
|
@@ -26,7 +26,7 @@ export function getConditionValidationErrors({
|
|
|
26
26
|
label,
|
|
27
27
|
}: {
|
|
28
28
|
condition: ToolcraftControlConditionSchema;
|
|
29
|
-
conditionName: "disabledWhen"
|
|
29
|
+
conditionName: "disabledWhen";
|
|
30
30
|
controlTargets: ReadonlySet<string>;
|
|
31
31
|
label: string;
|
|
32
32
|
}): string[] {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ResolvedToolcraftAppSchema,
|
|
3
|
-
|
|
3
|
+
ResolvedToolcraftControlSchema,
|
|
4
4
|
ToolcraftTimelineMode,
|
|
5
5
|
} from "@repo/toolcraft-runtime";
|
|
6
6
|
|
|
@@ -21,7 +21,7 @@ export type ToolcraftControlAcceptanceContext = {
|
|
|
21
21
|
};
|
|
22
22
|
|
|
23
23
|
export type ToolcraftControlRuleContext = {
|
|
24
|
-
control:
|
|
24
|
+
control: ResolvedToolcraftControlSchema;
|
|
25
25
|
controlId: string;
|
|
26
26
|
controlTargets: ReadonlySet<string>;
|
|
27
27
|
label: string;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getToolcraftControlKeyframeCapability,
|
|
3
3
|
type ResolvedToolcraftAppSchema,
|
|
4
|
-
type
|
|
4
|
+
type ResolvedToolcraftControlSchema,
|
|
5
5
|
type ToolcraftTimelineMode,
|
|
6
6
|
} from "@repo/toolcraft-runtime";
|
|
7
7
|
|
|
@@ -21,7 +21,6 @@ import {
|
|
|
21
21
|
import type {
|
|
22
22
|
ToolcraftBackgroundOutputCoverage,
|
|
23
23
|
ToolcraftComponentAcceptance,
|
|
24
|
-
ToolcraftConditionalVisibilityCoverage,
|
|
25
24
|
ToolcraftOrientationGizmoCoverage,
|
|
26
25
|
ToolcraftProductReadiness,
|
|
27
26
|
} from "./types";
|
|
@@ -53,7 +52,7 @@ function getControlAcceptanceEntryErrors({
|
|
|
53
52
|
entry,
|
|
54
53
|
label,
|
|
55
54
|
}: {
|
|
56
|
-
control:
|
|
55
|
+
control: ResolvedToolcraftControlSchema;
|
|
57
56
|
entry: ToolcraftComponentAcceptance;
|
|
58
57
|
label: string;
|
|
59
58
|
}): string[] {
|
|
@@ -98,7 +97,7 @@ function getControlLifecycleAndCustomErrors({
|
|
|
98
97
|
schema,
|
|
99
98
|
}: {
|
|
100
99
|
acceptance: readonly ToolcraftComponentAcceptance[];
|
|
101
|
-
control:
|
|
100
|
+
control: ResolvedToolcraftControlSchema;
|
|
102
101
|
entry: ToolcraftComponentAcceptance;
|
|
103
102
|
label: string;
|
|
104
103
|
layersEnabled: boolean;
|
|
@@ -155,7 +154,7 @@ function getControlEvidenceErrors({
|
|
|
155
154
|
schema,
|
|
156
155
|
sectionTitle,
|
|
157
156
|
}: {
|
|
158
|
-
control:
|
|
157
|
+
control: ResolvedToolcraftControlSchema;
|
|
159
158
|
controlId: string;
|
|
160
159
|
entry: ToolcraftComponentAcceptance;
|
|
161
160
|
label: string;
|
|
@@ -177,19 +176,6 @@ function getControlEvidenceErrors({
|
|
|
177
176
|
);
|
|
178
177
|
}
|
|
179
178
|
|
|
180
|
-
if (
|
|
181
|
-
control.visibleWhen &&
|
|
182
|
-
!hasTypedCoverage<ToolcraftConditionalVisibilityCoverage>(
|
|
183
|
-
entry.visibilityCoverage,
|
|
184
|
-
"all-conditional-visibility",
|
|
185
|
-
["hidden", "visible"],
|
|
186
|
-
)
|
|
187
|
-
) {
|
|
188
|
-
errors.push(
|
|
189
|
-
`${label} uses visibleWhen and must declare visibilityCoverage for both "hidden" and "visible" states reached through ${control.visibleWhen.target}.`,
|
|
190
|
-
);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
179
|
if (
|
|
194
180
|
schemaHasPngExportPanelAction(schema) &&
|
|
195
181
|
isOutputBackgroundToggleControl({ control, controlId, sectionTitle })
|
|
@@ -228,7 +214,7 @@ function getControlPartAndRuntimeCoverageErrors({
|
|
|
228
214
|
layersEnabled,
|
|
229
215
|
timelineMode,
|
|
230
216
|
}: {
|
|
231
|
-
control:
|
|
217
|
+
control: ResolvedToolcraftControlSchema;
|
|
232
218
|
entry: ToolcraftComponentAcceptance;
|
|
233
219
|
label: string;
|
|
234
220
|
layersEnabled: boolean;
|
|
@@ -281,7 +267,7 @@ export function getControlAcceptanceCoverageErrors({
|
|
|
281
267
|
timelineMode,
|
|
282
268
|
}: {
|
|
283
269
|
acceptance: readonly ToolcraftComponentAcceptance[];
|
|
284
|
-
control:
|
|
270
|
+
control: ResolvedToolcraftControlSchema;
|
|
285
271
|
controlId: string;
|
|
286
272
|
entry: ToolcraftComponentAcceptance;
|
|
287
273
|
label: string;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { getToolcraftSegmentedStaticFitError } from "@repo/toolcraft-runtime";
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
ToolcraftCollectionItemControlSchema,
|
|
4
|
+
ToolcraftControlSchema,
|
|
5
|
+
} from "@repo/toolcraft-runtime";
|
|
3
6
|
|
|
4
7
|
import { getActionValue, isResetPanelAction } from "./actions";
|
|
5
8
|
import {
|
|
@@ -103,13 +106,29 @@ function getOptionControlAcceptanceErrors({
|
|
|
103
106
|
}
|
|
104
107
|
}
|
|
105
108
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
+
const nestedItemControls: Array<
|
|
110
|
+
[string, ToolcraftCollectionItemControlSchema]
|
|
111
|
+
> = [];
|
|
112
|
+
|
|
113
|
+
if (control.itemControl) {
|
|
114
|
+
nestedItemControls.push(["itemControl", control.itemControl]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (control.itemControls) {
|
|
118
|
+
nestedItemControls.push(
|
|
119
|
+
...Object.entries(control.itemControls).map(
|
|
120
|
+
([itemId, itemControl]): [string, ToolcraftCollectionItemControlSchema] =>
|
|
121
|
+
[`itemControls.${itemId}`, itemControl],
|
|
122
|
+
),
|
|
109
123
|
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
for (const [itemId, itemControl] of nestedItemControls) {
|
|
127
|
+
const segmentedLayoutError =
|
|
128
|
+
getToolcraftSegmentedStaticFitError(itemControl);
|
|
110
129
|
|
|
111
130
|
if (segmentedLayoutError) {
|
|
112
|
-
errors.push(`${label}
|
|
131
|
+
errors.push(`${label} ${itemId} ${segmentedLayoutError}`);
|
|
113
132
|
}
|
|
114
133
|
}
|
|
115
134
|
|
|
@@ -140,17 +140,6 @@ function getControlStatePolicyErrors({
|
|
|
140
140
|
>): string[] {
|
|
141
141
|
const errors: string[] = [];
|
|
142
142
|
|
|
143
|
-
if (control.visibleWhen) {
|
|
144
|
-
errors.push(
|
|
145
|
-
...getConditionValidationErrors({
|
|
146
|
-
condition: control.visibleWhen,
|
|
147
|
-
conditionName: "visibleWhen",
|
|
148
|
-
controlTargets,
|
|
149
|
-
label,
|
|
150
|
-
}),
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
|
|
154
143
|
if (control.disabledWhen) {
|
|
155
144
|
errors.push(
|
|
156
145
|
...getConditionValidationErrors({
|
|
@@ -164,13 +153,13 @@ function getControlStatePolicyErrors({
|
|
|
164
153
|
|
|
165
154
|
if (control.disabled === true) {
|
|
166
155
|
errors.push(
|
|
167
|
-
`${label} sets disabled: true. Generated product panels should show only controls usable in the current state;
|
|
156
|
+
`${label} sets disabled: true. Generated product panels should show only controls usable in the current state; declare conditional applicability instead of rendering disabled controls.`,
|
|
168
157
|
);
|
|
169
158
|
}
|
|
170
159
|
|
|
171
160
|
if (control.disabledWhen) {
|
|
172
161
|
errors.push(
|
|
173
|
-
`${label} uses disabledWhen. Generated product panels should show only controls usable in the current state;
|
|
162
|
+
`${label} uses disabledWhen. Generated product panels should show only controls usable in the current state; declare conditional applicability instead of rendering disabled controls.`,
|
|
174
163
|
);
|
|
175
164
|
}
|
|
176
165
|
|