@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
|
@@ -12,13 +12,14 @@ import {
|
|
|
12
12
|
getRequiredToolcraftControlPartCoverage,
|
|
13
13
|
type ToolcraftBackgroundOutputCoverage,
|
|
14
14
|
type ToolcraftComponentAcceptance,
|
|
15
|
-
type
|
|
15
|
+
type ToolcraftControlSectionInventoryEntry,
|
|
16
16
|
type ToolcraftInfinityCanvasCoverage,
|
|
17
17
|
type ToolcraftModelImportCoverage,
|
|
18
18
|
type ToolcraftOrientationGizmoCoverage,
|
|
19
19
|
type ToolcraftTimelinePlaybackCoverage,
|
|
20
20
|
TOOLCRAFT_REQUIRED_MODEL_IMPORT_COVERAGE,
|
|
21
21
|
} from "../src/app/starter-acceptance";
|
|
22
|
+
import { expandToolcraftControlApplicabilityRequirements } from "./browser-runtime-applicability-requirements";
|
|
22
23
|
import { getToolcraftPerformancePathTestName } from "./performance-path-helpers";
|
|
23
24
|
|
|
24
25
|
type BrowserAcceptanceRequirementSource = Pick<
|
|
@@ -41,10 +42,14 @@ type BrowserAcceptanceRequirementSource = Pick<
|
|
|
41
42
|
| "target"
|
|
42
43
|
| "timelineCoverage"
|
|
43
44
|
| "timelinePlaybackCoverage"
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
> & {
|
|
46
|
+
kind?: ToolcraftComponentAcceptance["kind"];
|
|
47
|
+
};
|
|
46
48
|
|
|
47
|
-
type BrowserSchemaRequirementSource = Pick<
|
|
49
|
+
type BrowserSchemaRequirementSource = Pick<
|
|
50
|
+
ResolvedToolcraftAppSchema,
|
|
51
|
+
"canvas" | "panels"
|
|
52
|
+
>;
|
|
48
53
|
|
|
49
54
|
function getAcceptanceEvidenceType(
|
|
50
55
|
evidence: ToolcraftComponentAcceptance["evidence"],
|
|
@@ -93,18 +98,6 @@ const timelinePlaybackCoverage = Object.keys(
|
|
|
93
98
|
timelineEvidenceTypeByCoverage,
|
|
94
99
|
) as Array<keyof typeof timelineEvidenceTypeByCoverage>;
|
|
95
100
|
|
|
96
|
-
const conditionalVisibilityEvidenceTypeByCoverage = {
|
|
97
|
-
hidden: "conditional-control-hidden",
|
|
98
|
-
visible: "conditional-control-visible",
|
|
99
|
-
} as const satisfies Record<
|
|
100
|
-
ToolcraftConditionalVisibilityCoverage,
|
|
101
|
-
ToolcraftBrowserRuntimeRequirement["evidenceType"]
|
|
102
|
-
>;
|
|
103
|
-
|
|
104
|
-
const conditionalVisibilityCoverage = Object.keys(
|
|
105
|
-
conditionalVisibilityEvidenceTypeByCoverage,
|
|
106
|
-
) as ToolcraftConditionalVisibilityCoverage[];
|
|
107
|
-
|
|
108
101
|
const backgroundOutputEvidenceTypeByCoverage = {
|
|
109
102
|
"image-transparent-when-excluded": "background-image-transparency",
|
|
110
103
|
"infinity-viewport-color-and-dependency": "background-infinity-viewport",
|
|
@@ -170,7 +163,7 @@ const modelImportEvidenceTypeByCoverage = {
|
|
|
170
163
|
ToolcraftBrowserRuntimeRequirement["evidenceType"]
|
|
171
164
|
>;
|
|
172
165
|
|
|
173
|
-
|
|
166
|
+
function deriveUnqualifiedToolcraftBrowserRuntimeRequirements(
|
|
174
167
|
acceptance: readonly BrowserAcceptanceRequirementSource[],
|
|
175
168
|
schema?: BrowserSchemaRequirementSource,
|
|
176
169
|
): ToolcraftBrowserRuntimeRequirement[] {
|
|
@@ -237,15 +230,6 @@ export function deriveToolcraftBrowserRuntimeRequirements(
|
|
|
237
230
|
if (entry.referenceCoverage || entry.referenceTimelineCoverage) {
|
|
238
231
|
evidenceTypes.push("reference-parity");
|
|
239
232
|
}
|
|
240
|
-
const visibilityCoverage =
|
|
241
|
-
entry.visibilityCoverage === "all-conditional-visibility"
|
|
242
|
-
? conditionalVisibilityCoverage
|
|
243
|
-
: entry.visibilityCoverage ?? [];
|
|
244
|
-
evidenceTypes.push(
|
|
245
|
-
...visibilityCoverage.map(
|
|
246
|
-
(item) => conditionalVisibilityEvidenceTypeByCoverage[item],
|
|
247
|
-
),
|
|
248
|
-
);
|
|
249
233
|
const backgroundCoverage =
|
|
250
234
|
entry.backgroundOutputCoverage === "all-required-background-output"
|
|
251
235
|
? backgroundOutputCoverage.filter(
|
|
@@ -342,6 +326,25 @@ export function deriveToolcraftBrowserRuntimeRequirements(
|
|
|
342
326
|
});
|
|
343
327
|
}
|
|
344
328
|
|
|
329
|
+
export function deriveToolcraftBrowserRuntimeRequirements(
|
|
330
|
+
acceptance: readonly BrowserAcceptanceRequirementSource[],
|
|
331
|
+
schema?: BrowserSchemaRequirementSource,
|
|
332
|
+
sectionInventory: readonly ToolcraftControlSectionInventoryEntry[] = [],
|
|
333
|
+
): ToolcraftBrowserRuntimeRequirement[] {
|
|
334
|
+
return acceptance.flatMap((entry) => {
|
|
335
|
+
const templates = deriveUnqualifiedToolcraftBrowserRuntimeRequirements(
|
|
336
|
+
[entry],
|
|
337
|
+
schema,
|
|
338
|
+
);
|
|
339
|
+
return expandToolcraftControlApplicabilityRequirements({
|
|
340
|
+
entry,
|
|
341
|
+
schema,
|
|
342
|
+
sectionInventory,
|
|
343
|
+
templates,
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
345
348
|
const pathProductOutcomeInteractions = new Set<
|
|
346
349
|
ToolcraftPerformancePath["interaction"]
|
|
347
350
|
>([
|
|
@@ -55,3 +55,28 @@ export async function setSyntheticControlOwner(
|
|
|
55
55
|
{ target, visible },
|
|
56
56
|
);
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
export async function setSyntheticSwitchControlOwner(
|
|
60
|
+
page: Page,
|
|
61
|
+
target: string,
|
|
62
|
+
checked: boolean,
|
|
63
|
+
): Promise<void> {
|
|
64
|
+
await setSyntheticControlOwner(page, target, true);
|
|
65
|
+
await page.locator("[data-synthetic-target]").evaluateAll(
|
|
66
|
+
(owners, entry) => {
|
|
67
|
+
const owner = owners.find(
|
|
68
|
+
(candidate) =>
|
|
69
|
+
candidate.getAttribute("data-synthetic-target") === entry.target,
|
|
70
|
+
);
|
|
71
|
+
const button = owner?.querySelector("button");
|
|
72
|
+
|
|
73
|
+
if (!button) {
|
|
74
|
+
throw new Error(`Missing synthetic switch owner ${entry.target}.`);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
button.setAttribute("aria-checked", String(entry.checked));
|
|
78
|
+
button.setAttribute("role", "switch");
|
|
79
|
+
},
|
|
80
|
+
{ checked, target },
|
|
81
|
+
);
|
|
82
|
+
}
|
|
@@ -76,6 +76,7 @@
|
|
|
76
76
|
{ "type": "checkbox", "visualComponent": "Checkbox" },
|
|
77
77
|
{ "type": "actions", "visualComponent": "Actions" },
|
|
78
78
|
{ "type": "collectionActions", "visualComponent": "CollectionActions" },
|
|
79
|
+
{ "type": "sourceCollection", "visualComponent": "ControlsPanelCollectionItems" },
|
|
79
80
|
{ "type": "panelActions", "visualComponent": "PanelActions" },
|
|
80
81
|
{ "type": "colorOpacity", "visualComponent": "ColorOpacity" },
|
|
81
82
|
{ "type": "palette", "visualComponent": "Palette" },
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
1
|
import ts from "typescript";
|
|
4
2
|
|
|
5
3
|
import {
|
|
@@ -8,9 +6,10 @@ import {
|
|
|
8
6
|
} from "./toolcraft-integrity-policy.mjs";
|
|
9
7
|
import {
|
|
10
8
|
createToolcraftProductExportInspector,
|
|
11
|
-
getToolcraftProductExportModuleKind,
|
|
12
9
|
isForbiddenToolcraftRuntimeExport,
|
|
13
10
|
} from "./toolcraft-product-export-boundary.mjs";
|
|
11
|
+
import { createToolcraftProductControlInspector } from "./toolcraft-product-control-boundary.mjs";
|
|
12
|
+
import { getToolcraftSensitiveModuleKind } from "./toolcraft-product-boundary-module-policy.mjs";
|
|
14
13
|
import { inspectToolcraftProductStyleNode } from "./toolcraft-product-style-boundary.mjs";
|
|
15
14
|
|
|
16
15
|
const runtimeSurfaceNames = new Set(runtimeSurfaceComponentNames);
|
|
@@ -23,88 +22,9 @@ const runtimeModelPresentationInternalNames = new Set([
|
|
|
23
22
|
"useToolcraftModelRenderHost",
|
|
24
23
|
]);
|
|
25
24
|
|
|
26
|
-
function toPosixPath(value) {
|
|
27
|
-
return value.split(path.sep).join("/");
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function resolveSpecifierPath(sourceFilePath, moduleSpecifier, rootDir) {
|
|
31
|
-
if (moduleSpecifier.startsWith("@/") || moduleSpecifier.startsWith("#/")) {
|
|
32
|
-
return toPosixPath(path.resolve(rootDir, "src", moduleSpecifier.slice(2)));
|
|
33
|
-
}
|
|
34
|
-
if (moduleSpecifier.startsWith("/")) {
|
|
35
|
-
return toPosixPath(path.resolve(rootDir, moduleSpecifier.slice(1)));
|
|
36
|
-
}
|
|
37
|
-
if (moduleSpecifier.startsWith(".")) {
|
|
38
|
-
return toPosixPath(path.resolve(path.dirname(sourceFilePath), moduleSpecifier));
|
|
39
|
-
}
|
|
40
|
-
return null;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function getSensitiveModuleKind(sourceFilePath, moduleSpecifier, rootDir) {
|
|
44
|
-
const normalizedSpecifier = moduleSpecifier.replaceAll("\\", "/");
|
|
45
|
-
const resolvedSpecifier = resolveSpecifierPath(
|
|
46
|
-
sourceFilePath,
|
|
47
|
-
normalizedSpecifier,
|
|
48
|
-
rootDir,
|
|
49
|
-
);
|
|
50
|
-
const exportModuleKind = getToolcraftProductExportModuleKind(
|
|
51
|
-
normalizedSpecifier,
|
|
52
|
-
resolvedSpecifier,
|
|
53
|
-
);
|
|
54
|
-
if (exportModuleKind) return exportModuleKind;
|
|
55
|
-
|
|
56
|
-
if (
|
|
57
|
-
/^@repo\/toolcraft-runtime\/react\/model-rendering(?:\/|$)/u.test(
|
|
58
|
-
normalizedSpecifier,
|
|
59
|
-
) ||
|
|
60
|
-
/^[#@]\/toolcraft\/runtime\/react\/model-rendering(?:\/|$)/u.test(
|
|
61
|
-
normalizedSpecifier,
|
|
62
|
-
) ||
|
|
63
|
-
resolvedSpecifier?.includes("/src/toolcraft/runtime/react/model-rendering")
|
|
64
|
-
) {
|
|
65
|
-
return "runtime-model-presentation";
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (
|
|
69
|
-
/^three\/(?:addons|examples\/jsm)\/loaders(?:\/|$)/u.test(
|
|
70
|
-
normalizedSpecifier,
|
|
71
|
-
) ||
|
|
72
|
-
/^@gltf-transform(?:\/|$)/u.test(normalizedSpecifier) ||
|
|
73
|
-
/^@repo\/toolcraft-runtime\/model-import(?:\/|$)/u.test(
|
|
74
|
-
normalizedSpecifier,
|
|
75
|
-
) ||
|
|
76
|
-
/^[#@]\/toolcraft\/runtime\/model-import(?:\/|$)/u.test(
|
|
77
|
-
normalizedSpecifier,
|
|
78
|
-
) ||
|
|
79
|
-
resolvedSpecifier?.includes("/src/toolcraft/runtime/model-import")
|
|
80
|
-
) {
|
|
81
|
-
return "runtime-model-import";
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (
|
|
85
|
-
/^@repo\/toolcraft-runtime\/react(?:\/|$)/u.test(normalizedSpecifier) ||
|
|
86
|
-
/^[#@]\/toolcraft\/runtime\/react(?:\/|$)/u.test(normalizedSpecifier) ||
|
|
87
|
-
resolvedSpecifier?.includes("/src/toolcraft/runtime/react")
|
|
88
|
-
) {
|
|
89
|
-
return "runtime-react";
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
if (
|
|
93
|
-
/^@repo\/ui(?:\/controls(?:\/|$)|$)/u.test(normalizedSpecifier) ||
|
|
94
|
-
/^[#@]\/toolcraft\/ui(?:\/components\/controls(?:\/|$)|\/controls(?:\/|$)|$)/u.test(
|
|
95
|
-
normalizedSpecifier,
|
|
96
|
-
) ||
|
|
97
|
-
resolvedSpecifier?.includes("/src/toolcraft/ui/components/controls") ||
|
|
98
|
-
/\/src\/toolcraft\/ui$/u.test(resolvedSpecifier ?? "")
|
|
99
|
-
) {
|
|
100
|
-
return "ui-controls";
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
25
|
function isForbiddenNamedExport(moduleKind, importedName) {
|
|
107
|
-
if (
|
|
26
|
+
if (moduleKind === "ui-control-implementation") return true;
|
|
27
|
+
if (isForbiddenToolcraftRuntimeExport(moduleKind)) return true;
|
|
108
28
|
if (
|
|
109
29
|
moduleKind === "runtime-model-import" ||
|
|
110
30
|
moduleKind === "runtime-model-presentation"
|
|
@@ -117,6 +37,42 @@ function isForbiddenNamedExport(moduleKind, importedName) {
|
|
|
117
37
|
importedName !== "createControlHistoryGroupId");
|
|
118
38
|
}
|
|
119
39
|
|
|
40
|
+
function getImportViolationKind(moduleKind, importedName) {
|
|
41
|
+
switch (moduleKind) {
|
|
42
|
+
case "runtime-export-mechanics":
|
|
43
|
+
return "runtime-export-ownership";
|
|
44
|
+
case "runtime-model-presentation":
|
|
45
|
+
return "runtime-model-presentation-ownership";
|
|
46
|
+
case "runtime-react":
|
|
47
|
+
return runtimeModelPresentationInternalNames.has(importedName)
|
|
48
|
+
? "runtime-model-presentation-ownership"
|
|
49
|
+
: "runtime-surface";
|
|
50
|
+
case "runtime-model-import":
|
|
51
|
+
return "runtime-model-import-ownership";
|
|
52
|
+
case "ui-control-implementation":
|
|
53
|
+
return "built-in-control-implementation";
|
|
54
|
+
default:
|
|
55
|
+
return "built-in-control";
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function getViolationMessage(kind, subject, moduleSpecifier) {
|
|
60
|
+
switch (kind) {
|
|
61
|
+
case "runtime-export-ownership":
|
|
62
|
+
return `Product source must not own artifact encoding, recording, or download mechanics${subject} from ${moduleSpecifier}. Declare exportRenderer and let runtime export actions encode and download the artifact.`;
|
|
63
|
+
case "runtime-surface":
|
|
64
|
+
return `Product source must not import or re-export host-owned runtime surface${subject} from ${moduleSpecifier}. Use ToolcraftAppComposition, schema, canvasContent, controlRenderers, onPanelAction, and runtime commands.`;
|
|
65
|
+
case "runtime-model-presentation-ownership":
|
|
66
|
+
return `Product source must not import raw model render hosts or standard model canvas internals${subject} from ${moduleSpecifier}. Declare modelPresentation and use useToolcraftModelPresentationConsumer for visible custom model output.`;
|
|
67
|
+
case "runtime-model-import-ownership":
|
|
68
|
+
return `Product source must not import or re-export model loaders, topology/repair infrastructure, or runtime model-import internals${subject} from ${moduleSpecifier}. Declare a model fileDrop in schema and use the runtime-owned import, analysis, repair, persistence, preview, and export pipeline.`;
|
|
69
|
+
case "built-in-control-implementation":
|
|
70
|
+
return `Product source must not import or re-export a deep control implementation${subject} from ${moduleSpecifier}. Use the public schema control instead of copying or composing its private mechanics.`;
|
|
71
|
+
default:
|
|
72
|
+
return `Product source must not import or re-export built-in control${subject} from ${moduleSpecifier}. Declare it through schema or justify a true custom controlRenderer.`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
120
76
|
function createViolation({
|
|
121
77
|
getNodeLocation,
|
|
122
78
|
importedName,
|
|
@@ -127,26 +83,17 @@ function createViolation({
|
|
|
127
83
|
sourceFile,
|
|
128
84
|
}) {
|
|
129
85
|
const subject = importedName ? ` ${importedName}` : "";
|
|
130
|
-
const message =
|
|
131
|
-
kind === "runtime-export-ownership"
|
|
132
|
-
? `Product source must not own artifact encoding, recording, or download mechanics${subject} from ${moduleSpecifier}. Declare exportRenderer and let runtime export actions encode and download the artifact.`
|
|
133
|
-
: kind === "runtime-surface"
|
|
134
|
-
? `Product source must not import or re-export host-owned runtime surface${subject} from ${moduleSpecifier}. Use ToolcraftAppComposition, schema, canvasContent, controlRenderers, onPanelAction, and runtime commands.`
|
|
135
|
-
: kind === "runtime-model-presentation-ownership"
|
|
136
|
-
? `Product source must not import raw model render hosts or standard model canvas internals${subject} from ${moduleSpecifier}. Declare modelPresentation and use useToolcraftModelPresentationConsumer for visible custom model output.`
|
|
137
|
-
: kind === "runtime-model-import-ownership"
|
|
138
|
-
? `Product source must not import or re-export model loaders, topology/repair infrastructure, or runtime model-import internals${subject} from ${moduleSpecifier}. Declare a model fileDrop in schema and use the runtime-owned import, analysis, repair, persistence, preview, and export pipeline.`
|
|
139
|
-
: `Product source must not import or re-export built-in control${subject} from ${moduleSpecifier}. Declare it through schema or justify a true custom controlRenderer.`;
|
|
140
86
|
return {
|
|
141
87
|
...getNodeLocation(sourceFile, node),
|
|
142
88
|
kind,
|
|
143
|
-
message,
|
|
89
|
+
message: getViolationMessage(kind, subject, moduleSpecifier),
|
|
144
90
|
repoPath,
|
|
145
91
|
};
|
|
146
92
|
}
|
|
147
93
|
|
|
148
94
|
export function inspectToolcraftProductSource({
|
|
149
95
|
absolutePath,
|
|
96
|
+
checker,
|
|
150
97
|
getNodeLocation,
|
|
151
98
|
repoPath,
|
|
152
99
|
resolveStaticString,
|
|
@@ -159,6 +106,13 @@ export function inspectToolcraftProductSource({
|
|
|
159
106
|
repoPath,
|
|
160
107
|
sourceFile,
|
|
161
108
|
});
|
|
109
|
+
const inspectControls = createToolcraftProductControlInspector({
|
|
110
|
+
checker,
|
|
111
|
+
getNodeLocation,
|
|
112
|
+
repoPath,
|
|
113
|
+
resolveStaticString,
|
|
114
|
+
sourceFile,
|
|
115
|
+
});
|
|
162
116
|
|
|
163
117
|
function report(node, moduleSpecifier, moduleKind, importedName) {
|
|
164
118
|
if (importedName && !isForbiddenNamedExport(moduleKind, importedName)) {
|
|
@@ -168,19 +122,7 @@ export function inspectToolcraftProductSource({
|
|
|
168
122
|
createViolation({
|
|
169
123
|
getNodeLocation,
|
|
170
124
|
importedName,
|
|
171
|
-
kind:
|
|
172
|
-
moduleKind === "runtime-export-api" ||
|
|
173
|
-
moduleKind === "runtime-export-mechanics"
|
|
174
|
-
? "runtime-export-ownership"
|
|
175
|
-
: moduleKind === "runtime-model-presentation"
|
|
176
|
-
? "runtime-model-presentation-ownership"
|
|
177
|
-
: moduleKind === "runtime-react"
|
|
178
|
-
? runtimeModelPresentationInternalNames.has(importedName)
|
|
179
|
-
? "runtime-model-presentation-ownership"
|
|
180
|
-
: "runtime-surface"
|
|
181
|
-
: moduleKind === "runtime-model-import"
|
|
182
|
-
? "runtime-model-import-ownership"
|
|
183
|
-
: "built-in-control",
|
|
125
|
+
kind: getImportViolationKind(moduleKind, importedName),
|
|
184
126
|
moduleSpecifier,
|
|
185
127
|
node,
|
|
186
128
|
repoPath,
|
|
@@ -190,7 +132,25 @@ export function inspectToolcraftProductSource({
|
|
|
190
132
|
}
|
|
191
133
|
|
|
192
134
|
function getModuleKind(moduleSpecifier) {
|
|
193
|
-
return
|
|
135
|
+
return getToolcraftSensitiveModuleKind({
|
|
136
|
+
moduleSpecifier,
|
|
137
|
+
rootDir,
|
|
138
|
+
sourceFilePath: absolutePath,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function inspectModuleSpecifier(node, moduleSpecifier) {
|
|
143
|
+
const moduleKind = getModuleKind(moduleSpecifier);
|
|
144
|
+
if (!moduleKind) return null;
|
|
145
|
+
if (moduleKind === "ui-control-implementation") {
|
|
146
|
+
report(node, moduleSpecifier, moduleKind);
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
if (isForbiddenToolcraftRuntimeExport(moduleKind)) {
|
|
150
|
+
report(node, moduleSpecifier, moduleKind);
|
|
151
|
+
return null;
|
|
152
|
+
}
|
|
153
|
+
return moduleKind;
|
|
194
154
|
}
|
|
195
155
|
|
|
196
156
|
function visit(node) {
|
|
@@ -202,6 +162,7 @@ export function inspectToolcraftProductSource({
|
|
|
202
162
|
sourceFile,
|
|
203
163
|
}),
|
|
204
164
|
...inspectExportMechanics(node),
|
|
165
|
+
...inspectControls.inspectNode(node),
|
|
205
166
|
);
|
|
206
167
|
|
|
207
168
|
if (
|
|
@@ -209,7 +170,7 @@ export function inspectToolcraftProductSource({
|
|
|
209
170
|
ts.isStringLiteralLike(node.moduleSpecifier)
|
|
210
171
|
) {
|
|
211
172
|
const moduleSpecifier = node.moduleSpecifier.text;
|
|
212
|
-
const moduleKind =
|
|
173
|
+
const moduleKind = inspectModuleSpecifier(node, moduleSpecifier);
|
|
213
174
|
const importClause = node.importClause;
|
|
214
175
|
|
|
215
176
|
if (moduleKind && importClause && !importClause.isTypeOnly) {
|
|
@@ -238,7 +199,7 @@ export function inspectToolcraftProductSource({
|
|
|
238
199
|
ts.isStringLiteralLike(node.moduleSpecifier)
|
|
239
200
|
) {
|
|
240
201
|
const moduleSpecifier = node.moduleSpecifier.text;
|
|
241
|
-
const moduleKind =
|
|
202
|
+
const moduleKind = inspectModuleSpecifier(node, moduleSpecifier);
|
|
242
203
|
|
|
243
204
|
if (moduleKind && !node.isTypeOnly) {
|
|
244
205
|
if (!node.exportClause || ts.isNamespaceExport(node.exportClause)) {
|
|
@@ -260,14 +221,23 @@ export function inspectToolcraftProductSource({
|
|
|
260
221
|
|
|
261
222
|
if (
|
|
262
223
|
ts.isImportEqualsDeclaration(node) &&
|
|
263
|
-
!node.isTypeOnly &&
|
|
264
224
|
ts.isExternalModuleReference(node.moduleReference) &&
|
|
265
225
|
node.moduleReference.expression &&
|
|
266
226
|
ts.isStringLiteralLike(node.moduleReference.expression)
|
|
267
227
|
) {
|
|
268
228
|
const moduleSpecifier = node.moduleReference.expression.text;
|
|
269
|
-
const moduleKind =
|
|
270
|
-
if (moduleKind
|
|
229
|
+
const moduleKind = inspectModuleSpecifier(node, moduleSpecifier);
|
|
230
|
+
if (moduleKind && !node.isTypeOnly) {
|
|
231
|
+
report(node, moduleSpecifier, moduleKind);
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (
|
|
236
|
+
ts.isImportTypeNode(node) &&
|
|
237
|
+
ts.isLiteralTypeNode(node.argument) &&
|
|
238
|
+
ts.isStringLiteralLike(node.argument.literal)
|
|
239
|
+
) {
|
|
240
|
+
inspectModuleSpecifier(node, node.argument.literal.text);
|
|
271
241
|
}
|
|
272
242
|
|
|
273
243
|
if (
|
|
@@ -288,7 +258,7 @@ export function inspectToolcraftProductSource({
|
|
|
288
258
|
ts.forEachChild(node, visit);
|
|
289
259
|
return;
|
|
290
260
|
}
|
|
291
|
-
const moduleKind =
|
|
261
|
+
const moduleKind = inspectModuleSpecifier(node, moduleSpecifier);
|
|
292
262
|
if (moduleKind) report(node, moduleSpecifier, moduleKind);
|
|
293
263
|
}
|
|
294
264
|
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
getToolcraftProductExportModuleKind,
|
|
5
|
+
} from "./toolcraft-product-export-boundary.mjs";
|
|
6
|
+
import {
|
|
7
|
+
isToolcraftPrivateControlImplementationModule,
|
|
8
|
+
} from "./toolcraft-product-control-boundary.mjs";
|
|
9
|
+
|
|
10
|
+
function toPosixPath(value) {
|
|
11
|
+
return value.split(path.sep).join("/");
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function resolveSpecifierPath(sourceFilePath, moduleSpecifier, rootDir) {
|
|
15
|
+
if (moduleSpecifier.startsWith("@/") || moduleSpecifier.startsWith("#/")) {
|
|
16
|
+
return toPosixPath(path.resolve(rootDir, "src", moduleSpecifier.slice(2)));
|
|
17
|
+
}
|
|
18
|
+
if (moduleSpecifier.startsWith("/")) {
|
|
19
|
+
return toPosixPath(path.resolve(rootDir, moduleSpecifier.slice(1)));
|
|
20
|
+
}
|
|
21
|
+
if (moduleSpecifier.startsWith(".")) {
|
|
22
|
+
return toPosixPath(path.resolve(path.dirname(sourceFilePath), moduleSpecifier));
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getToolcraftSensitiveModuleKind({
|
|
28
|
+
moduleSpecifier,
|
|
29
|
+
rootDir,
|
|
30
|
+
sourceFilePath,
|
|
31
|
+
}) {
|
|
32
|
+
const normalizedSpecifier = moduleSpecifier.replaceAll("\\", "/");
|
|
33
|
+
const resolvedSpecifier = resolveSpecifierPath(
|
|
34
|
+
sourceFilePath,
|
|
35
|
+
normalizedSpecifier,
|
|
36
|
+
rootDir,
|
|
37
|
+
);
|
|
38
|
+
const exportModuleKind = getToolcraftProductExportModuleKind(
|
|
39
|
+
normalizedSpecifier,
|
|
40
|
+
resolvedSpecifier,
|
|
41
|
+
);
|
|
42
|
+
if (exportModuleKind) return exportModuleKind;
|
|
43
|
+
|
|
44
|
+
if (
|
|
45
|
+
isToolcraftPrivateControlImplementationModule({
|
|
46
|
+
moduleSpecifier: normalizedSpecifier,
|
|
47
|
+
resolvedSpecifier,
|
|
48
|
+
})
|
|
49
|
+
) {
|
|
50
|
+
return "ui-control-implementation";
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
if (
|
|
54
|
+
/^@repo\/toolcraft-runtime\/react\/model-rendering(?:\/|$)/u.test(
|
|
55
|
+
normalizedSpecifier,
|
|
56
|
+
) ||
|
|
57
|
+
/^[#@]\/toolcraft\/runtime\/react\/model-rendering(?:\/|$)/u.test(
|
|
58
|
+
normalizedSpecifier,
|
|
59
|
+
) ||
|
|
60
|
+
resolvedSpecifier?.includes("/src/toolcraft/runtime/react/model-rendering")
|
|
61
|
+
) {
|
|
62
|
+
return "runtime-model-presentation";
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (
|
|
66
|
+
/^three\/(?:addons|examples\/jsm)\/loaders(?:\/|$)/u.test(
|
|
67
|
+
normalizedSpecifier,
|
|
68
|
+
) ||
|
|
69
|
+
/^@gltf-transform(?:\/|$)/u.test(normalizedSpecifier) ||
|
|
70
|
+
/^@repo\/toolcraft-runtime\/model-import(?:\/|$)/u.test(
|
|
71
|
+
normalizedSpecifier,
|
|
72
|
+
) ||
|
|
73
|
+
/^[#@]\/toolcraft\/runtime\/model-import(?:\/|$)/u.test(
|
|
74
|
+
normalizedSpecifier,
|
|
75
|
+
) ||
|
|
76
|
+
resolvedSpecifier?.includes("/src/toolcraft/runtime/model-import")
|
|
77
|
+
) {
|
|
78
|
+
return "runtime-model-import";
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
/^@repo\/toolcraft-runtime\/react(?:\/|$)/u.test(normalizedSpecifier) ||
|
|
83
|
+
/^[#@]\/toolcraft\/runtime\/react(?:\/|$)/u.test(normalizedSpecifier) ||
|
|
84
|
+
resolvedSpecifier?.includes("/src/toolcraft/runtime/react")
|
|
85
|
+
) {
|
|
86
|
+
return "runtime-react";
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
if (
|
|
90
|
+
/^@repo\/ui(?:\/controls(?:\/|$)|$)/u.test(normalizedSpecifier) ||
|
|
91
|
+
/^[#@]\/toolcraft\/ui(?:\/components\/controls(?:\/|$)|\/controls(?:\/|$)|$)/u.test(
|
|
92
|
+
normalizedSpecifier,
|
|
93
|
+
) ||
|
|
94
|
+
resolvedSpecifier?.includes("/src/toolcraft/ui/components/controls") ||
|
|
95
|
+
/\/src\/toolcraft\/ui$/u.test(resolvedSpecifier ?? "")
|
|
96
|
+
) {
|
|
97
|
+
return "ui-controls";
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
@@ -75,32 +75,6 @@ test("checks Vite root-absolute imports against the same product boundary", asyn
|
|
|
75
75
|
);
|
|
76
76
|
});
|
|
77
77
|
|
|
78
|
-
test("finds built-in controls through re-exports, aliases, namespaces, and dynamic imports", async (context) => {
|
|
79
|
-
const rootDir = await createFixture(context, {
|
|
80
|
-
"src/features/control-bridge.ts": `
|
|
81
|
-
export { SliderControl as ProductSlider } from "@repo/ui/controls";
|
|
82
|
-
export { Color as ProductColor } from "@/toolcraft/ui";
|
|
83
|
-
`,
|
|
84
|
-
"src/features/dynamic.ts": `
|
|
85
|
-
export async function loadControls() {
|
|
86
|
-
return import("@/toolcraft/ui/components/controls/slider");
|
|
87
|
-
}
|
|
88
|
-
`,
|
|
89
|
-
"src/features/namespace.ts": `
|
|
90
|
-
import * as Controls from "@repo/ui";
|
|
91
|
-
export const Slider = Controls.Slider;
|
|
92
|
-
`,
|
|
93
|
-
});
|
|
94
|
-
|
|
95
|
-
const result = await evaluateToolcraftProductBoundary({ rootDir });
|
|
96
|
-
|
|
97
|
-
assert.equal(result.violations.length, 4);
|
|
98
|
-
assert.equal(
|
|
99
|
-
result.violations.every((violation) => violation.kind === "built-in-control"),
|
|
100
|
-
true,
|
|
101
|
-
);
|
|
102
|
-
});
|
|
103
|
-
|
|
104
78
|
test("keeps model import, topology, and repair infrastructure runtime-owned", async (context) => {
|
|
105
79
|
const rootDir = await createFixture(context, {
|
|
106
80
|
"src/features/direct-loaders.ts": `
|
|
@@ -143,52 +117,6 @@ test("keeps model import, topology, and repair infrastructure runtime-owned", as
|
|
|
143
117
|
);
|
|
144
118
|
});
|
|
145
119
|
|
|
146
|
-
test("keeps artifact encoding and download mechanics runtime-owned", async (context) => {
|
|
147
|
-
const rootDir = await createFixture(context, {
|
|
148
|
-
"src/features/export-mechanics.ts": `
|
|
149
|
-
import { createToolcraftPngExportCanvas } from "@/toolcraft/runtime";
|
|
150
|
-
import { Output } from "mediabunny";
|
|
151
|
-
export function exportArtifact(canvas: HTMLCanvasElement) {
|
|
152
|
-
const recorder = new MediaRecorder(canvas.captureStream());
|
|
153
|
-
const encoder = new VideoEncoder({ error() {}, output() {} });
|
|
154
|
-
canvas.toBlob(() => undefined);
|
|
155
|
-
canvas.toDataURL();
|
|
156
|
-
URL.createObjectURL(new Blob());
|
|
157
|
-
void createToolcraftPngExportCanvas;
|
|
158
|
-
void Output;
|
|
159
|
-
void recorder;
|
|
160
|
-
void encoder;
|
|
161
|
-
}
|
|
162
|
-
`,
|
|
163
|
-
"src/features/safe-renderer.ts": `
|
|
164
|
-
export const renderFrame = ({ context }) => context.fillRect(0, 0, 1, 1);
|
|
165
|
-
`,
|
|
166
|
-
"src/features/shadowed-globals.ts": `
|
|
167
|
-
export function localNames(MediaRecorder, VideoEncoder, URL) {
|
|
168
|
-
void new MediaRecorder();
|
|
169
|
-
void new VideoEncoder();
|
|
170
|
-
URL.createObjectURL();
|
|
171
|
-
}
|
|
172
|
-
`,
|
|
173
|
-
});
|
|
174
|
-
|
|
175
|
-
const result = await evaluateToolcraftProductBoundary({ rootDir });
|
|
176
|
-
|
|
177
|
-
assert.equal(result.violations.length, 8);
|
|
178
|
-
assert.equal(
|
|
179
|
-
result.violations.every(
|
|
180
|
-
(violation) => violation.kind === "runtime-export-ownership",
|
|
181
|
-
),
|
|
182
|
-
true,
|
|
183
|
-
);
|
|
184
|
-
assert.equal(
|
|
185
|
-
result.violations.some((violation) =>
|
|
186
|
-
violation.repoPath.endsWith("shadowed-globals.ts"),
|
|
187
|
-
),
|
|
188
|
-
false,
|
|
189
|
-
);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
120
|
test("ignores tests but checks a product bridge imported by production", async (context) => {
|
|
193
121
|
const rootDir = await createFixture(context, {
|
|
194
122
|
"src/features/bridge.ts": `
|