@adobe/design-data-spec 4.8.0 → 4.9.0
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/conformance/README.md +32 -9
- package/conformance/invalid/SPEC-051/dataset.json +9 -3
- package/conformance/invalid/SPEC-052/dataset.json +14 -4
- package/conformance/invalid/SPEC-053/dataset.json +16 -4
- package/conformance/invalid/SPEC-054/dataset.json +18 -5
- package/conformance/invalid/SPEC-055/dataset.json +9 -3
- package/conformance/invalid/SPEC-057/dataset.json +5 -2
- package/conformance/invalid/SPEC-058/dataset.json +8 -3
- package/conformance/invalid/SPEC-059/dataset.json +28 -0
- package/conformance/invalid/SPEC-059/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-060/dataset.json +44 -0
- package/conformance/invalid/SPEC-060/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-061/dataset.json +63 -0
- package/conformance/invalid/SPEC-061/expected-errors.json +15 -0
- package/conformance/invalid/SPEC-062/dataset.json +50 -0
- package/conformance/invalid/SPEC-062/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-063/dataset.json +57 -0
- package/conformance/invalid/SPEC-063/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-064/dataset.json +53 -0
- package/conformance/invalid/SPEC-064/expected-errors.json +15 -0
- package/conformance/invalid/SPEC-065/dataset.json +78 -0
- package/conformance/invalid/SPEC-065/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-066/dataset.json +37 -0
- package/conformance/invalid/SPEC-066/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-067/dataset.json +60 -0
- package/conformance/invalid/SPEC-067/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-068/dataset.json +37 -0
- package/conformance/invalid/SPEC-068/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-069/dataset.json +63 -0
- package/conformance/invalid/SPEC-069/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-070/dataset.json +71 -0
- package/conformance/invalid/SPEC-070/expected-errors.json +15 -0
- package/conformance/invalid/SPEC-071/dataset.json +77 -0
- package/conformance/invalid/SPEC-071/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-072/dataset.json +52 -0
- package/conformance/invalid/SPEC-072/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-073/dataset.json +59 -0
- package/conformance/invalid/SPEC-073/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-074/dataset.json +36 -0
- package/conformance/invalid/SPEC-074/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-075/dataset.json +53 -0
- package/conformance/invalid/SPEC-075/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-076/dataset.json +62 -0
- package/conformance/invalid/SPEC-076/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-076/manifest.json +6 -0
- package/conformance/invalid/SPEC-079/dataset.json +62 -0
- package/conformance/invalid/SPEC-079/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-079/manifest.json +58 -0
- package/conformance/invalid/SPEC-080/dataset.json +62 -0
- package/conformance/invalid/SPEC-080/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-080/manifest.json +32 -0
- package/conformance/invalid/SPEC-081/dataset.json +62 -0
- package/conformance/invalid/SPEC-081/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-081/manifest.json +7 -0
- package/conformance/invalid/SPEC-082/dataset.json +62 -0
- package/conformance/invalid/SPEC-082/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-082/manifest.json +14 -0
- package/conformance/invalid/SPEC-083/dataset.json +47 -0
- package/conformance/invalid/SPEC-083/expected-errors.json +10 -0
- package/conformance/invalid/SPEC-084/dataset.json +16 -0
- package/conformance/invalid/SPEC-084/expected-errors.json +10 -0
- package/conformance/valid/SPEC-025/dataset.json +1 -1
- package/conformance/valid/SPEC-049/dataset.json +1 -1
- package/conformance/valid/SPEC-051/dataset.json +40 -9
- package/conformance/valid/SPEC-064/dataset.json +64 -0
- package/conformance/valid/SPEC-064/expected-errors.json +4 -0
- package/conformance/valid/SPEC-065/dataset.json +89 -0
- package/conformance/valid/SPEC-065/expected-errors.json +4 -0
- package/conformance/valid/SPEC-079/dataset.json +62 -0
- package/conformance/valid/SPEC-079/manifest.json +58 -0
- package/package.json +1 -1
- package/rules/rules.yaml +373 -0
- package/schemas/anatomy-part.schema.json +11 -0
- package/schemas/component-changelog.schema.json +306 -0
- package/schemas/component-spec-sheet.schema.json +215 -0
- package/schemas/component-visual.schema.json +287 -0
- package/schemas/component.schema.json +80 -0
- package/schemas/manifest.schema.json +5 -0
- package/schemas/relationship.schema.json +8 -6
- package/spec/anatomy-format.md +97 -10
- package/spec/artifact-moves.md +157 -0
- package/spec/component-changelog.md +49 -0
- package/spec/component-format.md +4 -0
- package/spec/component-visuals.md +210 -0
- package/spec/index.md +5 -0
- package/spec/manifest.md +46 -29
- package/spec/option-constraints.md +87 -0
- package/spec/relationship-format.md +14 -11
package/rules/rules.yaml
CHANGED
|
@@ -724,3 +724,376 @@ rules:
|
|
|
724
724
|
message: "Alias {token} sets {field}={ownValue} but its $ref chain resolves to a token with {field}={leafValue}"
|
|
725
725
|
spec_ref: spec/cascade.md#alias-resolution
|
|
726
726
|
introduced_in: "1.0.0-draft"
|
|
727
|
+
|
|
728
|
+
- id: SPEC-060
|
|
729
|
+
name: visual-anatomy-valid
|
|
730
|
+
severity: error
|
|
731
|
+
layer: 2
|
|
732
|
+
category: reference-integrity
|
|
733
|
+
note: >
|
|
734
|
+
Cross-file sibling of SPEC-020 for visual recipes (`visuals/*.json`). A JSON Schema
|
|
735
|
+
cannot read the component file, so this is not a Layer 1 check. Skipped when no
|
|
736
|
+
component catalog is loaded.
|
|
737
|
+
assert: >
|
|
738
|
+
A visual recipe's `component` MUST name a declared component. Every key of `parts` MUST
|
|
739
|
+
be a declared anatomy part. `root` MUST be a recipe part and a top-level anatomy part
|
|
740
|
+
(listed in no other part's `contains`). Each part's `children` MUST be recipe parts and
|
|
741
|
+
appear in that anatomy part's `contains`. `around` MUST name a declared anatomy part;
|
|
742
|
+
`pressTarget` MUST name a declared anatomy part that is also a recipe part.
|
|
743
|
+
message: "Recipe part '{part}' is not a declared anatomy part of '{component}'"
|
|
744
|
+
spec_ref: spec/component-visuals.md#validation
|
|
745
|
+
introduced_in: "1.0.0-draft"
|
|
746
|
+
|
|
747
|
+
- id: SPEC-061
|
|
748
|
+
name: visual-conditions-valid
|
|
749
|
+
severity: error
|
|
750
|
+
layer: 2
|
|
751
|
+
category: reference-integrity
|
|
752
|
+
assert: >
|
|
753
|
+
Every `when.options` key (and `visibleWhen.options` key) in a visual recipe MUST be an
|
|
754
|
+
option of the component, with a value in that option's `values` (a boolean option
|
|
755
|
+
requires a boolean). Every `when.states` / `visibleWhen.states` entry MUST be the `name`
|
|
756
|
+
of a state declared by the component. Every `{name}` placeholder in a `token` or
|
|
757
|
+
`relationship` selector MUST be `size`, `sizeIndex` or an option of the component that
|
|
758
|
+
declares `values`.
|
|
759
|
+
message: "Option '{option}' of '{component}' has no value {value}"
|
|
760
|
+
spec_ref: spec/component-visuals.md#validation
|
|
761
|
+
introduced_in: "1.0.0-draft"
|
|
762
|
+
|
|
763
|
+
- id: SPEC-062
|
|
764
|
+
name: visual-selectors-resolve
|
|
765
|
+
severity: error
|
|
766
|
+
layer: 2
|
|
767
|
+
category: reference-integrity
|
|
768
|
+
note: >
|
|
769
|
+
`{sizeIndex}` expands over the `sizeScale` values, `{size}` over its keys and `{option}`
|
|
770
|
+
over the option's declared values before resolving. Relationship `context` is compared trimmed. Token selectors match name-object
|
|
771
|
+
fields the way the visual runtime does, including the property + `scaleIndex` fallback.
|
|
772
|
+
assert: >
|
|
773
|
+
Every `{relationship: {property, context}}` selector in a visual recipe MUST resolve to
|
|
774
|
+
a relationship record whose `scope.component` is the recipe's component and whose
|
|
775
|
+
`scope.property` and `context` match. Every `{token: {...}}` selector MUST match at
|
|
776
|
+
least one token.
|
|
777
|
+
message: "No relationship for '{component}' with property '{property}' and context '{context}'"
|
|
778
|
+
spec_ref: spec/component-visuals.md#validation
|
|
779
|
+
introduced_in: "1.0.0-draft"
|
|
780
|
+
|
|
781
|
+
- id: SPEC-063
|
|
782
|
+
name: visual-size-scale-valid
|
|
783
|
+
severity: error
|
|
784
|
+
layer: 2
|
|
785
|
+
category: reference-integrity
|
|
786
|
+
assert: >
|
|
787
|
+
The keys of a visual recipe's `sizeScale` MUST equal the values of the component's
|
|
788
|
+
`size` option. A component without a `size` option MAY declare a one-entry `sizeScale`,
|
|
789
|
+
the single size renderers draw (for example the fixed-size iOS switch).
|
|
790
|
+
message: "sizeScale key '{size}' is not a 'size' value of '{component}'"
|
|
791
|
+
spec_ref: spec/component-visuals.md#validation
|
|
792
|
+
introduced_in: "1.0.0-draft"
|
|
793
|
+
- id: SPEC-064
|
|
794
|
+
name: constraint-options-declared
|
|
795
|
+
severity: error
|
|
796
|
+
layer: 2
|
|
797
|
+
category: component
|
|
798
|
+
assert: >
|
|
799
|
+
Every option name used in a component constraint's `when` or `require` MUST be declared in
|
|
800
|
+
the component's `options`. Every value used there MUST appear in that option's `values`
|
|
801
|
+
list. Value checks are silent when the option declares no `values` list.
|
|
802
|
+
message: "Constraint option '{option}' is not declared on component '{component}'"
|
|
803
|
+
spec_ref: spec/option-constraints.md#rules
|
|
804
|
+
introduced_in: "1.0.0-draft"
|
|
805
|
+
|
|
806
|
+
- id: SPEC-065
|
|
807
|
+
name: recipe-targets-excluded-combination
|
|
808
|
+
severity: warning
|
|
809
|
+
layer: 2
|
|
810
|
+
category: component
|
|
811
|
+
note: >
|
|
812
|
+
Only `error` constraints count. Unpinned options range over their declared values (booleans
|
|
813
|
+
over true and false); an option with no known domain is never proven excluded. A rule that
|
|
814
|
+
also matches a valid combination is not reported.
|
|
815
|
+
assert: >
|
|
816
|
+
A visual recipe rule (`when.options`) or relationship `scope.options` SHOULD NOT match only
|
|
817
|
+
combinations excluded by an `error` constraint on the component.
|
|
818
|
+
message: "Recipe rule for '{component}' matches only combinations excluded by an error constraint"
|
|
819
|
+
spec_ref: spec/option-constraints.md#rules
|
|
820
|
+
introduced_in: "1.0.0-draft"
|
|
821
|
+
|
|
822
|
+
- id: SPEC-066
|
|
823
|
+
name: visual-covers-component
|
|
824
|
+
severity: warning
|
|
825
|
+
layer: 2
|
|
826
|
+
category: component
|
|
827
|
+
note: >
|
|
828
|
+
A name counts as used when a `when` or `visibleWhen` condition names it, when a token the
|
|
829
|
+
recipe binds carries the state, or when it is implied: `size` by `sizeScale`, `label` by a
|
|
830
|
+
text part, and `isDisabled` or `isSelected` by the `disabled` or `selected` states (and the
|
|
831
|
+
reverse). New recipes MUST be free of this warning; existing recipes are held at a baseline.
|
|
832
|
+
assert: >
|
|
833
|
+
Every option and state a component declares SHOULD either affect its visual recipe or be
|
|
834
|
+
listed in the recipe's `notVisual` array. A `notVisual` name MUST be declared by the
|
|
835
|
+
component and SHOULD NOT also be used by the recipe.
|
|
836
|
+
message: "Option '{option}' of '{component}' does not affect the recipe; use it in a condition or list it in notVisual"
|
|
837
|
+
spec_ref: spec/component-visuals.md#validation
|
|
838
|
+
introduced_in: "1.0.0-draft"
|
|
839
|
+
|
|
840
|
+
- id: SPEC-067
|
|
841
|
+
name: visual-prefers-relationship
|
|
842
|
+
severity: warning
|
|
843
|
+
layer: 2
|
|
844
|
+
category: reference-integrity
|
|
845
|
+
note: >
|
|
846
|
+
Relationships carry the component scope and the design-token group label, so a recipe
|
|
847
|
+
binds through them by default. Use a `token` selector only when no relationship covers the
|
|
848
|
+
value.
|
|
849
|
+
assert: >
|
|
850
|
+
A `token` selector in a visual recipe SHOULD NOT bind a token that one of the component's
|
|
851
|
+
relationships already binds.
|
|
852
|
+
message: "Token selector {selector} is also bound by relationship {relationship}; bind it through the relationship"
|
|
853
|
+
spec_ref: spec/component-visuals.md#validation
|
|
854
|
+
introduced_in: "1.0.0-draft"
|
|
855
|
+
|
|
856
|
+
- id: SPEC-068
|
|
857
|
+
name: visual-literal-discouraged
|
|
858
|
+
severity: warning
|
|
859
|
+
layer: 2
|
|
860
|
+
category: tech-debt
|
|
861
|
+
note: >
|
|
862
|
+
Layout keywords (`direction`, `align`, `justify`), `transparent` and `none` colors, zero
|
|
863
|
+
widths and ratio radii (`relativeTo`) are fine as literals.
|
|
864
|
+
assert: >
|
|
865
|
+
A literal (`{"value": ...}`) in a visual recipe SHOULD NOT supply a color or a non-zero
|
|
866
|
+
size; a token or relationship describes it, or one should be added.
|
|
867
|
+
message: "Literal {value} for '{prop}' on part '{part}'; bind a token or relationship instead"
|
|
868
|
+
spec_ref: spec/component-visuals.md#validation
|
|
869
|
+
introduced_in: "1.0.0-draft"
|
|
870
|
+
|
|
871
|
+
- id: SPEC-069
|
|
872
|
+
name: visual-token-not-deprecated
|
|
873
|
+
severity: warning
|
|
874
|
+
layer: 2
|
|
875
|
+
category: reference-integrity
|
|
876
|
+
note: >
|
|
877
|
+
Extends SPEC-058, which checks relationship `$ref` values, to the bindings a recipe draws
|
|
878
|
+
with.
|
|
879
|
+
assert: >
|
|
880
|
+
A `token` or `relationship` selector in a visual recipe SHOULD NOT resolve only to
|
|
881
|
+
deprecated tokens (those with `lifecycle.deprecatedIn`).
|
|
882
|
+
message: "{selector} resolves only to deprecated tokens (for example '{token}', deprecated in {version})"
|
|
883
|
+
spec_ref: spec/component-visuals.md#validation
|
|
884
|
+
introduced_in: "1.0.0-draft"
|
|
885
|
+
|
|
886
|
+
- id: SPEC-070
|
|
887
|
+
name: visual-ring-names-agree
|
|
888
|
+
severity: warning
|
|
889
|
+
layer: 2
|
|
890
|
+
category: naming-consistency
|
|
891
|
+
note: >
|
|
892
|
+
A shared name lets tools, relationships and docs treat the focus ring alike across
|
|
893
|
+
components. The rule reports the disagreement, not which name wins.
|
|
894
|
+
assert: >
|
|
895
|
+
Visual recipes SHOULD give the focus ring part (`kind: "ring"`) the same name.
|
|
896
|
+
message: "Focus ring part is named '{name}' here but '{other}' in other recipes; recipes should name it alike"
|
|
897
|
+
spec_ref: spec/component-visuals.md#validation
|
|
898
|
+
introduced_in: "1.0.0-draft"
|
|
899
|
+
|
|
900
|
+
- id: SPEC-071
|
|
901
|
+
name: visual-relationship-contexts-used
|
|
902
|
+
severity: info
|
|
903
|
+
layer: 2
|
|
904
|
+
category: component
|
|
905
|
+
note: >
|
|
906
|
+
Unused contexts are not errors: relationships describe the component beyond its recipe.
|
|
907
|
+
The count shows how much of the component's token data a recipe still has to cover.
|
|
908
|
+
assert: >
|
|
909
|
+
A visual recipe reports how many of its component's relationship contexts the recipe
|
|
910
|
+
never binds.
|
|
911
|
+
message: "{n} of {total} relationship contexts of '{component}' have no binding in this recipe, for example {sample}"
|
|
912
|
+
spec_ref: spec/component-visuals.md#validation
|
|
913
|
+
introduced_in: "1.0.0-draft"
|
|
914
|
+
|
|
915
|
+
- id: SPEC-072
|
|
916
|
+
name: relationship-duplicate-ref-scale-counterpart
|
|
917
|
+
severity: warning
|
|
918
|
+
layer: 2
|
|
919
|
+
category: relationship
|
|
920
|
+
note: >
|
|
921
|
+
Typically a desktop and a mobile record where the second was copied without repointing it,
|
|
922
|
+
so the other scale's token is never reachable through the relationship. A repeated record
|
|
923
|
+
on a token with no scale counterpart is not reported.
|
|
924
|
+
assert: >
|
|
925
|
+
Two relationship records with the same scope, context and `$ref` SHOULD NOT both point at
|
|
926
|
+
a token that has a scale counterpart (the same name with another `scale` value).
|
|
927
|
+
message: "Relationship {scope} references {ref} twice, but the token has a {scale} counterpart ({counterpart}); point one record at it"
|
|
928
|
+
spec_ref: spec/relationship-format.md
|
|
929
|
+
introduced_in: "1.0.0-draft"
|
|
930
|
+
|
|
931
|
+
- id: SPEC-073
|
|
932
|
+
name: component-anatomy-reviewed
|
|
933
|
+
severity: info
|
|
934
|
+
layer: 2
|
|
935
|
+
category: component
|
|
936
|
+
note: >
|
|
937
|
+
One diagnostic for the whole dataset, so the gap stays visible without a line per
|
|
938
|
+
component. Never an error: anatomy is authored as recipes are built. A component with
|
|
939
|
+
anatomy and no `anatomyReview` counts as draft.
|
|
940
|
+
assert: >
|
|
941
|
+
A component that has relationship records SHOULD declare anatomy, and a component's
|
|
942
|
+
anatomy SHOULD have `anatomyReview.status` of `reviewed`.
|
|
943
|
+
message: "Components without reviewed anatomy: {n} with relationships but no anatomy ({names}); {m} with draft anatomy ({names})"
|
|
944
|
+
spec_ref: spec/anatomy-format.md#review-checklist
|
|
945
|
+
introduced_in: "1.0.0-draft"
|
|
946
|
+
|
|
947
|
+
- id: SPEC-074
|
|
948
|
+
name: anatomy-present-in-declared
|
|
949
|
+
severity: error
|
|
950
|
+
layer: 2
|
|
951
|
+
category: reference-integrity
|
|
952
|
+
note: >
|
|
953
|
+
The anatomy version of SPEC-054. State names are compared after normalization, so
|
|
954
|
+
`focus`, `key-focus` and `keyboard-focus` are one state. A part that lists `presentIn`
|
|
955
|
+
on a component that declares no states is also reported.
|
|
956
|
+
assert: >
|
|
957
|
+
Every entry of an anatomy part's `presentIn` MUST match a state declared on the same
|
|
958
|
+
component.
|
|
959
|
+
message: "Anatomy part '{part}' on component '{component}' is present in state '{state}', but it is not a declared state"
|
|
960
|
+
spec_ref: spec/anatomy-format.md#presentin
|
|
961
|
+
introduced_in: "1.0.0-draft"
|
|
962
|
+
|
|
963
|
+
- id: SPEC-075
|
|
964
|
+
name: visual-present-in-matches-anatomy
|
|
965
|
+
severity: error
|
|
966
|
+
layer: 2
|
|
967
|
+
category: component
|
|
968
|
+
note: >
|
|
969
|
+
Keeps a recipe's `visibleWhen.states` and the anatomy's `presentIn` from drifting. States
|
|
970
|
+
are compared after normalization. `visibleWhen.states` means every listed state, and
|
|
971
|
+
`presentIn` means any listed state, so a difference is an error only when neither side
|
|
972
|
+
lists more than one state; otherwise it is reported at info level.
|
|
973
|
+
assert: >
|
|
974
|
+
For a recipe part that is also an anatomy part, the recipe's `visibleWhen.states` MUST
|
|
975
|
+
equal the anatomy part's `presentIn`.
|
|
976
|
+
message: "Recipe part '{part}' of '{component}' is visible in {recipeStates}, but its anatomy presentIn lists {presentIn}"
|
|
977
|
+
spec_ref: spec/anatomy-format.md#presentin
|
|
978
|
+
introduced_in: "1.0.0-draft"
|
|
979
|
+
|
|
980
|
+
- id: SPEC-076
|
|
981
|
+
name: visual-bindings-resolve-on-platform
|
|
982
|
+
severity: warning
|
|
983
|
+
layer: 2
|
|
984
|
+
category: component
|
|
985
|
+
note: >
|
|
986
|
+
Runs only when a platform manifest is in scope (for example `design-data validate
|
|
987
|
+
--platform ios --visuals-path ...`). Renders each recipe on the foundation and with the
|
|
988
|
+
manifest's cascade applied, over every size, light and dark, desktop and mobile, each
|
|
989
|
+
interaction state and each option value, and reports the unresolved bindings that appear
|
|
990
|
+
only under the platform. A gap the foundation also has is not reported.
|
|
991
|
+
assert: >
|
|
992
|
+
Every token or relationship binding a visual recipe resolves on the foundation SHOULD also
|
|
993
|
+
resolve once the platform manifest's include, exclude, overrides and extensions are applied.
|
|
994
|
+
message: "Recipe for '{component}' binds something that resolves on the foundation but not under platform '{platform}': {binding}"
|
|
995
|
+
spec_ref: spec/manifest.md
|
|
996
|
+
introduced_in: "1.0.0-draft"
|
|
997
|
+
|
|
998
|
+
# SPEC-077 (artifact-single-owner) and SPEC-078 (promoted-mode-fallback) are reserved by
|
|
999
|
+
# spec/artifact-moves.md and are not in this catalog until they are implemented.
|
|
1000
|
+
|
|
1001
|
+
- id: SPEC-079
|
|
1002
|
+
name: platform-recipe-resolves
|
|
1003
|
+
severity: warning
|
|
1004
|
+
layer: 2
|
|
1005
|
+
category: component
|
|
1006
|
+
note: >
|
|
1007
|
+
Runs only when a platform manifest with `extensions/visuals/` is in scope. A warning for
|
|
1008
|
+
now; a follow-up promotes it to an error once this release is published (needs a changeset).
|
|
1009
|
+
Renders each platform-owned recipe over the request grid with no foundation comparison.
|
|
1010
|
+
The request grid is `light`/`dark` by `desktop`/`mobile`, as in SPEC-076. The CI guard
|
|
1011
|
+
`.github/scripts/validate-platform-recipes.mjs` fails on it even while it is a warning.
|
|
1012
|
+
assert: >
|
|
1013
|
+
A platform-owned visual recipe MUST render over the request grid without a scene
|
|
1014
|
+
diagnostic once the platform manifest is applied.
|
|
1015
|
+
message: "Platform recipe for '{component}' does not render under platform '{platform}': {diagnostic}"
|
|
1016
|
+
spec_ref: spec/component-visuals.md#platform-owned-recipes
|
|
1017
|
+
introduced_in: "1.0.0-draft"
|
|
1018
|
+
|
|
1019
|
+
- id: SPEC-080
|
|
1020
|
+
name: platform-recipe-replaces-foundation
|
|
1021
|
+
severity: info
|
|
1022
|
+
layer: 2
|
|
1023
|
+
category: component
|
|
1024
|
+
note: >
|
|
1025
|
+
Runs only when a platform manifest with `extensions/visuals/` is in scope. Shows a reviewer
|
|
1026
|
+
which foundation recipe a platform recipe replaced, so a copy that may drift is visible.
|
|
1027
|
+
assert: >
|
|
1028
|
+
A platform recipe that has the same component name as a foundation recipe replaces it
|
|
1029
|
+
for that platform; validation reports the pair.
|
|
1030
|
+
message: "Recipe for '{component}' in platform '{platform}' replaces the foundation recipe"
|
|
1031
|
+
spec_ref: spec/component-visuals.md#platform-owned-recipes
|
|
1032
|
+
introduced_in: "1.0.0-draft"
|
|
1033
|
+
|
|
1034
|
+
- id: SPEC-081
|
|
1035
|
+
name: component-alias-valid
|
|
1036
|
+
severity: error
|
|
1037
|
+
layer: 2
|
|
1038
|
+
category: reference-integrity
|
|
1039
|
+
note: >
|
|
1040
|
+
Runs only when a platform manifest is in scope. Reads the manifest's merged
|
|
1041
|
+
`extensions.components` names and the foundation component catalog.
|
|
1042
|
+
assert: >
|
|
1043
|
+
Each `componentAliases` key MUST be a foundation component, its target MUST be a component
|
|
1044
|
+
the platform declares in `extensions/components/`, aliases MUST NOT chain or form a cycle,
|
|
1045
|
+
and a key MUST NOT also be replaced by `extensions/components/<key>.json`.
|
|
1046
|
+
message: "Invalid component alias '{alias}' in platform '{platform}': {reason}"
|
|
1047
|
+
spec_ref: spec/manifest.md#componentaliases
|
|
1048
|
+
introduced_in: "1.0.0-draft"
|
|
1049
|
+
|
|
1050
|
+
- id: SPEC-082
|
|
1051
|
+
name: platform-manifest-applies
|
|
1052
|
+
severity: error
|
|
1053
|
+
layer: 2
|
|
1054
|
+
category: reference-integrity
|
|
1055
|
+
note: >
|
|
1056
|
+
Runs only when a platform manifest is in scope. SPEC-076, SPEC-079 and the platform recipe
|
|
1057
|
+
checks apply the manifest themselves and report nothing when it fails, so this rule is what
|
|
1058
|
+
makes a manifest that cannot apply (for example one that extends a mode set that was not
|
|
1059
|
+
loaded, as when `validate --platform` runs without `--mode-sets-path`) fail instead of look
|
|
1060
|
+
like a pass. The CI guard `.github/scripts/validate-platform-recipes.mjs` fails on it.
|
|
1061
|
+
assert: >
|
|
1062
|
+
A platform manifest MUST apply to the foundation graph.
|
|
1063
|
+
message: "Platform '{platform}' failed to apply, so the platform rules (SPEC-076, SPEC-079 and the platform recipe checks) did not run: {error}"
|
|
1064
|
+
spec_ref: spec/manifest.md#validation
|
|
1065
|
+
introduced_in: "1.0.0-draft"
|
|
1066
|
+
|
|
1067
|
+
- id: SPEC-083
|
|
1068
|
+
name: visual-props-read-by-renderer
|
|
1069
|
+
severity: warning
|
|
1070
|
+
layer: 2
|
|
1071
|
+
category: component
|
|
1072
|
+
note: >
|
|
1073
|
+
The recipe schema accepts props the renderer does not read (`direction`,
|
|
1074
|
+
`align`, `minWidth`, and others on a part kind that has no use for them). The renderer
|
|
1075
|
+
ignores them without a diagnostic. The list of read props is the renderer's own table,
|
|
1076
|
+
not a copy kept in the rule. A recipe binding an ignored prop looks complete and draws
|
|
1077
|
+
differently from what it says.
|
|
1078
|
+
assert: >
|
|
1079
|
+
Every prop in a recipe part's `props` MUST be one the renderer reads for that part: the
|
|
1080
|
+
root part, a part of its `kind`, or a part with a `placement`.
|
|
1081
|
+
message: "Part '{part}' ({role}) of '{component}' binds '{prop}', which the renderer does not read for that part"
|
|
1082
|
+
spec_ref: spec/component-visuals.md#validation
|
|
1083
|
+
introduced_in: "1.0.0-draft"
|
|
1084
|
+
|
|
1085
|
+
- id: SPEC-084
|
|
1086
|
+
name: ctr-uuid-required
|
|
1087
|
+
severity: error
|
|
1088
|
+
layer: 2
|
|
1089
|
+
category: reference-integrity
|
|
1090
|
+
note: >
|
|
1091
|
+
Changelogs, platform overrides and `$ref` all need a stable identity for a
|
|
1092
|
+
relationship. The schema requires `uuid` in `relationships/*.json`; this rule also
|
|
1093
|
+
covers records the schema does not see (a platform manifest's inline relationship
|
|
1094
|
+
adds). Uniqueness is SPEC-056.
|
|
1095
|
+
assert: >
|
|
1096
|
+
Every relationship record MUST have a `uuid`.
|
|
1097
|
+
message: "Relationship #{index} has no uuid (component '{component}', property '{property}')"
|
|
1098
|
+
spec_ref: spec/relationship-format.md#identity
|
|
1099
|
+
introduced_in: "1.0.0-draft"
|
|
@@ -21,6 +21,12 @@
|
|
|
21
21
|
"default": false,
|
|
22
22
|
"description": "Whether this part is always rendered regardless of component configuration."
|
|
23
23
|
},
|
|
24
|
+
"presentIn": {
|
|
25
|
+
"type": "array",
|
|
26
|
+
"items": { "type": "string" },
|
|
27
|
+
"uniqueItems": true,
|
|
28
|
+
"description": "Declared component states in which this part is present (for example focus for a focus indicator); drawn when any is active. Absent means the part can appear in any state. Not for state-dependent styling. Each entry should match a `states[].name` declared on the component (SPEC-074)."
|
|
29
|
+
},
|
|
24
30
|
"contains": {
|
|
25
31
|
"type": "array",
|
|
26
32
|
"items": {
|
|
@@ -41,5 +47,10 @@
|
|
|
41
47
|
"description": "Version lifecycle metadata for this anatomy part. Set lifecycle.deprecated to signal that tokens referencing this part should migrate."
|
|
42
48
|
}
|
|
43
49
|
},
|
|
50
|
+
"if": {
|
|
51
|
+
"required": ["required"],
|
|
52
|
+
"properties": { "required": { "const": true } }
|
|
53
|
+
},
|
|
54
|
+
"then": { "not": { "required": ["presentIn"] } },
|
|
44
55
|
"additionalProperties": false
|
|
45
56
|
}
|