@mitre/hdf-generators 3.7.2-rc.2 → 3.8.0-next.42532249979.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.
- package/dist/index.d.ts +3 -21
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +7 -14
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { BaselineRequirement, Description, HDFBaseline, Reference } from "@mitre/hdf-schema";
|
|
2
|
-
//#region src/types.d.ts
|
|
3
2
|
/**
|
|
4
3
|
* Options for controlling InSpec profile generation.
|
|
5
4
|
*/
|
|
@@ -29,8 +28,6 @@ interface InSpecProfile {
|
|
|
29
28
|
/** Map of filename (e.g. 'controls/SV-238196.rb') to Ruby source code. */
|
|
30
29
|
controls: Map<string, string>;
|
|
31
30
|
}
|
|
32
|
-
//#endregion
|
|
33
|
-
//#region src/merge.d.ts
|
|
34
31
|
type PreferSide = 'current' | 'upstream' | undefined;
|
|
35
32
|
/**
|
|
36
33
|
* Smart-merge a current and upstream requirement.
|
|
@@ -54,9 +51,9 @@ export declare function mergeRequirement(current: BaselineRequirement, upstream:
|
|
|
54
51
|
* prefer "current": union; current wins on key conflicts.
|
|
55
52
|
* prefer "upstream": upstream replaces all.
|
|
56
53
|
*/
|
|
57
|
-
export declare function mergeTags(current: Record<string, any
|
|
58
|
-
|
|
59
|
-
|
|
54
|
+
export declare function mergeTags(current: Record<string, any>, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
55
|
+
upstream: Record<string, any>, // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
56
|
+
prefer?: PreferSide): Record<string, any>;
|
|
60
57
|
/**
|
|
61
58
|
* Merge two description arrays by label.
|
|
62
59
|
*
|
|
@@ -73,8 +70,6 @@ export declare function mergeDescriptions(current: Description[], upstream: Desc
|
|
|
73
70
|
* prefer "upstream": upstream only.
|
|
74
71
|
*/
|
|
75
72
|
export declare function mergeRefs(current?: Reference[], upstream?: Reference[], prefer?: PreferSide): Reference[] | undefined;
|
|
76
|
-
//#endregion
|
|
77
|
-
//#region src/delta-types.d.ts
|
|
78
73
|
/**
|
|
79
74
|
* A structured record linking an old requirement to a new one.
|
|
80
75
|
*/
|
|
@@ -147,8 +142,6 @@ interface UpgradeOptions {
|
|
|
147
142
|
}
|
|
148
143
|
/** Backward-compatible alias. */
|
|
149
144
|
type DeltaOptions = UpgradeOptions;
|
|
150
|
-
//#endregion
|
|
151
|
-
//#region src/ruby-escape.d.ts
|
|
152
145
|
/**
|
|
153
146
|
* Escape a string for use as a Ruby string literal.
|
|
154
147
|
*
|
|
@@ -161,8 +154,6 @@ type DeltaOptions = UpgradeOptions;
|
|
|
161
154
|
* inspec-parser's RubyRebuilder.
|
|
162
155
|
*/
|
|
163
156
|
export declare function escapeQuotes(s: string): string;
|
|
164
|
-
//#endregion
|
|
165
|
-
//#region src/control-stub.d.ts
|
|
166
157
|
/**
|
|
167
158
|
* Generate a Ruby InSpec control stub from an HDF BaselineRequirement.
|
|
168
159
|
*
|
|
@@ -177,8 +168,6 @@ export declare function escapeQuotes(s: string): string;
|
|
|
177
168
|
* end
|
|
178
169
|
*/
|
|
179
170
|
export declare function generateControlStub(req: BaselineRequirement): string;
|
|
180
|
-
//#endregion
|
|
181
|
-
//#region src/inspec-yml.d.ts
|
|
182
171
|
/**
|
|
183
172
|
* Generate an inspec.yml YAML string from an HDF Baseline and options.
|
|
184
173
|
*
|
|
@@ -186,8 +175,6 @@ export declare function generateControlStub(req: BaselineRequirement): string;
|
|
|
186
175
|
* is fixed and shallow.
|
|
187
176
|
*/
|
|
188
177
|
export declare function generateInSpecYml(baseline: HDFBaseline, options?: GeneratorOptions): string;
|
|
189
|
-
//#endregion
|
|
190
|
-
//#region src/profile-generator.d.ts
|
|
191
178
|
/**
|
|
192
179
|
* Generate an in-memory InSpec profile from an HDF Baseline.
|
|
193
180
|
*
|
|
@@ -196,8 +183,6 @@ export declare function generateInSpecYml(baseline: HDFBaseline, options?: Gener
|
|
|
196
183
|
* is responsible for writing files to disk.
|
|
197
184
|
*/
|
|
198
185
|
export declare function generateInSpecProfile(baseline: HDFBaseline, options?: GeneratorOptions): InSpecProfile;
|
|
199
|
-
//#endregion
|
|
200
|
-
//#region src/delta.d.ts
|
|
201
186
|
/**
|
|
202
187
|
* Generate an upgraded HDF Baseline by smart-merging current and upstream requirements.
|
|
203
188
|
*
|
|
@@ -216,8 +201,6 @@ export declare function generateUpgrade(currentBaseline: HDFBaseline, upstreamBa
|
|
|
216
201
|
* @deprecated Use generateUpgrade instead.
|
|
217
202
|
*/
|
|
218
203
|
export declare function generateDelta(newBaseline: HDFBaseline, linkRecords: LinkRecord[], oldCodeMap: Map<string, string>, opts?: DeltaOptions, oldControlCount?: number): DeltaResult;
|
|
219
|
-
//#endregion
|
|
220
|
-
//#region src/delta-report.d.ts
|
|
221
204
|
/**
|
|
222
205
|
* JSON report payload for delta operations.
|
|
223
206
|
* SAF CLI-compatible: { links: LinkRecord[] }
|
|
@@ -236,6 +219,5 @@ export declare function generateDeltaJson(result: DeltaResult): DeltaJsonReport;
|
|
|
236
219
|
* match statistics, and statistics validation.
|
|
237
220
|
*/
|
|
238
221
|
export declare function generateDeltaMarkdown(result: DeltaResult): string;
|
|
239
|
-
//#endregion
|
|
240
222
|
export type { DeltaJsonReport, DeltaOptions, DeltaResult, DeltaStatistics, GeneratorOptions, InSpecProfile, LinkRecord, PreferSide, ProfileMetadata, UpgradeOptions, UpgradeResult };
|
|
241
223
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/merge.ts","../src/delta-types.ts","../src/ruby-escape.ts","../src/control-stub.ts","../src/inspec-yml.ts","../src/profile-generator.ts","../src/delta.ts","../src/delta-report.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/merge.ts","../src/delta-types.ts","../src/ruby-escape.ts","../src/control-stub.ts","../src/inspec-yml.ts","../src/profile-generator.ts","../src/delta.ts","../src/delta-report.ts"],"mappings":";;;;UAGiB;;EAEf;;EAEA,WAAW;;EAEX;;;;;UAMe;EACf;EACA;EACA;EACA;;;;;UAMe;;EAEf;;EAEA,UAAU;;KC3BA;;;;;;;;;;;;;;;wBAgBI,iBACd,SAAS,qBACT,UAAU,qBACV,SAAS,aACR;;;;;;;;wBAwCa,UACd,SAAS;EACT,UAAU;EACV,SAAS,aACR;;;;;;;;wBA4Ba,kBACd,SAAS,eACT,UAAU,eACV,SAAS,aACR;;;;;;;;wBAqCa,UACd,UAAU,aACV,WAAW,aACX,SAAS,aACR;;;;UCpIc;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;;;;;;;;;;;;;UAgBe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;;;UAMe;EACf,UAAU;EACV,UAAU;EACV,aAAa;EACb,YAAY;;;KAIF,cAAc;;;;UAKT;;EAEf,SAAS;;EAET;;EAEA;;EAEA;;EAEA,WAAW;;EAEX;;;;;;;;EAQA;;;KAIU,eAAe;;;;;;;;;;;;wBCrEX,aAAa;;;;;;;;;;;;;;wBCWb,oBAAoB,KAAK;;;;;;;wBCbzB,kBACd,UAAU,aACV,UAAU;;;;;;;;wBCCI,sBACd,UAAU,aACV,UAAU,mBACT;;;;;;;;;;;;wBCGa,gBACd,iBAAiB,aACjB,kBAAkB,aAClB,aAAa,cACb,OAAO,iBACN;;;;;;wBAmFa,cACd,aAAa,aACb,aAAa,cACb,YAAY,qBACZ,OAAO,cACP,2BACC;;;;;UC1Gc;EACf,OAAO;;;;;;wBAOO,kBAAkB,QAAQ,cAAc;;;;;;wBAoCxC,sBAAsB,QAAQ"}
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
// src/ruby-escape.ts
|
|
2
2
|
/**
|
|
3
3
|
* Escape a string for use as a Ruby string literal.
|
|
4
4
|
*
|
|
@@ -17,8 +17,7 @@ function escapeQuotes(s) {
|
|
|
17
17
|
if (hasSingle) return `"${s.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")}"`;
|
|
18
18
|
return `'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
|
|
19
19
|
}
|
|
20
|
-
|
|
21
|
-
//#region src/control-stub.ts
|
|
20
|
+
// src/control-stub.ts
|
|
22
21
|
/**
|
|
23
22
|
* Detects when a code string already starts with `control 'ID' do`,
|
|
24
23
|
* meaning it's a complete InSpec control file — not a body fragment.
|
|
@@ -85,8 +84,7 @@ function formatTag(key, value) {
|
|
|
85
84
|
if (typeof value === "string") return `tag ${key}: ${escapeQuotes(value)}`;
|
|
86
85
|
return `tag ${key}: ${JSON.stringify(value)}`;
|
|
87
86
|
}
|
|
88
|
-
|
|
89
|
-
//#region src/inspec-yml.ts
|
|
87
|
+
// src/inspec-yml.ts
|
|
90
88
|
/**
|
|
91
89
|
* Generate an inspec.yml YAML string from an HDF Baseline and options.
|
|
92
90
|
*
|
|
@@ -154,8 +152,7 @@ function formatYamlValue(value) {
|
|
|
154
152
|
if (typeof value === "string") return value;
|
|
155
153
|
return JSON.stringify(value);
|
|
156
154
|
}
|
|
157
|
-
|
|
158
|
-
//#region src/profile-generator.ts
|
|
155
|
+
// src/profile-generator.ts
|
|
159
156
|
/**
|
|
160
157
|
* Generate an in-memory InSpec profile from an HDF Baseline.
|
|
161
158
|
*
|
|
@@ -182,8 +179,7 @@ function generateInSpecProfile(baseline, options) {
|
|
|
182
179
|
controls
|
|
183
180
|
};
|
|
184
181
|
}
|
|
185
|
-
|
|
186
|
-
//#region src/merge.ts
|
|
182
|
+
// src/merge.ts
|
|
187
183
|
/**
|
|
188
184
|
* Smart-merge a current and upstream requirement.
|
|
189
185
|
*
|
|
@@ -278,8 +274,7 @@ function mergeRefs(current, upstream, prefer) {
|
|
|
278
274
|
if (upstream) upstream.forEach(addRef);
|
|
279
275
|
return result.length > 0 ? result : void 0;
|
|
280
276
|
}
|
|
281
|
-
|
|
282
|
-
//#region src/delta.ts
|
|
277
|
+
// src/delta.ts
|
|
283
278
|
/**
|
|
284
279
|
* Generate an upgraded HDF Baseline by smart-merging current and upstream requirements.
|
|
285
280
|
*
|
|
@@ -407,8 +402,7 @@ function computeStatistics(linkRecords, oldControlCount, newControlCount) {
|
|
|
407
402
|
noMatch
|
|
408
403
|
};
|
|
409
404
|
}
|
|
410
|
-
|
|
411
|
-
//#region src/delta-report.ts
|
|
405
|
+
// src/delta-report.ts
|
|
412
406
|
/**
|
|
413
407
|
* Generate a structured JSON report from a delta result.
|
|
414
408
|
* Matches SAF CLI's delta.json format: { ...diff, links }.
|
|
@@ -475,7 +469,6 @@ function generateDeltaMarkdown(result) {
|
|
|
475
469
|
}
|
|
476
470
|
return lines.join("\n");
|
|
477
471
|
}
|
|
478
|
-
//#endregion
|
|
479
472
|
export { escapeQuotes, generateControlStub, generateDelta, generateDeltaJson, generateDeltaMarkdown, generateInSpecProfile, generateInSpecYml, generateUpgrade, mergeDescriptions, mergeRefs, mergeRequirement, mergeTags };
|
|
480
473
|
|
|
481
474
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/ruby-escape.ts","../src/control-stub.ts","../src/inspec-yml.ts","../src/profile-generator.ts","../src/merge.ts","../src/delta.ts","../src/delta-report.ts"],"sourcesContent":["/**\n * Escape a string for use as a Ruby string literal.\n *\n * Strategy:\n * - If the string contains both single and double quotes → %q() wrapper\n * - If the string contains only single quotes → double-quoted with escaping\n * - Otherwise → single-quoted with escaping\n *\n * Ported from ts-inspec-objects escapeQuotes(), cross-referenced with\n * inspec-parser's RubyRebuilder.\n */\nexport function escapeQuotes(s: string): string {\n const hasSingle = s.includes(\"'\");\n const hasDouble = s.includes('\"');\n\n if (hasSingle && hasDouble) {\n // %q() — escape backslashes before ) so Ruby doesn't treat \\) as escaped delimiter\n return `%q(${s.replace(/\\\\\\)/g, '\\\\\\\\)')})`;\n }\n\n if (hasSingle) {\n // Double-quoted: escape backslashes, then double quotes\n return `\"${s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n }\n\n // Single-quoted: escape backslashes, then single quotes\n return `'${s.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")}'`;\n}\n","import type { BaselineRequirement } from '@mitre/hdf-schema';\nimport { escapeQuotes } from './ruby-escape.js';\n\n/**\n * Detects when a code string already starts with `control 'ID' do`,\n * meaning it's a complete InSpec control file — not a body fragment.\n */\nconst FULL_CONTROL_BLOCK = /^\\s*control\\s+['\"]([^'\"]+)['\"]\\s+do\\b/;\n\n/**\n * Generate a Ruby InSpec control stub from an HDF BaselineRequirement.\n *\n * Output follows the InSpec DSL ordering convention:\n * control 'ID' do\n * title ...\n * desc ...\n * desc 'check', ...\n * impact ...\n * tag key: value\n * <code or stub comment>\n * end\n */\nexport function generateControlStub(req: BaselineRequirement): string {\n // If code is already a complete `control 'ID' do ... end` block (e.g.\n // from `-c controls/` reading whole .rb files), emit it as-is — wrapping\n // it again would produce nested control blocks, which InSpec rejects.\n // When the inner ID differs from req.id (e.g. an upgrade rename match\n // where current's code was carried into a renamed requirement), rewrite\n // the wrapper to match req.id so the file remains valid InSpec.\n if (req.code) {\n const m = FULL_CONTROL_BLOCK.exec(req.code);\n if (m && m[1] !== undefined) {\n const innerID = m[1];\n if (innerID === req.id) {\n return req.code;\n }\n const start = m.index + m[0].indexOf(innerID);\n return req.code.slice(0, start) + req.id + req.code.slice(start + innerID.length);\n }\n }\n\n const lines: string[] = [];\n\n lines.push(`control '${req.id}' do`);\n\n // Title\n if (req.title) {\n lines.push(` title ${escapeQuotes(req.title)}`);\n }\n\n // Descriptions: default first (as bare `desc`), then labeled\n const defaultDesc = req.descriptions.find((d) => d.label === 'default');\n if (defaultDesc) {\n lines.push(` desc ${escapeQuotes(defaultDesc.data)}`);\n }\n\n const seenDefault = new Set<string>();\n for (const d of req.descriptions) {\n if (d.label === 'default') {\n if (seenDefault.has('default')) {\n continue; // skip duplicate default\n }\n seenDefault.add('default');\n continue; // already emitted above as bare desc\n }\n lines.push(` desc '${d.label}', ${escapeQuotes(d.data)}`);\n }\n\n // Impact — always render with at least one decimal place for 0 and whole numbers\n // RAW impact by design: a generated control declares the impact the profile\n // asserts, not the impact an assessment later resolved it to.\n if (req.impact !== undefined) {\n const impactStr = Number.isInteger(req.impact)\n ? req.impact.toFixed(1)\n : String(req.impact);\n lines.push(` impact ${impactStr}`);\n }\n\n // Tags\n for (const [key, value] of Object.entries(req.tags)) {\n lines.push(` ${formatTag(key, value)}`);\n }\n\n // Code body or stub placeholder\n if (req.code) {\n lines.push('');\n lines.push(req.code);\n } else {\n lines.push('');\n lines.push(' # TODO: Add InSpec test code here');\n }\n\n lines.push('end');\n lines.push(''); // trailing newline\n\n return lines.join('\\n');\n}\n\n/** Format a single tag key-value pair as Ruby DSL. */\nfunction formatTag(key: string, value: unknown): string {\n if (value === null || value === undefined) {\n return `tag ${key}: nil`;\n }\n\n if (Array.isArray(value)) {\n // Ruby array syntax: tag key: ['val1', 'val2']\n const items = value.map((v: unknown) => `'${String(v)}'`).join(', ');\n return `tag ${key}: [${items}]`;\n }\n\n if (typeof value === 'boolean') {\n return `tag ${key}: ${value}`;\n }\n\n if (typeof value === 'string') {\n return `tag ${key}: ${escapeQuotes(value)}`;\n }\n\n // Fallback for other types (numbers, objects)\n return `tag ${key}: ${JSON.stringify(value)}`;\n}\n","import type { HDFBaseline } from '@mitre/hdf-schema';\nimport type { GeneratorOptions } from './types.js';\n\n/**\n * Generate an inspec.yml YAML string from an HDF Baseline and options.\n *\n * Uses string interpolation — no YAML library needed since the structure\n * is fixed and shallow.\n */\nexport function generateInSpecYml(\n baseline: HDFBaseline,\n options?: GeneratorOptions,\n): string {\n const lines: string[] = [];\n const meta = options?.metadata;\n\n // Required: name\n lines.push(`name: ${baseline.name}`);\n\n // Optional metadata fields\n if (baseline.title) {\n lines.push(`title: ${baseline.title}`);\n }\n\n const maintainer = meta?.maintainer ?? baseline.maintainer;\n if (maintainer) {\n lines.push(`maintainer: ${maintainer}`);\n }\n\n const copyright = meta?.copyright ?? baseline.copyright;\n if (copyright) {\n lines.push(`copyright: ${copyright}`);\n }\n\n const license = meta?.license ?? baseline.license;\n if (license) {\n lines.push(`license: ${license}`);\n }\n\n if (baseline.summary) {\n lines.push(`summary: ${baseline.summary}`);\n }\n\n // Version: metadata override takes priority\n const version = meta?.version ?? baseline.version;\n if (version) {\n lines.push(`version: '${version}'`);\n }\n\n // InSpec version constraint\n const inspecVersion = options?.inspecVersion ?? '~>6.0';\n lines.push(`inspec_version: '${inspecVersion}'`);\n\n // Supports array\n if (baseline.supports && baseline.supports.length > 0) {\n lines.push('supports:');\n for (const support of baseline.supports) {\n const entries: string[] = [];\n if (support.platformName) {\n entries.push(` platform-name: ${support.platformName}`);\n }\n if (support.platformFamily) {\n entries.push(` platform-family: ${support.platformFamily}`);\n }\n if (support.platform) {\n entries.push(` platform: ${support.platform}`);\n }\n if (support.release) {\n entries.push(` release: ${support.release}`);\n }\n if (entries.length > 0) {\n lines.push(`- ${entries[0]!.trimStart()}`);\n for (let i = 1; i < entries.length; i++) {\n lines.push(entries[i]!);\n }\n }\n }\n }\n\n // Depends array\n if (baseline.depends && baseline.depends.length > 0) {\n lines.push('depends:');\n for (const dep of baseline.depends) {\n const entries: string[] = [];\n if (dep.name) entries.push(`name: ${dep.name}`);\n if (dep.git) entries.push(`git: ${dep.git}`);\n if (dep.url) entries.push(`url: ${dep.url}`);\n if (dep.path) entries.push(`path: ${dep.path}`);\n if (dep.branch) entries.push(`branch: ${dep.branch}`);\n if (dep.compliance) entries.push(`compliance: ${dep.compliance}`);\n if (dep.supermarket) entries.push(`supermarket: ${dep.supermarket}`);\n if (entries.length > 0) {\n lines.push(`- ${entries[0]}`);\n for (let i = 1; i < entries.length; i++) {\n lines.push(` ${entries[i]}`);\n }\n }\n }\n }\n\n // Inputs array\n if (baseline.inputs && baseline.inputs.length > 0) {\n lines.push('inputs:');\n for (const input of baseline.inputs) {\n for (const [key, value] of Object.entries(input)) {\n lines.push(`- ${key}: ${formatYamlValue(value)}`);\n }\n }\n }\n\n lines.push(''); // trailing newline\n return lines.join('\\n');\n}\n\n/** Format a value for inline YAML output. */\nfunction formatYamlValue(value: unknown): string {\n if (typeof value === 'boolean') return String(value);\n if (typeof value === 'number') return String(value);\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n","import type { BaselineRequirement, HDFBaseline } from '@mitre/hdf-schema';\nimport type { GeneratorOptions, InSpecProfile } from './types.js';\nimport { generateControlStub } from './control-stub.js';\nimport { generateInSpecYml } from './inspec-yml.js';\n\n/**\n * Generate an in-memory InSpec profile from an HDF Baseline.\n *\n * Returns an InSpecProfile with inspec.yml content and a Map of\n * control filenames to Ruby source code. No file I/O — the CLI\n * is responsible for writing files to disk.\n */\nexport function generateInSpecProfile(\n baseline: HDFBaseline,\n options?: GeneratorOptions,\n): InSpecProfile {\n const inspecYml = generateInSpecYml(baseline, options);\n const controls = new Map<string, string>();\n\n if (baseline.requirements.length === 0) {\n return { inspecYml, controls };\n }\n\n if (options?.singleFile) {\n // All controls in a single file\n const stubs = baseline.requirements.map((req: BaselineRequirement) => generateControlStub(req));\n controls.set('controls/controls.rb', stubs.join('\\n'));\n } else {\n // One file per control — sanitize ID for safe filenames\n for (const req of baseline.requirements) {\n const safeId = req.id.replace(/\\.\\./g, '').replace(/[/\\\\]/g, '') || 'unknown';\n const filename = `controls/${safeId}.rb`;\n controls.set(filename, generateControlStub(req));\n }\n }\n\n return { inspecYml, controls };\n}\n","import type { BaselineRequirement, Description, Reference } from '@mitre/hdf-schema';\n\nexport type PreferSide = 'current' | 'upstream' | undefined;\n\n/**\n * Smart-merge a current and upstream requirement.\n *\n * Default (no prefer):\n * - ID: always upstream\n * - Scalars (title, impact, severity): upstream wins\n * - Tags: union, upstream wins key conflicts\n * - Descriptions: union by label, upstream wins on same label\n * - Code: current (preserve tests)\n * - Refs: union (deduplicated)\n *\n * prefer \"current\": scalars from current, current wins tag/desc conflicts\n * prefer \"upstream\": everything from upstream (full replacement)\n */\nexport function mergeRequirement(\n current: BaselineRequirement,\n upstream: BaselineRequirement,\n prefer?: PreferSide,\n): BaselineRequirement {\n const merged: BaselineRequirement = {\n // ID always comes from upstream\n id: upstream.id,\n\n // Scalars\n title: prefer === 'current' ? current.title : upstream.title,\n impact: prefer === 'current' ? current.impact : upstream.impact,\n severity: prefer === 'current' ? current.severity : upstream.severity,\n\n // Collections\n tags: mergeTags(current.tags, upstream.tags, prefer),\n descriptions: mergeDescriptions(current.descriptions, upstream.descriptions, prefer),\n refs: mergeRefs(current.refs, upstream.refs, prefer),\n\n // Code: current by default, upstream only with --prefer upstream\n code: prefer === 'upstream'\n ? upstream.code\n : (current.code ?? upstream.code),\n\n // SourceLocation follows scalars\n sourceLocation: prefer === 'current' ? current.sourceLocation : upstream.sourceLocation,\n };\n\n // Clean up undefined optional fields\n if (merged.code === undefined) delete merged.code;\n if (merged.severity === undefined) delete merged.severity;\n if (merged.sourceLocation === undefined) delete merged.sourceLocation;\n if (merged.refs === undefined || merged.refs.length === 0) delete merged.refs;\n\n return merged;\n}\n\n/**\n * Merge two tag maps.\n *\n * Default: union of keys; upstream wins on key conflicts.\n * prefer \"current\": union; current wins on key conflicts.\n * prefer \"upstream\": upstream replaces all.\n */\nexport function mergeTags(\n current: Record<string, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n upstream: Record<string, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n prefer?: PreferSide,\n): Record<string, any> { // eslint-disable-line @typescript-eslint/no-explicit-any\n if (prefer === 'upstream') {\n return { ...upstream };\n }\n\n const merged: Record<string, any> = { ...current }; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n for (const [key, value] of Object.entries(upstream)) {\n if (prefer === 'current') {\n if (!(key in merged)) {\n merged[key] = value;\n }\n } else {\n // Default: upstream wins on conflict\n merged[key] = value;\n }\n }\n\n return merged;\n}\n\n/**\n * Merge two description arrays by label.\n *\n * Default: union by label; upstream wins on label conflicts.\n * prefer \"current\": union; current wins on label conflicts.\n * prefer \"upstream\": upstream replaces all.\n */\nexport function mergeDescriptions(\n current: Description[],\n upstream: Description[],\n prefer?: PreferSide,\n): Description[] {\n if (prefer === 'upstream') {\n return [...upstream];\n }\n\n const byLabel = new Map<string, Description>();\n const order: string[] = [];\n\n // Start with current\n for (const d of current) {\n byLabel.set(d.label, d);\n order.push(d.label);\n }\n\n // Apply upstream\n for (const d of upstream) {\n if (byLabel.has(d.label)) {\n if (prefer !== 'current') {\n // Default: upstream wins\n byLabel.set(d.label, d);\n }\n } else {\n byLabel.set(d.label, d);\n order.push(d.label);\n }\n }\n\n return order.map(label => byLabel.get(label)!);\n}\n\n/**\n * Merge two reference arrays.\n *\n * Default: union, deduplicated by JSON key.\n * prefer \"current\": current only.\n * prefer \"upstream\": upstream only.\n */\nexport function mergeRefs(\n current?: Reference[],\n upstream?: Reference[],\n prefer?: PreferSide,\n): Reference[] | undefined {\n if (prefer === 'current') {\n return current ? [...current] : undefined;\n }\n if (prefer === 'upstream') {\n return upstream ? [...upstream] : undefined;\n }\n\n // Default: union, deduplicated\n if (!current && !upstream) return undefined;\n\n const seen = new Set<string>();\n const result: Reference[] = [];\n\n const addRef = (r: Reference): void => {\n const key = JSON.stringify(r);\n if (!seen.has(key)) {\n seen.add(key);\n result.push(r);\n }\n };\n\n if (current) current.forEach(addRef);\n if (upstream) upstream.forEach(addRef);\n\n return result.length > 0 ? result : undefined;\n}\n","import type { HDFBaseline, BaselineRequirement } from '@mitre/hdf-schema';\nimport type { UpgradeResult, UpgradeOptions, DeltaResult, DeltaOptions, LinkRecord, DeltaStatistics } from './delta-types.js';\nimport type { InSpecProfile } from './types.js';\nimport { mergeRequirement } from './merge.js';\nimport { generateControlStub } from './control-stub.js';\nimport { generateInSpecYml } from './inspec-yml.js';\n\n/**\n * Generate an upgraded HDF Baseline by smart-merging current and upstream requirements.\n *\n * For each upstream requirement:\n * - If matched: smart-merge current + upstream fields per mergeRequirement semantics\n * - If unmatched: include upstream requirement as-is (new control)\n *\n * Current requirements with no upstream match are dropped by default\n * (a control removed from upstream should not survive the upgrade).\n * Set opts.keepUnmatched to retain them instead.\n */\nexport function generateUpgrade(\n currentBaseline: HDFBaseline,\n upstreamBaseline: HDFBaseline,\n linkRecords: LinkRecord[],\n opts?: UpgradeOptions,\n): UpgradeResult {\n const prefer = opts?.prefer;\n\n // Build lookup: newId -> LinkRecord (prefer primary over related)\n const linkByNewId = new Map<string, LinkRecord>();\n for (const lr of linkRecords) {\n const existing = linkByNewId.get(lr.newId);\n if (!existing || lr.relationship === 'primary') {\n linkByNewId.set(lr.newId, lr);\n }\n }\n\n // Build lookup: oldId -> current requirement\n const currentById = new Map<string, BaselineRequirement>();\n for (const req of currentBaseline.requirements) {\n currentById.set(req.id, req);\n }\n\n // Track which current IDs got matched\n const matchedCurrentIds = new Set<string>();\n\n // Merge upstream requirements\n const mergedReqs: BaselineRequirement[] = [];\n for (const upReq of upstreamBaseline.requirements) {\n const link = linkByNewId.get(upReq.id);\n if (link && link.oldId) {\n const curReq = currentById.get(link.oldId);\n if (curReq) {\n matchedCurrentIds.add(link.oldId);\n\n // Handle --noCode\n const effectiveCurrent = opts?.noCode\n ? { ...curReq, code: undefined }\n : curReq;\n\n mergedReqs.push(mergeRequirement(effectiveCurrent, upReq, prefer));\n continue;\n }\n }\n // Unmatched upstream: include as-is\n mergedReqs.push(upReq);\n }\n\n // Include unmatched current requirements only when explicitly opted in.\n // By default they're dropped — a control removed from upstream should\n // not survive the upgrade, matching SAF CLI delta semantics.\n if (opts?.keepUnmatched) {\n for (const curReq of currentBaseline.requirements) {\n if (!matchedCurrentIds.has(curReq.id)) {\n mergedReqs.push(curReq);\n }\n }\n }\n\n // Build upgraded baseline (use upstream metadata)\n const upgradedBaseline: HDFBaseline = {\n ...upstreamBaseline,\n requirements: mergedReqs,\n };\n\n // Compute statistics\n const statistics = computeStatistics(linkRecords, currentBaseline.requirements.length, upstreamBaseline.requirements.length);\n\n const result: UpgradeResult = {\n baseline: upgradedBaseline,\n linkRecords,\n statistics,\n };\n\n // Generate InSpec profile if requested\n const outputFormat = opts?.outputFormat ?? '';\n if (outputFormat === 'inspec' || outputFormat === 'both' || outputFormat === '') {\n result.profile = generateProfileFromBaseline(upgradedBaseline, opts);\n }\n\n return result;\n}\n\n/**\n * Legacy entry point. Wraps generateUpgrade for backward compatibility.\n *\n * @deprecated Use generateUpgrade instead.\n */\nexport function generateDelta(\n newBaseline: HDFBaseline,\n linkRecords: LinkRecord[],\n oldCodeMap: Map<string, string>,\n opts?: DeltaOptions,\n oldControlCount?: number,\n): DeltaResult {\n // Build synthetic current baseline from code map\n const currentReqs = buildCurrentReqsFromCodeMap(linkRecords, oldCodeMap);\n const currentBaseline: HDFBaseline = {\n name: 'current',\n requirements: currentReqs,\n groups: [],\n supports: [],\n };\n\n const result = generateUpgrade(currentBaseline, newBaseline, linkRecords, opts);\n\n // Patch statistics to use provided old control count\n result.statistics.oldControlsLength = oldControlCount ?? 0;\n\n return result;\n}\n\nfunction buildCurrentReqsFromCodeMap(\n linkRecords: LinkRecord[],\n oldCodeMap: Map<string, string>,\n): BaselineRequirement[] {\n const seen = new Set<string>();\n const reqs: BaselineRequirement[] = [];\n\n for (const lr of linkRecords) {\n if (!lr.oldId || seen.has(lr.oldId)) continue;\n seen.add(lr.oldId);\n\n const req: BaselineRequirement = {\n id: lr.oldId,\n impact: 0,\n tags: {},\n descriptions: [{ label: 'default', data: '' }],\n };\n const code = oldCodeMap.get(lr.oldId);\n if (code) {\n req.code = code;\n }\n reqs.push(req);\n }\n return reqs;\n}\n\nfunction generateProfileFromBaseline(baseline: HDFBaseline, opts?: UpgradeOptions): InSpecProfile {\n const controls = new Map<string, string>();\n const allStubs: string[] = [];\n\n for (const req of baseline.requirements) {\n const ruby = generateControlStub(req);\n\n if (opts?.singleFile) {\n allStubs.push(ruby);\n } else {\n const safeId = req.id.replace(/\\.\\./g, '').replace(/[/\\\\]/g, '') || 'unknown';\n controls.set(`controls/${safeId}.rb`, ruby);\n }\n }\n\n if (opts?.singleFile && allStubs.length > 0) {\n controls.set('controls/controls.rb', allStubs.join('\\n'));\n }\n\n const inspecYml = generateInSpecYml(baseline, {\n singleFile: opts?.singleFile,\n metadata: opts?.metadata,\n inspecVersion: opts?.inspecVersion,\n });\n\n return { inspecYml, controls };\n}\n\nfunction computeStatistics(linkRecords: LinkRecord[], oldControlCount: number, newControlCount: number): DeltaStatistics {\n let match = 0;\n let posMisMatch = 0;\n let dupMatch = 0;\n let noMatch = 0;\n\n for (const lr of linkRecords) {\n if (lr.relationship === 'related') {\n dupMatch++;\n } else if (lr.relationship === 'no-match') {\n noMatch++;\n } else if (lr.potentialMismatch) {\n posMisMatch++;\n } else {\n match++;\n }\n }\n\n return {\n oldControlsLength: oldControlCount,\n newControlsLength: newControlCount,\n totalMappedControls: match + posMisMatch + dupMatch,\n match,\n posMisMatch,\n dupMatch,\n noMatch,\n };\n}\n","import type { DeltaResult, LinkRecord } from './delta-types.js';\n\n/**\n * JSON report payload for delta operations.\n * SAF CLI-compatible: { links: LinkRecord[] }\n */\nexport interface DeltaJsonReport {\n links: LinkRecord[];\n}\n\n/**\n * Generate a structured JSON report from a delta result.\n * Matches SAF CLI's delta.json format: { ...diff, links }.\n */\nexport function generateDeltaJson(result: DeltaResult): DeltaJsonReport {\n return {\n links: result.linkRecords,\n };\n}\n\n/**\n * Format a per-link match method description matching SAF CLI's logMatchMethod.\n */\nfunction formatMatchMethod(lr: LinkRecord): string {\n const confidencePct = (lr.confidence * 100).toFixed(0) + '%';\n switch (lr.matchMethod) {\n case 'srgDeterministic':\n return `SRG deterministic (${lr.srg ?? '?'}) [${lr.relationship}]`;\n case 'srgCciTiebreak':\n return `SRG block + CCI tiebreak (Jaccard=${confidencePct}) [${lr.relationship}]`;\n case 'vendorFuzzyTitle':\n return `Vendor fuzzy title (confidence=${confidencePct}) [${lr.relationship}]`;\n case 'exactId':\n return `Exact ID [${lr.relationship}]`;\n case 'cciMatch':\n return `CCI match [${lr.relationship}]`;\n case 'fuzzyTitle':\n return `Fuzzy title (confidence=${confidencePct}) [${lr.relationship}]`;\n case 'none':\n return 'No match';\n default:\n return `${lr.matchMethod} [${lr.relationship}]`;\n }\n}\n\n/**\n * Generate a Markdown report from a delta result.\n * Matches SAF CLI's delta.md format: mapping table, control counts,\n * match statistics, and statistics validation.\n */\nexport function generateDeltaMarkdown(result: DeltaResult): string {\n const lines: string[] = [];\n const stats = result.statistics;\n\n // Mapping results — SAF CLI format: Old Control -> New Control\n if (result.linkRecords.length > 0) {\n lines.push('Mapping Results ===========================================================================');\n lines.push('\\tOld Control -> New Control');\n for (const lr of result.linkRecords) {\n if (lr.relationship !== 'no-match' && lr.oldId) {\n lines.push(`\\t ${lr.oldId} -> ${lr.newId}`);\n }\n }\n\n const totalMapped = stats.totalMappedControls;\n lines.push(`Total Mapped Controls: ${totalMapped}`);\n lines.push('');\n }\n\n // Control counts\n lines.push('Control Counts ===========================');\n lines.push(`Total Controls Available for Delta: ${stats.oldControlsLength}`);\n lines.push(` Total Controls Found on XCCDF: ${stats.newControlsLength}`);\n lines.push('');\n\n // Match statistics\n lines.push('Match Statistics =========================');\n lines.push(` Match Controls: ${stats.match}`);\n lines.push(` Possible Mismatch Controls: ${stats.posMisMatch}`);\n lines.push(` Related Match Controls: ${stats.dupMatch}`);\n lines.push(` No Match Controls: ${stats.noMatch}`);\n lines.push('');\n\n // Statistics validation\n lines.push('Statistics Validation =============================================');\n const totalMapped = stats.totalMappedControls;\n const matchMappedValid = (stats.match + stats.posMisMatch + stats.dupMatch) === totalMapped;\n const processedValid = (totalMapped + stats.noMatch) === stats.newControlsLength;\n lines.push(`Match + Mismatch + Related = Total Mapped Controls: (${stats.match}+${stats.posMisMatch}+${stats.dupMatch}=${totalMapped}) ${matchMappedValid}`);\n lines.push(` Total Processed = Total XCCDF Controls: (${totalMapped}+${stats.noMatch}=${totalMapped + stats.noMatch}) ${processedValid}`);\n lines.push('');\n\n // Per-control match method details\n if (result.linkRecords.length > 0) {\n lines.push('Match Details =============================================================');\n for (const lr of result.linkRecords) {\n if (lr.oldId) {\n lines.push(` ${lr.oldId} --> ${lr.newId}`);\n lines.push(` Match method: ${formatMatchMethod(lr)}`);\n } else {\n lines.push(` (none) --> ${lr.newId} [no match]`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,aAAa,GAAmB;CAC9C,MAAM,YAAY,EAAE,SAAS,GAAG;CAChC,MAAM,YAAY,EAAE,SAAS,IAAG;CAEhC,IAAI,aAAa,WAEf,OAAO,MAAM,EAAE,QAAQ,SAAS,OAAO,EAAE;CAG3C,IAAI,WAEF,OAAO,IAAI,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAK,EAAE;CAI3D,OAAO,IAAI,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,KAAK,EAAE;AAC3D;;;;;;;ACpBA,MAAM,qBAAqB;;;;;;;;;;;;;;AAe3B,SAAgB,oBAAoB,KAAkC;CAOpE,IAAI,IAAI,MAAM;EACZ,MAAM,IAAI,mBAAmB,KAAK,IAAI,IAAI;EAC1C,IAAI,KAAK,EAAE,OAAO,KAAA,GAAW;GAC3B,MAAM,UAAU,EAAE;GAClB,IAAI,YAAY,IAAI,IAClB,OAAO,IAAI;GAEb,MAAM,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,OAAO;GAC5C,OAAO,IAAI,KAAK,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM;EAClF;CACF;CAEA,MAAM,QAAkB,CAAC;CAEzB,MAAM,KAAK,YAAY,IAAI,GAAG,KAAK;CAGnC,IAAI,IAAI,OACN,MAAM,KAAK,WAAW,aAAa,IAAI,KAAK,GAAG;CAIjD,MAAM,cAAc,IAAI,aAAa,MAAM,MAAM,EAAE,UAAU,SAAS;CACtE,IAAI,aACF,MAAM,KAAK,UAAU,aAAa,YAAY,IAAI,GAAG;CAGvD,MAAM,8BAAc,IAAI,IAAY;CACpC,KAAK,MAAM,KAAK,IAAI,cAAc;EAChC,IAAI,EAAE,UAAU,WAAW;GACzB,IAAI,YAAY,IAAI,SAAS,GAC3B;GAEF,YAAY,IAAI,SAAS;GACzB;EACF;EACA,MAAM,KAAK,WAAW,EAAE,MAAM,KAAK,aAAa,EAAE,IAAI,GAAG;CAC3D;CAKA,IAAI,IAAI,WAAW,KAAA,GAAW;EAC5B,MAAM,YAAY,OAAO,UAAU,IAAI,MAAM,IACzC,IAAI,OAAO,QAAQ,CAAC,IACpB,OAAO,IAAI,MAAM;EACrB,MAAM,KAAK,YAAY,WAAW;CACpC;CAGA,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,IAAI,GAChD,MAAM,KAAK,KAAK,UAAU,KAAK,KAAK,GAAG;CAIzC,IAAI,IAAI,MAAM;EACZ,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,IAAI,IAAI;CACrB,OAAO;EACL,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,qCAAqC;CAClD;CAEA,MAAM,KAAK,KAAK;CAChB,MAAM,KAAK,EAAE;CAEb,OAAO,MAAM,KAAK,IAAI;AACxB;;AAGA,SAAS,UAAU,KAAa,OAAwB;CACtD,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO,OAAO,IAAI;CAGpB,IAAI,MAAM,QAAQ,KAAK,GAGrB,OAAO,OAAO,IAAI,KADJ,MAAM,KAAK,MAAe,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IACpC,EAAE;CAG/B,IAAI,OAAO,UAAU,WACnB,OAAO,OAAO,IAAI,IAAI;CAGxB,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,IAAI,IAAI,aAAa,KAAK;CAI1C,OAAO,OAAO,IAAI,IAAI,KAAK,UAAU,KAAK;AAC5C;;;;;;;;;AC/GA,SAAgB,kBACd,UACA,SACQ;CACR,MAAM,QAAkB,CAAC;CACzB,MAAM,OAAO,SAAS;CAGtB,MAAM,KAAK,SAAS,SAAS,MAAM;CAGnC,IAAI,SAAS,OACX,MAAM,KAAK,UAAU,SAAS,OAAO;CAGvC,MAAM,aAAa,MAAM,cAAc,SAAS;CAChD,IAAI,YACF,MAAM,KAAK,eAAe,YAAY;CAGxC,MAAM,YAAY,MAAM,aAAa,SAAS;CAC9C,IAAI,WACF,MAAM,KAAK,cAAc,WAAW;CAGtC,MAAM,UAAU,MAAM,WAAW,SAAS;CAC1C,IAAI,SACF,MAAM,KAAK,YAAY,SAAS;CAGlC,IAAI,SAAS,SACX,MAAM,KAAK,YAAY,SAAS,SAAS;CAI3C,MAAM,UAAU,MAAM,WAAW,SAAS;CAC1C,IAAI,SACF,MAAM,KAAK,aAAa,QAAQ,EAAE;CAIpC,MAAM,gBAAgB,SAAS,iBAAiB;CAChD,MAAM,KAAK,oBAAoB,cAAc,EAAE;CAG/C,IAAI,SAAS,YAAY,SAAS,SAAS,SAAS,GAAG;EACrD,MAAM,KAAK,WAAW;EACtB,KAAK,MAAM,WAAW,SAAS,UAAU;GACvC,MAAM,UAAoB,CAAC;GAC3B,IAAI,QAAQ,cACV,QAAQ,KAAK,oBAAoB,QAAQ,cAAc;GAEzD,IAAI,QAAQ,gBACV,QAAQ,KAAK,sBAAsB,QAAQ,gBAAgB;GAE7D,IAAI,QAAQ,UACV,QAAQ,KAAK,eAAe,QAAQ,UAAU;GAEhD,IAAI,QAAQ,SACV,QAAQ,KAAK,cAAc,QAAQ,SAAS;GAE9C,IAAI,QAAQ,SAAS,GAAG;IACtB,MAAM,KAAK,KAAK,QAAQ,EAAE,CAAE,UAAU,GAAG;IACzC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAClC,MAAM,KAAK,QAAQ,EAAG;GAE1B;EACF;CACF;CAGA,IAAI,SAAS,WAAW,SAAS,QAAQ,SAAS,GAAG;EACnD,MAAM,KAAK,UAAU;EACrB,KAAK,MAAM,OAAO,SAAS,SAAS;GAClC,MAAM,UAAoB,CAAC;GAC3B,IAAI,IAAI,MAAM,QAAQ,KAAK,SAAS,IAAI,MAAM;GAC9C,IAAI,IAAI,KAAK,QAAQ,KAAK,QAAQ,IAAI,KAAK;GAC3C,IAAI,IAAI,KAAK,QAAQ,KAAK,QAAQ,IAAI,KAAK;GAC3C,IAAI,IAAI,MAAM,QAAQ,KAAK,SAAS,IAAI,MAAM;GAC9C,IAAI,IAAI,QAAQ,QAAQ,KAAK,WAAW,IAAI,QAAQ;GACpD,IAAI,IAAI,YAAY,QAAQ,KAAK,eAAe,IAAI,YAAY;GAChE,IAAI,IAAI,aAAa,QAAQ,KAAK,gBAAgB,IAAI,aAAa;GACnE,IAAI,QAAQ,SAAS,GAAG;IACtB,MAAM,KAAK,KAAK,QAAQ,IAAI;IAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAClC,MAAM,KAAK,KAAK,QAAQ,IAAI;GAEhC;EACF;CACF;CAGA,IAAI,SAAS,UAAU,SAAS,OAAO,SAAS,GAAG;EACjD,MAAM,KAAK,SAAS;EACpB,KAAK,MAAM,SAAS,SAAS,QAC3B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,MAAM,KAAK,KAAK,IAAI,IAAI,gBAAgB,KAAK,GAAG;CAGtD;CAEA,MAAM,KAAK,EAAE;CACb,OAAO,MAAM,KAAK,IAAI;AACxB;;AAGA,SAAS,gBAAgB,OAAwB;CAC/C,IAAI,OAAO,UAAU,WAAW,OAAO,OAAO,KAAK;CACnD,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,OAAO,KAAK,UAAU,KAAK;AAC7B;;;;;;;;;;AC5GA,SAAgB,sBACd,UACA,SACe;CACf,MAAM,YAAY,kBAAkB,UAAU,OAAO;CACrD,MAAM,2BAAW,IAAI,IAAoB;CAEzC,IAAI,SAAS,aAAa,WAAW,GACnC,OAAO;EAAE;EAAW;CAAS;CAG/B,IAAI,SAAS,YAAY;EAEvB,MAAM,QAAQ,SAAS,aAAa,KAAK,QAA6B,oBAAoB,GAAG,CAAC;EAC9F,SAAS,IAAI,wBAAwB,MAAM,KAAK,IAAI,CAAC;CACvD,OAEE,KAAK,MAAM,OAAO,SAAS,cAAc;EAEvC,MAAM,WAAW,YADF,IAAI,GAAG,QAAQ,SAAS,EAAE,CAAC,CAAC,QAAQ,UAAU,EAAE,KAAK,UAChC;EACpC,SAAS,IAAI,UAAU,oBAAoB,GAAG,CAAC;CACjD;CAGF,OAAO;EAAE;EAAW;CAAS;AAC/B;;;;;;;;;;;;;;;;;ACnBA,SAAgB,iBACd,SACA,UACA,QACqB;CACrB,MAAM,SAA8B;EAElC,IAAI,SAAS;EAGb,OAAO,WAAW,YAAY,QAAQ,QAAQ,SAAS;EACvD,QAAQ,WAAW,YAAY,QAAQ,SAAS,SAAS;EACzD,UAAU,WAAW,YAAY,QAAQ,WAAW,SAAS;EAG7D,MAAM,UAAU,QAAQ,MAAM,SAAS,MAAM,MAAM;EACnD,cAAc,kBAAkB,QAAQ,cAAc,SAAS,cAAc,MAAM;EACnF,MAAM,UAAU,QAAQ,MAAM,SAAS,MAAM,MAAM;EAGnD,MAAM,WAAW,aACb,SAAS,OACR,QAAQ,QAAQ,SAAS;EAG9B,gBAAgB,WAAW,YAAY,QAAQ,iBAAiB,SAAS;CAC3E;CAGA,IAAI,OAAO,SAAS,KAAA,GAAW,OAAO,OAAO;CAC7C,IAAI,OAAO,aAAa,KAAA,GAAW,OAAO,OAAO;CACjD,IAAI,OAAO,mBAAmB,KAAA,GAAW,OAAO,OAAO;CACvD,IAAI,OAAO,SAAS,KAAA,KAAa,OAAO,KAAK,WAAW,GAAG,OAAO,OAAO;CAEzE,OAAO;AACT;;;;;;;;AASA,SAAgB,UACd,SACA,UACA,QACqB;CACrB,IAAI,WAAW,YACb,OAAO,EAAE,GAAG,SAAS;CAGvB,MAAM,SAA8B,EAAE,GAAG,QAAQ;CAEjD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,GAChD,IAAI,WAAW,WACT;MAAA,EAAE,OAAO,SACX,OAAO,OAAO;CAAA,OAIhB,OAAO,OAAO;CAIlB,OAAO;AACT;;;;;;;;AASA,SAAgB,kBACd,SACA,UACA,QACe;CACf,IAAI,WAAW,YACb,OAAO,CAAC,GAAG,QAAQ;CAGrB,MAAM,0BAAU,IAAI,IAAyB;CAC7C,MAAM,QAAkB,CAAC;CAGzB,KAAK,MAAM,KAAK,SAAS;EACvB,QAAQ,IAAI,EAAE,OAAO,CAAC;EACtB,MAAM,KAAK,EAAE,KAAK;CACpB;CAGA,KAAK,MAAM,KAAK,UACd,IAAI,QAAQ,IAAI,EAAE,KAAK,GACjB;MAAA,WAAW,WAEb,QAAQ,IAAI,EAAE,OAAO,CAAC;CAAA,OAEnB;EACL,QAAQ,IAAI,EAAE,OAAO,CAAC;EACtB,MAAM,KAAK,EAAE,KAAK;CACpB;CAGF,OAAO,MAAM,KAAI,UAAS,QAAQ,IAAI,KAAK,CAAE;AAC/C;;;;;;;;AASA,SAAgB,UACd,SACA,UACA,QACyB;CACzB,IAAI,WAAW,WACb,OAAO,UAAU,CAAC,GAAG,OAAO,IAAI,KAAA;CAElC,IAAI,WAAW,YACb,OAAO,WAAW,CAAC,GAAG,QAAQ,IAAI,KAAA;CAIpC,IAAI,CAAC,WAAW,CAAC,UAAU,OAAO,KAAA;CAElC,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,SAAsB,CAAC;CAE7B,MAAM,UAAU,MAAuB;EACrC,MAAM,MAAM,KAAK,UAAU,CAAC;EAC5B,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG;GAClB,KAAK,IAAI,GAAG;GACZ,OAAO,KAAK,CAAC;EACf;CACF;CAEA,IAAI,SAAS,QAAQ,QAAQ,MAAM;CACnC,IAAI,UAAU,SAAS,QAAQ,MAAM;CAErC,OAAO,OAAO,SAAS,IAAI,SAAS,KAAA;AACtC;;;;;;;;;;;;;;ACnJA,SAAgB,gBACd,iBACA,kBACA,aACA,MACe;CACf,MAAM,SAAS,MAAM;CAGrB,MAAM,8BAAc,IAAI,IAAwB;CAChD,KAAK,MAAM,MAAM,aAEf,IAAI,CADa,YAAY,IAAI,GAAG,KACxB,KAAK,GAAG,iBAAiB,WACnC,YAAY,IAAI,GAAG,OAAO,EAAE;CAKhC,MAAM,8BAAc,IAAI,IAAiC;CACzD,KAAK,MAAM,OAAO,gBAAgB,cAChC,YAAY,IAAI,IAAI,IAAI,GAAG;CAI7B,MAAM,oCAAoB,IAAI,IAAY;CAG1C,MAAM,aAAoC,CAAC;CAC3C,KAAK,MAAM,SAAS,iBAAiB,cAAc;EACjD,MAAM,OAAO,YAAY,IAAI,MAAM,EAAE;EACrC,IAAI,QAAQ,KAAK,OAAO;GACtB,MAAM,SAAS,YAAY,IAAI,KAAK,KAAK;GACzC,IAAI,QAAQ;IACV,kBAAkB,IAAI,KAAK,KAAK;IAGhC,MAAM,mBAAmB,MAAM,SAC3B;KAAE,GAAG;KAAQ,MAAM,KAAA;IAAU,IAC7B;IAEJ,WAAW,KAAK,iBAAiB,kBAAkB,OAAO,MAAM,CAAC;IACjE;GACF;EACF;EAEA,WAAW,KAAK,KAAK;CACvB;CAKA,IAAI,MAAM,eACH;OAAA,MAAM,UAAU,gBAAgB,cACnC,IAAI,CAAC,kBAAkB,IAAI,OAAO,EAAE,GAClC,WAAW,KAAK,MAAM;CAAA;CAM5B,MAAM,mBAAgC;EACpC,GAAG;EACH,cAAc;CAChB;CAKA,MAAM,SAAwB;EAC5B,UAAU;EACV;EACA,YALiB,kBAAkB,aAAa,gBAAgB,aAAa,QAAQ,iBAAiB,aAAa,MAK1G;CACX;CAGA,MAAM,eAAe,MAAM,gBAAgB;CAC3C,IAAI,iBAAiB,YAAY,iBAAiB,UAAU,iBAAiB,IAC3E,OAAO,UAAU,4BAA4B,kBAAkB,IAAI;CAGrE,OAAO;AACT;;;;;;AAOA,SAAgB,cACd,aACA,aACA,YACA,MACA,iBACa;CAUb,MAAM,SAAS,gBAAgB;EAN7B,MAAM;EACN,cAHkB,4BAA4B,aAAa,UAGnC;EACxB,QAAQ,CAAC;EACT,UAAU,CAAC;CAGgC,GAAG,aAAa,aAAa,IAAI;CAG9E,OAAO,WAAW,oBAAoB,mBAAmB;CAEzD,OAAO;AACT;AAEA,SAAS,4BACP,aACA,YACuB;CACvB,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,OAA8B,CAAC;CAErC,KAAK,MAAM,MAAM,aAAa;EAC5B,IAAI,CAAC,GAAG,SAAS,KAAK,IAAI,GAAG,KAAK,GAAG;EACrC,KAAK,IAAI,GAAG,KAAK;EAEjB,MAAM,MAA2B;GAC/B,IAAI,GAAG;GACP,QAAQ;GACR,MAAM,CAAC;GACP,cAAc,CAAC;IAAE,OAAO;IAAW,MAAM;GAAG,CAAC;EAC/C;EACA,MAAM,OAAO,WAAW,IAAI,GAAG,KAAK;EACpC,IAAI,MACF,IAAI,OAAO;EAEb,KAAK,KAAK,GAAG;CACf;CACA,OAAO;AACT;AAEA,SAAS,4BAA4B,UAAuB,MAAsC;CAChG,MAAM,2BAAW,IAAI,IAAoB;CACzC,MAAM,WAAqB,CAAC;CAE5B,KAAK,MAAM,OAAO,SAAS,cAAc;EACvC,MAAM,OAAO,oBAAoB,GAAG;EAEpC,IAAI,MAAM,YACR,SAAS,KAAK,IAAI;OACb;GACL,MAAM,SAAS,IAAI,GAAG,QAAQ,SAAS,EAAE,CAAC,CAAC,QAAQ,UAAU,EAAE,KAAK;GACpE,SAAS,IAAI,YAAY,OAAO,MAAM,IAAI;EAC5C;CACF;CAEA,IAAI,MAAM,cAAc,SAAS,SAAS,GACxC,SAAS,IAAI,wBAAwB,SAAS,KAAK,IAAI,CAAC;CAS1D,OAAO;EAAE,WANS,kBAAkB,UAAU;GAC5C,YAAY,MAAM;GAClB,UAAU,MAAM;GAChB,eAAe,MAAM;EACvB,CAEiB;EAAG;CAAS;AAC/B;AAEA,SAAS,kBAAkB,aAA2B,iBAAyB,iBAA0C;CACvH,IAAI,QAAQ;CACZ,IAAI,cAAc;CAClB,IAAI,WAAW;CACf,IAAI,UAAU;CAEd,KAAK,MAAM,MAAM,aACf,IAAI,GAAG,iBAAiB,WACtB;MACK,IAAI,GAAG,iBAAiB,YAC7B;MACK,IAAI,GAAG,mBACZ;MAEA;CAIJ,OAAO;EACL,mBAAmB;EACnB,mBAAmB;EACnB,qBAAqB,QAAQ,cAAc;EAC3C;EACA;EACA;EACA;CACF;AACF;;;;;;;ACrMA,SAAgB,kBAAkB,QAAsC;CACtE,OAAO,EACL,OAAO,OAAO,YAChB;AACF;;;;AAKA,SAAS,kBAAkB,IAAwB;CACjD,MAAM,iBAAiB,GAAG,aAAa,IAAA,CAAK,QAAQ,CAAC,IAAI;CACzD,QAAQ,GAAG,aAAX;EACE,KAAK,oBACH,OAAO,sBAAsB,GAAG,OAAO,IAAI,KAAK,GAAG,aAAa;EAClE,KAAK,kBACH,OAAO,qCAAqC,cAAc,KAAK,GAAG,aAAa;EACjF,KAAK,oBACH,OAAO,kCAAkC,cAAc,KAAK,GAAG,aAAa;EAC9E,KAAK,WACH,OAAO,aAAa,GAAG,aAAa;EACtC,KAAK,YACH,OAAO,cAAc,GAAG,aAAa;EACvC,KAAK,cACH,OAAO,2BAA2B,cAAc,KAAK,GAAG,aAAa;EACvE,KAAK,QACH,OAAO;EACT,SACE,OAAO,GAAG,GAAG,YAAY,IAAI,GAAG,aAAa;CACjD;AACF;;;;;;AAOA,SAAgB,sBAAsB,QAA6B;CACjE,MAAM,QAAkB,CAAC;CACzB,MAAM,QAAQ,OAAO;CAGrB,IAAI,OAAO,YAAY,SAAS,GAAG;EACjC,MAAM,KAAK,6FAA6F;EACxG,MAAM,KAAK,6BAA8B;EACzC,KAAK,MAAM,MAAM,OAAO,aACtB,IAAI,GAAG,iBAAiB,cAAc,GAAG,OACvC,MAAM,KAAK,QAAQ,GAAG,MAAM,MAAM,GAAG,OAAO;EAIhD,MAAM,cAAc,MAAM;EAC1B,MAAM,KAAK,2BAA2B,aAAa;EACnD,MAAM,KAAK,EAAE;CACf;CAGA,MAAM,KAAK,4CAA4C;CACvD,MAAM,KAAK,wCAAwC,MAAM,mBAAmB;CAC5E,MAAM,KAAK,wCAAwC,MAAM,mBAAmB;CAC5E,MAAM,KAAK,EAAE;CAGb,MAAM,KAAK,4CAA4C;CACvD,MAAM,KAAK,wCAAwC,MAAM,OAAO;CAChE,MAAM,KAAK,wCAAwC,MAAM,aAAa;CACtE,MAAM,KAAK,wCAAwC,MAAM,UAAU;CACnE,MAAM,KAAK,wCAAwC,MAAM,SAAS;CAClE,MAAM,KAAK,EAAE;CAGb,MAAM,KAAK,qEAAqE;CAChF,MAAM,cAAc,MAAM;CAC1B,MAAM,mBAAoB,MAAM,QAAQ,MAAM,cAAc,MAAM,aAAc;CAChF,MAAM,iBAAkB,cAAc,MAAM,YAAa,MAAM;CAC/D,MAAM,KAAK,yDAAyD,MAAM,MAAM,GAAG,MAAM,YAAY,GAAG,MAAM,SAAS,GAAG,YAAY,IAAI,kBAAkB;CAC5J,MAAM,KAAK,+CAA+C,YAAY,GAAG,MAAM,QAAQ,GAAG,cAAc,MAAM,QAAQ,IAAI,gBAAgB;CAC1I,MAAM,KAAK,EAAE;CAGb,IAAI,OAAO,YAAY,SAAS,GAAG;EACjC,MAAM,KAAK,6EAA6E;EACxF,KAAK,MAAM,MAAM,OAAO,aACtB,IAAI,GAAG,OAAO;GACZ,MAAM,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,OAAO;GAC1C,MAAM,KAAK,yBAAyB,kBAAkB,EAAE,GAAG;EAC7D,OACE,MAAM,KAAK,gBAAgB,GAAG,MAAM,aAAa;EAGrD,MAAM,KAAK,EAAE;CACf;CAEA,OAAO,MAAM,KAAK,IAAI;AACxB"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/ruby-escape.ts","../src/control-stub.ts","../src/inspec-yml.ts","../src/profile-generator.ts","../src/merge.ts","../src/delta.ts","../src/delta-report.ts"],"sourcesContent":["/**\n * Escape a string for use as a Ruby string literal.\n *\n * Strategy:\n * - If the string contains both single and double quotes → %q() wrapper\n * - If the string contains only single quotes → double-quoted with escaping\n * - Otherwise → single-quoted with escaping\n *\n * Ported from ts-inspec-objects escapeQuotes(), cross-referenced with\n * inspec-parser's RubyRebuilder.\n */\nexport function escapeQuotes(s: string): string {\n const hasSingle = s.includes(\"'\");\n const hasDouble = s.includes('\"');\n\n if (hasSingle && hasDouble) {\n // %q() — escape backslashes before ) so Ruby doesn't treat \\) as escaped delimiter\n return `%q(${s.replace(/\\\\\\)/g, '\\\\\\\\)')})`;\n }\n\n if (hasSingle) {\n // Double-quoted: escape backslashes, then double quotes\n return `\"${s.replace(/\\\\/g, '\\\\\\\\').replace(/\"/g, '\\\\\"')}\"`;\n }\n\n // Single-quoted: escape backslashes, then single quotes\n return `'${s.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")}'`;\n}\n","import type { BaselineRequirement } from '@mitre/hdf-schema';\nimport { escapeQuotes } from './ruby-escape.js';\n\n/**\n * Detects when a code string already starts with `control 'ID' do`,\n * meaning it's a complete InSpec control file — not a body fragment.\n */\nconst FULL_CONTROL_BLOCK = /^\\s*control\\s+['\"]([^'\"]+)['\"]\\s+do\\b/;\n\n/**\n * Generate a Ruby InSpec control stub from an HDF BaselineRequirement.\n *\n * Output follows the InSpec DSL ordering convention:\n * control 'ID' do\n * title ...\n * desc ...\n * desc 'check', ...\n * impact ...\n * tag key: value\n * <code or stub comment>\n * end\n */\nexport function generateControlStub(req: BaselineRequirement): string {\n // If code is already a complete `control 'ID' do ... end` block (e.g.\n // from `-c controls/` reading whole .rb files), emit it as-is — wrapping\n // it again would produce nested control blocks, which InSpec rejects.\n // When the inner ID differs from req.id (e.g. an upgrade rename match\n // where current's code was carried into a renamed requirement), rewrite\n // the wrapper to match req.id so the file remains valid InSpec.\n if (req.code) {\n const m = FULL_CONTROL_BLOCK.exec(req.code);\n if (m && m[1] !== undefined) {\n const innerID = m[1];\n if (innerID === req.id) {\n return req.code;\n }\n const start = m.index + m[0].indexOf(innerID);\n return req.code.slice(0, start) + req.id + req.code.slice(start + innerID.length);\n }\n }\n\n const lines: string[] = [];\n\n lines.push(`control '${req.id}' do`);\n\n // Title\n if (req.title) {\n lines.push(` title ${escapeQuotes(req.title)}`);\n }\n\n // Descriptions: default first (as bare `desc`), then labeled\n const defaultDesc = req.descriptions.find((d) => d.label === 'default');\n if (defaultDesc) {\n lines.push(` desc ${escapeQuotes(defaultDesc.data)}`);\n }\n\n const seenDefault = new Set<string>();\n for (const d of req.descriptions) {\n if (d.label === 'default') {\n if (seenDefault.has('default')) {\n continue; // skip duplicate default\n }\n seenDefault.add('default');\n continue; // already emitted above as bare desc\n }\n lines.push(` desc '${d.label}', ${escapeQuotes(d.data)}`);\n }\n\n // Impact — always render with at least one decimal place for 0 and whole numbers\n // RAW impact by design: a generated control declares the impact the profile\n // asserts, not the impact an assessment later resolved it to.\n if (req.impact !== undefined) {\n const impactStr = Number.isInteger(req.impact)\n ? req.impact.toFixed(1)\n : String(req.impact);\n lines.push(` impact ${impactStr}`);\n }\n\n // Tags\n for (const [key, value] of Object.entries(req.tags)) {\n lines.push(` ${formatTag(key, value)}`);\n }\n\n // Code body or stub placeholder\n if (req.code) {\n lines.push('');\n lines.push(req.code);\n } else {\n lines.push('');\n lines.push(' # TODO: Add InSpec test code here');\n }\n\n lines.push('end');\n lines.push(''); // trailing newline\n\n return lines.join('\\n');\n}\n\n/** Format a single tag key-value pair as Ruby DSL. */\nfunction formatTag(key: string, value: unknown): string {\n if (value === null || value === undefined) {\n return `tag ${key}: nil`;\n }\n\n if (Array.isArray(value)) {\n // Ruby array syntax: tag key: ['val1', 'val2']\n const items = value.map((v: unknown) => `'${String(v)}'`).join(', ');\n return `tag ${key}: [${items}]`;\n }\n\n if (typeof value === 'boolean') {\n return `tag ${key}: ${value}`;\n }\n\n if (typeof value === 'string') {\n return `tag ${key}: ${escapeQuotes(value)}`;\n }\n\n // Fallback for other types (numbers, objects)\n return `tag ${key}: ${JSON.stringify(value)}`;\n}\n","import type { HDFBaseline } from '@mitre/hdf-schema';\nimport type { GeneratorOptions } from './types.js';\n\n/**\n * Generate an inspec.yml YAML string from an HDF Baseline and options.\n *\n * Uses string interpolation — no YAML library needed since the structure\n * is fixed and shallow.\n */\nexport function generateInSpecYml(\n baseline: HDFBaseline,\n options?: GeneratorOptions,\n): string {\n const lines: string[] = [];\n const meta = options?.metadata;\n\n // Required: name\n lines.push(`name: ${baseline.name}`);\n\n // Optional metadata fields\n if (baseline.title) {\n lines.push(`title: ${baseline.title}`);\n }\n\n const maintainer = meta?.maintainer ?? baseline.maintainer;\n if (maintainer) {\n lines.push(`maintainer: ${maintainer}`);\n }\n\n const copyright = meta?.copyright ?? baseline.copyright;\n if (copyright) {\n lines.push(`copyright: ${copyright}`);\n }\n\n const license = meta?.license ?? baseline.license;\n if (license) {\n lines.push(`license: ${license}`);\n }\n\n if (baseline.summary) {\n lines.push(`summary: ${baseline.summary}`);\n }\n\n // Version: metadata override takes priority\n const version = meta?.version ?? baseline.version;\n if (version) {\n lines.push(`version: '${version}'`);\n }\n\n // InSpec version constraint\n const inspecVersion = options?.inspecVersion ?? '~>6.0';\n lines.push(`inspec_version: '${inspecVersion}'`);\n\n // Supports array\n if (baseline.supports && baseline.supports.length > 0) {\n lines.push('supports:');\n for (const support of baseline.supports) {\n const entries: string[] = [];\n if (support.platformName) {\n entries.push(` platform-name: ${support.platformName}`);\n }\n if (support.platformFamily) {\n entries.push(` platform-family: ${support.platformFamily}`);\n }\n if (support.platform) {\n entries.push(` platform: ${support.platform}`);\n }\n if (support.release) {\n entries.push(` release: ${support.release}`);\n }\n if (entries.length > 0) {\n lines.push(`- ${entries[0]!.trimStart()}`);\n for (let i = 1; i < entries.length; i++) {\n lines.push(entries[i]!);\n }\n }\n }\n }\n\n // Depends array\n if (baseline.depends && baseline.depends.length > 0) {\n lines.push('depends:');\n for (const dep of baseline.depends) {\n const entries: string[] = [];\n if (dep.name) entries.push(`name: ${dep.name}`);\n if (dep.git) entries.push(`git: ${dep.git}`);\n if (dep.url) entries.push(`url: ${dep.url}`);\n if (dep.path) entries.push(`path: ${dep.path}`);\n if (dep.branch) entries.push(`branch: ${dep.branch}`);\n if (dep.compliance) entries.push(`compliance: ${dep.compliance}`);\n if (dep.supermarket) entries.push(`supermarket: ${dep.supermarket}`);\n if (entries.length > 0) {\n lines.push(`- ${entries[0]}`);\n for (let i = 1; i < entries.length; i++) {\n lines.push(` ${entries[i]}`);\n }\n }\n }\n }\n\n // Inputs array\n if (baseline.inputs && baseline.inputs.length > 0) {\n lines.push('inputs:');\n for (const input of baseline.inputs) {\n for (const [key, value] of Object.entries(input)) {\n lines.push(`- ${key}: ${formatYamlValue(value)}`);\n }\n }\n }\n\n lines.push(''); // trailing newline\n return lines.join('\\n');\n}\n\n/** Format a value for inline YAML output. */\nfunction formatYamlValue(value: unknown): string {\n if (typeof value === 'boolean') return String(value);\n if (typeof value === 'number') return String(value);\n if (typeof value === 'string') return value;\n return JSON.stringify(value);\n}\n","import type { BaselineRequirement, HDFBaseline } from '@mitre/hdf-schema';\nimport type { GeneratorOptions, InSpecProfile } from './types.js';\nimport { generateControlStub } from './control-stub.js';\nimport { generateInSpecYml } from './inspec-yml.js';\n\n/**\n * Generate an in-memory InSpec profile from an HDF Baseline.\n *\n * Returns an InSpecProfile with inspec.yml content and a Map of\n * control filenames to Ruby source code. No file I/O — the CLI\n * is responsible for writing files to disk.\n */\nexport function generateInSpecProfile(\n baseline: HDFBaseline,\n options?: GeneratorOptions,\n): InSpecProfile {\n const inspecYml = generateInSpecYml(baseline, options);\n const controls = new Map<string, string>();\n\n if (baseline.requirements.length === 0) {\n return { inspecYml, controls };\n }\n\n if (options?.singleFile) {\n // All controls in a single file\n const stubs = baseline.requirements.map((req: BaselineRequirement) => generateControlStub(req));\n controls.set('controls/controls.rb', stubs.join('\\n'));\n } else {\n // One file per control — sanitize ID for safe filenames\n for (const req of baseline.requirements) {\n const safeId = req.id.replace(/\\.\\./g, '').replace(/[/\\\\]/g, '') || 'unknown';\n const filename = `controls/${safeId}.rb`;\n controls.set(filename, generateControlStub(req));\n }\n }\n\n return { inspecYml, controls };\n}\n","import type { BaselineRequirement, Description, Reference } from '@mitre/hdf-schema';\n\nexport type PreferSide = 'current' | 'upstream' | undefined;\n\n/**\n * Smart-merge a current and upstream requirement.\n *\n * Default (no prefer):\n * - ID: always upstream\n * - Scalars (title, impact, severity): upstream wins\n * - Tags: union, upstream wins key conflicts\n * - Descriptions: union by label, upstream wins on same label\n * - Code: current (preserve tests)\n * - Refs: union (deduplicated)\n *\n * prefer \"current\": scalars from current, current wins tag/desc conflicts\n * prefer \"upstream\": everything from upstream (full replacement)\n */\nexport function mergeRequirement(\n current: BaselineRequirement,\n upstream: BaselineRequirement,\n prefer?: PreferSide,\n): BaselineRequirement {\n const merged: BaselineRequirement = {\n // ID always comes from upstream\n id: upstream.id,\n\n // Scalars\n title: prefer === 'current' ? current.title : upstream.title,\n impact: prefer === 'current' ? current.impact : upstream.impact,\n severity: prefer === 'current' ? current.severity : upstream.severity,\n\n // Collections\n tags: mergeTags(current.tags, upstream.tags, prefer),\n descriptions: mergeDescriptions(current.descriptions, upstream.descriptions, prefer),\n refs: mergeRefs(current.refs, upstream.refs, prefer),\n\n // Code: current by default, upstream only with --prefer upstream\n code: prefer === 'upstream'\n ? upstream.code\n : (current.code ?? upstream.code),\n\n // SourceLocation follows scalars\n sourceLocation: prefer === 'current' ? current.sourceLocation : upstream.sourceLocation,\n };\n\n // Clean up undefined optional fields\n if (merged.code === undefined) delete merged.code;\n if (merged.severity === undefined) delete merged.severity;\n if (merged.sourceLocation === undefined) delete merged.sourceLocation;\n if (merged.refs === undefined || merged.refs.length === 0) delete merged.refs;\n\n return merged;\n}\n\n/**\n * Merge two tag maps.\n *\n * Default: union of keys; upstream wins on key conflicts.\n * prefer \"current\": union; current wins on key conflicts.\n * prefer \"upstream\": upstream replaces all.\n */\nexport function mergeTags(\n current: Record<string, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n upstream: Record<string, any>, // eslint-disable-line @typescript-eslint/no-explicit-any\n prefer?: PreferSide,\n): Record<string, any> { // eslint-disable-line @typescript-eslint/no-explicit-any\n if (prefer === 'upstream') {\n return { ...upstream };\n }\n\n const merged: Record<string, any> = { ...current }; // eslint-disable-line @typescript-eslint/no-explicit-any\n\n for (const [key, value] of Object.entries(upstream)) {\n if (prefer === 'current') {\n if (!(key in merged)) {\n merged[key] = value;\n }\n } else {\n // Default: upstream wins on conflict\n merged[key] = value;\n }\n }\n\n return merged;\n}\n\n/**\n * Merge two description arrays by label.\n *\n * Default: union by label; upstream wins on label conflicts.\n * prefer \"current\": union; current wins on label conflicts.\n * prefer \"upstream\": upstream replaces all.\n */\nexport function mergeDescriptions(\n current: Description[],\n upstream: Description[],\n prefer?: PreferSide,\n): Description[] {\n if (prefer === 'upstream') {\n return [...upstream];\n }\n\n const byLabel = new Map<string, Description>();\n const order: string[] = [];\n\n // Start with current\n for (const d of current) {\n byLabel.set(d.label, d);\n order.push(d.label);\n }\n\n // Apply upstream\n for (const d of upstream) {\n if (byLabel.has(d.label)) {\n if (prefer !== 'current') {\n // Default: upstream wins\n byLabel.set(d.label, d);\n }\n } else {\n byLabel.set(d.label, d);\n order.push(d.label);\n }\n }\n\n return order.map(label => byLabel.get(label)!);\n}\n\n/**\n * Merge two reference arrays.\n *\n * Default: union, deduplicated by JSON key.\n * prefer \"current\": current only.\n * prefer \"upstream\": upstream only.\n */\nexport function mergeRefs(\n current?: Reference[],\n upstream?: Reference[],\n prefer?: PreferSide,\n): Reference[] | undefined {\n if (prefer === 'current') {\n return current ? [...current] : undefined;\n }\n if (prefer === 'upstream') {\n return upstream ? [...upstream] : undefined;\n }\n\n // Default: union, deduplicated\n if (!current && !upstream) return undefined;\n\n const seen = new Set<string>();\n const result: Reference[] = [];\n\n const addRef = (r: Reference): void => {\n const key = JSON.stringify(r);\n if (!seen.has(key)) {\n seen.add(key);\n result.push(r);\n }\n };\n\n if (current) current.forEach(addRef);\n if (upstream) upstream.forEach(addRef);\n\n return result.length > 0 ? result : undefined;\n}\n","import type { HDFBaseline, BaselineRequirement } from '@mitre/hdf-schema';\nimport type { UpgradeResult, UpgradeOptions, DeltaResult, DeltaOptions, LinkRecord, DeltaStatistics } from './delta-types.js';\nimport type { InSpecProfile } from './types.js';\nimport { mergeRequirement } from './merge.js';\nimport { generateControlStub } from './control-stub.js';\nimport { generateInSpecYml } from './inspec-yml.js';\n\n/**\n * Generate an upgraded HDF Baseline by smart-merging current and upstream requirements.\n *\n * For each upstream requirement:\n * - If matched: smart-merge current + upstream fields per mergeRequirement semantics\n * - If unmatched: include upstream requirement as-is (new control)\n *\n * Current requirements with no upstream match are dropped by default\n * (a control removed from upstream should not survive the upgrade).\n * Set opts.keepUnmatched to retain them instead.\n */\nexport function generateUpgrade(\n currentBaseline: HDFBaseline,\n upstreamBaseline: HDFBaseline,\n linkRecords: LinkRecord[],\n opts?: UpgradeOptions,\n): UpgradeResult {\n const prefer = opts?.prefer;\n\n // Build lookup: newId -> LinkRecord (prefer primary over related)\n const linkByNewId = new Map<string, LinkRecord>();\n for (const lr of linkRecords) {\n const existing = linkByNewId.get(lr.newId);\n if (!existing || lr.relationship === 'primary') {\n linkByNewId.set(lr.newId, lr);\n }\n }\n\n // Build lookup: oldId -> current requirement\n const currentById = new Map<string, BaselineRequirement>();\n for (const req of currentBaseline.requirements) {\n currentById.set(req.id, req);\n }\n\n // Track which current IDs got matched\n const matchedCurrentIds = new Set<string>();\n\n // Merge upstream requirements\n const mergedReqs: BaselineRequirement[] = [];\n for (const upReq of upstreamBaseline.requirements) {\n const link = linkByNewId.get(upReq.id);\n if (link && link.oldId) {\n const curReq = currentById.get(link.oldId);\n if (curReq) {\n matchedCurrentIds.add(link.oldId);\n\n // Handle --noCode\n const effectiveCurrent = opts?.noCode\n ? { ...curReq, code: undefined }\n : curReq;\n\n mergedReqs.push(mergeRequirement(effectiveCurrent, upReq, prefer));\n continue;\n }\n }\n // Unmatched upstream: include as-is\n mergedReqs.push(upReq);\n }\n\n // Include unmatched current requirements only when explicitly opted in.\n // By default they're dropped — a control removed from upstream should\n // not survive the upgrade, matching SAF CLI delta semantics.\n if (opts?.keepUnmatched) {\n for (const curReq of currentBaseline.requirements) {\n if (!matchedCurrentIds.has(curReq.id)) {\n mergedReqs.push(curReq);\n }\n }\n }\n\n // Build upgraded baseline (use upstream metadata)\n const upgradedBaseline: HDFBaseline = {\n ...upstreamBaseline,\n requirements: mergedReqs,\n };\n\n // Compute statistics\n const statistics = computeStatistics(linkRecords, currentBaseline.requirements.length, upstreamBaseline.requirements.length);\n\n const result: UpgradeResult = {\n baseline: upgradedBaseline,\n linkRecords,\n statistics,\n };\n\n // Generate InSpec profile if requested\n const outputFormat = opts?.outputFormat ?? '';\n if (outputFormat === 'inspec' || outputFormat === 'both' || outputFormat === '') {\n result.profile = generateProfileFromBaseline(upgradedBaseline, opts);\n }\n\n return result;\n}\n\n/**\n * Legacy entry point. Wraps generateUpgrade for backward compatibility.\n *\n * @deprecated Use generateUpgrade instead.\n */\nexport function generateDelta(\n newBaseline: HDFBaseline,\n linkRecords: LinkRecord[],\n oldCodeMap: Map<string, string>,\n opts?: DeltaOptions,\n oldControlCount?: number,\n): DeltaResult {\n // Build synthetic current baseline from code map\n const currentReqs = buildCurrentReqsFromCodeMap(linkRecords, oldCodeMap);\n const currentBaseline: HDFBaseline = {\n name: 'current',\n requirements: currentReqs,\n groups: [],\n supports: [],\n };\n\n const result = generateUpgrade(currentBaseline, newBaseline, linkRecords, opts);\n\n // Patch statistics to use provided old control count\n result.statistics.oldControlsLength = oldControlCount ?? 0;\n\n return result;\n}\n\nfunction buildCurrentReqsFromCodeMap(\n linkRecords: LinkRecord[],\n oldCodeMap: Map<string, string>,\n): BaselineRequirement[] {\n const seen = new Set<string>();\n const reqs: BaselineRequirement[] = [];\n\n for (const lr of linkRecords) {\n if (!lr.oldId || seen.has(lr.oldId)) continue;\n seen.add(lr.oldId);\n\n const req: BaselineRequirement = {\n id: lr.oldId,\n impact: 0,\n tags: {},\n descriptions: [{ label: 'default', data: '' }],\n };\n const code = oldCodeMap.get(lr.oldId);\n if (code) {\n req.code = code;\n }\n reqs.push(req);\n }\n return reqs;\n}\n\nfunction generateProfileFromBaseline(baseline: HDFBaseline, opts?: UpgradeOptions): InSpecProfile {\n const controls = new Map<string, string>();\n const allStubs: string[] = [];\n\n for (const req of baseline.requirements) {\n const ruby = generateControlStub(req);\n\n if (opts?.singleFile) {\n allStubs.push(ruby);\n } else {\n const safeId = req.id.replace(/\\.\\./g, '').replace(/[/\\\\]/g, '') || 'unknown';\n controls.set(`controls/${safeId}.rb`, ruby);\n }\n }\n\n if (opts?.singleFile && allStubs.length > 0) {\n controls.set('controls/controls.rb', allStubs.join('\\n'));\n }\n\n const inspecYml = generateInSpecYml(baseline, {\n singleFile: opts?.singleFile,\n metadata: opts?.metadata,\n inspecVersion: opts?.inspecVersion,\n });\n\n return { inspecYml, controls };\n}\n\nfunction computeStatistics(linkRecords: LinkRecord[], oldControlCount: number, newControlCount: number): DeltaStatistics {\n let match = 0;\n let posMisMatch = 0;\n let dupMatch = 0;\n let noMatch = 0;\n\n for (const lr of linkRecords) {\n if (lr.relationship === 'related') {\n dupMatch++;\n } else if (lr.relationship === 'no-match') {\n noMatch++;\n } else if (lr.potentialMismatch) {\n posMisMatch++;\n } else {\n match++;\n }\n }\n\n return {\n oldControlsLength: oldControlCount,\n newControlsLength: newControlCount,\n totalMappedControls: match + posMisMatch + dupMatch,\n match,\n posMisMatch,\n dupMatch,\n noMatch,\n };\n}\n","import type { DeltaResult, LinkRecord } from './delta-types.js';\n\n/**\n * JSON report payload for delta operations.\n * SAF CLI-compatible: { links: LinkRecord[] }\n */\nexport interface DeltaJsonReport {\n links: LinkRecord[];\n}\n\n/**\n * Generate a structured JSON report from a delta result.\n * Matches SAF CLI's delta.json format: { ...diff, links }.\n */\nexport function generateDeltaJson(result: DeltaResult): DeltaJsonReport {\n return {\n links: result.linkRecords,\n };\n}\n\n/**\n * Format a per-link match method description matching SAF CLI's logMatchMethod.\n */\nfunction formatMatchMethod(lr: LinkRecord): string {\n const confidencePct = (lr.confidence * 100).toFixed(0) + '%';\n switch (lr.matchMethod) {\n case 'srgDeterministic':\n return `SRG deterministic (${lr.srg ?? '?'}) [${lr.relationship}]`;\n case 'srgCciTiebreak':\n return `SRG block + CCI tiebreak (Jaccard=${confidencePct}) [${lr.relationship}]`;\n case 'vendorFuzzyTitle':\n return `Vendor fuzzy title (confidence=${confidencePct}) [${lr.relationship}]`;\n case 'exactId':\n return `Exact ID [${lr.relationship}]`;\n case 'cciMatch':\n return `CCI match [${lr.relationship}]`;\n case 'fuzzyTitle':\n return `Fuzzy title (confidence=${confidencePct}) [${lr.relationship}]`;\n case 'none':\n return 'No match';\n default:\n return `${lr.matchMethod} [${lr.relationship}]`;\n }\n}\n\n/**\n * Generate a Markdown report from a delta result.\n * Matches SAF CLI's delta.md format: mapping table, control counts,\n * match statistics, and statistics validation.\n */\nexport function generateDeltaMarkdown(result: DeltaResult): string {\n const lines: string[] = [];\n const stats = result.statistics;\n\n // Mapping results — SAF CLI format: Old Control -> New Control\n if (result.linkRecords.length > 0) {\n lines.push('Mapping Results ===========================================================================');\n lines.push('\\tOld Control -> New Control');\n for (const lr of result.linkRecords) {\n if (lr.relationship !== 'no-match' && lr.oldId) {\n lines.push(`\\t ${lr.oldId} -> ${lr.newId}`);\n }\n }\n\n const totalMapped = stats.totalMappedControls;\n lines.push(`Total Mapped Controls: ${totalMapped}`);\n lines.push('');\n }\n\n // Control counts\n lines.push('Control Counts ===========================');\n lines.push(`Total Controls Available for Delta: ${stats.oldControlsLength}`);\n lines.push(` Total Controls Found on XCCDF: ${stats.newControlsLength}`);\n lines.push('');\n\n // Match statistics\n lines.push('Match Statistics =========================');\n lines.push(` Match Controls: ${stats.match}`);\n lines.push(` Possible Mismatch Controls: ${stats.posMisMatch}`);\n lines.push(` Related Match Controls: ${stats.dupMatch}`);\n lines.push(` No Match Controls: ${stats.noMatch}`);\n lines.push('');\n\n // Statistics validation\n lines.push('Statistics Validation =============================================');\n const totalMapped = stats.totalMappedControls;\n const matchMappedValid = (stats.match + stats.posMisMatch + stats.dupMatch) === totalMapped;\n const processedValid = (totalMapped + stats.noMatch) === stats.newControlsLength;\n lines.push(`Match + Mismatch + Related = Total Mapped Controls: (${stats.match}+${stats.posMisMatch}+${stats.dupMatch}=${totalMapped}) ${matchMappedValid}`);\n lines.push(` Total Processed = Total XCCDF Controls: (${totalMapped}+${stats.noMatch}=${totalMapped + stats.noMatch}) ${processedValid}`);\n lines.push('');\n\n // Per-control match method details\n if (result.linkRecords.length > 0) {\n lines.push('Match Details =============================================================');\n for (const lr of result.linkRecords) {\n if (lr.oldId) {\n lines.push(` ${lr.oldId} --> ${lr.newId}`);\n lines.push(` Match method: ${formatMatchMethod(lr)}`);\n } else {\n lines.push(` (none) --> ${lr.newId} [no match]`);\n }\n }\n lines.push('');\n }\n\n return lines.join('\\n');\n}\n"],"mappings":";;;;;;;;;;;;AAWA,SAAgB,aAAa,GAAmB;CAC9C,MAAM,YAAY,EAAE,SAAS,GAAG;CAChC,MAAM,YAAY,EAAE,SAAS,IAAG;CAEhC,IAAI,aAAa,WAEf,OAAO,MAAM,EAAE,QAAQ,SAAS,OAAO,EAAE;CAG3C,IAAI,WAEF,OAAO,IAAI,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,MAAK,EAAE;CAI3D,OAAO,IAAI,EAAE,QAAQ,OAAO,MAAM,CAAC,CAAC,QAAQ,MAAM,KAAK,EAAE;AAC3D;;;;;;ACpBA,MAAM,qBAAqB;;;;;;;;;;;;;;AAe3B,SAAgB,oBAAoB,KAAkC;CAOpE,IAAI,IAAI,MAAM;EACZ,MAAM,IAAI,mBAAmB,KAAK,IAAI,IAAI;EAC1C,IAAI,KAAK,EAAE,OAAO,KAAA,GAAW;GAC3B,MAAM,UAAU,EAAE;GAClB,IAAI,YAAY,IAAI,IAClB,OAAO,IAAI;GAEb,MAAM,QAAQ,EAAE,QAAQ,EAAE,EAAE,CAAC,QAAQ,OAAO;GAC5C,OAAO,IAAI,KAAK,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,KAAK,MAAM,QAAQ,QAAQ,MAAM;EAClF;CACF;CAEA,MAAM,QAAkB,CAAC;CAEzB,MAAM,KAAK,YAAY,IAAI,GAAG,KAAK;CAGnC,IAAI,IAAI,OACN,MAAM,KAAK,WAAW,aAAa,IAAI,KAAK,GAAG;CAIjD,MAAM,cAAc,IAAI,aAAa,MAAM,MAAM,EAAE,UAAU,SAAS;CACtE,IAAI,aACF,MAAM,KAAK,UAAU,aAAa,YAAY,IAAI,GAAG;CAGvD,MAAM,8BAAc,IAAI,IAAY;CACpC,KAAK,MAAM,KAAK,IAAI,cAAc;EAChC,IAAI,EAAE,UAAU,WAAW;GACzB,IAAI,YAAY,IAAI,SAAS,GAC3B;GAEF,YAAY,IAAI,SAAS;GACzB;EACF;EACA,MAAM,KAAK,WAAW,EAAE,MAAM,KAAK,aAAa,EAAE,IAAI,GAAG;CAC3D;CAKA,IAAI,IAAI,WAAW,KAAA,GAAW;EAC5B,MAAM,YAAY,OAAO,UAAU,IAAI,MAAM,IACzC,IAAI,OAAO,QAAQ,CAAC,IACpB,OAAO,IAAI,MAAM;EACrB,MAAM,KAAK,YAAY,WAAW;CACpC;CAGA,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,IAAI,IAAI,GAChD,MAAM,KAAK,KAAK,UAAU,KAAK,KAAK,GAAG;CAIzC,IAAI,IAAI,MAAM;EACZ,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,IAAI,IAAI;CACrB,OAAO;EACL,MAAM,KAAK,EAAE;EACb,MAAM,KAAK,qCAAqC;CAClD;CAEA,MAAM,KAAK,KAAK;CAChB,MAAM,KAAK,EAAE;CAEb,OAAO,MAAM,KAAK,IAAI;AACxB;;AAGA,SAAS,UAAU,KAAa,OAAwB;CACtD,IAAI,UAAU,QAAQ,UAAU,KAAA,GAC9B,OAAO,OAAO,IAAI;CAGpB,IAAI,MAAM,QAAQ,KAAK,GAGrB,OAAO,OAAO,IAAI,KADJ,MAAM,KAAK,MAAe,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IACpC,EAAE;CAG/B,IAAI,OAAO,UAAU,WACnB,OAAO,OAAO,IAAI,IAAI;CAGxB,IAAI,OAAO,UAAU,UACnB,OAAO,OAAO,IAAI,IAAI,aAAa,KAAK;CAI1C,OAAO,OAAO,IAAI,IAAI,KAAK,UAAU,KAAK;AAC5C;;;;;;;;AC/GA,SAAgB,kBACd,UACA,SACQ;CACR,MAAM,QAAkB,CAAC;CACzB,MAAM,OAAO,SAAS;CAGtB,MAAM,KAAK,SAAS,SAAS,MAAM;CAGnC,IAAI,SAAS,OACX,MAAM,KAAK,UAAU,SAAS,OAAO;CAGvC,MAAM,aAAa,MAAM,cAAc,SAAS;CAChD,IAAI,YACF,MAAM,KAAK,eAAe,YAAY;CAGxC,MAAM,YAAY,MAAM,aAAa,SAAS;CAC9C,IAAI,WACF,MAAM,KAAK,cAAc,WAAW;CAGtC,MAAM,UAAU,MAAM,WAAW,SAAS;CAC1C,IAAI,SACF,MAAM,KAAK,YAAY,SAAS;CAGlC,IAAI,SAAS,SACX,MAAM,KAAK,YAAY,SAAS,SAAS;CAI3C,MAAM,UAAU,MAAM,WAAW,SAAS;CAC1C,IAAI,SACF,MAAM,KAAK,aAAa,QAAQ,EAAE;CAIpC,MAAM,gBAAgB,SAAS,iBAAiB;CAChD,MAAM,KAAK,oBAAoB,cAAc,EAAE;CAG/C,IAAI,SAAS,YAAY,SAAS,SAAS,SAAS,GAAG;EACrD,MAAM,KAAK,WAAW;EACtB,KAAK,MAAM,WAAW,SAAS,UAAU;GACvC,MAAM,UAAoB,CAAC;GAC3B,IAAI,QAAQ,cACV,QAAQ,KAAK,oBAAoB,QAAQ,cAAc;GAEzD,IAAI,QAAQ,gBACV,QAAQ,KAAK,sBAAsB,QAAQ,gBAAgB;GAE7D,IAAI,QAAQ,UACV,QAAQ,KAAK,eAAe,QAAQ,UAAU;GAEhD,IAAI,QAAQ,SACV,QAAQ,KAAK,cAAc,QAAQ,SAAS;GAE9C,IAAI,QAAQ,SAAS,GAAG;IACtB,MAAM,KAAK,KAAK,QAAQ,EAAE,CAAE,UAAU,GAAG;IACzC,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAClC,MAAM,KAAK,QAAQ,EAAG;GAE1B;EACF;CACF;CAGA,IAAI,SAAS,WAAW,SAAS,QAAQ,SAAS,GAAG;EACnD,MAAM,KAAK,UAAU;EACrB,KAAK,MAAM,OAAO,SAAS,SAAS;GAClC,MAAM,UAAoB,CAAC;GAC3B,IAAI,IAAI,MAAM,QAAQ,KAAK,SAAS,IAAI,MAAM;GAC9C,IAAI,IAAI,KAAK,QAAQ,KAAK,QAAQ,IAAI,KAAK;GAC3C,IAAI,IAAI,KAAK,QAAQ,KAAK,QAAQ,IAAI,KAAK;GAC3C,IAAI,IAAI,MAAM,QAAQ,KAAK,SAAS,IAAI,MAAM;GAC9C,IAAI,IAAI,QAAQ,QAAQ,KAAK,WAAW,IAAI,QAAQ;GACpD,IAAI,IAAI,YAAY,QAAQ,KAAK,eAAe,IAAI,YAAY;GAChE,IAAI,IAAI,aAAa,QAAQ,KAAK,gBAAgB,IAAI,aAAa;GACnE,IAAI,QAAQ,SAAS,GAAG;IACtB,MAAM,KAAK,KAAK,QAAQ,IAAI;IAC5B,KAAK,IAAI,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAClC,MAAM,KAAK,KAAK,QAAQ,IAAI;GAEhC;EACF;CACF;CAGA,IAAI,SAAS,UAAU,SAAS,OAAO,SAAS,GAAG;EACjD,MAAM,KAAK,SAAS;EACpB,KAAK,MAAM,SAAS,SAAS,QAC3B,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,GAC7C,MAAM,KAAK,KAAK,IAAI,IAAI,gBAAgB,KAAK,GAAG;CAGtD;CAEA,MAAM,KAAK,EAAE;CACb,OAAO,MAAM,KAAK,IAAI;AACxB;;AAGA,SAAS,gBAAgB,OAAwB;CAC/C,IAAI,OAAO,UAAU,WAAW,OAAO,OAAO,KAAK;CACnD,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO,KAAK;CAClD,IAAI,OAAO,UAAU,UAAU,OAAO;CACtC,OAAO,KAAK,UAAU,KAAK;AAC7B;;;;;;;;;AC5GA,SAAgB,sBACd,UACA,SACe;CACf,MAAM,YAAY,kBAAkB,UAAU,OAAO;CACrD,MAAM,2BAAW,IAAI,IAAoB;CAEzC,IAAI,SAAS,aAAa,WAAW,GACnC,OAAO;EAAE;EAAW;CAAS;CAG/B,IAAI,SAAS,YAAY;EAEvB,MAAM,QAAQ,SAAS,aAAa,KAAK,QAA6B,oBAAoB,GAAG,CAAC;EAC9F,SAAS,IAAI,wBAAwB,MAAM,KAAK,IAAI,CAAC;CACvD,OAEE,KAAK,MAAM,OAAO,SAAS,cAAc;EAEvC,MAAM,WAAW,YADF,IAAI,GAAG,QAAQ,SAAS,EAAE,CAAC,CAAC,QAAQ,UAAU,EAAE,KAAK,UAChC;EACpC,SAAS,IAAI,UAAU,oBAAoB,GAAG,CAAC;CACjD;CAGF,OAAO;EAAE;EAAW;CAAS;AAC/B;;;;;;;;;;;;;;;;ACnBA,SAAgB,iBACd,SACA,UACA,QACqB;CACrB,MAAM,SAA8B;EAElC,IAAI,SAAS;EAGb,OAAO,WAAW,YAAY,QAAQ,QAAQ,SAAS;EACvD,QAAQ,WAAW,YAAY,QAAQ,SAAS,SAAS;EACzD,UAAU,WAAW,YAAY,QAAQ,WAAW,SAAS;EAG7D,MAAM,UAAU,QAAQ,MAAM,SAAS,MAAM,MAAM;EACnD,cAAc,kBAAkB,QAAQ,cAAc,SAAS,cAAc,MAAM;EACnF,MAAM,UAAU,QAAQ,MAAM,SAAS,MAAM,MAAM;EAGnD,MAAM,WAAW,aACb,SAAS,OACR,QAAQ,QAAQ,SAAS;EAG9B,gBAAgB,WAAW,YAAY,QAAQ,iBAAiB,SAAS;CAC3E;CAGA,IAAI,OAAO,SAAS,KAAA,GAAW,OAAO,OAAO;CAC7C,IAAI,OAAO,aAAa,KAAA,GAAW,OAAO,OAAO;CACjD,IAAI,OAAO,mBAAmB,KAAA,GAAW,OAAO,OAAO;CACvD,IAAI,OAAO,SAAS,KAAA,KAAa,OAAO,KAAK,WAAW,GAAG,OAAO,OAAO;CAEzE,OAAO;AACT;;;;;;;;AASA,SAAgB,UACd,SACA,UACA,QACqB;CACrB,IAAI,WAAW,YACb,OAAO,EAAE,GAAG,SAAS;CAGvB,MAAM,SAA8B,EAAE,GAAG,QAAQ;CAEjD,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,GAChD,IAAI,WAAW,WACT;MAAA,EAAE,OAAO,SACX,OAAO,OAAO;CAAA,OAIhB,OAAO,OAAO;CAIlB,OAAO;AACT;;;;;;;;AASA,SAAgB,kBACd,SACA,UACA,QACe;CACf,IAAI,WAAW,YACb,OAAO,CAAC,GAAG,QAAQ;CAGrB,MAAM,0BAAU,IAAI,IAAyB;CAC7C,MAAM,QAAkB,CAAC;CAGzB,KAAK,MAAM,KAAK,SAAS;EACvB,QAAQ,IAAI,EAAE,OAAO,CAAC;EACtB,MAAM,KAAK,EAAE,KAAK;CACpB;CAGA,KAAK,MAAM,KAAK,UACd,IAAI,QAAQ,IAAI,EAAE,KAAK,GACjB;MAAA,WAAW,WAEb,QAAQ,IAAI,EAAE,OAAO,CAAC;CAAA,OAEnB;EACL,QAAQ,IAAI,EAAE,OAAO,CAAC;EACtB,MAAM,KAAK,EAAE,KAAK;CACpB;CAGF,OAAO,MAAM,KAAI,UAAS,QAAQ,IAAI,KAAK,CAAE;AAC/C;;;;;;;;AASA,SAAgB,UACd,SACA,UACA,QACyB;CACzB,IAAI,WAAW,WACb,OAAO,UAAU,CAAC,GAAG,OAAO,IAAI,KAAA;CAElC,IAAI,WAAW,YACb,OAAO,WAAW,CAAC,GAAG,QAAQ,IAAI,KAAA;CAIpC,IAAI,CAAC,WAAW,CAAC,UAAU,OAAO,KAAA;CAElC,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,SAAsB,CAAC;CAE7B,MAAM,UAAU,MAAuB;EACrC,MAAM,MAAM,KAAK,UAAU,CAAC;EAC5B,IAAI,CAAC,KAAK,IAAI,GAAG,GAAG;GAClB,KAAK,IAAI,GAAG;GACZ,OAAO,KAAK,CAAC;EACf;CACF;CAEA,IAAI,SAAS,QAAQ,QAAQ,MAAM;CACnC,IAAI,UAAU,SAAS,QAAQ,MAAM;CAErC,OAAO,OAAO,SAAS,IAAI,SAAS,KAAA;AACtC;;;;;;;;;;;;;ACnJA,SAAgB,gBACd,iBACA,kBACA,aACA,MACe;CACf,MAAM,SAAS,MAAM;CAGrB,MAAM,8BAAc,IAAI,IAAwB;CAChD,KAAK,MAAM,MAAM,aAEf,IAAI,CADa,YAAY,IAAI,GAAG,KACxB,KAAK,GAAG,iBAAiB,WACnC,YAAY,IAAI,GAAG,OAAO,EAAE;CAKhC,MAAM,8BAAc,IAAI,IAAiC;CACzD,KAAK,MAAM,OAAO,gBAAgB,cAChC,YAAY,IAAI,IAAI,IAAI,GAAG;CAI7B,MAAM,oCAAoB,IAAI,IAAY;CAG1C,MAAM,aAAoC,CAAC;CAC3C,KAAK,MAAM,SAAS,iBAAiB,cAAc;EACjD,MAAM,OAAO,YAAY,IAAI,MAAM,EAAE;EACrC,IAAI,QAAQ,KAAK,OAAO;GACtB,MAAM,SAAS,YAAY,IAAI,KAAK,KAAK;GACzC,IAAI,QAAQ;IACV,kBAAkB,IAAI,KAAK,KAAK;IAGhC,MAAM,mBAAmB,MAAM,SAC3B;KAAE,GAAG;KAAQ,MAAM,KAAA;IAAU,IAC7B;IAEJ,WAAW,KAAK,iBAAiB,kBAAkB,OAAO,MAAM,CAAC;IACjE;GACF;EACF;EAEA,WAAW,KAAK,KAAK;CACvB;CAKA,IAAI,MAAM,eACH;OAAA,MAAM,UAAU,gBAAgB,cACnC,IAAI,CAAC,kBAAkB,IAAI,OAAO,EAAE,GAClC,WAAW,KAAK,MAAM;CAAA;CAM5B,MAAM,mBAAgC;EACpC,GAAG;EACH,cAAc;CAChB;CAKA,MAAM,SAAwB;EAC5B,UAAU;EACV;EACA,YALiB,kBAAkB,aAAa,gBAAgB,aAAa,QAAQ,iBAAiB,aAAa,MAK1G;CACX;CAGA,MAAM,eAAe,MAAM,gBAAgB;CAC3C,IAAI,iBAAiB,YAAY,iBAAiB,UAAU,iBAAiB,IAC3E,OAAO,UAAU,4BAA4B,kBAAkB,IAAI;CAGrE,OAAO;AACT;;;;;;AAOA,SAAgB,cACd,aACA,aACA,YACA,MACA,iBACa;CAUb,MAAM,SAAS,gBAAgB;EAN7B,MAAM;EACN,cAHkB,4BAA4B,aAAa,UAGnC;EACxB,QAAQ,CAAC;EACT,UAAU,CAAC;CAGgC,GAAG,aAAa,aAAa,IAAI;CAG9E,OAAO,WAAW,oBAAoB,mBAAmB;CAEzD,OAAO;AACT;AAEA,SAAS,4BACP,aACA,YACuB;CACvB,MAAM,uBAAO,IAAI,IAAY;CAC7B,MAAM,OAA8B,CAAC;CAErC,KAAK,MAAM,MAAM,aAAa;EAC5B,IAAI,CAAC,GAAG,SAAS,KAAK,IAAI,GAAG,KAAK,GAAG;EACrC,KAAK,IAAI,GAAG,KAAK;EAEjB,MAAM,MAA2B;GAC/B,IAAI,GAAG;GACP,QAAQ;GACR,MAAM,CAAC;GACP,cAAc,CAAC;IAAE,OAAO;IAAW,MAAM;GAAG,CAAC;EAC/C;EACA,MAAM,OAAO,WAAW,IAAI,GAAG,KAAK;EACpC,IAAI,MACF,IAAI,OAAO;EAEb,KAAK,KAAK,GAAG;CACf;CACA,OAAO;AACT;AAEA,SAAS,4BAA4B,UAAuB,MAAsC;CAChG,MAAM,2BAAW,IAAI,IAAoB;CACzC,MAAM,WAAqB,CAAC;CAE5B,KAAK,MAAM,OAAO,SAAS,cAAc;EACvC,MAAM,OAAO,oBAAoB,GAAG;EAEpC,IAAI,MAAM,YACR,SAAS,KAAK,IAAI;OACb;GACL,MAAM,SAAS,IAAI,GAAG,QAAQ,SAAS,EAAE,CAAC,CAAC,QAAQ,UAAU,EAAE,KAAK;GACpE,SAAS,IAAI,YAAY,OAAO,MAAM,IAAI;EAC5C;CACF;CAEA,IAAI,MAAM,cAAc,SAAS,SAAS,GACxC,SAAS,IAAI,wBAAwB,SAAS,KAAK,IAAI,CAAC;CAS1D,OAAO;EAAE,WANS,kBAAkB,UAAU;GAC5C,YAAY,MAAM;GAClB,UAAU,MAAM;GAChB,eAAe,MAAM;EACvB,CAEiB;EAAG;CAAS;AAC/B;AAEA,SAAS,kBAAkB,aAA2B,iBAAyB,iBAA0C;CACvH,IAAI,QAAQ;CACZ,IAAI,cAAc;CAClB,IAAI,WAAW;CACf,IAAI,UAAU;CAEd,KAAK,MAAM,MAAM,aACf,IAAI,GAAG,iBAAiB,WACtB;MACK,IAAI,GAAG,iBAAiB,YAC7B;MACK,IAAI,GAAG,mBACZ;MAEA;CAIJ,OAAO;EACL,mBAAmB;EACnB,mBAAmB;EACnB,qBAAqB,QAAQ,cAAc;EAC3C;EACA;EACA;EACA;CACF;AACF;;;;;;ACrMA,SAAgB,kBAAkB,QAAsC;CACtE,OAAO,EACL,OAAO,OAAO,YAChB;AACF;;;;AAKA,SAAS,kBAAkB,IAAwB;CACjD,MAAM,iBAAiB,GAAG,aAAa,IAAA,CAAK,QAAQ,CAAC,IAAI;CACzD,QAAQ,GAAG,aAAX;EACE,KAAK,oBACH,OAAO,sBAAsB,GAAG,OAAO,IAAI,KAAK,GAAG,aAAa;EAClE,KAAK,kBACH,OAAO,qCAAqC,cAAc,KAAK,GAAG,aAAa;EACjF,KAAK,oBACH,OAAO,kCAAkC,cAAc,KAAK,GAAG,aAAa;EAC9E,KAAK,WACH,OAAO,aAAa,GAAG,aAAa;EACtC,KAAK,YACH,OAAO,cAAc,GAAG,aAAa;EACvC,KAAK,cACH,OAAO,2BAA2B,cAAc,KAAK,GAAG,aAAa;EACvE,KAAK,QACH,OAAO;EACT,SACE,OAAO,GAAG,GAAG,YAAY,IAAI,GAAG,aAAa;CACjD;AACF;;;;;;AAOA,SAAgB,sBAAsB,QAA6B;CACjE,MAAM,QAAkB,CAAC;CACzB,MAAM,QAAQ,OAAO;CAGrB,IAAI,OAAO,YAAY,SAAS,GAAG;EACjC,MAAM,KAAK,6FAA6F;EACxG,MAAM,KAAK,6BAA8B;EACzC,KAAK,MAAM,MAAM,OAAO,aACtB,IAAI,GAAG,iBAAiB,cAAc,GAAG,OACvC,MAAM,KAAK,QAAQ,GAAG,MAAM,MAAM,GAAG,OAAO;EAIhD,MAAM,cAAc,MAAM;EAC1B,MAAM,KAAK,2BAA2B,aAAa;EACnD,MAAM,KAAK,EAAE;CACf;CAGA,MAAM,KAAK,4CAA4C;CACvD,MAAM,KAAK,wCAAwC,MAAM,mBAAmB;CAC5E,MAAM,KAAK,wCAAwC,MAAM,mBAAmB;CAC5E,MAAM,KAAK,EAAE;CAGb,MAAM,KAAK,4CAA4C;CACvD,MAAM,KAAK,wCAAwC,MAAM,OAAO;CAChE,MAAM,KAAK,wCAAwC,MAAM,aAAa;CACtE,MAAM,KAAK,wCAAwC,MAAM,UAAU;CACnE,MAAM,KAAK,wCAAwC,MAAM,SAAS;CAClE,MAAM,KAAK,EAAE;CAGb,MAAM,KAAK,qEAAqE;CAChF,MAAM,cAAc,MAAM;CAC1B,MAAM,mBAAoB,MAAM,QAAQ,MAAM,cAAc,MAAM,aAAc;CAChF,MAAM,iBAAkB,cAAc,MAAM,YAAa,MAAM;CAC/D,MAAM,KAAK,yDAAyD,MAAM,MAAM,GAAG,MAAM,YAAY,GAAG,MAAM,SAAS,GAAG,YAAY,IAAI,kBAAkB;CAC5J,MAAM,KAAK,+CAA+C,YAAY,GAAG,MAAM,QAAQ,GAAG,cAAc,MAAM,QAAQ,IAAI,gBAAgB;CAC1I,MAAM,KAAK,EAAE;CAGb,IAAI,OAAO,YAAY,SAAS,GAAG;EACjC,MAAM,KAAK,6EAA6E;EACxF,KAAK,MAAM,MAAM,OAAO,aACtB,IAAI,GAAG,OAAO;GACZ,MAAM,KAAK,KAAK,GAAG,MAAM,OAAO,GAAG,OAAO;GAC1C,MAAM,KAAK,yBAAyB,kBAAkB,EAAE,GAAG;EAC7D,OACE,MAAM,KAAK,gBAAgB,GAAG,MAAM,aAAa;EAGrD,MAAM,KAAK,EAAE;CACf;CAEA,OAAO,MAAM,KAAK,IAAI;AACxB"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mitre/hdf-generators",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.0-next.42532249979.1",
|
|
4
4
|
"description": "Generate InSpec profile stubs from HDF Baseline definitions",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -25,10 +25,10 @@
|
|
|
25
25
|
"author": "MITRE Corporation",
|
|
26
26
|
"license": "Apache-2.0",
|
|
27
27
|
"dependencies": {
|
|
28
|
-
"@mitre/hdf-schema": "
|
|
28
|
+
"@mitre/hdf-schema": "3.8.0-next.42532249979.1"
|
|
29
29
|
},
|
|
30
30
|
"devDependencies": {
|
|
31
|
-
"@mitre/hdf-fixtures": "^3.
|
|
31
|
+
"@mitre/hdf-fixtures": "^3.8.0-next.42532249979.1"
|
|
32
32
|
},
|
|
33
33
|
"engines": {
|
|
34
34
|
"node": ">=24.0.0"
|