@mitre/hdf-parsers 3.1.0 → 3.3.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 CHANGED
@@ -18,13 +18,13 @@ Parse and load Heimdall Data Format (HDF) documents with validation. Provides a
18
18
  |-------------|----------------|
19
19
  | Parse JSON → typed objects | Validate JSON against schema |
20
20
  | "Load and validate this HDF file" | "Is this valid HDF?" |
21
- | Returns typed HdfResults/HdfBaseline | Returns validation errors |
21
+ | Returns typed HDFResults/HDFBaseline | Returns validation errors |
22
22
  | One-step parse + validate | Schema validation only |
23
23
  | Used by CLI commands and tools | Used internally by parsers |
24
24
 
25
25
  **Example:**
26
26
  - `validateResults(data)` → `{ valid: true, errors: [] }` (validators - just validates)
27
- - `parseResults(json)` → `{ success: true, data: HdfResults }` (parsers - validates AND parses)
27
+ - `parseResults(json)` → `{ success: true, data: HDFResults }` (parsers - validates AND parses)
28
28
 
29
29
  ## Installation
30
30
 
@@ -90,7 +90,7 @@ import (
90
90
  "fmt"
91
91
  "os"
92
92
 
93
- parsers "github.com/mitre/hdf-libs/hdf-parsers/go"
93
+ parsers "github.com/mitre/hdf-libs/hdf-parsers/go/v3"
94
94
  )
95
95
 
96
96
  func main() {
@@ -137,23 +137,23 @@ if result.Success {
137
137
 
138
138
  ### TypeScript
139
139
 
140
- #### `parseResults(input: string | Uint8Array): ParseResult<HdfResults>`
140
+ #### `parseResults(input: string | Uint8Array): ParseResult<HDFResults>`
141
141
 
142
142
  Parse HDF Results document from JSON string or bytes.
143
143
 
144
144
  - **Parameters:**
145
145
  - `input` - JSON string or Uint8Array to parse
146
- - **Returns:** `ParseResult<HdfResults>` with parsed data or error
146
+ - **Returns:** `ParseResult<HDFResults>` with parsed data or error
147
147
 
148
- #### `parseBaseline(input: string | Uint8Array): ParseResult<HdfBaseline>`
148
+ #### `parseBaseline(input: string | Uint8Array): ParseResult<HDFBaseline>`
149
149
 
150
150
  Parse HDF Baseline document from JSON string or bytes.
151
151
 
152
152
  - **Parameters:**
153
153
  - `input` - JSON string or Uint8Array to parse
154
- - **Returns:** `ParseResult<HdfBaseline>` with parsed data or error
154
+ - **Returns:** `ParseResult<HDFBaseline>` with parsed data or error
155
155
 
156
- #### `parse(input: string | Uint8Array): ParseResult<HdfResults | HdfBaseline>`
156
+ #### `parse(input: string | Uint8Array): ParseResult<HDFResults | HDFBaseline>`
157
157
 
158
158
  Parse HDF document with auto-detection of type (Results vs Baseline).
159
159
 
@@ -329,9 +329,9 @@ Get type-safe HDF objects:
329
329
 
330
330
  ```typescript
331
331
  import { parseResults } from '@mitre/hdf-parsers';
332
- import type { HdfResults } from '@mitre/hdf-schema';
332
+ import type { HDFResults } from '@mitre/hdf-schema';
333
333
 
334
- function processResults(data: HdfResults) {
334
+ function processResults(data: HDFResults) {
335
335
  // TypeScript knows the exact structure
336
336
  for (const baseline of data.baselines ?? []) {
337
337
  console.log(`Baseline: ${baseline.name}`);
package/dist/index.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { HdfBaseline, HdfResults } from "@mitre/hdf-schema";
1
+ import { HDFBaseline, HDFComparison, HDFEvidencePackage, HDFPlan, HDFResults, HDFSystem } from "@mitre/hdf-schema";
2
2
 
3
3
  //#region typescript/flatten.d.ts
4
4
  interface FlattenResult {
5
- results: HdfResults;
5
+ results: HDFResults;
6
6
  metadata: FlattenMetadata;
7
7
  }
8
8
  interface FlattenMetadata {
@@ -29,9 +29,16 @@ interface BaselineMerge {
29
29
  * @param results - Parsed HDF Results (from parseResults() or equivalent)
30
30
  * @returns FlattenResult with flattened data and merge metadata
31
31
  */
32
- declare function flattenOverlays(results: HdfResults): FlattenResult;
32
+ declare function flattenOverlays(results: HDFResults): FlattenResult;
33
33
  //#endregion
34
34
  //#region typescript/index.d.ts
35
+ /**
36
+ * Append Z (treat as UTC) to bare ISO timestamps in a JSON string so they
37
+ * pass schema validation. Exported so other workspace packages can use the
38
+ * same regex instead of re-implementing it. Matches the Go side at
39
+ * hdf-parsers/go/parsers.go.
40
+ */
41
+ declare function normalizeTimestamps(input: string): string;
35
42
  /**
36
43
  * Result of parsing operation
37
44
  */
@@ -39,26 +46,42 @@ interface ParseResult<T> {
39
46
  success: boolean;
40
47
  data?: T;
41
48
  error?: string;
42
- type?: 'results' | 'baseline';
49
+ type?: 'results' | 'baseline' | 'system' | 'plan' | 'evidencePackage' | 'comparison';
43
50
  }
44
51
  /**
45
52
  * Parse HDF Results document from string or bytes
46
53
  * @param input - JSON string or Uint8Array to parse
47
54
  * @returns ParseResult with parsed data or error
48
55
  */
49
- declare function parseResults(input: string | Uint8Array): ParseResult<HdfResults>;
56
+ declare function parseResults(input: string | Uint8Array): ParseResult<HDFResults>;
50
57
  /**
51
58
  * Parse HDF Baseline document from string or bytes
52
59
  * @param input - JSON string or Uint8Array to parse
53
60
  * @returns ParseResult with parsed data or error
54
61
  */
55
- declare function parseBaseline(input: string | Uint8Array): ParseResult<HdfBaseline>;
62
+ declare function parseBaseline(input: string | Uint8Array): ParseResult<HDFBaseline>;
63
+ /**
64
+ * Parse HDF System document from string or bytes
65
+ */
66
+ declare function parseSystem(input: string | Uint8Array): ParseResult<HDFSystem>;
67
+ /**
68
+ * Parse HDF Plan document from string or bytes
69
+ */
70
+ declare function parsePlan(input: string | Uint8Array): ParseResult<HDFPlan>;
71
+ /**
72
+ * Parse HDF Evidence Package document from string or bytes
73
+ */
74
+ declare function parseEvidencePackage(input: string | Uint8Array): ParseResult<HDFEvidencePackage>;
75
+ /**
76
+ * Parse HDF Comparison document from string or bytes
77
+ */
78
+ declare function parseComparison(input: string | Uint8Array): ParseResult<HDFComparison>;
56
79
  /**
57
80
  * Parse HDF document with auto-detection of type
58
81
  * @param input - JSON string or Uint8Array to parse
59
82
  * @returns ParseResult with parsed data, type indicator, or error
60
83
  */
61
- declare function parse(input: string | Uint8Array): ParseResult<HdfResults | HdfBaseline>;
84
+ declare function parse(input: string | Uint8Array): ParseResult<HDFResults | HDFBaseline | HDFSystem | HDFPlan | HDFEvidencePackage | HDFComparison>;
62
85
  //#endregion
63
- export { type BaselineMerge, type FlattenMetadata, type FlattenResult, ParseResult, flattenOverlays, parse, parseBaseline, parseResults };
86
+ export { type BaselineMerge, type FlattenMetadata, type FlattenResult, ParseResult, flattenOverlays, normalizeTimestamps, parse, parseBaseline, parseComparison, parseEvidencePackage, parsePlan, parseResults, parseSystem };
64
87
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"mappings":";;;UAIiB,aAAA;EACf,OAAA,EAAS,UAAA;EACT,QAAA,EAAU,eAAA;AAAA;AAAA,UAGK,eAAA;EACf,qBAAA;EACA,sBAAA;EACA,MAAA,EAAQ,aAAA;EACR,QAAA;AAAA;AAAA,UAGe,aAAA;EACf,YAAA;EACA,iBAAA;EACA,cAAA;EACA,aAAA;EACA,OAAA;AAAA;;;;;;;AALF;;;;;iBAgIgB,eAAA,CAAgB,OAAA,EAAS,UAAA,GAAa,aAAA;;;AA5ItD;;;AAAA,UCIiB,WAAA;EACf,OAAA;EACA,IAAA,GAAO,CAAA;EACP,KAAA;EACA,IAAA;AAAA;;ADHF;;;;iBCWgB,YAAA,CAAa,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,UAAA;;;;;;iBAsDtD,aAAA,CAAc,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,WAAA;AD1DvE;;;;;AAAA,iBC+GgB,KAAA,CAAM,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,UAAA,GAAa,WAAA"}
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"mappings":";;;UAIiB,aAAA;EACf,OAAA,EAAS,UAAA;EACT,QAAA,EAAU,eAAe;AAAA;AAAA,UAGV,eAAA;EACf,qBAAA;EACA,sBAAA;EACA,MAAA,EAAQ,aAAa;EACrB,QAAA;AAAA;AAAA,UAGe,aAAA;EACf,YAAA;EACA,iBAAA;EACA,cAAA;EACA,aAAA;EACA,OAAA;AAAA;;;;;;AARQ;AAGV;;;;;iBAgIgB,eAAA,CAAgB,OAAA,EAAS,UAAA,GAAa,aAAa;;;AA5InE;;;;;;AAAA,iBC2BgB,mBAAA,CAAoB,KAAa;;;ADzBtB;UCgCV,WAAA;EACf,OAAA;EACA,IAAA,GAAO,CAAC;EACR,KAAA;EACA,IAAA;AAAA;;;;;AD7BQ;iBCqCM,YAAA,CAAa,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,UAAA;;;;;;iBAmDtD,aAAA,CAAc,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,WAAA;;;;iBA6CvD,WAAA,CAAY,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,SAAA;ADFrE;;;AAAA,iBCwBgB,SAAA,CAAU,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,OAAA;;;;iBAsBnD,oBAAA,CAAqB,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,kBAAA;AD9CX;;;AAAA,iBCoEnD,eAAA,CAAgB,KAAA,WAAgB,UAAA,GAAa,WAAA,CAAY,aAAA;AArLzE;;;;AAAiD;AAAjD,iBA6MgB,KAAA,CACd,KAAA,WAAgB,UAAA,GACf,WAAA,CAAY,UAAA,GAAa,WAAA,GAAc,SAAA,GAAY,OAAA,GAAU,kBAAA,GAAqB,aAAA"}
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { validate, validateBaseline, validateResults } from "@mitre/hdf-validators";
1
+ import { validate, validateBaseline, validateComparison, validateEvidencePackage, validatePlan, validateResults, validateSystem } from "@mitre/hdf-validators";
2
2
  //#region typescript/flatten.ts
3
3
  /** BFS from root, returns names in top-down order. Cycle-safe. */
4
4
  function collectTree(root, childrenMap) {
@@ -168,13 +168,23 @@ function flattenOverlays(results) {
168
168
  }
169
169
  //#endregion
170
170
  //#region typescript/index.ts
171
+ const NO_TZ_TIMESTAMP_REGEX = /"(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?)"/g;
172
+ /**
173
+ * Append Z (treat as UTC) to bare ISO timestamps in a JSON string so they
174
+ * pass schema validation. Exported so other workspace packages can use the
175
+ * same regex instead of re-implementing it. Matches the Go side at
176
+ * hdf-parsers/go/parsers.go.
177
+ */
178
+ function normalizeTimestamps(input) {
179
+ return input.replace(NO_TZ_TIMESTAMP_REGEX, "\"$1Z\"");
180
+ }
171
181
  /**
172
182
  * Parse HDF Results document from string or bytes
173
183
  * @param input - JSON string or Uint8Array to parse
174
184
  * @returns ParseResult with parsed data or error
175
185
  */
176
186
  function parseResults(input) {
177
- const jsonStr = typeof input === "string" ? input : new TextDecoder().decode(input);
187
+ const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
178
188
  if (jsonStr.trim().length === 0) return {
179
189
  success: false,
180
190
  error: "Input is empty"
@@ -188,12 +198,6 @@ function parseResults(input) {
188
198
  error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
189
199
  };
190
200
  }
191
- const serialized = JSON.stringify(data);
192
- const trimmedInput = jsonStr.trim();
193
- if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) return {
194
- success: false,
195
- error: "Invalid JSON: unexpected trailing data after end of object"
196
- };
197
201
  const validationResult = validateResults(data);
198
202
  if (!validationResult.valid) return {
199
203
  success: false,
@@ -210,7 +214,7 @@ function parseResults(input) {
210
214
  * @returns ParseResult with parsed data or error
211
215
  */
212
216
  function parseBaseline(input) {
213
- const jsonStr = typeof input === "string" ? input : new TextDecoder().decode(input);
217
+ const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
214
218
  if (jsonStr.trim().length === 0) return {
215
219
  success: false,
216
220
  error: "Input is empty"
@@ -224,13 +228,119 @@ function parseBaseline(input) {
224
228
  error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
225
229
  };
226
230
  }
227
- const serialized = JSON.stringify(data);
228
- const trimmedInput = jsonStr.trim();
229
- if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) return {
231
+ const validationResult = validateBaseline(data);
232
+ if (!validationResult.valid) return {
230
233
  success: false,
231
- error: "Invalid JSON: unexpected trailing data after end of object"
234
+ error: `Schema validation failed: ${validationResult.getErrorMessage()}`
232
235
  };
233
- const validationResult = validateBaseline(data);
236
+ return {
237
+ success: true,
238
+ data
239
+ };
240
+ }
241
+ /**
242
+ * Parse HDF System document from string or bytes
243
+ */
244
+ function parseSystem(input) {
245
+ const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
246
+ if (jsonStr.trim().length === 0) return {
247
+ success: false,
248
+ error: "Input is empty"
249
+ };
250
+ let data;
251
+ try {
252
+ data = JSON.parse(jsonStr);
253
+ } catch (err) {
254
+ return {
255
+ success: false,
256
+ error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
257
+ };
258
+ }
259
+ const validationResult = validateSystem(data);
260
+ if (!validationResult.valid) return {
261
+ success: false,
262
+ error: `Schema validation failed: ${validationResult.getErrorMessage()}`
263
+ };
264
+ return {
265
+ success: true,
266
+ data
267
+ };
268
+ }
269
+ /**
270
+ * Parse HDF Plan document from string or bytes
271
+ */
272
+ function parsePlan(input) {
273
+ const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
274
+ if (jsonStr.trim().length === 0) return {
275
+ success: false,
276
+ error: "Input is empty"
277
+ };
278
+ let data;
279
+ try {
280
+ data = JSON.parse(jsonStr);
281
+ } catch (err) {
282
+ return {
283
+ success: false,
284
+ error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
285
+ };
286
+ }
287
+ const validationResult = validatePlan(data);
288
+ if (!validationResult.valid) return {
289
+ success: false,
290
+ error: `Schema validation failed: ${validationResult.getErrorMessage()}`
291
+ };
292
+ return {
293
+ success: true,
294
+ data
295
+ };
296
+ }
297
+ /**
298
+ * Parse HDF Evidence Package document from string or bytes
299
+ */
300
+ function parseEvidencePackage(input) {
301
+ const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
302
+ if (jsonStr.trim().length === 0) return {
303
+ success: false,
304
+ error: "Input is empty"
305
+ };
306
+ let data;
307
+ try {
308
+ data = JSON.parse(jsonStr);
309
+ } catch (err) {
310
+ return {
311
+ success: false,
312
+ error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
313
+ };
314
+ }
315
+ const validationResult = validateEvidencePackage(data);
316
+ if (!validationResult.valid) return {
317
+ success: false,
318
+ error: `Schema validation failed: ${validationResult.getErrorMessage()}`
319
+ };
320
+ return {
321
+ success: true,
322
+ data
323
+ };
324
+ }
325
+ /**
326
+ * Parse HDF Comparison document from string or bytes
327
+ */
328
+ function parseComparison(input) {
329
+ const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
330
+ if (jsonStr.trim().length === 0) return {
331
+ success: false,
332
+ error: "Input is empty"
333
+ };
334
+ let data;
335
+ try {
336
+ data = JSON.parse(jsonStr);
337
+ } catch (err) {
338
+ return {
339
+ success: false,
340
+ error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
341
+ };
342
+ }
343
+ const validationResult = validateComparison(data);
234
344
  if (!validationResult.valid) return {
235
345
  success: false,
236
346
  error: `Schema validation failed: ${validationResult.getErrorMessage()}`
@@ -246,7 +356,7 @@ function parseBaseline(input) {
246
356
  * @returns ParseResult with parsed data, type indicator, or error
247
357
  */
248
358
  function parse(input) {
249
- const jsonStr = typeof input === "string" ? input : new TextDecoder().decode(input);
359
+ const jsonStr = normalizeTimestamps(typeof input === "string" ? input : new TextDecoder().decode(input));
250
360
  if (jsonStr.trim().length === 0) return {
251
361
  success: false,
252
362
  error: "Input is empty"
@@ -260,12 +370,6 @@ function parse(input) {
260
370
  error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`
261
371
  };
262
372
  }
263
- const serialized = JSON.stringify(data);
264
- const trimmedInput = jsonStr.trim();
265
- if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) return {
266
- success: false,
267
- error: "Invalid JSON: unexpected trailing data after end of object"
268
- };
269
373
  const validationResult = validate(data);
270
374
  if (!validationResult.valid) return {
271
375
  success: false,
@@ -278,26 +382,38 @@ function parse(input) {
278
382
  data,
279
383
  type: "results"
280
384
  };
385
+ if ("requirementDiffs" in obj) return {
386
+ success: true,
387
+ data,
388
+ type: "comparison"
389
+ };
390
+ if ("assessments" in obj) return {
391
+ success: true,
392
+ data,
393
+ type: "plan"
394
+ };
395
+ if ("contents" in obj) return {
396
+ success: true,
397
+ data,
398
+ type: "evidencePackage"
399
+ };
281
400
  if ("name" in obj && "requirements" in obj) return {
282
401
  success: true,
283
402
  data,
284
403
  type: "baseline"
285
404
  };
405
+ if ("components" in obj) return {
406
+ success: true,
407
+ data,
408
+ type: "system"
409
+ };
286
410
  }
287
411
  return {
288
412
  success: false,
289
413
  error: "Unable to determine HDF document type"
290
414
  };
291
415
  }
292
- /**
293
- * Check if two JSON strings are equivalent modulo whitespace
294
- * This is a simple heuristic - we check if one is just whitespace-padded version of other
295
- */
296
- function isWhitespaceEquivalent(a, b) {
297
- const normalizeWhitespace = (s) => s.replace(/\s+/g, "");
298
- return normalizeWhitespace(a) === normalizeWhitespace(b);
299
- }
300
416
  //#endregion
301
- export { flattenOverlays, parse, parseBaseline, parseResults };
417
+ export { flattenOverlays, normalizeTimestamps, parse, parseBaseline, parseComparison, parseEvidencePackage, parsePlan, parseResults, parseSystem };
302
418
 
303
419
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["autoValidate"],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"sourcesContent":["import type { HdfResults, EvaluatedBaseline, EvaluatedRequirement } from '@mitre/hdf-schema';\n\n// ── Public Types ────────────────────────────────────────────\n\nexport interface FlattenResult {\n results: HdfResults;\n metadata: FlattenMetadata;\n}\n\nexport interface FlattenMetadata {\n originalBaselineCount: number;\n flattenedBaselineCount: number;\n merges: BaselineMerge[];\n warnings: string[];\n}\n\nexport interface BaselineMerge {\n rootBaseline: string;\n absorbedBaselines: string[];\n controlsBefore: number;\n controlsAfter: number;\n pattern: 'deep' | 'wide' | 'hybrid';\n}\n\n// ── Internal Helpers ───────────────────────────────────────\n\n/** BFS from root, returns names in top-down order. Cycle-safe. */\nfunction collectTree(root: string, childrenMap: Map<string, string[]>): string[] {\n const order: string[] = [];\n const seen = new Set<string>();\n const queue = [root];\n while (queue.length > 0) {\n const name = queue.shift()!;\n if (seen.has(name)) continue;\n seen.add(name);\n order.push(name);\n for (const child of (childrenMap.get(name) || [])) {\n queue.push(child);\n }\n }\n return order;\n}\n\n/** Classify merge pattern based on tree shape */\nfunction detectPattern(root: string, childrenMap: Map<string, string[]>): 'deep' | 'wide' | 'hybrid' {\n const rootChildren = childrenMap.get(root) || [];\n if (rootChildren.length <= 1) {\n return 'deep';\n }\n for (const child of rootChildren) {\n if ((childrenMap.get(child) || []).length > 0) {\n return 'hybrid';\n }\n }\n return 'wide';\n}\n\n/** Merge incoming requirement fields onto existing */\nfunction mergeRequirement(\n existing: EvaluatedRequirement,\n incoming: EvaluatedRequirement\n): EvaluatedRequirement {\n const result: EvaluatedRequirement = { ...existing };\n\n // Impact: incoming always wins (required field, always present)\n result.impact = incoming.impact;\n\n // Results: keep whichever is non-empty (base has them, overlay doesn't)\n if (incoming.results && incoming.results.length > 0) {\n result.results = incoming.results;\n }\n\n // Code: incoming wins if non-empty\n if (incoming.code && incoming.code.trim() !== '') {\n result.code = incoming.code;\n }\n\n // Tags: shallow merge (incoming keys override)\n if (incoming.tags) {\n result.tags = { ...existing.tags, ...incoming.tags };\n }\n\n // Severity: incoming wins if present, else keep existing\n if (incoming.severity !== undefined) {\n result.severity = incoming.severity;\n }\n\n // EffectiveStatus: incoming wins only if it has results (otherwise its\n // effectiveStatus is a computed artifact from empty results, not intentional).\n // Overlays typically have empty results — the base has the real test results.\n if (incoming.effectiveStatus !== undefined && incoming.results && incoming.results.length > 0) {\n result.effectiveStatus = incoming.effectiveStatus;\n }\n\n // Descriptions: merge by label (incoming overrides same label)\n if (incoming.descriptions && incoming.descriptions.length > 0) {\n const descMap = new Map(\n (existing.descriptions || []).map(d => [d.label, d])\n );\n for (const d of incoming.descriptions) {\n descMap.set(d.label, d);\n }\n result.descriptions = [...descMap.values()];\n }\n\n return result;\n}\n\n/**\n * Resolve parentBaseline for a baseline.\n * InSpec parent_profile can use depends-name aliases (e.g., 'k8s' instead of\n * 'k8s-node-stig-baseline'). When the value isn't a direct profile name,\n * find who depends on this baseline — that's the actual parent.\n */\nfunction resolveParentBaseline(\n b: EvaluatedBaseline,\n byName: Map<string, EvaluatedBaseline>,\n allBaselines: EvaluatedBaseline[]\n): string | undefined {\n if (!b.parentBaseline) return undefined;\n if (byName.has(b.parentBaseline)) return b.parentBaseline;\n\n // Alias resolution: find the profile whose depends array includes this baseline\n for (const candidate of allBaselines) {\n if (candidate.depends?.some((d) => d.name === b.name)) {\n return candidate.name;\n }\n }\n return undefined; // orphan\n}\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Flatten overlay/wrapper baselines in an HDF Results document.\n *\n * Handles:\n * - Deep nesting (overlay chains with shared control IDs via parentBaseline)\n * - Wide nesting (wrapper profiles aggregating independent bases)\n * - Hybrid (both patterns in one document)\n *\n * @param results - Parsed HDF Results (from parseResults() or equivalent)\n * @returns FlattenResult with flattened data and merge metadata\n */\nexport function flattenOverlays(results: HdfResults): FlattenResult {\n const { baselines } = results;\n const warnings: string[] = [];\n const merges: BaselineMerge[] = [];\n\n if (!baselines || baselines.length === 0) {\n return {\n results: { ...results, baselines: [] },\n metadata: {\n originalBaselineCount: 0,\n flattenedBaselineCount: 0,\n merges: [],\n warnings: [],\n },\n };\n }\n\n // Index baselines by name\n const byName = new Map<string, EvaluatedBaseline>();\n for (const b of baselines) {\n if (byName.has(b.name)) {\n warnings.push(`Duplicate baseline name \"${b.name}\" — later entry overwrites earlier`);\n }\n byName.set(b.name, b);\n }\n\n // Resolve parentBaseline aliases and build parent map\n const resolvedParent = new Map<string, string | undefined>();\n for (const b of baselines) {\n const parent = resolveParentBaseline(b, byName, baselines);\n resolvedParent.set(b.name, parent);\n if (b.parentBaseline && !parent) {\n warnings.push(\n `Baseline \"${b.name}\" references nonexistent parent \"${b.parentBaseline}\"`\n );\n }\n }\n\n // Build parent → children adjacency using resolved parents\n const childrenMap = new Map<string, string[]>();\n for (const b of baselines) {\n const parent = resolvedParent.get(b.name);\n if (parent) {\n const list = childrenMap.get(parent) || [];\n list.push(b.name);\n childrenMap.set(parent, list);\n }\n }\n\n // Find roots: no resolved parent\n const roots: string[] = [];\n const visited = new Set<string>();\n\n for (const b of baselines) {\n if (!resolvedParent.get(b.name)) {\n roots.push(b.name);\n }\n }\n\n // Mark reachable from roots (iterative DFS to avoid stack overflow on deep trees)\n function markReachable(start: string): void {\n const stack = [start];\n while (stack.length > 0) {\n const name = stack.pop()!;\n if (visited.has(name)) continue;\n visited.add(name);\n const children = childrenMap.get(name);\n if (children) {\n for (const child of children) {\n stack.push(child);\n }\n }\n }\n }\n for (const r of roots) {\n markReachable(r);\n }\n\n // Detect cycles: unvisited baselines are in cycles\n for (const b of baselines) {\n if (!visited.has(b.name)) {\n warnings.push(`Circular parentBaseline detected involving \"${b.name}\"`);\n roots.push(b.name);\n markReachable(b.name);\n }\n }\n\n // Process each root tree\n const flatBaselines: EvaluatedBaseline[] = [];\n\n for (const rootName of roots) {\n const root = byName.get(rootName)!;\n const treeNames = collectTree(rootName, childrenMap);\n\n if (treeNames.length === 1) {\n // Standalone baseline — pass through unchanged (preserve depends)\n flatBaselines.push(root);\n continue;\n }\n\n // Bottom-up order: reverse top-down BFS\n const bottomUp = [...treeNames].reverse();\n\n // Merge requirements across the tree\n const merged = new Map<string, EvaluatedRequirement>();\n let controlsBefore = 0;\n const absorbed: string[] = [];\n\n for (const name of bottomUp) {\n const b = byName.get(name)!;\n controlsBefore += b.requirements.length;\n if (name !== rootName) {\n absorbed.push(name);\n }\n for (const req of b.requirements) {\n if (merged.has(req.id)) {\n merged.set(req.id, mergeRequirement(merged.get(req.id)!, req));\n } else {\n merged.set(req.id, { ...req });\n }\n }\n }\n\n const mergedReqs = [...merged.values()];\n const pattern = detectPattern(rootName, childrenMap);\n\n merges.push({\n rootBaseline: rootName,\n absorbedBaselines: absorbed,\n controlsBefore,\n controlsAfter: mergedReqs.length,\n pattern,\n });\n\n const out: EvaluatedBaseline = {\n ...root,\n requirements: mergedReqs,\n };\n delete out.parentBaseline;\n delete out.depends;\n flatBaselines.push(out);\n }\n\n return {\n results: { ...results, baselines: flatBaselines },\n metadata: {\n originalBaselineCount: baselines.length,\n flattenedBaselineCount: flatBaselines.length,\n merges,\n warnings,\n },\n };\n}\n","import type { HdfResults, HdfBaseline } from '@mitre/hdf-schema';\nexport { flattenOverlays } from './flatten.js';\nexport type { FlattenResult, FlattenMetadata, BaselineMerge } from './flatten.js';\nimport { validateResults, validateBaseline, validate as autoValidate } from '@mitre/hdf-validators';\n\n/**\n * Result of parsing operation\n */\nexport interface ParseResult<T> {\n success: boolean;\n data?: T;\n error?: string;\n type?: 'results' | 'baseline';\n}\n\n/**\n * Parse HDF Results document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseResults(input: string | Uint8Array): ParseResult<HdfResults> {\n // Convert Uint8Array to string if needed\n const jsonStr = typeof input === 'string' ? input : new TextDecoder().decode(input);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Check for trailing garbage by re-serializing and comparing length\n // This catches cases like: {\"valid\":\"json\"}garbage\n const serialized = JSON.stringify(data);\n const trimmedInput = jsonStr.trim();\n if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) {\n return {\n success: false,\n error: 'Invalid JSON: unexpected trailing data after end of object'\n };\n }\n\n // Validate against schema\n const validationResult = validateResults(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HdfResults\n };\n}\n\n/**\n * Parse HDF Baseline document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseBaseline(input: string | Uint8Array): ParseResult<HdfBaseline> {\n // Convert Uint8Array to string if needed\n const jsonStr = typeof input === 'string' ? input : new TextDecoder().decode(input);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Check for trailing garbage\n const serialized = JSON.stringify(data);\n const trimmedInput = jsonStr.trim();\n if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) {\n return {\n success: false,\n error: 'Invalid JSON: unexpected trailing data after end of object'\n };\n }\n\n // Validate against schema\n const validationResult = validateBaseline(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HdfBaseline\n };\n}\n\n/**\n * Parse HDF document with auto-detection of type\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data, type indicator, or error\n */\nexport function parse(input: string | Uint8Array): ParseResult<HdfResults | HdfBaseline> {\n // Convert Uint8Array to string if needed\n const jsonStr = typeof input === 'string' ? input : new TextDecoder().decode(input);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Check for trailing garbage\n const serialized = JSON.stringify(data);\n const trimmedInput = jsonStr.trim();\n if (serialized.length !== trimmedInput.length && !isWhitespaceEquivalent(serialized, trimmedInput)) {\n return {\n success: false,\n error: 'Invalid JSON: unexpected trailing data after end of object'\n };\n }\n\n // Auto-validate and detect type\n const validationResult = autoValidate(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n // Determine type based on structure\n if (typeof data === 'object' && data !== null) {\n const obj = data as Record<string, unknown>;\n\n // HDF Results has 'baselines' array at root\n if ('baselines' in obj) {\n return {\n success: true,\n data: data as HdfResults,\n type: 'results'\n };\n }\n\n // HDF Baseline has 'name' and 'requirements' at root\n if ('name' in obj && 'requirements' in obj) {\n return {\n success: true,\n data: data as HdfBaseline,\n type: 'baseline'\n };\n }\n }\n\n return {\n success: false,\n error: 'Unable to determine HDF document type'\n };\n}\n\n/**\n * Check if two JSON strings are equivalent modulo whitespace\n * This is a simple heuristic - we check if one is just whitespace-padded version of other\n */\nfunction isWhitespaceEquivalent(a: string, b: string): boolean {\n // Remove all whitespace and compare\n const normalizeWhitespace = (s: string): string => s.replace(/\\s+/g, '');\n return normalizeWhitespace(a) === normalizeWhitespace(b);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["autoValidate"],"sources":["../typescript/flatten.ts","../typescript/index.ts"],"sourcesContent":["import type { HDFResults, EvaluatedBaseline, EvaluatedRequirement } from '@mitre/hdf-schema';\n\n// ── Public Types ────────────────────────────────────────────\n\nexport interface FlattenResult {\n results: HDFResults;\n metadata: FlattenMetadata;\n}\n\nexport interface FlattenMetadata {\n originalBaselineCount: number;\n flattenedBaselineCount: number;\n merges: BaselineMerge[];\n warnings: string[];\n}\n\nexport interface BaselineMerge {\n rootBaseline: string;\n absorbedBaselines: string[];\n controlsBefore: number;\n controlsAfter: number;\n pattern: 'deep' | 'wide' | 'hybrid';\n}\n\n// ── Internal Helpers ───────────────────────────────────────\n\n/** BFS from root, returns names in top-down order. Cycle-safe. */\nfunction collectTree(root: string, childrenMap: Map<string, string[]>): string[] {\n const order: string[] = [];\n const seen = new Set<string>();\n const queue = [root];\n while (queue.length > 0) {\n const name = queue.shift()!;\n if (seen.has(name)) continue;\n seen.add(name);\n order.push(name);\n for (const child of (childrenMap.get(name) || [])) {\n queue.push(child);\n }\n }\n return order;\n}\n\n/** Classify merge pattern based on tree shape */\nfunction detectPattern(root: string, childrenMap: Map<string, string[]>): 'deep' | 'wide' | 'hybrid' {\n const rootChildren = childrenMap.get(root) || [];\n if (rootChildren.length <= 1) {\n return 'deep';\n }\n for (const child of rootChildren) {\n if ((childrenMap.get(child) || []).length > 0) {\n return 'hybrid';\n }\n }\n return 'wide';\n}\n\n/** Merge incoming requirement fields onto existing */\nfunction mergeRequirement(\n existing: EvaluatedRequirement,\n incoming: EvaluatedRequirement\n): EvaluatedRequirement {\n const result: EvaluatedRequirement = { ...existing };\n\n // Impact: incoming always wins (required field, always present)\n result.impact = incoming.impact;\n\n // Results: keep whichever is non-empty (base has them, overlay doesn't)\n if (incoming.results && incoming.results.length > 0) {\n result.results = incoming.results;\n }\n\n // Code: incoming wins if non-empty\n if (incoming.code && incoming.code.trim() !== '') {\n result.code = incoming.code;\n }\n\n // Tags: shallow merge (incoming keys override)\n if (incoming.tags) {\n result.tags = { ...existing.tags, ...incoming.tags };\n }\n\n // Severity: incoming wins if present, else keep existing\n if (incoming.severity !== undefined) {\n result.severity = incoming.severity;\n }\n\n // EffectiveStatus: incoming wins only if it has results (otherwise its\n // effectiveStatus is a computed artifact from empty results, not intentional).\n // Overlays typically have empty results — the base has the real test results.\n if (incoming.effectiveStatus !== undefined && incoming.results && incoming.results.length > 0) {\n result.effectiveStatus = incoming.effectiveStatus;\n }\n\n // Descriptions: merge by label (incoming overrides same label)\n if (incoming.descriptions && incoming.descriptions.length > 0) {\n const descMap = new Map(\n (existing.descriptions || []).map(d => [d.label, d])\n );\n for (const d of incoming.descriptions) {\n descMap.set(d.label, d);\n }\n result.descriptions = [...descMap.values()];\n }\n\n return result;\n}\n\n/**\n * Resolve parentBaseline for a baseline.\n * InSpec parent_profile can use depends-name aliases (e.g., 'k8s' instead of\n * 'k8s-node-stig-baseline'). When the value isn't a direct profile name,\n * find who depends on this baseline — that's the actual parent.\n */\nfunction resolveParentBaseline(\n b: EvaluatedBaseline,\n byName: Map<string, EvaluatedBaseline>,\n allBaselines: EvaluatedBaseline[]\n): string | undefined {\n if (!b.parentBaseline) return undefined;\n if (byName.has(b.parentBaseline)) return b.parentBaseline;\n\n // Alias resolution: find the profile whose depends array includes this baseline\n for (const candidate of allBaselines) {\n if (candidate.depends?.some((d) => d.name === b.name)) {\n return candidate.name;\n }\n }\n return undefined; // orphan\n}\n\n// ── Public API ──────────────────────────────────────────────\n\n/**\n * Flatten overlay/wrapper baselines in an HDF Results document.\n *\n * Handles:\n * - Deep nesting (overlay chains with shared control IDs via parentBaseline)\n * - Wide nesting (wrapper profiles aggregating independent bases)\n * - Hybrid (both patterns in one document)\n *\n * @param results - Parsed HDF Results (from parseResults() or equivalent)\n * @returns FlattenResult with flattened data and merge metadata\n */\nexport function flattenOverlays(results: HDFResults): FlattenResult {\n const { baselines } = results;\n const warnings: string[] = [];\n const merges: BaselineMerge[] = [];\n\n if (!baselines || baselines.length === 0) {\n return {\n results: { ...results, baselines: [] },\n metadata: {\n originalBaselineCount: 0,\n flattenedBaselineCount: 0,\n merges: [],\n warnings: [],\n },\n };\n }\n\n // Index baselines by name\n const byName = new Map<string, EvaluatedBaseline>();\n for (const b of baselines) {\n if (byName.has(b.name)) {\n warnings.push(`Duplicate baseline name \"${b.name}\" — later entry overwrites earlier`);\n }\n byName.set(b.name, b);\n }\n\n // Resolve parentBaseline aliases and build parent map\n const resolvedParent = new Map<string, string | undefined>();\n for (const b of baselines) {\n const parent = resolveParentBaseline(b, byName, baselines);\n resolvedParent.set(b.name, parent);\n if (b.parentBaseline && !parent) {\n warnings.push(\n `Baseline \"${b.name}\" references nonexistent parent \"${b.parentBaseline}\"`\n );\n }\n }\n\n // Build parent → children adjacency using resolved parents\n const childrenMap = new Map<string, string[]>();\n for (const b of baselines) {\n const parent = resolvedParent.get(b.name);\n if (parent) {\n const list = childrenMap.get(parent) || [];\n list.push(b.name);\n childrenMap.set(parent, list);\n }\n }\n\n // Find roots: no resolved parent\n const roots: string[] = [];\n const visited = new Set<string>();\n\n for (const b of baselines) {\n if (!resolvedParent.get(b.name)) {\n roots.push(b.name);\n }\n }\n\n // Mark reachable from roots (iterative DFS to avoid stack overflow on deep trees)\n function markReachable(start: string): void {\n const stack = [start];\n while (stack.length > 0) {\n const name = stack.pop()!;\n if (visited.has(name)) continue;\n visited.add(name);\n const children = childrenMap.get(name);\n if (children) {\n for (const child of children) {\n stack.push(child);\n }\n }\n }\n }\n for (const r of roots) {\n markReachable(r);\n }\n\n // Detect cycles: unvisited baselines are in cycles\n for (const b of baselines) {\n if (!visited.has(b.name)) {\n warnings.push(`Circular parentBaseline detected involving \"${b.name}\"`);\n roots.push(b.name);\n markReachable(b.name);\n }\n }\n\n // Process each root tree\n const flatBaselines: EvaluatedBaseline[] = [];\n\n for (const rootName of roots) {\n const root = byName.get(rootName)!;\n const treeNames = collectTree(rootName, childrenMap);\n\n if (treeNames.length === 1) {\n // Standalone baseline — pass through unchanged (preserve depends)\n flatBaselines.push(root);\n continue;\n }\n\n // Bottom-up order: reverse top-down BFS\n const bottomUp = [...treeNames].reverse();\n\n // Merge requirements across the tree\n const merged = new Map<string, EvaluatedRequirement>();\n let controlsBefore = 0;\n const absorbed: string[] = [];\n\n for (const name of bottomUp) {\n const b = byName.get(name)!;\n controlsBefore += b.requirements.length;\n if (name !== rootName) {\n absorbed.push(name);\n }\n for (const req of b.requirements) {\n if (merged.has(req.id)) {\n merged.set(req.id, mergeRequirement(merged.get(req.id)!, req));\n } else {\n merged.set(req.id, { ...req });\n }\n }\n }\n\n const mergedReqs = [...merged.values()];\n const pattern = detectPattern(rootName, childrenMap);\n\n merges.push({\n rootBaseline: rootName,\n absorbedBaselines: absorbed,\n controlsBefore,\n controlsAfter: mergedReqs.length,\n pattern,\n });\n\n const out: EvaluatedBaseline = {\n ...root,\n requirements: mergedReqs,\n };\n delete out.parentBaseline;\n delete out.depends;\n flatBaselines.push(out);\n }\n\n return {\n results: { ...results, baselines: flatBaselines },\n metadata: {\n originalBaselineCount: baselines.length,\n flattenedBaselineCount: flatBaselines.length,\n merges,\n warnings,\n },\n };\n}\n","import type {\n HDFResults,\n HDFBaseline,\n HDFSystem,\n HDFPlan,\n HDFEvidencePackage,\n HDFComparison,\n} from '@mitre/hdf-schema';\nexport { flattenOverlays } from './flatten.js';\nexport type { FlattenResult, FlattenMetadata, BaselineMerge } from './flatten.js';\nimport {\n validateResults,\n validateBaseline,\n validateSystem,\n validatePlan,\n validateEvidencePackage,\n validateComparison,\n validate as autoValidate,\n} from '@mitre/hdf-validators';\n\n// JSON-quoted ISO 8601 timestamp with no trailing timezone — InSpec emits\n// these (e.g. \"2026-03-25T22:56:27.736808\"). ajv-formats requires RFC 3339\n// for `date-time` and rejects them.\nconst NO_TZ_TIMESTAMP_REGEX = /\"(\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)\"/g;\n\n/**\n * Append Z (treat as UTC) to bare ISO timestamps in a JSON string so they\n * pass schema validation. Exported so other workspace packages can use the\n * same regex instead of re-implementing it. Matches the Go side at\n * hdf-parsers/go/parsers.go.\n */\nexport function normalizeTimestamps(input: string): string {\n return input.replace(NO_TZ_TIMESTAMP_REGEX, '\"$1Z\"');\n}\n\n/**\n * Result of parsing operation\n */\nexport interface ParseResult<T> {\n success: boolean;\n data?: T;\n error?: string;\n type?: 'results' | 'baseline' | 'system' | 'plan' | 'evidencePackage' | 'comparison';\n}\n\n/**\n * Parse HDF Results document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseResults(input: string | Uint8Array): ParseResult<HDFResults> {\n // Convert Uint8Array to string if needed\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // JSON.parse already rejects trailing garbage (it throws on the first\n // non-whitespace byte after the root value), so the catch above covers\n // that case. A prior length-compare heuristic here false-positived on\n // complex real-world inputs (e.g. `0.70` parsed as `0.7` would re-\n // serialize to a different length) — caught by the cross-language\n // parser parity test in typescript/parse-equivalence.test.ts.\n\n // Validate against schema\n const validationResult = validateResults(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HDFResults\n };\n}\n\n/**\n * Parse HDF Baseline document from string or bytes\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data or error\n */\nexport function parseBaseline(input: string | Uint8Array): ParseResult<HDFBaseline> {\n // Convert Uint8Array to string if needed\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Trailing garbage already caught by the JSON.parse catch above; see\n // parseResults for the full rationale.\n\n // Validate against schema\n const validationResult = validateBaseline(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n return {\n success: true,\n data: data as HDFBaseline\n };\n}\n\n/**\n * Parse HDF System document from string or bytes\n */\nexport function parseSystem(input: string | Uint8Array): ParseResult<HDFSystem> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validateSystem(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFSystem };\n}\n\n/**\n * Parse HDF Plan document from string or bytes\n */\nexport function parsePlan(input: string | Uint8Array): ParseResult<HDFPlan> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validatePlan(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFPlan };\n}\n\n/**\n * Parse HDF Evidence Package document from string or bytes\n */\nexport function parseEvidencePackage(input: string | Uint8Array): ParseResult<HDFEvidencePackage> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validateEvidencePackage(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFEvidencePackage };\n}\n\n/**\n * Parse HDF Comparison document from string or bytes\n */\nexport function parseComparison(input: string | Uint8Array): ParseResult<HDFComparison> {\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n if (jsonStr.trim().length === 0) {\n return { success: false, error: 'Input is empty' };\n }\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return { success: false, error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}` };\n }\n const validationResult = validateComparison(data);\n if (!validationResult.valid) {\n return { success: false, error: `Schema validation failed: ${validationResult.getErrorMessage()}` };\n }\n return { success: true, data: data as HDFComparison };\n}\n\n/**\n * Parse HDF document with auto-detection of type\n * @param input - JSON string or Uint8Array to parse\n * @returns ParseResult with parsed data, type indicator, or error\n */\nexport function parse(\n input: string | Uint8Array,\n): ParseResult<HDFResults | HDFBaseline | HDFSystem | HDFPlan | HDFEvidencePackage | HDFComparison> {\n // Convert Uint8Array to string if needed\n const decoded = typeof input === 'string' ? input : new TextDecoder().decode(input);\n const jsonStr = normalizeTimestamps(decoded);\n\n // Check for empty input\n if (jsonStr.trim().length === 0) {\n return {\n success: false,\n error: 'Input is empty'\n };\n }\n\n // Parse JSON\n let data: unknown;\n try {\n data = JSON.parse(jsonStr);\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON: ${err instanceof Error ? err.message : String(err)}`\n };\n }\n\n // Trailing garbage already caught by the JSON.parse catch above; see\n // parseResults for the full rationale.\n\n // Auto-validate and detect type\n const validationResult = autoValidate(data);\n if (!validationResult.valid) {\n return {\n success: false,\n error: `Schema validation failed: ${validationResult.getErrorMessage()}`\n };\n }\n\n // Determine type based on structure\n if (typeof data === 'object' && data !== null) {\n const obj = data as Record<string, unknown>;\n\n // HDF Results has 'baselines' array at root\n if ('baselines' in obj) {\n return {\n success: true,\n data: data as HDFResults,\n type: 'results'\n };\n }\n\n // HDF Comparison has 'requirementDiffs' at root (unique discriminator)\n if ('requirementDiffs' in obj) {\n return { success: true, data: data as HDFComparison, type: 'comparison' };\n }\n\n // HDF Plan has 'assessments' at root\n if ('assessments' in obj) {\n return { success: true, data: data as HDFPlan, type: 'plan' };\n }\n\n // HDF Evidence Package has 'contents' at root\n if ('contents' in obj) {\n return { success: true, data: data as HDFEvidencePackage, type: 'evidencePackage' };\n }\n\n // HDF Baseline has 'name' and 'requirements' at root\n if ('name' in obj && 'requirements' in obj) {\n return {\n success: true,\n data: data as HDFBaseline,\n type: 'baseline'\n };\n }\n\n // HDF System has 'components' at root (Results' baselines check already ruled out)\n if ('components' in obj) {\n return { success: true, data: data as HDFSystem, type: 'system' };\n }\n }\n\n return {\n success: false,\n error: 'Unable to determine HDF document type'\n };\n}\n\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mitre/hdf-parsers",
3
- "version": "3.1.0",
3
+ "version": "3.3.0",
4
4
  "description": "Parse and load HDF documents with validation",
5
5
  "publishConfig": {
6
6
  "access": "public"
@@ -25,8 +25,8 @@
25
25
  "author": "MITRE Corporation",
26
26
  "license": "Apache-2.0",
27
27
  "dependencies": {
28
- "@mitre/hdf-validators": "^3.1.0",
29
- "@mitre/hdf-schema": "^3.1.0"
28
+ "@mitre/hdf-schema": "^3.3.0",
29
+ "@mitre/hdf-validators": "^3.3.0"
30
30
  },
31
31
  "engines": {
32
32
  "node": ">=22.0.0"
@@ -39,7 +39,8 @@
39
39
  ],
40
40
  "devDependencies": {
41
41
  "@stryker-mutator/core": "^9.5.1",
42
- "@stryker-mutator/vitest-runner": "^9.5.1"
42
+ "@stryker-mutator/vitest-runner": "^9.5.1",
43
+ "@mitre/hdf-fixtures": "^3.3.0"
43
44
  },
44
45
  "scripts": {
45
46
  "build": "tsdown",