@tracepass/dpp-validate 0.4.0 → 0.5.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/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/vendor/battery-scope.d.ts +31 -0
- package/dist/vendor/battery-scope.d.ts.map +1 -0
- package/dist/vendor/battery-scope.js +37 -0
- package/dist/vendor/battery-scope.js.map +1 -0
- package/dist/vendor/field-emptiness.d.ts +48 -0
- package/dist/vendor/field-emptiness.d.ts.map +1 -0
- package/dist/vendor/field-emptiness.js +54 -0
- package/dist/vendor/field-emptiness.js.map +1 -0
- package/dist/vendor/publish-gate.d.ts +71 -3
- package/dist/vendor/publish-gate.d.ts.map +1 -1
- package/dist/vendor/publish-gate.js +108 -7
- package/dist/vendor/publish-gate.js.map +1 -1
- package/package.json +2 -2
package/dist/index.d.ts
CHANGED
|
@@ -13,6 +13,9 @@ export type { ConditionalRule } from "./rules.js";
|
|
|
13
13
|
export { IN_SCOPE_BATTERY_CATEGORIES, BATTERY_FIELD_GATES, GATED_FIELD_KEYS, batteryFieldApplicability, gateForKey, } from "./battery-applicability.js";
|
|
14
14
|
export type { Applicability, FieldGate } from "./battery-applicability.js";
|
|
15
15
|
export { checkPublishReady } from "./vendor/publish-gate.js";
|
|
16
|
+
export { effectiveRequired, effectiveRequiredForBattery } from "./vendor/publish-gate.js";
|
|
17
|
+
export { isInScopeBatteryCategory } from "./vendor/battery-scope.js";
|
|
18
|
+
export { isFieldAbsent, isFieldValueAbsent } from "./vendor/field-emptiness.js";
|
|
16
19
|
export { getPartyRoles, isRequiredRole, allRolesForCategory, CATEGORY_PARTY_ROLES } from "./vendor/required-roles.js";
|
|
17
20
|
export type { CategoryKey } from "./vendor/required-roles.js";
|
|
18
21
|
export { derivePassportCounts } from "./vendor/counts.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,UAAU,GACX,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAI3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAElD,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,mBAAmB,EACnB,eAAe,EACf,WAAW,GACZ,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,UAAU,GACX,MAAM,4BAA4B,CAAC;AACpC,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAI3E,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAG7D,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AACtH,YAAY,EAAE,WAAW,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,11 @@ export { IN_SCOPE_BATTERY_CATEGORIES, BATTERY_FIELD_GATES, GATED_FIELD_KEYS, bat
|
|
|
12
12
|
// Re-exported because a passport's publish-readiness and required economic
|
|
13
13
|
// operators are part of judging whether it is compliant, not separate concerns.
|
|
14
14
|
export { checkPublishReady } from "./vendor/publish-gate.js";
|
|
15
|
+
// Exported alongside the gate: a caller rendering a form needs the same
|
|
16
|
+
// per-category answer the gate uses, or its asterisks disagree with its verdict.
|
|
17
|
+
export { effectiveRequired, effectiveRequiredForBattery } from "./vendor/publish-gate.js";
|
|
18
|
+
export { isInScopeBatteryCategory } from "./vendor/battery-scope.js";
|
|
19
|
+
export { isFieldAbsent, isFieldValueAbsent } from "./vendor/field-emptiness.js";
|
|
15
20
|
export { getPartyRoles, isRequiredRole, allRolesForCategory, CATEGORY_PARTY_ROLES } from "./vendor/required-roles.js";
|
|
16
21
|
export { derivePassportCounts } from "./vendor/counts.js";
|
|
17
22
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAWlD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,UAAU,GACX,MAAM,4BAA4B,CAAC;AAGpC,2EAA2E;AAC3E,gFAAgF;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEtH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAWlD,OAAO,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAEnD,OAAO,EACL,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AAGpB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,gBAAgB,EAChB,yBAAyB,EACzB,UAAU,GACX,MAAM,4BAA4B,CAAC;AAGpC,2EAA2E;AAC3E,gFAAgF;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,wEAAwE;AACxE,iFAAiF;AACjF,OAAO,EAAE,iBAAiB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAC1F,OAAO,EAAE,wBAAwB,EAAE,MAAM,2BAA2B,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,kBAAkB,EAAE,MAAM,6BAA6B,CAAC;AAChF,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAEtH,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which battery categories are in scope for the EU battery passport at all.
|
|
3
|
+
*
|
|
4
|
+
* Art. 77 of Reg (EU) 2023/1542 hangs the passport on LMT, EV and industrial
|
|
5
|
+
* batteries only. Portable and SLI batteries are covered by the Regulation for
|
|
6
|
+
* other duties (labelling, collection, removability) but carry NO passport
|
|
7
|
+
* obligation, and neither does industrial ≤ 2 kWh. The Commission's own data-point
|
|
8
|
+
* guidance is scoped the same way — it enumerates applicability for "EV, LMT and
|
|
9
|
+
* industrial batteries" and never addresses the other three categories.
|
|
10
|
+
*
|
|
11
|
+
* The template's `batteryCategory` enum offers all six values because it also
|
|
12
|
+
* describes batteries we hold data about; the enum is NOT the scope list. Read
|
|
13
|
+
* this module to answer "is a passport due", never the enum.
|
|
14
|
+
*
|
|
15
|
+
* Lives on its own so the compliance engine and the publish gate can share one
|
|
16
|
+
* definition without importing each other. Both did carry their own copy, kept
|
|
17
|
+
* in agreement by hand.
|
|
18
|
+
*/
|
|
19
|
+
/** Categories that owe a battery passport (BAT-1 / Art. 77(1)). */
|
|
20
|
+
export declare const IN_SCOPE_BATTERY_CATEGORIES: readonly ["LMT", "EV", "industrial_gt_2kwh"];
|
|
21
|
+
export type InScopeBatteryCategory = (typeof IN_SCOPE_BATTERY_CATEGORIES)[number];
|
|
22
|
+
/**
|
|
23
|
+
* True when `category` owes a battery passport.
|
|
24
|
+
*
|
|
25
|
+
* An unset category returns `false` — absence of a category is not evidence of
|
|
26
|
+
* an obligation. Callers that need to distinguish "out of scope" from "we don't
|
|
27
|
+
* know yet" must check for `undefined` themselves; BAT-1 does exactly that so it
|
|
28
|
+
* can raise `unverifiable_conditional` rather than silently passing.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isInScopeBatteryCategory(category: string | undefined | null): boolean;
|
|
31
|
+
//# sourceMappingURL=battery-scope.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"battery-scope.d.ts","sourceRoot":"","sources":["../../src/vendor/battery-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,mEAAmE;AACnE,eAAO,MAAM,2BAA2B,8CAI9B,CAAC;AAEX,MAAM,MAAM,sBAAsB,GAChC,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAI/C;;;;;;;GAOG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,GAClC,OAAO,CAET"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Which battery categories are in scope for the EU battery passport at all.
|
|
3
|
+
*
|
|
4
|
+
* Art. 77 of Reg (EU) 2023/1542 hangs the passport on LMT, EV and industrial
|
|
5
|
+
* batteries only. Portable and SLI batteries are covered by the Regulation for
|
|
6
|
+
* other duties (labelling, collection, removability) but carry NO passport
|
|
7
|
+
* obligation, and neither does industrial ≤ 2 kWh. The Commission's own data-point
|
|
8
|
+
* guidance is scoped the same way — it enumerates applicability for "EV, LMT and
|
|
9
|
+
* industrial batteries" and never addresses the other three categories.
|
|
10
|
+
*
|
|
11
|
+
* The template's `batteryCategory` enum offers all six values because it also
|
|
12
|
+
* describes batteries we hold data about; the enum is NOT the scope list. Read
|
|
13
|
+
* this module to answer "is a passport due", never the enum.
|
|
14
|
+
*
|
|
15
|
+
* Lives on its own so the compliance engine and the publish gate can share one
|
|
16
|
+
* definition without importing each other. Both did carry their own copy, kept
|
|
17
|
+
* in agreement by hand.
|
|
18
|
+
*/
|
|
19
|
+
/** Categories that owe a battery passport (BAT-1 / Art. 77(1)). */
|
|
20
|
+
export const IN_SCOPE_BATTERY_CATEGORIES = [
|
|
21
|
+
"LMT",
|
|
22
|
+
"EV",
|
|
23
|
+
"industrial_gt_2kwh",
|
|
24
|
+
];
|
|
25
|
+
const IN_SCOPE = new Set(IN_SCOPE_BATTERY_CATEGORIES);
|
|
26
|
+
/**
|
|
27
|
+
* True when `category` owes a battery passport.
|
|
28
|
+
*
|
|
29
|
+
* An unset category returns `false` — absence of a category is not evidence of
|
|
30
|
+
* an obligation. Callers that need to distinguish "out of scope" from "we don't
|
|
31
|
+
* know yet" must check for `undefined` themselves; BAT-1 does exactly that so it
|
|
32
|
+
* can raise `unverifiable_conditional` rather than silently passing.
|
|
33
|
+
*/
|
|
34
|
+
export function isInScopeBatteryCategory(category) {
|
|
35
|
+
return category != null && IN_SCOPE.has(category);
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=battery-scope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"battery-scope.js","sourceRoot":"","sources":["../../src/vendor/battery-scope.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,mEAAmE;AACnE,MAAM,CAAC,MAAM,2BAA2B,GAAG;IACzC,KAAK;IACL,IAAI;IACJ,oBAAoB;CACZ,CAAC;AAKX,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAS,2BAA2B,CAAC,CAAC;AAE9D;;;;;;;GAOG;AACH,MAAM,UAAU,wBAAwB,CACtC,QAAmC;IAEnC,OAAO,QAAQ,IAAI,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;AACpD,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is a passport field's value absent?
|
|
3
|
+
*
|
|
4
|
+
* This looks trivial and is not — the same question is asked in a dozen places
|
|
5
|
+
* (publish gate, compliance verdict, bulk approve, gap reports, the extraction
|
|
6
|
+
* pipeline, the review UI) and getting it subtly wrong has already cost real
|
|
7
|
+
* data twice.
|
|
8
|
+
*
|
|
9
|
+
* ── An empty ARRAY is an answer, not a gap ──
|
|
10
|
+
*
|
|
11
|
+
* `hazardousSubstances: []` asserts "we checked, there are none" — a positive
|
|
12
|
+
* compliance claim, the same kind as `svhcPresent: false`. Treating it as
|
|
13
|
+
* absent discards a declared finding and re-queues settled work.
|
|
14
|
+
*
|
|
15
|
+
* The trap is that **`String([]) === ""`**. Any check written as
|
|
16
|
+
* `String(v).trim() === ""` therefore swallows every empty array silently. A
|
|
17
|
+
* repair pass built that way flagged 60 of them, two on PUBLISHED passports,
|
|
18
|
+
* and would have wiped genuine "none apply" declarations.
|
|
19
|
+
*
|
|
20
|
+
* ── `false` and `0` are values ──
|
|
21
|
+
*
|
|
22
|
+
* `svhcPresent: false` is the ECHA register's actual answer.
|
|
23
|
+
* `recycledContentPercent: 0` is a measurement. `if (!value)` discards both,
|
|
24
|
+
* which is why that shortcut is never correct here.
|
|
25
|
+
*
|
|
26
|
+
* ── Whitespace is absent ──
|
|
27
|
+
*
|
|
28
|
+
* `" "` is what an empty form field or a trimmed-to-nothing extraction
|
|
29
|
+
* leaves behind. The long-standing inline checks used `value === ""` and so
|
|
30
|
+
* counted a whitespace string as filled — enough to satisfy a required field
|
|
31
|
+
* in the publish gate.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* True when the field holds no value.
|
|
35
|
+
*
|
|
36
|
+
* Absent: `null`, `undefined`, `""`, whitespace-only strings.
|
|
37
|
+
* Present: `false`, `0`, `[]`, `{}`, and every non-blank scalar.
|
|
38
|
+
*
|
|
39
|
+
* Note `[]` and `{}` count as PRESENT. An empty collection is a declaration
|
|
40
|
+
* that the collection is empty; callers that need "no entries" should test
|
|
41
|
+
* `.length` themselves, which reads as the different question it is.
|
|
42
|
+
*/
|
|
43
|
+
export declare function isFieldValueAbsent(value: unknown): boolean;
|
|
44
|
+
/** Convenience for the common `!field || absent(field.value)` shape. */
|
|
45
|
+
export declare function isFieldAbsent(field: {
|
|
46
|
+
value?: unknown;
|
|
47
|
+
} | undefined | null): boolean;
|
|
48
|
+
//# sourceMappingURL=field-emptiness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-emptiness.d.ts","sourceRoot":"","sources":["../../src/vendor/field-emptiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAI1D;AAED,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,KAAK,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GAAG,SAAS,GAAG,IAAI,GAAG,OAAO,CAEpF"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Is a passport field's value absent?
|
|
3
|
+
*
|
|
4
|
+
* This looks trivial and is not — the same question is asked in a dozen places
|
|
5
|
+
* (publish gate, compliance verdict, bulk approve, gap reports, the extraction
|
|
6
|
+
* pipeline, the review UI) and getting it subtly wrong has already cost real
|
|
7
|
+
* data twice.
|
|
8
|
+
*
|
|
9
|
+
* ── An empty ARRAY is an answer, not a gap ──
|
|
10
|
+
*
|
|
11
|
+
* `hazardousSubstances: []` asserts "we checked, there are none" — a positive
|
|
12
|
+
* compliance claim, the same kind as `svhcPresent: false`. Treating it as
|
|
13
|
+
* absent discards a declared finding and re-queues settled work.
|
|
14
|
+
*
|
|
15
|
+
* The trap is that **`String([]) === ""`**. Any check written as
|
|
16
|
+
* `String(v).trim() === ""` therefore swallows every empty array silently. A
|
|
17
|
+
* repair pass built that way flagged 60 of them, two on PUBLISHED passports,
|
|
18
|
+
* and would have wiped genuine "none apply" declarations.
|
|
19
|
+
*
|
|
20
|
+
* ── `false` and `0` are values ──
|
|
21
|
+
*
|
|
22
|
+
* `svhcPresent: false` is the ECHA register's actual answer.
|
|
23
|
+
* `recycledContentPercent: 0` is a measurement. `if (!value)` discards both,
|
|
24
|
+
* which is why that shortcut is never correct here.
|
|
25
|
+
*
|
|
26
|
+
* ── Whitespace is absent ──
|
|
27
|
+
*
|
|
28
|
+
* `" "` is what an empty form field or a trimmed-to-nothing extraction
|
|
29
|
+
* leaves behind. The long-standing inline checks used `value === ""` and so
|
|
30
|
+
* counted a whitespace string as filled — enough to satisfy a required field
|
|
31
|
+
* in the publish gate.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* True when the field holds no value.
|
|
35
|
+
*
|
|
36
|
+
* Absent: `null`, `undefined`, `""`, whitespace-only strings.
|
|
37
|
+
* Present: `false`, `0`, `[]`, `{}`, and every non-blank scalar.
|
|
38
|
+
*
|
|
39
|
+
* Note `[]` and `{}` count as PRESENT. An empty collection is a declaration
|
|
40
|
+
* that the collection is empty; callers that need "no entries" should test
|
|
41
|
+
* `.length` themselves, which reads as the different question it is.
|
|
42
|
+
*/
|
|
43
|
+
export function isFieldValueAbsent(value) {
|
|
44
|
+
if (value === null || value === undefined)
|
|
45
|
+
return true;
|
|
46
|
+
if (typeof value === "string")
|
|
47
|
+
return value.trim() === "";
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
/** Convenience for the common `!field || absent(field.value)` shape. */
|
|
51
|
+
export function isFieldAbsent(field) {
|
|
52
|
+
return !field || isFieldValueAbsent(field.value);
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=field-emptiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"field-emptiness.js","sourceRoot":"","sources":["../../src/vendor/field-emptiness.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAc;IAC/C,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC;IAC1D,OAAO,KAAK,CAAC;AACf,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,aAAa,CAAC,KAA6C;IACzE,OAAO,CAAC,KAAK,IAAI,kBAAkB,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;AACnD,CAAC"}
|
|
@@ -6,8 +6,19 @@
|
|
|
6
6
|
*
|
|
7
7
|
* One rule, one implementation. If the product policy for publishing
|
|
8
8
|
* changes (e.g. "warnings block", "min coverage %"), change it here.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ MIRRORED INTO THE PUBLIC npm PACKAGE @tracepass/dpp-validate.
|
|
11
|
+
* `tracepass-open/packages/dpp-validate/src/vendor/publish-gate.ts` is a hand-copy of this
|
|
12
|
+
* file — nothing generates one from the other, and a stale copy fails silently
|
|
13
|
+
* (it still compiles and still returns a plausible answer). tracepass-open
|
|
14
|
+
* gates on a hash of this file in CI, so after changing it:
|
|
15
|
+
*
|
|
16
|
+
* cd ../tracepass-open && node scripts/build-mirror-manifest.mjs \
|
|
17
|
+
* && npm run check:mirrors
|
|
18
|
+
*
|
|
19
|
+
* and commit `mirror-manifest.json` with the code.
|
|
9
20
|
*/
|
|
10
|
-
import type { Passport, Template } from "@tracepass/dpp-types";
|
|
21
|
+
import type { Passport, Template, TemplateField } from "@tracepass/dpp-types";
|
|
11
22
|
export interface PublishCheck {
|
|
12
23
|
ready: boolean;
|
|
13
24
|
/** Field keys that have no value set. */
|
|
@@ -27,13 +38,70 @@ export interface PublishCheck {
|
|
|
27
38
|
*/
|
|
28
39
|
blockerType?: "hard" | "gap";
|
|
29
40
|
}
|
|
41
|
+
/**
|
|
42
|
+
* Resolves whether a template field is effectively required for a specific
|
|
43
|
+
* battery category:
|
|
44
|
+
*
|
|
45
|
+
* 1. No `requiredBy` map → fall back to `validation.required`.
|
|
46
|
+
* This is the backward-compat path: ALL 11 non-battery templates and
|
|
47
|
+
* any battery field without a `requiredBy` entry behave exactly as before.
|
|
48
|
+
* 2. Category present in the map → "required" is true; "conditional" and
|
|
49
|
+
* "notApplicable" are false.
|
|
50
|
+
* 3. Category absent from the map, or unset on the passport → base required.
|
|
51
|
+
*
|
|
52
|
+
* `requiredBy` maps are keyed ONLY by the three in-scope categories, so step 3
|
|
53
|
+
* is what a portable or SLI battery would otherwise land on — see
|
|
54
|
+
* `effectiveRequiredForBattery`, which callers holding a battery passport should
|
|
55
|
+
* use instead.
|
|
56
|
+
*
|
|
57
|
+
* @param tf A template field (from the template's `fields` array).
|
|
58
|
+
* @param category The resolved `batteryCategory` value from the passport, or
|
|
59
|
+
* `undefined` when the field is unset.
|
|
60
|
+
*/
|
|
61
|
+
export declare function effectiveRequired(tf: Pick<TemplateField, "validation">, category: string | undefined): boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Battery-aware wrapper around `effectiveRequired`.
|
|
64
|
+
*
|
|
65
|
+
* A portable, SLI or industrial-≤2 kWh battery owes NO battery passport at all
|
|
66
|
+
* (Art. 77(1) — see `isInScopeBatteryCategory`), so no Annex XIII field is
|
|
67
|
+
* mandatory for it. Resolving those categories through `effectiveRequired`
|
|
68
|
+
* alone lands on the base `required` flag, which would demand the full
|
|
69
|
+
* category-agnostic field set from a battery that has no passport obligation —
|
|
70
|
+
* an obligation we would be inventing.
|
|
71
|
+
*
|
|
72
|
+
* An UNSET category still falls through to the base flag. That is deliberate:
|
|
73
|
+
* absence of a category is not evidence of exemption, and treating "not yet
|
|
74
|
+
* filled in" as "nothing required" would let a genuine EV battery publish empty.
|
|
75
|
+
* BAT-1 raises a warning for the unset case instead.
|
|
76
|
+
*
|
|
77
|
+
* Non-battery templates never reach the scope branch — they carry no
|
|
78
|
+
* `batteryCategory`, so `category` is `undefined` and behaviour is unchanged.
|
|
79
|
+
*/
|
|
80
|
+
export declare function effectiveRequiredForBattery(tf: Pick<TemplateField, "validation">, category: string | undefined): boolean;
|
|
81
|
+
/**
|
|
82
|
+
* True when the template EXPLICITLY marks this field `notApplicable` for the
|
|
83
|
+
* given category — i.e. the Regulation says it must not be filled or displayed.
|
|
84
|
+
*
|
|
85
|
+
* Distinct from "not required" in the way that matters for a compliance
|
|
86
|
+
* surface: a `conditional` field may legitimately be filled and simply isn't
|
|
87
|
+
* mandatory, whereas a `notApplicable` one carries an instruction NOT to report
|
|
88
|
+
* it (the Annex XIII 4(b) state-of-health exclusions are the live example — an
|
|
89
|
+
* EV battery must leave the granular metrics blank and an LMT battery must
|
|
90
|
+
* leave SOCE blank). Rendering those as "not provided" reads as missing data
|
|
91
|
+
* when the truth is that there is nothing to provide.
|
|
92
|
+
*
|
|
93
|
+
* Returns false when the category is unset or the field carries no map —
|
|
94
|
+
* absence of information is never grounds for asserting non-applicability.
|
|
95
|
+
*/
|
|
96
|
+
export declare function notApplicableForCategory(tf: Pick<TemplateField, "validation">, category: string | undefined): boolean;
|
|
30
97
|
/**
|
|
31
98
|
* Returns whether `passport` satisfies every publish precondition given
|
|
32
99
|
* its `template`. A passport is publish-ready iff:
|
|
33
100
|
* - status is in PUBLISHABLE_STATUSES (already-published + terminal
|
|
34
101
|
* states return ready:false with a specific reason),
|
|
35
|
-
* - every template field
|
|
36
|
-
*
|
|
102
|
+
* - every template field whose effective required flag (resolved via
|
|
103
|
+
* `effectiveRequired` — which consults `requiredBy` when present) is
|
|
104
|
+
* true has a non-empty value AND status === "approved".
|
|
37
105
|
*
|
|
38
106
|
* `undefined` template means we can't evaluate — treat as not-ready.
|
|
39
107
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-gate.d.ts","sourceRoot":"","sources":["../../src/vendor/publish-gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"publish-gate.d.ts","sourceRoot":"","sources":["../../src/vendor/publish-gate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAI9E,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,yCAAyC;IACzC,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,sDAAsD;IACtD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;;;OAQG;IACH,WAAW,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;CAC9B;AAQD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,EACrC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAUT;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,2BAA2B,CACzC,EAAE,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,EACrC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAKT;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,wBAAwB,CACtC,EAAE,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,EACrC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAC3B,OAAO,CAIT;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,QAAQ,EAClB,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAC7B,YAAY,CA6Ed"}
|
|
@@ -6,19 +6,107 @@
|
|
|
6
6
|
*
|
|
7
7
|
* One rule, one implementation. If the product policy for publishing
|
|
8
8
|
* changes (e.g. "warnings block", "min coverage %"), change it here.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ MIRRORED INTO THE PUBLIC npm PACKAGE @tracepass/dpp-validate.
|
|
11
|
+
* `tracepass-open/packages/dpp-validate/src/vendor/publish-gate.ts` is a hand-copy of this
|
|
12
|
+
* file — nothing generates one from the other, and a stale copy fails silently
|
|
13
|
+
* (it still compiles and still returns a plausible answer). tracepass-open
|
|
14
|
+
* gates on a hash of this file in CI, so after changing it:
|
|
15
|
+
*
|
|
16
|
+
* cd ../tracepass-open && node scripts/build-mirror-manifest.mjs \
|
|
17
|
+
* && npm run check:mirrors
|
|
18
|
+
*
|
|
19
|
+
* and commit `mirror-manifest.json` with the code.
|
|
9
20
|
*/
|
|
21
|
+
import { isInScopeBatteryCategory } from "./battery-scope.js";
|
|
22
|
+
import { isFieldAbsent } from "./field-emptiness.js";
|
|
10
23
|
const PUBLISHABLE_STATUSES = new Set([
|
|
11
24
|
"draft",
|
|
12
25
|
"in_review",
|
|
13
26
|
"approved",
|
|
14
27
|
]);
|
|
28
|
+
/**
|
|
29
|
+
* Resolves whether a template field is effectively required for a specific
|
|
30
|
+
* battery category:
|
|
31
|
+
*
|
|
32
|
+
* 1. No `requiredBy` map → fall back to `validation.required`.
|
|
33
|
+
* This is the backward-compat path: ALL 11 non-battery templates and
|
|
34
|
+
* any battery field without a `requiredBy` entry behave exactly as before.
|
|
35
|
+
* 2. Category present in the map → "required" is true; "conditional" and
|
|
36
|
+
* "notApplicable" are false.
|
|
37
|
+
* 3. Category absent from the map, or unset on the passport → base required.
|
|
38
|
+
*
|
|
39
|
+
* `requiredBy` maps are keyed ONLY by the three in-scope categories, so step 3
|
|
40
|
+
* is what a portable or SLI battery would otherwise land on — see
|
|
41
|
+
* `effectiveRequiredForBattery`, which callers holding a battery passport should
|
|
42
|
+
* use instead.
|
|
43
|
+
*
|
|
44
|
+
* @param tf A template field (from the template's `fields` array).
|
|
45
|
+
* @param category The resolved `batteryCategory` value from the passport, or
|
|
46
|
+
* `undefined` when the field is unset.
|
|
47
|
+
*/
|
|
48
|
+
export function effectiveRequired(tf, category) {
|
|
49
|
+
const { requiredBy, required } = tf.validation;
|
|
50
|
+
// Path 1 & 3: no map, or category not a key in the map → base required.
|
|
51
|
+
if (!requiredBy || category === undefined || !(category in requiredBy)) {
|
|
52
|
+
return required;
|
|
53
|
+
}
|
|
54
|
+
// Path 2: explicit per-category applicability.
|
|
55
|
+
return requiredBy[category] === "required";
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Battery-aware wrapper around `effectiveRequired`.
|
|
59
|
+
*
|
|
60
|
+
* A portable, SLI or industrial-≤2 kWh battery owes NO battery passport at all
|
|
61
|
+
* (Art. 77(1) — see `isInScopeBatteryCategory`), so no Annex XIII field is
|
|
62
|
+
* mandatory for it. Resolving those categories through `effectiveRequired`
|
|
63
|
+
* alone lands on the base `required` flag, which would demand the full
|
|
64
|
+
* category-agnostic field set from a battery that has no passport obligation —
|
|
65
|
+
* an obligation we would be inventing.
|
|
66
|
+
*
|
|
67
|
+
* An UNSET category still falls through to the base flag. That is deliberate:
|
|
68
|
+
* absence of a category is not evidence of exemption, and treating "not yet
|
|
69
|
+
* filled in" as "nothing required" would let a genuine EV battery publish empty.
|
|
70
|
+
* BAT-1 raises a warning for the unset case instead.
|
|
71
|
+
*
|
|
72
|
+
* Non-battery templates never reach the scope branch — they carry no
|
|
73
|
+
* `batteryCategory`, so `category` is `undefined` and behaviour is unchanged.
|
|
74
|
+
*/
|
|
75
|
+
export function effectiveRequiredForBattery(tf, category) {
|
|
76
|
+
if (category !== undefined && !isInScopeBatteryCategory(category)) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
return effectiveRequired(tf, category);
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* True when the template EXPLICITLY marks this field `notApplicable` for the
|
|
83
|
+
* given category — i.e. the Regulation says it must not be filled or displayed.
|
|
84
|
+
*
|
|
85
|
+
* Distinct from "not required" in the way that matters for a compliance
|
|
86
|
+
* surface: a `conditional` field may legitimately be filled and simply isn't
|
|
87
|
+
* mandatory, whereas a `notApplicable` one carries an instruction NOT to report
|
|
88
|
+
* it (the Annex XIII 4(b) state-of-health exclusions are the live example — an
|
|
89
|
+
* EV battery must leave the granular metrics blank and an LMT battery must
|
|
90
|
+
* leave SOCE blank). Rendering those as "not provided" reads as missing data
|
|
91
|
+
* when the truth is that there is nothing to provide.
|
|
92
|
+
*
|
|
93
|
+
* Returns false when the category is unset or the field carries no map —
|
|
94
|
+
* absence of information is never grounds for asserting non-applicability.
|
|
95
|
+
*/
|
|
96
|
+
export function notApplicableForCategory(tf, category) {
|
|
97
|
+
const { requiredBy } = tf.validation;
|
|
98
|
+
if (!requiredBy || category === undefined)
|
|
99
|
+
return false;
|
|
100
|
+
return requiredBy[category] === "notApplicable";
|
|
101
|
+
}
|
|
15
102
|
/**
|
|
16
103
|
* Returns whether `passport` satisfies every publish precondition given
|
|
17
104
|
* its `template`. A passport is publish-ready iff:
|
|
18
105
|
* - status is in PUBLISHABLE_STATUSES (already-published + terminal
|
|
19
106
|
* states return ready:false with a specific reason),
|
|
20
|
-
* - every template field
|
|
21
|
-
*
|
|
107
|
+
* - every template field whose effective required flag (resolved via
|
|
108
|
+
* `effectiveRequired` — which consults `requiredBy` when present) is
|
|
109
|
+
* true has a non-empty value AND status === "approved".
|
|
22
110
|
*
|
|
23
111
|
* `undefined` template means we can't evaluate — treat as not-ready.
|
|
24
112
|
*/
|
|
@@ -50,16 +138,29 @@ export function checkPublishReady(passport, template) {
|
|
|
50
138
|
blockerType: "hard",
|
|
51
139
|
};
|
|
52
140
|
}
|
|
141
|
+
// Read the passport's battery category so effectiveRequired can resolve
|
|
142
|
+
// per-category applicability. For non-battery passports (no batteryCategory
|
|
143
|
+
// field) this is always undefined and effectiveRequired falls back to the
|
|
144
|
+
// plain `required` boolean — no behaviour change for other templates.
|
|
145
|
+
const categoryField = passport.fields["batteryCategory"];
|
|
146
|
+
const category = categoryField && categoryField.value != null && categoryField.value !== ""
|
|
147
|
+
? String(categoryField.value)
|
|
148
|
+
: undefined;
|
|
53
149
|
const missingFields = [];
|
|
54
150
|
const unapprovedFields = [];
|
|
55
151
|
for (const tf of template.fields) {
|
|
56
|
-
|
|
152
|
+
// `anticipated` fields rest on a delegated act that has not been adopted,
|
|
153
|
+
// so no instrument in force compels the data and their absence cannot block
|
|
154
|
+
// publication. Skip them before the required check.
|
|
155
|
+
if (tf.validation.anticipated)
|
|
156
|
+
continue;
|
|
157
|
+
if (!effectiveRequiredForBattery(tf, category))
|
|
57
158
|
continue;
|
|
58
159
|
const f = passport.fields[tf.key];
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
160
|
+
// Shared helper: `[]` stays a valid answer ("none apply"), while a
|
|
161
|
+
// whitespace-only string now counts as missing — the inline `=== ""` it
|
|
162
|
+
// replaces let " " satisfy a required field and publish a blank.
|
|
163
|
+
if (isFieldAbsent(f)) {
|
|
63
164
|
missingFields.push(tf.key);
|
|
64
165
|
}
|
|
65
166
|
else if (f.status !== "approved") {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"publish-gate.js","sourceRoot":"","sources":["../../src/vendor/publish-gate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"publish-gate.js","sourceRoot":"","sources":["../../src/vendor/publish-gate.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tracepass/dpp-validate",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Evaluate an EU Digital Product Passport against its category field-spec — a three-tier compliance verdict with regulation-cited findings. Pure functions, no third-party runtime dependencies.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"digital-product-passport",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"clean": "rm -rf dist"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@tracepass/dpp-types": "^0.
|
|
48
|
+
"@tracepass/dpp-types": "^0.5.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
51
|
"typescript": "^5.6.3"
|