@uncefact/untp-utils 0.1.0 → 0.2.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 +23 -1
- package/build/artefacts/detect-version-from-context.d.ts +46 -0
- package/build/artefacts/detect-version-from-context.js +77 -0
- package/build/artefacts/detect-version-from-context.js.map +1 -0
- package/build/artefacts/detect-version-from-context.test.d.ts +1 -0
- package/build/artefacts/detect-version-from-context.test.js +69 -0
- package/build/artefacts/detect-version-from-context.test.js.map +1 -0
- package/build/artefacts/index.d.ts +3 -0
- package/build/artefacts/index.js +4 -0
- package/build/artefacts/index.js.map +1 -0
- package/build/artefacts/urls.d.ts +79 -0
- package/build/artefacts/urls.js +133 -0
- package/build/artefacts/urls.js.map +1 -0
- package/build/artefacts/urls.test.d.ts +1 -0
- package/build/artefacts/urls.test.js +91 -0
- package/build/artefacts/urls.test.js.map +1 -0
- package/build/artefacts/version.d.ts +9 -0
- package/build/artefacts/version.js +17 -0
- package/build/artefacts/version.js.map +1 -0
- package/build/artefacts/version.test.d.ts +1 -0
- package/build/artefacts/version.test.js +16 -0
- package/build/artefacts/version.test.js.map +1 -0
- package/build/cache/in-memory-ttl-cache.d.ts +2 -0
- package/build/cache/in-memory-ttl-cache.js +76 -0
- package/build/cache/in-memory-ttl-cache.js.map +1 -0
- package/build/cache/in-memory-ttl-cache.test.d.ts +1 -0
- package/build/cache/in-memory-ttl-cache.test.js +236 -0
- package/build/cache/in-memory-ttl-cache.test.js.map +1 -0
- package/build/cache/index.d.ts +2 -0
- package/build/cache/index.js +2 -0
- package/build/cache/index.js.map +1 -0
- package/build/cache/ttl-cache.d.ts +22 -0
- package/build/cache/ttl-cache.js +2 -0
- package/build/cache/ttl-cache.js.map +1 -0
- package/build/common/as-non-empty-string.d.ts +7 -0
- package/build/common/as-non-empty-string.js +10 -0
- package/build/common/as-non-empty-string.js.map +1 -0
- package/build/common/as-non-empty-string.test.d.ts +1 -0
- package/build/common/as-non-empty-string.test.js +25 -0
- package/build/common/as-non-empty-string.test.js.map +1 -0
- package/build/common/require-string.d.ts +12 -0
- package/build/common/require-string.js +27 -0
- package/build/common/require-string.js.map +1 -0
- package/build/common/require-string.test.d.ts +1 -0
- package/build/common/require-string.test.js +53 -0
- package/build/common/require-string.test.js.map +1 -0
- package/build/conformity-vocabulary/codes.d.ts +10 -0
- package/build/conformity-vocabulary/codes.js +10 -0
- package/build/conformity-vocabulary/codes.js.map +1 -0
- package/build/conformity-vocabulary/errors.d.ts +44 -0
- package/build/conformity-vocabulary/errors.js +68 -0
- package/build/conformity-vocabulary/errors.js.map +1 -0
- package/build/conformity-vocabulary/index.d.ts +6 -0
- package/build/conformity-vocabulary/index.js +7 -0
- package/build/conformity-vocabulary/index.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.d.ts +26 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.js +106 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.test.d.ts +1 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.test.js +327 -0
- package/build/conformity-vocabulary/parse-conformity-catalogue.test.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.d.ts +28 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.js +47 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.js.map +1 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.test.d.ts +1 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.test.js +284 -0
- package/build/conformity-vocabulary/parse-conformity-scheme.test.js.map +1 -0
- package/build/conformity-vocabulary/parsers/v0-7-0.parser.d.ts +19 -0
- package/build/conformity-vocabulary/parsers/v0-7-0.parser.js +219 -0
- package/build/conformity-vocabulary/parsers/v0-7-0.parser.js.map +1 -0
- package/build/conformity-vocabulary/types.d.ts +180 -0
- package/build/conformity-vocabulary/types.js +2 -0
- package/build/conformity-vocabulary/types.js.map +1 -0
- package/build/conformity-vocabulary/validate-conformity-claim.d.ts +26 -0
- package/build/conformity-vocabulary/validate-conformity-claim.js +165 -0
- package/build/conformity-vocabulary/validate-conformity-claim.js.map +1 -0
- package/build/conformity-vocabulary/validate-conformity-claim.test.d.ts +1 -0
- package/build/conformity-vocabulary/validate-conformity-claim.test.js +478 -0
- package/build/conformity-vocabulary/validate-conformity-claim.test.js.map +1 -0
- package/build/http-headers/index.d.ts +5 -0
- package/build/http-headers/index.js +6 -0
- package/build/http-headers/index.js.map +1 -0
- package/build/http-headers/is-safe-header-value.d.ts +10 -0
- package/build/http-headers/is-safe-header-value.js +15 -0
- package/build/http-headers/is-safe-header-value.js.map +1 -0
- package/build/http-headers/is-safe-header-value.test.d.ts +1 -0
- package/build/http-headers/is-safe-header-value.test.js +37 -0
- package/build/http-headers/is-safe-header-value.test.js.map +1 -0
- package/build/http-headers/parse-entity-tag.d.ts +9 -0
- package/build/http-headers/parse-entity-tag.js +18 -0
- package/build/http-headers/parse-entity-tag.js.map +1 -0
- package/build/http-headers/parse-entity-tag.test.d.ts +1 -0
- package/build/http-headers/parse-entity-tag.test.js +41 -0
- package/build/http-headers/parse-entity-tag.test.js.map +1 -0
- package/build/http-headers/parse-imf-date.d.ts +13 -0
- package/build/http-headers/parse-imf-date.js +23 -0
- package/build/http-headers/parse-imf-date.js.map +1 -0
- package/build/http-headers/parse-imf-date.test.d.ts +1 -0
- package/build/http-headers/parse-imf-date.test.js +31 -0
- package/build/http-headers/parse-imf-date.test.js.map +1 -0
- package/build/http-headers/parse-media-type.d.ts +8 -0
- package/build/http-headers/parse-media-type.js +21 -0
- package/build/http-headers/parse-media-type.js.map +1 -0
- package/build/http-headers/parse-media-type.test.d.ts +1 -0
- package/build/http-headers/parse-media-type.test.js +39 -0
- package/build/http-headers/parse-media-type.test.js.map +1 -0
- package/build/http-headers/user-agent.d.ts +35 -0
- package/build/http-headers/user-agent.js +45 -0
- package/build/http-headers/user-agent.js.map +1 -0
- package/build/http-headers/user-agent.test.d.ts +1 -0
- package/build/http-headers/user-agent.test.js +27 -0
- package/build/http-headers/user-agent.test.js.map +1 -0
- package/build/index.d.ts +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/loaders/errors.d.ts +21 -0
- package/build/loaders/errors.js +45 -0
- package/build/loaders/errors.js.map +1 -0
- package/build/loaders/index.d.ts +3 -0
- package/build/loaders/index.js +4 -0
- package/build/loaders/index.js.map +1 -0
- package/build/loaders/jsonld-document-loader.d.ts +46 -0
- package/build/loaders/jsonld-document-loader.js +34 -0
- package/build/loaders/jsonld-document-loader.js.map +1 -0
- package/build/loaders/jsonld-document-loader.test.d.ts +1 -0
- package/build/loaders/jsonld-document-loader.test.js +71 -0
- package/build/loaders/jsonld-document-loader.test.js.map +1 -0
- package/build/loaders/schema-loader.d.ts +21 -0
- package/build/loaders/schema-loader.js +67 -0
- package/build/loaders/schema-loader.js.map +1 -0
- package/build/loaders/schema-loader.ssrf.test.d.ts +1 -0
- package/build/loaders/schema-loader.ssrf.test.js +55 -0
- package/build/loaders/schema-loader.ssrf.test.js.map +1 -0
- package/build/loaders/schema-loader.test.d.ts +1 -0
- package/build/loaders/schema-loader.test.js +162 -0
- package/build/loaders/schema-loader.test.js.map +1 -0
- package/build/multibase-digest/multibase-digest.d.ts +23 -0
- package/build/multibase-digest/multibase-digest.js +40 -0
- package/build/multibase-digest/multibase-digest.js.map +1 -1
- package/build/multibase-digest/multibase-digest.test.js +46 -0
- package/build/multibase-digest/multibase-digest.test.js.map +1 -1
- package/build/node/errors.d.ts +41 -0
- package/build/node/errors.js +80 -0
- package/build/node/errors.js.map +1 -0
- package/build/node/index.d.ts +3 -0
- package/build/node/index.js +4 -0
- package/build/node/index.js.map +1 -0
- package/build/node/is-private-ip.d.ts +41 -0
- package/build/node/is-private-ip.js +138 -0
- package/build/node/is-private-ip.js.map +1 -0
- package/build/node/is-private-ip.test.d.ts +1 -0
- package/build/node/is-private-ip.test.js +96 -0
- package/build/node/is-private-ip.test.js.map +1 -0
- package/build/node/validate-public-url.d.ts +49 -0
- package/build/node/validate-public-url.js +94 -0
- package/build/node/validate-public-url.js.map +1 -0
- package/build/node/validate-public-url.test.d.ts +1 -0
- package/build/node/validate-public-url.test.js +177 -0
- package/build/node/validate-public-url.test.js.map +1 -0
- package/build/resolvers/errors.d.ts +43 -0
- package/build/resolvers/errors.js +99 -0
- package/build/resolvers/errors.js.map +1 -0
- package/build/resolvers/index.d.ts +5 -0
- package/build/resolvers/index.js +6 -0
- package/build/resolvers/index.js.map +1 -0
- package/build/resolvers/resolve-document-if-changed.d.ts +48 -0
- package/build/resolvers/resolve-document-if-changed.js +42 -0
- package/build/resolvers/resolve-document-if-changed.js.map +1 -0
- package/build/resolvers/resolve-document-if-changed.test.d.ts +1 -0
- package/build/resolvers/resolve-document-if-changed.test.js +109 -0
- package/build/resolvers/resolve-document-if-changed.test.js.map +1 -0
- package/build/resolvers/resolve-document.d.ts +86 -0
- package/build/resolvers/resolve-document.js +239 -0
- package/build/resolvers/resolve-document.js.map +1 -0
- package/build/resolvers/resolve-document.test.d.ts +1 -0
- package/build/resolvers/resolve-document.test.js +299 -0
- package/build/resolvers/resolve-document.test.js.map +1 -0
- package/build/resolvers/resolve-json-document.d.ts +40 -0
- package/build/resolvers/resolve-json-document.js +42 -0
- package/build/resolvers/resolve-json-document.js.map +1 -0
- package/build/resolvers/resolve-json-document.test.d.ts +1 -0
- package/build/resolvers/resolve-json-document.test.js +61 -0
- package/build/resolvers/resolve-json-document.test.js.map +1 -0
- package/build/structured-error.d.ts +49 -0
- package/build/structured-error.js +17 -0
- package/build/structured-error.js.map +1 -0
- package/build/structured-error.test.d.ts +1 -0
- package/build/structured-error.test.js +112 -0
- package/build/structured-error.test.js.map +1 -0
- package/build/validation/describe-jsonld-failure.d.ts +50 -0
- package/build/validation/describe-jsonld-failure.js +104 -0
- package/build/validation/describe-jsonld-failure.js.map +1 -0
- package/build/validation/describe-jsonld-failure.test.d.ts +1 -0
- package/build/validation/describe-jsonld-failure.test.js +141 -0
- package/build/validation/describe-jsonld-failure.test.js.map +1 -0
- package/build/validation/errors.d.ts +40 -0
- package/build/validation/errors.js +75 -0
- package/build/validation/errors.js.map +1 -0
- package/build/validation/index.d.ts +4 -0
- package/build/validation/index.js +5 -0
- package/build/validation/index.js.map +1 -0
- package/build/validation/validate-against-schemas.d.ts +22 -0
- package/build/validation/validate-against-schemas.js +65 -0
- package/build/validation/validate-against-schemas.js.map +1 -0
- package/build/validation/validate-against-schemas.test.d.ts +1 -0
- package/build/validation/validate-against-schemas.test.js +169 -0
- package/build/validation/validate-against-schemas.test.js.map +1 -0
- package/build/validation/validate-jsonld.context-cache.test.d.ts +1 -0
- package/build/validation/validate-jsonld.context-cache.test.js +32 -0
- package/build/validation/validate-jsonld.context-cache.test.js.map +1 -0
- package/build/validation/validate-jsonld.d.ts +33 -0
- package/build/validation/validate-jsonld.js +99 -0
- package/build/validation/validate-jsonld.js.map +1 -0
- package/build/validation/validate-jsonld.ssrf.test.d.ts +1 -0
- package/build/validation/validate-jsonld.ssrf.test.js +108 -0
- package/build/validation/validate-jsonld.ssrf.test.js.map +1 -0
- package/build/validation/validate-jsonld.test.d.ts +1 -0
- package/build/validation/validate-jsonld.test.js +200 -0
- package/build/validation/validate-jsonld.test.js.map +1 -0
- package/package.json +64 -3
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import type { StructuredWarning } from '../structured-error.js';
|
|
2
|
+
import type { ConformityWarningCode } from './codes.js';
|
|
3
|
+
/**
|
|
4
|
+
* Reference to the scheme owner. Optional; not all scheme documents carry it.
|
|
5
|
+
*/
|
|
6
|
+
export interface ConformitySchemeOwner {
|
|
7
|
+
/** Owner URI (typically a website or registered identifier). */
|
|
8
|
+
canonicalId?: string;
|
|
9
|
+
/** Human-readable owner name. */
|
|
10
|
+
name?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* A topic the criterion addresses (e.g. a SKOS concept from the UNTP
|
|
14
|
+
* conformity-topic vocabulary).
|
|
15
|
+
*/
|
|
16
|
+
export interface ConformityTopic {
|
|
17
|
+
/** Topic URI. */
|
|
18
|
+
canonicalId: string;
|
|
19
|
+
/** Human-readable name, when the topic is inlined as a structured object. */
|
|
20
|
+
name?: string;
|
|
21
|
+
/** Free-text definition, when present. */
|
|
22
|
+
definition?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A single auditable criterion within a profile.
|
|
26
|
+
*
|
|
27
|
+
* The criterion URI is stable and versioned per spec (e.g.
|
|
28
|
+
* `myscheme.org/criterion/forced-labour/1.0.0`).
|
|
29
|
+
*/
|
|
30
|
+
export interface ConformityCriterion {
|
|
31
|
+
/** Canonical (versioned) criterion URI. */
|
|
32
|
+
canonicalId: string;
|
|
33
|
+
/** Human-readable criterion name. */
|
|
34
|
+
name: string;
|
|
35
|
+
/** Criterion version string (also encoded in `canonicalId`). */
|
|
36
|
+
version: string;
|
|
37
|
+
/** Lifecycle status, e.g. `active`. */
|
|
38
|
+
status: string;
|
|
39
|
+
description?: string;
|
|
40
|
+
documentation?: string;
|
|
41
|
+
/** Conformity topics this criterion addresses. */
|
|
42
|
+
topics: ConformityTopic[];
|
|
43
|
+
/** Free-form tags attached to the criterion. */
|
|
44
|
+
tags: string[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* A profile within a scheme. Profile URI is stable and versioned per spec.
|
|
48
|
+
*/
|
|
49
|
+
export interface ConformityProfile {
|
|
50
|
+
/** Canonical (versioned) profile URI. */
|
|
51
|
+
canonicalId: string;
|
|
52
|
+
name: string;
|
|
53
|
+
/** Profile version string (also encoded in `canonicalId`). */
|
|
54
|
+
version: string;
|
|
55
|
+
/** Lifecycle status, e.g. `active`. */
|
|
56
|
+
status: string;
|
|
57
|
+
description?: string;
|
|
58
|
+
documentation?: string;
|
|
59
|
+
/** Optional ISO-8601 date the profile becomes valid. */
|
|
60
|
+
validFrom?: string;
|
|
61
|
+
/** Criteria inlined within this profile. */
|
|
62
|
+
criteria: ConformityCriterion[];
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* A parsed conformity scheme as published by a scheme owner.
|
|
66
|
+
*
|
|
67
|
+
* The scheme URI is stable but not independently versioned. Profiles and
|
|
68
|
+
* criteria inside the scheme carry their own version segments.
|
|
69
|
+
*
|
|
70
|
+
* @see https://untp.unece.org/docs/specification/ConformityVocabularyCatalog
|
|
71
|
+
*/
|
|
72
|
+
export interface ConformityScheme {
|
|
73
|
+
/** Canonical scheme URI (no version segment). */
|
|
74
|
+
canonicalId: string;
|
|
75
|
+
/** URL the scheme document was fetched from (callers pass this in). */
|
|
76
|
+
sourceUrl: string;
|
|
77
|
+
/** CVC specification version that was used to parse this document. */
|
|
78
|
+
specVersion: string;
|
|
79
|
+
/** Human-readable scheme name. */
|
|
80
|
+
name: string;
|
|
81
|
+
description?: string;
|
|
82
|
+
documentation?: string;
|
|
83
|
+
owner?: ConformitySchemeOwner;
|
|
84
|
+
profiles: ConformityProfile[];
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* One entry in the UNTP Conformity Vocabulary Catalogue Register. Ingestion
|
|
88
|
+
* consumers route on {@link status} (skipping deprecated entries) and fetch
|
|
89
|
+
* the scheme document from {@link vocabularyUrl}.
|
|
90
|
+
*/
|
|
91
|
+
export interface ConformityCatalogueEntry {
|
|
92
|
+
/** CVC-canonical scheme URI; from the register entry's `id`. */
|
|
93
|
+
canonicalId: string;
|
|
94
|
+
/** Owner-published scheme document URL; from the register entry's `vocabularyURL`. Validated as a parseable URL at parse time. */
|
|
95
|
+
vocabularyUrl: string;
|
|
96
|
+
/** Human-readable scheme name. */
|
|
97
|
+
name: string;
|
|
98
|
+
/** Lifecycle status of the scheme in the register, when supplied (`'pilot'`, `'active'`, `'deprecated'`, etc.). */
|
|
99
|
+
status?: string;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Warnings emitted by {@link validateConformityClaim}. Narrows
|
|
103
|
+
* {@link StructuredWarning} so the `code` is one of the validator's known codes.
|
|
104
|
+
*/
|
|
105
|
+
export type ConformityWarning = StructuredWarning & {
|
|
106
|
+
code: ConformityWarningCode;
|
|
107
|
+
};
|
|
108
|
+
/**
|
|
109
|
+
* A single criterion entry on a credential's conformity claim. The credential
|
|
110
|
+
* issuer asserts conformity to `criterion` and may classify it with conformity
|
|
111
|
+
* topics.
|
|
112
|
+
*/
|
|
113
|
+
export interface ConformityClaimCriterion {
|
|
114
|
+
/** Criterion URI the claim references. */
|
|
115
|
+
criterion: string;
|
|
116
|
+
/**
|
|
117
|
+
* Topic URIs the claim declares for this criterion. Optional and
|
|
118
|
+
* version-specific: an extractor populates it only when its data model
|
|
119
|
+
* carries criterion topics. A criterion may be classified by more than one
|
|
120
|
+
* topic, so it is a list; when present, the validator checks every entry
|
|
121
|
+
* against the criterion's published topic set.
|
|
122
|
+
*/
|
|
123
|
+
conformityTopics?: string[];
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* A single assessment entry on a credential's conformity claim: the criteria
|
|
127
|
+
* the assessment references and the topics it declares for itself. The
|
|
128
|
+
* declared topics are validated against the deduplicated union of the
|
|
129
|
+
* published topics of the assessment's criteria, in one direction only: a
|
|
130
|
+
* declared topic outside the union warns, while a union topic the assessment
|
|
131
|
+
* does not declare is acceptable, because the assessment's topics are a
|
|
132
|
+
* categorisation rather than an exhaustive enumeration.
|
|
133
|
+
*/
|
|
134
|
+
export interface ConformityClaimAssessment {
|
|
135
|
+
/**
|
|
136
|
+
* Criterion URIs the assessment references. Extractors must also emit every
|
|
137
|
+
* entry here as a {@link ConformityClaimCriterion} in the claim's `criteria`
|
|
138
|
+
* list: the validator's assessment check skips unresolved criteria on the
|
|
139
|
+
* assumption that `conformity-criterion.not-in-profile` has already surfaced
|
|
140
|
+
* them from `criteria`, so an entry present only here would silently escape
|
|
141
|
+
* both checks.
|
|
142
|
+
*/
|
|
143
|
+
criteria: string[];
|
|
144
|
+
/** Topic URIs the assessment declares for itself. */
|
|
145
|
+
conformityTopics: string[];
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* A conformity claim extracted from a Digital Conformity Credential, in the
|
|
149
|
+
* minimal shape the validator needs.
|
|
150
|
+
*
|
|
151
|
+
* This type is the version-neutral interlingua between the version-specific
|
|
152
|
+
* data model bridge extractors and {@link validateConformityClaim}. Its fields
|
|
153
|
+
* are optional capabilities keyed on presence, not on spec version: an
|
|
154
|
+
* extractor populates a field only when its data model carries the concept,
|
|
155
|
+
* and the validator runs a rule only when the data is present. Never repurpose
|
|
156
|
+
* a field with changed semantics for a new spec version; add a new field, or
|
|
157
|
+
* fork the validation rules into versioned modules (the delta pattern the
|
|
158
|
+
* `parsers/` directory already uses) the first time a rule genuinely differs
|
|
159
|
+
* between versions. A version conditional inside the shared validator is the
|
|
160
|
+
* signal to fork, not a fix. See ADR-033 (update of 2026-07-13).
|
|
161
|
+
*/
|
|
162
|
+
export interface ConformityClaim {
|
|
163
|
+
/** Scheme URI the claim references. */
|
|
164
|
+
scheme: string;
|
|
165
|
+
/**
|
|
166
|
+
* Profile URI the claim references. Optional because not every data model
|
|
167
|
+
* requires a profile reference. When absent, the validator checks the scheme
|
|
168
|
+
* reference only and emits a `conformity-profile.not-specified` advisory,
|
|
169
|
+
* since criteria are published per versioned profile.
|
|
170
|
+
*/
|
|
171
|
+
profile?: string;
|
|
172
|
+
/** Criteria the claim addresses. */
|
|
173
|
+
criteria: ConformityClaimCriterion[];
|
|
174
|
+
/**
|
|
175
|
+
* Assessment-level topic declarations. Optional and version-specific: an
|
|
176
|
+
* extractor populates it only when its data model classifies assessments by
|
|
177
|
+
* topic.
|
|
178
|
+
*/
|
|
179
|
+
assessments?: ConformityClaimAssessment[];
|
|
180
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/conformity-vocabulary/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ConformityClaim, ConformityScheme, ConformityWarning } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates a credential's conformity claim against a parsed scheme.
|
|
4
|
+
*
|
|
5
|
+
* Short-circuits at the first miss:
|
|
6
|
+
* - scheme null or `canonicalId` mismatch → only `conformity-scheme.not-found`.
|
|
7
|
+
* - profile absent on the claim → scheme check plus a
|
|
8
|
+
* `conformity-profile.not-specified` advisory; criteria are published per
|
|
9
|
+
* versioned profile, so without one the criterion and topic checks cannot
|
|
10
|
+
* run, and silence would be indistinguishable from a clean pass.
|
|
11
|
+
* - profile not in scheme → only `conformity-profile.not-found`.
|
|
12
|
+
* - otherwise → criteria-level, criterion-topic, and assessment-topic warnings
|
|
13
|
+
* accumulate.
|
|
14
|
+
*
|
|
15
|
+
* Pointers are relative to `claim`. A consumer that holds the document the
|
|
16
|
+
* claim was extracted from re-maps them onto it, and prepending a wrapper path
|
|
17
|
+
* is only sound where the claim is a sub-document of that source. Where an
|
|
18
|
+
* extractor synthesises the claim, a prefix is not enough and the consumer
|
|
19
|
+
* needs the exact source path of each projected value: `criteria` may be
|
|
20
|
+
* flattened from several places, field names need not match, and an extractor
|
|
21
|
+
* that filters empty or malformed entries shifts both `/assessments/{i}` and
|
|
22
|
+
* topic indices away from their source positions (#753).
|
|
23
|
+
*
|
|
24
|
+
* @see ADR-033 §3 for warning code definitions.
|
|
25
|
+
*/
|
|
26
|
+
export declare function validateConformityClaim(claim: ConformityClaim, scheme: ConformityScheme | null): readonly ConformityWarning[];
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { ConformityWarningCode } from './codes.js';
|
|
2
|
+
/**
|
|
3
|
+
* Validates a credential's conformity claim against a parsed scheme.
|
|
4
|
+
*
|
|
5
|
+
* Short-circuits at the first miss:
|
|
6
|
+
* - scheme null or `canonicalId` mismatch → only `conformity-scheme.not-found`.
|
|
7
|
+
* - profile absent on the claim → scheme check plus a
|
|
8
|
+
* `conformity-profile.not-specified` advisory; criteria are published per
|
|
9
|
+
* versioned profile, so without one the criterion and topic checks cannot
|
|
10
|
+
* run, and silence would be indistinguishable from a clean pass.
|
|
11
|
+
* - profile not in scheme → only `conformity-profile.not-found`.
|
|
12
|
+
* - otherwise → criteria-level, criterion-topic, and assessment-topic warnings
|
|
13
|
+
* accumulate.
|
|
14
|
+
*
|
|
15
|
+
* Pointers are relative to `claim`. A consumer that holds the document the
|
|
16
|
+
* claim was extracted from re-maps them onto it, and prepending a wrapper path
|
|
17
|
+
* is only sound where the claim is a sub-document of that source. Where an
|
|
18
|
+
* extractor synthesises the claim, a prefix is not enough and the consumer
|
|
19
|
+
* needs the exact source path of each projected value: `criteria` may be
|
|
20
|
+
* flattened from several places, field names need not match, and an extractor
|
|
21
|
+
* that filters empty or malformed entries shifts both `/assessments/{i}` and
|
|
22
|
+
* topic indices away from their source positions (#753).
|
|
23
|
+
*
|
|
24
|
+
* @see ADR-033 §3 for warning code definitions.
|
|
25
|
+
*/
|
|
26
|
+
export function validateConformityClaim(claim, scheme) {
|
|
27
|
+
const warnings = [];
|
|
28
|
+
if (!scheme || scheme.canonicalId !== claim.scheme) {
|
|
29
|
+
warnings.push({
|
|
30
|
+
code: ConformityWarningCode.SchemeNotFound,
|
|
31
|
+
message: 'Scheme URI is not in the known set.',
|
|
32
|
+
received: claim.scheme,
|
|
33
|
+
pointer: '/scheme',
|
|
34
|
+
});
|
|
35
|
+
return warnings;
|
|
36
|
+
}
|
|
37
|
+
// `== null` covers undefined and a runtime null from JSON or database rows.
|
|
38
|
+
if (claim.profile == null) {
|
|
39
|
+
warnings.push({
|
|
40
|
+
code: ConformityWarningCode.ProfileNotSpecified,
|
|
41
|
+
message: 'The claim references no profile; criterion and topic checks were not performed because criteria are published per profile.',
|
|
42
|
+
pointer: '/profile',
|
|
43
|
+
});
|
|
44
|
+
return warnings;
|
|
45
|
+
}
|
|
46
|
+
const profile = scheme.profiles.find((p) => p.canonicalId === claim.profile);
|
|
47
|
+
if (!profile) {
|
|
48
|
+
warnings.push({
|
|
49
|
+
code: ConformityWarningCode.ProfileNotFound,
|
|
50
|
+
message: "Profile URI is not among the scheme's published profiles.",
|
|
51
|
+
received: claim.profile,
|
|
52
|
+
expected: scheme.profiles.map((p) => p.canonicalId),
|
|
53
|
+
pointer: '/profile',
|
|
54
|
+
});
|
|
55
|
+
return warnings;
|
|
56
|
+
}
|
|
57
|
+
const profileCriteriaById = new Map(profile.criteria.map((c) => [c.canonicalId, c]));
|
|
58
|
+
const claimCriteriaIds = new Set(claim.criteria.map((c) => c.criterion));
|
|
59
|
+
const publishedCriterionIds = profile.criteria.map((c) => c.canonicalId);
|
|
60
|
+
// criterion-not-in-profile
|
|
61
|
+
claim.criteria.forEach((claimCriterion, i) => {
|
|
62
|
+
if (!profileCriteriaById.has(claimCriterion.criterion)) {
|
|
63
|
+
warnings.push({
|
|
64
|
+
code: ConformityWarningCode.CriterionNotInProfile,
|
|
65
|
+
message: `Criterion URI is not in the criterion list published by profile ${profile.canonicalId}.`,
|
|
66
|
+
received: claimCriterion.criterion,
|
|
67
|
+
expected: publishedCriterionIds,
|
|
68
|
+
pointer: `/criteria/${i}/criterion`,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
// criterion-missing
|
|
73
|
+
for (const profileCriterion of profile.criteria) {
|
|
74
|
+
if (!claimCriteriaIds.has(profileCriterion.canonicalId)) {
|
|
75
|
+
warnings.push({
|
|
76
|
+
code: ConformityWarningCode.CriterionMissing,
|
|
77
|
+
message: `Profile ${profile.canonicalId} publishes a criterion that the claim does not address.`,
|
|
78
|
+
expected: profileCriterion.canonicalId,
|
|
79
|
+
pointer: '/criteria',
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// criterion-topic-mismatch: each criterion defines its own conformity topics,
|
|
84
|
+
// and a profile references a collection of independently-versioned criteria.
|
|
85
|
+
// For each criterion the claim addresses, the topics it declares should match
|
|
86
|
+
// the topics that criterion defines. The check runs whenever the claim carries
|
|
87
|
+
// a topic list, including an empty one, so a criterion that omits a topic it
|
|
88
|
+
// defines is flagged. An absent list marks a data model that classifies
|
|
89
|
+
// criteria without conformity topics, and the check passes over it.
|
|
90
|
+
claim.criteria.forEach((claimCriterion, i) => {
|
|
91
|
+
// `== null` covers both undefined and a runtime null (for example a claim
|
|
92
|
+
// parsed from JSON or a database row where the optional field serialised
|
|
93
|
+
// as null); an empty array still runs the check.
|
|
94
|
+
if (claimCriterion.conformityTopics == null) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const profileCriterion = profileCriteriaById.get(claimCriterion.criterion);
|
|
98
|
+
if (!profileCriterion) {
|
|
99
|
+
// already surfaced by criterion-not-in-profile
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const criterionTopicIds = profileCriterion.topics.map((t) => t.canonicalId);
|
|
103
|
+
const declaredTopics = claimCriterion.conformityTopics;
|
|
104
|
+
// A topic the criterion defines that the claim leaves out.
|
|
105
|
+
criterionTopicIds.forEach((expected) => {
|
|
106
|
+
if (!declaredTopics.includes(expected)) {
|
|
107
|
+
warnings.push({
|
|
108
|
+
code: ConformityWarningCode.CriterionTopicMismatch,
|
|
109
|
+
message: `The criterion, as published in profile ${profile.canonicalId}, defines a topic the claim does not declare.`,
|
|
110
|
+
expected,
|
|
111
|
+
pointer: `/criteria/${i}/conformityTopics`,
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
// A topic the claim declares that the criterion does not define.
|
|
116
|
+
declaredTopics.forEach((declared, t) => {
|
|
117
|
+
if (!criterionTopicIds.includes(declared)) {
|
|
118
|
+
warnings.push({
|
|
119
|
+
code: ConformityWarningCode.CriterionTopicMismatch,
|
|
120
|
+
message: `The claim declares a topic the criterion, as published in profile ${profile.canonicalId}, does not define.`,
|
|
121
|
+
received: declared,
|
|
122
|
+
expected: criterionTopicIds,
|
|
123
|
+
pointer: `/criteria/${i}/conformityTopics/${t}`,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
// assessment-topic-mismatch: an assessment's declared topics must sit within
|
|
129
|
+
// the deduplicated union of the published topics of the criteria it
|
|
130
|
+
// references. One direction only: an assessment may declare a subset of the
|
|
131
|
+
// union (its topics categorise the assessment, they do not enumerate it), but
|
|
132
|
+
// a declared topic outside the union references taxonomy none of its criteria
|
|
133
|
+
// carry. The check runs only when the assessment references at least one
|
|
134
|
+
// criterion and every referenced criterion resolves in the profile. With no
|
|
135
|
+
// referenced criteria the parent-level topic is the only classification the
|
|
136
|
+
// claim carries, so there is no criteria union to check it against. An
|
|
137
|
+
// unresolved criterion could itself carry the declared topic, so warning
|
|
138
|
+
// against a partial union would be unfounded, and unresolved criteria are
|
|
139
|
+
// already surfaced by criterion-not-in-profile.
|
|
140
|
+
claim.assessments?.forEach((assessment, i) => {
|
|
141
|
+
if (assessment.criteria.length === 0) {
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const resolvedCriteria = assessment.criteria
|
|
145
|
+
.map((criterionId) => profileCriteriaById.get(criterionId))
|
|
146
|
+
.filter((criterion) => criterion !== undefined);
|
|
147
|
+
if (resolvedCriteria.length !== assessment.criteria.length) {
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
const unionTopicIds = new Set(resolvedCriteria.flatMap((criterion) => criterion.topics.map((t) => t.canonicalId)));
|
|
151
|
+
assessment.conformityTopics.forEach((declared, t) => {
|
|
152
|
+
if (!unionTopicIds.has(declared)) {
|
|
153
|
+
warnings.push({
|
|
154
|
+
code: ConformityWarningCode.AssessmentTopicMismatch,
|
|
155
|
+
message: `The assessment declares a topic that none of its assessed criteria, as published in profile ${profile.canonicalId}, define.`,
|
|
156
|
+
received: declared,
|
|
157
|
+
expected: [...unionTopicIds],
|
|
158
|
+
pointer: `/assessments/${i}/conformityTopics/${t}`,
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
return warnings;
|
|
164
|
+
}
|
|
165
|
+
//# sourceMappingURL=validate-conformity-claim.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validate-conformity-claim.js","sourceRoot":"","sources":["../../src/conformity-vocabulary/validate-conformity-claim.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|