@metaobjectsdev/metadata 0.9.0 → 0.11.0-rc.1
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/dist/attr-schema-validate.d.ts +1 -1
- package/dist/attr-schema-validate.d.ts.map +1 -1
- package/dist/attr-schema-validate.js +96 -11
- package/dist/attr-schema-validate.js.map +1 -1
- package/dist/constraint-merge.d.ts +18 -0
- package/dist/constraint-merge.d.ts.map +1 -0
- package/dist/constraint-merge.js +0 -0
- package/dist/constraint-merge.js.map +1 -0
- package/dist/constraint-validate.d.ts +6 -0
- package/dist/constraint-validate.d.ts.map +1 -0
- package/dist/constraint-validate.js +274 -0
- package/dist/constraint-validate.js.map +1 -0
- package/dist/core/attr/attr-constants.d.ts +13 -3
- package/dist/core/attr/attr-constants.d.ts.map +1 -1
- package/dist/core/attr/attr-constants.js +11 -2
- package/dist/core/attr/attr-constants.js.map +1 -1
- package/dist/core/attr/attr-definition.embedded.d.ts +3 -0
- package/dist/core/attr/attr-definition.embedded.d.ts.map +1 -0
- package/dist/core/attr/attr-definition.embedded.js +60 -0
- package/dist/core/attr/attr-definition.embedded.js.map +1 -0
- package/dist/core/documentation/doc-constants.d.ts +3 -2
- package/dist/core/documentation/doc-constants.d.ts.map +1 -1
- package/dist/core/documentation/doc-constants.js +3 -1
- package/dist/core/documentation/doc-constants.js.map +1 -1
- package/dist/core/documentation/doc-provider.d.ts.map +1 -1
- package/dist/core/documentation/doc-provider.js +6 -2
- package/dist/core/documentation/doc-provider.js.map +1 -1
- package/dist/core/documentation/documentation-definition.embedded.d.ts +3 -0
- package/dist/core/documentation/documentation-definition.embedded.d.ts.map +1 -0
- package/dist/core/documentation/documentation-definition.embedded.js +79 -0
- package/dist/core/documentation/documentation-definition.embedded.js.map +1 -0
- package/dist/core/field/field-constants.d.ts +7 -4
- package/dist/core/field/field-constants.d.ts.map +1 -1
- package/dist/core/field/field-constants.js +7 -7
- package/dist/core/field/field-constants.js.map +1 -1
- package/dist/core/field/field-definition.embedded.d.ts +3 -0
- package/dist/core/field/field-definition.embedded.d.ts.map +1 -0
- package/dist/core/field/field-definition.embedded.js +236 -0
- package/dist/core/field/field-definition.embedded.js.map +1 -0
- package/dist/core/field/meta-field.d.ts.map +1 -1
- package/dist/core/field/meta-field.js +7 -5
- package/dist/core/field/meta-field.js.map +1 -1
- package/dist/core/identity/identity-constants.d.ts.map +1 -1
- package/dist/core/identity/identity-constants.js +3 -0
- package/dist/core/identity/identity-constants.js.map +1 -1
- package/dist/core/identity/identity-definition.embedded.d.ts +3 -0
- package/dist/core/identity/identity-definition.embedded.d.ts.map +1 -0
- package/dist/core/identity/identity-definition.embedded.js +93 -0
- package/dist/core/identity/identity-definition.embedded.js.map +1 -0
- package/dist/core/identity/meta-identity.d.ts.map +1 -1
- package/dist/core/identity/meta-identity.js +8 -1
- package/dist/core/identity/meta-identity.js.map +1 -1
- package/dist/core/identity/validate-identity-passthrough.d.ts +42 -0
- package/dist/core/identity/validate-identity-passthrough.d.ts.map +1 -0
- package/dist/core/identity/validate-identity-passthrough.js +158 -0
- package/dist/core/identity/validate-identity-passthrough.js.map +1 -0
- package/dist/core/object/object-constants.d.ts +2 -1
- package/dist/core/object/object-constants.d.ts.map +1 -1
- package/dist/core/object/object-constants.js +3 -0
- package/dist/core/object/object-constants.js.map +1 -1
- package/dist/core/object/object-definition.embedded.d.ts +3 -0
- package/dist/core/object/object-definition.embedded.d.ts.map +1 -0
- package/dist/core/object/object-definition.embedded.js +110 -0
- package/dist/core/object/object-definition.embedded.js.map +1 -0
- package/dist/core/object/validate-discriminator.d.ts.map +1 -1
- package/dist/core/object/validate-discriminator.js +1 -3
- package/dist/core/object/validate-discriminator.js.map +1 -1
- package/dist/core/query/query-constants.d.ts.map +1 -1
- package/dist/core/query/query-constants.js +5 -3
- package/dist/core/query/query-constants.js.map +1 -1
- package/dist/core/relationship/derive-m2m-fields.d.ts +26 -0
- package/dist/core/relationship/derive-m2m-fields.d.ts.map +1 -0
- package/dist/core/relationship/derive-m2m-fields.js +102 -0
- package/dist/core/relationship/derive-m2m-fields.js.map +1 -0
- package/dist/core/relationship/meta-relationship.d.ts +6 -4
- package/dist/core/relationship/meta-relationship.d.ts.map +1 -1
- package/dist/core/relationship/meta-relationship.js +12 -8
- package/dist/core/relationship/meta-relationship.js.map +1 -1
- package/dist/core/relationship/relationship-constants.d.ts +6 -2
- package/dist/core/relationship/relationship-constants.d.ts.map +1 -1
- package/dist/core/relationship/relationship-constants.js +6 -2
- package/dist/core/relationship/relationship-constants.js.map +1 -1
- package/dist/core/relationship/relationship-definition.embedded.d.ts +3 -0
- package/dist/core/relationship/relationship-definition.embedded.d.ts.map +1 -0
- package/dist/core/relationship/relationship-definition.embedded.js +310 -0
- package/dist/core/relationship/relationship-definition.embedded.js.map +1 -0
- package/dist/core/validator/validator-constants.d.ts +14 -1
- package/dist/core/validator/validator-constants.d.ts.map +1 -1
- package/dist/core/validator/validator-constants.js +20 -1
- package/dist/core/validator/validator-constants.js.map +1 -1
- package/dist/core/validator/validator-definition.embedded.d.ts +3 -0
- package/dist/core/validator/validator-definition.embedded.d.ts.map +1 -0
- package/dist/core/validator/validator-definition.embedded.js +255 -0
- package/dist/core/validator/validator-definition.embedded.js.map +1 -0
- package/dist/core/yaml-desugar.d.ts.map +1 -1
- package/dist/core/yaml-desugar.js +88 -10
- package/dist/core/yaml-desugar.js.map +1 -1
- package/dist/core-types.d.ts +5 -2
- package/dist/core-types.d.ts.map +1 -1
- package/dist/core-types.js +285 -116
- package/dist/core-types.js.map +1 -1
- package/dist/errors.d.ts +3 -3
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +87 -0
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +17 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +26 -1
- package/dist/index.js.map +1 -1
- package/dist/library/embedded-library.generated.d.ts +2 -0
- package/dist/library/embedded-library.generated.d.ts.map +1 -0
- package/dist/library/embedded-library.generated.js +11 -0
- package/dist/library/embedded-library.generated.js.map +1 -0
- package/dist/library/library-sources.d.ts +12 -0
- package/dist/library/library-sources.d.ts.map +1 -0
- package/dist/library/library-sources.js +88 -0
- package/dist/library/library-sources.js.map +1 -0
- package/dist/loader/meta-data-loader.d.ts +10 -2
- package/dist/loader/meta-data-loader.d.ts.map +1 -1
- package/dist/loader/meta-data-loader.js +57 -6
- package/dist/loader/meta-data-loader.js.map +1 -1
- package/dist/loader/shortcuts.d.ts +2 -5
- package/dist/loader/shortcuts.d.ts.map +1 -1
- package/dist/loader/shortcuts.js.map +1 -1
- package/dist/loader/validation-passes.d.ts +3 -0
- package/dist/loader/validation-passes.d.ts.map +1 -1
- package/dist/loader/validation-passes.js +519 -34
- package/dist/loader/validation-passes.js.map +1 -1
- package/dist/loader/validation-registry.d.ts +10 -0
- package/dist/loader/validation-registry.d.ts.map +1 -0
- package/dist/loader/validation-registry.js +84 -0
- package/dist/loader/validation-registry.js.map +1 -0
- package/dist/metamodel-docs/index.d.ts +19 -0
- package/dist/metamodel-docs/index.d.ts.map +1 -0
- package/dist/metamodel-docs/index.js +37 -0
- package/dist/metamodel-docs/index.js.map +1 -0
- package/dist/metamodel-docs/provenance.d.ts +42 -0
- package/dist/metamodel-docs/provenance.d.ts.map +1 -0
- package/dist/metamodel-docs/provenance.js +148 -0
- package/dist/metamodel-docs/provenance.js.map +1 -0
- package/dist/metamodel-docs/provider-definitions.d.ts +8 -0
- package/dist/metamodel-docs/provider-definitions.d.ts.map +1 -0
- package/dist/metamodel-docs/provider-definitions.js +48 -0
- package/dist/metamodel-docs/provider-definitions.js.map +1 -0
- package/dist/metamodel-docs/render.d.ts +12 -0
- package/dist/metamodel-docs/render.d.ts.map +1 -0
- package/dist/metamodel-docs/render.js +252 -0
- package/dist/metamodel-docs/render.js.map +1 -0
- package/dist/naming-refs.d.ts +41 -0
- package/dist/naming-refs.d.ts.map +1 -0
- package/dist/naming-refs.js +144 -0
- package/dist/naming-refs.js.map +1 -0
- package/dist/naming.d.ts.map +1 -1
- package/dist/naming.js +10 -2
- package/dist/naming.js.map +1 -1
- package/dist/parser-core.d.ts.map +1 -1
- package/dist/parser-core.js +84 -9
- package/dist/parser-core.js.map +1 -1
- package/dist/persistence/db/db-constants.d.ts +10 -0
- package/dist/persistence/db/db-constants.d.ts.map +1 -1
- package/dist/persistence/db/db-constants.js +14 -0
- package/dist/persistence/db/db-constants.js.map +1 -1
- package/dist/persistence/db/db-definition.embedded.d.ts +3 -0
- package/dist/persistence/db/db-definition.embedded.d.ts.map +1 -0
- package/dist/persistence/db/db-definition.embedded.js +227 -0
- package/dist/persistence/db/db-definition.embedded.js.map +1 -0
- package/dist/persistence/db/db-provider.d.ts.map +1 -1
- package/dist/persistence/db/db-provider.js +13 -18
- package/dist/persistence/db/db-provider.js.map +1 -1
- package/dist/persistence/origin/origin-definition.embedded.d.ts +3 -0
- package/dist/persistence/origin/origin-definition.embedded.d.ts.map +1 -0
- package/dist/persistence/origin/origin-definition.embedded.js +88 -0
- package/dist/persistence/origin/origin-definition.embedded.js.map +1 -0
- package/dist/persistence/source/source-definition.embedded.d.ts +3 -0
- package/dist/persistence/source/source-definition.embedded.d.ts.map +1 -0
- package/dist/persistence/source/source-definition.embedded.js +17 -0
- package/dist/persistence/source/source-definition.embedded.js.map +1 -0
- package/dist/persistence/source/validate-source-parameter-ref.d.ts.map +1 -1
- package/dist/persistence/source/validate-source-parameter-ref.js +7 -1
- package/dist/persistence/source/validate-source-parameter-ref.js.map +1 -1
- package/dist/persistence/source/validate-source-roles.d.ts.map +1 -1
- package/dist/persistence/source/validate-source-roles.js +16 -1
- package/dist/persistence/source/validate-source-roles.js.map +1 -1
- package/dist/presentation/layout/layout-definition.embedded.d.ts +3 -0
- package/dist/presentation/layout/layout-definition.embedded.d.ts.map +1 -0
- package/dist/presentation/layout/layout-definition.embedded.js +16 -0
- package/dist/presentation/layout/layout-definition.embedded.js.map +1 -0
- package/dist/presentation/ui/ui-definition.embedded.d.ts +3 -0
- package/dist/presentation/ui/ui-definition.embedded.d.ts.map +1 -0
- package/dist/presentation/ui/ui-definition.embedded.js +114 -0
- package/dist/presentation/ui/ui-definition.embedded.js.map +1 -0
- package/dist/presentation/ui/ui-provider.d.ts +3 -0
- package/dist/presentation/ui/ui-provider.d.ts.map +1 -0
- package/dist/presentation/ui/ui-provider.js +21 -0
- package/dist/presentation/ui/ui-provider.js.map +1 -0
- package/dist/presentation/view/view-definition.embedded.d.ts +3 -0
- package/dist/presentation/view/view-definition.embedded.d.ts.map +1 -0
- package/dist/presentation/view/view-definition.embedded.js +76 -0
- package/dist/presentation/view/view-definition.embedded.js.map +1 -0
- package/dist/provider-data.d.ts +184 -0
- package/dist/provider-data.d.ts.map +1 -0
- package/dist/provider-data.js +271 -0
- package/dist/provider-data.js.map +1 -0
- package/dist/provider.d.ts +3 -1
- package/dist/provider.d.ts.map +1 -1
- package/dist/provider.js +15 -1
- package/dist/provider.js.map +1 -1
- package/dist/registry-coverage.d.ts +99 -0
- package/dist/registry-coverage.d.ts.map +1 -0
- package/dist/registry-coverage.js +294 -0
- package/dist/registry-coverage.js.map +1 -0
- package/dist/registry-manifest-exclusions.d.ts +62 -0
- package/dist/registry-manifest-exclusions.d.ts.map +1 -0
- package/dist/registry-manifest-exclusions.js +163 -0
- package/dist/registry-manifest-exclusions.js.map +1 -0
- package/dist/registry-manifest.d.ts +117 -0
- package/dist/registry-manifest.d.ts.map +1 -0
- package/dist/registry-manifest.js +242 -0
- package/dist/registry-manifest.js.map +1 -0
- package/dist/registry.d.ts +76 -2
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +37 -1
- package/dist/registry.js.map +1 -1
- package/dist/shared/structural.d.ts +7 -0
- package/dist/shared/structural.d.ts.map +1 -1
- package/dist/shared/structural.js +7 -0
- package/dist/shared/structural.js.map +1 -1
- package/dist/subtype-rules.d.ts.map +1 -1
- package/dist/subtype-rules.js +97 -13
- package/dist/subtype-rules.js.map +1 -1
- package/dist/super-resolve.d.ts +49 -2
- package/dist/super-resolve.d.ts.map +1 -1
- package/dist/super-resolve.js +128 -43
- package/dist/super-resolve.js.map +1 -1
- package/dist/template/meta-template.d.ts +3 -2
- package/dist/template/meta-template.d.ts.map +1 -1
- package/dist/template/meta-template.js +3 -2
- package/dist/template/meta-template.js.map +1 -1
- package/dist/template/prompt-definition.embedded.d.ts +3 -0
- package/dist/template/prompt-definition.embedded.d.ts.map +1 -0
- package/dist/template/prompt-definition.embedded.js +368 -0
- package/dist/template/prompt-definition.embedded.js.map +1 -0
- package/dist/template/prompt-provider.d.ts +3 -0
- package/dist/template/prompt-provider.d.ts.map +1 -0
- package/dist/template/prompt-provider.js +25 -0
- package/dist/template/prompt-provider.js.map +1 -0
- package/dist/template/template-constants.d.ts +2 -0
- package/dist/template/template-constants.d.ts.map +1 -1
- package/dist/template/template-constants.js +7 -0
- package/dist/template/template-constants.js.map +1 -1
- package/dist/template/template-definition.embedded.d.ts +3 -0
- package/dist/template/template-definition.embedded.d.ts.map +1 -0
- package/dist/template/template-definition.embedded.js +30 -0
- package/dist/template/template-definition.embedded.js.map +1 -0
- package/dist/validate-max-occurs.d.ts +5 -0
- package/dist/validate-max-occurs.d.ts.map +1 -0
- package/dist/validate-max-occurs.js +28 -0
- package/dist/validate-max-occurs.js.map +1 -0
- package/dist/validation-types.d.ts +36 -0
- package/dist/validation-types.d.ts.map +1 -0
- package/dist/validation-types.js +7 -0
- package/dist/validation-types.js.map +1 -0
- package/package.json +33 -22
- package/src/attr-schema-validate.ts +108 -8
- package/src/constraint-merge.ts +0 -0
- package/src/constraint-validate.ts +363 -0
- package/src/core/attr/attr-constants.ts +15 -3
- package/src/core/attr/attr-definition.embedded.ts +67 -0
- package/src/core/documentation/doc-constants.ts +3 -1
- package/src/core/documentation/doc-provider.ts +6 -2
- package/src/core/documentation/documentation-definition.embedded.ts +86 -0
- package/src/core/field/field-constants.ts +8 -7
- package/src/core/field/field-definition.embedded.ts +243 -0
- package/src/core/field/meta-field.ts +6 -7
- package/src/core/identity/identity-constants.ts +4 -0
- package/src/core/identity/identity-definition.embedded.ts +100 -0
- package/src/core/identity/meta-identity.ts +8 -1
- package/src/core/identity/validate-identity-passthrough.ts +194 -0
- package/src/core/object/object-constants.ts +3 -0
- package/src/core/object/object-definition.embedded.ts +117 -0
- package/src/core/object/validate-discriminator.ts +0 -4
- package/src/core/query/query-constants.ts +5 -3
- package/src/core/relationship/derive-m2m-fields.ts +145 -0
- package/src/core/relationship/meta-relationship.ts +15 -9
- package/src/core/relationship/relationship-constants.ts +6 -2
- package/src/core/relationship/relationship-definition.embedded.ts +317 -0
- package/src/core/validator/validator-constants.ts +22 -1
- package/src/core/validator/validator-definition.embedded.ts +262 -0
- package/src/core/yaml-desugar.ts +96 -7
- package/src/core-types.ts +314 -150
- package/src/errors.ts +89 -2
- package/src/index.ts +47 -2
- package/src/library/embedded-library.generated.ts +10 -0
- package/src/library/library-sources.ts +97 -0
- package/src/loader/meta-data-loader.ts +78 -7
- package/src/loader/shortcuts.ts +2 -2
- package/src/loader/validation-passes.ts +690 -34
- package/src/loader/validation-registry.ts +93 -0
- package/src/metamodel-docs/index.ts +41 -0
- package/src/metamodel-docs/provenance.ts +187 -0
- package/src/metamodel-docs/provider-definitions.ts +50 -0
- package/src/metamodel-docs/render.ts +309 -0
- package/src/naming-refs.ts +162 -0
- package/src/naming.ts +10 -2
- package/src/parser-core.ts +96 -9
- package/src/persistence/db/db-constants.ts +16 -0
- package/src/persistence/db/db-definition.embedded.ts +234 -0
- package/src/persistence/db/db-provider.ts +13 -18
- package/src/persistence/origin/origin-definition.embedded.ts +95 -0
- package/src/persistence/source/source-definition.embedded.ts +24 -0
- package/src/persistence/source/validate-source-parameter-ref.ts +7 -1
- package/src/persistence/source/validate-source-roles.ts +22 -1
- package/src/presentation/layout/layout-definition.embedded.ts +23 -0
- package/src/presentation/ui/ui-definition.embedded.ts +121 -0
- package/src/presentation/ui/ui-provider.ts +25 -0
- package/src/presentation/view/view-definition.embedded.ts +83 -0
- package/src/provider-data.ts +463 -0
- package/src/provider.ts +18 -0
- package/src/registry-coverage.ts +430 -0
- package/src/registry-manifest-exclusions.ts +176 -0
- package/src/registry-manifest.ts +334 -0
- package/src/registry.ts +106 -3
- package/src/shared/structural.ts +8 -0
- package/src/subtype-rules.ts +135 -18
- package/src/super-resolve.ts +153 -43
- package/src/template/meta-template.ts +3 -2
- package/src/template/prompt-definition.embedded.ts +375 -0
- package/src/template/prompt-provider.ts +29 -0
- package/src/template/template-constants.ts +8 -0
- package/src/template/template-definition.embedded.ts +37 -0
- package/src/validate-max-occurs.ts +39 -0
- package/src/validation-types.ts +57 -0
- package/dist/core/documentation/doc-schema.d.ts +0 -8
- package/dist/core/documentation/doc-schema.d.ts.map +0 -1
- package/dist/core/documentation/doc-schema.js +0 -53
- package/dist/core/documentation/doc-schema.js.map +0 -1
- package/dist/core/field/field-schema.d.ts +0 -22
- package/dist/core/field/field-schema.d.ts.map +0 -1
- package/dist/core/field/field-schema.js +0 -171
- package/dist/core/field/field-schema.js.map +0 -1
- package/dist/core/identity/identity-schema.d.ts +0 -6
- package/dist/core/identity/identity-schema.d.ts.map +0 -1
- package/dist/core/identity/identity-schema.js +0 -55
- package/dist/core/identity/identity-schema.js.map +0 -1
- package/dist/core/object/object-schema.d.ts +0 -4
- package/dist/core/object/object-schema.d.ts.map +0 -1
- package/dist/core/object/object-schema.js +0 -28
- package/dist/core/object/object-schema.js.map +0 -1
- package/dist/core/relationship/relationship-schema.d.ts +0 -4
- package/dist/core/relationship/relationship-schema.d.ts.map +0 -1
- package/dist/core/relationship/relationship-schema.js +0 -51
- package/dist/core/relationship/relationship-schema.js.map +0 -1
- package/dist/core/validator/validator-schema.d.ts +0 -4
- package/dist/core/validator/validator-schema.d.ts.map +0 -1
- package/dist/core/validator/validator-schema.js +0 -38
- package/dist/core/validator/validator-schema.js.map +0 -1
- package/dist/persistence/db/db-schema.d.ts +0 -14
- package/dist/persistence/db/db-schema.d.ts.map +0 -1
- package/dist/persistence/db/db-schema.js +0 -35
- package/dist/persistence/db/db-schema.js.map +0 -1
- package/dist/persistence/origin/origin-schema.d.ts +0 -4
- package/dist/persistence/origin/origin-schema.d.ts.map +0 -1
- package/dist/persistence/origin/origin-schema.js +0 -59
- package/dist/persistence/origin/origin-schema.js.map +0 -1
- package/dist/persistence/source/source-schema.d.ts +0 -4
- package/dist/persistence/source/source-schema.d.ts.map +0 -1
- package/dist/persistence/source/source-schema.js +0 -98
- package/dist/persistence/source/source-schema.js.map +0 -1
- package/dist/presentation/layout/layout-schema.d.ts +0 -4
- package/dist/presentation/layout/layout-schema.d.ts.map +0 -1
- package/dist/presentation/layout/layout-schema.js +0 -46
- package/dist/presentation/layout/layout-schema.js.map +0 -1
- package/dist/presentation/view/view-schema.d.ts +0 -4
- package/dist/presentation/view/view-schema.d.ts.map +0 -1
- package/dist/presentation/view/view-schema.js +0 -15
- package/dist/presentation/view/view-schema.js.map +0 -1
- package/dist/template/template-schema.d.ts +0 -3
- package/dist/template/template-schema.d.ts.map +0 -1
- package/dist/template/template-schema.js +0 -173
- package/dist/template/template-schema.js.map +0 -1
- package/src/core/documentation/doc-schema.ts +0 -64
- package/src/core/field/field-schema.ts +0 -228
- package/src/core/identity/identity-schema.ts +0 -80
- package/src/core/object/object-schema.ts +0 -35
- package/src/core/relationship/relationship-schema.ts +0 -67
- package/src/core/validator/validator-schema.ts +0 -50
- package/src/persistence/db/db-schema.ts +0 -50
- package/src/persistence/origin/origin-schema.ts +0 -80
- package/src/persistence/source/source-schema.ts +0 -129
- package/src/presentation/layout/layout-schema.ts +0 -62
- package/src/presentation/view/view-schema.ts +0 -21
- package/src/template/template-schema.ts +0 -211
|
@@ -0,0 +1,430 @@
|
|
|
1
|
+
// SP-G Unit 5 — untested-vocabulary coverage report.
|
|
2
|
+
//
|
|
3
|
+
// Cross-references the REGISTERED metamodel vocabulary (the canonical
|
|
4
|
+
// registry-conformance manifest — "what SHOULD be exercised") against the
|
|
5
|
+
// conformance FIXTURE corpora ("what IS exercised"), and surfaces every
|
|
6
|
+
// registered (type, subType) — and each attr — that NO fixture exercises.
|
|
7
|
+
//
|
|
8
|
+
// This closes the meta-gap that let SP-C's vocabulary drift hide for weeks: a
|
|
9
|
+
// drifted/missing vocabulary member was only caught incidentally, if some
|
|
10
|
+
// fixture happened to use it. Making the *untested* set VISIBLE is the
|
|
11
|
+
// deliverable. The registry-conformance gate (Unit 1) proves the vocabulary is
|
|
12
|
+
// IDENTICAL across ports; this report proves the vocabulary is EXERCISED at all.
|
|
13
|
+
//
|
|
14
|
+
// Pure + testable: takes the parsed manifest + a set of fixture roots, walks the
|
|
15
|
+
// canonical-JSON node graph (nodes keyed `"<type>.<subType>"`, `@attr` inline
|
|
16
|
+
// keys, reserved bare keys, nested `children`), and returns the registered /
|
|
17
|
+
// exercised / untested sets — all deterministic + sorted.
|
|
18
|
+
|
|
19
|
+
import { readdirSync, readFileSync, statSync } from "node:fs";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import {
|
|
22
|
+
ATTR_PREFIX,
|
|
23
|
+
RESERVED_KEYS,
|
|
24
|
+
TYPE_SUBTYPE_SEPARATOR,
|
|
25
|
+
} from "./shared/structural.js";
|
|
26
|
+
|
|
27
|
+
// ---------------------------------------------------------------------------
|
|
28
|
+
// Manifest shape (a structural subset of fixtures/registry-conformance schema)
|
|
29
|
+
// ---------------------------------------------------------------------------
|
|
30
|
+
|
|
31
|
+
/** One attr in the registry manifest. */
|
|
32
|
+
export interface ManifestAttr {
|
|
33
|
+
name: string;
|
|
34
|
+
valueType: string | null;
|
|
35
|
+
required: boolean;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** One registered (type, subType) with its declared attrs. */
|
|
39
|
+
export interface ManifestType {
|
|
40
|
+
type: string;
|
|
41
|
+
subType: string;
|
|
42
|
+
attrs: ManifestAttr[];
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** The canonical registry manifest (expected-registry.json). */
|
|
46
|
+
export interface RegistryManifest {
|
|
47
|
+
types: ManifestType[];
|
|
48
|
+
commonAttrs: ManifestAttr[];
|
|
49
|
+
defaultSubTypes: Record<string, string>;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
// Coverage result
|
|
54
|
+
// ---------------------------------------------------------------------------
|
|
55
|
+
|
|
56
|
+
/** Per-subtype attr coverage: which declared attrs no fixture sets. */
|
|
57
|
+
export interface UntestedAttrs {
|
|
58
|
+
/** The `"<type>.<subType>"` key. */
|
|
59
|
+
key: string;
|
|
60
|
+
/** Sorted attr names declared on this subtype that NO fixture exercises. */
|
|
61
|
+
untestedAttrs: string[];
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/** The full coverage report — all collections sorted for determinism. */
|
|
65
|
+
export interface CoverageReport {
|
|
66
|
+
/** Total registered `(type, subType)` keys. */
|
|
67
|
+
registeredSubTypeCount: number;
|
|
68
|
+
/** Registered keys at least one fixture exercises. */
|
|
69
|
+
exercisedSubTypeCount: number;
|
|
70
|
+
/** Sorted registered keys NO fixture exercises (the valuable backlog). */
|
|
71
|
+
untestedSubTypes: string[];
|
|
72
|
+
/**
|
|
73
|
+
* Per EXERCISED subtype, the declared attrs no fixture sets. Only includes
|
|
74
|
+
* subtypes that ARE exercised (an untested subtype's attrs are all untested
|
|
75
|
+
* by definition — listing them would be noise). Sorted by key; only entries
|
|
76
|
+
* with a non-empty `untestedAttrs` list are included.
|
|
77
|
+
*/
|
|
78
|
+
untestedAttrsByExercisedSubType: UntestedAttrs[];
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** The snapshot written to disk — a stable, diffable subset of the report. */
|
|
82
|
+
export interface CoverageSnapshot {
|
|
83
|
+
registeredSubTypeCount: number;
|
|
84
|
+
exercisedSubTypeCount: number;
|
|
85
|
+
untestedSubTypes: string[];
|
|
86
|
+
untestedAttrsByExercisedSubType: UntestedAttrs[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ---------------------------------------------------------------------------
|
|
90
|
+
// Fixture-corpus scanning
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
|
|
93
|
+
/** What a single fixture corpus exercises. */
|
|
94
|
+
interface Usage {
|
|
95
|
+
/** Set of `"<type>.<subType>"` keys seen in any fixture node. */
|
|
96
|
+
subTypes: Set<string>;
|
|
97
|
+
/** key → set of attr names (sans `@` prefix) set on a node of that subtype. */
|
|
98
|
+
attrsByKey: Map<string, Set<string>>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function newUsage(): Usage {
|
|
102
|
+
return { subTypes: new Set<string>(), attrsByKey: new Map<string, Set<string>>() };
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/** Recursively collect every *.json file path under a directory root. */
|
|
106
|
+
function collectJsonFiles(root: string): string[] {
|
|
107
|
+
const out: string[] = [];
|
|
108
|
+
const walk = (dir: string): void => {
|
|
109
|
+
let entries: string[];
|
|
110
|
+
try {
|
|
111
|
+
entries = readdirSync(dir);
|
|
112
|
+
} catch {
|
|
113
|
+
return; // missing/unreadable dir — skip (a corpus root may not exist)
|
|
114
|
+
}
|
|
115
|
+
for (const entry of entries) {
|
|
116
|
+
const full = join(dir, entry);
|
|
117
|
+
let st: ReturnType<typeof statSync>;
|
|
118
|
+
try {
|
|
119
|
+
st = statSync(full);
|
|
120
|
+
} catch {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
if (st.isDirectory()) {
|
|
124
|
+
walk(full);
|
|
125
|
+
} else if (st.isFile() && entry.endsWith(".json")) {
|
|
126
|
+
out.push(full);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
walk(root);
|
|
131
|
+
return out;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/** True if a node-body key is a `"<type>.<subType>"` wrapper key. */
|
|
135
|
+
function isTypeSubTypeKey(key: string): boolean {
|
|
136
|
+
// A wrapper key fuses type + subType with the separator. Reserved structural
|
|
137
|
+
// keys, `@`-attrs, and the JSON `$schema` key are NOT wrapper keys.
|
|
138
|
+
if (key.startsWith(ATTR_PREFIX)) return false;
|
|
139
|
+
if (RESERVED_KEYS.has(key)) return false;
|
|
140
|
+
if (!key.includes(TYPE_SUBTYPE_SEPARATOR)) return false;
|
|
141
|
+
if (key.startsWith("$")) return false;
|
|
142
|
+
// Must be exactly `type.subType` (one separator, two non-empty halves).
|
|
143
|
+
const idx = key.indexOf(TYPE_SUBTYPE_SEPARATOR);
|
|
144
|
+
const type = key.slice(0, idx);
|
|
145
|
+
const subType = key.slice(idx + TYPE_SUBTYPE_SEPARATOR.length);
|
|
146
|
+
return type.length > 0 && subType.length > 0 && !subType.includes(TYPE_SUBTYPE_SEPARATOR);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Record one node-body: its inline `@attrs` (against the owning wrapper key) and
|
|
151
|
+
* recurse into its children. `body` is the object under a wrapper key.
|
|
152
|
+
*/
|
|
153
|
+
function visitBody(body: unknown, ownerKey: string, usage: Usage): void {
|
|
154
|
+
if (body === null || typeof body !== "object" || Array.isArray(body)) return;
|
|
155
|
+
const obj = body as Record<string, unknown>;
|
|
156
|
+
|
|
157
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
158
|
+
if (k.startsWith(ATTR_PREFIX)) {
|
|
159
|
+
// An inline attr on this node. Strip the prefix → the logical attr name.
|
|
160
|
+
const attrName = k.slice(ATTR_PREFIX.length);
|
|
161
|
+
let set = usage.attrsByKey.get(ownerKey);
|
|
162
|
+
if (!set) {
|
|
163
|
+
set = new Set<string>();
|
|
164
|
+
usage.attrsByKey.set(ownerKey, set);
|
|
165
|
+
}
|
|
166
|
+
set.add(attrName);
|
|
167
|
+
} else if (k === "children") {
|
|
168
|
+
visitNodeList(v, usage);
|
|
169
|
+
}
|
|
170
|
+
// Reserved bare keys (name/package/extends/value/...) are not attrs — skip.
|
|
171
|
+
// (`value` may hold nested arbitrary data, not metamodel nodes — skip it.)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/** Visit an array of wrapper-keyed nodes (the `children` list, or a root list). */
|
|
176
|
+
function visitNodeList(list: unknown, usage: Usage): void {
|
|
177
|
+
if (!Array.isArray(list)) return;
|
|
178
|
+
for (const item of list) {
|
|
179
|
+
visitNode(item, usage);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Visit one wrapper-keyed node object: `{ "<type>.<subType>": { ...body } }`.
|
|
185
|
+
* A single object may carry multiple wrapper keys; handle each.
|
|
186
|
+
*/
|
|
187
|
+
function visitNode(node: unknown, usage: Usage): void {
|
|
188
|
+
if (node === null || typeof node !== "object" || Array.isArray(node)) return;
|
|
189
|
+
const obj = node as Record<string, unknown>;
|
|
190
|
+
for (const [key, body] of Object.entries(obj)) {
|
|
191
|
+
if (isTypeSubTypeKey(key)) {
|
|
192
|
+
usage.subTypes.add(key);
|
|
193
|
+
visitBody(body, key, usage);
|
|
194
|
+
} else if (key === "children") {
|
|
195
|
+
// Some corpora nest a bare `children` list at a level without a wrapper.
|
|
196
|
+
visitNodeList(body, usage);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
/**
|
|
202
|
+
* Parse one fixture JSON document and fold its vocabulary usage into `usage`.
|
|
203
|
+
* The document root is the metadata.root wrapper (or, defensively, an array or
|
|
204
|
+
* a bare node). Robust to non-metadata JSON (e.g. CAPABILITIES.json) — such a
|
|
205
|
+
* doc simply contributes no wrapper keys.
|
|
206
|
+
*/
|
|
207
|
+
function scanDocument(text: string, usage: Usage): void {
|
|
208
|
+
let parsed: unknown;
|
|
209
|
+
try {
|
|
210
|
+
parsed = JSON.parse(text);
|
|
211
|
+
} catch {
|
|
212
|
+
return; // not JSON / malformed — contributes nothing
|
|
213
|
+
}
|
|
214
|
+
if (Array.isArray(parsed)) {
|
|
215
|
+
visitNodeList(parsed, usage);
|
|
216
|
+
} else {
|
|
217
|
+
visitNode(parsed, usage);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/** Scan a set of corpus roots, unioning vocabulary usage across all of them. */
|
|
222
|
+
export function scanFixtureUsage(roots: readonly string[]): Usage {
|
|
223
|
+
const usage = newUsage();
|
|
224
|
+
for (const root of roots) {
|
|
225
|
+
for (const file of collectJsonFiles(root)) {
|
|
226
|
+
let text: string;
|
|
227
|
+
try {
|
|
228
|
+
text = readFileSync(file, "utf8");
|
|
229
|
+
} catch {
|
|
230
|
+
continue;
|
|
231
|
+
}
|
|
232
|
+
scanDocument(text, usage);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
return usage;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// Coverage computation
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
function compareStrings(a: string, b: string): number {
|
|
243
|
+
return a < b ? -1 : a > b ? 1 : 0;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Compute the untested-vocabulary coverage report.
|
|
248
|
+
*
|
|
249
|
+
* @param manifest the parsed registry manifest (the registered vocabulary)
|
|
250
|
+
* @param roots fixture-corpus directory roots to scan for usage
|
|
251
|
+
*/
|
|
252
|
+
export function computeCoverage(
|
|
253
|
+
manifest: RegistryManifest,
|
|
254
|
+
roots: readonly string[],
|
|
255
|
+
): CoverageReport {
|
|
256
|
+
const usage = scanFixtureUsage(roots);
|
|
257
|
+
|
|
258
|
+
const registeredKeys = manifest.types.map(
|
|
259
|
+
(t) => `${t.type}${TYPE_SUBTYPE_SEPARATOR}${t.subType}`,
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
const untestedSubTypes = registeredKeys
|
|
263
|
+
.filter((key) => !usage.subTypes.has(key))
|
|
264
|
+
.sort(compareStrings);
|
|
265
|
+
|
|
266
|
+
const exercisedSubTypeCount = registeredKeys.length - untestedSubTypes.length;
|
|
267
|
+
|
|
268
|
+
// Per EXERCISED subtype, which declared attrs no fixture sets.
|
|
269
|
+
const untestedAttrsByExercisedSubType: UntestedAttrs[] = [];
|
|
270
|
+
for (const t of manifest.types) {
|
|
271
|
+
const key = `${t.type}${TYPE_SUBTYPE_SEPARATOR}${t.subType}`;
|
|
272
|
+
if (!usage.subTypes.has(key)) continue; // skip untested subtypes (all-untested by definition)
|
|
273
|
+
if (t.attrs.length === 0) continue;
|
|
274
|
+
const seen = usage.attrsByKey.get(key) ?? new Set<string>();
|
|
275
|
+
const untestedAttrs = t.attrs
|
|
276
|
+
.map((a) => a.name)
|
|
277
|
+
.filter((name) => !seen.has(name))
|
|
278
|
+
.sort(compareStrings);
|
|
279
|
+
if (untestedAttrs.length > 0) {
|
|
280
|
+
untestedAttrsByExercisedSubType.push({ key, untestedAttrs });
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
untestedAttrsByExercisedSubType.sort((a, b) => compareStrings(a.key, b.key));
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
registeredSubTypeCount: registeredKeys.length,
|
|
287
|
+
exercisedSubTypeCount,
|
|
288
|
+
untestedSubTypes,
|
|
289
|
+
untestedAttrsByExercisedSubType,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/** Project a report into the stable, diffable snapshot shape. */
|
|
294
|
+
export function toSnapshot(report: CoverageReport): CoverageSnapshot {
|
|
295
|
+
return {
|
|
296
|
+
registeredSubTypeCount: report.registeredSubTypeCount,
|
|
297
|
+
exercisedSubTypeCount: report.exercisedSubTypeCount,
|
|
298
|
+
untestedSubTypes: report.untestedSubTypes,
|
|
299
|
+
untestedAttrsByExercisedSubType: report.untestedAttrsByExercisedSubType,
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/** Serialize a snapshot as byte-stable JSON (2-space indent, trailing newline). */
|
|
304
|
+
export function emitSnapshot(snapshot: CoverageSnapshot): string {
|
|
305
|
+
return `${JSON.stringify(snapshot, null, 2)}\n`;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// ---------------------------------------------------------------------------
|
|
309
|
+
// Monotonic ratchet (Wave 4a)
|
|
310
|
+
// ---------------------------------------------------------------------------
|
|
311
|
+
//
|
|
312
|
+
// The committed snapshot (coverage-report.json) is a BASELINE, not an exact
|
|
313
|
+
// expectation. The ratchet hard-fails only when coverage REGRESSES — never when
|
|
314
|
+
// it improves. Coverage regresses when a registered (type, subType) or an attr
|
|
315
|
+
// on an exercised subtype that the baseline considered EXERCISED becomes
|
|
316
|
+
// UNEXERCISED, i.e. a NEW item appears in an untested set that wasn't there
|
|
317
|
+
// before. Adding an exercising fixture (an item LEAVES an untested set) is an
|
|
318
|
+
// improvement and is always allowed.
|
|
319
|
+
//
|
|
320
|
+
// Comparison granularity is SET-based, not count-based: an integer-only check
|
|
321
|
+
// would let a regression hide behind a simultaneous improvement (untested count
|
|
322
|
+
// stays flat while one item is newly exercised and a different one regresses).
|
|
323
|
+
// We compare the untested SETS directly so each individual regression is named.
|
|
324
|
+
|
|
325
|
+
/** One named coverage regression — an item that became unexercised. */
|
|
326
|
+
export interface CoverageRegression {
|
|
327
|
+
/** "subtype" — a registered (type, subType) no longer exercised; or "attr". */
|
|
328
|
+
kind: "subtype" | "attr";
|
|
329
|
+
/** The `"<type>.<subType>"` key that regressed. */
|
|
330
|
+
key: string;
|
|
331
|
+
/** For an attr regression: the attr name that became untested (else undefined). */
|
|
332
|
+
attr?: string;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/** The ratchet verdict: ok=true when live coverage is no worse than baseline. */
|
|
336
|
+
export interface RatchetResult {
|
|
337
|
+
ok: boolean;
|
|
338
|
+
/** Every named regression (empty when ok). Sorted for determinism. */
|
|
339
|
+
regressions: CoverageRegression[];
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function sortedUnique(items: readonly string[]): string[] {
|
|
343
|
+
return [...new Set(items)].sort(compareStrings);
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Compare a live coverage snapshot against a committed baseline and report any
|
|
348
|
+
* REGRESSION (an item the baseline had exercised that the live run no longer
|
|
349
|
+
* exercises). Improvements (items that left an untested set) are NOT regressions.
|
|
350
|
+
*
|
|
351
|
+
* - subtype regression: a key in `live.untestedSubTypes` not in baseline's set.
|
|
352
|
+
* - attr regression: an attr in a live subtype's `untestedAttrs` not in the
|
|
353
|
+
* baseline's untested-attrs set for that SAME key. (A subtype that newly became
|
|
354
|
+
* untested is reported once as a subtype regression — its attrs are not double-
|
|
355
|
+
* reported, since an untested subtype has no per-attr entry by construction.)
|
|
356
|
+
*/
|
|
357
|
+
export function checkRatchet(
|
|
358
|
+
baseline: CoverageSnapshot,
|
|
359
|
+
live: CoverageSnapshot,
|
|
360
|
+
): RatchetResult {
|
|
361
|
+
const baselineUntestedSubTypes = new Set(baseline.untestedSubTypes);
|
|
362
|
+
const liveUntestedSubTypes = sortedUnique(live.untestedSubTypes);
|
|
363
|
+
|
|
364
|
+
const regressions: CoverageRegression[] = [];
|
|
365
|
+
|
|
366
|
+
// Subtype regressions: a NEW untested subtype (was exercised in the baseline).
|
|
367
|
+
for (const key of liveUntestedSubTypes) {
|
|
368
|
+
if (!baselineUntestedSubTypes.has(key)) {
|
|
369
|
+
regressions.push({ kind: "subtype", key });
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// Attr regressions: for each EXERCISED subtype (it carries a per-attr entry),
|
|
374
|
+
// any attr now untested that the baseline did not list as untested for that key.
|
|
375
|
+
const baselineAttrsByKey = new Map<string, Set<string>>();
|
|
376
|
+
for (const entry of baseline.untestedAttrsByExercisedSubType) {
|
|
377
|
+
baselineAttrsByKey.set(entry.key, new Set(entry.untestedAttrs));
|
|
378
|
+
}
|
|
379
|
+
for (const entry of live.untestedAttrsByExercisedSubType) {
|
|
380
|
+
// If the whole subtype regressed, it's already reported above — don't also
|
|
381
|
+
// attribute its attrs (it has no per-attr baseline entry by construction).
|
|
382
|
+
if (
|
|
383
|
+
!baselineUntestedSubTypes.has(entry.key) &&
|
|
384
|
+
liveUntestedSubTypes.includes(entry.key)
|
|
385
|
+
) {
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
const baselineUntested = baselineAttrsByKey.get(entry.key) ?? new Set<string>();
|
|
389
|
+
for (const attr of sortedUnique(entry.untestedAttrs)) {
|
|
390
|
+
if (!baselineUntested.has(attr)) {
|
|
391
|
+
regressions.push({ kind: "attr", key: entry.key, attr });
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
regressions.sort((a, b) => {
|
|
397
|
+
const byKind = compareStrings(a.kind, b.kind);
|
|
398
|
+
if (byKind !== 0) return byKind;
|
|
399
|
+
const byKey = compareStrings(a.key, b.key);
|
|
400
|
+
if (byKey !== 0) return byKey;
|
|
401
|
+
return compareStrings(a.attr ?? "", b.attr ?? "");
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
return { ok: regressions.length === 0, regressions };
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/** Render the regressions into an actionable, human-readable failure message. */
|
|
408
|
+
export function formatRatchetFailure(result: RatchetResult): string {
|
|
409
|
+
const lines: string[] = [
|
|
410
|
+
"Registry coverage REGRESSED — a previously-exercised vocabulary member is no",
|
|
411
|
+
"longer exercised by any conformance fixture (monotonic-ratchet violation):",
|
|
412
|
+
"",
|
|
413
|
+
];
|
|
414
|
+
for (const r of result.regressions) {
|
|
415
|
+
if (r.kind === "subtype") {
|
|
416
|
+
lines.push(` - subtype ${r.key} (no fixture exercises it anymore)`);
|
|
417
|
+
} else {
|
|
418
|
+
lines.push(` - attr ${r.key} @${r.attr} (no fixture sets it anymore)`);
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
lines.push(
|
|
422
|
+
"",
|
|
423
|
+
"Fix: add a conformance fixture that exercises the listed member(s). Only if",
|
|
424
|
+
"the member was LEGITIMATELY removed from the vocabulary (a justified change)",
|
|
425
|
+
"should you regenerate the baseline:",
|
|
426
|
+
" cd server/typescript",
|
|
427
|
+
" MO_UPDATE_COVERAGE_SNAPSHOT=1 bun test packages/metadata/test/registry-coverage.test.ts",
|
|
428
|
+
);
|
|
429
|
+
return lines.join("\n");
|
|
430
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
// SP-G Registry Conformance — manifest emitter CLASSIFICATION (the in/out boundary).
|
|
2
|
+
//
|
|
3
|
+
// WHY THIS FILE IS A CLASSIFICATION, NOT A NAME-MATCH LIST (Wave 3b).
|
|
4
|
+
// ---------------------------------------------------------------------------
|
|
5
|
+
// The manifest's in/out boundary used to be decided by a bare exclusion
|
|
6
|
+
// name-list: an attr was OUT iff its name happened to be hand-added to the set,
|
|
7
|
+
// IN otherwise — a silent default-include. That is a tautology: it cannot tell a
|
|
8
|
+
// genuinely-logical attr from a port-private one; it just records the names
|
|
9
|
+
// someone remembered to list. The next physical/binding attr nobody adds to the
|
|
10
|
+
// list silently enters the cross-port logical contract.
|
|
11
|
+
//
|
|
12
|
+
// The principled axis. Every metamodel facet the emitter encounters is one of:
|
|
13
|
+
//
|
|
14
|
+
// • LOGICAL — part of the cross-port vocabulary contract. MUST be identical
|
|
15
|
+
// in all five ports (this is what the gate measures). INCLUDED.
|
|
16
|
+
// Note "logical" is NOT "non-physical": the physical-DB attrs
|
|
17
|
+
// `column`/`dbColumnType`/`db.indexed`/`precision`/`scale`/
|
|
18
|
+
// `maxLength`/`unique` ARE logical here — they are the agreed
|
|
19
|
+
// cross-port persistence vocabulary (every port emits the same
|
|
20
|
+
// DDL contract from them). The axis is cross-port-CONTRACT vs
|
|
21
|
+
// port-PRIVATE-mechanism, not abstract-vs-physical.
|
|
22
|
+
//
|
|
23
|
+
// • PORT_PRIVATE — a per-port mechanism, NOT cross-port vocabulary:
|
|
24
|
+
// - NATIVE_BINDING factories / native type classes / the ADR-0001
|
|
25
|
+
// `object` class-FQN binding + ADR-0005 `objectAdapter`
|
|
26
|
+
// value-access seam (OO-port runtime mechanisms).
|
|
27
|
+
// - STRUCTURAL_KEYWORD bare body keywords (`isArray`/`isAbstract`/
|
|
28
|
+
// `extends`/`implements`/`isInterface`) — the
|
|
29
|
+
// structural/OO-shape spine, peers of name/children,
|
|
30
|
+
// never per-type attributes.
|
|
31
|
+
// - COMMON_ATTR_DUP `description` re-registered per-type (it lives in the
|
|
32
|
+
// `commonAttrs` block, never as a per-type attr).
|
|
33
|
+
// - INHERITANCE_ANCHOR the `metadata.base` per-port abstract anchor (the
|
|
34
|
+
// deferred `inheritsFrom` facet; other ports register
|
|
35
|
+
// only the concrete `metadata.root`).
|
|
36
|
+
// - PRESENTATION_ONLY the 11 generic `view.*` controls (checkbox/date/…)
|
|
37
|
+
// — a TS-web presentation facet (TS web client + TS
|
|
38
|
+
// form codegen consume them; zero backend/codegen/
|
|
39
|
+
// render consumers in any port), like the TS-only `D1`
|
|
40
|
+
// dialect. Stay REGISTERED in TS; deregistered in
|
|
41
|
+
// C#/Python; EXCLUDED from the manifest everywhere.
|
|
42
|
+
//
|
|
43
|
+
// The boundary is now an EXPLICIT classification (not a silent default): the
|
|
44
|
+
// port-private set is enumerated WITH a reason category, and a TRIPWIRE
|
|
45
|
+
// (`assertExclusionsAreLive`) asserts every enumerated exclusion is genuinely
|
|
46
|
+
// present in the registry — so a stale/typo'd exclusion (an excluded name no
|
|
47
|
+
// provider registers) fails the emit instead of silently doing nothing.
|
|
48
|
+
//
|
|
49
|
+
// Inclusion-by-default is SOUND here precisely because of ADR-0023: the library
|
|
50
|
+
// seals its composed metamodel registry after the agreed-provider bootstrap, so
|
|
51
|
+
// every registered (type, subType, attr) is, by construction, deliberately-agreed
|
|
52
|
+
// metamodel vocabulary — there is no "accidental" registration to silently let
|
|
53
|
+
// in. The classification's job is therefore to carve the small, declared set of
|
|
54
|
+
// agreed-but-port-private facets OUT of that agreed vocabulary, with a reason and
|
|
55
|
+
// a liveness tripwire. See fixtures/registry-conformance/README.md.
|
|
56
|
+
//
|
|
57
|
+
// FR-033 NOTE — the manifest now emits per-type and per-attr `description`
|
|
58
|
+
// (required, non-empty), optional `rules`/`example`/`whenToUse`, AND the full
|
|
59
|
+
// structural constraint graph (`children` from childRules, with optional
|
|
60
|
+
// cardinality, and optional `parents`) as FIRST-CLASS PROPERTIES of each type/
|
|
61
|
+
// attr entry. The v1 boundary note that listed `childRules` / type-level
|
|
62
|
+
// `description` as EXCLUDED is SUPERSEDED for those facets. This does NOT change
|
|
63
|
+
// the COMMON_ATTR_DUP carve-out below: that entry removes a per-type ATTR whose
|
|
64
|
+
// NAME is "description" (the commonAttr re-registered as a per-type attr) from
|
|
65
|
+
// the `attrs` ARRAY — a different mechanism from the type/attr-level
|
|
66
|
+
// `description` PROPERTY now emitted as a sibling of `attrs`. The carve-out (and
|
|
67
|
+
// the test asserting no `attrs[]` entry is named "description") stays unchanged.
|
|
68
|
+
|
|
69
|
+
import { RESERVED_KEY_IS_ARRAY, RESERVED_KEY_EXTENDS } from "./shared/structural.js";
|
|
70
|
+
import { DOC_ATTR_DESCRIPTION } from "./core/documentation/doc-constants.js";
|
|
71
|
+
import { SUBTYPE_BASE, TYPE_METADATA, TYPE_VIEW } from "./shared/base-types.js";
|
|
72
|
+
import { VIEW_SUBTYPE_CURRENCY } from "./presentation/view/view-constants.js";
|
|
73
|
+
|
|
74
|
+
/** The reason an attr/row is classified PORT_PRIVATE (carved out of the agreed vocabulary). */
|
|
75
|
+
export enum ExclusionReason {
|
|
76
|
+
/** Native type-binding / factory mechanism (incl. ADR-0001 `object`, ADR-0005 `objectAdapter`). */
|
|
77
|
+
NativeBinding = "native-binding",
|
|
78
|
+
/** Bare structural / OO-shape keyword (`isArray`/`isAbstract`/`extends`/`implements`/`isInterface`). */
|
|
79
|
+
StructuralKeyword = "structural-keyword",
|
|
80
|
+
/** A `commonAttr` (`description`) re-registered per-type — belongs in the commonAttrs block. */
|
|
81
|
+
CommonAttrDup = "common-attr-dup",
|
|
82
|
+
/** The `metadata.base` per-port inheritance anchor (deferred `inheritsFrom` facet). */
|
|
83
|
+
InheritanceAnchor = "inheritance-anchor",
|
|
84
|
+
/** TS-web-presentation-only facet (the generic `view.*` controls). */
|
|
85
|
+
PresentationOnly = "presentation-only",
|
|
86
|
+
/**
|
|
87
|
+
* FR-024 TS-reference-first rollout (RETIRED at the atomic flip): new
|
|
88
|
+
* vocabulary genuinely registered (and gated by TS tests) but carved out of
|
|
89
|
+
* the cross-port manifest until every port registered it; the carve-outs were
|
|
90
|
+
* then removed and the canonical updated in ONE commit (the same lifecycle
|
|
91
|
+
* the retired TsPilotVocab carve-outs followed for `@responseRef`/`@provided`).
|
|
92
|
+
* The `object.projection` row + the `origin.aggregate.via` required-override
|
|
93
|
+
* flipped when all five ports shipped the FR-024 loader-grammar slice. The
|
|
94
|
+
* reason is kept as the documented lifecycle slot for the NEXT
|
|
95
|
+
* reference-first rollout; it currently has no members.
|
|
96
|
+
*/
|
|
97
|
+
Fr024Pending = "fr024-pending",
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/** `isAbstract` as Java's per-type attr name (the contract's bare `abstract` structural keyword). */
|
|
101
|
+
const ATTR_NAME_IS_ABSTRACT = "isAbstract";
|
|
102
|
+
/** Java-OO structural-shape keywords as per-type attr names (the OO modeling spine). */
|
|
103
|
+
const ATTR_NAME_IMPLEMENTS = "implements";
|
|
104
|
+
const ATTR_NAME_IS_INTERFACE = "isInterface";
|
|
105
|
+
/** ADR-0001 class-FQN type binding + ADR-0005 hybrid value-access seam (per-port runtime mechanisms). */
|
|
106
|
+
const ATTR_NAME_OBJECT = "object";
|
|
107
|
+
const ATTR_NAME_OBJECT_ADAPTER = "objectAdapter";
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* The per-type attr names carved OUT of the agreed vocabulary, each mapped to
|
|
111
|
+
* its PORT_PRIVATE reason category. This is the classification — an attr name
|
|
112
|
+
* here is OUT *because of its declared category*, not merely because it is
|
|
113
|
+
* listed. A per-type attr NOT in this map is LOGICAL (INCLUDED) by the
|
|
114
|
+
* ADR-0023 sealed-vocabulary contract.
|
|
115
|
+
*/
|
|
116
|
+
export const EXCLUDED_PER_TYPE_ATTRS: ReadonlyMap<string, ExclusionReason> = new Map([
|
|
117
|
+
[RESERVED_KEY_IS_ARRAY, ExclusionReason.StructuralKeyword],
|
|
118
|
+
[ATTR_NAME_IS_ABSTRACT, ExclusionReason.StructuralKeyword],
|
|
119
|
+
[RESERVED_KEY_EXTENDS, ExclusionReason.StructuralKeyword],
|
|
120
|
+
[ATTR_NAME_IMPLEMENTS, ExclusionReason.StructuralKeyword],
|
|
121
|
+
[ATTR_NAME_IS_INTERFACE, ExclusionReason.StructuralKeyword],
|
|
122
|
+
[ATTR_NAME_OBJECT, ExclusionReason.NativeBinding],
|
|
123
|
+
[ATTR_NAME_OBJECT_ADAPTER, ExclusionReason.NativeBinding],
|
|
124
|
+
[DOC_ATTR_DESCRIPTION, ExclusionReason.CommonAttrDup],
|
|
125
|
+
]);
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* `(type, subType)` rows carved OUT of the agreed vocabulary, with reason.
|
|
129
|
+
* `metadata.base` is the per-port inheritance anchor (INHERITANCE_ANCHOR); the
|
|
130
|
+
* 11 generic `view.*` controls are TS-web-presentation-only (PRESENTATION_ONLY).
|
|
131
|
+
* Returns the reason, or `undefined` for an INCLUDED (logical) row.
|
|
132
|
+
*/
|
|
133
|
+
export function classifyTypeSubType(
|
|
134
|
+
type: string,
|
|
135
|
+
subType: string,
|
|
136
|
+
): ExclusionReason | undefined {
|
|
137
|
+
if (type === TYPE_METADATA && subType === SUBTYPE_BASE) {
|
|
138
|
+
return ExclusionReason.InheritanceAnchor; // C-5 — Java's internal inheritance anchor
|
|
139
|
+
}
|
|
140
|
+
if (type === TYPE_VIEW && subType !== SUBTYPE_BASE && subType !== VIEW_SUBTYPE_CURRENCY) {
|
|
141
|
+
return ExclusionReason.PresentationOnly; // B-2 — TS-web-presentation generic view controls
|
|
142
|
+
}
|
|
143
|
+
return undefined;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** True if a `(type, subType)` row is carved out of the manifest (any reason). */
|
|
147
|
+
export function isExcludedTypeSubType(type: string, subType: string): boolean {
|
|
148
|
+
return classifyTypeSubType(type, subType) !== undefined;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* FR-024-pending manifest REQUIREDNESS overrides (the attr-level analogue of
|
|
153
|
+
* the `Fr024Pending` row carve-out). Key is `"type.subType.attrName"`; value is
|
|
154
|
+
* the requiredness the cross-port canonical (`expected-registry.json`) still
|
|
155
|
+
* records. The TS registry already registers the FR-024 requiredness (and the
|
|
156
|
+
* TS loader enforces it), but the other four ports have not flipped yet — the
|
|
157
|
+
* manifest keeps emitting the pre-FR-024 agreed value so the shared canonical
|
|
158
|
+
* stays byte-identical until the Phase-E atomic all-ports flip, when this map
|
|
159
|
+
* empties and the canonical is updated in ONE commit.
|
|
160
|
+
*
|
|
161
|
+
* Members today: NONE — `origin.aggregate.via` flipped at the FR-024 atomic
|
|
162
|
+
* all-ports manifest flip (it is OPTIONAL everywhere under ADR-0029 decision 5:
|
|
163
|
+
* omitted `@via` is inferred when exactly one single-hop relationship leads
|
|
164
|
+
* from the base entity to the `@of` entity). The mechanism stays for the next
|
|
165
|
+
* reference-first rollout.
|
|
166
|
+
*/
|
|
167
|
+
export const FR024_PENDING_REQUIRED_OVERRIDES: ReadonlyMap<string, boolean> = new Map([]);
|
|
168
|
+
|
|
169
|
+
/** Manifest requiredness for an attr — the FR-024-pending override when one exists. */
|
|
170
|
+
export function manifestRequiredOverride(
|
|
171
|
+
type: string,
|
|
172
|
+
subType: string,
|
|
173
|
+
attrName: string,
|
|
174
|
+
): boolean | undefined {
|
|
175
|
+
return FR024_PENDING_REQUIRED_OVERRIDES.get(`${type}.${subType}.${attrName}`);
|
|
176
|
+
}
|