@aws/nx-plugin 0.14.2 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -2
- package/src/open-api/ts-client/__snapshots__/generator.additional-properties.spec.ts.snap +2236 -0
- package/src/open-api/ts-client/__snapshots__/generator.complex-types.spec.ts.snap +2307 -0
- package/src/open-api/ts-client/__snapshots__/generator.composite-types.spec.ts.snap +1495 -0
- package/src/open-api/ts-client/__snapshots__/generator.primitive-types.spec.ts.snap +1470 -0
- package/src/open-api/ts-client/__snapshots__/generator.request.spec.ts.snap +1138 -0
- package/src/open-api/ts-client/__snapshots__/generator.response.spec.ts.snap +732 -0
- package/src/open-api/ts-client/__snapshots__/generator.tags.spec.ts.snap +743 -0
- package/src/open-api/ts-client/files/client.gen.ts.template +52 -15
- package/src/open-api/ts-client/files/types.gen.ts.template +5 -0
- package/src/open-api/ts-hooks/__snapshots__/generator.spec.tsx.snap +1092 -0
- package/src/open-api/ts-hooks/files/options-proxy.gen.ts.template +210 -0
- package/src/open-api/ts-hooks/generator.d.ts +5 -0
- package/src/open-api/ts-hooks/generator.js +15 -2
- package/src/open-api/ts-hooks/generator.js.map +1 -1
- package/src/open-api/ts-hooks/generator.spec.tsx +1787 -0
- package/src/open-api/utils/codegen-data/types.d.ts +25 -0
- package/src/open-api/utils/codegen-data/types.js +26 -1
- package/src/open-api/utils/codegen-data/types.js.map +1 -1
- package/src/open-api/utils/codegen-data.js +187 -79
- package/src/open-api/utils/codegen-data.js.map +1 -1
- package/src/open-api/utils/normalise.js +11 -1
- package/src/open-api/utils/normalise.js.map +1 -1
- package/src/py/fast-api/react/__snapshots__/generator.spec.ts.snap +120 -10
- package/src/py/fast-api/react/files/website/components/__apiNameClassName__Provider.tsx.template +40 -0
- package/src/py/fast-api/react/files/website/hooks/use__apiNameClassName__.tsx.template +13 -18
- package/src/py/fast-api/react/files/website/hooks/use__apiNameClassName__Client.tsx.template +13 -0
- package/src/py/fast-api/react/generator.js +35 -9
- package/src/py/fast-api/react/generator.js.map +1 -1
- package/src/py/project/generator.js +5 -0
- package/src/py/project/generator.js.map +1 -1
- package/src/trpc/backend/__snapshots__/generator.spec.ts.snap +7 -9
- package/src/utils/files/http-api/common/constructs/src/core/http-api.ts.template +7 -9
- package/src/open-api/ts-client/__snapshots__/generator.spec.ts.snap +0 -7880
|
@@ -23,3 +23,28 @@ export declare const flattenModelLink: (link?: Model | Model[]) => Model;
|
|
|
23
23
|
export declare const COMPOSED_SCHEMA_TYPES: Set<string>;
|
|
24
24
|
export declare const COLLECTION_TYPES: Set<string>;
|
|
25
25
|
export declare const PRIMITIVE_TYPES: Set<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Vendor extensions which are used to customise generated code
|
|
28
|
+
*/
|
|
29
|
+
export declare const VENDOR_EXTENSIONS: {
|
|
30
|
+
/**
|
|
31
|
+
* Set to 'true' to indicate this is a streaming API
|
|
32
|
+
*/
|
|
33
|
+
readonly STREAMING: "x-streaming";
|
|
34
|
+
/**
|
|
35
|
+
* Set to true to indicate this is a mutation, regardless of its HTTP method
|
|
36
|
+
*/
|
|
37
|
+
readonly MUTATION: "x-mutation";
|
|
38
|
+
/**
|
|
39
|
+
* Set to true to indicate this is a query, regardless of its HTTP method
|
|
40
|
+
*/
|
|
41
|
+
readonly QUERY: "x-query";
|
|
42
|
+
/**
|
|
43
|
+
* Set to the name of the input property used as the cursor for pagination if
|
|
44
|
+
* the API accepts a cursor that is not named 'cursor'.
|
|
45
|
+
* This can also be set to false to override behaviour and indicate this is not
|
|
46
|
+
* a paginated API.
|
|
47
|
+
* Used for tanstack infinite query hooks.
|
|
48
|
+
*/
|
|
49
|
+
readonly CURSOR: "x-cursor";
|
|
50
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.PRIMITIVE_TYPES = exports.COLLECTION_TYPES = exports.COMPOSED_SCHEMA_TYPES = exports.flattenModelLink = void 0;
|
|
3
|
+
exports.VENDOR_EXTENSIONS = exports.PRIMITIVE_TYPES = exports.COLLECTION_TYPES = exports.COMPOSED_SCHEMA_TYPES = exports.flattenModelLink = void 0;
|
|
4
4
|
const flattenModelLink = (link) => link === undefined ? undefined : Array.isArray(link) ? link[0] : link;
|
|
5
5
|
exports.flattenModelLink = flattenModelLink;
|
|
6
6
|
// Model types which indicate it is composed (ie inherits/mixin's another schema)
|
|
@@ -16,4 +16,29 @@ exports.PRIMITIVE_TYPES = new Set([
|
|
|
16
16
|
'binary',
|
|
17
17
|
'void',
|
|
18
18
|
]);
|
|
19
|
+
/**
|
|
20
|
+
* Vendor extensions which are used to customise generated code
|
|
21
|
+
*/
|
|
22
|
+
exports.VENDOR_EXTENSIONS = {
|
|
23
|
+
/**
|
|
24
|
+
* Set to 'true' to indicate this is a streaming API
|
|
25
|
+
*/
|
|
26
|
+
STREAMING: 'x-streaming',
|
|
27
|
+
/**
|
|
28
|
+
* Set to true to indicate this is a mutation, regardless of its HTTP method
|
|
29
|
+
*/
|
|
30
|
+
MUTATION: 'x-mutation',
|
|
31
|
+
/**
|
|
32
|
+
* Set to true to indicate this is a query, regardless of its HTTP method
|
|
33
|
+
*/
|
|
34
|
+
QUERY: 'x-query',
|
|
35
|
+
/**
|
|
36
|
+
* Set to the name of the input property used as the cursor for pagination if
|
|
37
|
+
* the API accepts a cursor that is not named 'cursor'.
|
|
38
|
+
* This can also be set to false to override behaviour and indicate this is not
|
|
39
|
+
* a paginated API.
|
|
40
|
+
* Used for tanstack infinite query hooks.
|
|
41
|
+
*/
|
|
42
|
+
CURSOR: 'x-cursor',
|
|
43
|
+
};
|
|
19
44
|
//# sourceMappingURL=types.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../packages/nx-plugin/src/open-api/utils/codegen-data/types.ts"],"names":[],"mappings":";;;AAoBO,MAAM,gBAAgB,GAAG,CAAC,IAAsB,EAAS,EAAE,CAChE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAD3D,QAAA,gBAAgB,oBAC2C;AAExE,iFAAiF;AACpE,QAAA,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAChE,QAAA,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;AACpD,QAAA,eAAe,GAAG,IAAI,GAAG,CAAC;IACrC,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,SAAS;IACT,MAAM;IACN,KAAK;IACL,QAAQ;IACR,MAAM;CACP,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../../../../../packages/nx-plugin/src/open-api/utils/codegen-data/types.ts"],"names":[],"mappings":";;;AAoBO,MAAM,gBAAgB,GAAG,CAAC,IAAsB,EAAS,EAAE,CAChE,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAD3D,QAAA,gBAAgB,oBAC2C;AAExE,iFAAiF;AACpE,QAAA,qBAAqB,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;AAChE,QAAA,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC;AACpD,QAAA,eAAe,GAAG,IAAI,GAAG,CAAC;IACrC,QAAQ;IACR,SAAS;IACT,QAAQ;IACR,SAAS;IACT,MAAM;IACN,KAAK;IACL,QAAQ;IACR,MAAM;CACP,CAAC,CAAC;AAEH;;GAEG;AACU,QAAA,iBAAiB,GAAG;IAC/B;;OAEG;IACH,SAAS,EAAE,aAAa;IACxB;;OAEG;IACH,QAAQ,EAAE,YAAY;IACtB;;OAEG;IACH,KAAK,EAAE,SAAS;IAChB;;;;;;OAMG;IACH,MAAM,EAAE,UAAU;CACV,CAAC"}
|
|
@@ -22,6 +22,7 @@ const types_1 = require("./codegen-data/types");
|
|
|
22
22
|
* Builds a data structure from an OpenAPI spec which can be used to generate code
|
|
23
23
|
*/
|
|
24
24
|
const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
25
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s;
|
|
25
26
|
// Ensure spec is ready for codegen
|
|
26
27
|
const spec = (0, normalise_1.normaliseOpenApiSpecForCodeGen)(inSpec);
|
|
27
28
|
// Build the initial data, which we will augment with additional information
|
|
@@ -32,12 +33,11 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
32
33
|
ensureCompositeModels(data);
|
|
33
34
|
const modelsByName = Object.fromEntries(data.models.map((m) => [m.name, m]));
|
|
34
35
|
// Augment operations with additional data
|
|
35
|
-
data.services
|
|
36
|
+
for (const service of data.services) {
|
|
36
37
|
// Keep track of the request and response models we need the service (ie api client) to import
|
|
37
38
|
const requestModelImports = [];
|
|
38
39
|
const responseModelImports = [];
|
|
39
|
-
service.operations
|
|
40
|
-
var _a, _b, _c, _d, _e, _f;
|
|
40
|
+
for (const op of service.operations) {
|
|
41
41
|
// Extract the operation back from the openapi spec
|
|
42
42
|
const specOp = (_b = (_a = spec === null || spec === void 0 ? void 0 : spec.paths) === null || _a === void 0 ? void 0 : _a[op.path]) === null || _b === void 0 ? void 0 : _b[op.method.toLowerCase()];
|
|
43
43
|
op.name = (_c = op.id) !== null && _c !== void 0 ? _c : op.name;
|
|
@@ -53,12 +53,11 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
53
53
|
responseModelImports.push(...op.responses
|
|
54
54
|
.filter((r) => r.export === 'reference')
|
|
55
55
|
.map((r) => r.type));
|
|
56
|
-
op.responses
|
|
57
|
-
var _a;
|
|
56
|
+
for (const response of op.responses) {
|
|
58
57
|
// Validate that the response is not a composite schema of primitives since we cannot determine what
|
|
59
58
|
// the type of the response is (it all comes back as text!)
|
|
60
59
|
if (response.export === 'reference' &&
|
|
61
|
-
types_1.COMPOSED_SCHEMA_TYPES.has((
|
|
60
|
+
types_1.COMPOSED_SCHEMA_TYPES.has((_e = modelsByName[response.type]) === null || _e === void 0 ? void 0 : _e.export)) {
|
|
62
61
|
const composedPrimitives = modelsByName[response.type].composedPrimitives.filter((p) => !['array', 'dictionary'].includes(p.export));
|
|
63
62
|
if (composedPrimitives.length > 0) {
|
|
64
63
|
throw new Error(`Operation "${op.method} ${op.path}" returns a composite schema of primitives with ${(0, lodash_camelcase_1.default)(modelsByName[response.type].export)}, which cannot be distinguished at runtime`);
|
|
@@ -79,25 +78,23 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
79
78
|
// Add the response media types
|
|
80
79
|
const mediaTypes = Object.keys(specResponse.content);
|
|
81
80
|
response.mediaTypes = mediaTypes;
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const responseContent = (_b = (_a = specResponse.content) === null || _a === void 0 ? void 0 : _a[mediaType]) !== null && _b !== void 0 ? _b : Object.values(specResponse.content)[0];
|
|
81
|
+
for (const mediaType of mediaTypes) {
|
|
82
|
+
const responseContent = (_g = (_f = specResponse.content) === null || _f === void 0 ? void 0 : _f[mediaType]) !== null && _g !== void 0 ? _g : Object.values(specResponse.content)[0];
|
|
85
83
|
const responseSchema = (0, refs_1.resolveIfRef)(spec, responseContent.schema);
|
|
86
84
|
if (responseSchema) {
|
|
87
|
-
mutateWithOpenapiSchemaProperties(spec, response, responseSchema);
|
|
85
|
+
yield mutateWithOpenapiSchemaProperties(spec, response, responseSchema, modelsByName);
|
|
88
86
|
}
|
|
89
|
-
}
|
|
87
|
+
}
|
|
90
88
|
}
|
|
91
89
|
}
|
|
92
|
-
}
|
|
90
|
+
}
|
|
93
91
|
}
|
|
94
|
-
const specParametersByName = Object.fromEntries(((
|
|
92
|
+
const specParametersByName = Object.fromEntries(((_h = specOp === null || specOp === void 0 ? void 0 : specOp.parameters) !== null && _h !== void 0 ? _h : []).map((p) => {
|
|
95
93
|
const param = (0, refs_1.resolveIfRef)(spec, p);
|
|
96
94
|
return [param.name, param];
|
|
97
95
|
}));
|
|
98
96
|
// Loop through the parameters
|
|
99
|
-
op.parameters
|
|
100
|
-
var _a, _b, _c, _d, _e;
|
|
97
|
+
for (const parameter of op.parameters) {
|
|
101
98
|
// Add the request model import
|
|
102
99
|
if (parameter.export === 'reference') {
|
|
103
100
|
requestModelImports.push(parameter.type);
|
|
@@ -105,7 +102,7 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
105
102
|
const specParameter = specParametersByName[parameter.prop];
|
|
106
103
|
const specParameterSchema = (0, refs_1.resolveIfRef)(spec, specParameter === null || specParameter === void 0 ? void 0 : specParameter.schema);
|
|
107
104
|
if (specParameterSchema) {
|
|
108
|
-
mutateWithOpenapiSchemaProperties(spec, parameter, specParameterSchema);
|
|
105
|
+
yield mutateWithOpenapiSchemaProperties(spec, parameter, specParameterSchema, modelsByName);
|
|
109
106
|
}
|
|
110
107
|
if (parameter.in === 'body') {
|
|
111
108
|
// Parameter name for the body is 'body'
|
|
@@ -116,9 +113,9 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
116
113
|
const specBody = (0, refs_1.resolveIfRef)(spec, specOp === null || specOp === void 0 ? void 0 : specOp.requestBody);
|
|
117
114
|
if (specBody) {
|
|
118
115
|
if (parameter.mediaType) {
|
|
119
|
-
const bodySchema = (0, refs_1.resolveIfRef)(spec, (
|
|
116
|
+
const bodySchema = (0, refs_1.resolveIfRef)(spec, (_k = (_j = specBody.content) === null || _j === void 0 ? void 0 : _j[parameter.mediaType]) === null || _k === void 0 ? void 0 : _k.schema);
|
|
120
117
|
if (bodySchema) {
|
|
121
|
-
mutateWithOpenapiSchemaProperties(spec, parameter, bodySchema);
|
|
118
|
+
yield mutateWithOpenapiSchemaProperties(spec, parameter, bodySchema, modelsByName);
|
|
122
119
|
}
|
|
123
120
|
}
|
|
124
121
|
// Track all the media types that can be accepted in the request body
|
|
@@ -129,17 +126,17 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
129
126
|
specParameter) {
|
|
130
127
|
// Translate style/explode to OpenAPI v2 style collectionFormat
|
|
131
128
|
// https://spec.openapis.org/oas/v3.0.3.html#style-values
|
|
132
|
-
const style = (
|
|
133
|
-
const explode = (
|
|
129
|
+
const style = (_l = specParameter.style) !== null && _l !== void 0 ? _l : (parameter.in === 'query' ? 'form' : 'simple');
|
|
130
|
+
const explode = (_m = specParameter.explode) !== null && _m !== void 0 ? _m : style === 'form';
|
|
134
131
|
if (parameter.in === 'query') {
|
|
135
132
|
parameter.collectionFormat = explode
|
|
136
133
|
? 'multi'
|
|
137
|
-
: ((
|
|
134
|
+
: ((_o = {
|
|
138
135
|
spaceDelimited: 'ssv',
|
|
139
136
|
pipeDelimited: 'tsv',
|
|
140
137
|
simple: 'csv',
|
|
141
138
|
form: 'csv',
|
|
142
|
-
}[style]) !== null &&
|
|
139
|
+
}[style]) !== null && _o !== void 0 ? _o : 'multi');
|
|
143
140
|
}
|
|
144
141
|
else {
|
|
145
142
|
// parameter.in === "header"
|
|
@@ -147,9 +144,9 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
147
144
|
}
|
|
148
145
|
}
|
|
149
146
|
mutateModelWithAdditionalTypes(parameter);
|
|
150
|
-
}
|
|
147
|
+
}
|
|
151
148
|
// Add language types to response models
|
|
152
|
-
((
|
|
149
|
+
((_p = op.responses) !== null && _p !== void 0 ? _p : []).forEach(mutateModelWithAdditionalTypes);
|
|
153
150
|
// Sort responses by code
|
|
154
151
|
op.responses = (0, lodash_orderby_1.default)(op.responses, (r) => r.code);
|
|
155
152
|
// Result is the lowest successful response, otherwise is the 2XX or default response
|
|
@@ -160,7 +157,8 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
160
157
|
op.operationIdPascalCase = (0, names_1.pascalCase)(op.uniqueName);
|
|
161
158
|
op.operationIdKebabCase = (0, lodash_kebabcase_1.default)(op.uniqueName);
|
|
162
159
|
op.operationIdSnakeCase = (0, languages_1.toPythonName)('operation', op.uniqueName);
|
|
163
|
-
|
|
160
|
+
mutateOperationWithAdditionalData(op);
|
|
161
|
+
}
|
|
164
162
|
// Lexicographical ordering of operations
|
|
165
163
|
service.operations = (0, lodash_orderby_1.default)(service.operations, (op) => op.uniqueName);
|
|
166
164
|
// Add the models to import
|
|
@@ -169,7 +167,7 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
169
167
|
service.className = `${service.name}Api`;
|
|
170
168
|
service.classNameSnakeCase = (0, lodash_snakecase_1.default)(service.className);
|
|
171
169
|
service.nameSnakeCase = (0, lodash_snakecase_1.default)(service.name);
|
|
172
|
-
}
|
|
170
|
+
}
|
|
173
171
|
// All operations across all services
|
|
174
172
|
const allOperations = (0, lodash_uniqby_1.default)(data.services.flatMap((s) => s.operations), (o) => o.uniqueName);
|
|
175
173
|
// Add additional models for operation parameters
|
|
@@ -245,14 +243,13 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
245
243
|
}),
|
|
246
244
|
];
|
|
247
245
|
// Augment models with additional data
|
|
248
|
-
data.models
|
|
249
|
-
var _a, _b;
|
|
246
|
+
for (const model of data.models) {
|
|
250
247
|
// Add a snake_case name
|
|
251
248
|
model.nameSnakeCase = (0, languages_1.toPythonName)('model', model.name);
|
|
252
|
-
const matchingSpecModel = (
|
|
249
|
+
const matchingSpecModel = (_r = (_q = spec === null || spec === void 0 ? void 0 : spec.components) === null || _q === void 0 ? void 0 : _q.schemas) === null || _r === void 0 ? void 0 : _r[model.name];
|
|
253
250
|
if (matchingSpecModel) {
|
|
254
251
|
const specModel = (0, refs_1.resolveIfRef)(spec, matchingSpecModel);
|
|
255
|
-
mutateWithOpenapiSchemaProperties(spec, model, specModel);
|
|
252
|
+
yield mutateWithOpenapiSchemaProperties(spec, model, specModel, modelsByName);
|
|
256
253
|
// Add unique imports
|
|
257
254
|
model.uniqueImports = (0, lodash_orderby_1.default)((0, lodash_uniqby_1.default)([
|
|
258
255
|
...model.imports,
|
|
@@ -263,26 +260,21 @@ const buildOpenApiCodeGenData = (inSpec) => tslib_1.__awaiter(void 0, void 0, vo
|
|
|
263
260
|
], (x) => x)).filter((modelImport) => modelImport !== model.name); // Filter out self for recursive model references
|
|
264
261
|
// Add deprecated flag if present
|
|
265
262
|
model.deprecated = specModel.deprecated || false;
|
|
266
|
-
// If the model has "additionalProperties" there should be a "dictionary" property
|
|
267
|
-
if (specModel.additionalProperties) {
|
|
268
|
-
model.additionalPropertiesProperty = model.properties.find((p) => !p.name && p.export === 'dictionary');
|
|
269
|
-
}
|
|
270
263
|
// Augment properties with additional data
|
|
271
|
-
model.properties
|
|
272
|
-
|
|
273
|
-
const matchingSpecProperty = (_a = specModel.properties) === null || _a === void 0 ? void 0 : _a[property.name];
|
|
264
|
+
for (const property of model.properties) {
|
|
265
|
+
const matchingSpecProperty = (_s = specModel.properties) === null || _s === void 0 ? void 0 : _s[property.name];
|
|
274
266
|
if (matchingSpecProperty) {
|
|
275
267
|
const specProperty = (0, refs_1.resolveIfRef)(spec, matchingSpecProperty);
|
|
276
|
-
mutateWithOpenapiSchemaProperties(spec, property, specProperty);
|
|
268
|
+
yield mutateWithOpenapiSchemaProperties(spec, property, specProperty, modelsByName);
|
|
277
269
|
}
|
|
278
|
-
}
|
|
270
|
+
}
|
|
279
271
|
}
|
|
280
272
|
// Augment properties with additional data
|
|
281
273
|
model.properties.forEach((property) => {
|
|
282
274
|
// Add language-specific names/types
|
|
283
275
|
mutateModelWithAdditionalTypes(property);
|
|
284
276
|
});
|
|
285
|
-
}
|
|
277
|
+
}
|
|
286
278
|
// Order models lexicographically by name
|
|
287
279
|
data.models = (0, lodash_orderby_1.default)(data.models, (d) => d.name);
|
|
288
280
|
// Order services so default appears first, then otherwise by name
|
|
@@ -321,35 +313,57 @@ const buildInitialCodeGenData = (spec) => tslib_1.__awaiter(void 0, void 0, void
|
|
|
321
313
|
data = client;
|
|
322
314
|
},
|
|
323
315
|
});
|
|
324
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
path: spec,
|
|
336
|
-
},
|
|
337
|
-
output: 'unused',
|
|
338
|
-
plugins: [plugin()],
|
|
339
|
-
dryRun: true,
|
|
340
|
-
logs: { level: 'silent' },
|
|
341
|
-
});
|
|
342
|
-
}
|
|
343
|
-
finally {
|
|
344
|
-
global.window = prevGlobalWindow;
|
|
345
|
-
global.location = prevGlobalLocation;
|
|
346
|
-
}
|
|
316
|
+
// Use @hey-api/openapi-ts to build the initial data structure that we'll generate clients from
|
|
317
|
+
yield gen.createClient({
|
|
318
|
+
experimentalParser: false,
|
|
319
|
+
input: {
|
|
320
|
+
path: spec,
|
|
321
|
+
},
|
|
322
|
+
output: 'unused',
|
|
323
|
+
plugins: [plugin()],
|
|
324
|
+
dryRun: true,
|
|
325
|
+
logs: { level: 'silent' },
|
|
326
|
+
});
|
|
347
327
|
if (!data) {
|
|
348
328
|
// If this happens it indicates an update to @hey-api/openapi-ts which has removed the legacy parser
|
|
349
329
|
throw new Error('Failed to build code generation data');
|
|
350
330
|
}
|
|
351
331
|
return data;
|
|
352
332
|
});
|
|
333
|
+
/**
|
|
334
|
+
* Build a model for a particular primitive schema.
|
|
335
|
+
* Only primitives are supported since we only return one model.
|
|
336
|
+
* For non-primitives, it assumes all referenced subschemas are already models
|
|
337
|
+
*/
|
|
338
|
+
const buildModelForPrimitive = (originalSpec, schema) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
339
|
+
var _a;
|
|
340
|
+
const targetSchemaName = '___aws_nx_plugin_openapi_tmp_schema___';
|
|
341
|
+
const spec = {
|
|
342
|
+
openapi: '3.1.0',
|
|
343
|
+
info: { title: 'tmp', version: '1.0.0' },
|
|
344
|
+
paths: {},
|
|
345
|
+
components: {
|
|
346
|
+
schemas: Object.assign(Object.assign({}, (_a = originalSpec.components) === null || _a === void 0 ? void 0 : _a.schemas), { [targetSchemaName]: schema }),
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
const data = yield buildInitialCodeGenData(spec);
|
|
350
|
+
const model = data.models.find((m) => m.name === targetSchemaName);
|
|
351
|
+
if (!model) {
|
|
352
|
+
throw new Error(`Failed to construct model for schema ${JSON.stringify(schema)}`);
|
|
353
|
+
}
|
|
354
|
+
ensureModelLinks(spec, data);
|
|
355
|
+
yield mutateWithOpenapiSchemaProperties(spec, model, schema, Object.fromEntries(data.models.map((m) => [m.name, m])));
|
|
356
|
+
return model;
|
|
357
|
+
});
|
|
358
|
+
const buildOrReferenceModel = (spec, modelsByName, schema) => tslib_1.__awaiter(void 0, void 0, void 0, function* () {
|
|
359
|
+
if ((0, refs_1.isRef)(schema)) {
|
|
360
|
+
const name = (0, refs_1.splitRef)(schema.$ref)[2];
|
|
361
|
+
return modelsByName[name];
|
|
362
|
+
}
|
|
363
|
+
// Non referenced schemas won't have a model created as they are primitives and aren't covered by @heyapi
|
|
364
|
+
// So we build the model here
|
|
365
|
+
return yield buildModelForPrimitive(spec, schema);
|
|
366
|
+
});
|
|
353
367
|
/**
|
|
354
368
|
* Copy vendor extensions from the first parameter to the second
|
|
355
369
|
*/
|
|
@@ -360,8 +374,8 @@ const copyVendorExtensions = (object, vendorExtensions) => {
|
|
|
360
374
|
}
|
|
361
375
|
});
|
|
362
376
|
};
|
|
363
|
-
const mutateWithOpenapiSchemaProperties = (spec, model, schema, visited = new Set())
|
|
364
|
-
var _a;
|
|
377
|
+
const mutateWithOpenapiSchemaProperties = (spec_1, model_1, schema_1, modelsByName_1, ...args_1) => tslib_1.__awaiter(void 0, [spec_1, model_1, schema_1, modelsByName_1, ...args_1], void 0, function* (spec, model, schema, modelsByName, visited = new Set()) {
|
|
378
|
+
var _a, _b, _c;
|
|
365
379
|
model.format = schema.format;
|
|
366
380
|
model.isInteger = schema.type === 'integer';
|
|
367
381
|
model.isShort = schema.format === 'int32';
|
|
@@ -375,6 +389,53 @@ const mutateWithOpenapiSchemaProperties = (spec, model, schema, visited = new Se
|
|
|
375
389
|
copyVendorExtensions(schema, model.vendorExtensions);
|
|
376
390
|
// Use our added vendor extension
|
|
377
391
|
model.isHoisted = !!((_a = model.vendorExtensions) === null || _a === void 0 ? void 0 : _a['x-aws-nx-hoisted']);
|
|
392
|
+
// Ensure models with additional properties are handled correctly
|
|
393
|
+
if (schema.additionalProperties) {
|
|
394
|
+
const additionalPropertiesModel = yield buildOrReferenceModel(spec, modelsByName, schema.additionalProperties === true ? {} : schema.additionalProperties);
|
|
395
|
+
// The original models treat _some_ objects with additional properties as a "dictionary", and others as an "interface"
|
|
396
|
+
// For the purposes of our code generation, we define a "dictionary" to be a model with no explicit properties, only
|
|
397
|
+
// additional properties. Interfaces can have a mixture of explicit properties and additional properties.
|
|
398
|
+
if (model.export === 'dictionary') {
|
|
399
|
+
// Dictionaries contain a special property which is the model itself. Other properties are explicit properties.
|
|
400
|
+
const explicitProperties = model.properties.filter((p) => !(p.export === 'dictionary' && p.name === model.name));
|
|
401
|
+
if (explicitProperties.length > 0 || schema.patternProperties) {
|
|
402
|
+
// Treat this model as an interface instead of a dictionary, since this has
|
|
403
|
+
// explicit properties
|
|
404
|
+
model.export = 'interface';
|
|
405
|
+
model.hasAdditionalProperties = true;
|
|
406
|
+
model.additionalPropertiesModel = additionalPropertiesModel;
|
|
407
|
+
model.properties = explicitProperties;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
model.hasAdditionalProperties = true;
|
|
412
|
+
model.additionalPropertiesModel = additionalPropertiesModel;
|
|
413
|
+
// There's a special property named [key: string] which is the definition of the additional properties
|
|
414
|
+
// We remove this so we don't render it as a regular property.
|
|
415
|
+
model.properties = ((_b = model.properties) !== null && _b !== void 0 ? _b : []).filter((p) => p.name !== '[key: string]');
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
// Ensure models with pattern properties are handled correctly
|
|
419
|
+
if (schema.patternProperties) {
|
|
420
|
+
const patternProperties = (0, refs_1.resolveIfRef)(spec, schema.patternProperties);
|
|
421
|
+
const patternPropertiesModels = [];
|
|
422
|
+
// When there are pattern properties, we don't want to treat models as dictionaries since there can be more than one type of "value"
|
|
423
|
+
// depending on what pattern the key matches
|
|
424
|
+
if (model.export === 'dictionary') {
|
|
425
|
+
model.export = 'interface';
|
|
426
|
+
}
|
|
427
|
+
for (const [pattern, patternProperty] of Object.entries(patternProperties)) {
|
|
428
|
+
const patternPropertyModel = yield buildOrReferenceModel(spec, modelsByName, patternProperty);
|
|
429
|
+
if (patternPropertyModel) {
|
|
430
|
+
patternPropertiesModels.push({
|
|
431
|
+
pattern,
|
|
432
|
+
model: patternPropertyModel,
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
model.hasPatternProperties = true;
|
|
437
|
+
model.patternPropertiesModels = patternPropertiesModels;
|
|
438
|
+
}
|
|
378
439
|
mutateModelWithAdditionalTypes(model);
|
|
379
440
|
visited.add(model);
|
|
380
441
|
const modelLink = (0, types_1.flattenModelLink)(model.link);
|
|
@@ -385,7 +446,7 @@ const mutateWithOpenapiSchemaProperties = (spec, model, schema, visited = new Se
|
|
|
385
446
|
schema.items &&
|
|
386
447
|
!visited.has(modelLink)) {
|
|
387
448
|
const subSchema = (0, refs_1.resolveIfRef)(spec, schema.items);
|
|
388
|
-
mutateWithOpenapiSchemaProperties(spec, modelLink, subSchema, visited);
|
|
449
|
+
yield mutateWithOpenapiSchemaProperties(spec, modelLink, subSchema, modelsByName, visited);
|
|
389
450
|
}
|
|
390
451
|
// Also apply to object properties recursively
|
|
391
452
|
if (model.export === 'dictionary' &&
|
|
@@ -396,25 +457,22 @@ const mutateWithOpenapiSchemaProperties = (spec, model, schema, visited = new Se
|
|
|
396
457
|
const subSchema = (0, refs_1.resolveIfRef)(spec, schema.additionalProperties);
|
|
397
458
|
// Additional properties can be "true" rather than a type
|
|
398
459
|
if (subSchema !== true) {
|
|
399
|
-
mutateWithOpenapiSchemaProperties(spec, modelLink, subSchema, visited);
|
|
460
|
+
yield mutateWithOpenapiSchemaProperties(spec, modelLink, subSchema, modelsByName, visited);
|
|
400
461
|
}
|
|
401
462
|
}
|
|
402
|
-
model.properties
|
|
403
|
-
.filter((p) => { var _a; return !visited.has(p) && ((_a = schema.properties) === null || _a === void 0 ? void 0 : _a[(0, lodash_trim_1.default)(p.name, `"'`)]); })
|
|
404
|
-
.forEach((property) => {
|
|
463
|
+
for (const property of model.properties.filter((p) => { var _a; return !visited.has(p) && ((_a = schema.properties) === null || _a === void 0 ? void 0 : _a[(0, lodash_trim_1.default)(p.name, `"'`)]); })) {
|
|
405
464
|
const subSchema = (0, refs_1.resolveIfRef)(spec, schema.properties[(0, lodash_trim_1.default)(property.name, `"'`)]);
|
|
406
|
-
mutateWithOpenapiSchemaProperties(spec, property, subSchema, visited);
|
|
407
|
-
}
|
|
465
|
+
yield mutateWithOpenapiSchemaProperties(spec, property, subSchema, modelsByName, visited);
|
|
466
|
+
}
|
|
408
467
|
if (types_1.COMPOSED_SCHEMA_TYPES.has(model.export)) {
|
|
409
|
-
model.properties.
|
|
410
|
-
|
|
411
|
-
const subSchema = (0, refs_1.resolveIfRef)(spec, (_a = schema[(0, lodash_camelcase_1.default)(model.export)]) === null || _a === void 0 ? void 0 : _a[i]);
|
|
468
|
+
for (let i = 0; i < model.properties.length; i++) {
|
|
469
|
+
const subSchema = (0, refs_1.resolveIfRef)(spec, (_c = schema[(0, lodash_camelcase_1.default)(model.export)]) === null || _c === void 0 ? void 0 : _c[i]);
|
|
412
470
|
if (subSchema) {
|
|
413
|
-
mutateWithOpenapiSchemaProperties(spec,
|
|
471
|
+
yield mutateWithOpenapiSchemaProperties(spec, model.properties[i], subSchema, modelsByName, visited);
|
|
414
472
|
}
|
|
415
|
-
}
|
|
473
|
+
}
|
|
416
474
|
}
|
|
417
|
-
};
|
|
475
|
+
});
|
|
418
476
|
/**
|
|
419
477
|
* Ensure that the "link" property of all dictionary/array models and properties are set recursively
|
|
420
478
|
*/
|
|
@@ -427,7 +485,8 @@ const ensureModelLinks = (spec, data) => {
|
|
|
427
485
|
const schema = (0, refs_1.resolveIfRef)(spec, (_b = (_a = spec === null || spec === void 0 ? void 0 : spec.components) === null || _a === void 0 ? void 0 : _a.schemas) === null || _b === void 0 ? void 0 : _b[model.name]);
|
|
428
486
|
if (schema) {
|
|
429
487
|
// Object schemas should be typed as the model we will create
|
|
430
|
-
if (schema.type === 'object' &&
|
|
488
|
+
if (schema.type === 'object' &&
|
|
489
|
+
(schema.properties || schema.patternProperties)) {
|
|
431
490
|
model.type = model.name;
|
|
432
491
|
}
|
|
433
492
|
_ensureModelLinks(spec, modelsByName, model, schema, visited);
|
|
@@ -579,4 +638,53 @@ const mutateModelWithAdditionalTypes = (model) => {
|
|
|
579
638
|
!types_1.COMPOSED_SCHEMA_TYPES.has(model.export) &&
|
|
580
639
|
!types_1.COLLECTION_TYPES.has(model.export);
|
|
581
640
|
};
|
|
641
|
+
/**
|
|
642
|
+
* Determine whether or not an operation is a mutation
|
|
643
|
+
*/
|
|
644
|
+
const isOperationMutation = (op) => {
|
|
645
|
+
// Let the user override whether an operation is a query or mutation using x-mutation/x-query
|
|
646
|
+
const { vendorExtensions } = op;
|
|
647
|
+
if (vendorExtensions === null || vendorExtensions === void 0 ? void 0 : vendorExtensions[types_1.VENDOR_EXTENSIONS.MUTATION]) {
|
|
648
|
+
return true;
|
|
649
|
+
}
|
|
650
|
+
else if (vendorExtensions === null || vendorExtensions === void 0 ? void 0 : vendorExtensions[types_1.VENDOR_EXTENSIONS.QUERY]) {
|
|
651
|
+
return false;
|
|
652
|
+
}
|
|
653
|
+
// Assume a restful API and treat mutative HTTP methods as mutations
|
|
654
|
+
return ['PATCH', 'POST', 'PUT', 'DELETE'].includes(op.method);
|
|
655
|
+
};
|
|
656
|
+
/**
|
|
657
|
+
* Add infinite query details to the operation
|
|
658
|
+
*/
|
|
659
|
+
const mutateOperationWithInfiniteQueryDetails = (op) => {
|
|
660
|
+
var _a;
|
|
661
|
+
const { vendorExtensions } = op;
|
|
662
|
+
// Allow users to customise the "cursor" property used for paginated requests
|
|
663
|
+
const cursorPropertyName = (_a = vendorExtensions === null || vendorExtensions === void 0 ? void 0 : vendorExtensions[types_1.VENDOR_EXTENSIONS.CURSOR]) !== null && _a !== void 0 ? _a : 'cursor';
|
|
664
|
+
const cursorProperty = op.parameters.find((p) => p.name === cursorPropertyName);
|
|
665
|
+
// The operation is an infinite query if:
|
|
666
|
+
// - x-cursor is not set to 'false' (this allows users to disable infinite queries for operations that accept a 'cursor')
|
|
667
|
+
// - the operation accepts a parameter named 'cursor', or a parameter named as the user specified with x-cursor
|
|
668
|
+
op.isInfiniteQuery =
|
|
669
|
+
(vendorExtensions === null || vendorExtensions === void 0 ? void 0 : vendorExtensions[types_1.VENDOR_EXTENSIONS.CURSOR]) !== false && !!cursorProperty;
|
|
670
|
+
if (op.isInfiniteQuery) {
|
|
671
|
+
op.infiniteQueryCursorProperty = cursorProperty;
|
|
672
|
+
}
|
|
673
|
+
};
|
|
674
|
+
/**
|
|
675
|
+
* Add additional data to an operation for code generation decisions
|
|
676
|
+
*/
|
|
677
|
+
const mutateOperationWithAdditionalData = (op) => {
|
|
678
|
+
var _a;
|
|
679
|
+
// Add mutation/query details
|
|
680
|
+
const isMutation = isOperationMutation(op);
|
|
681
|
+
op.isMutation = isMutation;
|
|
682
|
+
op.isQuery = !isMutation;
|
|
683
|
+
// Streaming responses
|
|
684
|
+
op.isStreaming = !!((_a = op.vendorExtensions) === null || _a === void 0 ? void 0 : _a[types_1.VENDOR_EXTENSIONS.STREAMING]);
|
|
685
|
+
// Add infinite query details if applicable
|
|
686
|
+
if (!isMutation) {
|
|
687
|
+
mutateOperationWithInfiniteQueryDetails(op);
|
|
688
|
+
}
|
|
689
|
+
};
|
|
582
690
|
//# sourceMappingURL=codegen-data.js.map
|