@nestia/migrate 11.0.0-dev.20260312 → 11.0.0-dev.20260313-2
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/lib/NestiaMigrateApplication.js +1 -1
- package/lib/NestiaMigrateApplication.js.map +1 -1
- package/lib/bundles/NEST_TEMPLATE.js +1 -1
- package/lib/bundles/SDK_TEMPLATE.js +1 -1
- package/lib/index.mjs +50 -4
- package/lib/index.mjs.map +1 -1
- package/lib/module.d.ts +2 -2
- package/lib/module.js +2 -2
- package/lib/module.js.map +1 -1
- package/lib/programmers/index.d.ts +15 -0
- package/lib/programmers/index.js +32 -0
- package/lib/programmers/index.js.map +1 -0
- package/lib/structures/index.d.ts +4 -0
- package/lib/structures/index.js +21 -0
- package/lib/structures/index.js.map +1 -0
- package/lib/utils/openapi-down-convert/converter.js +2 -2
- package/package.json +5 -6
- package/src/NestiaMigrateApplication.ts +4 -1
- package/src/archivers/NestiaMigrateFileArchiver.ts +28 -28
- package/src/bundles/NEST_TEMPLATE.ts +1 -1
- package/src/bundles/SDK_TEMPLATE.ts +1 -1
- package/src/executable/migrate.ts +7 -7
- package/src/index.ts +4 -4
- package/src/programmers/NestiaMigrateApiProgrammer.ts +107 -107
- package/src/programmers/NestiaMigrateNestModuleProgrammer.ts +65 -65
- package/src/programmers/NestiaMigrateNestProgrammer.ts +88 -88
- package/src/structures/INestiaMigrateConfig.ts +19 -19
- package/src/structures/INestiaMigrateFile.ts +5 -5
- package/src/structures/INestiaMigrateSchema.ts +4 -4
- package/src/utils/MapUtil.ts +13 -13
- package/src/utils/SetupWizard.ts +12 -12
- package/src/utils/openapi-down-convert/RefVisitor.ts +134 -134
- package/src/utils/openapi-down-convert/converter.ts +536 -536
|
@@ -1,88 +1,88 @@
|
|
|
1
|
-
import ts from "typescript";
|
|
2
|
-
|
|
3
|
-
import { NestiaMigrateControllerAnalyzer } from "../analyzers/NestiaMigrateControllerAnalyzer";
|
|
4
|
-
import { INestiaMigrateContext } from "../structures/INestiaMigrateContext";
|
|
5
|
-
import { INestiaMigrateController } from "../structures/INestiaMigrateController";
|
|
6
|
-
import { FilePrinter } from "../utils/FilePrinter";
|
|
7
|
-
import { NestiaMigrateDtoProgrammer } from "./NestiaMigrateDtoProgrammer";
|
|
8
|
-
import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
|
|
9
|
-
import { NestiaMigrateNestControllerProgrammer } from "./NestiaMigrateNestControllerProgrammer";
|
|
10
|
-
import { NestiaMigrateNestModuleProgrammer } from "./NestiaMigrateNestModuleProgrammer";
|
|
11
|
-
|
|
12
|
-
export namespace NestiaMigrateNestProgrammer {
|
|
13
|
-
export const write = (
|
|
14
|
-
context: INestiaMigrateContext,
|
|
15
|
-
): Record<string, string> => {
|
|
16
|
-
const controllers: INestiaMigrateController[] =
|
|
17
|
-
NestiaMigrateControllerAnalyzer.analyze(context.application.routes);
|
|
18
|
-
const statements: [string, ts.Statement[]][] = [
|
|
19
|
-
["src/MyModule.ts", NestiaMigrateNestModuleProgrammer.write(controllers)],
|
|
20
|
-
...controllers.map(
|
|
21
|
-
(c) =>
|
|
22
|
-
[
|
|
23
|
-
`${c.location}/${c.name}.ts`,
|
|
24
|
-
NestiaMigrateNestControllerProgrammer.write({
|
|
25
|
-
config: context.config,
|
|
26
|
-
components: context.application.document().components,
|
|
27
|
-
controller: c,
|
|
28
|
-
}),
|
|
29
|
-
] satisfies [string, ts.Statement[]],
|
|
30
|
-
),
|
|
31
|
-
...[
|
|
32
|
-
...NestiaMigrateDtoProgrammer.compose({
|
|
33
|
-
config: context.config,
|
|
34
|
-
components: context.application.document().components,
|
|
35
|
-
}).entries(),
|
|
36
|
-
].map(
|
|
37
|
-
([key, value]) =>
|
|
38
|
-
[`src/api/structures/${key}.ts`, writeDtoFile(key, value)] satisfies [
|
|
39
|
-
string,
|
|
40
|
-
ts.Statement[],
|
|
41
|
-
],
|
|
42
|
-
),
|
|
43
|
-
];
|
|
44
|
-
return Object.fromEntries(
|
|
45
|
-
statements.map(([key, value]) => [
|
|
46
|
-
key,
|
|
47
|
-
FilePrinter.write({ statements: value }),
|
|
48
|
-
]),
|
|
49
|
-
);
|
|
50
|
-
};
|
|
51
|
-
|
|
52
|
-
const writeDtoFile = (
|
|
53
|
-
key: string,
|
|
54
|
-
modulo: NestiaMigrateDtoProgrammer.IModule,
|
|
55
|
-
): ts.Statement[] => {
|
|
56
|
-
const importer = new NestiaMigrateImportProgrammer();
|
|
57
|
-
const statements: ts.Statement[] = iterate(importer)(modulo);
|
|
58
|
-
if (statements.length === 0) return [];
|
|
59
|
-
|
|
60
|
-
return [
|
|
61
|
-
...importer.toStatements((name) => `./${name}`, key),
|
|
62
|
-
...(importer.empty() ? [] : [FilePrinter.newLine()]),
|
|
63
|
-
...statements,
|
|
64
|
-
];
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
const iterate =
|
|
68
|
-
(importer: NestiaMigrateImportProgrammer) =>
|
|
69
|
-
(modulo: NestiaMigrateDtoProgrammer.IModule): ts.Statement[] => {
|
|
70
|
-
const output: ts.Statement[] = [];
|
|
71
|
-
if (modulo.programmer !== null) output.push(modulo.programmer(importer));
|
|
72
|
-
if (modulo.children.size) {
|
|
73
|
-
const internal: ts.Statement[] = [];
|
|
74
|
-
for (const child of modulo.children.values())
|
|
75
|
-
internal.push(...iterate(importer)(child));
|
|
76
|
-
output.push(
|
|
77
|
-
ts.factory.createModuleDeclaration(
|
|
78
|
-
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
79
|
-
ts.factory.createIdentifier(modulo.name),
|
|
80
|
-
ts.factory.createModuleBlock(internal),
|
|
81
|
-
ts.NodeFlags.Namespace,
|
|
82
|
-
),
|
|
83
|
-
);
|
|
84
|
-
}
|
|
85
|
-
output.push(FilePrinter.newLine());
|
|
86
|
-
return output;
|
|
87
|
-
};
|
|
88
|
-
}
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
import { NestiaMigrateControllerAnalyzer } from "../analyzers/NestiaMigrateControllerAnalyzer";
|
|
4
|
+
import { INestiaMigrateContext } from "../structures/INestiaMigrateContext";
|
|
5
|
+
import { INestiaMigrateController } from "../structures/INestiaMigrateController";
|
|
6
|
+
import { FilePrinter } from "../utils/FilePrinter";
|
|
7
|
+
import { NestiaMigrateDtoProgrammer } from "./NestiaMigrateDtoProgrammer";
|
|
8
|
+
import { NestiaMigrateImportProgrammer } from "./NestiaMigrateImportProgrammer";
|
|
9
|
+
import { NestiaMigrateNestControllerProgrammer } from "./NestiaMigrateNestControllerProgrammer";
|
|
10
|
+
import { NestiaMigrateNestModuleProgrammer } from "./NestiaMigrateNestModuleProgrammer";
|
|
11
|
+
|
|
12
|
+
export namespace NestiaMigrateNestProgrammer {
|
|
13
|
+
export const write = (
|
|
14
|
+
context: INestiaMigrateContext,
|
|
15
|
+
): Record<string, string> => {
|
|
16
|
+
const controllers: INestiaMigrateController[] =
|
|
17
|
+
NestiaMigrateControllerAnalyzer.analyze(context.application.routes);
|
|
18
|
+
const statements: [string, ts.Statement[]][] = [
|
|
19
|
+
["src/MyModule.ts", NestiaMigrateNestModuleProgrammer.write(controllers)],
|
|
20
|
+
...controllers.map(
|
|
21
|
+
(c) =>
|
|
22
|
+
[
|
|
23
|
+
`${c.location}/${c.name}.ts`,
|
|
24
|
+
NestiaMigrateNestControllerProgrammer.write({
|
|
25
|
+
config: context.config,
|
|
26
|
+
components: context.application.document().components,
|
|
27
|
+
controller: c,
|
|
28
|
+
}),
|
|
29
|
+
] satisfies [string, ts.Statement[]],
|
|
30
|
+
),
|
|
31
|
+
...[
|
|
32
|
+
...NestiaMigrateDtoProgrammer.compose({
|
|
33
|
+
config: context.config,
|
|
34
|
+
components: context.application.document().components,
|
|
35
|
+
}).entries(),
|
|
36
|
+
].map(
|
|
37
|
+
([key, value]) =>
|
|
38
|
+
[`src/api/structures/${key}.ts`, writeDtoFile(key, value)] satisfies [
|
|
39
|
+
string,
|
|
40
|
+
ts.Statement[],
|
|
41
|
+
],
|
|
42
|
+
),
|
|
43
|
+
];
|
|
44
|
+
return Object.fromEntries(
|
|
45
|
+
statements.map(([key, value]) => [
|
|
46
|
+
key,
|
|
47
|
+
FilePrinter.write({ statements: value }),
|
|
48
|
+
]),
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
const writeDtoFile = (
|
|
53
|
+
key: string,
|
|
54
|
+
modulo: NestiaMigrateDtoProgrammer.IModule,
|
|
55
|
+
): ts.Statement[] => {
|
|
56
|
+
const importer = new NestiaMigrateImportProgrammer();
|
|
57
|
+
const statements: ts.Statement[] = iterate(importer)(modulo);
|
|
58
|
+
if (statements.length === 0) return [];
|
|
59
|
+
|
|
60
|
+
return [
|
|
61
|
+
...importer.toStatements((name) => `./${name}`, key),
|
|
62
|
+
...(importer.empty() ? [] : [FilePrinter.newLine()]),
|
|
63
|
+
...statements,
|
|
64
|
+
];
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
const iterate =
|
|
68
|
+
(importer: NestiaMigrateImportProgrammer) =>
|
|
69
|
+
(modulo: NestiaMigrateDtoProgrammer.IModule): ts.Statement[] => {
|
|
70
|
+
const output: ts.Statement[] = [];
|
|
71
|
+
if (modulo.programmer !== null) output.push(modulo.programmer(importer));
|
|
72
|
+
if (modulo.children.size) {
|
|
73
|
+
const internal: ts.Statement[] = [];
|
|
74
|
+
for (const child of modulo.children.values())
|
|
75
|
+
internal.push(...iterate(importer)(child));
|
|
76
|
+
output.push(
|
|
77
|
+
ts.factory.createModuleDeclaration(
|
|
78
|
+
[ts.factory.createModifier(ts.SyntaxKind.ExportKeyword)],
|
|
79
|
+
ts.factory.createIdentifier(modulo.name),
|
|
80
|
+
ts.factory.createModuleBlock(internal),
|
|
81
|
+
ts.NodeFlags.Namespace,
|
|
82
|
+
),
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
output.push(FilePrinter.newLine());
|
|
86
|
+
return output;
|
|
87
|
+
};
|
|
88
|
+
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
import ts from "typescript";
|
|
2
|
-
|
|
3
|
-
import { NestiaMigrateNestMethodProgrammer } from "../programmers/NestiaMigrateNestMethodProgrammer";
|
|
4
|
-
|
|
5
|
-
export interface INestiaMigrateConfig {
|
|
6
|
-
simulate: boolean;
|
|
7
|
-
e2e: boolean;
|
|
8
|
-
package?: string;
|
|
9
|
-
keyword?: boolean;
|
|
10
|
-
author?: {
|
|
11
|
-
tag: string;
|
|
12
|
-
value: string;
|
|
13
|
-
};
|
|
14
|
-
programmer?: {
|
|
15
|
-
controllerMethod?: (
|
|
16
|
-
ctx: NestiaMigrateNestMethodProgrammer.IContext,
|
|
17
|
-
) => ts.MethodDeclaration;
|
|
18
|
-
};
|
|
19
|
-
}
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
|
|
3
|
+
import { NestiaMigrateNestMethodProgrammer } from "../programmers/NestiaMigrateNestMethodProgrammer";
|
|
4
|
+
|
|
5
|
+
export interface INestiaMigrateConfig {
|
|
6
|
+
simulate: boolean;
|
|
7
|
+
e2e: boolean;
|
|
8
|
+
package?: string;
|
|
9
|
+
keyword?: boolean;
|
|
10
|
+
author?: {
|
|
11
|
+
tag: string;
|
|
12
|
+
value: string;
|
|
13
|
+
};
|
|
14
|
+
programmer?: {
|
|
15
|
+
controllerMethod?: (
|
|
16
|
+
ctx: NestiaMigrateNestMethodProgrammer.IContext,
|
|
17
|
+
) => ts.MethodDeclaration;
|
|
18
|
+
};
|
|
19
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export interface INestiaMigrateFile {
|
|
2
|
-
location: string;
|
|
3
|
-
file: string;
|
|
4
|
-
content: string;
|
|
5
|
-
}
|
|
1
|
+
export interface INestiaMigrateFile {
|
|
2
|
+
location: string;
|
|
3
|
+
file: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export interface INestiaMigrateSchema {
|
|
2
|
-
name: string;
|
|
3
|
-
children: INestiaMigrateSchema[];
|
|
4
|
-
}
|
|
1
|
+
export interface INestiaMigrateSchema {
|
|
2
|
+
name: string;
|
|
3
|
+
children: INestiaMigrateSchema[];
|
|
4
|
+
}
|
package/src/utils/MapUtil.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
export namespace MapUtil {
|
|
2
|
-
export const take =
|
|
3
|
-
<Key, T>(dict: Map<Key, T>) =>
|
|
4
|
-
(key: Key) =>
|
|
5
|
-
(generator: () => T): T => {
|
|
6
|
-
const oldbie: T | undefined = dict.get(key);
|
|
7
|
-
if (oldbie) return oldbie;
|
|
8
|
-
|
|
9
|
-
const value: T = generator();
|
|
10
|
-
dict.set(key, value);
|
|
11
|
-
return value;
|
|
12
|
-
};
|
|
13
|
-
}
|
|
1
|
+
export namespace MapUtil {
|
|
2
|
+
export const take =
|
|
3
|
+
<Key, T>(dict: Map<Key, T>) =>
|
|
4
|
+
(key: Key) =>
|
|
5
|
+
(generator: () => T): T => {
|
|
6
|
+
const oldbie: T | undefined = dict.get(key);
|
|
7
|
+
if (oldbie) return oldbie;
|
|
8
|
+
|
|
9
|
+
const value: T = generator();
|
|
10
|
+
dict.set(key, value);
|
|
11
|
+
return value;
|
|
12
|
+
};
|
|
13
|
+
}
|
package/src/utils/SetupWizard.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import cp from "child_process";
|
|
2
|
-
|
|
3
|
-
export namespace SetupWizard {
|
|
4
|
-
export const setup = (output: string) => {
|
|
5
|
-
execute(output)("npm install");
|
|
6
|
-
};
|
|
7
|
-
|
|
8
|
-
const execute = (cwd: string) => (command: string, fake?: string) => {
|
|
9
|
-
console.log(fake ?? command);
|
|
10
|
-
cp.execSync(command, { cwd, stdio: "inherit" });
|
|
11
|
-
};
|
|
12
|
-
}
|
|
1
|
+
import cp from "child_process";
|
|
2
|
+
|
|
3
|
+
export namespace SetupWizard {
|
|
4
|
+
export const setup = (output: string) => {
|
|
5
|
+
execute(output)("npm install");
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
const execute = (cwd: string) => (command: string, fake?: string) => {
|
|
9
|
+
console.log(fake ?? command);
|
|
10
|
+
cp.execSync(command, { cwd, stdio: "inherit" });
|
|
11
|
+
};
|
|
12
|
+
}
|
|
@@ -1,134 +1,134 @@
|
|
|
1
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Recursively walk a JSON object and invoke a callback function on each `{
|
|
5
|
-
* "$ref" : "path" }` object found
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
/**
|
|
9
|
-
* Represents a JSON Reference object, such as `{"$ref":
|
|
10
|
-
* "#/components/schemas/problemResponse" }`
|
|
11
|
-
*/
|
|
12
|
-
export interface RefObject {
|
|
13
|
-
$ref: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
/** JsonNode represents a node within the OpenAPI object */
|
|
17
|
-
export type JsonNode = object | [] | string | boolean | null | number;
|
|
18
|
-
|
|
19
|
-
/** A JSON Schema object in an API def */
|
|
20
|
-
export type SchemaObject = object;
|
|
21
|
-
|
|
22
|
-
/** Function signature for the visitRefObjects callback */
|
|
23
|
-
export type RefVisitor = (node: RefObject) => JsonNode;
|
|
24
|
-
/** Function signature for the visitSchemaObjects callback */
|
|
25
|
-
export type SchemaVisitor = (node: SchemaObject) => SchemaObject;
|
|
26
|
-
|
|
27
|
-
/** /** Function signature for the walkObject callback */
|
|
28
|
-
export type ObjectVisitor = (node: object) => JsonNode;
|
|
29
|
-
|
|
30
|
-
/** Test if a JSON node is a `{ $ref: "uri" }` object */
|
|
31
|
-
export function isRef(node: any): boolean {
|
|
32
|
-
return (
|
|
33
|
-
node !== null &&
|
|
34
|
-
typeof node === "object" &&
|
|
35
|
-
node.hasOwnProperty("$ref") &&
|
|
36
|
-
typeof node["$ref"] === "string"
|
|
37
|
-
);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
/**
|
|
41
|
-
* Walk a JSON object and apply `schemaCallback` when a JSON schema is found.
|
|
42
|
-
* JSON Schema objects are items in components/schemas or in an item named
|
|
43
|
-
* `schema`
|
|
44
|
-
*
|
|
45
|
-
* @param node A node in the OpenAPI document
|
|
46
|
-
* @param schemaCallback The function to call on JSON schema objects
|
|
47
|
-
* @returns The modified (annotated) node
|
|
48
|
-
*/
|
|
49
|
-
export function visitSchemaObjects(
|
|
50
|
-
node: any,
|
|
51
|
-
schemaCallback: SchemaVisitor,
|
|
52
|
-
): any {
|
|
53
|
-
const objectVisitor = (node: any): JsonNode => {
|
|
54
|
-
if (node.hasOwnProperty("schema")) {
|
|
55
|
-
const schema = node["schema"];
|
|
56
|
-
if (schema != null && typeof schema === "object") {
|
|
57
|
-
node["schema"] = schemaCallback(schema);
|
|
58
|
-
}
|
|
59
|
-
} else if (node.hasOwnProperty("schemas")) {
|
|
60
|
-
const schemas = node["schemas"];
|
|
61
|
-
if (schemas != null && typeof schemas === "object") {
|
|
62
|
-
for (const schemaName in schemas) {
|
|
63
|
-
const schema = schemas[schemaName];
|
|
64
|
-
const newSchema = schemaCallback(schema);
|
|
65
|
-
schemas[schemaName] = newSchema;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
return node;
|
|
70
|
-
};
|
|
71
|
-
return walkObject(node, objectVisitor);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
/**
|
|
75
|
-
* Walk a JSON object and apply `refCallback` when a JSON `{$ref: url }` is
|
|
76
|
-
* found
|
|
77
|
-
*
|
|
78
|
-
* @param node A node in the OpenAPI document
|
|
79
|
-
* @param refCallback The function to call on JSON `$ref` objects
|
|
80
|
-
* @returns The modified (annotated) node
|
|
81
|
-
*/
|
|
82
|
-
export function visitRefObjects(node: any, refCallback: RefVisitor): any {
|
|
83
|
-
const objectVisitor = (node: object): JsonNode => {
|
|
84
|
-
if (isRef(node)) {
|
|
85
|
-
return refCallback(node as RefObject);
|
|
86
|
-
}
|
|
87
|
-
return node;
|
|
88
|
-
};
|
|
89
|
-
return walkObject(node, objectVisitor);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Walk a JSON object or array and apply objectCallback when a JSON object is
|
|
94
|
-
* found
|
|
95
|
-
*
|
|
96
|
-
* @param node A node in the OpenAPI document
|
|
97
|
-
* @param objectCallback The function to call on JSON objects
|
|
98
|
-
* @param nav Tracks where we are in the original document
|
|
99
|
-
* @returns The modified (annotated) node
|
|
100
|
-
*/
|
|
101
|
-
export function walkObject(
|
|
102
|
-
node: object,
|
|
103
|
-
objectCallback: ObjectVisitor,
|
|
104
|
-
): JsonNode {
|
|
105
|
-
return walkObj(node);
|
|
106
|
-
|
|
107
|
-
function walkObj(node: any): JsonNode {
|
|
108
|
-
const object = objectCallback(node);
|
|
109
|
-
if (object !== null && typeof object === "object") {
|
|
110
|
-
const keys = [...Object.keys(node)]; // make copy since this code may re-enter objects
|
|
111
|
-
for (const key of keys) {
|
|
112
|
-
const val = node[key];
|
|
113
|
-
if (Array.isArray(val)) {
|
|
114
|
-
node[key] = walkArray(val as []);
|
|
115
|
-
} else if (val !== null && typeof val === "object") {
|
|
116
|
-
node[key] = walkObj(val);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
return object;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
function walkArray(array: JsonNode[]): JsonNode[] {
|
|
124
|
-
for (let index = 0; index < array.length; index += 1) {
|
|
125
|
-
const val = array[index] as JsonNode;
|
|
126
|
-
if (val !== null && typeof val === "object") {
|
|
127
|
-
array[index] = walkObj(val) as object;
|
|
128
|
-
} else if (Array.isArray(val)) {
|
|
129
|
-
array[index] = walkArray(val as JsonNode[]) as [];
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
return array;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Recursively walk a JSON object and invoke a callback function on each `{
|
|
5
|
+
* "$ref" : "path" }` object found
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Represents a JSON Reference object, such as `{"$ref":
|
|
10
|
+
* "#/components/schemas/problemResponse" }`
|
|
11
|
+
*/
|
|
12
|
+
export interface RefObject {
|
|
13
|
+
$ref: string;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** JsonNode represents a node within the OpenAPI object */
|
|
17
|
+
export type JsonNode = object | [] | string | boolean | null | number;
|
|
18
|
+
|
|
19
|
+
/** A JSON Schema object in an API def */
|
|
20
|
+
export type SchemaObject = object;
|
|
21
|
+
|
|
22
|
+
/** Function signature for the visitRefObjects callback */
|
|
23
|
+
export type RefVisitor = (node: RefObject) => JsonNode;
|
|
24
|
+
/** Function signature for the visitSchemaObjects callback */
|
|
25
|
+
export type SchemaVisitor = (node: SchemaObject) => SchemaObject;
|
|
26
|
+
|
|
27
|
+
/** /** Function signature for the walkObject callback */
|
|
28
|
+
export type ObjectVisitor = (node: object) => JsonNode;
|
|
29
|
+
|
|
30
|
+
/** Test if a JSON node is a `{ $ref: "uri" }` object */
|
|
31
|
+
export function isRef(node: any): boolean {
|
|
32
|
+
return (
|
|
33
|
+
node !== null &&
|
|
34
|
+
typeof node === "object" &&
|
|
35
|
+
node.hasOwnProperty("$ref") &&
|
|
36
|
+
typeof node["$ref"] === "string"
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Walk a JSON object and apply `schemaCallback` when a JSON schema is found.
|
|
42
|
+
* JSON Schema objects are items in components/schemas or in an item named
|
|
43
|
+
* `schema`
|
|
44
|
+
*
|
|
45
|
+
* @param node A node in the OpenAPI document
|
|
46
|
+
* @param schemaCallback The function to call on JSON schema objects
|
|
47
|
+
* @returns The modified (annotated) node
|
|
48
|
+
*/
|
|
49
|
+
export function visitSchemaObjects(
|
|
50
|
+
node: any,
|
|
51
|
+
schemaCallback: SchemaVisitor,
|
|
52
|
+
): any {
|
|
53
|
+
const objectVisitor = (node: any): JsonNode => {
|
|
54
|
+
if (node.hasOwnProperty("schema")) {
|
|
55
|
+
const schema = node["schema"];
|
|
56
|
+
if (schema != null && typeof schema === "object") {
|
|
57
|
+
node["schema"] = schemaCallback(schema);
|
|
58
|
+
}
|
|
59
|
+
} else if (node.hasOwnProperty("schemas")) {
|
|
60
|
+
const schemas = node["schemas"];
|
|
61
|
+
if (schemas != null && typeof schemas === "object") {
|
|
62
|
+
for (const schemaName in schemas) {
|
|
63
|
+
const schema = schemas[schemaName];
|
|
64
|
+
const newSchema = schemaCallback(schema);
|
|
65
|
+
schemas[schemaName] = newSchema;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return node;
|
|
70
|
+
};
|
|
71
|
+
return walkObject(node, objectVisitor);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Walk a JSON object and apply `refCallback` when a JSON `{$ref: url }` is
|
|
76
|
+
* found
|
|
77
|
+
*
|
|
78
|
+
* @param node A node in the OpenAPI document
|
|
79
|
+
* @param refCallback The function to call on JSON `$ref` objects
|
|
80
|
+
* @returns The modified (annotated) node
|
|
81
|
+
*/
|
|
82
|
+
export function visitRefObjects(node: any, refCallback: RefVisitor): any {
|
|
83
|
+
const objectVisitor = (node: object): JsonNode => {
|
|
84
|
+
if (isRef(node)) {
|
|
85
|
+
return refCallback(node as RefObject);
|
|
86
|
+
}
|
|
87
|
+
return node;
|
|
88
|
+
};
|
|
89
|
+
return walkObject(node, objectVisitor);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Walk a JSON object or array and apply objectCallback when a JSON object is
|
|
94
|
+
* found
|
|
95
|
+
*
|
|
96
|
+
* @param node A node in the OpenAPI document
|
|
97
|
+
* @param objectCallback The function to call on JSON objects
|
|
98
|
+
* @param nav Tracks where we are in the original document
|
|
99
|
+
* @returns The modified (annotated) node
|
|
100
|
+
*/
|
|
101
|
+
export function walkObject(
|
|
102
|
+
node: object,
|
|
103
|
+
objectCallback: ObjectVisitor,
|
|
104
|
+
): JsonNode {
|
|
105
|
+
return walkObj(node);
|
|
106
|
+
|
|
107
|
+
function walkObj(node: any): JsonNode {
|
|
108
|
+
const object = objectCallback(node);
|
|
109
|
+
if (object !== null && typeof object === "object") {
|
|
110
|
+
const keys = [...Object.keys(node)]; // make copy since this code may re-enter objects
|
|
111
|
+
for (const key of keys) {
|
|
112
|
+
const val = node[key];
|
|
113
|
+
if (Array.isArray(val)) {
|
|
114
|
+
node[key] = walkArray(val as []);
|
|
115
|
+
} else if (val !== null && typeof val === "object") {
|
|
116
|
+
node[key] = walkObj(val);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return object;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
function walkArray(array: JsonNode[]): JsonNode[] {
|
|
124
|
+
for (let index = 0; index < array.length; index += 1) {
|
|
125
|
+
const val = array[index] as JsonNode;
|
|
126
|
+
if (val !== null && typeof val === "object") {
|
|
127
|
+
array[index] = walkObj(val) as object;
|
|
128
|
+
} else if (Array.isArray(val)) {
|
|
129
|
+
array[index] = walkArray(val as JsonNode[]) as [];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return array;
|
|
133
|
+
}
|
|
134
|
+
}
|