diff --git a/API.md b/API.md index 3321e42..e86f301 100644 --- a/API.md +++ b/API.md @@ -8,7 +8,7 @@ In an interactive terminal, running bare `interfacectl` with no arguments opens ## Generation-time gating -`interfacectl validate` is the canonical command for contract compliance. Use it to gate changes before merge or deployment. For deterministic, category-based exit codes, use `--exit-codes v2` or set `INTERFACECTL_EXIT_CODES=v2`. The command `enforce --mode fail` runs a structural diff and applies a policy threshold. It is optional and useful when you want to block on diff severity separately from compliance. For the minimal contract format and where contract semantics live in the repo, see [docs/contract-baseline.md](docs/contract-baseline.md). +`interfacectl validate` is the canonical command for contract compliance. Use it to gate changes before merge or deployment. For deterministic, category-based exit codes, use `--exit-codes v2` or set `INTERFACECTL_EXIT_CODES=v2`. The command `enforce --mode fail` runs a structural diff and applies a policy threshold. It is optional and useful when you want to block on diff severity separately from compliance. For the minimal contract format and where contract semantics live in the repo, see [docs/contract-baseline.md](docs/contract-baseline.md). For optional generator-facing authoring metadata, see [docs/authoring-contracts.md](docs/authoring-contracts.md). ## Commands diff --git a/docs/authoring-contracts.md b/docs/authoring-contracts.md new file mode 100644 index 0000000..77edcdf --- /dev/null +++ b/docs/authoring-contracts.md @@ -0,0 +1,161 @@ +# Authoring Contract Metadata + +These optional contract fields help agentic UI generators interpret structure, safe edits, responsive behavior, implementation preferences, and external sources of truth for any governed web surface. + +The fields are advisory-first in v1: + +- `interfacectl validate` checks shape and referential integrity. +- The fields do not add new blocking runtime or CI semantics by themselves. +- Existing contracts remain valid without them. + +## Scope + +Authoring metadata in v1 is for web surfaces: + +- `contract.components[]` +- `sections[].anatomy` +- `sections[].editPolicy` +- `sections[].responsive` +- `surfaces[].viewports` +- `surfaces[].authoring` + +Do not treat these fields as first-party patterns. They are generic primitives for any ingested web surface. + +## Generator Consumption Order + +When both contract metadata and external sources exist, consume them in this order: + +1. Use the contract to determine the allowed structure. +2. Respect shell boundaries, section edit policies, and slot constraints. +3. Read `surfaces[].authoring.sourcePriority` to decide which secondary sources to consult next. +4. Resolve `components[].references[]` or other external references only after the contract shape is known. +5. If an external source conflicts with the contract, the contract wins. + +Recommended default precedence: + +```json +{ + "sourcePriority": ["contract", "figma", "code", "story", "url"] +} +``` + +## Field Summary + +- `components[]`: reusable, named building blocks for a surface. +- `components[].slots[]`: machine-editable anatomy for text, media, actions, icons, and nested content. +- `components[].states[]`: explicit UI states such as loading, empty, disabled, or expanded. +- `components[].interactions[]`: navigational or state-changing behaviors that generators must preserve. +- `sections[].anatomy`: section pattern, allowed components, and section-local slots. +- `sections[].editPolicy`: safe mutation boundary for agent edits. +- `sections[].responsive.rules[]`: named viewport behavior for layout and slot reflow. +- `surfaces[].viewports[]`: named breakpoint profiles and width ranges. +- `surfaces[].authoring`: framework, styling, preferred libraries, and source precedence. +- `references[]`: tool-neutral mappings to Figma, code, Storybook, live URLs, or asset systems. + +## Marketing Page Example + +```json +{ + "surfaces": [ + { + "id": "marketing-site", + "type": "web", + "viewports": [ + { "id": "mobile", "maxWidthPx": 767 }, + { "id": "desktop", "minWidthPx": 768 } + ], + "authoring": { + "framework": "react", + "styling": { "strategy": "design-tokens" }, + "sourcePriority": ["contract", "figma", "code", "url"] + } + } + ], + "components": [ + { + "id": "copy-block", + "intent": "intro copy", + "slots": [ + { "id": "headline", "kind": "text", "required": true }, + { "id": "body", "kind": "richText", "required": true }, + { "id": "primary-action", "kind": "action", "required": false } + ] + } + ], + "sections": [ + { + "id": "page.intro", + "intent": "intro", + "description": "Top-of-page introduction.", + "anatomy": { + "pattern": "copy-block", + "defaultComponent": "copy-block" + }, + "editPolicy": { + "mode": "slot-bound", + "allowedOperations": ["update-copy", "swap-variant", "adjust-layout"] + }, + "responsive": { + "rules": [ + { "viewport": "mobile", "layoutIntent": "stack" }, + { "viewport": "desktop", "layoutIntent": "columns" } + ] + } + } + ] +} +``` + +## Application Screen Example + +```json +{ + "components": [ + { + "id": "results-table", + "intent": "tabular search results", + "slots": [ + { "id": "toolbar", "kind": "container", "required": true }, + { "id": "rows", "kind": "item-list", "required": true, "repeatable": true }, + { "id": "empty-copy", "kind": "text", "required": false } + ], + "states": [ + { "id": "loading", "hiddenSlots": ["rows"], "requiredSlots": ["toolbar"] }, + { "id": "empty", "hiddenSlots": ["rows"], "requiredSlots": ["empty-copy"] }, + { "id": "ready", "requiredSlots": ["toolbar", "rows"] } + ], + "interactions": [ + { + "id": "apply-filter", + "trigger": "submit toolbar filter form", + "effect": "filter", + "resultingState": "ready" + } + ] + } + ], + "sections": [ + { + "id": "screen.results", + "intent": "search-results", + "description": "Primary results screen.", + "anatomy": { + "pattern": "data-panel", + "defaultComponent": "results-table" + }, + "editPolicy": { + "mode": "slot-bound", + "allowedOperations": ["bind-data", "wire-interaction", "adjust-layout"] + } + } + ] +} +``` + +## Reference Fixture + +The first annotated example lives at: + +- `packages/interfacectl-validator/test/fixtures/authoring/reference-target-web.contract.json` + +It uses the live `reference-target-web` surface as calibration, but it is expressed only through generic authoring primitives such as copy block, repeated card list, viewport rules, and source precedence. diff --git a/docs/contract-baseline.md b/docs/contract-baseline.md index 4e32005..e94e4aa 100644 --- a/docs/contract-baseline.md +++ b/docs/contract-baseline.md @@ -64,6 +64,19 @@ Each item in `sections` must include: - `intent` (string, non-empty) - `description` (string, non-empty) +Optional authoring metadata for web surfaces: + +- `components[]`: reusable component library for agentic generation and adaptation. +- `sections[*].anatomy`: generic section pattern, allowed/default components, and section-local slots. +- `sections[*].editPolicy`: safe mutation boundary such as `locked`, `slot-bound`, or `freeform`. +- `sections[*].responsive`: named viewport rules for layout intent and slot reflow. +- `surfaces[*].viewports`: named breakpoint profiles with min/max widths. +- `surfaces[*].authoring`: implementation preferences and source precedence across contract, Figma, code, stories, and live URLs. + +These fields are advisory-first in v1. `interfacectl validate` checks structure and referential integrity, but they do not add new compliance violations on their own beyond malformed metadata. + +For generator consumption order and end-to-end examples, see `docs/authoring-contracts.md`. + ## Required color policy The top-level `color` object must include: diff --git a/packages/interfacectl-validator/dist/index.d.ts b/packages/interfacectl-validator/dist/index.d.ts index f20d9d8..01382fb 100644 --- a/packages/interfacectl-validator/dist/index.d.ts +++ b/packages/interfacectl-validator/dist/index.d.ts @@ -8,7 +8,7 @@ export interface ContractStructureValidation { export declare function validateContractStructure(contractData: unknown, schema: object): ContractStructureValidation; export declare function evaluateSurfaceCompliance(contract: InterfaceContract, descriptor: SurfaceDescriptor): SurfaceReport; export declare function evaluateContractCompliance(contract: InterfaceContract, descriptors: SurfaceDescriptor[]): ValidationSummary; -export type { InterfaceContract, ContractSurface, ContractSection, ContractConstraints, ContractTokenPolicies, SurfaceDescriptor, SurfaceSectionDescriptor, SurfaceFontDescriptor, SurfaceColorDescriptor, SurfaceIconDescriptor, SurfaceTokenDescriptor, SurfaceTokenUsage, SurfaceMotionDescriptor, SurfaceLayoutDescriptor, PageFrameLayoutDescriptor, ChromeLayoutDescriptor, ChromePolicyTarget, ChromeShadowKind, LandingPatternDescriptor, SurfacePrimitiveDescriptor, SurfaceReport, DriftViolation, ValidationSummary, DriftViolationType, ContractRef, RuleRef, DiffOutput, DiffEntry, DiffChangeType, DriftRisk, Severity, SafetyLevel, EnforcementPolicy, EnforcementMode, IconPolicy, TokenCategory, TokenMetadata, TokenPolicy, ContractMarketingProfiles, MarketingLayoutProfile, MarketingTypographyProfile, MarketingTypographyRoleProfile, MarketingHeroContainerMode, MarketingHeroVisualPlacement, MarketingSectionDividerMode, MarketingSectionSpacingProfile, MarketingTypographyRole, FlowPolicy, FlowRequirement, FlowTransitionRequirement, LandingPatternPolicy, SurfaceMarketingTypographyDescriptor, SurfaceMarketingTypographyRoleDescriptor, SurfaceFlowDescriptor, SurfaceFlowStepDescriptor, SurfaceFlowTransitionDescriptor, AutofixRule, FixSummary, FixEntry, FixError, } from "./types.js"; +export type { InterfaceContract, ContractComponent, ContractSlot, ContractSlotKind, ContractSlotContentRules, ContractComponentVariant, ContractState, ContractInteraction, ContractInteractionEffect, ContractComponentImplementation, ExternalReference, ExternalReferenceSystem, AuthoringSource, SectionAnatomy, SectionEditPolicy, SectionEditMode, SectionAllowedOperation, SectionResponsive, SectionResponsiveRule, ResponsiveLayoutIntent, ResponsiveSlotBehavior, ResponsiveSlotBehaviorKind, ViewportProfile, SurfaceAuthoring, SurfaceAuthoringStyling, SurfaceAuthoringLibraries, ContractSurface, ContractSection, ContractConstraints, ContractTokenPolicies, SurfaceDescriptor, SurfaceSectionDescriptor, SurfaceFontDescriptor, SurfaceColorDescriptor, SurfaceIconDescriptor, SurfaceTokenDescriptor, SurfaceTokenUsage, SurfaceMotionDescriptor, SurfaceLayoutDescriptor, PageFrameLayoutDescriptor, ChromeLayoutDescriptor, ChromePolicyTarget, ChromeShadowKind, LandingPatternDescriptor, SurfacePrimitiveDescriptor, SurfaceReport, DriftViolation, ValidationSummary, DriftViolationType, ContractRef, RuleRef, DiffOutput, DiffEntry, DiffChangeType, DriftRisk, Severity, SafetyLevel, EnforcementPolicy, EnforcementMode, IconPolicy, TokenCategory, TokenMetadata, TokenPolicy, ContractMarketingProfiles, MarketingLayoutProfile, MarketingTypographyProfile, MarketingTypographyRoleProfile, MarketingHeroContainerMode, MarketingHeroVisualPlacement, MarketingSectionDividerMode, MarketingSectionSpacingProfile, MarketingTypographyRole, FlowPolicy, FlowRequirement, FlowTransitionRequirement, LandingPatternPolicy, SurfaceMarketingTypographyDescriptor, SurfaceMarketingTypographyRoleDescriptor, SurfaceFlowDescriptor, SurfaceFlowStepDescriptor, SurfaceFlowTransitionDescriptor, AutofixRule, FixSummary, FixEntry, FixError, } from "./types.js"; export { getBundledDiffSchema, getBundledPolicySchema, getBundledFixSummarySchema, validateDiffOutput, validatePolicy, validateFixSummary, type ValidationResult, } from "./schema-validate.js"; export { normalizeColorValue, normalizeColorValues, } from "./color-policy.js"; export { matchTokenPolicy, normalizeTokenLiteralValue, type TokenPolicyMatch, } from "./token-policy.js"; diff --git a/packages/interfacectl-validator/dist/index.d.ts.map b/packages/interfacectl-validator/dist/index.d.ts.map index 1e0f35b..99708bf 100644 --- a/packages/interfacectl-validator/dist/index.d.ts.map +++ b/packages/interfacectl-validator/dist/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EAQlB,MAAM,YAAY,CAAC;AASpB,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,OAAO,EACrB,MAAM,EAAE,MAAM,GACb,2BAA2B,CAmC7B;AAstBD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,UAAU,EAAE,iBAAiB,GAC5B,aAAa,CAgbf;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,iBAAiB,EAAE,GAC/B,iBAAiB,CA6CnB;AAyCD,YAAY,EACV,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,OAAO,EACP,UAAU,EACV,SAAS,EACT,cAAc,EACd,SAAS,EACT,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,yBAAyB,EACzB,sBAAsB,EACtB,0BAA0B,EAC1B,8BAA8B,EAC9B,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAC3B,8BAA8B,EAC9B,uBAAuB,EACvB,UAAU,EACV,eAAe,EACf,yBAAyB,EACzB,oBAAoB,EACpB,oCAAoC,EACpC,wCAAwC,EACxC,qBAAqB,EACrB,yBAAyB,EACzB,+BAA+B,EAC/B,WAAW,EACX,UAAU,EACV,QAAQ,EACR,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,KAAK,gBAAgB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,gBAAgB,GACtB,MAAM,mBAAmB,CAAC"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,iBAAiB,EAQlB,MAAM,YAAY,CAAC;AASpB,wBAAgB,wBAAwB,IAAI,MAAM,CAEjD;AAED,MAAM,WAAW,2BAA2B;IAC1C,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CAC9B;AAED,wBAAgB,yBAAyB,CACvC,YAAY,EAAE,OAAO,EACrB,MAAM,EAAE,MAAM,GACb,2BAA2B,CA0C7B;AAo+BD,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,iBAAiB,EAC3B,UAAU,EAAE,iBAAiB,GAC5B,aAAa,CAgbf;AAED,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,iBAAiB,EAC3B,WAAW,EAAE,iBAAiB,EAAE,GAC/B,iBAAiB,CA6CnB;AAyCD,YAAY,EACV,iBAAiB,EACjB,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,wBAAwB,EACxB,wBAAwB,EACxB,aAAa,EACb,mBAAmB,EACnB,yBAAyB,EACzB,+BAA+B,EAC/B,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,EACf,cAAc,EACd,iBAAiB,EACjB,eAAe,EACf,uBAAuB,EACvB,iBAAiB,EACjB,qBAAqB,EACrB,sBAAsB,EACtB,sBAAsB,EACtB,0BAA0B,EAC1B,eAAe,EACf,gBAAgB,EAChB,uBAAuB,EACvB,yBAAyB,EACzB,eAAe,EACf,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,sBAAsB,EACtB,qBAAqB,EACrB,sBAAsB,EACtB,iBAAiB,EACjB,uBAAuB,EACvB,uBAAuB,EACvB,yBAAyB,EACzB,sBAAsB,EACtB,kBAAkB,EAClB,gBAAgB,EAChB,wBAAwB,EACxB,0BAA0B,EAC1B,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,WAAW,EACX,OAAO,EACP,UAAU,EACV,SAAS,EACT,cAAc,EACd,SAAS,EACT,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,eAAe,EACf,UAAU,EACV,aAAa,EACb,aAAa,EACb,WAAW,EACX,yBAAyB,EACzB,sBAAsB,EACtB,0BAA0B,EAC1B,8BAA8B,EAC9B,0BAA0B,EAC1B,4BAA4B,EAC5B,2BAA2B,EAC3B,8BAA8B,EAC9B,uBAAuB,EACvB,UAAU,EACV,eAAe,EACf,yBAAyB,EACzB,oBAAoB,EACpB,oCAAoC,EACpC,wCAAwC,EACxC,qBAAqB,EACrB,yBAAyB,EACzB,+BAA+B,EAC/B,WAAW,EACX,UAAU,EACV,QAAQ,EACR,QAAQ,GACT,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,sBAAsB,EACtB,0BAA0B,EAC1B,kBAAkB,EAClB,cAAc,EACd,kBAAkB,EAClB,KAAK,gBAAgB,GACtB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,EACL,mBAAmB,EACnB,oBAAoB,GACrB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,0BAA0B,EAC1B,KAAK,gBAAgB,GACtB,MAAM,mBAAmB,CAAC"} \ No newline at end of file diff --git a/packages/interfacectl-validator/dist/index.js b/packages/interfacectl-validator/dist/index.js index e58e2c4..af0981b 100644 --- a/packages/interfacectl-validator/dist/index.js +++ b/packages/interfacectl-validator/dist/index.js @@ -24,10 +24,15 @@ export function validateContractStructure(contractData, schema) { }; } const marketingReferenceErrors = validateMarketingProfileReferences(contractData); - if (marketingReferenceErrors.length > 0) { + const authoringReferenceErrors = validateAuthoringMetadata(contractData); + const validationErrors = [ + ...marketingReferenceErrors, + ...authoringReferenceErrors, + ]; + if (validationErrors.length > 0) { return { ok: false, - errors: marketingReferenceErrors, + errors: validationErrors, }; } return { @@ -52,6 +57,159 @@ function validateMarketingProfileReferences(contract) { } return errors; } +function validateAuthoringMetadata(contract) { + const errors = []; + const hasWebSurface = contract.surfaces.some((surface) => surface.type === "web"); + const hasAuthoringMetadata = (contract.components?.length ?? 0) > 0 || + contract.sections.some((section) => section.anatomy !== undefined || + section.editPolicy !== undefined || + section.responsive !== undefined) || + contract.surfaces.some((surface) => (surface.viewports?.length ?? 0) > 0 || surface.authoring !== undefined); + if (hasAuthoringMetadata && !hasWebSurface) { + errors.push("/components authoring metadata requires at least one web surface in the contract"); + } + const declaredViewportIds = new Set(); + for (const surface of contract.surfaces) { + const hasWebOnlyAuthoring = (surface.viewports?.length ?? 0) > 0 || surface.authoring !== undefined; + if (hasWebOnlyAuthoring && surface.type !== "web") { + errors.push(`/surfaces/${surface.id} authoring metadata is only supported when type is "web"`); + } + const viewportIds = new Set(); + for (const viewport of surface.viewports ?? []) { + if (viewportIds.has(viewport.id)) { + errors.push(`/surfaces/${surface.id}/viewports/${viewport.id} must use unique viewport ids within a surface`); + } + viewportIds.add(viewport.id); + declaredViewportIds.add(viewport.id); + if (viewport.minWidthPx !== undefined && + viewport.maxWidthPx !== undefined && + viewport.minWidthPx > viewport.maxWidthPx) { + errors.push(`/surfaces/${surface.id}/viewports/${viewport.id} maxWidthPx must be greater than or equal to minWidthPx`); + } + } + } + const components = contract.components ?? []; + const componentIds = new Set(); + const componentsById = new Map(); + for (const component of components) { + if (componentIds.has(component.id)) { + errors.push(`/components/${component.id} must use a unique component id`); + continue; + } + componentIds.add(component.id); + componentsById.set(component.id, component); + } + for (const component of components) { + validateComponentAuthoring(component, componentIds, errors); + } + for (const section of contract.sections) { + validateSectionAuthoring(section, componentIds, componentsById, declaredViewportIds, errors); + } + return errors; +} +function validateComponentAuthoring(component, componentIds, errors) { + const slotIds = new Set(); + for (const slot of component.slots) { + if (slotIds.has(slot.id)) { + errors.push(`/components/${component.id}/slots/${slot.id} must use a unique slot id within the component`); + } + slotIds.add(slot.id); + validateSlotDefinition(slot, `/components/${component.id}/slots/${slot.id}`, componentIds, errors); + } + const stateIds = new Set(); + for (const state of component.states ?? []) { + if (stateIds.has(state.id)) { + errors.push(`/components/${component.id}/states/${state.id} must use a unique state id within the component`); + } + stateIds.add(state.id); + for (const requiredSlot of state.requiredSlots ?? []) { + if (!slotIds.has(requiredSlot)) { + errors.push(`/components/${component.id}/states/${state.id}/requiredSlots/${requiredSlot} must reference a declared slot id`); + } + } + for (const hiddenSlot of state.hiddenSlots ?? []) { + if (!slotIds.has(hiddenSlot)) { + errors.push(`/components/${component.id}/states/${state.id}/hiddenSlots/${hiddenSlot} must reference a declared slot id`); + } + } + } + const interactionIds = new Set(); + for (const interaction of component.interactions ?? []) { + if (interactionIds.has(interaction.id)) { + errors.push(`/components/${component.id}/interactions/${interaction.id} must use a unique interaction id within the component`); + } + interactionIds.add(interaction.id); + if (interaction.resultingState !== undefined && + !stateIds.has(interaction.resultingState)) { + errors.push(`/components/${component.id}/interactions/${interaction.id}/resultingState must reference a declared state id`); + } + } + const implementation = component.implementation; + if (implementation?.preferredSource && + implementation.allowedSources?.length && + !implementation.allowedSources.includes(implementation.preferredSource)) { + errors.push(`/components/${component.id}/implementation/preferredSource must be included in implementation.allowedSources when both are provided`); + } +} +function validateSectionAuthoring(section, componentIds, componentsById, declaredViewportIds, errors) { + const anatomy = section.anatomy; + const knownSlotIds = new Set(); + if (anatomy?.defaultComponent && !componentIds.has(anatomy.defaultComponent)) { + errors.push(`/sections/${section.id}/anatomy/defaultComponent must reference a declared component id`); + } + for (const componentId of anatomy?.allowedComponents ?? []) { + if (!componentIds.has(componentId)) { + errors.push(`/sections/${section.id}/anatomy/allowedComponents/${componentId} must reference a declared component id`); + } + } + if (anatomy?.defaultComponent && + anatomy.allowedComponents?.length && + !anatomy.allowedComponents.includes(anatomy.defaultComponent)) { + errors.push(`/sections/${section.id}/anatomy/defaultComponent must be included in anatomy.allowedComponents when both are provided`); + } + for (const slot of anatomy?.slots ?? []) { + if (knownSlotIds.has(slot.id)) { + errors.push(`/sections/${section.id}/anatomy/slots/${slot.id} must use a unique slot id within the section`); + } + knownSlotIds.add(slot.id); + validateSlotDefinition(slot, `/sections/${section.id}/anatomy/slots/${slot.id}`, componentIds, errors); + } + if (knownSlotIds.size === 0 && anatomy?.defaultComponent) { + for (const slot of componentsById.get(anatomy.defaultComponent)?.slots ?? []) { + knownSlotIds.add(slot.id); + } + } + for (const rule of section.responsive?.rules ?? []) { + if (declaredViewportIds.size === 0) { + errors.push(`/sections/${section.id}/responsive/rules/${rule.viewport} must reference a declared surfaces[*].viewports id; none were declared`); + } + else if (!declaredViewportIds.has(rule.viewport)) { + errors.push(`/sections/${section.id}/responsive/rules/${rule.viewport} must reference a declared surfaces[*].viewports id`); + } + for (const slotBehavior of rule.slotBehaviors ?? []) { + if (knownSlotIds.size > 0 && !knownSlotIds.has(slotBehavior.slotId)) { + errors.push(`/sections/${section.id}/responsive/rules/${rule.viewport}/slotBehaviors/${slotBehavior.slotId} must reference a declared anatomy slot id`); + } + } + } +} +function validateSlotDefinition(slot, path, componentIds, errors) { + if (slot.minItems !== undefined && + slot.maxItems !== undefined && + slot.minItems > slot.maxItems) { + errors.push(`${path}/maxItems must be greater than or equal to minItems`); + } + if (slot.contentRules?.minLength !== undefined && + slot.contentRules?.maxLength !== undefined && + slot.contentRules.minLength > slot.contentRules.maxLength) { + errors.push(`${path}/contentRules/maxLength must be greater than or equal to minLength`); + } + for (const componentId of slot.acceptsComponents ?? []) { + if (!componentIds.has(componentId)) { + errors.push(`${path}/acceptsComponents/${componentId} must reference a declared component id`); + } + } +} function validateColorPolicy(contract, descriptor, violations) { const colorPolicy = contract.color; if (!colorPolicy || colorPolicy.policy === "off") { diff --git a/packages/interfacectl-validator/dist/schema/web.surface.contract.schema.json b/packages/interfacectl-validator/dist/schema/web.surface.contract.schema.json index 16167e3..c8f44a9 100644 --- a/packages/interfacectl-validator/dist/schema/web.surface.contract.schema.json +++ b/packages/interfacectl-validator/dist/schema/web.surface.contract.schema.json @@ -43,6 +43,12 @@ "$ref": "#/$defs/section" } }, + "components": { + "type": "array", + "items": { + "$ref": "#/$defs/component" + } + }, "constraints": { "$ref": "#/$defs/constraints" }, @@ -237,8 +243,44 @@ "minLength": 1 }, "uniqueItems": true + }, + "viewports": { + "type": "array", + "items": { + "$ref": "#/$defs/viewport" + } + }, + "authoring": { + "$ref": "#/$defs/surfaceAuthoring" } - } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "cli" + } + } + }, + "then": { + "not": { + "anyOf": [ + { + "required": [ + "viewports" + ] + }, + { + "required": [ + "authoring" + ] + } + ] + } + } + } + ] }, "section": { "type": "object", @@ -260,9 +302,585 @@ "description": { "type": "string", "minLength": 1 + }, + "anatomy": { + "$ref": "#/$defs/sectionAnatomy" + }, + "editPolicy": { + "$ref": "#/$defs/sectionEditPolicy" + }, + "responsive": { + "$ref": "#/$defs/sectionResponsive" + } + } + }, + "component": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "intent", + "slots" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "intent": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/$defs/componentVariant" + } + }, + "slots": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/slot" + } + }, + "states": { + "type": "array", + "items": { + "$ref": "#/$defs/componentState" + } + }, + "interactions": { + "type": "array", + "items": { + "$ref": "#/$defs/componentInteraction" + } + }, + "implementation": { + "$ref": "#/$defs/componentImplementation" + }, + "references": { + "type": "array", + "items": { + "$ref": "#/$defs/externalReference" + } + } + } + }, + "componentVariant": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "when": { + "type": "string" + } + } + }, + "slot": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "kind", + "required" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "kind": { + "type": "string", + "enum": [ + "text", + "richText", + "media", + "action", + "icon", + "container", + "item-list" + ] + }, + "required": { + "type": "boolean" + }, + "repeatable": { + "type": "boolean" + }, + "minItems": { + "type": "integer", + "minimum": 0 + }, + "maxItems": { + "type": "integer", + "minimum": 0 + }, + "textRole": { + "type": "string", + "minLength": 1 + }, + "acceptsComponents": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "contentRules": { + "$ref": "#/$defs/slotContentRules" + } + } + }, + "slotContentRules": { + "type": "object", + "additionalProperties": false, + "properties": { + "minLength": { + "type": "integer", + "minimum": 0 + }, + "maxLength": { + "type": "integer", + "minimum": 0 + }, + "allowHtml": { + "type": "boolean" + }, + "allowedMimeTypes": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + } + } + }, + "componentState": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "label": { + "type": "string" + }, + "when": { + "type": "string" + }, + "requiredSlots": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "hiddenSlots": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "notes": { + "type": "string" + } + } + }, + "componentInteraction": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "trigger", + "effect" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "trigger": { + "type": "string", + "minLength": 1 + }, + "effect": { + "type": "string", + "enum": [ + "navigate", + "open", + "close", + "submit", + "filter", + "toggle", + "expand", + "collapse", + "select", + "set-state" + ] + }, + "target": { + "type": "string", + "minLength": 1 + }, + "resultingState": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "navigationTarget": { + "type": "string", + "minLength": 1 + }, + "notes": { + "type": "string" + } + } + }, + "componentImplementation": { + "type": "object", + "additionalProperties": false, + "properties": { + "preferredSource": { + "$ref": "#/$defs/authoringSource" + }, + "allowedSources": { + "type": "array", + "items": { + "$ref": "#/$defs/authoringSource" + }, + "uniqueItems": true + }, + "htmlFallback": { + "type": "string" + }, + "accessibilityNotes": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + } + } + }, + "externalReference": { + "type": "object", + "additionalProperties": false, + "required": [ + "system", + "kind", + "ref" + ], + "properties": { + "system": { + "type": "string", + "enum": [ + "figma", + "code", + "story", + "url", + "asset" + ] + }, + "kind": { + "type": "string", + "minLength": 1 + }, + "ref": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string" } } }, + "sectionAnatomy": { + "type": "object", + "additionalProperties": false, + "required": [ + "pattern" + ], + "properties": { + "pattern": { + "type": "string", + "minLength": 1 + }, + "defaultComponent": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "allowedComponents": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "slots": { + "type": "array", + "items": { + "$ref": "#/$defs/slot" + } + } + } + }, + "sectionEditPolicy": { + "type": "object", + "additionalProperties": false, + "required": [ + "mode" + ], + "properties": { + "mode": { + "type": "string", + "enum": [ + "locked", + "slot-bound", + "freeform" + ] + }, + "allowedOperations": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "update-copy", + "swap-variant", + "reorder-items", + "change-media", + "adjust-layout", + "bind-data", + "wire-interaction" + ] + }, + "uniqueItems": true + } + } + }, + "sectionResponsive": { + "type": "object", + "additionalProperties": false, + "required": [ + "rules" + ], + "properties": { + "rules": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/responsiveRule" + } + } + } + }, + "responsiveRule": { + "type": "object", + "additionalProperties": false, + "required": [ + "viewport", + "layoutIntent" + ], + "properties": { + "viewport": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "layoutIntent": { + "type": "string", + "enum": [ + "stack", + "columns", + "auto-fit-grid", + "sidebar-main", + "single-column-form" + ] + }, + "slotBehaviors": { + "type": "array", + "items": { + "$ref": "#/$defs/responsiveSlotBehavior" + } + }, + "notes": { + "type": "string" + } + } + }, + "responsiveSlotBehavior": { + "type": "object", + "additionalProperties": false, + "required": [ + "slotId", + "behavior" + ], + "properties": { + "slotId": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "behavior": { + "type": "string", + "enum": [ + "stack", + "inline", + "grid", + "hide", + "collapse", + "pin" + ] + }, + "notes": { + "type": "string" + } + } + }, + "viewport": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "label": { + "type": "string" + }, + "minWidthPx": { + "type": "number", + "minimum": 0 + }, + "maxWidthPx": { + "type": "number", + "minimum": 0 + }, + "density": { + "type": "string", + "enum": [ + "compact", + "comfortable", + "spacious" + ] + }, + "notes": { + "type": "string" + } + } + }, + "surfaceAuthoring": { + "type": "object", + "additionalProperties": false, + "required": [ + "sourcePriority" + ], + "properties": { + "framework": { + "type": "string", + "minLength": 1 + }, + "routing": { + "type": "string", + "minLength": 1 + }, + "styling": { + "$ref": "#/$defs/surfaceAuthoringStyling" + }, + "preferredLibraries": { + "$ref": "#/$defs/surfaceAuthoringLibraries" + }, + "sourcePriority": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/authoringSource" + }, + "uniqueItems": true + } + } + }, + "surfaceAuthoringStyling": { + "type": "object", + "additionalProperties": false, + "properties": { + "strategy": { + "type": "string", + "minLength": 1 + }, + "tokenPrefix": { + "type": "string", + "minLength": 1 + } + } + }, + "surfaceAuthoringLibraries": { + "type": "object", + "additionalProperties": false, + "properties": { + "components": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "icons": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "data": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + } + } + }, + "authoringSource": { + "type": "string", + "enum": [ + "contract", + "figma", + "code", + "story", + "url", + "asset" + ] + }, "constraints": { "type": "object", "additionalProperties": false, diff --git a/packages/interfacectl-validator/dist/types.d.ts b/packages/interfacectl-validator/dist/types.d.ts index 43c2b3c..78113c4 100644 --- a/packages/interfacectl-validator/dist/types.d.ts +++ b/packages/interfacectl-validator/dist/types.d.ts @@ -39,6 +39,125 @@ export interface FlowPolicy { policy: "off" | "warn" | "strict"; requirements: FlowRequirement[]; } +export type ExternalReferenceSystem = "figma" | "code" | "story" | "url" | "asset"; +export type AuthoringSource = "contract" | ExternalReferenceSystem; +export interface ExternalReference { + system: ExternalReferenceSystem; + kind: string; + ref: string; + name?: string; +} +export type ContractSlotKind = "text" | "richText" | "media" | "action" | "icon" | "container" | "item-list"; +export interface ContractSlotContentRules { + minLength?: number; + maxLength?: number; + allowHtml?: boolean; + allowedMimeTypes?: string[]; +} +export interface ContractSlot { + id: string; + kind: ContractSlotKind; + required: boolean; + repeatable?: boolean; + minItems?: number; + maxItems?: number; + textRole?: string; + acceptsComponents?: string[]; + contentRules?: ContractSlotContentRules; +} +export interface ContractComponentVariant { + id: string; + label?: string; + description?: string; + when?: string; +} +export interface ContractState { + id: string; + label?: string; + when?: string; + requiredSlots?: string[]; + hiddenSlots?: string[]; + notes?: string; +} +export type ContractInteractionEffect = "navigate" | "open" | "close" | "submit" | "filter" | "toggle" | "expand" | "collapse" | "select" | "set-state"; +export interface ContractInteraction { + id: string; + trigger: string; + effect: ContractInteractionEffect; + target?: string; + resultingState?: string; + navigationTarget?: string; + notes?: string; +} +export interface ContractComponentImplementation { + preferredSource?: AuthoringSource; + allowedSources?: AuthoringSource[]; + htmlFallback?: string; + accessibilityNotes?: string[]; +} +export interface ContractComponent { + id: string; + intent: string; + description?: string; + variants?: ContractComponentVariant[]; + slots: ContractSlot[]; + states?: ContractState[]; + interactions?: ContractInteraction[]; + implementation?: ContractComponentImplementation; + references?: ExternalReference[]; +} +export interface SectionAnatomy { + pattern: string; + defaultComponent?: string; + allowedComponents?: string[]; + slots?: ContractSlot[]; +} +export type SectionEditMode = "locked" | "slot-bound" | "freeform"; +export type SectionAllowedOperation = "update-copy" | "swap-variant" | "reorder-items" | "change-media" | "adjust-layout" | "bind-data" | "wire-interaction"; +export interface SectionEditPolicy { + mode: SectionEditMode; + allowedOperations?: SectionAllowedOperation[]; +} +export type ResponsiveLayoutIntent = "stack" | "columns" | "auto-fit-grid" | "sidebar-main" | "single-column-form"; +export type ResponsiveSlotBehaviorKind = "stack" | "inline" | "grid" | "hide" | "collapse" | "pin"; +export interface ResponsiveSlotBehavior { + slotId: string; + behavior: ResponsiveSlotBehaviorKind; + notes?: string; +} +export interface SectionResponsiveRule { + viewport: string; + layoutIntent: ResponsiveLayoutIntent; + slotBehaviors?: ResponsiveSlotBehavior[]; + notes?: string; +} +export interface SectionResponsive { + rules: SectionResponsiveRule[]; +} +export interface ViewportProfile { + id: string; + label?: string; + minWidthPx?: number; + maxWidthPx?: number; + density?: "compact" | "comfortable" | "spacious"; + notes?: string; +} +export interface SurfaceAuthoringStyling { + strategy?: string; + tokenPrefix?: string; +} +export interface SurfaceAuthoringLibraries { + components?: string[]; + icons?: string[]; + data?: string[]; +} +export interface SurfaceAuthoring { + framework?: string; + routing?: string; + styling?: SurfaceAuthoringStyling; + preferredLibraries?: SurfaceAuthoringLibraries; + sourcePriority: AuthoringSource[]; +} export interface ContractSurface { id: string; displayName: string; @@ -58,11 +177,16 @@ export interface ContractSurface { flows?: FlowPolicy; mustNotEmit?: string[]; shellOwnedPrimitiveAllowSources?: string[]; + viewports?: ViewportProfile[]; + authoring?: SurfaceAuthoring; } export interface ContractSection { id: string; intent: string; description: string; + anatomy?: SectionAnatomy; + editPolicy?: SectionEditPolicy; + responsive?: SectionResponsive; } export interface ContractConstraints { motion: { @@ -131,6 +255,7 @@ export interface InterfaceContract { description?: string; surfaces: ContractSurface[]; sections: ContractSection[]; + components?: ContractComponent[]; constraints: ContractConstraints; color: ColorPolicy; tokens?: ContractTokenPolicies; diff --git a/packages/interfacectl-validator/dist/types.d.ts.map b/packages/interfacectl-validator/dist/types.d.ts.map index 87e3798..85cba21 100644 --- a/packages/interfacectl-validator/dist/types.d.ts.map +++ b/packages/interfacectl-validator/dist/types.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/packages/interfacectl-validator/src/index.ts b/packages/interfacectl-validator/src/index.ts index f895ae6..3c3ecc8 100644 --- a/packages/interfacectl-validator/src/index.ts +++ b/packages/interfacectl-validator/src/index.ts @@ -1,6 +1,8 @@ import AjvModule, { type ErrorObject } from "ajv/dist/2020.js"; import addFormats from "ajv-formats"; import { + ContractComponent, + ContractSlot, InterfaceContract, SurfaceDescriptor, SurfaceReport, @@ -57,10 +59,17 @@ export function validateContractStructure( const marketingReferenceErrors = validateMarketingProfileReferences( contractData as InterfaceContract, ); - if (marketingReferenceErrors.length > 0) { + const authoringReferenceErrors = validateAuthoringMetadata( + contractData as InterfaceContract, + ); + const validationErrors = [ + ...marketingReferenceErrors, + ...authoringReferenceErrors, + ]; + if (validationErrors.length > 0) { return { ok: false, - errors: marketingReferenceErrors, + errors: validationErrors, }; } @@ -101,6 +110,276 @@ function validateMarketingProfileReferences( return errors; } +function validateAuthoringMetadata(contract: InterfaceContract): string[] { + const errors: string[] = []; + const hasWebSurface = contract.surfaces.some((surface) => surface.type === "web"); + const hasAuthoringMetadata = + (contract.components?.length ?? 0) > 0 || + contract.sections.some( + (section) => + section.anatomy !== undefined || + section.editPolicy !== undefined || + section.responsive !== undefined, + ) || + contract.surfaces.some( + (surface) => + (surface.viewports?.length ?? 0) > 0 || surface.authoring !== undefined, + ); + + if (hasAuthoringMetadata && !hasWebSurface) { + errors.push( + "/components authoring metadata requires at least one web surface in the contract", + ); + } + + const declaredViewportIds = new Set(); + for (const surface of contract.surfaces) { + const hasWebOnlyAuthoring = + (surface.viewports?.length ?? 0) > 0 || surface.authoring !== undefined; + if (hasWebOnlyAuthoring && surface.type !== "web") { + errors.push( + `/surfaces/${surface.id} authoring metadata is only supported when type is "web"`, + ); + } + + const viewportIds = new Set(); + for (const viewport of surface.viewports ?? []) { + if (viewportIds.has(viewport.id)) { + errors.push( + `/surfaces/${surface.id}/viewports/${viewport.id} must use unique viewport ids within a surface`, + ); + } + viewportIds.add(viewport.id); + declaredViewportIds.add(viewport.id); + + if ( + viewport.minWidthPx !== undefined && + viewport.maxWidthPx !== undefined && + viewport.minWidthPx > viewport.maxWidthPx + ) { + errors.push( + `/surfaces/${surface.id}/viewports/${viewport.id} maxWidthPx must be greater than or equal to minWidthPx`, + ); + } + } + } + + const components = contract.components ?? []; + const componentIds = new Set(); + const componentsById = new Map(); + for (const component of components) { + if (componentIds.has(component.id)) { + errors.push(`/components/${component.id} must use a unique component id`); + continue; + } + componentIds.add(component.id); + componentsById.set(component.id, component); + } + + for (const component of components) { + validateComponentAuthoring(component, componentIds, errors); + } + + for (const section of contract.sections) { + validateSectionAuthoring( + section, + componentIds, + componentsById, + declaredViewportIds, + errors, + ); + } + + return errors; +} + +function validateComponentAuthoring( + component: ContractComponent, + componentIds: ReadonlySet, + errors: string[], +): void { + const slotIds = new Set(); + for (const slot of component.slots) { + if (slotIds.has(slot.id)) { + errors.push( + `/components/${component.id}/slots/${slot.id} must use a unique slot id within the component`, + ); + } + slotIds.add(slot.id); + validateSlotDefinition( + slot, + `/components/${component.id}/slots/${slot.id}`, + componentIds, + errors, + ); + } + + const stateIds = new Set(); + for (const state of component.states ?? []) { + if (stateIds.has(state.id)) { + errors.push( + `/components/${component.id}/states/${state.id} must use a unique state id within the component`, + ); + } + stateIds.add(state.id); + + for (const requiredSlot of state.requiredSlots ?? []) { + if (!slotIds.has(requiredSlot)) { + errors.push( + `/components/${component.id}/states/${state.id}/requiredSlots/${requiredSlot} must reference a declared slot id`, + ); + } + } + + for (const hiddenSlot of state.hiddenSlots ?? []) { + if (!slotIds.has(hiddenSlot)) { + errors.push( + `/components/${component.id}/states/${state.id}/hiddenSlots/${hiddenSlot} must reference a declared slot id`, + ); + } + } + } + + const interactionIds = new Set(); + for (const interaction of component.interactions ?? []) { + if (interactionIds.has(interaction.id)) { + errors.push( + `/components/${component.id}/interactions/${interaction.id} must use a unique interaction id within the component`, + ); + } + interactionIds.add(interaction.id); + + if ( + interaction.resultingState !== undefined && + !stateIds.has(interaction.resultingState) + ) { + errors.push( + `/components/${component.id}/interactions/${interaction.id}/resultingState must reference a declared state id`, + ); + } + } + + const implementation = component.implementation; + if ( + implementation?.preferredSource && + implementation.allowedSources?.length && + !implementation.allowedSources.includes(implementation.preferredSource) + ) { + errors.push( + `/components/${component.id}/implementation/preferredSource must be included in implementation.allowedSources when both are provided`, + ); + } +} + +function validateSectionAuthoring( + section: ContractSection, + componentIds: ReadonlySet, + componentsById: ReadonlyMap, + declaredViewportIds: ReadonlySet, + errors: string[], +): void { + const anatomy = section.anatomy; + const knownSlotIds = new Set(); + + if (anatomy?.defaultComponent && !componentIds.has(anatomy.defaultComponent)) { + errors.push( + `/sections/${section.id}/anatomy/defaultComponent must reference a declared component id`, + ); + } + + for (const componentId of anatomy?.allowedComponents ?? []) { + if (!componentIds.has(componentId)) { + errors.push( + `/sections/${section.id}/anatomy/allowedComponents/${componentId} must reference a declared component id`, + ); + } + } + + if ( + anatomy?.defaultComponent && + anatomy.allowedComponents?.length && + !anatomy.allowedComponents.includes(anatomy.defaultComponent) + ) { + errors.push( + `/sections/${section.id}/anatomy/defaultComponent must be included in anatomy.allowedComponents when both are provided`, + ); + } + + for (const slot of anatomy?.slots ?? []) { + if (knownSlotIds.has(slot.id)) { + errors.push( + `/sections/${section.id}/anatomy/slots/${slot.id} must use a unique slot id within the section`, + ); + } + knownSlotIds.add(slot.id); + validateSlotDefinition( + slot, + `/sections/${section.id}/anatomy/slots/${slot.id}`, + componentIds, + errors, + ); + } + + if (knownSlotIds.size === 0 && anatomy?.defaultComponent) { + for (const slot of componentsById.get(anatomy.defaultComponent)?.slots ?? []) { + knownSlotIds.add(slot.id); + } + } + + for (const rule of section.responsive?.rules ?? []) { + if (declaredViewportIds.size === 0) { + errors.push( + `/sections/${section.id}/responsive/rules/${rule.viewport} must reference a declared surfaces[*].viewports id; none were declared`, + ); + } else if (!declaredViewportIds.has(rule.viewport)) { + errors.push( + `/sections/${section.id}/responsive/rules/${rule.viewport} must reference a declared surfaces[*].viewports id`, + ); + } + + for (const slotBehavior of rule.slotBehaviors ?? []) { + if (knownSlotIds.size > 0 && !knownSlotIds.has(slotBehavior.slotId)) { + errors.push( + `/sections/${section.id}/responsive/rules/${rule.viewport}/slotBehaviors/${slotBehavior.slotId} must reference a declared anatomy slot id`, + ); + } + } + } +} + +function validateSlotDefinition( + slot: ContractSlot, + path: string, + componentIds: ReadonlySet, + errors: string[], +): void { + if ( + slot.minItems !== undefined && + slot.maxItems !== undefined && + slot.minItems > slot.maxItems + ) { + errors.push(`${path}/maxItems must be greater than or equal to minItems`); + } + + if ( + slot.contentRules?.minLength !== undefined && + slot.contentRules?.maxLength !== undefined && + slot.contentRules.minLength > slot.contentRules.maxLength + ) { + errors.push( + `${path}/contentRules/maxLength must be greater than or equal to minLength`, + ); + } + + for (const componentId of slot.acceptsComponents ?? []) { + if (!componentIds.has(componentId)) { + errors.push( + `${path}/acceptsComponents/${componentId} must reference a declared component id`, + ); + } + } +} + function validateColorPolicy( contract: InterfaceContract, descriptor: SurfaceDescriptor, @@ -1323,6 +1602,31 @@ function findSurface( export type { InterfaceContract, + ContractComponent, + ContractSlot, + ContractSlotKind, + ContractSlotContentRules, + ContractComponentVariant, + ContractState, + ContractInteraction, + ContractInteractionEffect, + ContractComponentImplementation, + ExternalReference, + ExternalReferenceSystem, + AuthoringSource, + SectionAnatomy, + SectionEditPolicy, + SectionEditMode, + SectionAllowedOperation, + SectionResponsive, + SectionResponsiveRule, + ResponsiveLayoutIntent, + ResponsiveSlotBehavior, + ResponsiveSlotBehaviorKind, + ViewportProfile, + SurfaceAuthoring, + SurfaceAuthoringStyling, + SurfaceAuthoringLibraries, ContractSurface, ContractSection, ContractConstraints, diff --git a/packages/interfacectl-validator/src/schema/web.surface.contract.schema.json b/packages/interfacectl-validator/src/schema/web.surface.contract.schema.json index 16167e3..c8f44a9 100644 --- a/packages/interfacectl-validator/src/schema/web.surface.contract.schema.json +++ b/packages/interfacectl-validator/src/schema/web.surface.contract.schema.json @@ -43,6 +43,12 @@ "$ref": "#/$defs/section" } }, + "components": { + "type": "array", + "items": { + "$ref": "#/$defs/component" + } + }, "constraints": { "$ref": "#/$defs/constraints" }, @@ -237,8 +243,44 @@ "minLength": 1 }, "uniqueItems": true + }, + "viewports": { + "type": "array", + "items": { + "$ref": "#/$defs/viewport" + } + }, + "authoring": { + "$ref": "#/$defs/surfaceAuthoring" } - } + }, + "allOf": [ + { + "if": { + "properties": { + "type": { + "const": "cli" + } + } + }, + "then": { + "not": { + "anyOf": [ + { + "required": [ + "viewports" + ] + }, + { + "required": [ + "authoring" + ] + } + ] + } + } + } + ] }, "section": { "type": "object", @@ -260,9 +302,585 @@ "description": { "type": "string", "minLength": 1 + }, + "anatomy": { + "$ref": "#/$defs/sectionAnatomy" + }, + "editPolicy": { + "$ref": "#/$defs/sectionEditPolicy" + }, + "responsive": { + "$ref": "#/$defs/sectionResponsive" + } + } + }, + "component": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "intent", + "slots" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "intent": { + "type": "string", + "minLength": 1 + }, + "description": { + "type": "string" + }, + "variants": { + "type": "array", + "items": { + "$ref": "#/$defs/componentVariant" + } + }, + "slots": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/slot" + } + }, + "states": { + "type": "array", + "items": { + "$ref": "#/$defs/componentState" + } + }, + "interactions": { + "type": "array", + "items": { + "$ref": "#/$defs/componentInteraction" + } + }, + "implementation": { + "$ref": "#/$defs/componentImplementation" + }, + "references": { + "type": "array", + "items": { + "$ref": "#/$defs/externalReference" + } + } + } + }, + "componentVariant": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "label": { + "type": "string" + }, + "description": { + "type": "string" + }, + "when": { + "type": "string" + } + } + }, + "slot": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "kind", + "required" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "kind": { + "type": "string", + "enum": [ + "text", + "richText", + "media", + "action", + "icon", + "container", + "item-list" + ] + }, + "required": { + "type": "boolean" + }, + "repeatable": { + "type": "boolean" + }, + "minItems": { + "type": "integer", + "minimum": 0 + }, + "maxItems": { + "type": "integer", + "minimum": 0 + }, + "textRole": { + "type": "string", + "minLength": 1 + }, + "acceptsComponents": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "contentRules": { + "$ref": "#/$defs/slotContentRules" + } + } + }, + "slotContentRules": { + "type": "object", + "additionalProperties": false, + "properties": { + "minLength": { + "type": "integer", + "minimum": 0 + }, + "maxLength": { + "type": "integer", + "minimum": 0 + }, + "allowHtml": { + "type": "boolean" + }, + "allowedMimeTypes": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + } + } + }, + "componentState": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "label": { + "type": "string" + }, + "when": { + "type": "string" + }, + "requiredSlots": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "hiddenSlots": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "notes": { + "type": "string" + } + } + }, + "componentInteraction": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "trigger", + "effect" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "trigger": { + "type": "string", + "minLength": 1 + }, + "effect": { + "type": "string", + "enum": [ + "navigate", + "open", + "close", + "submit", + "filter", + "toggle", + "expand", + "collapse", + "select", + "set-state" + ] + }, + "target": { + "type": "string", + "minLength": 1 + }, + "resultingState": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "navigationTarget": { + "type": "string", + "minLength": 1 + }, + "notes": { + "type": "string" + } + } + }, + "componentImplementation": { + "type": "object", + "additionalProperties": false, + "properties": { + "preferredSource": { + "$ref": "#/$defs/authoringSource" + }, + "allowedSources": { + "type": "array", + "items": { + "$ref": "#/$defs/authoringSource" + }, + "uniqueItems": true + }, + "htmlFallback": { + "type": "string" + }, + "accessibilityNotes": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + } + } + }, + "externalReference": { + "type": "object", + "additionalProperties": false, + "required": [ + "system", + "kind", + "ref" + ], + "properties": { + "system": { + "type": "string", + "enum": [ + "figma", + "code", + "story", + "url", + "asset" + ] + }, + "kind": { + "type": "string", + "minLength": 1 + }, + "ref": { + "type": "string", + "minLength": 1 + }, + "name": { + "type": "string" } } }, + "sectionAnatomy": { + "type": "object", + "additionalProperties": false, + "required": [ + "pattern" + ], + "properties": { + "pattern": { + "type": "string", + "minLength": 1 + }, + "defaultComponent": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "allowedComponents": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "uniqueItems": true + }, + "slots": { + "type": "array", + "items": { + "$ref": "#/$defs/slot" + } + } + } + }, + "sectionEditPolicy": { + "type": "object", + "additionalProperties": false, + "required": [ + "mode" + ], + "properties": { + "mode": { + "type": "string", + "enum": [ + "locked", + "slot-bound", + "freeform" + ] + }, + "allowedOperations": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "update-copy", + "swap-variant", + "reorder-items", + "change-media", + "adjust-layout", + "bind-data", + "wire-interaction" + ] + }, + "uniqueItems": true + } + } + }, + "sectionResponsive": { + "type": "object", + "additionalProperties": false, + "required": [ + "rules" + ], + "properties": { + "rules": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/responsiveRule" + } + } + } + }, + "responsiveRule": { + "type": "object", + "additionalProperties": false, + "required": [ + "viewport", + "layoutIntent" + ], + "properties": { + "viewport": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "layoutIntent": { + "type": "string", + "enum": [ + "stack", + "columns", + "auto-fit-grid", + "sidebar-main", + "single-column-form" + ] + }, + "slotBehaviors": { + "type": "array", + "items": { + "$ref": "#/$defs/responsiveSlotBehavior" + } + }, + "notes": { + "type": "string" + } + } + }, + "responsiveSlotBehavior": { + "type": "object", + "additionalProperties": false, + "required": [ + "slotId", + "behavior" + ], + "properties": { + "slotId": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "behavior": { + "type": "string", + "enum": [ + "stack", + "inline", + "grid", + "hide", + "collapse", + "pin" + ] + }, + "notes": { + "type": "string" + } + } + }, + "viewport": { + "type": "object", + "additionalProperties": false, + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+([.-][a-z0-9]+)*$" + }, + "label": { + "type": "string" + }, + "minWidthPx": { + "type": "number", + "minimum": 0 + }, + "maxWidthPx": { + "type": "number", + "minimum": 0 + }, + "density": { + "type": "string", + "enum": [ + "compact", + "comfortable", + "spacious" + ] + }, + "notes": { + "type": "string" + } + } + }, + "surfaceAuthoring": { + "type": "object", + "additionalProperties": false, + "required": [ + "sourcePriority" + ], + "properties": { + "framework": { + "type": "string", + "minLength": 1 + }, + "routing": { + "type": "string", + "minLength": 1 + }, + "styling": { + "$ref": "#/$defs/surfaceAuthoringStyling" + }, + "preferredLibraries": { + "$ref": "#/$defs/surfaceAuthoringLibraries" + }, + "sourcePriority": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/authoringSource" + }, + "uniqueItems": true + } + } + }, + "surfaceAuthoringStyling": { + "type": "object", + "additionalProperties": false, + "properties": { + "strategy": { + "type": "string", + "minLength": 1 + }, + "tokenPrefix": { + "type": "string", + "minLength": 1 + } + } + }, + "surfaceAuthoringLibraries": { + "type": "object", + "additionalProperties": false, + "properties": { + "components": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "icons": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + }, + "data": { + "type": "array", + "items": { + "type": "string", + "minLength": 1 + }, + "uniqueItems": true + } + } + }, + "authoringSource": { + "type": "string", + "enum": [ + "contract", + "figma", + "code", + "story", + "url", + "asset" + ] + }, "constraints": { "type": "object", "additionalProperties": false, diff --git a/packages/interfacectl-validator/src/types.ts b/packages/interfacectl-validator/src/types.ts index e5c5ded..13cb254 100644 --- a/packages/interfacectl-validator/src/types.ts +++ b/packages/interfacectl-validator/src/types.ts @@ -51,6 +51,190 @@ export interface FlowPolicy { requirements: FlowRequirement[]; } +export type ExternalReferenceSystem = + | "figma" + | "code" + | "story" + | "url" + | "asset"; + +export type AuthoringSource = "contract" | ExternalReferenceSystem; + +export interface ExternalReference { + system: ExternalReferenceSystem; + kind: string; + ref: string; + name?: string; +} + +export type ContractSlotKind = + | "text" + | "richText" + | "media" + | "action" + | "icon" + | "container" + | "item-list"; + +export interface ContractSlotContentRules { + minLength?: number; + maxLength?: number; + allowHtml?: boolean; + allowedMimeTypes?: string[]; +} + +export interface ContractSlot { + id: string; + kind: ContractSlotKind; + required: boolean; + repeatable?: boolean; + minItems?: number; + maxItems?: number; + textRole?: string; + acceptsComponents?: string[]; + contentRules?: ContractSlotContentRules; +} + +export interface ContractComponentVariant { + id: string; + label?: string; + description?: string; + when?: string; +} + +export interface ContractState { + id: string; + label?: string; + when?: string; + requiredSlots?: string[]; + hiddenSlots?: string[]; + notes?: string; +} + +export type ContractInteractionEffect = + | "navigate" + | "open" + | "close" + | "submit" + | "filter" + | "toggle" + | "expand" + | "collapse" + | "select" + | "set-state"; + +export interface ContractInteraction { + id: string; + trigger: string; + effect: ContractInteractionEffect; + target?: string; + resultingState?: string; + navigationTarget?: string; + notes?: string; +} + +export interface ContractComponentImplementation { + preferredSource?: AuthoringSource; + allowedSources?: AuthoringSource[]; + htmlFallback?: string; + accessibilityNotes?: string[]; +} + +export interface ContractComponent { + id: string; + intent: string; + description?: string; + variants?: ContractComponentVariant[]; + slots: ContractSlot[]; + states?: ContractState[]; + interactions?: ContractInteraction[]; + implementation?: ContractComponentImplementation; + references?: ExternalReference[]; +} + +export interface SectionAnatomy { + pattern: string; + defaultComponent?: string; + allowedComponents?: string[]; + slots?: ContractSlot[]; +} + +export type SectionEditMode = "locked" | "slot-bound" | "freeform"; + +export type SectionAllowedOperation = + | "update-copy" + | "swap-variant" + | "reorder-items" + | "change-media" + | "adjust-layout" + | "bind-data" + | "wire-interaction"; + +export interface SectionEditPolicy { + mode: SectionEditMode; + allowedOperations?: SectionAllowedOperation[]; +} + +export type ResponsiveLayoutIntent = + | "stack" + | "columns" + | "auto-fit-grid" + | "sidebar-main" + | "single-column-form"; + +export type ResponsiveSlotBehaviorKind = + | "stack" + | "inline" + | "grid" + | "hide" + | "collapse" + | "pin"; + +export interface ResponsiveSlotBehavior { + slotId: string; + behavior: ResponsiveSlotBehaviorKind; + notes?: string; +} + +export interface SectionResponsiveRule { + viewport: string; + layoutIntent: ResponsiveLayoutIntent; + slotBehaviors?: ResponsiveSlotBehavior[]; + notes?: string; +} + +export interface SectionResponsive { + rules: SectionResponsiveRule[]; +} + +export interface ViewportProfile { + id: string; + label?: string; + minWidthPx?: number; + maxWidthPx?: number; + density?: "compact" | "comfortable" | "spacious"; + notes?: string; +} + +export interface SurfaceAuthoringStyling { + strategy?: string; + tokenPrefix?: string; +} + +export interface SurfaceAuthoringLibraries { + components?: string[]; + icons?: string[]; + data?: string[]; +} + +export interface SurfaceAuthoring { + framework?: string; + routing?: string; + styling?: SurfaceAuthoringStyling; + preferredLibraries?: SurfaceAuthoringLibraries; + sourcePriority: AuthoringSource[]; +} + export interface ContractSurface { id: string; displayName: string; @@ -70,12 +254,17 @@ export interface ContractSurface { flows?: FlowPolicy; mustNotEmit?: string[]; shellOwnedPrimitiveAllowSources?: string[]; + viewports?: ViewportProfile[]; + authoring?: SurfaceAuthoring; } export interface ContractSection { id: string; intent: string; description: string; + anatomy?: SectionAnatomy; + editPolicy?: SectionEditPolicy; + responsive?: SectionResponsive; } export interface ContractConstraints { @@ -167,6 +356,7 @@ export interface InterfaceContract { description?: string; surfaces: ContractSurface[]; sections: ContractSection[]; + components?: ContractComponent[]; constraints: ContractConstraints; color: ColorPolicy; tokens?: ContractTokenPolicies; diff --git a/packages/interfacectl-validator/test/authoring-contract.test.mjs b/packages/interfacectl-validator/test/authoring-contract.test.mjs new file mode 100644 index 0000000..b062f0a --- /dev/null +++ b/packages/interfacectl-validator/test/authoring-contract.test.mjs @@ -0,0 +1,89 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { readFile } from "node:fs/promises"; +import path from "node:path"; +import url from "node:url"; +import { + getBundledContractSchema, + validateContractStructure, +} from "../dist/index.js"; + +const fixturePath = path.join( + url.fileURLToPath(new URL(".", import.meta.url)), + "fixtures", + "authoring", + "reference-target-web.contract.json", +); + +async function loadFixture() { + const raw = await readFile(fixturePath, "utf8"); + return JSON.parse(raw); +} + +test("validateContractStructure accepts generic authoring metadata for a web surface", async () => { + const schema = getBundledContractSchema(); + const contract = await loadFixture(); + const result = validateContractStructure(contract, schema); + assert.equal(result.ok, true); +}); + +test("validateContractStructure rejects section anatomy references to unknown components", async () => { + const schema = getBundledContractSchema(); + const contract = await loadFixture(); + contract.sections[0].anatomy.defaultComponent = "missing-component"; + const result = validateContractStructure(contract, schema); + assert.equal(result.ok, false); + assert.ok( + result.errors.some((error) => error.includes("/sections/page.intro/anatomy/defaultComponent")), + `expected defaultComponent validation error, got ${JSON.stringify(result.errors)}`, + ); +}); + +test("validateContractStructure rejects component states that reference unknown slots", async () => { + const schema = getBundledContractSchema(); + const contract = await loadFixture(); + contract.components[1].states[0].requiredSlots.push("missing-slot"); + const result = validateContractStructure(contract, schema); + assert.equal(result.ok, false); + assert.ok( + result.errors.some((error) => error.includes("/components/feature-card/states/default/requiredSlots/missing-slot")), + `expected requiredSlots validation error, got ${JSON.stringify(result.errors)}`, + ); +}); + +test("validateContractStructure rejects interactions with unknown effects", async () => { + const schema = getBundledContractSchema(); + const contract = await loadFixture(); + contract.components[1].interactions[0].effect = "launch"; + const result = validateContractStructure(contract, schema); + assert.equal(result.ok, false); + assert.ok( + result.errors.some((error) => error.includes("/components/1/interactions/0/effect")), + `expected effect schema validation error, got ${JSON.stringify(result.errors)}`, + ); +}); + +test("validateContractStructure rejects invalid viewport ranges", async () => { + const schema = getBundledContractSchema(); + const contract = await loadFixture(); + contract.surfaces[0].viewports[0].minWidthPx = 900; + contract.surfaces[0].viewports[0].maxWidthPx = 767; + const result = validateContractStructure(contract, schema); + assert.equal(result.ok, false); + assert.ok( + result.errors.some((error) => error.includes("/surfaces/reference-target-web/viewports/mobile")), + `expected viewport range validation error, got ${JSON.stringify(result.errors)}`, + ); +}); + +test("validateContractStructure rejects authoring metadata on non-web surfaces", async () => { + const schema = getBundledContractSchema(); + const contract = await loadFixture(); + contract.surfaces[0].type = "cli"; + const result = validateContractStructure(contract, schema); + assert.equal(result.ok, false); + assert.ok( + result.errors.some((error) => error.includes("/surfaces/0")), + `expected surface type validation error, got ${JSON.stringify(result.errors)}`, + ); +}); diff --git a/packages/interfacectl-validator/test/fixtures/authoring/reference-target-web.contract.json b/packages/interfacectl-validator/test/fixtures/authoring/reference-target-web.contract.json new file mode 100644 index 0000000..f9d84ea --- /dev/null +++ b/packages/interfacectl-validator/test/fixtures/authoring/reference-target-web.contract.json @@ -0,0 +1,318 @@ +{ + "$schema": "https://contracts.surfaces.local/web.surface.contract.schema.json", + "contractId": "reference-target-web.authoring-example", + "version": "0.1.0", + "description": "Annotated authoring example for the deterministic reference target surface.", + "surfaces": [ + { + "id": "reference-target-web", + "displayName": "Reference Target Web", + "type": "web", + "requiredSections": [ + "page.intro", + "page.featurecards", + "page.footer" + ], + "allowedFonts": [ + "Inter" + ], + "layout": { + "maxContentWidth": 1160 + }, + "viewports": [ + { + "id": "mobile", + "maxWidthPx": 767, + "density": "comfortable", + "notes": "Single-column reading flow." + }, + { + "id": "desktop", + "minWidthPx": 768, + "density": "comfortable", + "notes": "Card grid can spread across columns." + } + ], + "authoring": { + "framework": "react", + "routing": "static-anchor", + "styling": { + "strategy": "css-variables" + }, + "preferredLibraries": { + "components": [ + "custom" + ], + "icons": [ + "custom" + ] + }, + "sourcePriority": [ + "contract", + "figma", + "code", + "url" + ] + } + } + ], + "sections": [ + { + "id": "page.intro", + "intent": "intro", + "description": "Introductory copy block near the top of the page.", + "anatomy": { + "pattern": "copy-block", + "defaultComponent": "copy-block", + "allowedComponents": [ + "copy-block" + ] + }, + "editPolicy": { + "mode": "slot-bound", + "allowedOperations": [ + "update-copy", + "swap-variant", + "adjust-layout" + ] + }, + "responsive": { + "rules": [ + { + "viewport": "mobile", + "layoutIntent": "stack" + }, + { + "viewport": "desktop", + "layoutIntent": "columns" + } + ] + } + }, + { + "id": "page.featurecards", + "intent": "feature-list", + "description": "Repeated feature summaries presented as cards.", + "anatomy": { + "pattern": "repeated-card-list", + "defaultComponent": "feature-card", + "allowedComponents": [ + "feature-card" + ], + "slots": [ + { + "id": "items", + "kind": "item-list", + "required": true, + "repeatable": true, + "minItems": 3, + "acceptsComponents": [ + "feature-card" + ] + } + ] + }, + "editPolicy": { + "mode": "slot-bound", + "allowedOperations": [ + "update-copy", + "reorder-items", + "change-media" + ] + }, + "responsive": { + "rules": [ + { + "viewport": "mobile", + "layoutIntent": "stack", + "slotBehaviors": [ + { + "slotId": "items", + "behavior": "stack" + } + ] + }, + { + "viewport": "desktop", + "layoutIntent": "auto-fit-grid", + "slotBehaviors": [ + { + "slotId": "items", + "behavior": "grid" + } + ] + } + ] + } + }, + { + "id": "page.footer", + "intent": "footer-info", + "description": "Compact footer metadata row.", + "anatomy": { + "pattern": "meta-row" + }, + "editPolicy": { + "mode": "locked" + } + } + ], + "components": [ + { + "id": "copy-block", + "intent": "copy block", + "description": "Reusable copy cluster with optional primary action.", + "variants": [ + { + "id": "standard", + "label": "Standard" + } + ], + "slots": [ + { + "id": "eyebrow", + "kind": "text", + "required": false, + "textRole": "eyebrow" + }, + { + "id": "headline", + "kind": "text", + "required": true, + "textRole": "headline", + "contentRules": { + "minLength": 1, + "maxLength": 80 + } + }, + { + "id": "body", + "kind": "richText", + "required": true, + "contentRules": { + "minLength": 1, + "maxLength": 280 + } + }, + { + "id": "primary-action", + "kind": "action", + "required": false + } + ], + "implementation": { + "preferredSource": "contract", + "allowedSources": [ + "contract", + "figma", + "code", + "url" + ], + "htmlFallback": "section > h1 + p", + "accessibilityNotes": [ + "Preserve the page heading hierarchy." + ] + }, + "references": [ + { + "system": "url", + "kind": "live-example", + "ref": "https://reference-target-web.vercel.app/#hero", + "name": "Intro block" + } + ] + }, + { + "id": "feature-card", + "intent": "feature summary card", + "description": "Single feature summary used inside the repeated card list.", + "slots": [ + { + "id": "title", + "kind": "text", + "required": true, + "textRole": "title", + "contentRules": { + "maxLength": 40 + } + }, + { + "id": "body", + "kind": "text", + "required": true, + "contentRules": { + "maxLength": 120 + } + }, + { + "id": "cta", + "kind": "action", + "required": false + } + ], + "states": [ + { + "id": "default", + "requiredSlots": [ + "title", + "body" + ] + } + ], + "interactions": [ + { + "id": "open-detail", + "trigger": "activate card action", + "effect": "navigate", + "navigationTarget": "feature-detail" + } + ], + "references": [ + { + "system": "url", + "kind": "live-example", + "ref": "https://reference-target-web.vercel.app/#capabilities", + "name": "Feature list" + } + ] + } + ], + "constraints": { + "motion": { + "allowedDurationsMs": [ + 120 + ], + "allowedTimingFunctions": [ + "linear" + ] + } + }, + "color": { + "policy": "warn", + "allowedValues": [ + "rgb(15, 23, 42)", + "rgb(244, 246, 251)", + "rgb(255, 255, 255)" + ] + }, + "tokens": { + "layout": { + "policy": "warn", + "allowedTokens": [ + "var(--max-content)" + ] + }, + "typography": { + "policy": "warn", + "allowedTokens": [ + "var(--font-inter)" + ] + } + }, + "shell": { + "owns": [ + "navigation" + ], + "contentSlot": "page-root" + } +}