@zuplo/cli 6.63.4 → 6.63.6
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/cmds/mtls-certificates/create.js +8 -8
- package/dist/cmds/mtls-certificates/create.js.map +1 -1
- package/dist/cmds/mtls-certificates/disable.d.ts +9 -0
- package/dist/cmds/mtls-certificates/disable.d.ts.map +1 -0
- package/dist/cmds/mtls-certificates/disable.js +57 -0
- package/dist/cmds/mtls-certificates/disable.js.map +1 -0
- package/dist/cmds/mtls-certificates/index.d.ts.map +1 -1
- package/dist/cmds/mtls-certificates/index.js +2 -0
- package/dist/cmds/mtls-certificates/index.js.map +1 -1
- package/dist/cmds/mtls-certificates/update.js +8 -8
- package/dist/cmds/mtls-certificates/update.js.map +1 -1
- package/dist/cmds/open-api/overlay.js +1 -1
- package/dist/cmds/open-api/overlay.js.map +1 -1
- package/dist/common/open-api/constants.d.ts +13 -0
- package/dist/common/open-api/constants.d.ts.map +1 -0
- package/dist/common/open-api/constants.js +16 -0
- package/dist/common/open-api/constants.js.map +1 -0
- package/dist/common/open-api/index.d.ts +3 -0
- package/dist/common/open-api/index.d.ts.map +1 -0
- package/dist/common/open-api/index.js +3 -0
- package/dist/common/open-api/index.js.map +1 -0
- package/dist/common/open-api/validation.d.ts +297 -0
- package/dist/common/open-api/validation.d.ts.map +1 -0
- package/dist/common/open-api/validation.js +88 -0
- package/dist/common/open-api/validation.js.map +1 -0
- package/dist/deploy/handler.js +3 -2
- package/dist/deploy/handler.js.map +1 -1
- package/dist/mtls-certificates/create/handler.js +1 -1
- package/dist/mtls-certificates/create/handler.js.map +1 -1
- package/dist/mtls-certificates/describe/handler.js +3 -3
- package/dist/mtls-certificates/describe/handler.js.map +1 -1
- package/dist/mtls-certificates/disable/handler.d.ts +3 -0
- package/dist/mtls-certificates/disable/handler.d.ts.map +1 -0
- package/dist/mtls-certificates/disable/handler.js +32 -0
- package/dist/mtls-certificates/disable/handler.js.map +1 -0
- package/dist/mtls-certificates/list/handler.js +3 -3
- package/dist/mtls-certificates/list/handler.js.map +1 -1
- package/dist/mtls-certificates/models.d.ts +8 -2
- package/dist/mtls-certificates/models.d.ts.map +1 -1
- package/dist/mtls-certificates/models.js.map +1 -1
- package/dist/mtls-certificates/update/handler.js +2 -2
- package/dist/mtls-certificates/update/handler.js.map +1 -1
- package/dist/open-api/merge/merge-engine.d.ts +2 -5
- package/dist/open-api/merge/merge-engine.d.ts.map +1 -1
- package/dist/open-api/merge/merge-engine.js +2 -1
- package/dist/open-api/merge/merge-engine.js.map +1 -1
- package/dist/open-api/merge/utils.d.ts +0 -1
- package/dist/open-api/merge/utils.d.ts.map +1 -1
- package/dist/open-api/merge/utils.js +2 -11
- package/dist/open-api/merge/utils.js.map +1 -1
- package/dist/open-api/overlay/handler.d.ts.map +1 -1
- package/dist/open-api/overlay/handler.js +33 -33
- package/dist/open-api/overlay/handler.js.map +1 -1
- package/dist/open-api/overlay/overlay-engine.d.ts +20 -30
- package/dist/open-api/overlay/overlay-engine.d.ts.map +1 -1
- package/dist/open-api/overlay/overlay-engine.js +75 -46
- package/dist/open-api/overlay/overlay-engine.js.map +1 -1
- package/dist/open-api/overlay/overlay-engine.spec.js +109 -31
- package/dist/open-api/overlay/overlay-engine.spec.js.map +1 -1
- package/dist/source/migrate/dev-portal/handler.d.ts.map +1 -1
- package/dist/source/migrate/dev-portal/handler.js +48 -1
- package/dist/source/migrate/dev-portal/handler.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -5
|
@@ -3,41 +3,26 @@ import path from "node:path";
|
|
|
3
3
|
import { detectFormatFromExtension, parseFile, serializeContent, } from "../../common/file-format.js";
|
|
4
4
|
import { printDiagnosticsToConsole } from "../../common/output.js";
|
|
5
5
|
import { logger } from "../../common/logger.js";
|
|
6
|
-
import { applyOverlay as applyOverlayEngine
|
|
6
|
+
import { applyOverlay as applyOverlayEngine } from "./overlay-engine.js";
|
|
7
7
|
function applyOverlayWithProgress(openapi, overlay) {
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
try {
|
|
16
|
-
const { applied, count } = applyAction(result, action);
|
|
17
|
-
if (applied) {
|
|
18
|
-
printDiagnosticsToConsole(`✓ (${count} node${count !== 1 ? "s" : ""})`);
|
|
19
|
-
stats.applied++;
|
|
20
|
-
stats.totalNodes += count;
|
|
21
|
-
}
|
|
22
|
-
else {
|
|
23
|
-
printDiagnosticsToConsole("⊘ skipped");
|
|
24
|
-
stats.skipped++;
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
catch (error) {
|
|
28
|
-
printDiagnosticsToConsole(`✗ failed`);
|
|
29
|
-
logger.warn(error, `Failed to apply action: ${desc}`);
|
|
30
|
-
stats.skipped++;
|
|
8
|
+
let validatedOverlay;
|
|
9
|
+
try {
|
|
10
|
+
validatedOverlay = applyOverlayEngine(openapi, overlay);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error instanceof Error) {
|
|
14
|
+
printDiagnosticsToConsole(`\n${error.message}`);
|
|
31
15
|
}
|
|
16
|
+
throw error;
|
|
32
17
|
}
|
|
18
|
+
const { result, stats } = validatedOverlay;
|
|
33
19
|
printDiagnosticsToConsole(`\n=== Summary ===`);
|
|
34
|
-
printDiagnosticsToConsole(`Applied: ${stats.applied}
|
|
35
|
-
printDiagnosticsToConsole(`Modified: ${stats.totalNodes}
|
|
20
|
+
printDiagnosticsToConsole(`Applied: ${stats.applied} action${stats.applied !== 1 ? "s" : ""}`);
|
|
21
|
+
printDiagnosticsToConsole(`Modified: ${stats.totalNodes} node${stats.totalNodes !== 1 ? "s" : ""}`);
|
|
36
22
|
if (stats.skipped > 0) {
|
|
37
|
-
printDiagnosticsToConsole(`Skipped: ${stats.skipped}
|
|
23
|
+
printDiagnosticsToConsole(`Skipped: ${stats.skipped} action${stats.skipped !== 1 ? "s" : ""}`);
|
|
38
24
|
}
|
|
39
|
-
|
|
40
|
-
return finalResult;
|
|
25
|
+
return result;
|
|
41
26
|
}
|
|
42
27
|
export async function applyOverlay(args) {
|
|
43
28
|
const openapiPath = path.resolve(args.input);
|
|
@@ -57,10 +42,25 @@ export async function applyOverlay(args) {
|
|
|
57
42
|
try {
|
|
58
43
|
const openapiContent = fs.readFileSync(openapiPath, "utf-8");
|
|
59
44
|
const overlayContent = fs.readFileSync(overlayPath, "utf-8");
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
45
|
+
let openapi;
|
|
46
|
+
let overlay;
|
|
47
|
+
try {
|
|
48
|
+
const parsed = parseFile(openapiContent, openapiPath);
|
|
49
|
+
openapi = parsed.document;
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
throw new Error(`Failed to parse OpenAPI file '${openapiPath}'`, {
|
|
53
|
+
cause: error,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
const parsed = parseFile(overlayContent, overlayPath);
|
|
58
|
+
overlay = parsed.document;
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
throw new Error(`Failed to parse overlay file '${overlayPath}'`, {
|
|
62
|
+
cause: error,
|
|
63
|
+
});
|
|
64
64
|
}
|
|
65
65
|
const result = applyOverlayWithProgress(openapi, overlay);
|
|
66
66
|
let outputFormat;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/open-api/overlay/handler.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,yBAAyB,EACzB,SAAS,EACT,gBAAgB,GAEjB,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wBAAwB,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAChD,OAAO,
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../../src/open-api/overlay/handler.ts"],"names":[],"mappings":"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","sourcesContent":["/** biome-ignore-all lint/suspicious/noConsole: CLI output file */\nimport fs from \"node:fs\";\nimport path from \"node:path\";\nimport {\n detectFormatFromExtension,\n parseFile,\n serializeContent,\n type FileFormat,\n} from \"../../common/file-format.js\";\nimport { printDiagnosticsToConsole } from \"../../common/output.js\";\nimport { logger } from \"../../common/logger.js\";\nimport { applyOverlay as applyOverlayEngine } from \"./overlay-engine.js\";\n\nexport interface Arguments {\n overlay: string;\n input: string;\n output: string;\n format?: \"json\" | \"yaml\";\n json?: boolean;\n yaml?: boolean;\n}\n\n/**\n * Apply overlay to OpenAPI document with console output\n * Validates inputs and provides progress feedback\n */\nfunction applyOverlayWithProgress(\n openapi: unknown,\n overlay: unknown\n): Record<string, unknown> {\n // Apply overlay (includes validation)\n let validatedOverlay: ReturnType<typeof applyOverlayEngine>;\n\n try {\n validatedOverlay = applyOverlayEngine(openapi, overlay);\n } catch (error) {\n // Re-throw with better context for CLI users\n if (error instanceof Error) {\n printDiagnosticsToConsole(`\\n${error.message}`);\n }\n throw error;\n }\n\n const { result, stats } = validatedOverlay;\n\n // Show summary\n printDiagnosticsToConsole(`\\n=== Summary ===`);\n printDiagnosticsToConsole(\n `Applied: ${stats.applied} action${stats.applied !== 1 ? \"s\" : \"\"}`\n );\n printDiagnosticsToConsole(\n `Modified: ${stats.totalNodes} node${stats.totalNodes !== 1 ? \"s\" : \"\"}`\n );\n if (stats.skipped > 0) {\n printDiagnosticsToConsole(\n `Skipped: ${stats.skipped} action${stats.skipped !== 1 ? \"s\" : \"\"}`\n );\n }\n\n return result;\n}\n\n/**\n * Main handler function\n */\nexport async function applyOverlay(args: Arguments): Promise<void> {\n const openapiPath = path.resolve(args.input);\n const overlayPath = path.resolve(args.overlay);\n const outputPath = path.resolve(args.output);\n\n // Validate input files exist\n if (!fs.existsSync(openapiPath)) {\n throw new Error(`OpenAPI file not found: ${openapiPath}`);\n }\n\n if (!fs.existsSync(overlayPath)) {\n throw new Error(`Overlay file not found: ${overlayPath}`);\n }\n\n printDiagnosticsToConsole(\"OpenAPI Overlay Applicator\");\n printDiagnosticsToConsole(\"===========================\");\n printDiagnosticsToConsole(`OpenAPI file: ${openapiPath}`);\n printDiagnosticsToConsole(`Overlay file: ${overlayPath}`);\n printDiagnosticsToConsole(`Output file: ${outputPath}`);\n\n try {\n // Load files with flexible parsing\n const openapiContent = fs.readFileSync(openapiPath, \"utf-8\");\n const overlayContent = fs.readFileSync(overlayPath, \"utf-8\");\n\n // Parse with automatic format detection\n let openapi: unknown;\n let overlay: unknown;\n\n try {\n const parsed = parseFile(openapiContent, openapiPath);\n openapi = parsed.document;\n } catch (error) {\n throw new Error(`Failed to parse OpenAPI file '${openapiPath}'`, {\n cause: error,\n });\n }\n\n try {\n const parsed = parseFile(overlayContent, overlayPath);\n overlay = parsed.document;\n } catch (error) {\n throw new Error(`Failed to parse overlay file '${overlayPath}'`, {\n cause: error,\n });\n }\n\n // Apply overlay with progress output\n // Validation happens inside applyOverlayWithProgress\n const result = applyOverlayWithProgress(openapi, overlay);\n\n // Determine output format\n let outputFormat: FileFormat;\n if (args.format) {\n outputFormat = args.format;\n } else if (args.json) {\n outputFormat = \"json\";\n } else if (args.yaml) {\n outputFormat = \"yaml\";\n } else {\n // Try to detect from output file extension\n const formatFromExt = detectFormatFromExtension(outputPath);\n outputFormat = formatFromExt || \"json\"; // Default to JSON if no extension\n }\n\n // Serialize output\n const outputContent = serializeContent(result, outputFormat);\n\n // Create output directory if it doesn't exist\n const outputDir = path.dirname(outputPath);\n if (!fs.existsSync(outputDir)) {\n fs.mkdirSync(outputDir, { recursive: true });\n }\n\n fs.writeFileSync(outputPath, outputContent, \"utf-8\");\n\n printDiagnosticsToConsole(\n `\\n✓ Output written to: ${outputPath} (${outputFormat.toUpperCase()})`\n );\n } catch (error) {\n logger.error(error, \"Error applying overlay\");\n printDiagnosticsToConsole(`Error: ${(error as Error).message}`);\n throw error;\n }\n}\n"]}
|
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
};
|
|
7
|
-
actions: OverlayAction[];
|
|
8
|
-
extends?: string;
|
|
9
|
-
}
|
|
10
|
-
export interface OverlayAction {
|
|
11
|
-
target: string;
|
|
12
|
-
description?: string;
|
|
13
|
-
update?: any;
|
|
14
|
-
remove?: boolean | RemoveCondition;
|
|
15
|
-
}
|
|
16
|
-
export interface RemoveCondition {
|
|
17
|
-
empty?: boolean;
|
|
18
|
-
missing?: string;
|
|
19
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
type OverlayAction,
|
|
3
|
+
type OverlayDocument,
|
|
4
|
+
type RemoveCondition,
|
|
5
|
+
} from "../../common/open-api/index.js";
|
|
20
6
|
export interface ApplyResult {
|
|
21
7
|
applied: boolean;
|
|
22
8
|
count: number;
|
|
@@ -27,29 +13,33 @@ export interface OverlayStats {
|
|
|
27
13
|
totalNodes: number;
|
|
28
14
|
}
|
|
29
15
|
export declare function deepClone<T>(obj: T): T;
|
|
30
|
-
export declare function deepMerge(target:
|
|
16
|
+
export declare function deepMerge(target: unknown, source: unknown): unknown;
|
|
31
17
|
export declare function checkCondition(
|
|
32
|
-
value:
|
|
18
|
+
value: unknown,
|
|
33
19
|
condition: RemoveCondition
|
|
34
20
|
): boolean;
|
|
35
21
|
export declare function setValueAtPath(
|
|
36
|
-
doc:
|
|
22
|
+
doc: unknown,
|
|
37
23
|
target: string,
|
|
38
|
-
value:
|
|
24
|
+
value: unknown
|
|
39
25
|
): void;
|
|
40
26
|
export declare function applyAction(
|
|
41
|
-
doc:
|
|
27
|
+
doc: unknown,
|
|
42
28
|
action: OverlayAction
|
|
43
29
|
): ApplyResult;
|
|
44
30
|
export declare function extractPathOrder(overlay: OverlayDocument): string[];
|
|
45
|
-
export declare function reorderOperationProperties(
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
export declare function reorderOperationProperties(
|
|
32
|
+
operation: unknown
|
|
33
|
+
): Record<string, unknown>;
|
|
34
|
+
export declare function reorderPaths<T>(doc: T, pathOrder: string[]): T;
|
|
35
|
+
export declare function reorderDocumentProperties(
|
|
36
|
+
doc: unknown
|
|
37
|
+
): Record<string, unknown>;
|
|
48
38
|
export declare function applyOverlay(
|
|
49
|
-
openapi:
|
|
50
|
-
overlay:
|
|
39
|
+
openapi: unknown,
|
|
40
|
+
overlay: unknown
|
|
51
41
|
): {
|
|
52
|
-
result:
|
|
42
|
+
result: Record<string, unknown>;
|
|
53
43
|
stats: OverlayStats;
|
|
54
44
|
};
|
|
55
45
|
//# sourceMappingURL=overlay-engine.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-engine.d.ts","sourceRoot":"","sources":["../../../src/open-api/overlay/overlay-engine.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"overlay-engine.d.ts","sourceRoot":"","sources":["../../../src/open-api/overlay/overlay-engine.ts"],"names":[],"mappings":"AACA,OAAO,EAIL,KAAK,aAAa,EAClB,KAAK,eAAe,EACpB,KAAK,eAAe,EACrB,MAAM,gCAAgC,CAAC;AAExC,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAmBD,wBAAgB,SAAS,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,CAKtC;AAQD,wBAAgB,SAAS,CAAC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CA+DnE;AAKD,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,eAAe,GACzB,OAAO,CAgCT;AAyCD,wBAAgB,cAAc,CAC5B,GAAG,EAAE,OAAO,EACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,OAAO,GACb,IAAI,CAyCN;AAKD,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,aAAa,GAAG,WAAW,CA2F5E;AAMD,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,eAAe,GAAG,MAAM,EAAE,CAiBnE;AAMD,wBAAgB,0BAA0B,CACxC,SAAS,EAAE,OAAO,GACjB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBzB;AAMD,wBAAgB,YAAY,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,CAAC,CAkD9D;AAOD,wBAAgB,yBAAyB,CACvC,GAAG,EAAE,OAAO,GACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAoBzB;AAmBD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,OAAO,EAChB,OAAO,EAAE,OAAO,GACf;IAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAAC,KAAK,EAAE,YAAY,CAAA;CAAE,CA6B1D"}
|
|
@@ -1,4 +1,11 @@
|
|
|
1
1
|
import { JSONPath } from "jsonpath-plus";
|
|
2
|
+
import { HTTP_METHODS, validateOpenApiDocument, validateOverlayDocument, } from "../../common/open-api/index.js";
|
|
3
|
+
function toRecord(value, context) {
|
|
4
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
5
|
+
throw new Error(`Expected object at ${context}, but got ${Array.isArray(value) ? "array" : typeof value}`);
|
|
6
|
+
}
|
|
7
|
+
return value;
|
|
8
|
+
}
|
|
2
9
|
export function deepClone(obj) {
|
|
3
10
|
if (typeof structuredClone === "function") {
|
|
4
11
|
return structuredClone(obj);
|
|
@@ -17,11 +24,22 @@ export function deepMerge(target, source) {
|
|
|
17
24
|
return deepClone(source);
|
|
18
25
|
}
|
|
19
26
|
if (source.length > 0 &&
|
|
20
|
-
source[0]
|
|
21
|
-
source[0]
|
|
27
|
+
typeof source[0] === "object" &&
|
|
28
|
+
source[0] !== null &&
|
|
29
|
+
"name" in source[0] &&
|
|
30
|
+
"in" in source[0]) {
|
|
22
31
|
const merged = [...target];
|
|
23
32
|
for (const sourceParam of source) {
|
|
24
|
-
|
|
33
|
+
if (typeof sourceParam !== "object" || sourceParam === null)
|
|
34
|
+
continue;
|
|
35
|
+
const existingIndex = merged.findIndex((p) => typeof p === "object" &&
|
|
36
|
+
p !== null &&
|
|
37
|
+
"name" in p &&
|
|
38
|
+
"in" in p &&
|
|
39
|
+
"name" in sourceParam &&
|
|
40
|
+
"in" in sourceParam &&
|
|
41
|
+
p.name === sourceParam.name &&
|
|
42
|
+
p.in === sourceParam.in);
|
|
25
43
|
if (existingIndex >= 0) {
|
|
26
44
|
merged[existingIndex] = deepMerge(merged[existingIndex], sourceParam);
|
|
27
45
|
}
|
|
@@ -33,8 +51,10 @@ export function deepMerge(target, source) {
|
|
|
33
51
|
}
|
|
34
52
|
return [...target, ...deepClone(source)];
|
|
35
53
|
}
|
|
36
|
-
const
|
|
37
|
-
|
|
54
|
+
const targetObj = target;
|
|
55
|
+
const sourceObj = source;
|
|
56
|
+
const result = { ...targetObj };
|
|
57
|
+
for (const [key, value] of Object.entries(sourceObj)) {
|
|
38
58
|
if (key in result) {
|
|
39
59
|
result[key] = deepMerge(result[key], value);
|
|
40
60
|
}
|
|
@@ -58,7 +78,10 @@ export function checkCondition(value, condition) {
|
|
|
58
78
|
const parts = condition.missing.split(".");
|
|
59
79
|
let current = value;
|
|
60
80
|
for (const part of parts) {
|
|
61
|
-
if (current &&
|
|
81
|
+
if (current &&
|
|
82
|
+
typeof current === "object" &&
|
|
83
|
+
!Array.isArray(current) &&
|
|
84
|
+
part in current) {
|
|
62
85
|
current = current[part];
|
|
63
86
|
}
|
|
64
87
|
else {
|
|
@@ -83,7 +106,7 @@ function extractBracketKey(bracketNotation) {
|
|
|
83
106
|
export function setValueAtPath(doc, target, value) {
|
|
84
107
|
const targetPath = target.replace(/^\$\./, "");
|
|
85
108
|
const parts = targetPath.match(JSONPATH_SEGMENT_PATTERN) || [];
|
|
86
|
-
let current = doc;
|
|
109
|
+
let current = toRecord(doc, "setValueAtPath document");
|
|
87
110
|
for (let i = 0; i < parts.length - 1; i++) {
|
|
88
111
|
const part = parts[i];
|
|
89
112
|
if (part.startsWith("[")) {
|
|
@@ -91,13 +114,15 @@ export function setValueAtPath(doc, target, value) {
|
|
|
91
114
|
if (!(key in current)) {
|
|
92
115
|
current[key] = {};
|
|
93
116
|
}
|
|
94
|
-
|
|
117
|
+
const next = current[key];
|
|
118
|
+
current = toRecord(next, `setValueAtPath at ${target}[${i}]`);
|
|
95
119
|
}
|
|
96
120
|
else {
|
|
97
121
|
if (!(part in current)) {
|
|
98
122
|
current[part] = {};
|
|
99
123
|
}
|
|
100
|
-
|
|
124
|
+
const next = current[part];
|
|
125
|
+
current = toRecord(next, `setValueAtPath at ${target}.${part}`);
|
|
101
126
|
}
|
|
102
127
|
}
|
|
103
128
|
const lastPart = parts[parts.length - 1];
|
|
@@ -110,9 +135,10 @@ export function setValueAtPath(doc, target, value) {
|
|
|
110
135
|
}
|
|
111
136
|
}
|
|
112
137
|
export function applyAction(doc, action) {
|
|
138
|
+
const docRecord = toRecord(doc, "applyAction document");
|
|
113
139
|
if (action.update) {
|
|
114
140
|
if (action.target === "$") {
|
|
115
|
-
Object.assign(
|
|
141
|
+
Object.assign(docRecord, deepMerge(doc, action.update));
|
|
116
142
|
return { applied: true, count: 1 };
|
|
117
143
|
}
|
|
118
144
|
try {
|
|
@@ -125,8 +151,12 @@ export function applyAction(doc, action) {
|
|
|
125
151
|
let count = 0;
|
|
126
152
|
for (const result of results) {
|
|
127
153
|
const { parent, parentProperty } = result;
|
|
128
|
-
if (parent &&
|
|
129
|
-
parent
|
|
154
|
+
if (parent &&
|
|
155
|
+
typeof parent === "object" &&
|
|
156
|
+
!Array.isArray(parent) &&
|
|
157
|
+
parentProperty !== undefined) {
|
|
158
|
+
const parentRecord = parent;
|
|
159
|
+
parentRecord[parentProperty] = deepMerge(parentRecord[parentProperty], action.update);
|
|
130
160
|
count++;
|
|
131
161
|
}
|
|
132
162
|
}
|
|
@@ -135,8 +165,8 @@ export function applyAction(doc, action) {
|
|
|
135
165
|
setValueAtPath(doc, action.target, action.update);
|
|
136
166
|
return { applied: true, count: 1 };
|
|
137
167
|
}
|
|
138
|
-
catch (
|
|
139
|
-
throw new Error(
|
|
168
|
+
catch (cause) {
|
|
169
|
+
throw new Error("Failed to apply update", { cause });
|
|
140
170
|
}
|
|
141
171
|
}
|
|
142
172
|
else if (action.remove) {
|
|
@@ -160,7 +190,7 @@ export function applyAction(doc, action) {
|
|
|
160
190
|
if (Array.isArray(parent)) {
|
|
161
191
|
parent.splice(parentProperty, 1);
|
|
162
192
|
}
|
|
163
|
-
else {
|
|
193
|
+
else if (typeof parent === "object" && parent !== null) {
|
|
164
194
|
delete parent[parentProperty];
|
|
165
195
|
}
|
|
166
196
|
count++;
|
|
@@ -168,8 +198,8 @@ export function applyAction(doc, action) {
|
|
|
168
198
|
}
|
|
169
199
|
return { applied: true, count };
|
|
170
200
|
}
|
|
171
|
-
catch (
|
|
172
|
-
throw new Error(
|
|
201
|
+
catch (cause) {
|
|
202
|
+
throw new Error("Failed to remove", { cause });
|
|
173
203
|
}
|
|
174
204
|
}
|
|
175
205
|
return { applied: false, count: 0 };
|
|
@@ -190,14 +220,15 @@ export function extractPathOrder(overlay) {
|
|
|
190
220
|
return pathOrder;
|
|
191
221
|
}
|
|
192
222
|
export function reorderOperationProperties(operation) {
|
|
223
|
+
const operationObj = toRecord(operation, "reorderOperationProperties");
|
|
193
224
|
const priorityKeys = ["summary", "description", "operationId"];
|
|
194
225
|
const reordered = {};
|
|
195
226
|
for (const key of priorityKeys) {
|
|
196
|
-
if (key in
|
|
197
|
-
reordered[key] =
|
|
227
|
+
if (key in operationObj) {
|
|
228
|
+
reordered[key] = operationObj[key];
|
|
198
229
|
}
|
|
199
230
|
}
|
|
200
|
-
for (const [key, value] of Object.entries(
|
|
231
|
+
for (const [key, value] of Object.entries(operationObj)) {
|
|
201
232
|
if (!priorityKeys.includes(key)) {
|
|
202
233
|
reordered[key] = value;
|
|
203
234
|
}
|
|
@@ -205,10 +236,14 @@ export function reorderOperationProperties(operation) {
|
|
|
205
236
|
return reordered;
|
|
206
237
|
}
|
|
207
238
|
export function reorderPaths(doc, pathOrder) {
|
|
208
|
-
if (
|
|
239
|
+
if (typeof doc !== "object" ||
|
|
240
|
+
doc === null ||
|
|
241
|
+
!("paths" in doc) ||
|
|
242
|
+
pathOrder.length === 0) {
|
|
209
243
|
return doc;
|
|
210
244
|
}
|
|
211
|
-
const
|
|
245
|
+
const docRecord = doc;
|
|
246
|
+
const originalPaths = toRecord(docRecord.paths, "paths");
|
|
212
247
|
const reorderedPaths = {};
|
|
213
248
|
for (const targetPath of pathOrder) {
|
|
214
249
|
if (targetPath in originalPaths) {
|
|
@@ -221,35 +256,30 @@ export function reorderPaths(doc, pathOrder) {
|
|
|
221
256
|
}
|
|
222
257
|
}
|
|
223
258
|
for (const pathItem of Object.values(reorderedPaths)) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
"trace",
|
|
233
|
-
];
|
|
234
|
-
for (const method of httpMethods) {
|
|
235
|
-
if (pathItem[method] &&
|
|
236
|
-
typeof pathItem[method] === "object") {
|
|
237
|
-
pathItem[method] = reorderOperationProperties(pathItem[method]);
|
|
259
|
+
if (typeof pathItem !== "object" || pathItem === null)
|
|
260
|
+
continue;
|
|
261
|
+
const pathItemRecord = pathItem;
|
|
262
|
+
for (const method of HTTP_METHODS) {
|
|
263
|
+
if (method in pathItemRecord &&
|
|
264
|
+
typeof pathItemRecord[method] === "object" &&
|
|
265
|
+
pathItemRecord[method] !== null) {
|
|
266
|
+
pathItemRecord[method] = reorderOperationProperties(pathItemRecord[method]);
|
|
238
267
|
}
|
|
239
268
|
}
|
|
240
269
|
}
|
|
241
|
-
|
|
270
|
+
docRecord.paths = reorderedPaths;
|
|
242
271
|
return doc;
|
|
243
272
|
}
|
|
244
273
|
export function reorderDocumentProperties(doc) {
|
|
274
|
+
const docObj = toRecord(doc, "reorderDocumentProperties");
|
|
245
275
|
const priorityKeys = ["openapi", "info", "tags"];
|
|
246
276
|
const reordered = {};
|
|
247
277
|
for (const key of priorityKeys) {
|
|
248
|
-
if (key in
|
|
249
|
-
reordered[key] =
|
|
278
|
+
if (key in docObj) {
|
|
279
|
+
reordered[key] = docObj[key];
|
|
250
280
|
}
|
|
251
281
|
}
|
|
252
|
-
for (const [key, value] of Object.entries(
|
|
282
|
+
for (const [key, value] of Object.entries(docObj)) {
|
|
253
283
|
if (!priorityKeys.includes(key)) {
|
|
254
284
|
reordered[key] = value;
|
|
255
285
|
}
|
|
@@ -257,12 +287,11 @@ export function reorderDocumentProperties(doc) {
|
|
|
257
287
|
return reordered;
|
|
258
288
|
}
|
|
259
289
|
export function applyOverlay(openapi, overlay) {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
const result = deepClone(openapi);
|
|
290
|
+
const validatedOverlay = validateOverlayDocument(overlay);
|
|
291
|
+
const validatedOpenApi = validateOpenApiDocument(openapi);
|
|
292
|
+
const result = deepClone(validatedOpenApi);
|
|
264
293
|
const stats = { applied: 0, skipped: 0, totalNodes: 0 };
|
|
265
|
-
for (const action of
|
|
294
|
+
for (const action of validatedOverlay.actions) {
|
|
266
295
|
const { applied, count } = applyAction(result, action);
|
|
267
296
|
if (applied) {
|
|
268
297
|
stats.applied++;
|
|
@@ -272,7 +301,7 @@ export function applyOverlay(openapi, overlay) {
|
|
|
272
301
|
stats.skipped++;
|
|
273
302
|
}
|
|
274
303
|
}
|
|
275
|
-
const pathOrder = extractPathOrder(
|
|
304
|
+
const pathOrder = extractPathOrder(validatedOverlay);
|
|
276
305
|
reorderPaths(result, pathOrder);
|
|
277
306
|
const reordered = reorderDocumentProperties(result);
|
|
278
307
|
return { result: reordered, stats };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"overlay-engine.js","sourceRoot":"","sources":["../../../src/open-api/overlay/overlay-engine.ts"],"names":[],"mappings":"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","sourcesContent":["/** biome-ignore-all lint/suspicious/noExplicitAny: Complex overlay algorithm working with dynamic JSON structures */\nimport { JSONPath } from \"jsonpath-plus\";\n\nexport interface OverlayDocument {\n overlay: string;\n info: {\n title: string;\n version: string;\n };\n actions: OverlayAction[];\n extends?: string;\n}\n\nexport interface OverlayAction {\n target: string;\n description?: string;\n update?: any;\n remove?: boolean | RemoveCondition;\n}\n\nexport interface RemoveCondition {\n empty?: boolean;\n missing?: string;\n}\n\nexport interface ApplyResult {\n applied: boolean;\n count: number;\n}\n\nexport interface OverlayStats {\n applied: number;\n skipped: number;\n totalNodes: number;\n}\n\n/**\n * Deep clone an object using structuredClone for better performance and correctness\n * Falls back to JSON parse/stringify for environments without structuredClone\n */\nexport function deepClone<T>(obj: T): T {\n if (typeof structuredClone === \"function\") {\n return structuredClone(obj);\n }\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Deep merge two objects\n * Special handling for OpenAPI parameters (merge by name+in)\n */\nexport function deepMerge(target: any, source: any): any {\n if (!source || typeof source !== \"object\") {\n return source;\n }\n\n if (!target || typeof target !== \"object\") {\n return deepClone(source);\n }\n\n if (Array.isArray(source)) {\n if (!Array.isArray(target)) {\n return deepClone(source);\n }\n\n // Special case for OpenAPI parameters - merge by name+in\n if (\n source.length > 0 &&\n source[0].name !== undefined &&\n source[0].in !== undefined\n ) {\n const merged = [...target];\n for (const sourceParam of source) {\n const existingIndex = merged.findIndex(\n (p) => p.name === sourceParam.name && p.in === sourceParam.in\n );\n if (existingIndex >= 0) {\n merged[existingIndex] = deepMerge(merged[existingIndex], sourceParam);\n } else {\n merged.push(deepClone(sourceParam));\n }\n }\n return merged;\n }\n\n // For other arrays, concatenate\n return [...target, ...deepClone(source)];\n }\n\n const result = { ...target };\n for (const [key, value] of Object.entries(source)) {\n if (key in result) {\n result[key] = deepMerge(result[key], value);\n } else {\n result[key] = deepClone(value);\n }\n }\n\n return result;\n}\n\n/**\n * Check if a condition is met for conditional removal\n */\nexport function checkCondition(\n value: any,\n condition: RemoveCondition\n): boolean {\n // Support \"empty\" condition to check if object has no keys\n if (condition.empty) {\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n return Object.keys(value).length === 0;\n }\n if (Array.isArray(value)) {\n return value.length === 0;\n }\n return false;\n }\n\n // Support \"missing\" condition to check if a property doesn't exist\n if (condition.missing) {\n const parts = condition.missing.split(\".\");\n let current = value;\n for (const part of parts) {\n if (current && typeof current === \"object\" && part in current) {\n current = current[part];\n } else {\n return true; // Property is missing\n }\n }\n return false; // Property exists\n }\n\n return false;\n}\n\n/**\n * Regular expression for parsing JSONPath segments\n * Matches: word, or [quoted], or ['quoted'], or [\"quoted\"], or numeric indices [0]\n */\nconst JSONPATH_SEGMENT_PATTERN = /[^.[]+|\\[[^\\]]+\\]/g;\n\n/**\n * Extract key from bracket notation, handling various formats:\n * - ['key'] -> key\n * - [\"key\"] -> key\n * - [key] -> key\n * - [0] -> 0 (as string for consistency)\n */\nfunction extractBracketKey(bracketNotation: string): string {\n const inner = bracketNotation.slice(1, -1); // Remove [ and ]\n\n // Handle single-quoted: ['key'] -> key\n if (inner.startsWith(\"'\") && inner.endsWith(\"'\")) {\n return inner.slice(1, -1);\n }\n\n // Handle double-quoted: [\"key\"] -> key\n if (inner.startsWith('\"') && inner.endsWith('\"')) {\n return inner.slice(1, -1);\n }\n\n // Handle unquoted: [key] or [0] -> key or 0\n return inner;\n}\n\n/**\n * Set a value at a JSONPath, creating parent paths as needed\n * Handles patterns like:\n * $.paths['/route'].method\n * $.components.parameters['name']\n * $.paths[\"/users\"].get\n * $.paths[users].get\n * $.items[0].value\n */\nexport function setValueAtPath(doc: any, target: string, value: any): void {\n // Parse the path manually to handle both bracket and dot notation\n // Example: $.paths['/route'].post -> [\"paths\", \"['/route']\", \"post\"]\n\n // Remove leading $.\n const targetPath = target.replace(/^\\$\\./, \"\");\n\n // Split by dots, but keep bracket notation together\n const parts = targetPath.match(JSONPATH_SEGMENT_PATTERN) || [];\n\n let current = doc;\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n\n // Handle bracket notation\n if (part.startsWith(\"[\")) {\n const key = extractBracketKey(part);\n if (!(key in current)) {\n current[key] = {};\n }\n current = current[key];\n } else {\n // Handle regular property\n if (!(part in current)) {\n current[part] = {};\n }\n current = current[part];\n }\n }\n\n // Set the final value\n const lastPart = parts[parts.length - 1];\n if (lastPart.startsWith(\"[\")) {\n const key = extractBracketKey(lastPart);\n current[key] = value;\n } else {\n current[lastPart] = value;\n }\n}\n\n/**\n * Apply a single overlay action to the document\n */\nexport function applyAction(doc: any, action: OverlayAction): ApplyResult {\n if (action.update) {\n // Handle root level updates specially\n if (action.target === \"$\") {\n Object.assign(doc, deepMerge(doc, action.update));\n return { applied: true, count: 1 };\n }\n\n try {\n // Try to find existing nodes\n const results = JSONPath({\n path: action.target,\n json: doc,\n resultType: \"all\",\n });\n\n if (results.length > 0) {\n // Path exists, merge the update\n let count = 0;\n for (const result of results) {\n const { parent, parentProperty } = result;\n if (parent && parentProperty !== undefined) {\n parent[parentProperty] = deepMerge(\n parent[parentProperty],\n action.update\n );\n count++;\n }\n }\n return { applied: true, count };\n }\n\n // Path doesn't exist, create it manually\n setValueAtPath(doc, action.target, action.update);\n return { applied: true, count: 1 };\n } catch (error) {\n throw new Error(`Failed to apply update: ${(error as Error).message}`);\n }\n } else if (action.remove) {\n try {\n const results = JSONPath({\n path: action.target,\n json: doc,\n resultType: \"all\",\n });\n\n if (results.length === 0) {\n return { applied: false, count: 0 };\n }\n\n let count = 0;\n // Process in reverse to avoid index issues when removing\n for (let i = results.length - 1; i >= 0; i--) {\n const result = results[i];\n const { parent, parentProperty, value } = result;\n\n // Check condition if specified\n const shouldRemove =\n typeof action.remove === \"object\"\n ? checkCondition(value, action.remove)\n : true;\n\n if (shouldRemove && parent && parentProperty !== undefined) {\n if (Array.isArray(parent)) {\n parent.splice(parentProperty as number, 1);\n } else {\n delete parent[parentProperty];\n }\n count++;\n }\n }\n\n return { applied: true, count };\n } catch (error) {\n throw new Error(`Failed to remove: ${(error as Error).message}`);\n }\n }\n\n return { applied: false, count: 0 };\n}\n\n/**\n * Extract path order from overlay actions\n * Returns array of paths in the order they appear in overlay\n */\nexport function extractPathOrder(overlay: OverlayDocument): string[] {\n const pathOrder: string[] = [];\n const seenPaths = new Set<string>();\n\n for (const action of overlay.actions) {\n // Match patterns like $.paths['/route'].method\n const match = action.target.match(/^\\$\\.paths\\['([^']+)'\\]/);\n if (match) {\n const targetPath = match[1];\n if (!seenPaths.has(targetPath)) {\n pathOrder.push(targetPath);\n seenPaths.add(targetPath);\n }\n }\n }\n\n return pathOrder;\n}\n\n/**\n * Reorder operation properties so summary, description, operationId come first\n */\nexport function reorderOperationProperties(operation: any): any {\n const priorityKeys = [\"summary\", \"description\", \"operationId\"];\n const reordered: any = {};\n\n // Add priority keys first (in order)\n for (const key of priorityKeys) {\n if (key in operation) {\n reordered[key] = operation[key];\n }\n }\n\n // Add remaining keys\n for (const [key, value] of Object.entries(operation)) {\n if (!priorityKeys.includes(key)) {\n reordered[key] = value;\n }\n }\n\n return reordered;\n}\n\n/**\n * Reorder paths object to match the order from overlay\n */\nexport function reorderPaths(doc: any, pathOrder: string[]): any {\n if (!doc.paths || pathOrder.length === 0) {\n return doc;\n }\n\n const originalPaths = doc.paths;\n const reorderedPaths: any = {};\n\n // First, add paths in the order specified by overlay\n for (const targetPath of pathOrder) {\n if (targetPath in originalPaths) {\n reorderedPaths[targetPath] = originalPaths[targetPath];\n }\n }\n\n // Then add any remaining paths that weren't in the overlay\n for (const [targetPath, value] of Object.entries(originalPaths)) {\n if (!(targetPath in reorderedPaths)) {\n reorderedPaths[targetPath] = value;\n }\n }\n\n // Reorder operation properties within each path\n for (const pathItem of Object.values(reorderedPaths)) {\n const httpMethods = [\n \"get\",\n \"post\",\n \"put\",\n \"patch\",\n \"delete\",\n \"options\",\n \"head\",\n \"trace\",\n ];\n\n for (const method of httpMethods) {\n if (\n (pathItem as any)[method] &&\n typeof (pathItem as any)[method] === \"object\"\n ) {\n (pathItem as any)[method] = reorderOperationProperties(\n (pathItem as any)[method]\n );\n }\n }\n }\n\n doc.paths = reorderedPaths;\n return doc;\n}\n\n/**\n * Reorder top-level document properties to ensure proper ordering\n * OpenAPI spec should have: openapi, info, tags, servers, paths, components, etc.\n */\nexport function reorderDocumentProperties(doc: any): any {\n const priorityKeys = [\"openapi\", \"info\", \"tags\"];\n const reordered: any = {};\n\n // Add priority keys first\n for (const key of priorityKeys) {\n if (key in doc) {\n reordered[key] = doc[key];\n }\n }\n\n // Add remaining keys\n for (const [key, value] of Object.entries(doc)) {\n if (!priorityKeys.includes(key)) {\n reordered[key] = value;\n }\n }\n\n return reordered;\n}\n\n/**\n * Apply overlay to OpenAPI document\n * @param openapi The OpenAPI document to modify\n * @param overlay The overlay document to apply\n * @returns The modified OpenAPI document and statistics\n */\nexport function applyOverlay(\n openapi: any,\n overlay: OverlayDocument\n): { result: any; stats: OverlayStats } {\n // Validate overlay format\n if (!overlay.overlay || !overlay.actions) {\n throw new Error(\n \"Invalid overlay format. Must include 'overlay' version and 'actions' array.\"\n );\n }\n\n const result = deepClone(openapi);\n const stats: OverlayStats = { applied: 0, skipped: 0, totalNodes: 0 };\n\n for (const action of overlay.actions) {\n const { applied, count } = applyAction(result, action);\n\n if (applied) {\n stats.applied++;\n stats.totalNodes += count;\n } else {\n stats.skipped++;\n }\n }\n\n // Reorder paths to match overlay order\n const pathOrder = extractPathOrder(overlay);\n reorderPaths(result, pathOrder);\n\n // Reorder top-level document properties\n const reordered = reorderDocumentProperties(result);\n\n return { result: reordered, stats };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"overlay-engine.js","sourceRoot":"","sources":["../../../src/open-api/overlay/overlay-engine.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AACzC,OAAO,EACL,YAAY,EACZ,uBAAuB,EACvB,uBAAuB,GAIxB,MAAM,gCAAgC,CAAC;AAiBxC,SAAS,QAAQ,CAAC,KAAc,EAAE,OAAe;IAC/C,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,MAAM,IAAI,KAAK,CACb,sBAAsB,OAAO,aAAa,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,KAAK,EAAE,CAC1F,CAAC;IACJ,CAAC;IACD,OAAO,KAAgC,CAAC;AAC1C,CAAC;AAMD,MAAM,UAAU,SAAS,CAAI,GAAM;IACjC,IAAI,OAAO,eAAe,KAAK,UAAU,EAAE,CAAC;QAC1C,OAAO,eAAe,CAAC,GAAG,CAAC,CAAC;IAC9B,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;AACzC,CAAC;AAQD,MAAM,UAAU,SAAS,CAAC,MAAe,EAAE,MAAe;IACxD,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,EAAE,CAAC;QAC1C,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;IAC3B,CAAC;IAED,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3B,OAAO,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3B,CAAC;QAGD,IACE,MAAM,CAAC,MAAM,GAAG,CAAC;YACjB,OAAO,MAAM,CAAC,CAAC,CAAC,KAAK,QAAQ;YAC7B,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI;YAClB,MAAM,IAAI,MAAM,CAAC,CAAC,CAAC;YACnB,IAAI,IAAI,MAAM,CAAC,CAAC,CAAC,EACjB,CAAC;YACD,MAAM,MAAM,GAAG,CAAC,GAAG,MAAM,CAAC,CAAC;YAC3B,KAAK,MAAM,WAAW,IAAI,MAAM,EAAE,CAAC;gBACjC,IAAI,OAAO,WAAW,KAAK,QAAQ,IAAI,WAAW,KAAK,IAAI;oBAAE,SAAS;gBACtE,MAAM,aAAa,GAAG,MAAM,CAAC,SAAS,CACpC,CAAC,CAAC,EAAE,EAAE,CACJ,OAAO,CAAC,KAAK,QAAQ;oBACrB,CAAC,KAAK,IAAI;oBACV,MAAM,IAAI,CAAC;oBACX,IAAI,IAAI,CAAC;oBACT,MAAM,IAAI,WAAW;oBACrB,IAAI,IAAI,WAAW;oBACnB,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC,IAAI;oBAC3B,CAAC,CAAC,EAAE,KAAK,WAAW,CAAC,EAAE,CAC1B,CAAC;gBACF,IAAI,aAAa,IAAI,CAAC,EAAE,CAAC;oBACvB,MAAM,CAAC,aAAa,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,aAAa,CAAC,EAAE,WAAW,CAAC,CAAC;gBACxE,CAAC;qBAAM,CAAC;oBACN,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC;gBACtC,CAAC;YACH,CAAC;YACD,OAAO,MAAM,CAAC;QAChB,CAAC;QAGD,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IAC3C,CAAC;IAGD,MAAM,SAAS,GAAG,MAAiC,CAAC;IACpD,MAAM,SAAS,GAAG,MAAiC,CAAC;IACpD,MAAM,MAAM,GAAG,EAAE,GAAG,SAAS,EAAE,CAAC;IAEhC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC;QACrD,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;YAClB,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAKD,MAAM,UAAU,cAAc,CAC5B,KAAc,EACd,SAA0B;IAG1B,IAAI,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzE,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;YACzB,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC,CAAC;QAC5B,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAGD,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC;QACtB,MAAM,KAAK,GAAG,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3C,IAAI,OAAO,GAAY,KAAK,CAAC;QAC7B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACzB,IACE,OAAO;gBACP,OAAO,OAAO,KAAK,QAAQ;gBAC3B,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC;gBACvB,IAAI,IAAI,OAAO,EACf,CAAC;gBACD,OAAO,GAAI,OAAmC,CAAC,IAAI,CAAC,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACN,OAAO,IAAI,CAAC;YACd,CAAC;QACH,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAMD,MAAM,wBAAwB,GAAG,oBAAoB,CAAC;AAStD,SAAS,iBAAiB,CAAC,eAAuB;IAChD,MAAM,KAAK,GAAG,eAAe,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAG3C,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAGD,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QACjD,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC5B,CAAC;IAGD,OAAO,KAAK,CAAC;AACf,CAAC;AAWD,MAAM,UAAU,cAAc,CAC5B,GAAY,EACZ,MAAc,EACd,KAAc;IAMd,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;IAG/C,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,wBAAwB,CAAC,IAAI,EAAE,CAAC;IAE/D,IAAI,OAAO,GAAG,QAAQ,CAAC,GAAG,EAAE,yBAAyB,CAAC,CAAC;IAEvD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;QAGtB,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACzB,MAAM,GAAG,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC;YACpC,IAAI,CAAC,CAAC,GAAG,IAAI,OAAO,CAAC,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;YACpB,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC1B,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,qBAAqB,MAAM,IAAI,CAAC,GAAG,CAAC,CAAC;QAChE,CAAC;aAAM,CAAC;YAEN,IAAI,CAAC,CAAC,IAAI,IAAI,OAAO,CAAC,EAAE,CAAC;gBACvB,OAAO,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC;YACrB,CAAC;YACD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;YAC3B,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,qBAAqB,MAAM,IAAI,IAAI,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC;IAGD,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,GAAG,GAAG,iBAAiB,CAAC,QAAQ,CAAC,CAAC;QACxC,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACvB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,QAAQ,CAAC,GAAG,KAAK,CAAC;IAC5B,CAAC;AACH,CAAC;AAKD,MAAM,UAAU,WAAW,CAAC,GAAY,EAAE,MAAqB;IAC7D,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IAExD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAElB,IAAI,MAAM,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC1B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACxD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACrC,CAAC;QAED,IAAI,CAAC;YAEH,MAAM,OAAO,GAAG,QAAQ,CAAC;gBACvB,IAAI,EAAE,MAAM,CAAC,MAAM;gBAEnB,IAAI,EAAE,GAAU;gBAChB,UAAU,EAAE,KAAK;aAClB,CAAwE,CAAC;YAE1E,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAEvB,IAAI,KAAK,GAAG,CAAC,CAAC;gBACd,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC;oBAC1C,IACE,MAAM;wBACN,OAAO,MAAM,KAAK,QAAQ;wBAC1B,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;wBACtB,cAAc,KAAK,SAAS,EAC5B,CAAC;wBACD,MAAM,YAAY,GAAG,MAAiC,CAAC;wBACvD,YAAY,CAAC,cAAwB,CAAC,GAAG,SAAS,CAChD,YAAY,CAAC,cAAwB,CAAC,EACtC,MAAM,CAAC,MAAM,CACd,CAAC;wBACF,KAAK,EAAE,CAAC;oBACV,CAAC;gBACH,CAAC;gBACD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;YAClC,CAAC;YAGD,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;YAClD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;QACrC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;SAAM,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,QAAQ,CAAC;gBACvB,IAAI,EAAE,MAAM,CAAC,MAAM;gBAEnB,IAAI,EAAE,GAAU;gBAChB,UAAU,EAAE,KAAK;aAClB,CAAwE,CAAC;YAE1E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;YACtC,CAAC;YAED,IAAI,KAAK,GAAG,CAAC,CAAC;YAEd,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;gBAC7C,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC1B,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;gBAGjD,MAAM,YAAY,GAChB,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ;oBAC/B,CAAC,CAAC,cAAc,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC;oBACtC,CAAC,CAAC,IAAI,CAAC;gBAEX,IAAI,YAAY,IAAI,MAAM,IAAI,cAAc,KAAK,SAAS,EAAE,CAAC;oBAC3D,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;wBAC1B,MAAM,CAAC,MAAM,CAAC,cAAwB,EAAE,CAAC,CAAC,CAAC;oBAC7C,CAAC;yBAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;wBACzD,OAAQ,MAAkC,CACxC,cAAwB,CACzB,CAAC;oBACJ,CAAC;oBACD,KAAK,EAAE,CAAC;gBACV,CAAC;YACH,CAAC;YAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QAClC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,KAAK,CAAC,kBAAkB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;QACjD,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,EAAE,CAAC;AACtC,CAAC;AAMD,MAAM,UAAU,gBAAgB,CAAC,OAAwB;IACvD,MAAM,SAAS,GAAa,EAAE,CAAC;IAC/B,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IAEpC,KAAK,MAAM,MAAM,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QAErC,MAAM,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7D,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;YAC5B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,EAAE,CAAC;gBAC/B,SAAS,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;gBAC3B,SAAS,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAMD,MAAM,UAAU,0BAA0B,CACxC,SAAkB;IAElB,MAAM,YAAY,GAAG,QAAQ,CAAC,SAAS,EAAE,4BAA4B,CAAC,CAAC;IACvE,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,aAAa,EAAE,aAAa,CAAC,CAAC;IAC/D,MAAM,SAAS,GAA4B,EAAE,CAAC;IAG9C,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,GAAG,IAAI,YAAY,EAAE,CAAC;YACxB,SAAS,CAAC,GAAG,CAAC,GAAG,YAAY,CAAC,GAAG,CAAC,CAAC;QACrC,CAAC;IACH,CAAC;IAGD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QACxD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAMD,MAAM,UAAU,YAAY,CAAI,GAAM,EAAE,SAAmB;IAEzD,IACE,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,KAAK,IAAI;QACZ,CAAC,CAAC,OAAO,IAAI,GAAG,CAAC;QACjB,SAAS,CAAC,MAAM,KAAK,CAAC,EACtB,CAAC;QACD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,MAAM,SAAS,GAAG,GAA8B,CAAC;IACjD,MAAM,aAAa,GAAG,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACzD,MAAM,cAAc,GAA4B,EAAE,CAAC;IAGnD,KAAK,MAAM,UAAU,IAAI,SAAS,EAAE,CAAC;QACnC,IAAI,UAAU,IAAI,aAAa,EAAE,CAAC;YAChC,cAAc,CAAC,UAAU,CAAC,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;IAGD,KAAK,MAAM,CAAC,UAAU,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,CAAC,UAAU,IAAI,cAAc,CAAC,EAAE,CAAC;YACpC,cAAc,CAAC,UAAU,CAAC,GAAG,KAAK,CAAC;QACrC,CAAC;IACH,CAAC;IAGD,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QACrD,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI;YAAE,SAAS;QAEhE,MAAM,cAAc,GAAG,QAAmC,CAAC;QAE3D,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;YAClC,IACE,MAAM,IAAI,cAAc;gBACxB,OAAO,cAAc,CAAC,MAAM,CAAC,KAAK,QAAQ;gBAC1C,cAAc,CAAC,MAAM,CAAC,KAAK,IAAI,EAC/B,CAAC;gBACD,cAAc,CAAC,MAAM,CAAC,GAAG,0BAA0B,CACjD,cAAc,CAAC,MAAM,CAAC,CACvB,CAAC;YACJ,CAAC;QACH,CAAC;IACH,CAAC;IAED,SAAS,CAAC,KAAK,GAAG,cAAc,CAAC;IACjC,OAAO,GAAG,CAAC;AACb,CAAC;AAOD,MAAM,UAAU,yBAAyB,CACvC,GAAY;IAEZ,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,2BAA2B,CAAC,CAAC;IAC1D,MAAM,YAAY,GAAG,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACjD,MAAM,SAAS,GAA4B,EAAE,CAAC;IAG9C,KAAK,MAAM,GAAG,IAAI,YAAY,EAAE,CAAC;QAC/B,IAAI,GAAG,IAAI,MAAM,EAAE,CAAC;YAClB,SAAS,CAAC,GAAG,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAGD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,CAAC,YAAY,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;YAChC,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACzB,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAmBD,MAAM,UAAU,YAAY,CAC1B,OAAgB,EAChB,OAAgB;IAGhB,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAC1D,MAAM,gBAAgB,GAAG,uBAAuB,CAAC,OAAO,CAAC,CAAC;IAG1D,MAAM,MAAM,GAAG,SAAS,CAAC,gBAAgB,CAAC,CAAC;IAC3C,MAAM,KAAK,GAAiB,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,CAAC;IAGtE,KAAK,MAAM,MAAM,IAAI,gBAAgB,CAAC,OAAO,EAAE,CAAC;QAC9C,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAEvD,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,CAAC,OAAO,EAAE,CAAC;YAChB,KAAK,CAAC,UAAU,IAAI,KAAK,CAAC;QAC5B,CAAC;aAAM,CAAC;YACN,KAAK,CAAC,OAAO,EAAE,CAAC;QAClB,CAAC;IACH,CAAC;IAGD,MAAM,SAAS,GAAG,gBAAgB,CAAC,gBAAgB,CAAC,CAAC;IACrD,YAAY,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAGhC,MAAM,SAAS,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAEpD,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;AACtC,CAAC","sourcesContent":["import { JSONPath } from \"jsonpath-plus\";\nimport {\n HTTP_METHODS,\n validateOpenApiDocument,\n validateOverlayDocument,\n type OverlayAction,\n type OverlayDocument,\n type RemoveCondition,\n} from \"../../common/open-api/index.js\";\n\nexport interface ApplyResult {\n applied: boolean;\n count: number;\n}\n\nexport interface OverlayStats {\n applied: number;\n skipped: number;\n totalNodes: number;\n}\n\n/**\n * Safely validate and return a generic object\n * Used internally for dynamic JSON manipulation\n */\nfunction toRecord(value: unknown, context: string): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new Error(\n `Expected object at ${context}, but got ${Array.isArray(value) ? \"array\" : typeof value}`\n );\n }\n return value as Record<string, unknown>;\n}\n\n/**\n * Deep clone an object using structuredClone for better performance and correctness\n * Falls back to JSON parse/stringify for environments without structuredClone\n */\nexport function deepClone<T>(obj: T): T {\n if (typeof structuredClone === \"function\") {\n return structuredClone(obj);\n }\n return JSON.parse(JSON.stringify(obj));\n}\n\n/**\n * Deep merge two objects\n * Special handling for OpenAPI parameters (merge by name+in)\n * Returns the merged result, which will have the shape of source if target is not an object,\n * or a merged object/array if both are objects/arrays\n */\nexport function deepMerge(target: unknown, source: unknown): unknown {\n if (!source || typeof source !== \"object\") {\n return source;\n }\n\n if (!target || typeof target !== \"object\") {\n return deepClone(source);\n }\n\n if (Array.isArray(source)) {\n if (!Array.isArray(target)) {\n return deepClone(source);\n }\n\n // Special case for OpenAPI parameters - merge by name+in\n if (\n source.length > 0 &&\n typeof source[0] === \"object\" &&\n source[0] !== null &&\n \"name\" in source[0] &&\n \"in\" in source[0]\n ) {\n const merged = [...target];\n for (const sourceParam of source) {\n if (typeof sourceParam !== \"object\" || sourceParam === null) continue;\n const existingIndex = merged.findIndex(\n (p) =>\n typeof p === \"object\" &&\n p !== null &&\n \"name\" in p &&\n \"in\" in p &&\n \"name\" in sourceParam &&\n \"in\" in sourceParam &&\n p.name === sourceParam.name &&\n p.in === sourceParam.in\n );\n if (existingIndex >= 0) {\n merged[existingIndex] = deepMerge(merged[existingIndex], sourceParam);\n } else {\n merged.push(deepClone(sourceParam));\n }\n }\n return merged;\n }\n\n // For other arrays, concatenate\n return [...target, ...deepClone(source)];\n }\n\n // Both are objects at this point (checked above)\n const targetObj = target as Record<string, unknown>;\n const sourceObj = source as Record<string, unknown>;\n const result = { ...targetObj };\n\n for (const [key, value] of Object.entries(sourceObj)) {\n if (key in result) {\n result[key] = deepMerge(result[key], value);\n } else {\n result[key] = deepClone(value);\n }\n }\n\n return result;\n}\n\n/**\n * Check if a condition is met for conditional removal\n */\nexport function checkCondition(\n value: unknown,\n condition: RemoveCondition\n): boolean {\n // Support \"empty\" condition to check if object has no keys\n if (condition.empty) {\n if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n return Object.keys(value).length === 0;\n }\n if (Array.isArray(value)) {\n return value.length === 0;\n }\n return false;\n }\n\n // Support \"missing\" condition to check if a property doesn't exist\n if (condition.missing) {\n const parts = condition.missing.split(\".\");\n let current: unknown = value;\n for (const part of parts) {\n if (\n current &&\n typeof current === \"object\" &&\n !Array.isArray(current) &&\n part in current\n ) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return true; // Property is missing\n }\n }\n return false; // Property exists\n }\n\n return false;\n}\n\n/**\n * Regular expression for parsing JSONPath segments\n * Matches: word, or [quoted], or ['quoted'], or [\"quoted\"], or numeric indices [0]\n */\nconst JSONPATH_SEGMENT_PATTERN = /[^.[]+|\\[[^\\]]+\\]/g;\n\n/**\n * Extract key from bracket notation, handling various formats:\n * - ['key'] -> key\n * - [\"key\"] -> key\n * - [key] -> key\n * - [0] -> 0 (as string for consistency)\n */\nfunction extractBracketKey(bracketNotation: string): string {\n const inner = bracketNotation.slice(1, -1); // Remove [ and ]\n\n // Handle single-quoted: ['key'] -> key\n if (inner.startsWith(\"'\") && inner.endsWith(\"'\")) {\n return inner.slice(1, -1);\n }\n\n // Handle double-quoted: [\"key\"] -> key\n if (inner.startsWith('\"') && inner.endsWith('\"')) {\n return inner.slice(1, -1);\n }\n\n // Handle unquoted: [key] or [0] -> key or 0\n return inner;\n}\n\n/**\n * Set a value at a JSONPath, creating parent paths as needed\n * Handles patterns like:\n * $.paths['/route'].method\n * $.components.parameters['name']\n * $.paths[\"/users\"].get\n * $.paths[users].get\n * $.items[0].value\n */\nexport function setValueAtPath(\n doc: unknown,\n target: string,\n value: unknown\n): void {\n // Parse the path manually to handle both bracket and dot notation\n // Example: $.paths['/route'].post -> [\"paths\", \"['/route']\", \"post\"]\n\n // Remove leading $.\n const targetPath = target.replace(/^\\$\\./, \"\");\n\n // Split by dots, but keep bracket notation together\n const parts = targetPath.match(JSONPATH_SEGMENT_PATTERN) || [];\n\n let current = toRecord(doc, \"setValueAtPath document\");\n\n for (let i = 0; i < parts.length - 1; i++) {\n const part = parts[i];\n\n // Handle bracket notation\n if (part.startsWith(\"[\")) {\n const key = extractBracketKey(part);\n if (!(key in current)) {\n current[key] = {};\n }\n const next = current[key];\n current = toRecord(next, `setValueAtPath at ${target}[${i}]`);\n } else {\n // Handle regular property\n if (!(part in current)) {\n current[part] = {};\n }\n const next = current[part];\n current = toRecord(next, `setValueAtPath at ${target}.${part}`);\n }\n }\n\n // Set the final value\n const lastPart = parts[parts.length - 1];\n if (lastPart.startsWith(\"[\")) {\n const key = extractBracketKey(lastPart);\n current[key] = value;\n } else {\n current[lastPart] = value;\n }\n}\n\n/**\n * Apply a single overlay action to the document\n */\nexport function applyAction(doc: unknown, action: OverlayAction): ApplyResult {\n const docRecord = toRecord(doc, \"applyAction document\");\n\n if (action.update) {\n // Handle root level updates specially\n if (action.target === \"$\") {\n Object.assign(docRecord, deepMerge(doc, action.update));\n return { applied: true, count: 1 };\n }\n\n try {\n // Try to find existing nodes\n const results = JSONPath({\n path: action.target,\n // biome-ignore lint/suspicious/noExplicitAny: JSONPath library requires loose typing\n json: doc as any,\n resultType: \"all\",\n }) as Array<{ parent: unknown; parentProperty: unknown; value: unknown }>;\n\n if (results.length > 0) {\n // Path exists, merge the update\n let count = 0;\n for (const result of results) {\n const { parent, parentProperty } = result;\n if (\n parent &&\n typeof parent === \"object\" &&\n !Array.isArray(parent) &&\n parentProperty !== undefined\n ) {\n const parentRecord = parent as Record<string, unknown>;\n parentRecord[parentProperty as string] = deepMerge(\n parentRecord[parentProperty as string],\n action.update\n );\n count++;\n }\n }\n return { applied: true, count };\n }\n\n // Path doesn't exist, create it manually\n setValueAtPath(doc, action.target, action.update);\n return { applied: true, count: 1 };\n } catch (cause) {\n throw new Error(\"Failed to apply update\", { cause });\n }\n } else if (action.remove) {\n try {\n const results = JSONPath({\n path: action.target,\n // biome-ignore lint/suspicious/noExplicitAny: JSONPath library requires loose typing\n json: doc as any,\n resultType: \"all\",\n }) as Array<{ parent: unknown; parentProperty: unknown; value: unknown }>;\n\n if (results.length === 0) {\n return { applied: false, count: 0 };\n }\n\n let count = 0;\n // Process in reverse to avoid index issues when removing\n for (let i = results.length - 1; i >= 0; i--) {\n const result = results[i];\n const { parent, parentProperty, value } = result;\n\n // Check condition if specified\n const shouldRemove =\n typeof action.remove === \"object\"\n ? checkCondition(value, action.remove)\n : true;\n\n if (shouldRemove && parent && parentProperty !== undefined) {\n if (Array.isArray(parent)) {\n parent.splice(parentProperty as number, 1);\n } else if (typeof parent === \"object\" && parent !== null) {\n delete (parent as Record<string, unknown>)[\n parentProperty as string\n ];\n }\n count++;\n }\n }\n\n return { applied: true, count };\n } catch (cause) {\n throw new Error(\"Failed to remove\", { cause });\n }\n }\n\n return { applied: false, count: 0 };\n}\n\n/**\n * Extract path order from overlay actions\n * Returns array of paths in the order they appear in overlay\n */\nexport function extractPathOrder(overlay: OverlayDocument): string[] {\n const pathOrder: string[] = [];\n const seenPaths = new Set<string>();\n\n for (const action of overlay.actions) {\n // Match patterns like $.paths['/route'].method\n const match = action.target.match(/^\\$\\.paths\\['([^']+)'\\]/);\n if (match) {\n const targetPath = match[1];\n if (!seenPaths.has(targetPath)) {\n pathOrder.push(targetPath);\n seenPaths.add(targetPath);\n }\n }\n }\n\n return pathOrder;\n}\n\n/**\n * Reorder operation properties so summary, description, operationId come first\n * Returns a new object with reordered keys\n */\nexport function reorderOperationProperties(\n operation: unknown\n): Record<string, unknown> {\n const operationObj = toRecord(operation, \"reorderOperationProperties\");\n const priorityKeys = [\"summary\", \"description\", \"operationId\"];\n const reordered: Record<string, unknown> = {};\n\n // Add priority keys first (in order)\n for (const key of priorityKeys) {\n if (key in operationObj) {\n reordered[key] = operationObj[key];\n }\n }\n\n // Add remaining keys\n for (const [key, value] of Object.entries(operationObj)) {\n if (!priorityKeys.includes(key)) {\n reordered[key] = value;\n }\n }\n\n return reordered;\n}\n\n/**\n * Reorder paths object to match the order from overlay\n * Modifies the document in place and returns it\n */\nexport function reorderPaths<T>(doc: T, pathOrder: string[]): T {\n // Early return if no paths to reorder\n if (\n typeof doc !== \"object\" ||\n doc === null ||\n !(\"paths\" in doc) ||\n pathOrder.length === 0\n ) {\n return doc;\n }\n\n const docRecord = doc as Record<string, unknown>;\n const originalPaths = toRecord(docRecord.paths, \"paths\");\n const reorderedPaths: Record<string, unknown> = {};\n\n // First, add paths in the order specified by overlay\n for (const targetPath of pathOrder) {\n if (targetPath in originalPaths) {\n reorderedPaths[targetPath] = originalPaths[targetPath];\n }\n }\n\n // Then add any remaining paths that weren't in the overlay\n for (const [targetPath, value] of Object.entries(originalPaths)) {\n if (!(targetPath in reorderedPaths)) {\n reorderedPaths[targetPath] = value;\n }\n }\n\n // Reorder operation properties within each path\n for (const pathItem of Object.values(reorderedPaths)) {\n if (typeof pathItem !== \"object\" || pathItem === null) continue;\n\n const pathItemRecord = pathItem as Record<string, unknown>;\n\n for (const method of HTTP_METHODS) {\n if (\n method in pathItemRecord &&\n typeof pathItemRecord[method] === \"object\" &&\n pathItemRecord[method] !== null\n ) {\n pathItemRecord[method] = reorderOperationProperties(\n pathItemRecord[method]\n );\n }\n }\n }\n\n docRecord.paths = reorderedPaths;\n return doc;\n}\n\n/**\n * Reorder top-level document properties to ensure proper ordering\n * OpenAPI spec should have: openapi, info, tags, servers, paths, components, etc.\n * Returns a new object with reordered keys\n */\nexport function reorderDocumentProperties(\n doc: unknown\n): Record<string, unknown> {\n const docObj = toRecord(doc, \"reorderDocumentProperties\");\n const priorityKeys = [\"openapi\", \"info\", \"tags\"];\n const reordered: Record<string, unknown> = {};\n\n // Add priority keys first\n for (const key of priorityKeys) {\n if (key in docObj) {\n reordered[key] = docObj[key];\n }\n }\n\n // Add remaining keys\n for (const [key, value] of Object.entries(docObj)) {\n if (!priorityKeys.includes(key)) {\n reordered[key] = value;\n }\n }\n\n return reordered;\n}\n\n/**\n * Apply overlay to OpenAPI document\n *\n * Validates both the OpenAPI document and overlay upfront, then applies\n * all actions defined in the overlay to produce a modified OpenAPI document.\n *\n * @param openapi The OpenAPI document to modify (will be validated)\n * @param overlay The overlay document to apply (will be validated)\n * @returns The modified OpenAPI document and statistics about what was applied\n * @throws {Error} if either document is invalid, with actionable error messages\n *\n * @example\n * ```typescript\n * const result = applyOverlay(openapiDoc, overlayDoc);\n * console.log(`Applied ${result.stats.applied} actions`);\n * ```\n */\nexport function applyOverlay(\n openapi: unknown,\n overlay: unknown\n): { result: Record<string, unknown>; stats: OverlayStats } {\n // Validate inputs upfront with actionable error messages\n const validatedOverlay = validateOverlayDocument(overlay);\n const validatedOpenApi = validateOpenApiDocument(openapi);\n\n // Clone the document for modification\n const result = deepClone(validatedOpenApi);\n const stats: OverlayStats = { applied: 0, skipped: 0, totalNodes: 0 };\n\n // Apply each action\n for (const action of validatedOverlay.actions) {\n const { applied, count } = applyAction(result, action);\n\n if (applied) {\n stats.applied++;\n stats.totalNodes += count;\n } else {\n stats.skipped++;\n }\n }\n\n // Reorder paths to match overlay order\n const pathOrder = extractPathOrder(validatedOverlay);\n reorderPaths(result, pathOrder);\n\n // Reorder top-level document properties\n const reordered = reorderDocumentProperties(result);\n\n return { result: reordered, stats };\n}\n"]}
|