@rathnasgala2/schemas 2.11.0 → 2.13.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/README.md +192 -84
- package/THIRD_PARTY_LICENSES.json +79 -106
- package/diagnostics/diagnostic-map.json +443 -405
- package/diagnostics/diagnostic-map.public-runtime-origins.json +5 -0
- package/docs/catalogs/app-routes.json +2 -1
- package/docs/catalogs/schema-inventory.json +33 -54
- package/examples/valid/adapter-capability/rules.json +11 -0
- package/examples/valid/artifact-manifest/rules.json +156 -177
- package/examples/valid/build-input/rules.json +67 -63
- package/examples/valid/build-provenance/rules.json +151 -172
- package/examples/valid/deployment-intent/rules.json +152 -148
- package/examples/valid/deployment-observation/rules.json +24 -20
- package/examples/valid/deployment-receipt/rules.json +152 -148
- package/examples/valid/navigation/rules.json +2 -4
- package/examples/valid/theme-contract/rules.json +4 -1
- package/fixtures/boundary/adapter-capability/rules.json +16 -0
- package/fixtures/boundary/artifact-manifest/rules.json +195 -202
- package/fixtures/boundary/build-input/rules.json +99 -86
- package/fixtures/boundary/build-provenance/rules.json +193 -202
- package/fixtures/boundary/deployment-intent/rules.json +186 -140
- package/fixtures/boundary/deployment-observation/rules.json +68 -18
- package/fixtures/boundary/deployment-receipt/rules.json +186 -140
- package/fixtures/boundary/navigation/rules.json +2 -17
- package/fixtures/boundary/theme-contract/rules.json +34 -0
- package/fixtures/invalid/adapter-capability/SCHEMA_STRING_TOO_LONG/cases.json +11 -0
- package/fixtures/invalid/adapter-capability/UTF8_BYTE_LENGTH_INVALID/cases.json +11 -0
- package/fixtures/invalid/artifact-manifest/ASCII_BYTE_LENGTH_INVALID/cases.json +13 -0
- package/fixtures/invalid/artifact-manifest/INTEGER_RANGE_INVALID/cases.json +24 -0
- package/fixtures/invalid/artifact-manifest/REQUEST_FIELD_UNKNOWN/cases.json +19 -19
- package/fixtures/invalid/artifact-manifest/SCHEMA_CONSTANT_INVALID/cases.json +48 -48
- package/fixtures/invalid/artifact-manifest/SCHEMA_ENUM_INVALID/cases.json +11 -11
- package/fixtures/invalid/artifact-manifest/SCHEMA_FORMAT_INVALID/cases.json +0 -9
- package/fixtures/invalid/artifact-manifest/SCHEMA_NEGATED_RULE_MATCHED/cases.json +0 -11
- package/fixtures/invalid/artifact-manifest/SCHEMA_PATTERN_INVALID/cases.json +0 -22
- package/fixtures/invalid/artifact-manifest/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +1105 -1105
- package/fixtures/invalid/artifact-manifest/SCHEMA_STRING_TOO_LONG/cases.json +4 -6
- package/fixtures/invalid/artifact-manifest/SCHEMA_STRING_TOO_SHORT/cases.json +9 -11
- package/fixtures/invalid/artifact-manifest/SCHEMA_TYPE_INVALID/cases.json +22 -31
- package/fixtures/invalid/artifact-manifest/UTF8_BYTE_LENGTH_INVALID/cases.json +0 -11
- package/fixtures/invalid/build-input/INTEGER_RANGE_INVALID/cases.json +13 -0
- package/fixtures/invalid/build-input/REQUEST_FIELD_UNKNOWN/cases.json +32 -32
- package/fixtures/invalid/build-input/SCHEMA_CONSTANT_INVALID/cases.json +11 -11
- package/fixtures/invalid/build-input/SCHEMA_ENUM_INVALID/cases.json +11 -11
- package/fixtures/invalid/build-input/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +78 -78
- package/fixtures/invalid/build-input/SCHEMA_TYPE_INVALID/cases.json +51 -18
- package/fixtures/invalid/build-provenance/ASCII_BYTE_LENGTH_INVALID/cases.json +13 -0
- package/fixtures/invalid/build-provenance/INTEGER_RANGE_INVALID/cases.json +22 -0
- package/fixtures/invalid/build-provenance/REQUEST_FIELD_UNKNOWN/cases.json +56 -56
- package/fixtures/invalid/build-provenance/SCHEMA_CONSTANT_INVALID/cases.json +37 -37
- package/fixtures/invalid/build-provenance/SCHEMA_ENUM_INVALID/cases.json +11 -11
- package/fixtures/invalid/build-provenance/SCHEMA_FORMAT_INVALID/cases.json +0 -9
- package/fixtures/invalid/build-provenance/SCHEMA_NEGATED_RULE_MATCHED/cases.json +0 -11
- package/fixtures/invalid/build-provenance/SCHEMA_PATTERN_INVALID/cases.json +0 -22
- package/fixtures/invalid/build-provenance/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +927 -927
- package/fixtures/invalid/build-provenance/SCHEMA_STRING_TOO_LONG/cases.json +9 -11
- package/fixtures/invalid/build-provenance/SCHEMA_STRING_TOO_SHORT/cases.json +8 -10
- package/fixtures/invalid/build-provenance/SCHEMA_TYPE_INVALID/cases.json +20 -25
- package/fixtures/invalid/build-provenance/UTF8_BYTE_LENGTH_INVALID/cases.json +0 -11
- package/fixtures/invalid/deployment-intent/INTEGER_RANGE_INVALID/cases.json +24 -0
- package/fixtures/invalid/deployment-intent/REQUEST_FIELD_UNKNOWN/cases.json +30 -30
- package/fixtures/invalid/deployment-intent/SCHEMA_CONSTANT_INVALID/cases.json +41 -41
- package/fixtures/invalid/deployment-intent/SCHEMA_ENUM_INVALID/cases.json +11 -11
- package/fixtures/invalid/deployment-intent/SCHEMA_FORMAT_INVALID/cases.json +0 -9
- package/fixtures/invalid/deployment-intent/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +1209 -1209
- package/fixtures/invalid/deployment-intent/SCHEMA_STRING_TOO_LONG/cases.json +9 -0
- package/fixtures/invalid/deployment-intent/SCHEMA_STRING_TOO_SHORT/cases.json +9 -0
- package/fixtures/invalid/deployment-intent/SCHEMA_TYPE_INVALID/cases.json +22 -20
- package/fixtures/invalid/deployment-observation/INTEGER_RANGE_INVALID/cases.json +24 -0
- package/fixtures/invalid/deployment-observation/REQUEST_FIELD_UNKNOWN/cases.json +16 -16
- package/fixtures/invalid/deployment-observation/SCHEMA_FORMAT_INVALID/cases.json +0 -9
- package/fixtures/invalid/deployment-observation/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +39 -39
- package/fixtures/invalid/deployment-observation/SCHEMA_STRING_TOO_LONG/cases.json +11 -0
- package/fixtures/invalid/deployment-observation/SCHEMA_STRING_TOO_SHORT/cases.json +11 -0
- package/fixtures/invalid/deployment-observation/SCHEMA_TYPE_INVALID/cases.json +11 -11
- package/fixtures/invalid/deployment-receipt/INTEGER_RANGE_INVALID/cases.json +24 -0
- package/fixtures/invalid/deployment-receipt/REQUEST_FIELD_UNKNOWN/cases.json +70 -70
- package/fixtures/invalid/deployment-receipt/SCHEMA_CONSTANT_INVALID/cases.json +36 -36
- package/fixtures/invalid/deployment-receipt/SCHEMA_ENUM_INVALID/cases.json +11 -11
- package/fixtures/invalid/deployment-receipt/SCHEMA_FORMAT_INVALID/cases.json +0 -9
- package/fixtures/invalid/deployment-receipt/SCHEMA_REQUIRED_FIELD_MISSING/cases.json +1304 -1304
- package/fixtures/invalid/deployment-receipt/SCHEMA_STRING_TOO_LONG/cases.json +9 -0
- package/fixtures/invalid/deployment-receipt/SCHEMA_STRING_TOO_SHORT/cases.json +9 -0
- package/fixtures/invalid/deployment-receipt/SCHEMA_TYPE_INVALID/cases.json +22 -20
- package/fixtures/invalid/navigation/SCHEMA_ARRAY_TOO_LONG/cases.json +0 -15
- package/fixtures/invalid/navigation/SCHEMA_CONSTANT_INVALID/cases.json +11 -0
- package/fixtures/invalid/navigation/SCHEMA_TYPE_INVALID/cases.json +0 -11
- package/fixtures/invalid/theme-contract/INTEGER_RANGE_INVALID/cases.json +11 -0
- package/fixtures/invalid/theme-contract/SCHEMA_FORMAT_INVALID/cases.json +0 -9
- package/fixtures/invalid/theme-contract/SCHEMA_STRING_TOO_LONG/cases.json +9 -0
- package/fixtures/invalid/theme-contract/SCHEMA_STRING_TOO_SHORT/cases.json +9 -0
- package/fixtures/manifest.json +3217 -2930
- package/fixtures/unknown-field/adapter-capability/rules.json +2 -0
- package/fixtures/unknown-field/artifact-manifest/rules.json +111 -114
- package/fixtures/unknown-field/build-input/rules.json +36 -32
- package/fixtures/unknown-field/build-provenance/rules.json +111 -114
- package/fixtures/unknown-field/deployment-intent/rules.json +109 -105
- package/fixtures/unknown-field/deployment-observation/rules.json +24 -20
- package/fixtures/unknown-field/deployment-receipt/rules.json +109 -105
- package/fixtures/unknown-field/navigation/rules.json +1 -3
- package/fixtures/unknown-field/theme-contract/rules.json +3 -0
- package/generated/browser/runtime-origins-validator-core.d.mts +10 -0
- package/generated/browser/runtime-origins-validator-core.mjs +35 -0
- package/generated/browser/validator-core.d.mts +10 -0
- package/generated/browser/validator-core.mjs +80 -0
- package/generated/typescript/contracts/artifact-manifest.d.ts +49 -48
- package/generated/typescript/contracts/build-input.d.ts +15 -15
- package/generated/typescript/contracts/build-provenance.d.ts +51 -50
- package/generated/typescript/contracts/deployment-intent.d.ts +6 -6
- package/generated/typescript/contracts/deployment-observation.d.ts +1 -1
- package/generated/typescript/contracts/deployment-receipt.d.ts +5 -5
- package/generated/typescript/contracts/navigation.d.ts +1 -1
- package/generated/typescript/index.js +11 -37
- package/openapi/http-catalog.json +14 -2
- package/openapi/openapi.yaml +527 -13
- package/package.json +19 -16
- package/sbom.cdx.json +23 -23
- package/schemas/adapter-capability.schema.json +5 -1
- package/schemas/appearance.schema.json +1 -1
- package/schemas/artifact-manifest.schema.json +15 -18
- package/schemas/build-input.schema.json +18 -11
- package/schemas/build-provenance.schema.json +15 -18
- package/schemas/deployment-intent.schema.json +13 -8
- package/schemas/deployment-observation.schema.json +10 -5
- package/schemas/deployment-receipt.schema.json +12 -7
- package/schemas/navigation.schema.json +5 -26
- package/schemas/theme-contract.schema.json +4 -2
- package/src/index.js +2 -2
- package/src/internal/browser-schema-validator.js +43 -0
- package/src/internal/format-validators.js +1 -1
- package/src/internal/gala-keywords.js +148 -0
- package/src/internal/validator-core.js +244 -108
- package/src/runtime-origins.js +18 -18
- package/types/index.d.ts +2 -2
- package/types/internal/browser-schema-validator.d.ts +16 -0
- package/types/internal/format-validators.d.ts +1 -1
- package/types/internal/gala-keywords.d.ts +68 -0
- package/types/internal/validator-core.d.ts +80 -1
- package/compatibility/compatibility.json +0 -594
- package/generated/java/src/main/java/io/gala/schema/generated/GalaSchemaRegistry.java +0 -67
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityAdapterConfigurationCapabilities.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityAdapterIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityCapabilityDecision.java +0 -62
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityCredentialEgressProfile.java +0 -35
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityDestinationIdentity.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityDestinationProviderCoordinates.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityDocument.java +0 -52
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityFilesystemProviderLimits.java +0 -32
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityGithubActionsOidcOriginCatalog.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityHttpProviderLimits.java +0 -72
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemAllowlist.java +0 -21
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemAllowlistEntry.java +0 -28
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemCapabilityEvidence.java +0 -42
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemControlPublication.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemControlRow.java +0 -44
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemFailureEvidence.java +0 -40
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemObservationEvidence.java +0 -40
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemPlatform.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemProbeSummary.java +0 -32
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemProbeTranscript.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemReplacement.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityLocalFilesystemSurfaceIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityManagedExecutionBudget.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityPagesOidcCredentialEgress.java +0 -30
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityProviderCallClassBinding.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityProviderCredentialEgress.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityProviderCredentialHeader.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityProviderDerivedHeader.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityProviderFixedHeader.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilityProviderRequestTemplate.java +0 -39
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilitySpacesControlPlaneBinding.java +0 -32
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilitySpacesControlPlaneRequest.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilitySpacesControlPlaneRequestCatalog.java +0 -31
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilitySpacesControlPlaneResponseCatalog.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/AdapterCapabilitySpacesWebsiteConfiguration.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/AppearanceColorMode.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/AppearanceDocument.java +0 -37
- package/generated/java/src/main/java/io/gala/schema/generated/model/AppearanceExtensionMap.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/AppearanceSemanticTokens.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestActionPinEvidence.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestArtifactLicenseConclusion.java +0 -21
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestAssertedWorkload.java +0 -44
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestBuildSandboxEvidence.java +0 -38
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestDocument.java +0 -73
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestFinding.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestAsset.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestCompositionIdentity.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestExcludedInput.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestIncludedSource.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestRedirect.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestRoute.java +0 -28
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestSourceIdentity.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestManifestValidationEvidence.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestMeasurement.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestPackageIdentity.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestRenderPolicyIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestReproducibleBuildRecord.java +0 -56
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestWorkflowCarrierEvidence.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/ArtifactManifestWorkflowFileEvidence.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/AuthorDocument.java +0 -33
- package/generated/java/src/main/java/io/gala/schema/generated/model/AuthorExtensionMap.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/AuthorLocalizedAuthor.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/AuthorSocialLink.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputAdapterIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputAppearanceNormalized.java +0 -33
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputAuthorNormalized.java +0 -31
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputBuildPackages.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputColorMode.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputContentBuildRecord.java +0 -33
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputContentFrontmatterNormalized.java +0 -44
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputDestinationCapabilityProfile.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputDocument.java +0 -51
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputLocalizedAuthor.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputModuleBuildSelection.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputNavigationItem.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputNavigationLeaf.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputNavigationNormalized.java +0 -21
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputPackageIdentity.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputPublicationNormalized.java +0 -39
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputRenderPolicyIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputRenderableBody.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputRepositorySnapshot.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputResolvedFile.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputResolvedMedia.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputSemanticTokens.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildInputSocialLink.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceActionPinEvidence.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceArtifactLicenseConclusion.java +0 -21
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceAssertedWorkload.java +0 -44
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceBuildSandboxEvidence.java +0 -38
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceDocument.java +0 -69
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceFinding.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestAsset.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestCompositionIdentity.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestExcludedInput.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestIncludedSource.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestRedirect.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestRoute.java +0 -28
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestSourceIdentity.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceManifestValidationEvidence.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceMeasurement.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenancePackageIdentity.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceRenderPolicyIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceReproducibleBuildRecord.java +0 -56
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceWorkflowCarrierEvidence.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/BuildProvenanceWorkflowFileEvidence.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/ContentFrontmatterDocument.java +0 -50
- package/generated/java/src/main/java/io/gala/schema/generated/model/ContentFrontmatterExtensionMap.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/ContentFrontmatterMediaRef.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentActivationBasis.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentActivationDetectionObservation.java +0 -33
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentActivationDetectionPlan.java +0 -44
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentActivationDetectionProbe.java +0 -52
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentAdapterIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentCancellationFinalizationEvidence.java +0 -41
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentDeadlineFinalizationEvidence.java +0 -39
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentDeadlineFinalizationStream.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentDeploymentPolicyDecision.java +0 -75
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentDestinationIdentity.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentDestinationMutationAuthority.java +0 -36
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentDestinationProviderCoordinates.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentDocument.java +0 -136
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentExpectedRedirectHop.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentObservedVerificationHeader.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentPackageIdentity.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentPagesInterveningRunAttempt.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentPagesReconciliationCommand.java +0 -48
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentPagesReconciliationRecovery.java +0 -41
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentPagesRunAttemptGapProof.java +0 -27
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentPublicGenerationMarkerPayload.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentPublicProbeObservation.java +0 -54
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentRecognizedPriorRouteContract.java +0 -30
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentRenderPolicyIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentReproducibleBuildRecord.java +0 -56
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentSupersessionFinalizationEvidence.java +0 -45
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentVerificationHeaderExpectation.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentIntentVerificationPlanTarget.java +0 -52
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationActivationDetectionObservation.java +0 -33
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationActivationDetectionProbe.java +0 -52
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationAdapterIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationCancellationFinalizationEvidence.java +0 -41
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationDeadlineFinalizationEvidence.java +0 -39
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationDeadlineFinalizationStream.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationDestinationIdentity.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationDestinationProviderCoordinates.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationDocument.java +0 -57
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationExpectedRedirectHop.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationObservedVerificationHeader.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationPackageIdentity.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationPublicProbeObservation.java +0 -54
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationRecognizedPriorRouteContract.java +0 -30
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationRenderPolicyIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationSupersessionFinalizationEvidence.java +0 -45
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationVerificationHeaderExpectation.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentObservationVerificationPlanTarget.java +0 -52
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptActivationBasis.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptActivationDetectionObservation.java +0 -33
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptActivationDetectionPlan.java +0 -44
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptActivationDetectionProbe.java +0 -52
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptAdapterIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptCancellationFinalizationEvidence.java +0 -41
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeadlineFinalizationEvidence.java +0 -39
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeadlineFinalizationStream.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentAttempt.java +0 -38
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentFailure.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentObservation.java +0 -53
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentPolicyDecision.java +0 -75
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentStageEvidence.java +0 -36
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentStageInput.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentStageObservationEvidenceReference.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDeploymentStageResult.java +0 -31
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDestinationIdentity.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDestinationMutationAuthority.java +0 -36
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDestinationProviderCoordinates.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptDocument.java +0 -105
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptExpectedRedirectHop.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptFinding.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptObservedVerificationHeader.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptPackageIdentity.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptPagesInterveningRunAttempt.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptPagesReconciliationCommand.java +0 -48
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptPagesReconciliationRecovery.java +0 -41
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptPagesRunAttemptGapProof.java +0 -27
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptPublicGenerationMarkerPayload.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptPublicProbeObservation.java +0 -54
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptRecognizedPriorRouteContract.java +0 -30
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptRenderPolicyIdentity.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptReproducibleBuildRecord.java +0 -56
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptSupersessionFinalizationEvidence.java +0 -45
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptVerificationHeaderExpectation.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/DeploymentReceiptVerificationPlanTarget.java +0 -52
- package/generated/java/src/main/java/io/gala/schema/generated/model/EventEnvelopeDocument.java +0 -46
- package/generated/java/src/main/java/io/gala/schema/generated/model/EventEnvelopeRegisteredEventPayload.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/LockDependencyEdge.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/LockDocument.java +0 -39
- package/generated/java/src/main/java/io/gala/schema/generated/model/LockLockedPackage.java +0 -26
- package/generated/java/src/main/java/io/gala/schema/generated/model/LockLockedTemplate.java +0 -28
- package/generated/java/src/main/java/io/gala/schema/generated/model/LockPackageIdentity.java +0 -22
- package/generated/java/src/main/java/io/gala/schema/generated/model/NavigationDocument.java +0 -25
- package/generated/java/src/main/java/io/gala/schema/generated/model/NavigationExtensionMap.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/NavigationNavigationItem.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/NavigationNavigationLeaf.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/ProblemDocument.java +0 -37
- package/generated/java/src/main/java/io/gala/schema/generated/model/ProblemFieldError.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/PublicGenerationMarkerDocument.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/PublicRuntimeOriginsDocument.java +0 -44
- package/generated/java/src/main/java/io/gala/schema/generated/model/PublicationDocument.java +0 -41
- package/generated/java/src/main/java/io/gala/schema/generated/model/PublicationExtensionMap.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/PublicationFooterCard.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/PublicationPublicationProfile.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/PublicationSocialLink.java +0 -19
- package/generated/java/src/main/java/io/gala/schema/generated/model/RepositoryAssetRoot.java +0 -16
- package/generated/java/src/main/java/io/gala/schema/generated/model/RepositoryContentRoot.java +0 -23
- package/generated/java/src/main/java/io/gala/schema/generated/model/RepositoryDocument.java +0 -41
- package/generated/java/src/main/java/io/gala/schema/generated/model/RepositoryExtensionMap.java +0 -15
- package/generated/java/src/main/java/io/gala/schema/generated/model/RepositoryGeneratedRoot.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/TemplateCompositionDocument.java +0 -18
- package/generated/java/src/main/java/io/gala/schema/generated/model/ThemeContractDocument.java +0 -53
- package/generated/java/src/main/java/io/gala/schema/generated/model/ThemeContractPassiveAsset.java +0 -24
- package/generated/java/src/main/java/io/gala/schema/generated/model/ThemeContractThemeBudgets.java +0 -20
- package/generated/java/src/main/java/io/gala/schema/generated/model/ThemeContractThemeToken.java +0 -22
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/adapter-capability.schema.json +0 -2689
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/appearance.schema.json +0 -226
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/artifact-manifest.schema.json +0 -1063
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/author.schema.json +0 -231
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/build-input.schema.json +0 -866
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/build-provenance.schema.json +0 -937
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/content-frontmatter.schema.json +0 -241
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/deployment-intent.schema.json +0 -2067
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/deployment-observation.schema.json +0 -1654
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/deployment-receipt.schema.json +0 -5546
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/event-envelope.schema.json +0 -195
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/lock.schema.json +0 -326
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/navigation.schema.json +0 -229
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/problem.schema.json +0 -194
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/public-generation-marker.schema.json +0 -142
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/public-runtime-origins.schema.json +0 -183
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/publication.schema.json +0 -248
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/repository.schema.json +0 -219
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/template-composition.schema.json +0 -133
- package/generated/java/src/main/resources/io/gala/schema/generated/schemas/theme-contract.schema.json +0 -850
- package/generated/typescript/validator-core.cjs +0 -17
- package/openapi/generator/spring.json +0 -22
- package/openapi/generator/typescript-fetch.json +0 -19
- package/openapi/source/authentication.yaml +0 -557
- package/openapi/source/callbacks.yaml +0 -332
- package/openapi/source/components.yaml +0 -5670
- package/openapi/source/github.yaml +0 -351
- package/openapi/source/internal.yaml +0 -71
- package/openapi/source/membership-invitations.yaml +0 -203
- package/openapi/source/organizations.yaml +0 -11144
- package/openapi/source/root.yaml +0 -20
- package/openapi/source/self.yaml +0 -1940
- package/openapi/source/session.yaml +0 -308
- package/openapi/source/workloads.yaml +0 -744
- package/src/internal/build-artifact-semantics.js +0 -4391
- package/src/internal/deployment-record-semantics.js +0 -7567
- package/src/internal/deployment-stage-semantics.js +0 -1207
- package/src/internal/http-problem-contract.js +0 -35
- package/src/internal/managed-evidence-journal.js +0 -160
- package/src/internal/public-runtime-origins.js +0 -143
- package/src/internal/theme-composition-semantics.js +0 -2441
- package/types/internal/build-artifact-semantics.d.ts +0 -77
- package/types/internal/deployment-record-semantics.d.ts +0 -313
- package/types/internal/deployment-stage-semantics.d.ts +0 -108
- package/types/internal/http-problem-contract.d.ts +0 -4
- package/types/internal/managed-evidence-journal.d.ts +0 -26
- package/types/internal/public-runtime-origins.d.ts +0 -22
- package/types/internal/theme-composition-semantics.d.ts +0 -143
|
@@ -1,2441 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
canonicalizeJcs,
|
|
3
|
-
canonicalizeJcsBytes,
|
|
4
|
-
parseDuplicateFreeIJson,
|
|
5
|
-
sha256Tagged,
|
|
6
|
-
} from './canonical-jcs.js';
|
|
7
|
-
import { ACTIVE_DIGEST_PROFILES } from './digest-profiles.js';
|
|
8
|
-
import {
|
|
9
|
-
parseSemver,
|
|
10
|
-
parseSemverRange,
|
|
11
|
-
satisfiesSemverRange,
|
|
12
|
-
SemanticValidationError,
|
|
13
|
-
} from './semver.js';
|
|
14
|
-
import { validateSpdxCatalogEvidence, validateSpdxExpression } from './spdx.js';
|
|
15
|
-
import unicodeData from './generated/unicode17.json' with { type: 'json' };
|
|
16
|
-
import {
|
|
17
|
-
assertUnicodeScalarString,
|
|
18
|
-
graphemeLength17,
|
|
19
|
-
normalizeNfc17,
|
|
20
|
-
unicodeCollisionKey17,
|
|
21
|
-
} from './unicode17.js';
|
|
22
|
-
|
|
23
|
-
const FATAL_UTF8_DECODER = new TextDecoder('utf-8', { fatal: true });
|
|
24
|
-
const DIGEST_PATTERN = /^sha256:[0-9a-f]{64}$/u;
|
|
25
|
-
const STABLE_ID_PATTERN =
|
|
26
|
-
/^[0-9a-f]{8}-[0-9a-f]{4}-7[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/u;
|
|
27
|
-
const POSITIVE_INT64_PATTERN = /^[1-9][0-9]*$/u;
|
|
28
|
-
const NONNEGATIVE_INT64_PATTERN = /^(?:0|[1-9][0-9]*)$/u;
|
|
29
|
-
const INT64_MAXIMUM = 9_223_372_036_854_775_807n;
|
|
30
|
-
const STYLE_NAME_PATTERN = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/u;
|
|
31
|
-
const COLOR_PATTERN = /^#[0-9a-f]{6}(?:[0-9a-f]{2})?$/u;
|
|
32
|
-
const LENGTH_PATTERN =
|
|
33
|
-
/^(?:0|(?:[1-9][0-9]*(?:\.[0-9]{0,3}[1-9])?|0\.(?:[0-9]{0,3}[1-9]))(?:px|rem))$/u;
|
|
34
|
-
const FONT_FAMILY_PATTERN =
|
|
35
|
-
/^[A-Za-z][A-Za-z0-9]*(?:[ -][A-Za-z0-9]+)*(?:, [A-Za-z][A-Za-z0-9]*(?:[ -][A-Za-z0-9]+)*){0,7}$/u;
|
|
36
|
-
const FONT_WEIGHT_PATTERN = /^[1-9]00$/u;
|
|
37
|
-
const PACKAGE_NAME_PATTERN =
|
|
38
|
-
/^(?:[a-z0-9][a-z0-9._-]*|@[a-z0-9][a-z0-9._-]*\/[a-z0-9][a-z0-9._-]*)$/u;
|
|
39
|
-
|
|
40
|
-
const TEMPLATE_COMPOSITION_KEYS = ['schemaId', 'schemaVersion'];
|
|
41
|
-
const THEME_KEYS = [
|
|
42
|
-
'schemaId',
|
|
43
|
-
'schemaVersion',
|
|
44
|
-
'themeId',
|
|
45
|
-
'package',
|
|
46
|
-
'contractVersion',
|
|
47
|
-
'templateRange',
|
|
48
|
-
'stylesheets',
|
|
49
|
-
'cssLayers',
|
|
50
|
-
'slotHooks',
|
|
51
|
-
'tokens',
|
|
52
|
-
'modes',
|
|
53
|
-
'assets',
|
|
54
|
-
'fixtures',
|
|
55
|
-
'browserPolicyRef',
|
|
56
|
-
'integrity',
|
|
57
|
-
'budgets',
|
|
58
|
-
'fixtureDigest',
|
|
59
|
-
'evidenceDigest',
|
|
60
|
-
'stylingContractDigest',
|
|
61
|
-
];
|
|
62
|
-
const TOKEN_KEYS = ['key', 'type', 'light', 'dark'];
|
|
63
|
-
const ASSET_KEYS = ['path', 'mediaType', 'byteLength', 'sha256', 'license'];
|
|
64
|
-
const BUDGET_KEYS = ['maximumFileBytes', 'maximumTotalBytes', 'maximumFiles'];
|
|
65
|
-
const PACKAGE_FILE_KEYS = ['path', 'kind', 'mode', 'bytes'];
|
|
66
|
-
const PACKAGE_JSON_KEYS = ['name', 'version', 'license', 'files'];
|
|
67
|
-
const LICENSE_EVIDENCE_KEYS = [
|
|
68
|
-
'profile',
|
|
69
|
-
'licenseListVersion',
|
|
70
|
-
'licenseListDigest',
|
|
71
|
-
'packageExpression',
|
|
72
|
-
'assetOverrides',
|
|
73
|
-
'catalogEntries',
|
|
74
|
-
];
|
|
75
|
-
const LICENSE_OVERRIDE_KEYS = ['path', 'expression'];
|
|
76
|
-
|
|
77
|
-
const STYLING_CONTRACT_KEYS = [
|
|
78
|
-
'profile',
|
|
79
|
-
'contractVersion',
|
|
80
|
-
'templatePackage',
|
|
81
|
-
'templateVersion',
|
|
82
|
-
'orderedLayers',
|
|
83
|
-
'stylesheetLayers',
|
|
84
|
-
'publicationRootSelector',
|
|
85
|
-
'resolvedPaletteSelectors',
|
|
86
|
-
'typeSelectors',
|
|
87
|
-
'classSelectors',
|
|
88
|
-
'idSelectors',
|
|
89
|
-
'attributes',
|
|
90
|
-
'pseudoClasses',
|
|
91
|
-
'pseudoElements',
|
|
92
|
-
'functionalPseudos',
|
|
93
|
-
'combinators',
|
|
94
|
-
'publicThemeSlotHooks',
|
|
95
|
-
'composition',
|
|
96
|
-
'catalogDigest',
|
|
97
|
-
];
|
|
98
|
-
const STYLE_ATTRIBUTE_KEYS = ['name', 'match', 'values', 'role'];
|
|
99
|
-
const STYLE_HOOK_KEYS = ['hookId', 'selectorAtom'];
|
|
100
|
-
const STYLESHEET_LAYER_KEYS = ['tokens', 'components', 'utilities', 'print'];
|
|
101
|
-
const PALETTE_SELECTOR_KEYS = ['light', 'dark'];
|
|
102
|
-
const COMPOSITION_KEYS = [
|
|
103
|
-
'rootScope',
|
|
104
|
-
'compoundOrder',
|
|
105
|
-
'functionalSelectorArguments',
|
|
106
|
-
'maximumFunctionalDepth',
|
|
107
|
-
'nthExpressionProfile',
|
|
108
|
-
];
|
|
109
|
-
|
|
110
|
-
const FIXTURE_RELEASE_KEYS = [
|
|
111
|
-
'profile',
|
|
112
|
-
'fixtureReleaseId',
|
|
113
|
-
'contractVersion',
|
|
114
|
-
'browserPolicyRef',
|
|
115
|
-
'binaryAssetProfile',
|
|
116
|
-
'stylingContractDigest',
|
|
117
|
-
'runners',
|
|
118
|
-
'fixtures',
|
|
119
|
-
'fixtureDigest',
|
|
120
|
-
];
|
|
121
|
-
const FIXTURE_RUNNER_KEYS = ['runnerId', 'version', 'executableDigest'];
|
|
122
|
-
const FIXTURE_DEFINITION_KEYS = [
|
|
123
|
-
'fixtureId',
|
|
124
|
-
'runnerId',
|
|
125
|
-
'inputDigest',
|
|
126
|
-
'expectedDisposition',
|
|
127
|
-
'expectedEvidenceDigest',
|
|
128
|
-
];
|
|
129
|
-
const CONFORMANCE_RESULT_KEYS = [
|
|
130
|
-
'profile',
|
|
131
|
-
'fixtureReleaseId',
|
|
132
|
-
'fixtureDigest',
|
|
133
|
-
'themeConformanceInputDigest',
|
|
134
|
-
'results',
|
|
135
|
-
'overallState',
|
|
136
|
-
'evidenceDigest',
|
|
137
|
-
];
|
|
138
|
-
const FIXTURE_RESULT_KEYS = [
|
|
139
|
-
'fixtureId',
|
|
140
|
-
'runnerId',
|
|
141
|
-
'observedDisposition',
|
|
142
|
-
'observedEvidenceDigest',
|
|
143
|
-
'state',
|
|
144
|
-
];
|
|
145
|
-
|
|
146
|
-
const CSS_EVIDENCE_BASE_KEYS = [
|
|
147
|
-
'path',
|
|
148
|
-
'profile',
|
|
149
|
-
'disposition',
|
|
150
|
-
'byteLength',
|
|
151
|
-
'sha256',
|
|
152
|
-
'outerLayer',
|
|
153
|
-
'usedSlotHookIds',
|
|
154
|
-
'referencedAssetPaths',
|
|
155
|
-
'fontFaceAssetPaths',
|
|
156
|
-
'metrics',
|
|
157
|
-
];
|
|
158
|
-
const CSS_METRIC_KEYS = [
|
|
159
|
-
'tokens',
|
|
160
|
-
'qualifiedRules',
|
|
161
|
-
'declarations',
|
|
162
|
-
'localUrls',
|
|
163
|
-
'fontFaces',
|
|
164
|
-
'pageRules',
|
|
165
|
-
'mediaRules',
|
|
166
|
-
'maximumBlockFunctionDepth',
|
|
167
|
-
'commentBytes',
|
|
168
|
-
];
|
|
169
|
-
const TOKEN_DECLARATION_KEYS = [
|
|
170
|
-
'lightSelector',
|
|
171
|
-
'darkSelector',
|
|
172
|
-
'light',
|
|
173
|
-
'dark',
|
|
174
|
-
];
|
|
175
|
-
const PASSIVE_EVIDENCE_KEYS = [
|
|
176
|
-
'path',
|
|
177
|
-
'mediaType',
|
|
178
|
-
'profile',
|
|
179
|
-
'disposition',
|
|
180
|
-
'byteLength',
|
|
181
|
-
'sha256',
|
|
182
|
-
];
|
|
183
|
-
const RUNNER_EVIDENCE_KEYS = ['runner', 'records'];
|
|
184
|
-
|
|
185
|
-
const THEME_TOKEN_CATALOG = Object.freeze([
|
|
186
|
-
['border-width', 'length'],
|
|
187
|
-
['color-accent', 'color'],
|
|
188
|
-
['color-border', 'color'],
|
|
189
|
-
['color-canvas', 'color'],
|
|
190
|
-
['color-code-canvas', 'color'],
|
|
191
|
-
['color-code-text', 'color'],
|
|
192
|
-
['color-danger', 'color'],
|
|
193
|
-
['color-focus', 'color'],
|
|
194
|
-
['color-link', 'color'],
|
|
195
|
-
['color-link-visited', 'color'],
|
|
196
|
-
['color-on-accent', 'color'],
|
|
197
|
-
['color-selection', 'color'],
|
|
198
|
-
['color-success', 'color'],
|
|
199
|
-
['color-surface', 'color'],
|
|
200
|
-
['color-surface-raised', 'color'],
|
|
201
|
-
['color-text', 'color'],
|
|
202
|
-
['color-text-muted', 'color'],
|
|
203
|
-
['color-warning', 'color'],
|
|
204
|
-
['content-measure', 'length'],
|
|
205
|
-
['focus-width', 'length'],
|
|
206
|
-
['font-body', 'font-family'],
|
|
207
|
-
['font-heading', 'font-family'],
|
|
208
|
-
['font-mono', 'font-family'],
|
|
209
|
-
['radius-medium', 'length'],
|
|
210
|
-
['radius-small', 'length'],
|
|
211
|
-
['space-1', 'length'],
|
|
212
|
-
['space-2', 'length'],
|
|
213
|
-
['space-3', 'length'],
|
|
214
|
-
['space-4', 'length'],
|
|
215
|
-
['space-6', 'length'],
|
|
216
|
-
['space-8', 'length'],
|
|
217
|
-
['weight-heading', 'font-weight'],
|
|
218
|
-
['weight-medium', 'font-weight'],
|
|
219
|
-
['weight-normal', 'font-weight'],
|
|
220
|
-
['weight-strong', 'font-weight'],
|
|
221
|
-
]);
|
|
222
|
-
|
|
223
|
-
const THEME_IDENTITIES = Object.freeze(
|
|
224
|
-
Object.fromEntries(
|
|
225
|
-
['default', 'amaze', 'flashy', 'minimal', 'zebra'].map((themeId) => [
|
|
226
|
-
themeId,
|
|
227
|
-
`@rathnasgala2/theme-${themeId}`,
|
|
228
|
-
]),
|
|
229
|
-
),
|
|
230
|
-
);
|
|
231
|
-
const STYLESHEET_VARIANTS = Object.freeze([
|
|
232
|
-
Object.freeze({
|
|
233
|
-
paths: Object.freeze(['tokens.css', 'components.css', 'print.css']),
|
|
234
|
-
layers: Object.freeze(['gala-tokens', 'gala-components', 'gala-print']),
|
|
235
|
-
}),
|
|
236
|
-
Object.freeze({
|
|
237
|
-
paths: Object.freeze([
|
|
238
|
-
'tokens.css',
|
|
239
|
-
'components.css',
|
|
240
|
-
'utilities.css',
|
|
241
|
-
'print.css',
|
|
242
|
-
]),
|
|
243
|
-
layers: Object.freeze([
|
|
244
|
-
'gala-tokens',
|
|
245
|
-
'gala-components',
|
|
246
|
-
'gala-utilities',
|
|
247
|
-
'gala-print',
|
|
248
|
-
]),
|
|
249
|
-
}),
|
|
250
|
-
]);
|
|
251
|
-
const MODES = Object.freeze(['dark', 'light', 'system']);
|
|
252
|
-
const ORDERED_LAYERS = Object.freeze([
|
|
253
|
-
'gala-tokens',
|
|
254
|
-
'gala-components',
|
|
255
|
-
'gala-utilities',
|
|
256
|
-
'gala-print',
|
|
257
|
-
]);
|
|
258
|
-
const FIXTURE_RUNNER_IDS = Object.freeze([
|
|
259
|
-
'schema',
|
|
260
|
-
'semantic',
|
|
261
|
-
'package',
|
|
262
|
-
'css',
|
|
263
|
-
'binary',
|
|
264
|
-
'browser',
|
|
265
|
-
'a11y',
|
|
266
|
-
'absence',
|
|
267
|
-
]);
|
|
268
|
-
/** @type {Readonly<Record<string, string>>} */
|
|
269
|
-
const MEDIA_BY_EXTENSION = Object.freeze({
|
|
270
|
-
'.woff2': 'font/woff2',
|
|
271
|
-
'.png': 'image/png',
|
|
272
|
-
'.jpg': 'image/jpeg',
|
|
273
|
-
'.webp': 'image/webp',
|
|
274
|
-
'.avif': 'image/avif',
|
|
275
|
-
'.svg': 'image/svg+xml',
|
|
276
|
-
});
|
|
277
|
-
/** @type {Readonly<Record<string, number>>} */
|
|
278
|
-
const PASSIVE_SOURCE_LIMITS = Object.freeze({
|
|
279
|
-
'font/woff2': 4_194_304,
|
|
280
|
-
'image/png': 16_777_216,
|
|
281
|
-
'image/jpeg': 16_777_216,
|
|
282
|
-
'image/webp': 16_777_216,
|
|
283
|
-
'image/avif': 16_777_216,
|
|
284
|
-
'image/svg+xml': 262_144,
|
|
285
|
-
});
|
|
286
|
-
/** @type {Readonly<Record<string, number>>} */
|
|
287
|
-
const CSS_METRIC_LIMITS = Object.freeze({
|
|
288
|
-
tokens: 32_768,
|
|
289
|
-
qualifiedRules: 4_096,
|
|
290
|
-
declarations: 32_768,
|
|
291
|
-
localUrls: 256,
|
|
292
|
-
fontFaces: 128,
|
|
293
|
-
pageRules: 64,
|
|
294
|
-
mediaRules: 512,
|
|
295
|
-
maximumBlockFunctionDepth: 16,
|
|
296
|
-
commentBytes: 1_048_576,
|
|
297
|
-
});
|
|
298
|
-
|
|
299
|
-
/** @typedef {[number, number, string]} UnicodePropertyRange */
|
|
300
|
-
|
|
301
|
-
const portableUnicodeTable =
|
|
302
|
-
/** @type {{ version: string, whiteSpace: UnicodePropertyRange[], noncharacter: UnicodePropertyRange[], defaultIgnorable: UnicodePropertyRange[] }} */ (
|
|
303
|
-
/** @type {unknown} */ (unicodeData)
|
|
304
|
-
);
|
|
305
|
-
if (portableUnicodeTable.version !== '17.0.0') {
|
|
306
|
-
throw new TypeError('UNICODE_GENERATED_DATA_INVALID');
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
/**
|
|
310
|
-
* @typedef {Record<string, unknown>} UnknownRecord
|
|
311
|
-
*/
|
|
312
|
-
|
|
313
|
-
/**
|
|
314
|
-
* @typedef {{ path: string, kind: 'file', mode: number, bytes: Uint8Array }} ThemePackageFile
|
|
315
|
-
*/
|
|
316
|
-
|
|
317
|
-
/**
|
|
318
|
-
* @typedef {{ path: string, byteLength: string, sha256: string }} ThemeEntry
|
|
319
|
-
*/
|
|
320
|
-
|
|
321
|
-
/**
|
|
322
|
-
* Throw one stable semantic diagnostic.
|
|
323
|
-
*
|
|
324
|
-
* @param {string} code diagnostic code
|
|
325
|
-
* @returns {never} never returns
|
|
326
|
-
*/
|
|
327
|
-
function invalid(code) {
|
|
328
|
-
throw new SemanticValidationError(code);
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/**
|
|
332
|
-
* Test whether a value is a plain object.
|
|
333
|
-
*
|
|
334
|
-
* @param {unknown} value candidate value
|
|
335
|
-
* @returns {value is UnknownRecord} whether the value is a plain object
|
|
336
|
-
*/
|
|
337
|
-
function isPlainObject(value) {
|
|
338
|
-
if (value === null || typeof value !== 'object' || Array.isArray(value)) {
|
|
339
|
-
return false;
|
|
340
|
-
}
|
|
341
|
-
const prototype = Object.getPrototypeOf(value);
|
|
342
|
-
return prototype === Object.prototype || prototype === null;
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
/**
|
|
346
|
-
* Require a closed plain object.
|
|
347
|
-
*
|
|
348
|
-
* @param {unknown} value candidate object
|
|
349
|
-
* @param {readonly string[]} keys exact key ledger
|
|
350
|
-
* @param {string} code failure diagnostic
|
|
351
|
-
* @returns {UnknownRecord} validated record
|
|
352
|
-
*/
|
|
353
|
-
function exactRecord(value, keys, code) {
|
|
354
|
-
if (!isPlainObject(value)) invalid(code);
|
|
355
|
-
const actual = Object.keys(value).sort();
|
|
356
|
-
const expected = [...keys].sort();
|
|
357
|
-
if (
|
|
358
|
-
actual.length !== expected.length ||
|
|
359
|
-
actual.some((key, index) => key !== expected[index])
|
|
360
|
-
) {
|
|
361
|
-
invalid(code);
|
|
362
|
-
}
|
|
363
|
-
return value;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
/**
|
|
367
|
-
* Compare two values by exact RFC 8785 bytes.
|
|
368
|
-
*
|
|
369
|
-
* @param {unknown} left first value
|
|
370
|
-
* @param {unknown} right second value
|
|
371
|
-
* @returns {boolean} whether canonical bytes are equal
|
|
372
|
-
*/
|
|
373
|
-
function jcsEqual(left, right) {
|
|
374
|
-
return canonicalizeJcs(left) === canonicalizeJcs(right);
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
/**
|
|
378
|
-
* Compare two strings by unsigned UTF-8 bytes.
|
|
379
|
-
*
|
|
380
|
-
* @param {string} left first string
|
|
381
|
-
* @param {string} right second string
|
|
382
|
-
* @returns {number} byte-order comparison
|
|
383
|
-
*/
|
|
384
|
-
function compareUtf8(left, right) {
|
|
385
|
-
return Buffer.compare(Buffer.from(left, 'utf8'), Buffer.from(right, 'utf8'));
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
/**
|
|
389
|
-
* Compare JSON values by their complete RFC 8785 encoded bytes.
|
|
390
|
-
*
|
|
391
|
-
* @param {unknown} left first value
|
|
392
|
-
* @param {unknown} right second value
|
|
393
|
-
* @returns {number} canonical-byte comparison
|
|
394
|
-
*/
|
|
395
|
-
function compareJcsValues(left, right) {
|
|
396
|
-
return Buffer.compare(
|
|
397
|
-
canonicalizeJcsBytes(left),
|
|
398
|
-
canonicalizeJcsBytes(right),
|
|
399
|
-
);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
/**
|
|
403
|
-
* Compare string values by their complete RFC 8785 encoded bytes.
|
|
404
|
-
*
|
|
405
|
-
* @param {string} left first string
|
|
406
|
-
* @param {string} right second string
|
|
407
|
-
* @returns {number} canonical-byte comparison
|
|
408
|
-
*/
|
|
409
|
-
function compareJcsStrings(left, right) {
|
|
410
|
-
return Buffer.compare(
|
|
411
|
-
Buffer.from(canonicalizeJcs(left), 'utf8'),
|
|
412
|
-
Buffer.from(canonicalizeJcs(right), 'utf8'),
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
/**
|
|
417
|
-
* Report whether a string contains any code unit in inclusive ranges.
|
|
418
|
-
*
|
|
419
|
-
* The caller has already rejected lone surrogates, so code-unit iteration is
|
|
420
|
-
* exact for the BMP control and bidi ranges used here.
|
|
421
|
-
*
|
|
422
|
-
* @param {string} value checked string
|
|
423
|
-
* @param {readonly (readonly [number, number])[]} ranges inclusive ranges
|
|
424
|
-
* @returns {boolean} whether a range contains a code unit
|
|
425
|
-
*/
|
|
426
|
-
function hasCodeUnitInRanges(value, ranges) {
|
|
427
|
-
for (let index = 0; index < value.length; index += 1) {
|
|
428
|
-
const codeUnit = value.charCodeAt(index);
|
|
429
|
-
if (ranges.some(([first, last]) => codeUnit >= first && codeUnit <= last)) {
|
|
430
|
-
return true;
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
return false;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
/**
|
|
437
|
-
* Test Unicode scalar membership in one generated sorted inclusive range set.
|
|
438
|
-
*
|
|
439
|
-
* @param {number} codePoint Unicode scalar value
|
|
440
|
-
* @param {UnicodePropertyRange[]} ranges generated property ranges
|
|
441
|
-
* @returns {boolean} membership
|
|
442
|
-
*/
|
|
443
|
-
function inUnicodeRanges(codePoint, ranges) {
|
|
444
|
-
let low = 0;
|
|
445
|
-
let high = ranges.length - 1;
|
|
446
|
-
while (low <= high) {
|
|
447
|
-
const middle = Math.floor((low + high) / 2);
|
|
448
|
-
const range = ranges[middle];
|
|
449
|
-
if (!range) return false;
|
|
450
|
-
if (codePoint < range[0]) high = middle - 1;
|
|
451
|
-
else if (codePoint > range[1]) low = middle + 1;
|
|
452
|
-
else return true;
|
|
453
|
-
}
|
|
454
|
-
return false;
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Test whether a Unicode scalar is forbidden by gala-portable-v2.
|
|
459
|
-
*
|
|
460
|
-
* @param {string} character one Unicode scalar
|
|
461
|
-
* @returns {boolean} whether the scalar is forbidden
|
|
462
|
-
*/
|
|
463
|
-
function forbiddenPortablePathScalar(character) {
|
|
464
|
-
const codePoint = character.codePointAt(0);
|
|
465
|
-
return (
|
|
466
|
-
codePoint === undefined ||
|
|
467
|
-
codePoint < 0x20 ||
|
|
468
|
-
(codePoint >= 0x7f && codePoint <= 0x9f) ||
|
|
469
|
-
['%', '<', '>', ':', '"', '|', '?', '*', '\\'].includes(character) ||
|
|
470
|
-
inUnicodeRanges(codePoint, portableUnicodeTable.defaultIgnorable) ||
|
|
471
|
-
inUnicodeRanges(codePoint, portableUnicodeTable.noncharacter)
|
|
472
|
-
);
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/**
|
|
476
|
-
* Test whether one segment begins or ends in Unicode 17 White_Space.
|
|
477
|
-
*
|
|
478
|
-
* @param {string} segment non-empty path segment
|
|
479
|
-
* @returns {boolean} whether either edge is White_Space
|
|
480
|
-
*/
|
|
481
|
-
function hasWhitespaceEdge(segment) {
|
|
482
|
-
const scalars = [...segment];
|
|
483
|
-
const first = scalars[0]?.codePointAt(0);
|
|
484
|
-
const last = scalars.at(-1)?.codePointAt(0);
|
|
485
|
-
return (
|
|
486
|
-
first === undefined ||
|
|
487
|
-
last === undefined ||
|
|
488
|
-
inUnicodeRanges(first, portableUnicodeTable.whiteSpace) ||
|
|
489
|
-
inUnicodeRanges(last, portableUnicodeTable.whiteSpace)
|
|
490
|
-
);
|
|
491
|
-
}
|
|
492
|
-
|
|
493
|
-
/**
|
|
494
|
-
* Test one gala-portable-v2 reserved path stem.
|
|
495
|
-
*
|
|
496
|
-
* @param {string} segment normalized path segment
|
|
497
|
-
* @returns {boolean} whether the stem is reserved
|
|
498
|
-
*/
|
|
499
|
-
function isReservedPortableStem(segment) {
|
|
500
|
-
const stem = segment.split('.', 1)[0];
|
|
501
|
-
if (!stem) return false;
|
|
502
|
-
const folded = unicodeCollisionKey17(stem);
|
|
503
|
-
return (
|
|
504
|
-
['con', 'prn', 'aux', 'nul'].includes(folded) ||
|
|
505
|
-
/^(?:com|lpt)[1-9]$/u.test(folded) ||
|
|
506
|
-
/^(?:com|lpt)[¹²³]$/u.test(folded)
|
|
507
|
-
);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
/**
|
|
511
|
-
* Require exact array contents.
|
|
512
|
-
*
|
|
513
|
-
* @param {unknown} value candidate array
|
|
514
|
-
* @param {readonly unknown[]} expected required sequence
|
|
515
|
-
* @param {string} code failure diagnostic
|
|
516
|
-
* @returns {void}
|
|
517
|
-
*/
|
|
518
|
-
function requireExactArray(value, expected, code) {
|
|
519
|
-
if (
|
|
520
|
-
!Array.isArray(value) ||
|
|
521
|
-
value.length !== expected.length ||
|
|
522
|
-
value.some((entry, index) => !jcsEqual(entry, expected[index]))
|
|
523
|
-
) {
|
|
524
|
-
invalid(code);
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
|
|
528
|
-
/**
|
|
529
|
-
* Require a tagged SHA-256 digest.
|
|
530
|
-
*
|
|
531
|
-
* @param {unknown} value candidate digest
|
|
532
|
-
* @param {string} code failure diagnostic
|
|
533
|
-
* @returns {string} checked digest
|
|
534
|
-
*/
|
|
535
|
-
function requireDigest(value, code) {
|
|
536
|
-
if (typeof value !== 'string' || !DIGEST_PATTERN.test(value)) invalid(code);
|
|
537
|
-
return value;
|
|
538
|
-
}
|
|
539
|
-
|
|
540
|
-
/**
|
|
541
|
-
* Require a canonical UUIDv7 stable ID.
|
|
542
|
-
*
|
|
543
|
-
* @param {unknown} value candidate identifier
|
|
544
|
-
* @param {string} code failure diagnostic
|
|
545
|
-
* @returns {string} checked identifier
|
|
546
|
-
*/
|
|
547
|
-
function requireStableId(value, code) {
|
|
548
|
-
if (typeof value !== 'string' || !STABLE_ID_PATTERN.test(value))
|
|
549
|
-
invalid(code);
|
|
550
|
-
return value;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* Require a canonical SemVer scalar while normalizing its diagnostic.
|
|
555
|
-
*
|
|
556
|
-
* @param {unknown} value candidate version
|
|
557
|
-
* @param {string} code failure diagnostic
|
|
558
|
-
* @returns {string} checked version
|
|
559
|
-
*/
|
|
560
|
-
function requireSemver(value, code) {
|
|
561
|
-
if (typeof value !== 'string') invalid(code);
|
|
562
|
-
try {
|
|
563
|
-
parseSemver(value);
|
|
564
|
-
} catch {
|
|
565
|
-
invalid(code);
|
|
566
|
-
}
|
|
567
|
-
return value;
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
/**
|
|
571
|
-
* Require a canonical SemVer range while normalizing its diagnostic.
|
|
572
|
-
*
|
|
573
|
-
* @param {unknown} value candidate range
|
|
574
|
-
* @param {string} code failure diagnostic
|
|
575
|
-
* @returns {string} checked range
|
|
576
|
-
*/
|
|
577
|
-
function requireSemverRange(value, code) {
|
|
578
|
-
if (typeof value !== 'string') invalid(code);
|
|
579
|
-
try {
|
|
580
|
-
parseSemverRange(value);
|
|
581
|
-
} catch {
|
|
582
|
-
invalid(code);
|
|
583
|
-
}
|
|
584
|
-
return value;
|
|
585
|
-
}
|
|
586
|
-
|
|
587
|
-
/**
|
|
588
|
-
* Require one canonical signed-64 non-negative or positive decimal.
|
|
589
|
-
*
|
|
590
|
-
* @param {unknown} value candidate decimal
|
|
591
|
-
* @param {boolean} positive whether zero is forbidden
|
|
592
|
-
* @param {string} code failure diagnostic
|
|
593
|
-
* @returns {bigint} checked numeric value
|
|
594
|
-
*/
|
|
595
|
-
function requireInt64(value, positive, code) {
|
|
596
|
-
const pattern = positive ? POSITIVE_INT64_PATTERN : NONNEGATIVE_INT64_PATTERN;
|
|
597
|
-
if (typeof value !== 'string' || !pattern.test(value)) invalid(code);
|
|
598
|
-
const numeric = BigInt(value);
|
|
599
|
-
if (numeric > INT64_MAXIMUM) invalid(code);
|
|
600
|
-
return numeric;
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
/**
|
|
604
|
-
* Require normalized bounded plain-label text.
|
|
605
|
-
*
|
|
606
|
-
* @param {unknown} value candidate label
|
|
607
|
-
* @param {string} code failure diagnostic
|
|
608
|
-
* @returns {string} checked label
|
|
609
|
-
*/
|
|
610
|
-
function requirePlainLabel(value, code) {
|
|
611
|
-
if (typeof value !== 'string') invalid(code);
|
|
612
|
-
try {
|
|
613
|
-
assertUnicodeScalarString(value);
|
|
614
|
-
} catch {
|
|
615
|
-
invalid(code);
|
|
616
|
-
}
|
|
617
|
-
if (
|
|
618
|
-
normalizeNfc17(value) !== value ||
|
|
619
|
-
graphemeLength17(value) < 1 ||
|
|
620
|
-
graphemeLength17(value) > 80 ||
|
|
621
|
-
value.includes('<') ||
|
|
622
|
-
value.includes('>') ||
|
|
623
|
-
hasCodeUnitInRanges(value, [
|
|
624
|
-
[0x00, 0x1f],
|
|
625
|
-
[0x7f, 0x9f],
|
|
626
|
-
[0x202a, 0x202e],
|
|
627
|
-
[0x2066, 0x2069],
|
|
628
|
-
])
|
|
629
|
-
) {
|
|
630
|
-
invalid(code);
|
|
631
|
-
}
|
|
632
|
-
return value;
|
|
633
|
-
}
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* Require a normalized repository-relative path.
|
|
637
|
-
*
|
|
638
|
-
* @param {unknown} value candidate path
|
|
639
|
-
* @param {string} code failure diagnostic
|
|
640
|
-
* @returns {string} checked path
|
|
641
|
-
*/
|
|
642
|
-
function requireRepositoryPath(value, code) {
|
|
643
|
-
if (typeof value !== 'string') invalid(code);
|
|
644
|
-
try {
|
|
645
|
-
assertUnicodeScalarString(value);
|
|
646
|
-
} catch {
|
|
647
|
-
invalid(code);
|
|
648
|
-
}
|
|
649
|
-
if (
|
|
650
|
-
Buffer.byteLength(value, 'utf8') < 1 ||
|
|
651
|
-
Buffer.byteLength(value, 'utf8') > 512 ||
|
|
652
|
-
normalizeNfc17(value) !== value ||
|
|
653
|
-
value.startsWith('/') ||
|
|
654
|
-
value.endsWith('/') ||
|
|
655
|
-
value.includes('//') ||
|
|
656
|
-
value.includes('\\') ||
|
|
657
|
-
value.includes('%') ||
|
|
658
|
-
hasCodeUnitInRanges(value, [
|
|
659
|
-
[0x00, 0x1f],
|
|
660
|
-
[0x7f, 0x9f],
|
|
661
|
-
])
|
|
662
|
-
) {
|
|
663
|
-
invalid(code);
|
|
664
|
-
}
|
|
665
|
-
const segments = value.split('/');
|
|
666
|
-
if (
|
|
667
|
-
segments.some(
|
|
668
|
-
(segment) =>
|
|
669
|
-
segment === '.' ||
|
|
670
|
-
segment === '..' ||
|
|
671
|
-
Buffer.byteLength(segment, 'utf8') > 128 ||
|
|
672
|
-
hasWhitespaceEdge(segment) ||
|
|
673
|
-
segment.endsWith('.') ||
|
|
674
|
-
[...segment].some(forbiddenPortablePathScalar) ||
|
|
675
|
-
isReservedPortableStem(segment),
|
|
676
|
-
)
|
|
677
|
-
) {
|
|
678
|
-
invalid(code);
|
|
679
|
-
}
|
|
680
|
-
return value;
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
/**
|
|
684
|
-
* Require an array of unique, byte-sorted strings.
|
|
685
|
-
*
|
|
686
|
-
* @param {unknown} value candidate array
|
|
687
|
-
* @param {number} minimum minimum length
|
|
688
|
-
* @param {number} maximum maximum length
|
|
689
|
-
* @param {(entry: unknown) => string} validateEntry element validator
|
|
690
|
-
* @param {string} code failure diagnostic
|
|
691
|
-
* @param {(left: string, right: string) => number} [compare] order comparator
|
|
692
|
-
* @returns {string[]} checked array
|
|
693
|
-
*/
|
|
694
|
-
function requireSortedStringSet(
|
|
695
|
-
value,
|
|
696
|
-
minimum,
|
|
697
|
-
maximum,
|
|
698
|
-
validateEntry,
|
|
699
|
-
code,
|
|
700
|
-
compare = compareUtf8,
|
|
701
|
-
) {
|
|
702
|
-
if (
|
|
703
|
-
!Array.isArray(value) ||
|
|
704
|
-
value.length < minimum ||
|
|
705
|
-
value.length > maximum
|
|
706
|
-
) {
|
|
707
|
-
invalid(code);
|
|
708
|
-
}
|
|
709
|
-
const checked = value.map(validateEntry);
|
|
710
|
-
for (let index = 1; index < checked.length; index += 1) {
|
|
711
|
-
const previous = checked[index - 1];
|
|
712
|
-
const current = checked[index];
|
|
713
|
-
if (
|
|
714
|
-
previous === undefined ||
|
|
715
|
-
current === undefined ||
|
|
716
|
-
compare(previous, current) >= 0
|
|
717
|
-
) {
|
|
718
|
-
invalid(code);
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
|
-
return checked;
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
/**
|
|
725
|
-
* Require one 1..64-byte style selector name/value.
|
|
726
|
-
*
|
|
727
|
-
* @param {unknown} value candidate style scalar
|
|
728
|
-
* @param {string} code failure diagnostic
|
|
729
|
-
* @returns {string} checked value
|
|
730
|
-
*/
|
|
731
|
-
function requireStyleName(value, code) {
|
|
732
|
-
if (
|
|
733
|
-
typeof value !== 'string' ||
|
|
734
|
-
Buffer.byteLength(value, 'utf8') > 64 ||
|
|
735
|
-
!STYLE_NAME_PATTERN.test(value)
|
|
736
|
-
) {
|
|
737
|
-
invalid(code);
|
|
738
|
-
}
|
|
739
|
-
return value;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
/**
|
|
743
|
-
* Require exact compact JCS bytes for an object.
|
|
744
|
-
*
|
|
745
|
-
* @param {unknown} bytes candidate retained bytes
|
|
746
|
-
* @param {unknown} value represented object
|
|
747
|
-
* @param {string} code failure diagnostic
|
|
748
|
-
* @returns {void}
|
|
749
|
-
*/
|
|
750
|
-
function requireCanonicalBytes(bytes, value, code) {
|
|
751
|
-
if (
|
|
752
|
-
!(bytes instanceof Uint8Array) ||
|
|
753
|
-
!Buffer.from(bytes).equals(canonicalizeJcsBytes(value))
|
|
754
|
-
) {
|
|
755
|
-
invalid(code);
|
|
756
|
-
}
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
/**
|
|
760
|
-
* Parse one retained JSON file and normalize all parser failures.
|
|
761
|
-
*
|
|
762
|
-
* @param {Uint8Array} bytes exact file bytes
|
|
763
|
-
* @param {string} code failure diagnostic
|
|
764
|
-
* @returns {unknown} parsed I-JSON value
|
|
765
|
-
*/
|
|
766
|
-
function parseRetainedJson(bytes, code) {
|
|
767
|
-
try {
|
|
768
|
-
return parseDuplicateFreeIJson(bytes);
|
|
769
|
-
} catch {
|
|
770
|
-
invalid(code);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
/**
|
|
775
|
-
* Return one package's exact package name and version.
|
|
776
|
-
*
|
|
777
|
-
* @param {unknown} value candidate packageExact scalar
|
|
778
|
-
* @param {string} code failure diagnostic
|
|
779
|
-
* @returns {{ name: string, version: string }} parsed identity
|
|
780
|
-
*/
|
|
781
|
-
function parsePackageExact(value, code) {
|
|
782
|
-
if (typeof value !== 'string') invalid(code);
|
|
783
|
-
const separator = value.lastIndexOf('@');
|
|
784
|
-
if (separator <= 0) invalid(code);
|
|
785
|
-
const name = value.slice(0, separator);
|
|
786
|
-
const version = value.slice(separator + 1);
|
|
787
|
-
if (
|
|
788
|
-
Buffer.byteLength(name, 'utf8') > 214 ||
|
|
789
|
-
!PACKAGE_NAME_PATTERN.test(name)
|
|
790
|
-
) {
|
|
791
|
-
invalid(code);
|
|
792
|
-
}
|
|
793
|
-
requireSemver(version, code);
|
|
794
|
-
return { name, version };
|
|
795
|
-
}
|
|
796
|
-
|
|
797
|
-
/**
|
|
798
|
-
* Return whether a string array exactly equals another sequence.
|
|
799
|
-
*
|
|
800
|
-
* @param {unknown} value candidate array
|
|
801
|
-
* @param {readonly string[]} expected required strings
|
|
802
|
-
* @returns {boolean} exact equality
|
|
803
|
-
*/
|
|
804
|
-
function stringArrayEquals(value, expected) {
|
|
805
|
-
return (
|
|
806
|
-
Array.isArray(value) &&
|
|
807
|
-
value.length === expected.length &&
|
|
808
|
-
value.every((entry, index) => entry === expected[index])
|
|
809
|
-
);
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
/**
|
|
813
|
-
* Validate the intentionally empty MVP template-composition projection.
|
|
814
|
-
*
|
|
815
|
-
* @param {unknown} value template-composition instance
|
|
816
|
-
* @returns {void}
|
|
817
|
-
*/
|
|
818
|
-
export function validateTemplateComposition(value) {
|
|
819
|
-
const record = exactRecord(
|
|
820
|
-
value,
|
|
821
|
-
TEMPLATE_COMPOSITION_KEYS,
|
|
822
|
-
'TEMPLATE_COMPOSITION_INVALID',
|
|
823
|
-
);
|
|
824
|
-
if (
|
|
825
|
-
record.schemaId !== 'urn:gala:schema:template-composition:2.0.0' ||
|
|
826
|
-
record.schemaVersion !== '2.0.0'
|
|
827
|
-
) {
|
|
828
|
-
invalid('TEMPLATE_COMPOSITION_INVALID');
|
|
829
|
-
}
|
|
830
|
-
}
|
|
831
|
-
|
|
832
|
-
/**
|
|
833
|
-
* Validate one exact 35-row theme token catalog.
|
|
834
|
-
*
|
|
835
|
-
* @param {unknown} value candidate token array
|
|
836
|
-
* @returns {void}
|
|
837
|
-
*/
|
|
838
|
-
function validateThemeTokens(value) {
|
|
839
|
-
const code = 'THEME_TOKEN_CATALOG_INVALID';
|
|
840
|
-
if (!Array.isArray(value) || value.length !== THEME_TOKEN_CATALOG.length) {
|
|
841
|
-
invalid(code);
|
|
842
|
-
}
|
|
843
|
-
for (let index = 0; index < THEME_TOKEN_CATALOG.length; index += 1) {
|
|
844
|
-
const expected = THEME_TOKEN_CATALOG[index];
|
|
845
|
-
const token = exactRecord(value[index], TOKEN_KEYS, code);
|
|
846
|
-
if (!expected || token.key !== expected[0] || token.type !== expected[1]) {
|
|
847
|
-
invalid(code);
|
|
848
|
-
}
|
|
849
|
-
if (typeof token.light !== 'string' || typeof token.dark !== 'string') {
|
|
850
|
-
invalid(code);
|
|
851
|
-
}
|
|
852
|
-
let valid = false;
|
|
853
|
-
if (token.type === 'color') {
|
|
854
|
-
valid = COLOR_PATTERN.test(token.light) && COLOR_PATTERN.test(token.dark);
|
|
855
|
-
} else if (token.type === 'length') {
|
|
856
|
-
valid =
|
|
857
|
-
LENGTH_PATTERN.test(token.light) && LENGTH_PATTERN.test(token.dark);
|
|
858
|
-
} else if (token.type === 'font-family') {
|
|
859
|
-
valid =
|
|
860
|
-
FONT_FAMILY_PATTERN.test(token.light) &&
|
|
861
|
-
FONT_FAMILY_PATTERN.test(token.dark) &&
|
|
862
|
-
token.light
|
|
863
|
-
.split(', ')
|
|
864
|
-
.every((component) => Buffer.byteLength(component, 'ascii') <= 64) &&
|
|
865
|
-
token.dark
|
|
866
|
-
.split(', ')
|
|
867
|
-
.every((component) => Buffer.byteLength(component, 'ascii') <= 64);
|
|
868
|
-
} else if (token.type === 'font-weight') {
|
|
869
|
-
valid =
|
|
870
|
-
FONT_WEIGHT_PATTERN.test(token.light) &&
|
|
871
|
-
FONT_WEIGHT_PATTERN.test(token.dark);
|
|
872
|
-
}
|
|
873
|
-
if (!valid || (token.type !== 'color' && token.light !== token.dark)) {
|
|
874
|
-
invalid(code);
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
}
|
|
878
|
-
|
|
879
|
-
/**
|
|
880
|
-
* Validate one passive-asset manifest row.
|
|
881
|
-
*
|
|
882
|
-
* @param {unknown} value candidate row
|
|
883
|
-
* @returns {UnknownRecord} checked row
|
|
884
|
-
*/
|
|
885
|
-
function validatePassiveAsset(value) {
|
|
886
|
-
const code = 'THEME_PASSIVE_ASSET_INVALID';
|
|
887
|
-
const asset = exactRecord(value, ASSET_KEYS, code);
|
|
888
|
-
requireRepositoryPath(asset.path, code);
|
|
889
|
-
if (
|
|
890
|
-
typeof asset.mediaType !== 'string' ||
|
|
891
|
-
![
|
|
892
|
-
'text/css',
|
|
893
|
-
'font/woff2',
|
|
894
|
-
'image/png',
|
|
895
|
-
'image/jpeg',
|
|
896
|
-
'image/webp',
|
|
897
|
-
'image/avif',
|
|
898
|
-
'image/svg+xml',
|
|
899
|
-
].includes(asset.mediaType)
|
|
900
|
-
) {
|
|
901
|
-
invalid(code);
|
|
902
|
-
}
|
|
903
|
-
requireInt64(asset.byteLength, false, code);
|
|
904
|
-
requireDigest(asset.sha256, code);
|
|
905
|
-
if (typeof asset.license !== 'string') invalid(code);
|
|
906
|
-
try {
|
|
907
|
-
validateSpdxExpression(asset.license);
|
|
908
|
-
} catch {
|
|
909
|
-
invalid(code);
|
|
910
|
-
}
|
|
911
|
-
return asset;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
/**
|
|
915
|
-
* Validate declared theme budgets and return their numeric values.
|
|
916
|
-
*
|
|
917
|
-
* @param {unknown} value candidate budget record
|
|
918
|
-
* @param {string} [code] failure diagnostic
|
|
919
|
-
* @returns {{ maximumFileBytes: bigint, maximumTotalBytes: bigint, maximumFiles: number }} numeric budgets
|
|
920
|
-
*/
|
|
921
|
-
function validateBudgets(value, code = 'THEME_BUDGET_INVALID') {
|
|
922
|
-
const budgets = exactRecord(value, BUDGET_KEYS, code);
|
|
923
|
-
const maximumFileBytes = requireInt64(budgets.maximumFileBytes, true, code);
|
|
924
|
-
const maximumTotalBytes = requireInt64(budgets.maximumTotalBytes, true, code);
|
|
925
|
-
if (
|
|
926
|
-
!Number.isInteger(budgets.maximumFiles) ||
|
|
927
|
-
Number(budgets.maximumFiles) < 1 ||
|
|
928
|
-
Number(budgets.maximumFiles) > 512
|
|
929
|
-
) {
|
|
930
|
-
invalid(code);
|
|
931
|
-
}
|
|
932
|
-
return {
|
|
933
|
-
maximumFileBytes,
|
|
934
|
-
maximumTotalBytes,
|
|
935
|
-
maximumFiles: Number(budgets.maximumFiles),
|
|
936
|
-
};
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
/**
|
|
940
|
-
* Validate the closed theme-contract instance independent of external records.
|
|
941
|
-
*
|
|
942
|
-
* @param {unknown} value theme-contract instance
|
|
943
|
-
* @returns {void}
|
|
944
|
-
*/
|
|
945
|
-
export function validateThemeContract(value) {
|
|
946
|
-
const code = 'THEME_CONTRACT_INVALID';
|
|
947
|
-
const theme = exactRecord(value, THEME_KEYS, code);
|
|
948
|
-
if (
|
|
949
|
-
theme.schemaId !== 'urn:gala:schema:theme-contract:2.0.0' ||
|
|
950
|
-
theme.schemaVersion !== '2.0.0' ||
|
|
951
|
-
typeof theme.themeId !== 'string' ||
|
|
952
|
-
!Object.hasOwn(THEME_IDENTITIES, theme.themeId)
|
|
953
|
-
) {
|
|
954
|
-
invalid(code);
|
|
955
|
-
}
|
|
956
|
-
|
|
957
|
-
const identity = parsePackageExact(theme.package, code);
|
|
958
|
-
if (identity.name !== THEME_IDENTITIES[theme.themeId]) invalid(code);
|
|
959
|
-
requireSemver(theme.contractVersion, code);
|
|
960
|
-
requireSemverRange(theme.templateRange, code);
|
|
961
|
-
|
|
962
|
-
const variant = STYLESHEET_VARIANTS.find(
|
|
963
|
-
({ paths, layers }) =>
|
|
964
|
-
stringArrayEquals(theme.stylesheets, paths) &&
|
|
965
|
-
stringArrayEquals(theme.cssLayers, layers),
|
|
966
|
-
);
|
|
967
|
-
if (!variant) invalid(code);
|
|
968
|
-
|
|
969
|
-
requireSortedStringSet(
|
|
970
|
-
theme.slotHooks,
|
|
971
|
-
1,
|
|
972
|
-
64,
|
|
973
|
-
(entry) => requirePlainLabel(entry, code),
|
|
974
|
-
code,
|
|
975
|
-
compareJcsStrings,
|
|
976
|
-
);
|
|
977
|
-
validateThemeTokens(theme.tokens);
|
|
978
|
-
requireExactArray(theme.modes, MODES, code);
|
|
979
|
-
|
|
980
|
-
if (!Array.isArray(theme.assets) || theme.assets.length > 256) invalid(code);
|
|
981
|
-
const assetPaths = new Set();
|
|
982
|
-
for (const candidate of theme.assets) {
|
|
983
|
-
const asset = validatePassiveAsset(candidate);
|
|
984
|
-
if (typeof asset.path !== 'string' || assetPaths.has(asset.path))
|
|
985
|
-
invalid(code);
|
|
986
|
-
assetPaths.add(asset.path);
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
requireSortedStringSet(
|
|
990
|
-
theme.fixtures,
|
|
991
|
-
1,
|
|
992
|
-
64,
|
|
993
|
-
(entry) => requirePlainLabel(entry, code),
|
|
994
|
-
code,
|
|
995
|
-
);
|
|
996
|
-
if (theme.browserPolicyRef !== 'gala-theme-css-v2-20211224') invalid(code);
|
|
997
|
-
requireDigest(theme.integrity, code);
|
|
998
|
-
validateBudgets(theme.budgets);
|
|
999
|
-
requireDigest(theme.fixtureDigest, code);
|
|
1000
|
-
requireDigest(theme.evidenceDigest, code);
|
|
1001
|
-
requireDigest(theme.stylingContractDigest, code);
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
/**
|
|
1005
|
-
* Compute the exact self-excluding template styling-contract digest.
|
|
1006
|
-
*
|
|
1007
|
-
* @param {unknown} contract complete styling-contract record
|
|
1008
|
-
* @returns {string} tagged digest
|
|
1009
|
-
*/
|
|
1010
|
-
export function computeTemplateStylingContractDigest(contract) {
|
|
1011
|
-
const profile = ACTIVE_DIGEST_PROFILES.templateStylingContract;
|
|
1012
|
-
if (!profile) throw new TypeError('DIGEST_PROFILE_MISSING');
|
|
1013
|
-
return profile.digest(contract);
|
|
1014
|
-
}
|
|
1015
|
-
|
|
1016
|
-
/**
|
|
1017
|
-
* Build the exact public-hook atom catalog and count each atom occurrence.
|
|
1018
|
-
*
|
|
1019
|
-
* @param {UnknownRecord} contract validated styling contract
|
|
1020
|
-
* @param {string} code failure diagnostic
|
|
1021
|
-
* @returns {Map<string, number>} atom occurrence counts
|
|
1022
|
-
*/
|
|
1023
|
-
function buildHookAtomCatalog(contract, code) {
|
|
1024
|
-
/** @type {Map<string, number>} */
|
|
1025
|
-
const atoms = new Map();
|
|
1026
|
-
/**
|
|
1027
|
-
* @param {string} atom selector atom
|
|
1028
|
-
* @returns {void}
|
|
1029
|
-
*/
|
|
1030
|
-
const add = (atom) => {
|
|
1031
|
-
atoms.set(atom, (atoms.get(atom) ?? 0) + 1);
|
|
1032
|
-
};
|
|
1033
|
-
|
|
1034
|
-
for (const selector of /** @type {string[]} */ (contract.typeSelectors)) {
|
|
1035
|
-
add(selector);
|
|
1036
|
-
}
|
|
1037
|
-
for (const selector of /** @type {string[]} */ (contract.classSelectors)) {
|
|
1038
|
-
add(`.${selector}`);
|
|
1039
|
-
}
|
|
1040
|
-
for (const selector of /** @type {string[]} */ (contract.idSelectors)) {
|
|
1041
|
-
add(`#${selector}`);
|
|
1042
|
-
}
|
|
1043
|
-
for (const candidate of /** @type {unknown[]} */ (contract.attributes)) {
|
|
1044
|
-
const attribute = exactRecord(candidate, STYLE_ATTRIBUTE_KEYS, code);
|
|
1045
|
-
if (
|
|
1046
|
-
attribute.name === 'data-gala-publication-root' ||
|
|
1047
|
-
attribute.name === 'data-gala-resolved-color-mode'
|
|
1048
|
-
) {
|
|
1049
|
-
continue;
|
|
1050
|
-
}
|
|
1051
|
-
if (attribute.match === 'presence') {
|
|
1052
|
-
add(`[${String(attribute.name)}]`);
|
|
1053
|
-
} else {
|
|
1054
|
-
for (const value of /** @type {string[]} */ (attribute.values)) {
|
|
1055
|
-
add(`[${String(attribute.name)}="${value}"]`);
|
|
1056
|
-
}
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
return atoms;
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
/**
|
|
1063
|
-
* Validate the selected template's exact immutable styling contract.
|
|
1064
|
-
*
|
|
1065
|
-
* `context.bytes` is the retained
|
|
1066
|
-
* `contracts/theme-styling-contract.jcs` member. `context.lockedTemplate` is
|
|
1067
|
-
* the integrity-verified selected lock row; no package or digest fields are
|
|
1068
|
-
* synthesized by this validator.
|
|
1069
|
-
*
|
|
1070
|
-
* @param {unknown} value template styling-contract record
|
|
1071
|
-
* @param {unknown} context retained bytes and selected template identity
|
|
1072
|
-
* @returns {void}
|
|
1073
|
-
*/
|
|
1074
|
-
export function validateTemplateStylingContract(value, context) {
|
|
1075
|
-
const code = 'TEMPLATE_STYLING_CONTRACT_INVALID';
|
|
1076
|
-
const contract = exactRecord(value, STYLING_CONTRACT_KEYS, code);
|
|
1077
|
-
const retained = exactRecord(context, ['bytes', 'lockedTemplate'], code);
|
|
1078
|
-
const lockedTemplate = isPlainObject(retained.lockedTemplate)
|
|
1079
|
-
? retained.lockedTemplate
|
|
1080
|
-
: invalid(code);
|
|
1081
|
-
|
|
1082
|
-
if (
|
|
1083
|
-
contract.profile !== 'gala-template-styling-contract-v2' ||
|
|
1084
|
-
contract.contractVersion !== '2.0.0' ||
|
|
1085
|
-
contract.templatePackage !== '@rathnasgala2/template' ||
|
|
1086
|
-
contract.templatePackage !== lockedTemplate.package ||
|
|
1087
|
-
contract.templateVersion !== lockedTemplate.version
|
|
1088
|
-
) {
|
|
1089
|
-
invalid(code);
|
|
1090
|
-
}
|
|
1091
|
-
requireSemver(contract.templateVersion, code);
|
|
1092
|
-
requireCanonicalBytes(retained.bytes, contract, code);
|
|
1093
|
-
requireExactArray(contract.orderedLayers, ORDERED_LAYERS, code);
|
|
1094
|
-
|
|
1095
|
-
const layers = exactRecord(
|
|
1096
|
-
contract.stylesheetLayers,
|
|
1097
|
-
STYLESHEET_LAYER_KEYS,
|
|
1098
|
-
code,
|
|
1099
|
-
);
|
|
1100
|
-
if (
|
|
1101
|
-
layers.tokens !== 'gala-tokens' ||
|
|
1102
|
-
layers.components !== 'gala-components' ||
|
|
1103
|
-
layers.utilities !== 'gala-utilities' ||
|
|
1104
|
-
layers.print !== 'gala-print'
|
|
1105
|
-
) {
|
|
1106
|
-
invalid(code);
|
|
1107
|
-
}
|
|
1108
|
-
if (contract.publicationRootSelector !== '[data-gala-publication-root]') {
|
|
1109
|
-
invalid(code);
|
|
1110
|
-
}
|
|
1111
|
-
const palettes = exactRecord(
|
|
1112
|
-
contract.resolvedPaletteSelectors,
|
|
1113
|
-
PALETTE_SELECTOR_KEYS,
|
|
1114
|
-
code,
|
|
1115
|
-
);
|
|
1116
|
-
if (
|
|
1117
|
-
palettes.light !==
|
|
1118
|
-
'[data-gala-publication-root][data-gala-resolved-color-mode="light"]' ||
|
|
1119
|
-
palettes.dark !==
|
|
1120
|
-
'[data-gala-publication-root][data-gala-resolved-color-mode="dark"]'
|
|
1121
|
-
) {
|
|
1122
|
-
invalid(code);
|
|
1123
|
-
}
|
|
1124
|
-
|
|
1125
|
-
/** @type {readonly (readonly [string, number])[]} */
|
|
1126
|
-
const selectorSets = [
|
|
1127
|
-
['typeSelectors', 64],
|
|
1128
|
-
['classSelectors', 256],
|
|
1129
|
-
['idSelectors', 64],
|
|
1130
|
-
['pseudoClasses', 64],
|
|
1131
|
-
];
|
|
1132
|
-
for (const [member, maximum] of selectorSets) {
|
|
1133
|
-
requireSortedStringSet(
|
|
1134
|
-
contract[member],
|
|
1135
|
-
0,
|
|
1136
|
-
maximum,
|
|
1137
|
-
(entry) => requireStyleName(entry, code),
|
|
1138
|
-
code,
|
|
1139
|
-
);
|
|
1140
|
-
}
|
|
1141
|
-
|
|
1142
|
-
if (
|
|
1143
|
-
!Array.isArray(contract.attributes) ||
|
|
1144
|
-
contract.attributes.length < 2 ||
|
|
1145
|
-
contract.attributes.length > 128
|
|
1146
|
-
) {
|
|
1147
|
-
invalid(code);
|
|
1148
|
-
}
|
|
1149
|
-
/** @type {UnknownRecord | undefined} */
|
|
1150
|
-
let previousAttribute;
|
|
1151
|
-
const attributeNames = new Set();
|
|
1152
|
-
let rootRows = 0;
|
|
1153
|
-
let paletteRows = 0;
|
|
1154
|
-
for (const candidate of contract.attributes) {
|
|
1155
|
-
const attribute = exactRecord(candidate, STYLE_ATTRIBUTE_KEYS, code);
|
|
1156
|
-
const name = requireStyleName(attribute.name, code);
|
|
1157
|
-
if (attributeNames.has(name)) invalid(code);
|
|
1158
|
-
if (!['presence', 'exact-value'].includes(String(attribute.match))) {
|
|
1159
|
-
invalid(code);
|
|
1160
|
-
}
|
|
1161
|
-
if (!['root', 'state', 'semantic'].includes(String(attribute.role))) {
|
|
1162
|
-
invalid(code);
|
|
1163
|
-
}
|
|
1164
|
-
const values = requireSortedStringSet(
|
|
1165
|
-
attribute.values,
|
|
1166
|
-
attribute.match === 'presence' ? 0 : 1,
|
|
1167
|
-
32,
|
|
1168
|
-
(entry) => requireStyleName(entry, code),
|
|
1169
|
-
code,
|
|
1170
|
-
);
|
|
1171
|
-
if (attribute.match === 'presence' && values.length !== 0) invalid(code);
|
|
1172
|
-
|
|
1173
|
-
if (
|
|
1174
|
-
name === 'data-gala-publication-root' &&
|
|
1175
|
-
attribute.match === 'presence' &&
|
|
1176
|
-
attribute.role === 'root' &&
|
|
1177
|
-
values.length === 0
|
|
1178
|
-
) {
|
|
1179
|
-
rootRows += 1;
|
|
1180
|
-
} else if (attribute.role === 'root') {
|
|
1181
|
-
invalid(code);
|
|
1182
|
-
}
|
|
1183
|
-
if (
|
|
1184
|
-
name === 'data-gala-resolved-color-mode' &&
|
|
1185
|
-
attribute.match === 'exact-value' &&
|
|
1186
|
-
attribute.role === 'state' &&
|
|
1187
|
-
stringArrayEquals(values, ['dark', 'light'])
|
|
1188
|
-
) {
|
|
1189
|
-
paletteRows += 1;
|
|
1190
|
-
} else if (name === 'data-gala-resolved-color-mode') {
|
|
1191
|
-
invalid(code);
|
|
1192
|
-
}
|
|
1193
|
-
if (
|
|
1194
|
-
previousAttribute !== undefined &&
|
|
1195
|
-
compareJcsValues(previousAttribute, attribute) >= 0
|
|
1196
|
-
) {
|
|
1197
|
-
invalid(code);
|
|
1198
|
-
}
|
|
1199
|
-
previousAttribute = attribute;
|
|
1200
|
-
attributeNames.add(name);
|
|
1201
|
-
}
|
|
1202
|
-
if (rootRows !== 1 || paletteRows !== 1) invalid(code);
|
|
1203
|
-
|
|
1204
|
-
requireExactArray(
|
|
1205
|
-
contract.pseudoElements,
|
|
1206
|
-
['after', 'before', 'marker', 'selection'],
|
|
1207
|
-
code,
|
|
1208
|
-
);
|
|
1209
|
-
requireExactArray(
|
|
1210
|
-
contract.functionalPseudos,
|
|
1211
|
-
['is', 'where', 'not', 'nth-child', 'nth-last-child'],
|
|
1212
|
-
code,
|
|
1213
|
-
);
|
|
1214
|
-
requireExactArray(contract.combinators, [' ', ' > ', ' + ', ' ~ '], code);
|
|
1215
|
-
|
|
1216
|
-
const composition = exactRecord(contract.composition, COMPOSITION_KEYS, code);
|
|
1217
|
-
if (
|
|
1218
|
-
composition.rootScope !== 'first-compound-required' ||
|
|
1219
|
-
!stringArrayEquals(composition.compoundOrder, [
|
|
1220
|
-
'type',
|
|
1221
|
-
'id',
|
|
1222
|
-
'class',
|
|
1223
|
-
'attribute',
|
|
1224
|
-
'pseudo-class',
|
|
1225
|
-
'pseudo-element',
|
|
1226
|
-
]) ||
|
|
1227
|
-
composition.functionalSelectorArguments !== 'compound-only' ||
|
|
1228
|
-
composition.maximumFunctionalDepth !== 1 ||
|
|
1229
|
-
composition.nthExpressionProfile !== 'gala-positive-an-plus-b-v2'
|
|
1230
|
-
) {
|
|
1231
|
-
invalid(code);
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
if (
|
|
1235
|
-
!Array.isArray(contract.publicThemeSlotHooks) ||
|
|
1236
|
-
contract.publicThemeSlotHooks.length < 1 ||
|
|
1237
|
-
contract.publicThemeSlotHooks.length > 64
|
|
1238
|
-
) {
|
|
1239
|
-
invalid(code);
|
|
1240
|
-
}
|
|
1241
|
-
const atomCatalog = buildHookAtomCatalog(contract, code);
|
|
1242
|
-
let previousHookId = '';
|
|
1243
|
-
const hookAtoms = new Set();
|
|
1244
|
-
for (const candidate of contract.publicThemeSlotHooks) {
|
|
1245
|
-
const hook = exactRecord(candidate, STYLE_HOOK_KEYS, code);
|
|
1246
|
-
const hookId = requirePlainLabel(hook.hookId, code);
|
|
1247
|
-
if (previousHookId !== '' && compareUtf8(previousHookId, hookId) >= 0) {
|
|
1248
|
-
invalid(code);
|
|
1249
|
-
}
|
|
1250
|
-
previousHookId = hookId;
|
|
1251
|
-
if (
|
|
1252
|
-
typeof hook.selectorAtom !== 'string' ||
|
|
1253
|
-
Buffer.byteLength(hook.selectorAtom, 'utf8') < 1 ||
|
|
1254
|
-
Buffer.byteLength(hook.selectorAtom, 'utf8') > 132 ||
|
|
1255
|
-
atomCatalog.get(hook.selectorAtom) !== 1 ||
|
|
1256
|
-
hookAtoms.has(hook.selectorAtom)
|
|
1257
|
-
) {
|
|
1258
|
-
invalid(code);
|
|
1259
|
-
}
|
|
1260
|
-
hookAtoms.add(hook.selectorAtom);
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
requireDigest(contract.catalogDigest, code);
|
|
1264
|
-
let expectedDigest;
|
|
1265
|
-
try {
|
|
1266
|
-
expectedDigest = computeTemplateStylingContractDigest(contract);
|
|
1267
|
-
} catch {
|
|
1268
|
-
invalid(code);
|
|
1269
|
-
}
|
|
1270
|
-
if (contract.catalogDigest !== expectedDigest) invalid(code);
|
|
1271
|
-
}
|
|
1272
|
-
|
|
1273
|
-
/**
|
|
1274
|
-
* Compute the exact self-excluding shared theme-fixture release digest.
|
|
1275
|
-
*
|
|
1276
|
-
* @param {unknown} release complete fixture-release record
|
|
1277
|
-
* @returns {string} tagged digest
|
|
1278
|
-
*/
|
|
1279
|
-
export function computeThemeFixtureReleaseDigest(release) {
|
|
1280
|
-
const profile = ACTIVE_DIGEST_PROFILES.themeFixtureRelease;
|
|
1281
|
-
if (!profile) throw new TypeError('DIGEST_PROFILE_MISSING');
|
|
1282
|
-
return profile.digest(release);
|
|
1283
|
-
}
|
|
1284
|
-
|
|
1285
|
-
/**
|
|
1286
|
-
* Validate an immutable shared theme fixture release.
|
|
1287
|
-
*
|
|
1288
|
-
* `context.bytes` are its retained compact-JCS bytes and
|
|
1289
|
-
* `context.stylingContractDigest` is the independently validated template
|
|
1290
|
-
* styling catalog digest.
|
|
1291
|
-
*
|
|
1292
|
-
* @param {unknown} value fixture-release record
|
|
1293
|
-
* @param {unknown} context retained bytes and styling digest
|
|
1294
|
-
* @returns {void}
|
|
1295
|
-
*/
|
|
1296
|
-
export function validateThemeFixtureRelease(value, context) {
|
|
1297
|
-
const code = 'THEME_FIXTURE_RELEASE_INVALID';
|
|
1298
|
-
const release = exactRecord(value, FIXTURE_RELEASE_KEYS, code);
|
|
1299
|
-
const retained = exactRecord(
|
|
1300
|
-
context,
|
|
1301
|
-
['bytes', 'stylingContractDigest'],
|
|
1302
|
-
code,
|
|
1303
|
-
);
|
|
1304
|
-
if (
|
|
1305
|
-
release.profile !== 'gala-theme-fixture-release-v2' ||
|
|
1306
|
-
release.contractVersion !== '2.0.0' ||
|
|
1307
|
-
release.browserPolicyRef !== 'gala-theme-css-v2-20211224' ||
|
|
1308
|
-
release.binaryAssetProfile !== 'gala-theme-binary-assets-v2'
|
|
1309
|
-
) {
|
|
1310
|
-
invalid(code);
|
|
1311
|
-
}
|
|
1312
|
-
requireStableId(release.fixtureReleaseId, code);
|
|
1313
|
-
requireDigest(release.stylingContractDigest, code);
|
|
1314
|
-
if (release.stylingContractDigest !== retained.stylingContractDigest) {
|
|
1315
|
-
invalid(code);
|
|
1316
|
-
}
|
|
1317
|
-
requireCanonicalBytes(retained.bytes, release, code);
|
|
1318
|
-
|
|
1319
|
-
if (
|
|
1320
|
-
!Array.isArray(release.runners) ||
|
|
1321
|
-
release.runners.length < 1 ||
|
|
1322
|
-
release.runners.length > 16
|
|
1323
|
-
) {
|
|
1324
|
-
invalid(code);
|
|
1325
|
-
}
|
|
1326
|
-
const runnerIds = new Set();
|
|
1327
|
-
let previousRunner = '';
|
|
1328
|
-
for (const candidate of release.runners) {
|
|
1329
|
-
const runner = exactRecord(candidate, FIXTURE_RUNNER_KEYS, code);
|
|
1330
|
-
if (
|
|
1331
|
-
typeof runner.runnerId !== 'string' ||
|
|
1332
|
-
!FIXTURE_RUNNER_IDS.includes(runner.runnerId) ||
|
|
1333
|
-
runnerIds.has(runner.runnerId) ||
|
|
1334
|
-
(previousRunner !== '' &&
|
|
1335
|
-
compareUtf8(previousRunner, runner.runnerId) >= 0)
|
|
1336
|
-
) {
|
|
1337
|
-
invalid(code);
|
|
1338
|
-
}
|
|
1339
|
-
runnerIds.add(runner.runnerId);
|
|
1340
|
-
previousRunner = runner.runnerId;
|
|
1341
|
-
requireSemver(runner.version, code);
|
|
1342
|
-
requireDigest(runner.executableDigest, code);
|
|
1343
|
-
}
|
|
1344
|
-
|
|
1345
|
-
if (
|
|
1346
|
-
!Array.isArray(release.fixtures) ||
|
|
1347
|
-
release.fixtures.length < 1 ||
|
|
1348
|
-
release.fixtures.length > 64
|
|
1349
|
-
) {
|
|
1350
|
-
invalid(code);
|
|
1351
|
-
}
|
|
1352
|
-
let previousFixture = '';
|
|
1353
|
-
for (const candidate of release.fixtures) {
|
|
1354
|
-
const fixture = exactRecord(candidate, FIXTURE_DEFINITION_KEYS, code);
|
|
1355
|
-
const fixtureId = requirePlainLabel(fixture.fixtureId, code);
|
|
1356
|
-
if (
|
|
1357
|
-
(previousFixture !== '' &&
|
|
1358
|
-
compareUtf8(previousFixture, fixtureId) >= 0) ||
|
|
1359
|
-
typeof fixture.runnerId !== 'string' ||
|
|
1360
|
-
!runnerIds.has(fixture.runnerId) ||
|
|
1361
|
-
!FIXTURE_RUNNER_IDS.includes(fixture.runnerId) ||
|
|
1362
|
-
!['accepted', 'rejected'].includes(String(fixture.expectedDisposition))
|
|
1363
|
-
) {
|
|
1364
|
-
invalid(code);
|
|
1365
|
-
}
|
|
1366
|
-
previousFixture = fixtureId;
|
|
1367
|
-
requireDigest(fixture.inputDigest, code);
|
|
1368
|
-
requireDigest(fixture.expectedEvidenceDigest, code);
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
requireDigest(release.fixtureDigest, code);
|
|
1372
|
-
let expectedDigest;
|
|
1373
|
-
try {
|
|
1374
|
-
expectedDigest = computeThemeFixtureReleaseDigest(release);
|
|
1375
|
-
} catch {
|
|
1376
|
-
invalid(code);
|
|
1377
|
-
}
|
|
1378
|
-
if (release.fixtureDigest !== expectedDigest) invalid(code);
|
|
1379
|
-
}
|
|
1380
|
-
|
|
1381
|
-
/**
|
|
1382
|
-
* Compute the exact self-excluding theme conformance-evidence digest.
|
|
1383
|
-
*
|
|
1384
|
-
* @param {unknown} result complete conformance result
|
|
1385
|
-
* @returns {string} tagged digest
|
|
1386
|
-
*/
|
|
1387
|
-
export function computeThemeConformanceEvidenceDigest(result) {
|
|
1388
|
-
const profile = ACTIVE_DIGEST_PROFILES.themeConformanceEvidence;
|
|
1389
|
-
if (!profile) throw new TypeError('DIGEST_PROFILE_MISSING');
|
|
1390
|
-
return profile.digest(result);
|
|
1391
|
-
}
|
|
1392
|
-
|
|
1393
|
-
/**
|
|
1394
|
-
* Validate one retained theme conformance result against its fixture release.
|
|
1395
|
-
*
|
|
1396
|
-
* `context.bytes` are exact compact-JCS result bytes. The other context fields
|
|
1397
|
-
* are independently validated retained inputs, not additional wire members.
|
|
1398
|
-
*
|
|
1399
|
-
* @param {unknown} value conformance-result record
|
|
1400
|
-
* @param {unknown} context release, input digest, and retained result bytes
|
|
1401
|
-
* @returns {void}
|
|
1402
|
-
*/
|
|
1403
|
-
export function validateThemeConformanceResult(value, context) {
|
|
1404
|
-
const code = 'THEME_CONFORMANCE_RESULT_INVALID';
|
|
1405
|
-
const result = exactRecord(value, CONFORMANCE_RESULT_KEYS, code);
|
|
1406
|
-
const retained = exactRecord(
|
|
1407
|
-
context,
|
|
1408
|
-
['bytes', 'fixtureRelease', 'themeConformanceInputDigest'],
|
|
1409
|
-
code,
|
|
1410
|
-
);
|
|
1411
|
-
const release = isPlainObject(retained.fixtureRelease)
|
|
1412
|
-
? retained.fixtureRelease
|
|
1413
|
-
: invalid(code);
|
|
1414
|
-
if (
|
|
1415
|
-
result.profile !== 'gala-theme-conformance-result-v2' ||
|
|
1416
|
-
result.fixtureReleaseId !== release.fixtureReleaseId ||
|
|
1417
|
-
result.fixtureDigest !== release.fixtureDigest ||
|
|
1418
|
-
result.themeConformanceInputDigest !== retained.themeConformanceInputDigest
|
|
1419
|
-
) {
|
|
1420
|
-
invalid(code);
|
|
1421
|
-
}
|
|
1422
|
-
requireStableId(result.fixtureReleaseId, code);
|
|
1423
|
-
requireDigest(result.fixtureDigest, code);
|
|
1424
|
-
requireDigest(result.themeConformanceInputDigest, code);
|
|
1425
|
-
requireCanonicalBytes(retained.bytes, result, code);
|
|
1426
|
-
|
|
1427
|
-
if (
|
|
1428
|
-
!Array.isArray(release.fixtures) ||
|
|
1429
|
-
!Array.isArray(result.results) ||
|
|
1430
|
-
result.results.length !== release.fixtures.length
|
|
1431
|
-
) {
|
|
1432
|
-
invalid(code);
|
|
1433
|
-
}
|
|
1434
|
-
let everyPasses = true;
|
|
1435
|
-
let previousFixtureId = '';
|
|
1436
|
-
for (let index = 0; index < release.fixtures.length; index += 1) {
|
|
1437
|
-
const definition = exactRecord(
|
|
1438
|
-
release.fixtures[index],
|
|
1439
|
-
FIXTURE_DEFINITION_KEYS,
|
|
1440
|
-
code,
|
|
1441
|
-
);
|
|
1442
|
-
const row = exactRecord(result.results[index], FIXTURE_RESULT_KEYS, code);
|
|
1443
|
-
const fixtureId = requirePlainLabel(row.fixtureId, code);
|
|
1444
|
-
if (
|
|
1445
|
-
row.fixtureId !== definition.fixtureId ||
|
|
1446
|
-
(previousFixtureId !== '' &&
|
|
1447
|
-
compareUtf8(previousFixtureId, fixtureId) >= 0) ||
|
|
1448
|
-
typeof row.runnerId !== 'string' ||
|
|
1449
|
-
!FIXTURE_RUNNER_IDS.includes(row.runnerId) ||
|
|
1450
|
-
!['accepted', 'rejected'].includes(String(row.observedDisposition)) ||
|
|
1451
|
-
!['pass', 'fail'].includes(String(row.state))
|
|
1452
|
-
) {
|
|
1453
|
-
invalid(code);
|
|
1454
|
-
}
|
|
1455
|
-
previousFixtureId = fixtureId;
|
|
1456
|
-
requireDigest(row.observedEvidenceDigest, code);
|
|
1457
|
-
const passes =
|
|
1458
|
-
row.runnerId === definition.runnerId &&
|
|
1459
|
-
row.observedDisposition === definition.expectedDisposition &&
|
|
1460
|
-
row.observedEvidenceDigest === definition.expectedEvidenceDigest;
|
|
1461
|
-
if (row.state !== (passes ? 'pass' : 'fail')) invalid(code);
|
|
1462
|
-
everyPasses &&= passes;
|
|
1463
|
-
}
|
|
1464
|
-
if (result.overallState !== (everyPasses ? 'pass' : 'fail')) invalid(code);
|
|
1465
|
-
requireDigest(result.evidenceDigest, code);
|
|
1466
|
-
let expectedDigest;
|
|
1467
|
-
try {
|
|
1468
|
-
expectedDigest = computeThemeConformanceEvidenceDigest(result);
|
|
1469
|
-
} catch {
|
|
1470
|
-
invalid(code);
|
|
1471
|
-
}
|
|
1472
|
-
if (result.evidenceDigest !== expectedDigest) invalid(code);
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
/**
|
|
1476
|
-
* Validate extracted package-file observations shared by both digest profiles.
|
|
1477
|
-
*
|
|
1478
|
-
* The extraction layer supplies one row for every stripped `package/` tar
|
|
1479
|
-
* member. Requiring `kind:file` and mode 0644 here makes links, devices,
|
|
1480
|
-
* directories, and executable members unrepresentable as admitted input.
|
|
1481
|
-
*
|
|
1482
|
-
* @param {unknown} value candidate file rows
|
|
1483
|
-
* @param {string} code failure diagnostic
|
|
1484
|
-
* @returns {ThemePackageFile[]} checked copied rows
|
|
1485
|
-
*/
|
|
1486
|
-
function validatePackageFiles(value, code) {
|
|
1487
|
-
if (!Array.isArray(value) || value.length === 0 || value.length > 512) {
|
|
1488
|
-
invalid(code);
|
|
1489
|
-
}
|
|
1490
|
-
/** @type {ThemePackageFile[]} */
|
|
1491
|
-
const files = [];
|
|
1492
|
-
const paths = new Set();
|
|
1493
|
-
const collisionKeys = new Set();
|
|
1494
|
-
for (const candidate of value) {
|
|
1495
|
-
const row = exactRecord(candidate, PACKAGE_FILE_KEYS, code);
|
|
1496
|
-
const path = requireRepositoryPath(row.path, code);
|
|
1497
|
-
let collisionKey;
|
|
1498
|
-
try {
|
|
1499
|
-
collisionKey = unicodeCollisionKey17(path);
|
|
1500
|
-
} catch {
|
|
1501
|
-
invalid(code);
|
|
1502
|
-
}
|
|
1503
|
-
if (
|
|
1504
|
-
paths.has(path) ||
|
|
1505
|
-
collisionKeys.has(collisionKey) ||
|
|
1506
|
-
row.kind !== 'file' ||
|
|
1507
|
-
row.mode !== 0o644 ||
|
|
1508
|
-
!(row.bytes instanceof Uint8Array)
|
|
1509
|
-
) {
|
|
1510
|
-
invalid(code);
|
|
1511
|
-
}
|
|
1512
|
-
paths.add(path);
|
|
1513
|
-
collisionKeys.add(collisionKey);
|
|
1514
|
-
files.push({
|
|
1515
|
-
path,
|
|
1516
|
-
kind: 'file',
|
|
1517
|
-
mode: 0o644,
|
|
1518
|
-
bytes: row.bytes,
|
|
1519
|
-
});
|
|
1520
|
-
}
|
|
1521
|
-
return files;
|
|
1522
|
-
}
|
|
1523
|
-
|
|
1524
|
-
/**
|
|
1525
|
-
* Replace theme.json with one of the two authority-defined virtual manifests
|
|
1526
|
-
* and return the complete path-sorted entry projection.
|
|
1527
|
-
*
|
|
1528
|
-
* @param {unknown} theme complete theme contract
|
|
1529
|
-
* @param {unknown} packageFiles extracted package-file rows
|
|
1530
|
-
* @param {readonly string[]} excludedManifestMembers self fields to omit
|
|
1531
|
-
* @returns {ThemeEntry[]} exact digest entries
|
|
1532
|
-
*/
|
|
1533
|
-
function projectThemeEntries(theme, packageFiles, excludedManifestMembers) {
|
|
1534
|
-
validateThemeContract(theme);
|
|
1535
|
-
const source = /** @type {UnknownRecord} */ (theme);
|
|
1536
|
-
const files = validatePackageFiles(packageFiles, 'THEME_PACKAGE_INVALID');
|
|
1537
|
-
if (files.filter((file) => file.path === 'theme.json').length !== 1) {
|
|
1538
|
-
invalid('THEME_PACKAGE_INVALID');
|
|
1539
|
-
}
|
|
1540
|
-
const excluded = new Set(excludedManifestMembers);
|
|
1541
|
-
const virtualTheme = Object.fromEntries(
|
|
1542
|
-
Object.entries(source).filter(([key]) => !excluded.has(key)),
|
|
1543
|
-
);
|
|
1544
|
-
const virtualBytes = canonicalizeJcsBytes(virtualTheme);
|
|
1545
|
-
return files
|
|
1546
|
-
.map((file) => {
|
|
1547
|
-
const bytes = file.path === 'theme.json' ? virtualBytes : file.bytes;
|
|
1548
|
-
return {
|
|
1549
|
-
path: file.path,
|
|
1550
|
-
byteLength: String(bytes.byteLength),
|
|
1551
|
-
sha256: sha256Tagged(bytes),
|
|
1552
|
-
};
|
|
1553
|
-
})
|
|
1554
|
-
.sort((left, right) => compareUtf8(left.path, right.path));
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
/**
|
|
1558
|
-
* Compute the pre-finalization conformance-input digest.
|
|
1559
|
-
*
|
|
1560
|
-
* `theme.json` is virtualized with exactly `integrity` and `evidenceDigest`
|
|
1561
|
-
* omitted; every other package member is represented by its raw bytes.
|
|
1562
|
-
*
|
|
1563
|
-
* @param {unknown} theme complete theme contract
|
|
1564
|
-
* @param {unknown} packageFiles extracted package-file rows
|
|
1565
|
-
* @returns {string} tagged digest
|
|
1566
|
-
*/
|
|
1567
|
-
export function computeThemeConformanceInputDigest(theme, packageFiles) {
|
|
1568
|
-
const profile = ACTIVE_DIGEST_PROFILES.themeConformanceInput;
|
|
1569
|
-
if (!profile) throw new TypeError('DIGEST_PROFILE_MISSING');
|
|
1570
|
-
return profile.digest(
|
|
1571
|
-
projectThemeEntries(theme, packageFiles, ['integrity', 'evidenceDigest']),
|
|
1572
|
-
);
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
/**
|
|
1576
|
-
* Compute final semantic theme-package integrity.
|
|
1577
|
-
*
|
|
1578
|
-
* `theme.json` is virtualized with exactly `integrity` omitted; every other
|
|
1579
|
-
* package member is represented by its raw bytes.
|
|
1580
|
-
*
|
|
1581
|
-
* @param {unknown} theme complete theme contract
|
|
1582
|
-
* @param {unknown} packageFiles extracted package-file rows
|
|
1583
|
-
* @returns {string} tagged digest
|
|
1584
|
-
*/
|
|
1585
|
-
export function computeThemePackageIntegrity(theme, packageFiles) {
|
|
1586
|
-
const profile = ACTIVE_DIGEST_PROFILES.themePackageIntegrity;
|
|
1587
|
-
if (!profile) throw new TypeError('DIGEST_PROFILE_MISSING');
|
|
1588
|
-
return profile.digest(
|
|
1589
|
-
projectThemeEntries(theme, packageFiles, ['integrity']),
|
|
1590
|
-
);
|
|
1591
|
-
}
|
|
1592
|
-
|
|
1593
|
-
/**
|
|
1594
|
-
* Find one checked package file by path.
|
|
1595
|
-
*
|
|
1596
|
-
* @param {ThemePackageFile[]} files checked file rows
|
|
1597
|
-
* @param {string} path exact path
|
|
1598
|
-
* @param {string} code failure diagnostic
|
|
1599
|
-
* @returns {ThemePackageFile} required file
|
|
1600
|
-
*/
|
|
1601
|
-
function requirePackageFile(files, path, code) {
|
|
1602
|
-
const file = files.find((candidate) => candidate.path === path);
|
|
1603
|
-
if (!file) invalid(code);
|
|
1604
|
-
return file;
|
|
1605
|
-
}
|
|
1606
|
-
|
|
1607
|
-
/**
|
|
1608
|
-
* Return one non-CSS asset's required media type.
|
|
1609
|
-
*
|
|
1610
|
-
* @param {string} path asset path
|
|
1611
|
-
* @param {string} code failure diagnostic
|
|
1612
|
-
* @returns {string} required media type
|
|
1613
|
-
*/
|
|
1614
|
-
function mediaTypeForAssetPath(path, code) {
|
|
1615
|
-
if (!path.startsWith('assets/') || path.length === 'assets/'.length) {
|
|
1616
|
-
invalid(code);
|
|
1617
|
-
}
|
|
1618
|
-
const dot = path.lastIndexOf('.');
|
|
1619
|
-
const extension = dot < 0 ? '' : path.slice(dot);
|
|
1620
|
-
const mediaType = MEDIA_BY_EXTENSION[extension];
|
|
1621
|
-
if (!mediaType) invalid(code);
|
|
1622
|
-
return mediaType;
|
|
1623
|
-
}
|
|
1624
|
-
|
|
1625
|
-
/**
|
|
1626
|
-
* Validate an exact asset-to-file byte binding.
|
|
1627
|
-
*
|
|
1628
|
-
* @param {UnknownRecord} asset checked manifest asset
|
|
1629
|
-
* @param {ThemePackageFile} file retained package file
|
|
1630
|
-
* @param {string} code failure diagnostic
|
|
1631
|
-
* @returns {void}
|
|
1632
|
-
*/
|
|
1633
|
-
function validateAssetBytes(asset, file, code) {
|
|
1634
|
-
if (
|
|
1635
|
-
asset.byteLength !== String(file.bytes.byteLength) ||
|
|
1636
|
-
asset.sha256 !== sha256Tagged(file.bytes)
|
|
1637
|
-
) {
|
|
1638
|
-
invalid(code);
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
/**
|
|
1643
|
-
* Validate the exact package.json projection and return its package expression.
|
|
1644
|
-
*
|
|
1645
|
-
* @param {ThemePackageFile[]} files checked package files
|
|
1646
|
-
* @param {UnknownRecord} theme checked theme root
|
|
1647
|
-
* @param {string[]} manifestFilePaths package.json `files` closure
|
|
1648
|
-
* @param {string} code failure diagnostic
|
|
1649
|
-
* @returns {string} canonical package SPDX expression
|
|
1650
|
-
*/
|
|
1651
|
-
function validatePackageJson(files, theme, manifestFilePaths, code) {
|
|
1652
|
-
const packageFile = requirePackageFile(files, 'package.json', code);
|
|
1653
|
-
const parsed = exactRecord(
|
|
1654
|
-
parseRetainedJson(packageFile.bytes, code),
|
|
1655
|
-
PACKAGE_JSON_KEYS,
|
|
1656
|
-
code,
|
|
1657
|
-
);
|
|
1658
|
-
const identity = parsePackageExact(theme.package, code);
|
|
1659
|
-
if (parsed.name !== identity.name || parsed.version !== identity.version) {
|
|
1660
|
-
invalid(code);
|
|
1661
|
-
}
|
|
1662
|
-
if (typeof parsed.license !== 'string') invalid(code);
|
|
1663
|
-
try {
|
|
1664
|
-
validateSpdxExpression(parsed.license);
|
|
1665
|
-
} catch {
|
|
1666
|
-
invalid(code);
|
|
1667
|
-
}
|
|
1668
|
-
if (!stringArrayEquals(parsed.files, manifestFilePaths)) invalid(code);
|
|
1669
|
-
return parsed.license;
|
|
1670
|
-
}
|
|
1671
|
-
|
|
1672
|
-
/**
|
|
1673
|
-
* Validate compact-JCS LICENSE evidence and exact per-asset inheritance.
|
|
1674
|
-
*
|
|
1675
|
-
* @param {ThemePackageFile[]} files checked package files
|
|
1676
|
-
* @param {UnknownRecord[]} assets checked manifest assets
|
|
1677
|
-
* @param {string} packageExpression package.json expression
|
|
1678
|
-
* @param {string} code failure diagnostic
|
|
1679
|
-
* @returns {void}
|
|
1680
|
-
*/
|
|
1681
|
-
function validateLicenseEvidence(files, assets, packageExpression, code) {
|
|
1682
|
-
const licenseFile = requirePackageFile(files, 'LICENSE', code);
|
|
1683
|
-
const evidence = exactRecord(
|
|
1684
|
-
parseRetainedJson(licenseFile.bytes, code),
|
|
1685
|
-
LICENSE_EVIDENCE_KEYS,
|
|
1686
|
-
code,
|
|
1687
|
-
);
|
|
1688
|
-
requireCanonicalBytes(licenseFile.bytes, evidence, code);
|
|
1689
|
-
if (
|
|
1690
|
-
evidence.profile !== 'gala-theme-license-evidence-v2' ||
|
|
1691
|
-
evidence.packageExpression !== packageExpression ||
|
|
1692
|
-
!Array.isArray(evidence.assetOverrides) ||
|
|
1693
|
-
evidence.assetOverrides.length > 256 ||
|
|
1694
|
-
!Array.isArray(evidence.catalogEntries) ||
|
|
1695
|
-
evidence.catalogEntries.length < 1 ||
|
|
1696
|
-
evidence.catalogEntries.length > 512
|
|
1697
|
-
) {
|
|
1698
|
-
invalid(code);
|
|
1699
|
-
}
|
|
1700
|
-
|
|
1701
|
-
/** @type {Map<string, string>} */
|
|
1702
|
-
const overrides = new Map();
|
|
1703
|
-
/** @type {UnknownRecord | undefined} */
|
|
1704
|
-
let previousOverride;
|
|
1705
|
-
for (const candidate of evidence.assetOverrides) {
|
|
1706
|
-
const override = exactRecord(candidate, LICENSE_OVERRIDE_KEYS, code);
|
|
1707
|
-
const path = requireRepositoryPath(override.path, code);
|
|
1708
|
-
if (overrides.has(path)) invalid(code);
|
|
1709
|
-
if (typeof override.expression !== 'string') invalid(code);
|
|
1710
|
-
try {
|
|
1711
|
-
validateSpdxExpression(override.expression);
|
|
1712
|
-
} catch {
|
|
1713
|
-
invalid(code);
|
|
1714
|
-
}
|
|
1715
|
-
if (
|
|
1716
|
-
previousOverride !== undefined &&
|
|
1717
|
-
compareJcsValues(previousOverride, override) >= 0
|
|
1718
|
-
) {
|
|
1719
|
-
invalid(code);
|
|
1720
|
-
}
|
|
1721
|
-
previousOverride = override;
|
|
1722
|
-
overrides.set(path, override.expression);
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1725
|
-
const expressions = [packageExpression];
|
|
1726
|
-
for (const asset of assets) {
|
|
1727
|
-
if (typeof asset.path !== 'string' || typeof asset.license !== 'string') {
|
|
1728
|
-
invalid(code);
|
|
1729
|
-
}
|
|
1730
|
-
expressions.push(asset.license);
|
|
1731
|
-
const inherited = asset.license === packageExpression;
|
|
1732
|
-
const override = overrides.get(asset.path);
|
|
1733
|
-
if (asset.mediaType === 'text/css') {
|
|
1734
|
-
if (!inherited || override !== undefined) invalid(code);
|
|
1735
|
-
} else if (
|
|
1736
|
-
(inherited && override !== undefined) ||
|
|
1737
|
-
(!inherited && override !== asset.license)
|
|
1738
|
-
) {
|
|
1739
|
-
invalid(code);
|
|
1740
|
-
}
|
|
1741
|
-
}
|
|
1742
|
-
const nonCssPaths = new Set(
|
|
1743
|
-
assets
|
|
1744
|
-
.filter((asset) => asset.mediaType !== 'text/css')
|
|
1745
|
-
.map((asset) => String(asset.path)),
|
|
1746
|
-
);
|
|
1747
|
-
if ([...overrides.keys()].some((path) => !nonCssPaths.has(path))) {
|
|
1748
|
-
invalid(code);
|
|
1749
|
-
}
|
|
1750
|
-
|
|
1751
|
-
try {
|
|
1752
|
-
validateSpdxCatalogEvidence(expressions, evidence);
|
|
1753
|
-
} catch {
|
|
1754
|
-
invalid(code);
|
|
1755
|
-
}
|
|
1756
|
-
}
|
|
1757
|
-
|
|
1758
|
-
/**
|
|
1759
|
-
* Validate the retained source byte subset that precedes pinned CSS parsing.
|
|
1760
|
-
*
|
|
1761
|
-
* @param {Uint8Array} bytes stylesheet bytes
|
|
1762
|
-
* @param {string} code failure diagnostic
|
|
1763
|
-
* @returns {void}
|
|
1764
|
-
*/
|
|
1765
|
-
function validateCssSourceBytes(bytes, code) {
|
|
1766
|
-
if (
|
|
1767
|
-
bytes.byteLength === 0 ||
|
|
1768
|
-
bytes.byteLength > 1_048_576 ||
|
|
1769
|
-
(bytes[0] === 0xef && bytes[1] === 0xbb && bytes[2] === 0xbf)
|
|
1770
|
-
) {
|
|
1771
|
-
invalid(code);
|
|
1772
|
-
}
|
|
1773
|
-
let source;
|
|
1774
|
-
try {
|
|
1775
|
-
source = FATAL_UTF8_DECODER.decode(bytes);
|
|
1776
|
-
} catch {
|
|
1777
|
-
invalid(code);
|
|
1778
|
-
}
|
|
1779
|
-
const forbiddenSourceByte = [...source].some((character) => {
|
|
1780
|
-
const codePoint = character.codePointAt(0);
|
|
1781
|
-
return (
|
|
1782
|
-
codePoint === undefined ||
|
|
1783
|
-
(codePoint !== 0x09 &&
|
|
1784
|
-
codePoint !== 0x0a &&
|
|
1785
|
-
(codePoint < 0x20 || codePoint > 0x7e))
|
|
1786
|
-
);
|
|
1787
|
-
});
|
|
1788
|
-
if (
|
|
1789
|
-
normalizeNfc17(source) !== source ||
|
|
1790
|
-
source.includes('\\') ||
|
|
1791
|
-
forbiddenSourceByte
|
|
1792
|
-
) {
|
|
1793
|
-
invalid(code);
|
|
1794
|
-
}
|
|
1795
|
-
}
|
|
1796
|
-
|
|
1797
|
-
/**
|
|
1798
|
-
* Validate parser-reported CSS resource counters.
|
|
1799
|
-
*
|
|
1800
|
-
* @param {unknown} value metric record
|
|
1801
|
-
* @param {Record<string, number>} totals package aggregate counters
|
|
1802
|
-
* @param {string} code failure diagnostic
|
|
1803
|
-
* @returns {void}
|
|
1804
|
-
*/
|
|
1805
|
-
function validateCssMetrics(value, totals, code) {
|
|
1806
|
-
const metrics = exactRecord(value, CSS_METRIC_KEYS, code);
|
|
1807
|
-
for (const key of CSS_METRIC_KEYS) {
|
|
1808
|
-
const metric = metrics[key];
|
|
1809
|
-
const limit = CSS_METRIC_LIMITS[key];
|
|
1810
|
-
if (
|
|
1811
|
-
!Number.isInteger(metric) ||
|
|
1812
|
-
Number(metric) < 0 ||
|
|
1813
|
-
limit === undefined ||
|
|
1814
|
-
Number(metric) > limit
|
|
1815
|
-
) {
|
|
1816
|
-
invalid(code);
|
|
1817
|
-
}
|
|
1818
|
-
if (key === 'maximumBlockFunctionDepth') {
|
|
1819
|
-
totals[key] = Math.max(totals[key] ?? 0, Number(metric));
|
|
1820
|
-
} else {
|
|
1821
|
-
totals[key] = (totals[key] ?? 0) + Number(metric);
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
|
|
1826
|
-
/**
|
|
1827
|
-
* Validate tokens.css's exact parser-derived custom-property projection.
|
|
1828
|
-
*
|
|
1829
|
-
* @param {unknown} value token declaration evidence
|
|
1830
|
-
* @param {UnknownRecord} theme checked theme
|
|
1831
|
-
* @param {UnknownRecord} stylingContract checked styling contract
|
|
1832
|
-
* @param {string} code failure diagnostic
|
|
1833
|
-
* @returns {void}
|
|
1834
|
-
*/
|
|
1835
|
-
function validateTokenDeclarations(value, theme, stylingContract, code) {
|
|
1836
|
-
const declarations = exactRecord(value, TOKEN_DECLARATION_KEYS, code);
|
|
1837
|
-
const palettes = exactRecord(
|
|
1838
|
-
stylingContract.resolvedPaletteSelectors,
|
|
1839
|
-
PALETTE_SELECTOR_KEYS,
|
|
1840
|
-
code,
|
|
1841
|
-
);
|
|
1842
|
-
if (
|
|
1843
|
-
declarations.lightSelector !== palettes.light ||
|
|
1844
|
-
declarations.darkSelector !== palettes.dark
|
|
1845
|
-
) {
|
|
1846
|
-
invalid(code);
|
|
1847
|
-
}
|
|
1848
|
-
const light = isPlainObject(declarations.light)
|
|
1849
|
-
? declarations.light
|
|
1850
|
-
: invalid(code);
|
|
1851
|
-
const dark = isPlainObject(declarations.dark)
|
|
1852
|
-
? declarations.dark
|
|
1853
|
-
: invalid(code);
|
|
1854
|
-
const expectedProperties = THEME_TOKEN_CATALOG.map(
|
|
1855
|
-
([key]) => `--gala-${key}`,
|
|
1856
|
-
).sort();
|
|
1857
|
-
if (
|
|
1858
|
-
!stringArrayEquals(Object.keys(light).sort(), expectedProperties) ||
|
|
1859
|
-
!stringArrayEquals(Object.keys(dark).sort(), expectedProperties)
|
|
1860
|
-
) {
|
|
1861
|
-
invalid(code);
|
|
1862
|
-
}
|
|
1863
|
-
if (!Array.isArray(theme.tokens)) invalid(code);
|
|
1864
|
-
for (const candidate of theme.tokens) {
|
|
1865
|
-
const token = exactRecord(candidate, TOKEN_KEYS, code);
|
|
1866
|
-
const property = `--gala-${String(token.key)}`;
|
|
1867
|
-
if (light[property] !== token.light || dark[property] !== token.dark) {
|
|
1868
|
-
invalid(code);
|
|
1869
|
-
}
|
|
1870
|
-
}
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
/**
|
|
1874
|
-
* Bind one retained parser-evidence envelope to the exact runner identity in
|
|
1875
|
-
* the independently validated immutable fixture release.
|
|
1876
|
-
*
|
|
1877
|
-
* This is the T03/S2 trust boundary: S2 owns isolated execution of the
|
|
1878
|
-
* integrity-verified runner bytes; T03 accepts only that runner's retained
|
|
1879
|
-
* evidence envelope and verifies its identity against the release ledger.
|
|
1880
|
-
* Copying these fields is not proof that the runner executed, so callers must
|
|
1881
|
-
* obtain the envelope directly from the trusted S2 parser runner.
|
|
1882
|
-
*
|
|
1883
|
-
* @param {unknown} value parser-evidence envelope
|
|
1884
|
-
* @param {UnknownRecord} fixtureRelease independently validated fixture release
|
|
1885
|
-
* @param {'css' | 'binary'} expectedRunnerId required runner identity
|
|
1886
|
-
* @param {string} code failure diagnostic
|
|
1887
|
-
* @returns {unknown[]} retained parser-evidence records
|
|
1888
|
-
*/
|
|
1889
|
-
function requireTrustedRunnerEvidence(
|
|
1890
|
-
value,
|
|
1891
|
-
fixtureRelease,
|
|
1892
|
-
expectedRunnerId,
|
|
1893
|
-
code,
|
|
1894
|
-
) {
|
|
1895
|
-
const envelope = exactRecord(value, RUNNER_EVIDENCE_KEYS, code);
|
|
1896
|
-
const runner = exactRecord(envelope.runner, FIXTURE_RUNNER_KEYS, code);
|
|
1897
|
-
if (runner.runnerId !== expectedRunnerId) invalid(code);
|
|
1898
|
-
requireSemver(runner.version, code);
|
|
1899
|
-
requireDigest(runner.executableDigest, code);
|
|
1900
|
-
if (!Array.isArray(fixtureRelease.runners)) invalid(code);
|
|
1901
|
-
const matchingRunners = fixtureRelease.runners
|
|
1902
|
-
.map((candidate) => exactRecord(candidate, FIXTURE_RUNNER_KEYS, code))
|
|
1903
|
-
.filter((candidate) => candidate.runnerId === expectedRunnerId);
|
|
1904
|
-
if (
|
|
1905
|
-
matchingRunners.length !== 1 ||
|
|
1906
|
-
!jcsEqual(runner, matchingRunners[0]) ||
|
|
1907
|
-
!Array.isArray(envelope.records)
|
|
1908
|
-
) {
|
|
1909
|
-
invalid(code);
|
|
1910
|
-
}
|
|
1911
|
-
return envelope.records;
|
|
1912
|
-
}
|
|
1913
|
-
|
|
1914
|
-
/**
|
|
1915
|
-
* Validate trusted pinned-parser CSS evidence and all semantic relations it
|
|
1916
|
-
* exposes. The parser owns CSS tokenization, selector/property grammar, and
|
|
1917
|
-
* at-rule context; this validator owns exact source bytes, counts, layers,
|
|
1918
|
-
* token values, hooks, and local asset closure.
|
|
1919
|
-
*
|
|
1920
|
-
* @param {unknown} value trusted CSS parser-evidence envelope
|
|
1921
|
-
* @param {UnknownRecord} theme checked theme
|
|
1922
|
-
* @param {UnknownRecord} stylingContract checked styling contract
|
|
1923
|
-
* @param {UnknownRecord} fixtureRelease independently validated fixture release
|
|
1924
|
-
* @param {ThemePackageFile[]} files checked package files
|
|
1925
|
-
* @param {UnknownRecord[]} assets checked manifest assets
|
|
1926
|
-
* @returns {void}
|
|
1927
|
-
*/
|
|
1928
|
-
function validateCssEvidence(
|
|
1929
|
-
value,
|
|
1930
|
-
theme,
|
|
1931
|
-
stylingContract,
|
|
1932
|
-
fixtureRelease,
|
|
1933
|
-
files,
|
|
1934
|
-
assets,
|
|
1935
|
-
) {
|
|
1936
|
-
const code = 'THEME_CSS_EVIDENCE_INVALID';
|
|
1937
|
-
const records = requireTrustedRunnerEvidence(
|
|
1938
|
-
value,
|
|
1939
|
-
fixtureRelease,
|
|
1940
|
-
'css',
|
|
1941
|
-
code,
|
|
1942
|
-
);
|
|
1943
|
-
if (
|
|
1944
|
-
!Array.isArray(theme.stylesheets) ||
|
|
1945
|
-
!Array.isArray(theme.cssLayers) ||
|
|
1946
|
-
records.length !== theme.stylesheets.length
|
|
1947
|
-
) {
|
|
1948
|
-
invalid(code);
|
|
1949
|
-
}
|
|
1950
|
-
/** @type {Record<string, number>} */
|
|
1951
|
-
const metricTotals = {};
|
|
1952
|
-
const usedHooks = new Set();
|
|
1953
|
-
const referencedAssets = new Set();
|
|
1954
|
-
const fontAssets = new Set();
|
|
1955
|
-
let cssBytes = 0;
|
|
1956
|
-
for (let index = 0; index < records.length; index += 1) {
|
|
1957
|
-
const path = theme.stylesheets[index];
|
|
1958
|
-
const layer = theme.cssLayers[index];
|
|
1959
|
-
if (typeof path !== 'string' || typeof layer !== 'string') invalid(code);
|
|
1960
|
-
const keys =
|
|
1961
|
-
path === 'tokens.css'
|
|
1962
|
-
? [...CSS_EVIDENCE_BASE_KEYS, 'tokenDeclarations']
|
|
1963
|
-
: CSS_EVIDENCE_BASE_KEYS;
|
|
1964
|
-
const evidence = exactRecord(records[index], keys, code);
|
|
1965
|
-
const file = requirePackageFile(files, path, code);
|
|
1966
|
-
validateCssSourceBytes(file.bytes, code);
|
|
1967
|
-
cssBytes += file.bytes.byteLength;
|
|
1968
|
-
if (
|
|
1969
|
-
evidence.path !== path ||
|
|
1970
|
-
evidence.profile !== fixtureRelease.browserPolicyRef ||
|
|
1971
|
-
evidence.disposition !== 'accepted' ||
|
|
1972
|
-
evidence.byteLength !== String(file.bytes.byteLength) ||
|
|
1973
|
-
evidence.sha256 !== sha256Tagged(file.bytes) ||
|
|
1974
|
-
evidence.outerLayer !== layer
|
|
1975
|
-
) {
|
|
1976
|
-
invalid(code);
|
|
1977
|
-
}
|
|
1978
|
-
validateCssMetrics(evidence.metrics, metricTotals, code);
|
|
1979
|
-
const rowHooks = requireSortedStringSet(
|
|
1980
|
-
evidence.usedSlotHookIds,
|
|
1981
|
-
0,
|
|
1982
|
-
64,
|
|
1983
|
-
(entry) => requirePlainLabel(entry, code),
|
|
1984
|
-
code,
|
|
1985
|
-
);
|
|
1986
|
-
const rowAssets = requireSortedStringSet(
|
|
1987
|
-
evidence.referencedAssetPaths,
|
|
1988
|
-
0,
|
|
1989
|
-
256,
|
|
1990
|
-
(entry) => requireRepositoryPath(entry, code),
|
|
1991
|
-
code,
|
|
1992
|
-
);
|
|
1993
|
-
const rowFonts = requireSortedStringSet(
|
|
1994
|
-
evidence.fontFaceAssetPaths,
|
|
1995
|
-
0,
|
|
1996
|
-
128,
|
|
1997
|
-
(entry) => requireRepositoryPath(entry, code),
|
|
1998
|
-
code,
|
|
1999
|
-
);
|
|
2000
|
-
rowHooks.forEach((hook) => usedHooks.add(hook));
|
|
2001
|
-
rowAssets.forEach((asset) => referencedAssets.add(asset));
|
|
2002
|
-
rowFonts.forEach((asset) => fontAssets.add(asset));
|
|
2003
|
-
if (path === 'tokens.css') {
|
|
2004
|
-
validateTokenDeclarations(
|
|
2005
|
-
evidence.tokenDeclarations,
|
|
2006
|
-
theme,
|
|
2007
|
-
stylingContract,
|
|
2008
|
-
code,
|
|
2009
|
-
);
|
|
2010
|
-
}
|
|
2011
|
-
}
|
|
2012
|
-
if (cssBytes > 4_194_304) invalid(code);
|
|
2013
|
-
for (const [key, limit] of Object.entries(CSS_METRIC_LIMITS)) {
|
|
2014
|
-
if ((metricTotals[key] ?? 0) > limit) invalid(code);
|
|
2015
|
-
}
|
|
2016
|
-
|
|
2017
|
-
const hooks = [...usedHooks].sort(compareJcsStrings);
|
|
2018
|
-
if (!stringArrayEquals(theme.slotHooks, hooks)) invalid(code);
|
|
2019
|
-
const publicHooks = new Set(
|
|
2020
|
-
Array.isArray(stylingContract.publicThemeSlotHooks)
|
|
2021
|
-
? stylingContract.publicThemeSlotHooks.map((candidate) =>
|
|
2022
|
-
String(exactRecord(candidate, STYLE_HOOK_KEYS, code).hookId),
|
|
2023
|
-
)
|
|
2024
|
-
: invalid(code),
|
|
2025
|
-
);
|
|
2026
|
-
if (hooks.some((hook) => !publicHooks.has(hook))) invalid(code);
|
|
2027
|
-
|
|
2028
|
-
const nonCssAssets = assets.filter((asset) => asset.mediaType !== 'text/css');
|
|
2029
|
-
const nonCssPaths = nonCssAssets
|
|
2030
|
-
.map((asset) => String(asset.path))
|
|
2031
|
-
.sort(compareUtf8);
|
|
2032
|
-
if (
|
|
2033
|
-
!stringArrayEquals([...referencedAssets].sort(compareUtf8), nonCssPaths)
|
|
2034
|
-
) {
|
|
2035
|
-
invalid(code);
|
|
2036
|
-
}
|
|
2037
|
-
const mediaByPath = new Map(
|
|
2038
|
-
nonCssAssets.map((asset) => [String(asset.path), String(asset.mediaType)]),
|
|
2039
|
-
);
|
|
2040
|
-
if (
|
|
2041
|
-
[...fontAssets].some((path) => mediaByPath.get(path) !== 'font/woff2') ||
|
|
2042
|
-
nonCssAssets
|
|
2043
|
-
.filter((asset) => asset.mediaType === 'font/woff2')
|
|
2044
|
-
.some((asset) => !fontAssets.has(String(asset.path)))
|
|
2045
|
-
) {
|
|
2046
|
-
invalid(code);
|
|
2047
|
-
}
|
|
2048
|
-
}
|
|
2049
|
-
|
|
2050
|
-
/**
|
|
2051
|
-
* Validate trusted pinned SVG/binary parser evidence against exact members.
|
|
2052
|
-
*
|
|
2053
|
-
* @param {unknown} value trusted passive parser-evidence envelope
|
|
2054
|
-
* @param {ThemePackageFile[]} files checked package files
|
|
2055
|
-
* @param {UnknownRecord[]} assets checked manifest assets
|
|
2056
|
-
* @param {UnknownRecord} fixtureRelease independently validated fixture release
|
|
2057
|
-
* @returns {void}
|
|
2058
|
-
*/
|
|
2059
|
-
function validatePassiveAssetEvidence(value, files, assets, fixtureRelease) {
|
|
2060
|
-
const code = 'THEME_PASSIVE_ASSET_EVIDENCE_INVALID';
|
|
2061
|
-
const records = requireTrustedRunnerEvidence(
|
|
2062
|
-
value,
|
|
2063
|
-
fixtureRelease,
|
|
2064
|
-
'binary',
|
|
2065
|
-
code,
|
|
2066
|
-
);
|
|
2067
|
-
const nonCssAssets = assets
|
|
2068
|
-
.filter((asset) => asset.mediaType !== 'text/css')
|
|
2069
|
-
.sort((left, right) => compareUtf8(String(left.path), String(right.path)));
|
|
2070
|
-
if (records.length !== nonCssAssets.length) invalid(code);
|
|
2071
|
-
for (let index = 0; index < nonCssAssets.length; index += 1) {
|
|
2072
|
-
const asset = nonCssAssets[index];
|
|
2073
|
-
if (!asset || typeof asset.path !== 'string') invalid(code);
|
|
2074
|
-
const evidence = exactRecord(records[index], PASSIVE_EVIDENCE_KEYS, code);
|
|
2075
|
-
const file = requirePackageFile(files, asset.path, code);
|
|
2076
|
-
const limit = PASSIVE_SOURCE_LIMITS[String(asset.mediaType)];
|
|
2077
|
-
if (
|
|
2078
|
-
limit === undefined ||
|
|
2079
|
-
file.bytes.byteLength === 0 ||
|
|
2080
|
-
file.bytes.byteLength > limit ||
|
|
2081
|
-
evidence.path !== asset.path ||
|
|
2082
|
-
evidence.mediaType !== asset.mediaType ||
|
|
2083
|
-
evidence.profile !==
|
|
2084
|
-
(asset.mediaType === 'image/svg+xml'
|
|
2085
|
-
? 'gala-passive-svg-v2'
|
|
2086
|
-
: fixtureRelease.binaryAssetProfile) ||
|
|
2087
|
-
evidence.disposition !== 'accepted' ||
|
|
2088
|
-
evidence.byteLength !== String(file.bytes.byteLength) ||
|
|
2089
|
-
evidence.sha256 !== sha256Tagged(file.bytes)
|
|
2090
|
-
) {
|
|
2091
|
-
invalid(code);
|
|
2092
|
-
}
|
|
2093
|
-
}
|
|
2094
|
-
}
|
|
2095
|
-
|
|
2096
|
-
/**
|
|
2097
|
-
* Validate the exact closed theme package, byte budgets, manifests, licenses,
|
|
2098
|
-
* and trusted parser-evidence projections.
|
|
2099
|
-
*
|
|
2100
|
-
* `context.packageFiles` is the extraction layer's complete stripped-member
|
|
2101
|
-
* observation. `fixtureRelease` is independently validated immutable shared
|
|
2102
|
-
* infra state. `cssEvidence` and `passiveAssetEvidence` are retained envelopes
|
|
2103
|
-
* emitted by the isolated S2 runners whose exact identities appear in that
|
|
2104
|
-
* release; they are context, never fields invented on theme.json. The caller
|
|
2105
|
-
* owns the trusted execution boundary: copying a runner ledger row into an
|
|
2106
|
-
* envelope does not prove execution. `acceptedBudgetCeilings` is the
|
|
2107
|
-
* independently selected release-policy ceiling and is mandatory because
|
|
2108
|
-
* DEC-097 deliberately defines no evidence-free universal package ceiling.
|
|
2109
|
-
*
|
|
2110
|
-
* @param {unknown} value complete theme contract
|
|
2111
|
-
* @param {unknown} context package files, parser evidence, styling catalog, and policy ceilings
|
|
2112
|
-
* @returns {void}
|
|
2113
|
-
*/
|
|
2114
|
-
export function validateThemePackage(value, context) {
|
|
2115
|
-
validateThemeContract(value);
|
|
2116
|
-
const code = 'THEME_PACKAGE_INVALID';
|
|
2117
|
-
const theme = /** @type {UnknownRecord} */ (value);
|
|
2118
|
-
const retained = exactRecord(
|
|
2119
|
-
context,
|
|
2120
|
-
[
|
|
2121
|
-
'packageFiles',
|
|
2122
|
-
'cssEvidence',
|
|
2123
|
-
'passiveAssetEvidence',
|
|
2124
|
-
'stylingContract',
|
|
2125
|
-
'fixtureRelease',
|
|
2126
|
-
'acceptedBudgetCeilings',
|
|
2127
|
-
],
|
|
2128
|
-
code,
|
|
2129
|
-
);
|
|
2130
|
-
const stylingContract = isPlainObject(retained.stylingContract)
|
|
2131
|
-
? retained.stylingContract
|
|
2132
|
-
: invalid(code);
|
|
2133
|
-
const fixtureRelease = isPlainObject(retained.fixtureRelease)
|
|
2134
|
-
? retained.fixtureRelease
|
|
2135
|
-
: invalid(code);
|
|
2136
|
-
try {
|
|
2137
|
-
validateThemeFixtureRelease(fixtureRelease, {
|
|
2138
|
-
bytes: canonicalizeJcsBytes(fixtureRelease),
|
|
2139
|
-
stylingContractDigest: theme.stylingContractDigest,
|
|
2140
|
-
});
|
|
2141
|
-
} catch {
|
|
2142
|
-
invalid(code);
|
|
2143
|
-
}
|
|
2144
|
-
if (
|
|
2145
|
-
stylingContract.catalogDigest !== theme.stylingContractDigest ||
|
|
2146
|
-
fixtureRelease.contractVersion !== theme.contractVersion ||
|
|
2147
|
-
fixtureRelease.browserPolicyRef !== theme.browserPolicyRef ||
|
|
2148
|
-
fixtureRelease.fixtureDigest !== theme.fixtureDigest ||
|
|
2149
|
-
fixtureRelease.stylingContractDigest !== theme.stylingContractDigest ||
|
|
2150
|
-
!Array.isArray(fixtureRelease.fixtures) ||
|
|
2151
|
-
!stringArrayEquals(
|
|
2152
|
-
theme.fixtures,
|
|
2153
|
-
fixtureRelease.fixtures.map((candidate) =>
|
|
2154
|
-
String(exactRecord(candidate, FIXTURE_DEFINITION_KEYS, code).fixtureId),
|
|
2155
|
-
),
|
|
2156
|
-
)
|
|
2157
|
-
) {
|
|
2158
|
-
invalid(code);
|
|
2159
|
-
}
|
|
2160
|
-
const files = validatePackageFiles(retained.packageFiles, code);
|
|
2161
|
-
const budgets = validateBudgets(theme.budgets, code);
|
|
2162
|
-
const ceilings = validateBudgets(retained.acceptedBudgetCeilings, code);
|
|
2163
|
-
if (
|
|
2164
|
-
budgets.maximumFileBytes > ceilings.maximumFileBytes ||
|
|
2165
|
-
budgets.maximumTotalBytes > ceilings.maximumTotalBytes ||
|
|
2166
|
-
budgets.maximumFiles > ceilings.maximumFiles
|
|
2167
|
-
) {
|
|
2168
|
-
invalid(code);
|
|
2169
|
-
}
|
|
2170
|
-
|
|
2171
|
-
let totalBytes = 0n;
|
|
2172
|
-
for (const file of files) {
|
|
2173
|
-
const byteLength = BigInt(file.bytes.byteLength);
|
|
2174
|
-
totalBytes += byteLength;
|
|
2175
|
-
if (byteLength > budgets.maximumFileBytes) invalid(code);
|
|
2176
|
-
}
|
|
2177
|
-
if (
|
|
2178
|
-
files.length > budgets.maximumFiles ||
|
|
2179
|
-
totalBytes > budgets.maximumTotalBytes
|
|
2180
|
-
) {
|
|
2181
|
-
invalid(code);
|
|
2182
|
-
}
|
|
2183
|
-
|
|
2184
|
-
if (!Array.isArray(theme.assets) || !Array.isArray(theme.stylesheets)) {
|
|
2185
|
-
invalid(code);
|
|
2186
|
-
}
|
|
2187
|
-
const assets = theme.assets.map(validatePassiveAsset);
|
|
2188
|
-
const stylesheetSet = new Set(theme.stylesheets.map((path) => String(path)));
|
|
2189
|
-
const assetByPath = new Map(
|
|
2190
|
-
assets.map((asset) => [String(asset.path), asset]),
|
|
2191
|
-
);
|
|
2192
|
-
if (assetByPath.size !== assets.length) invalid(code);
|
|
2193
|
-
for (const path of stylesheetSet) {
|
|
2194
|
-
const asset = assetByPath.get(path);
|
|
2195
|
-
if (!asset || asset.mediaType !== 'text/css') invalid(code);
|
|
2196
|
-
}
|
|
2197
|
-
const nonCssAssets = assets.filter((asset) => {
|
|
2198
|
-
if (typeof asset.path !== 'string') invalid(code);
|
|
2199
|
-
if (stylesheetSet.has(asset.path)) return false;
|
|
2200
|
-
if (
|
|
2201
|
-
asset.mediaType === 'text/css' ||
|
|
2202
|
-
mediaTypeForAssetPath(asset.path, code) !== asset.mediaType
|
|
2203
|
-
) {
|
|
2204
|
-
invalid(code);
|
|
2205
|
-
}
|
|
2206
|
-
return true;
|
|
2207
|
-
});
|
|
2208
|
-
if (assets.length !== stylesheetSet.size + nonCssAssets.length) invalid(code);
|
|
2209
|
-
|
|
2210
|
-
const expectedPaths = [
|
|
2211
|
-
'package.json',
|
|
2212
|
-
'theme.json',
|
|
2213
|
-
...theme.stylesheets.map((path) => String(path)),
|
|
2214
|
-
'LICENSE',
|
|
2215
|
-
'README.md',
|
|
2216
|
-
...nonCssAssets.map((asset) => String(asset.path)),
|
|
2217
|
-
].sort(compareUtf8);
|
|
2218
|
-
const actualPaths = files.map((file) => file.path).sort(compareUtf8);
|
|
2219
|
-
if (!stringArrayEquals(actualPaths, expectedPaths)) invalid(code);
|
|
2220
|
-
|
|
2221
|
-
for (const asset of assets) {
|
|
2222
|
-
if (typeof asset.path !== 'string') invalid(code);
|
|
2223
|
-
const file = requirePackageFile(files, asset.path, code);
|
|
2224
|
-
validateAssetBytes(asset, file, code);
|
|
2225
|
-
if (asset.mediaType !== 'text/css') {
|
|
2226
|
-
const limit = PASSIVE_SOURCE_LIMITS[String(asset.mediaType)];
|
|
2227
|
-
if (
|
|
2228
|
-
limit === undefined ||
|
|
2229
|
-
file.bytes.byteLength === 0 ||
|
|
2230
|
-
file.bytes.byteLength > limit
|
|
2231
|
-
) {
|
|
2232
|
-
invalid(code);
|
|
2233
|
-
}
|
|
2234
|
-
}
|
|
2235
|
-
}
|
|
2236
|
-
|
|
2237
|
-
const themeFile = requirePackageFile(files, 'theme.json', code);
|
|
2238
|
-
requireCanonicalBytes(themeFile.bytes, theme, code);
|
|
2239
|
-
const packageManifestPaths = [
|
|
2240
|
-
'theme.json',
|
|
2241
|
-
...theme.stylesheets.map((path) => String(path)),
|
|
2242
|
-
...nonCssAssets.map((asset) => String(asset.path)),
|
|
2243
|
-
].sort(compareUtf8);
|
|
2244
|
-
const packageExpression = validatePackageJson(
|
|
2245
|
-
files,
|
|
2246
|
-
theme,
|
|
2247
|
-
packageManifestPaths,
|
|
2248
|
-
code,
|
|
2249
|
-
);
|
|
2250
|
-
validateLicenseEvidence(files, assets, packageExpression, code);
|
|
2251
|
-
validateCssEvidence(
|
|
2252
|
-
retained.cssEvidence,
|
|
2253
|
-
theme,
|
|
2254
|
-
stylingContract,
|
|
2255
|
-
fixtureRelease,
|
|
2256
|
-
files,
|
|
2257
|
-
assets,
|
|
2258
|
-
);
|
|
2259
|
-
validatePassiveAssetEvidence(
|
|
2260
|
-
retained.passiveAssetEvidence,
|
|
2261
|
-
files,
|
|
2262
|
-
assets,
|
|
2263
|
-
fixtureRelease,
|
|
2264
|
-
);
|
|
2265
|
-
|
|
2266
|
-
let integrity;
|
|
2267
|
-
try {
|
|
2268
|
-
integrity = computeThemePackageIntegrity(theme, files);
|
|
2269
|
-
} catch {
|
|
2270
|
-
invalid(code);
|
|
2271
|
-
}
|
|
2272
|
-
if (theme.integrity !== integrity) invalid(code);
|
|
2273
|
-
}
|
|
2274
|
-
|
|
2275
|
-
/**
|
|
2276
|
-
* Validate the complete DEC-097 theme composition across the selected lock,
|
|
2277
|
-
* template catalog, package, fixture release, and conformance result.
|
|
2278
|
-
*
|
|
2279
|
-
* The context ledger is exact and consists only of independently retained or
|
|
2280
|
-
* integrity-verified inputs:
|
|
2281
|
-
*
|
|
2282
|
-
* - `lockedTheme` and `lockedTemplate`: selected lock rows;
|
|
2283
|
-
* - styling/fixture/result objects plus their exact compact-JCS bytes;
|
|
2284
|
-
* - complete extracted package-file observations;
|
|
2285
|
-
* - pinned CSS/passive parser evidence; and
|
|
2286
|
-
* - selected release-policy budget ceilings.
|
|
2287
|
-
*
|
|
2288
|
-
* @param {unknown} value complete theme-contract instance
|
|
2289
|
-
* @param {unknown} context exact retained validation context
|
|
2290
|
-
* @returns {void}
|
|
2291
|
-
*/
|
|
2292
|
-
export function validateThemeComposition(value, context) {
|
|
2293
|
-
validateThemeContract(value);
|
|
2294
|
-
const code = 'THEME_COMPOSITION_INVALID';
|
|
2295
|
-
const theme = /** @type {UnknownRecord} */ (value);
|
|
2296
|
-
const retained = exactRecord(
|
|
2297
|
-
context,
|
|
2298
|
-
[
|
|
2299
|
-
'lockedTheme',
|
|
2300
|
-
'lockedTemplate',
|
|
2301
|
-
'templateStylingContract',
|
|
2302
|
-
'templateStylingContractBytes',
|
|
2303
|
-
'fixtureRelease',
|
|
2304
|
-
'fixtureReleaseBytes',
|
|
2305
|
-
'conformanceResult',
|
|
2306
|
-
'conformanceResultBytes',
|
|
2307
|
-
'packageFiles',
|
|
2308
|
-
'cssEvidence',
|
|
2309
|
-
'passiveAssetEvidence',
|
|
2310
|
-
'acceptedBudgetCeilings',
|
|
2311
|
-
],
|
|
2312
|
-
code,
|
|
2313
|
-
);
|
|
2314
|
-
const lockedTheme = exactRecord(
|
|
2315
|
-
retained.lockedTheme,
|
|
2316
|
-
[
|
|
2317
|
-
'package',
|
|
2318
|
-
'version',
|
|
2319
|
-
'integrity',
|
|
2320
|
-
'registry',
|
|
2321
|
-
'contractVersion',
|
|
2322
|
-
'compatibleWith',
|
|
2323
|
-
],
|
|
2324
|
-
code,
|
|
2325
|
-
);
|
|
2326
|
-
const lockedTemplate = exactRecord(
|
|
2327
|
-
retained.lockedTemplate,
|
|
2328
|
-
[
|
|
2329
|
-
'package',
|
|
2330
|
-
'version',
|
|
2331
|
-
'integrity',
|
|
2332
|
-
'registry',
|
|
2333
|
-
'contractVersion',
|
|
2334
|
-
'compatibleWith',
|
|
2335
|
-
'templateModules',
|
|
2336
|
-
],
|
|
2337
|
-
code,
|
|
2338
|
-
);
|
|
2339
|
-
const stylingContract = isPlainObject(retained.templateStylingContract)
|
|
2340
|
-
? retained.templateStylingContract
|
|
2341
|
-
: invalid(code);
|
|
2342
|
-
const fixtureRelease = isPlainObject(retained.fixtureRelease)
|
|
2343
|
-
? retained.fixtureRelease
|
|
2344
|
-
: invalid(code);
|
|
2345
|
-
const conformanceResult = isPlainObject(retained.conformanceResult)
|
|
2346
|
-
? retained.conformanceResult
|
|
2347
|
-
: invalid(code);
|
|
2348
|
-
|
|
2349
|
-
const themeIdentity = parsePackageExact(theme.package, code);
|
|
2350
|
-
if (
|
|
2351
|
-
lockedTheme.package !== themeIdentity.name ||
|
|
2352
|
-
lockedTheme.version !== themeIdentity.version ||
|
|
2353
|
-
lockedTheme.contractVersion !== theme.contractVersion ||
|
|
2354
|
-
lockedTheme.compatibleWith !== theme.templateRange ||
|
|
2355
|
-
lockedTemplate.package !== '@rathnasgala2/template' ||
|
|
2356
|
-
!stringArrayEquals(lockedTemplate.templateModules, [])
|
|
2357
|
-
) {
|
|
2358
|
-
invalid(code);
|
|
2359
|
-
}
|
|
2360
|
-
requireSemver(lockedTheme.version, code);
|
|
2361
|
-
requireDigest(lockedTheme.integrity, code);
|
|
2362
|
-
requireSemver(lockedTheme.contractVersion, code);
|
|
2363
|
-
requireSemverRange(lockedTheme.compatibleWith, code);
|
|
2364
|
-
requireSemver(lockedTemplate.version, code);
|
|
2365
|
-
requireDigest(lockedTemplate.integrity, code);
|
|
2366
|
-
requireSemver(lockedTemplate.contractVersion, code);
|
|
2367
|
-
requireSemverRange(lockedTemplate.compatibleWith, code);
|
|
2368
|
-
try {
|
|
2369
|
-
if (
|
|
2370
|
-
!satisfiesSemverRange(
|
|
2371
|
-
String(lockedTemplate.version),
|
|
2372
|
-
String(theme.templateRange),
|
|
2373
|
-
)
|
|
2374
|
-
) {
|
|
2375
|
-
invalid(code);
|
|
2376
|
-
}
|
|
2377
|
-
} catch {
|
|
2378
|
-
invalid(code);
|
|
2379
|
-
}
|
|
2380
|
-
if (theme.integrity === lockedTheme.integrity) invalid(code);
|
|
2381
|
-
|
|
2382
|
-
validateTemplateStylingContract(stylingContract, {
|
|
2383
|
-
bytes: retained.templateStylingContractBytes,
|
|
2384
|
-
lockedTemplate,
|
|
2385
|
-
});
|
|
2386
|
-
if (
|
|
2387
|
-
stylingContract.contractVersion !== lockedTemplate.contractVersion ||
|
|
2388
|
-
theme.stylingContractDigest !== stylingContract.catalogDigest
|
|
2389
|
-
) {
|
|
2390
|
-
invalid(code);
|
|
2391
|
-
}
|
|
2392
|
-
validateThemeFixtureRelease(fixtureRelease, {
|
|
2393
|
-
bytes: retained.fixtureReleaseBytes,
|
|
2394
|
-
stylingContractDigest: stylingContract.catalogDigest,
|
|
2395
|
-
});
|
|
2396
|
-
if (
|
|
2397
|
-
theme.contractVersion !== fixtureRelease.contractVersion ||
|
|
2398
|
-
theme.browserPolicyRef !== fixtureRelease.browserPolicyRef ||
|
|
2399
|
-
theme.fixtureDigest !== fixtureRelease.fixtureDigest ||
|
|
2400
|
-
theme.stylingContractDigest !== fixtureRelease.stylingContractDigest ||
|
|
2401
|
-
!Array.isArray(fixtureRelease.fixtures) ||
|
|
2402
|
-
!stringArrayEquals(
|
|
2403
|
-
theme.fixtures,
|
|
2404
|
-
fixtureRelease.fixtures.map((candidate) =>
|
|
2405
|
-
String(exactRecord(candidate, FIXTURE_DEFINITION_KEYS, code).fixtureId),
|
|
2406
|
-
),
|
|
2407
|
-
)
|
|
2408
|
-
) {
|
|
2409
|
-
invalid(code);
|
|
2410
|
-
}
|
|
2411
|
-
|
|
2412
|
-
validateThemePackage(theme, {
|
|
2413
|
-
packageFiles: retained.packageFiles,
|
|
2414
|
-
cssEvidence: retained.cssEvidence,
|
|
2415
|
-
passiveAssetEvidence: retained.passiveAssetEvidence,
|
|
2416
|
-
stylingContract,
|
|
2417
|
-
fixtureRelease,
|
|
2418
|
-
acceptedBudgetCeilings: retained.acceptedBudgetCeilings,
|
|
2419
|
-
});
|
|
2420
|
-
|
|
2421
|
-
let inputDigest;
|
|
2422
|
-
try {
|
|
2423
|
-
inputDigest = computeThemeConformanceInputDigest(
|
|
2424
|
-
theme,
|
|
2425
|
-
retained.packageFiles,
|
|
2426
|
-
);
|
|
2427
|
-
} catch {
|
|
2428
|
-
invalid(code);
|
|
2429
|
-
}
|
|
2430
|
-
validateThemeConformanceResult(conformanceResult, {
|
|
2431
|
-
bytes: retained.conformanceResultBytes,
|
|
2432
|
-
fixtureRelease,
|
|
2433
|
-
themeConformanceInputDigest: inputDigest,
|
|
2434
|
-
});
|
|
2435
|
-
if (
|
|
2436
|
-
conformanceResult.overallState !== 'pass' ||
|
|
2437
|
-
theme.evidenceDigest !== conformanceResult.evidenceDigest
|
|
2438
|
-
) {
|
|
2439
|
-
invalid(code);
|
|
2440
|
-
}
|
|
2441
|
-
}
|