@ifc-lite/ids 1.14.10 → 1.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +53 -44
  2. package/dist/audit/coherence/index.d.ts +12 -0
  3. package/dist/audit/coherence/index.d.ts.map +1 -0
  4. package/dist/audit/coherence/index.js +392 -0
  5. package/dist/audit/coherence/index.js.map +1 -0
  6. package/dist/audit/coherence/regex.d.ts +57 -0
  7. package/dist/audit/coherence/regex.d.ts.map +1 -0
  8. package/dist/audit/coherence/regex.js +111 -0
  9. package/dist/audit/coherence/regex.js.map +1 -0
  10. package/dist/audit/ifc-schema/index.d.ts +4 -0
  11. package/dist/audit/ifc-schema/index.d.ts.map +1 -0
  12. package/dist/audit/ifc-schema/index.js +637 -0
  13. package/dist/audit/ifc-schema/index.js.map +1 -0
  14. package/dist/audit/index.d.ts +37 -0
  15. package/dist/audit/index.d.ts.map +1 -0
  16. package/dist/audit/index.js +60 -0
  17. package/dist/audit/index.js.map +1 -0
  18. package/dist/audit/parser-shim.d.ts +13 -0
  19. package/dist/audit/parser-shim.d.ts.map +1 -0
  20. package/dist/audit/parser-shim.js +66 -0
  21. package/dist/audit/parser-shim.js.map +1 -0
  22. package/dist/audit/structural/index.d.ts +22 -0
  23. package/dist/audit/structural/index.d.ts.map +1 -0
  24. package/dist/audit/structural/index.js +441 -0
  25. package/dist/audit/structural/index.js.map +1 -0
  26. package/dist/audit/types.d.ts +91 -0
  27. package/dist/audit/types.d.ts.map +1 -0
  28. package/dist/audit/types.js +5 -0
  29. package/dist/audit/types.js.map +1 -0
  30. package/dist/audit/xsd/index.d.ts +13 -0
  31. package/dist/audit/xsd/index.d.ts.map +1 -0
  32. package/dist/audit/xsd/index.js +203 -0
  33. package/dist/audit/xsd/index.js.map +1 -0
  34. package/dist/bridge/classifications.d.ts +15 -0
  35. package/dist/bridge/classifications.d.ts.map +1 -0
  36. package/dist/bridge/classifications.js +114 -0
  37. package/dist/bridge/classifications.js.map +1 -0
  38. package/dist/bridge/data-accessor.d.ts +16 -0
  39. package/dist/bridge/data-accessor.d.ts.map +1 -0
  40. package/dist/bridge/data-accessor.js +205 -0
  41. package/dist/bridge/data-accessor.js.map +1 -0
  42. package/dist/bridge/data-types.d.ts +11 -0
  43. package/dist/bridge/data-types.d.ts.map +1 -0
  44. package/dist/bridge/data-types.js +47 -0
  45. package/dist/bridge/data-types.js.map +1 -0
  46. package/dist/bridge/index.d.ts +17 -0
  47. package/dist/bridge/index.d.ts.map +1 -0
  48. package/dist/bridge/index.js +20 -0
  49. package/dist/bridge/index.js.map +1 -0
  50. package/dist/bridge/materials.d.ts +11 -0
  51. package/dist/bridge/materials.d.ts.map +1 -0
  52. package/dist/bridge/materials.js +68 -0
  53. package/dist/bridge/materials.js.map +1 -0
  54. package/dist/bridge/predefined-types.d.ts +19 -0
  55. package/dist/bridge/predefined-types.d.ts.map +1 -0
  56. package/dist/bridge/predefined-types.js +84 -0
  57. package/dist/bridge/predefined-types.js.map +1 -0
  58. package/dist/bridge/properties.d.ts +20 -0
  59. package/dist/bridge/properties.d.ts.map +1 -0
  60. package/dist/bridge/properties.js +168 -0
  61. package/dist/bridge/properties.js.map +1 -0
  62. package/dist/bridge/schema-version.d.ts +10 -0
  63. package/dist/bridge/schema-version.d.ts.map +1 -0
  64. package/dist/bridge/schema-version.js +25 -0
  65. package/dist/bridge/schema-version.js.map +1 -0
  66. package/dist/bridge/units.d.ts +18 -0
  67. package/dist/bridge/units.d.ts.map +1 -0
  68. package/dist/bridge/units.js +55 -0
  69. package/dist/bridge/units.js.map +1 -0
  70. package/dist/constraints/comparators.d.ts +32 -0
  71. package/dist/constraints/comparators.d.ts.map +1 -0
  72. package/dist/constraints/comparators.js +94 -0
  73. package/dist/constraints/comparators.js.map +1 -0
  74. package/dist/constraints/index.d.ts +11 -1
  75. package/dist/constraints/index.d.ts.map +1 -1
  76. package/dist/constraints/index.js +74 -58
  77. package/dist/constraints/index.js.map +1 -1
  78. package/dist/constraints/xsd-cast.d.ts +20 -0
  79. package/dist/constraints/xsd-cast.d.ts.map +1 -0
  80. package/dist/constraints/xsd-cast.js +89 -0
  81. package/dist/constraints/xsd-cast.js.map +1 -0
  82. package/dist/facets/attribute-facet.d.ts.map +1 -1
  83. package/dist/facets/attribute-facet.js +80 -12
  84. package/dist/facets/attribute-facet.js.map +1 -1
  85. package/dist/facets/classification-facet.d.ts.map +1 -1
  86. package/dist/facets/classification-facet.js +21 -2
  87. package/dist/facets/classification-facet.js.map +1 -1
  88. package/dist/facets/entity-facet.d.ts.map +1 -1
  89. package/dist/facets/entity-facet.js +59 -7
  90. package/dist/facets/entity-facet.js.map +1 -1
  91. package/dist/facets/partof-facet.d.ts.map +1 -1
  92. package/dist/facets/partof-facet.js +40 -8
  93. package/dist/facets/partof-facet.js.map +1 -1
  94. package/dist/facets/property-facet.d.ts.map +1 -1
  95. package/dist/facets/property-facet.js +171 -55
  96. package/dist/facets/property-facet.js.map +1 -1
  97. package/dist/facets/test-helpers.d.ts +42 -0
  98. package/dist/facets/test-helpers.d.ts.map +1 -0
  99. package/dist/facets/test-helpers.js +106 -0
  100. package/dist/facets/test-helpers.js.map +1 -0
  101. package/dist/index.d.ts +2 -0
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +4 -0
  104. package/dist/index.js.map +1 -1
  105. package/dist/parser/xml-parser.d.ts.map +1 -1
  106. package/dist/parser/xml-parser.js +198 -68
  107. package/dist/parser/xml-parser.js.map +1 -1
  108. package/dist/translation/locales/de.d.ts +1 -0
  109. package/dist/translation/locales/de.d.ts.map +1 -1
  110. package/dist/translation/locales/de.js +1 -0
  111. package/dist/translation/locales/de.js.map +1 -1
  112. package/dist/translation/locales/en.d.ts +1 -0
  113. package/dist/translation/locales/en.d.ts.map +1 -1
  114. package/dist/translation/locales/en.js +1 -0
  115. package/dist/translation/locales/en.js.map +1 -1
  116. package/dist/translation/locales/fr.d.ts +1 -0
  117. package/dist/translation/locales/fr.d.ts.map +1 -1
  118. package/dist/translation/locales/fr.js +1 -0
  119. package/dist/translation/locales/fr.js.map +1 -1
  120. package/dist/types.d.ts +116 -7
  121. package/dist/types.d.ts.map +1 -1
  122. package/dist/validation/validator.js +49 -3
  123. package/dist/validation/validator.js.map +1 -1
  124. package/package.json +10 -3
package/README.md CHANGED
@@ -1,13 +1,6 @@
1
1
  # @ifc-lite/ids
2
2
 
3
- IDS (Information Delivery Specification) support for IFC-Lite.
4
-
5
- ## Features
6
-
7
- - **Full IDS 1.0 Support**: Parse and validate buildingSMART IDS XML files
8
- - **All Facet Types**: Entity, Attribute, Property, Classification, Material, PartOf
9
- - **Multi-Language Reports**: Human-readable translations in English, German, French
10
- - **Deep Viewer Integration**: Color-coded results, bidirectional selection, entity isolation
3
+ IDS (Information Delivery Specification) support for IFClite. Parses buildingSMART IDS XML files and validates an `IfcDataStore` against them — every facet type, every constraint type, with multi-language reports.
11
4
 
12
5
  ## Installation
13
6
 
@@ -15,62 +8,78 @@ IDS (Information Delivery Specification) support for IFC-Lite.
15
8
  npm install @ifc-lite/ids
16
9
  ```
17
10
 
18
- ## Usage
11
+ ## Validate against an IDS file
19
12
 
20
13
  ```typescript
21
14
  import { parseIDS, validateIDS, createTranslationService } from '@ifc-lite/ids';
22
15
 
23
- // Parse IDS file
24
- const idsSpec = parseIDS(xmlContent);
16
+ const idsXml = await fetch('project-requirements.ids').then(r => r.text());
17
+ const idsSpec = parseIDS(idsXml);
25
18
 
26
- // Create translation service
27
19
  const translator = createTranslationService('en');
20
+ const report = await validateIDS(idsSpec, store, { translator });
28
21
 
29
- // Validate against IFC data
30
- const report = await validateIDS(idsSpec, ifcDataStore, { translator });
22
+ console.log(`Overall: ${report.totalPassed} / ${report.totalChecked} passed`);
31
23
 
32
- // Get human-readable results
33
- for (const specResult of report.specificationResults) {
34
- console.log(`${specResult.specificationName}: ${specResult.passRate}% passed`);
24
+ for (const spec of report.specificationResults) {
25
+ console.log(`\n${spec.specificationName}: ${spec.passRate}%`);
35
26
 
36
- for (const entityResult of specResult.entityResults) {
37
- if (!entityResult.passed) {
38
- for (const reqResult of entityResult.requirementResults) {
39
- if (!reqResult.passed) {
40
- console.log(` - ${translator.describeFailure(reqResult)}`);
41
- }
27
+ for (const entity of spec.entityResults) {
28
+ if (!entity.passed) {
29
+ for (const req of entity.requirementResults.filter(r => !r.passed)) {
30
+ console.log(` ✗ ${entity.entityType} #${entity.expressId}: ${translator.describeFailure(req)}`);
42
31
  }
43
32
  }
44
33
  }
45
34
  }
46
35
  ```
47
36
 
48
- ## Supported Languages
37
+ ## Multi-language reports
38
+
39
+ Reports translate automatically. Supported languages: English (`en`), German (`de`), French (`fr`).
40
+
41
+ ```typescript
42
+ const de = createTranslationService('de');
43
+ const report = await validateIDS(idsSpec, store, { translator: de });
44
+ // Failures now read: "Anforderung 'FireRating' nicht erfüllt..."
45
+ ```
46
+
47
+ ## Inspect an IDS specification
48
+
49
+ ```typescript
50
+ const idsSpec = parseIDS(idsXml);
51
+
52
+ for (const spec of idsSpec.specifications) {
53
+ console.log(`Spec: ${spec.name} (${spec.identifier})`);
54
+ console.log(` Applies to: ${spec.applicability.facets.length} facet(s)`);
55
+ console.log(` Requires: ${spec.requirements.facets.length} facet(s)`);
56
+ }
57
+ ```
58
+
59
+ ## Supported facets
49
60
 
50
- - English (en)
51
- - German (de)
52
- - French (fr)
61
+ | Facet | Matches |
62
+ |---|---|
63
+ | `Entity` | IFC entity type (`IfcWall`, `IfcDoor`, …) |
64
+ | `Attribute` | IfcRoot attributes (`Name`, `Description`, `Tag`, …) |
65
+ | `Property` | Property set + property name + value |
66
+ | `Classification` | Classification system + reference code |
67
+ | `Material` | Material assignment |
68
+ | `PartOf` | Spatial / compositional relationship |
53
69
 
54
- ## IDS Facets
70
+ ## Supported constraints
55
71
 
56
- | Facet | Description |
57
- |-------|-------------|
58
- | Entity | Match by IFC entity type (e.g., IfcWall, IfcDoor) |
59
- | Attribute | Match by IFC attribute value (Name, Description, etc.) |
60
- | Property | Match by property set and property value |
61
- | Classification | Match by classification system and code |
62
- | Material | Match by material assignment |
63
- | PartOf | Match by spatial/compositional relationship |
72
+ | Constraint | Matches |
73
+ |---|---|
74
+ | `SimpleValue` | Exact match |
75
+ | `Pattern` | Regex match |
76
+ | `Enumeration` | One-of-list |
77
+ | `Bounds` | Numeric range (min/max, inclusive/exclusive) |
64
78
 
65
- ## Constraint Types
79
+ ## API
66
80
 
67
- | Constraint | Description |
68
- |------------|-------------|
69
- | SimpleValue | Exact match |
70
- | Pattern | Regex pattern matching |
71
- | Enumeration | One of a list of values |
72
- | Bounds | Numeric range (min/max inclusive/exclusive) |
81
+ See the [IDS Guide](https://louistrue.github.io/ifc-lite/guide/ids/) and [API Reference](https://louistrue.github.io/ifc-lite/api/typescript/#ifc-liteids).
73
82
 
74
83
  ## License
75
84
 
76
- MPL-2.0
85
+ [MPL-2.0](../../LICENSE)
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Restriction & cardinality coherence checks.
3
+ *
4
+ * Catches authoring mistakes that aren't strictly XSD violations but
5
+ * make a specification ill-formed in practice — empty enumerations,
6
+ * inverted bounds, regex patterns that don't compile, prohibited
7
+ * cardinality on applicability blocks, etc.
8
+ */
9
+ import type { IDSDocument } from '../../types.js';
10
+ import type { IDSAuditIssue } from '../types.js';
11
+ export declare function runCoherenceAudit(doc: IDSDocument): IDSAuditIssue[];
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/audit/coherence/index.ts"],"names":[],"mappings":"AAIA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAEV,WAAW,EAIZ,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAGjD,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,aAAa,EAAE,CAMnE"}
@@ -0,0 +1,392 @@
1
+ /* This Source Code Form is subject to the terms of the Mozilla Public
2
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
3
+ * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
+ import { compileXsdRegex } from './regex.js';
5
+ export function runCoherenceAudit(doc) {
6
+ const issues = [];
7
+ doc.specifications.forEach((spec, i) => {
8
+ auditSpec(spec, `specifications[${i}]`, issues);
9
+ });
10
+ return issues;
11
+ }
12
+ function auditSpec(spec, path, issues) {
13
+ // minOccurs / maxOccurs sanity. Spec parses them as numbers (or
14
+ // 'unbounded'); both must be >= 0 and the order must hold.
15
+ const min = spec.minOccurs;
16
+ const max = spec.maxOccurs;
17
+ if (min !== undefined && (!Number.isInteger(min) || min < 0)) {
18
+ issues.push({
19
+ severity: 'error',
20
+ code: 'E_CARDINALITY_INVALID',
21
+ message: `minOccurs must be a non-negative integer; got ${min}`,
22
+ path: `${path}.minOccurs`,
23
+ detail: { value: String(min) },
24
+ });
25
+ }
26
+ if (max !== undefined && max !== 'unbounded') {
27
+ if (!Number.isInteger(max) || max < 0) {
28
+ issues.push({
29
+ severity: 'error',
30
+ code: 'E_CARDINALITY_INVALID',
31
+ message: `maxOccurs must be a non-negative integer or "unbounded"; got ${max}`,
32
+ path: `${path}.maxOccurs`,
33
+ detail: { value: String(max) },
34
+ });
35
+ }
36
+ }
37
+ if (typeof min === 'number' &&
38
+ typeof max === 'number' &&
39
+ min > max) {
40
+ issues.push({
41
+ severity: 'error',
42
+ code: 'E_CARDINALITY_INVALID',
43
+ message: `minOccurs (${min}) is greater than maxOccurs (${max})`,
44
+ path: `${path}.minOccurs`,
45
+ detail: { min: min, max: max },
46
+ });
47
+ }
48
+ // Upstream IDS-Audit-tool flags `cardinality` on `<applicability>` —
49
+ // it's meaningless there. (Report 202)
50
+ if (spec.applicability.cardinality) {
51
+ issues.push({
52
+ severity: 'warning',
53
+ code: 'W_CARDINALITY_PROHIBITED_APPLICABILITY',
54
+ message: `cardinality="${spec.applicability.cardinality}" has no effect on <applicability>`,
55
+ path: `${path}.applicability.cardinality`,
56
+ });
57
+ }
58
+ spec.applicability.facets.forEach((facet, fi) => {
59
+ auditFacetConstraints(facet, `${path}.applicability.facets[${fi}]`, issues);
60
+ });
61
+ spec.requirements.forEach((req, ri) => {
62
+ auditFacetConstraints(req.facet, `${path}.requirements[${ri}]`, issues);
63
+ auditRequirementCardinality(req, `${path}.requirements[${ri}]`, issues);
64
+ });
65
+ }
66
+ /**
67
+ * Cardinality coherence on a requirement facet (Report 202 upstream).
68
+ *
69
+ * Per upstream IDS-Audit-tool:
70
+ * - `cardinality="optional"` on a `<property>` requires `@dataType`.
71
+ * - `cardinality="prohibited"` on a `<property>` is incompatible with
72
+ * `@dataType` (the property must not exist at all).
73
+ * - `cardinality="optional"` on `<material>`, `<classification>` and
74
+ * `<partOf>` requires a value/system/entity to be specified — an
75
+ * `optional` facet without a constraint is meaningless.
76
+ */
77
+ function auditRequirementCardinality(req, path, issues) {
78
+ // The XSD `conditionalCardinality` / `simpleCardinality` enums are
79
+ // case-sensitive lowercase: `required`, `optional`, `prohibited`. The
80
+ // parser preserves the raw value when it didn't match exactly so we
81
+ // can flag mistakes here (`Required`, `Invalid`, empty string, …)
82
+ // rather than silently defaulting to `required`.
83
+ if (req.cardinalityRaw !== undefined) {
84
+ issues.push({
85
+ severity: 'error',
86
+ code: 'E_CARDINALITY_INVALID',
87
+ message: `@cardinality="${req.cardinalityRaw}" is not a valid value; expected one of {required, optional, prohibited}`,
88
+ path: `${path}.cardinality`,
89
+ facetType: req.facet.type,
90
+ detail: { value: req.cardinalityRaw },
91
+ });
92
+ }
93
+ switch (req.facet.type) {
94
+ case 'property': {
95
+ const hasDataType = req.facet.dataType !== undefined;
96
+ if (req.optionality === 'optional' && !hasDataType) {
97
+ issues.push({
98
+ severity: 'error',
99
+ code: 'E_CARDINALITY_INVALID',
100
+ message: 'optional <property> requirement requires @dataType to be specified',
101
+ path: `${path}.cardinality`,
102
+ facetType: 'property',
103
+ });
104
+ }
105
+ if (req.optionality === 'prohibited' && hasDataType) {
106
+ issues.push({
107
+ severity: 'error',
108
+ code: 'E_CARDINALITY_INVALID',
109
+ message: 'prohibited <property> requirement is incompatible with @dataType',
110
+ path: `${path}.cardinality`,
111
+ facetType: 'property',
112
+ });
113
+ }
114
+ break;
115
+ }
116
+ case 'material': {
117
+ if (req.optionality === 'optional') {
118
+ const hasValue = req.facet.value !== undefined && !isEmptyConstraint(req.facet.value);
119
+ if (!hasValue) {
120
+ issues.push({
121
+ severity: 'error',
122
+ code: 'E_CARDINALITY_INVALID',
123
+ message: 'optional <material> requirement must specify a non-empty <value> constraint',
124
+ path: `${path}.cardinality`,
125
+ facetType: 'material',
126
+ });
127
+ }
128
+ }
129
+ break;
130
+ }
131
+ case 'classification': {
132
+ if (req.optionality === 'optional') {
133
+ const hasSystem = req.facet.system !== undefined &&
134
+ !isEmptyConstraint(req.facet.system);
135
+ const hasValue = req.facet.value !== undefined && !isEmptyConstraint(req.facet.value);
136
+ if (!hasSystem && !hasValue) {
137
+ issues.push({
138
+ severity: 'error',
139
+ code: 'E_CARDINALITY_INVALID',
140
+ message: 'optional <classification> requirement must specify <system> or <value>',
141
+ path: `${path}.cardinality`,
142
+ facetType: 'classification',
143
+ });
144
+ }
145
+ }
146
+ break;
147
+ }
148
+ case 'attribute':
149
+ case 'entity':
150
+ case 'partOf':
151
+ // Attribute/entity/partOf carry their own intrinsic content;
152
+ // cardinality on them is just required/optional/prohibited.
153
+ break;
154
+ }
155
+ }
156
+ function isEmptyConstraint(c) {
157
+ switch (c.type) {
158
+ case 'simpleValue':
159
+ return c.value === '' || c.value == null;
160
+ case 'enumeration':
161
+ return c.values.length === 0;
162
+ case 'pattern':
163
+ return c.pattern === '';
164
+ case 'bounds':
165
+ return (c.minInclusive === undefined &&
166
+ c.maxInclusive === undefined &&
167
+ c.minExclusive === undefined &&
168
+ c.maxExclusive === undefined &&
169
+ c.length === undefined &&
170
+ c.minLength === undefined &&
171
+ c.maxLength === undefined);
172
+ }
173
+ }
174
+ function auditFacetConstraints(facet, path, issues) {
175
+ switch (facet.type) {
176
+ case 'entity':
177
+ check(facet.name, `${path}.name`, issues, facet.type);
178
+ if (facet.predefinedType) {
179
+ check(facet.predefinedType, `${path}.predefinedType`, issues, facet.type);
180
+ }
181
+ break;
182
+ case 'attribute':
183
+ check(facet.name, `${path}.name`, issues, facet.type);
184
+ if (facet.value)
185
+ check(facet.value, `${path}.value`, issues, facet.type);
186
+ break;
187
+ case 'property':
188
+ check(facet.propertySet, `${path}.propertySet`, issues, facet.type);
189
+ check(facet.baseName, `${path}.baseName`, issues, facet.type);
190
+ if (facet.dataType)
191
+ check(facet.dataType, `${path}.dataType`, issues, facet.type);
192
+ if (facet.value)
193
+ check(facet.value, `${path}.value`, issues, facet.type);
194
+ break;
195
+ case 'classification':
196
+ if (facet.system)
197
+ check(facet.system, `${path}.system`, issues, facet.type);
198
+ if (facet.value)
199
+ check(facet.value, `${path}.value`, issues, facet.type);
200
+ break;
201
+ case 'material':
202
+ if (facet.value)
203
+ check(facet.value, `${path}.value`, issues, facet.type);
204
+ break;
205
+ case 'partOf':
206
+ if (facet.entity) {
207
+ auditFacetConstraints(facet.entity, `${path}.entity`, issues);
208
+ }
209
+ break;
210
+ }
211
+ }
212
+ function check(c, path, issues, facetType) {
213
+ switch (c.type) {
214
+ case 'enumeration':
215
+ if (c.values.length === 0) {
216
+ issues.push({
217
+ severity: 'error',
218
+ code: 'E_RESTRICTION_EMPTY',
219
+ message: 'xs:enumeration must have at least one value',
220
+ path,
221
+ facetType,
222
+ });
223
+ }
224
+ else if (c.values.some((v) => v === '' || v == null)) {
225
+ issues.push({
226
+ severity: 'warning',
227
+ code: 'E_RESTRICTION_EMPTY',
228
+ message: 'xs:enumeration has an empty entry',
229
+ path,
230
+ facetType,
231
+ });
232
+ }
233
+ // When the restriction base is a typed primitive
234
+ // (`xs:double`/`xs:integer`/`xs:boolean`/…), every enumeration
235
+ // value must match the base's lexical space — upstream's
236
+ // `Report 305 BadConstraintValue`. Otherwise an `xs:double`
237
+ // restriction can carry strings like `"12,0"` or `"a"` that
238
+ // would never compare equal to a real numeric value.
239
+ if (c.base) {
240
+ for (const v of c.values) {
241
+ if (v == null || v === '')
242
+ continue;
243
+ if (!isValidLexicalForXsType(v, c.base)) {
244
+ issues.push({
245
+ severity: 'error',
246
+ code: 'E_RESTRICTION_VALUE_MISMATCH',
247
+ message: `xs:enumeration value "${v}" is not valid for xs:restriction @base="${c.base}"`,
248
+ path,
249
+ facetType,
250
+ detail: { value: v, base: c.base },
251
+ });
252
+ }
253
+ }
254
+ }
255
+ break;
256
+ case 'bounds':
257
+ checkBounds(c, path, issues, facetType);
258
+ break;
259
+ case 'pattern':
260
+ checkPattern(c.pattern, path, issues, facetType);
261
+ break;
262
+ case 'simpleValue':
263
+ // No coherence check beyond the XSD's required-non-empty check,
264
+ // which we already do in the XSD audit.
265
+ break;
266
+ }
267
+ }
268
+ function checkBounds(c, path, issues, facetType) {
269
+ const lo = c.minInclusive ?? c.minExclusive;
270
+ const hi = c.maxInclusive ?? c.maxExclusive;
271
+ if (typeof lo === 'number' &&
272
+ typeof hi === 'number' &&
273
+ lo > hi) {
274
+ issues.push({
275
+ severity: 'error',
276
+ code: 'E_RESTRICTION_RANGE',
277
+ message: `xs:restriction bounds inverted: lower (${lo}) > upper (${hi})`,
278
+ path,
279
+ facetType,
280
+ detail: { min: lo, max: hi },
281
+ });
282
+ }
283
+ if (typeof c.minLength === 'number' &&
284
+ typeof c.maxLength === 'number' &&
285
+ c.minLength > c.maxLength) {
286
+ issues.push({
287
+ severity: 'error',
288
+ code: 'E_RESTRICTION_RANGE',
289
+ message: `xs:restriction lengths inverted: minLength (${c.minLength}) > maxLength (${c.maxLength})`,
290
+ path,
291
+ facetType,
292
+ detail: { min: c.minLength, max: c.maxLength },
293
+ });
294
+ }
295
+ if (typeof c.length === 'number' &&
296
+ (typeof c.minLength === 'number' || typeof c.maxLength === 'number')) {
297
+ issues.push({
298
+ severity: 'warning',
299
+ code: 'E_RESTRICTION_RANGE',
300
+ message: 'xs:length is mutually exclusive with xs:minLength/xs:maxLength',
301
+ path,
302
+ facetType,
303
+ });
304
+ }
305
+ const empty = c.minInclusive === undefined &&
306
+ c.minExclusive === undefined &&
307
+ c.maxInclusive === undefined &&
308
+ c.maxExclusive === undefined &&
309
+ c.length === undefined &&
310
+ c.minLength === undefined &&
311
+ c.maxLength === undefined;
312
+ if (empty) {
313
+ issues.push({
314
+ severity: 'error',
315
+ code: 'E_RESTRICTION_EMPTY',
316
+ message: 'xs:restriction has no min/max bounds or length facets',
317
+ path,
318
+ facetType,
319
+ });
320
+ }
321
+ }
322
+ /**
323
+ * Validate `pattern` against XSD regex semantics by translating XSD-only
324
+ * escape codes to JS regex equivalents (cf. upstream `XmlRegex.cs`).
325
+ *
326
+ * Translation handles `\i`/`\c`/`\d`/`\w` and their negations via
327
+ * Unicode property escapes (compiled with the `u` flag). Char-class
328
+ * subtraction (`[a-z-[aeiou]]`) is XSD-only and surfaces as
329
+ * `W_REGEX_UNVERIFIED`. Any remaining syntactic errors are real
330
+ * authoring mistakes and surface as `E_RESTRICTION_EMPTY` (upstream
331
+ * Report 109).
332
+ */
333
+ function checkPattern(pattern, path, issues, facetType) {
334
+ const result = compileXsdRegex(pattern);
335
+ if (result.ok)
336
+ return;
337
+ if (result.severity === 'error') {
338
+ issues.push({
339
+ severity: 'error',
340
+ code: pattern === '' ? 'E_RESTRICTION_EMPTY' : 'E_RESTRICTION_EMPTY',
341
+ message: pattern === ''
342
+ ? 'xs:pattern @value is empty'
343
+ : `xs:pattern is not a valid regular expression: ${result.reason}`,
344
+ path,
345
+ facetType,
346
+ detail: pattern === '' ? undefined : { pattern },
347
+ });
348
+ return;
349
+ }
350
+ issues.push({
351
+ severity: 'warning',
352
+ code: 'W_REGEX_UNVERIFIED',
353
+ message: `xs:pattern uses XSD-specific syntax not verifiable in JS: ${result.reason}`,
354
+ path,
355
+ facetType,
356
+ detail: { pattern },
357
+ });
358
+ }
359
+ /**
360
+ * Validate that `value` matches the lexical space of the supplied XSD
361
+ * primitive base. Mirrors upstream `XsTypes.IsValid` — same regexes,
362
+ * just expressed in JS. Used by the enumeration coherence check to
363
+ * flag entries like `<xs:enumeration value="12,0"/>` under a
364
+ * `<xs:restriction base="xs:double">`.
365
+ */
366
+ const XS_VALUE_REGEX = {
367
+ // Lifted from upstream `XmlRegex.cs` static fields.
368
+ 'xs:integer': /^[+-]?(\d+)$/,
369
+ 'xs:double': /^([-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?|NaN|\+INF|-INF)$/,
370
+ 'xs:float': /^([-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?|NaN|\+INF|-INF)$/,
371
+ 'xs:decimal': /^([-+]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?|NaN|\+INF|-INF)$/,
372
+ 'xs:boolean': /^(true|false|0|1)$/,
373
+ 'xs:date': /^\d{4}-\d{2}-\d{2}(Z|([+-]\d{2}:\d{2}))?$/,
374
+ 'xs:dateTime': /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|([+-]\d{2}:\d{2}))?$/,
375
+ 'xs:time': /^\d{2}:\d{2}:\d{2}(\.\d+)?(Z|([+-]\d{2}:\d{2}))?$/,
376
+ 'xs:duration': /^[-+]?P(\d+Y)?(\d+M)?(\d+D)?(T(\d+H)?(\d+M)?(\d+S)?)?$/,
377
+ };
378
+ function isValidLexicalForXsType(value, base) {
379
+ const rx = XS_VALUE_REGEX[base];
380
+ if (!rx)
381
+ return true; // base we don't recognise → don't fabricate errors
382
+ // For doubles/floats/decimals, an empty lexeme is technically allowed
383
+ // by the regex but isn't a meaningful number — reject.
384
+ if ((base === 'xs:double' ||
385
+ base === 'xs:float' ||
386
+ base === 'xs:decimal') &&
387
+ !/[0-9]/.test(value)) {
388
+ return false;
389
+ }
390
+ return rx.test(value);
391
+ }
392
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/audit/coherence/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Translate an XSD regex pattern into JavaScript regex syntax.
3
+ *
4
+ * Ported from `IdsLib/IdsSchema/XsNodes/XmlRegex.cs` (MIT) which itself
5
+ * mirrors Microsoft's reference XSD facet checker. XSD regex extends
6
+ * the JS dialect with:
7
+ *
8
+ * - `\i` — XML name start char (letter, `_`, `:` plus a swathe of
9
+ * Unicode letters)
10
+ * - `\c` — XML name char (`\i` plus digits, `.`, `-`, U+00B7, etc.)
11
+ * - `\d` — Unicode digit (broader than JS `[0-9]`)
12
+ * - `\w` — Unicode word char (letters + digits, no `_`)
13
+ * - `\D`, `\C`, `\I`, `\W` — negations
14
+ * - char-class subtraction `[a-z-[aeiou]]` — the JS dialect doesn't
15
+ * support this; we fall back to a marker so the auditor can warn.
16
+ *
17
+ * The translation maps to JS Unicode property escapes (require `u` flag).
18
+ * `\d` and `\w` already exist in JS and map close enough that we leave
19
+ * them alone — same applies to `\D`/`\W`. The XML name char escapes are
20
+ * the only ones that genuinely need translation.
21
+ */
22
+ interface TranslateResult {
23
+ /** The pattern usable with the JS `RegExp` constructor. */
24
+ pattern: string;
25
+ /** Whether translation produced a faithful JS-compatible regex. */
26
+ supported: boolean;
27
+ /**
28
+ * Human-readable reason when `supported === false`. Empty string when
29
+ * fully supported.
30
+ */
31
+ reason: string;
32
+ }
33
+ /**
34
+ * Translate the XSD pattern. Returns the JS-compatible pattern plus a
35
+ * `supported` flag — when `false`, the auditor should warn rather than
36
+ * compile-test the result (the unsupported construct may produce
37
+ * spurious failures).
38
+ */
39
+ export declare function translateXsdRegex(pattern: string): TranslateResult;
40
+ /**
41
+ * Try to compile `pattern` as XSD regex semantics. Returns:
42
+ * - `{ ok: true }` when the pattern is valid (after translation).
43
+ * - `{ ok: false, severity: 'error', reason }` for syntactic errors
44
+ * that JS *and* XSD agree on (e.g. unclosed `[`).
45
+ * - `{ ok: false, severity: 'warning', reason }` when the pattern uses
46
+ * XSD-only syntax we can't translate (char-class subtraction).
47
+ */
48
+ export declare function compileXsdRegex(pattern: string): {
49
+ ok: true;
50
+ jsPattern: string;
51
+ } | {
52
+ ok: false;
53
+ severity: 'error' | 'warning';
54
+ reason: string;
55
+ };
56
+ export {};
57
+ //# sourceMappingURL=regex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex.d.ts","sourceRoot":"","sources":["../../../src/audit/coherence/regex.ts"],"names":[],"mappings":"AAIA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,UAAU,eAAe;IACvB,2DAA2D;IAC3D,OAAO,EAAE,MAAM,CAAC;IAChB,mEAAmE;IACnE,SAAS,EAAE,OAAO,CAAC;IACnB;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,eAAe,CAiClE;AA2CD;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,GAEb;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAA;CAAE,GAC/B;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,EAAE,OAAO,GAAG,SAAS,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAkB/D"}