@opra/cli 1.0.0-alpha.9 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/file-writer.js +2 -2
- package/cjs/oprimp-cli.js +11 -9
- package/cjs/ts-generator/{processors → generators}/clean-directory.js +4 -5
- package/cjs/ts-generator/generators/generate-data-type.js +258 -0
- package/cjs/ts-generator/generators/generate-document.js +64 -0
- package/cjs/ts-generator/{processors/process-http-api.js → generators/generate-http-api.js} +3 -4
- package/cjs/ts-generator/generators/generate-http-controller.js +296 -0
- package/cjs/ts-generator/ts-file.js +18 -12
- package/cjs/ts-generator/ts-generator.js +20 -20
- package/cjs/ts-generator/utils/locate-named-type.js +1 -2
- package/cjs/ts-generator/utils/string-utils.js +4 -5
- package/esm/file-writer.js +1 -1
- package/esm/oprimp-cli.js +9 -7
- package/esm/package.json +3 -0
- package/esm/ts-generator/{processors → generators}/clean-directory.js +3 -3
- package/esm/ts-generator/generators/generate-data-type.js +248 -0
- package/esm/ts-generator/{processors/process-document.js → generators/generate-document.js} +17 -12
- package/esm/ts-generator/{processors/process-http-api.js → generators/generate-http-api.js} +2 -2
- package/esm/ts-generator/generators/generate-http-controller.js +292 -0
- package/esm/ts-generator/ts-file.js +15 -9
- package/esm/ts-generator/ts-generator.js +20 -20
- package/package.json +28 -33
- package/types/file-writer.d.ts +1 -1
- package/types/index.d.cts +1 -0
- package/types/interfaces/service-generation-context.interface.d.ts +2 -2
- package/types/ts-generator/generators/generate-data-type.d.ts +41 -0
- package/types/ts-generator/{processors/process-document.d.ts → generators/generate-document.d.ts} +1 -1
- package/types/ts-generator/generators/generate-http-api.d.ts +3 -0
- package/types/ts-generator/generators/generate-http-controller.d.ts +3 -0
- package/types/ts-generator/ts-file.d.ts +6 -2
- package/types/ts-generator/ts-generator.d.ts +22 -20
- package/bin/bin/oprimp.mjs +0 -3
- package/cjs/ts-generator/processors/process-data-types.js +0 -262
- package/cjs/ts-generator/processors/process-document.js +0 -60
- package/cjs/ts-generator/processors/process-http-controller.js +0 -189
- package/esm/ts-generator/processors/process-data-types.js +0 -251
- package/esm/ts-generator/processors/process-http-controller.js +0 -184
- package/types/ts-generator/processors/process-data-types.d.ts +0 -30
- package/types/ts-generator/processors/process-http-api.d.ts +0 -3
- package/types/ts-generator/processors/process-http-controller.d.ts +0 -3
- /package/types/ts-generator/{processors → generators}/clean-directory.d.ts +0 -0
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateHttpController = generateHttpController;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
|
+
const type_is_1 = tslib_1.__importDefault(require("@browsery/type-is"));
|
|
7
|
+
const common_1 = require("@opra/common");
|
|
8
|
+
const putil_varhelpers_1 = require("putil-varhelpers");
|
|
9
|
+
const code_block_js_1 = require("../../code-block.js");
|
|
10
|
+
const locate_named_type_js_1 = require("../utils/locate-named-type.js");
|
|
11
|
+
const string_utils_js_1 = require("../utils/string-utils.js");
|
|
12
|
+
async function generateHttpController(controller) {
|
|
13
|
+
let file = this._filesMap.get(controller);
|
|
14
|
+
if (file)
|
|
15
|
+
return file;
|
|
16
|
+
const generateParamDoc = async (name, type, options) => {
|
|
17
|
+
let typeDef;
|
|
18
|
+
if (type) {
|
|
19
|
+
const xt = await this.generateDataType(type, 'typeDef', file);
|
|
20
|
+
typeDef = xt.kind === 'embedded' ? 'object' : xt.typeName;
|
|
21
|
+
}
|
|
22
|
+
else
|
|
23
|
+
typeDef = 'any';
|
|
24
|
+
if (options?.isArray)
|
|
25
|
+
typeDef += '[]';
|
|
26
|
+
let out = `\n * @param {${typeDef}} ` + (options?.required ? name : `[${name}]`);
|
|
27
|
+
if (options?.description)
|
|
28
|
+
out += ` - ${(0, string_utils_js_1.wrapJSDocString)(options?.description)}`;
|
|
29
|
+
if (type instanceof common_1.ComplexType && type.embedded) {
|
|
30
|
+
for (const f of type.fields.values()) {
|
|
31
|
+
out += await generateParamDoc(name + '.' + f.name, f.type, f);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
};
|
|
36
|
+
const className = (0, putil_varhelpers_1.pascalCase)(controller.name) + 'Controller';
|
|
37
|
+
file = this.addFile(node_path_1.default.join(this._apiPath, className + '.ts'));
|
|
38
|
+
file.addImport('@opra/client', ['HttpRequestObservable', 'kClient', 'OpraHttpClient']);
|
|
39
|
+
file.addImport(node_path_1.default.relative(file.dirname, '/http-controller-node.ts'), ['HttpControllerNode']);
|
|
40
|
+
const classBlock = (file.code[className] = new code_block_js_1.CodeBlock());
|
|
41
|
+
classBlock.doc = `/**
|
|
42
|
+
* ${(0, string_utils_js_1.wrapJSDocString)(controller.description || '')}
|
|
43
|
+
* @class ${className}
|
|
44
|
+
* @apiUrl ${node_path_1.default.posix.join(this.serviceUrl, controller.getFullUrl())}
|
|
45
|
+
*/`;
|
|
46
|
+
classBlock.head = `\nexport class ${className} extends HttpControllerNode {\n\t`;
|
|
47
|
+
classBlock.properties = '';
|
|
48
|
+
const classConstBlock = (classBlock.classConstBlock = new code_block_js_1.CodeBlock());
|
|
49
|
+
classConstBlock.head = `\n/**
|
|
50
|
+
* @param {OpraHttpClient} client - OpraHttpClient instance to operate
|
|
51
|
+
* @constructor
|
|
52
|
+
*/
|
|
53
|
+
constructor(client: OpraHttpClient) {`;
|
|
54
|
+
classConstBlock.body = `\n\tsuper(client);`;
|
|
55
|
+
classConstBlock.tail = `\b\n}\n`;
|
|
56
|
+
if (controller.controllers.size) {
|
|
57
|
+
for (const child of controller.controllers.values()) {
|
|
58
|
+
const generator = this.extend();
|
|
59
|
+
generator._apiPath = node_path_1.default.join(this._apiPath, className);
|
|
60
|
+
const f = await generator.generateHttpController(child);
|
|
61
|
+
const childClassName = (0, putil_varhelpers_1.pascalCase)(child.name) + 'Controller';
|
|
62
|
+
file.addImport(f.filename, [childClassName]);
|
|
63
|
+
const property = '$' + child.name.charAt(0).toLowerCase() + (0, putil_varhelpers_1.camelCase)(child.name.substring(1));
|
|
64
|
+
classBlock.properties += `\nreadonly ${property}: ${childClassName};`;
|
|
65
|
+
classConstBlock.body += `\nthis.${property} = new ${childClassName}(client);`;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Process operations */
|
|
69
|
+
const mergedControllerParams = [...controller.parameters];
|
|
70
|
+
let _base = controller;
|
|
71
|
+
while (_base.owner instanceof common_1.HttpController) {
|
|
72
|
+
_base = _base.owner;
|
|
73
|
+
mergedControllerParams.unshift(..._base?.parameters);
|
|
74
|
+
}
|
|
75
|
+
for (const operation of controller.operations.values()) {
|
|
76
|
+
const mergedParams = [...mergedControllerParams, ...operation.parameters];
|
|
77
|
+
const operationBlock = (classBlock['operation_' + operation.name] = new code_block_js_1.CodeBlock());
|
|
78
|
+
operationBlock.doc = new code_block_js_1.CodeBlock();
|
|
79
|
+
operationBlock.doc.header = `
|
|
80
|
+
/**
|
|
81
|
+
* ${(0, string_utils_js_1.wrapJSDocString)(operation.description || operation.name + ' operation')}`;
|
|
82
|
+
operationBlock.doc.parameters = new code_block_js_1.CodeBlock();
|
|
83
|
+
if (mergedParams.length) {
|
|
84
|
+
const block = new code_block_js_1.CodeBlock();
|
|
85
|
+
block.doc = '\n *\n * RegExp parameters:';
|
|
86
|
+
let i = 0;
|
|
87
|
+
for (const prm of operation.parameters) {
|
|
88
|
+
if (!(prm.name instanceof RegExp))
|
|
89
|
+
continue;
|
|
90
|
+
i++;
|
|
91
|
+
block.doc +=
|
|
92
|
+
`\n * > ${String(prm.name)} - ${prm.description || ''}` +
|
|
93
|
+
`\n * - location: ${prm.location}` +
|
|
94
|
+
`\n * - type: ${(0, locate_named_type_js_1.locateNamedType)(prm.type)?.name || 'any'}${prm.isArray ? '[' + prm.arraySeparator + ']' : ''}` +
|
|
95
|
+
(prm.required ? `\n * required: ${prm.required}` : '') +
|
|
96
|
+
(prm.deprecated ? `\n * deprecated: ${prm.deprecated}` : '');
|
|
97
|
+
}
|
|
98
|
+
if (i)
|
|
99
|
+
operationBlock.doc.regExParameters = block;
|
|
100
|
+
}
|
|
101
|
+
operationBlock.doc.tail = `
|
|
102
|
+
* @apiUrl ${node_path_1.default.posix.join(this.serviceUrl, operation.getFullUrl())}
|
|
103
|
+
*/\n`;
|
|
104
|
+
operationBlock.head = `${operation.name}(`;
|
|
105
|
+
/** Process operation parameters */
|
|
106
|
+
const pathParams = [];
|
|
107
|
+
const queryParams = [];
|
|
108
|
+
const headerParams = [];
|
|
109
|
+
if (mergedParams.length) {
|
|
110
|
+
const pathParamsMap = {};
|
|
111
|
+
const queryParamsMap = {};
|
|
112
|
+
const headerParamsMap = {};
|
|
113
|
+
for (const prm of mergedParams) {
|
|
114
|
+
if (typeof prm.name !== 'string')
|
|
115
|
+
continue;
|
|
116
|
+
if (prm.location === 'path')
|
|
117
|
+
pathParamsMap[prm.name] = prm;
|
|
118
|
+
if (prm.location === 'query')
|
|
119
|
+
queryParamsMap[prm.name] = prm;
|
|
120
|
+
if (prm.location === 'header')
|
|
121
|
+
headerParamsMap[prm.name] = prm;
|
|
122
|
+
}
|
|
123
|
+
pathParams.push(...Object.values(pathParamsMap));
|
|
124
|
+
queryParams.push(...Object.values(queryParamsMap));
|
|
125
|
+
headerParams.push(...Object.values(headerParamsMap));
|
|
126
|
+
}
|
|
127
|
+
/** Process path parameters and add as function arguments */
|
|
128
|
+
let argIndex = 0;
|
|
129
|
+
for (const prm of pathParams) {
|
|
130
|
+
let typeDef;
|
|
131
|
+
if (prm.type) {
|
|
132
|
+
const xt = await this.generateDataType(prm.type, 'typeDef', file);
|
|
133
|
+
typeDef = xt.kind === 'embedded' ? xt.code : xt.typeName;
|
|
134
|
+
}
|
|
135
|
+
else
|
|
136
|
+
typeDef = `any`;
|
|
137
|
+
if (prm.isArray)
|
|
138
|
+
typeDef += '[]';
|
|
139
|
+
if (argIndex++ > 0)
|
|
140
|
+
operationBlock.head += ', ';
|
|
141
|
+
operationBlock.head += `${prm.name}: ${typeDef}`;
|
|
142
|
+
operationBlock.doc.parameters +=
|
|
143
|
+
`\n * @param {${typeDef}} ` +
|
|
144
|
+
(prm.required ? prm.name : `[${prm.name}]`) +
|
|
145
|
+
(prm.description ? ' - ' + (0, string_utils_js_1.wrapJSDocString)(prm.description || '') : '');
|
|
146
|
+
}
|
|
147
|
+
/** Process requestBody and add as function argument ($body) */
|
|
148
|
+
let hasBody = false;
|
|
149
|
+
if (operation.requestBody?.content.length) {
|
|
150
|
+
if (argIndex++ > 0)
|
|
151
|
+
operationBlock.head += ', ';
|
|
152
|
+
let typeArr = [];
|
|
153
|
+
for (const content of operation.requestBody.content) {
|
|
154
|
+
if (content.type) {
|
|
155
|
+
/** Generate JSDoc for parameter */
|
|
156
|
+
operationBlock.doc.parameters += await generateParamDoc('$body', content.type, {
|
|
157
|
+
required: operation.requestBody.required,
|
|
158
|
+
description: content.description || content.type.description,
|
|
159
|
+
});
|
|
160
|
+
/** */
|
|
161
|
+
const xt = await this.generateDataType(content.type, 'typeDef', file);
|
|
162
|
+
let typeDef = xt.kind === 'embedded' ? xt.code : xt.typeName;
|
|
163
|
+
if (typeDef === 'any') {
|
|
164
|
+
typeArr = [];
|
|
165
|
+
break;
|
|
166
|
+
}
|
|
167
|
+
if (xt.kind === 'named') {
|
|
168
|
+
if (operation.requestBody.partial) {
|
|
169
|
+
file.addImport('ts-gems', ['PartialDTO']);
|
|
170
|
+
typeDef = `PartialDTO<${typeDef}>`;
|
|
171
|
+
}
|
|
172
|
+
else {
|
|
173
|
+
file.addImport('ts-gems', ['DTO']);
|
|
174
|
+
typeDef = `DTO<${typeDef}>`;
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
if (typeDef && content.isArray)
|
|
178
|
+
typeDef += '[]';
|
|
179
|
+
typeDef = typeDef || 'undefined';
|
|
180
|
+
if (!typeArr.includes(typeDef))
|
|
181
|
+
typeArr.push(typeDef);
|
|
182
|
+
continue;
|
|
183
|
+
}
|
|
184
|
+
else if (content.contentType && type_is_1.default.is(String(content.contentType), ['multipart/*'])) {
|
|
185
|
+
const typeDef = 'FormData';
|
|
186
|
+
if (!typeArr.includes(typeDef))
|
|
187
|
+
typeArr.push(typeDef);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
typeArr = [];
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
const typeDef = typeArr.join(' | ') || 'any';
|
|
194
|
+
operationBlock.head += `$body: ${typeDef}`;
|
|
195
|
+
// operationBlock.doc.parameters += `\n * @param {${typeDef}} $body - Http body` + bodyFields;
|
|
196
|
+
hasBody = true;
|
|
197
|
+
}
|
|
198
|
+
/** process query params */
|
|
199
|
+
const isQueryRequired = queryParams.find(p => p.required);
|
|
200
|
+
const isHeadersRequired = queryParams.find(p => p.required);
|
|
201
|
+
if (queryParams.length) {
|
|
202
|
+
if (argIndex++ > 0)
|
|
203
|
+
operationBlock.head += ', ';
|
|
204
|
+
operationBlock.head += '\n\t$params' + (isHeadersRequired || isQueryRequired ? '' : '?') + ': {\n\t';
|
|
205
|
+
operationBlock.doc.parameters += '\n * @param {object} $params - Available parameters for the operation';
|
|
206
|
+
let hasAdditionalFields = false;
|
|
207
|
+
for (const prm of queryParams) {
|
|
208
|
+
if (typeof prm.name !== 'string') {
|
|
209
|
+
hasAdditionalFields = true;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
operationBlock.doc.parameters += await generateParamDoc('$params.' + prm.name, prm.type, prm);
|
|
213
|
+
operationBlock.head += `${prm.name}${prm.required ? '' : '?'}: `;
|
|
214
|
+
if (prm.type) {
|
|
215
|
+
const xt = await this.generateDataType(prm.type, 'typeDef', file);
|
|
216
|
+
let typeDef = xt.kind === 'embedded' ? xt.code : xt.typeName;
|
|
217
|
+
if (prm.isArray)
|
|
218
|
+
typeDef += '[]';
|
|
219
|
+
operationBlock.head += `${typeDef};\n`;
|
|
220
|
+
}
|
|
221
|
+
else
|
|
222
|
+
operationBlock.head += `any;\n`;
|
|
223
|
+
}
|
|
224
|
+
if (hasAdditionalFields) {
|
|
225
|
+
operationBlock.head += '[index: string]: any;\n';
|
|
226
|
+
}
|
|
227
|
+
operationBlock.head += '\b}\b';
|
|
228
|
+
}
|
|
229
|
+
/** process header params */
|
|
230
|
+
if (headerParams.length) {
|
|
231
|
+
if (argIndex++ > 0)
|
|
232
|
+
operationBlock.head += ', \n';
|
|
233
|
+
operationBlock.head += '\t$headers' + (isHeadersRequired ? '' : '?') + ': {\n\t';
|
|
234
|
+
for (const prm of headerParams) {
|
|
235
|
+
operationBlock.head += `/**\n * ${prm.description || ''}\n */\n`;
|
|
236
|
+
operationBlock.head += `${prm.name}${prm.required ? '' : '?'}: `;
|
|
237
|
+
if (prm.type) {
|
|
238
|
+
const xt = await this.generateDataType(prm.type, 'typeDef', file);
|
|
239
|
+
let typeDef = xt.kind === 'embedded' ? xt.code : xt.typeName;
|
|
240
|
+
if (prm.isArray)
|
|
241
|
+
typeDef += '[]';
|
|
242
|
+
operationBlock.head += `${typeDef};\n`;
|
|
243
|
+
}
|
|
244
|
+
else
|
|
245
|
+
operationBlock.head += `any;\n`;
|
|
246
|
+
}
|
|
247
|
+
operationBlock.head += '\b}\b';
|
|
248
|
+
}
|
|
249
|
+
/* Determine return type */
|
|
250
|
+
const returnTypes = [];
|
|
251
|
+
let typeDef = '';
|
|
252
|
+
for (const resp of operation.responses) {
|
|
253
|
+
if (!resp.statusCode.find(r => r.intersects(200, 299)))
|
|
254
|
+
continue;
|
|
255
|
+
typeDef = '';
|
|
256
|
+
if (resp.type) {
|
|
257
|
+
const xt = await this.generateDataType(resp.type, 'typeDef', file);
|
|
258
|
+
typeDef = xt.kind === 'embedded' ? xt.code : xt.typeName;
|
|
259
|
+
}
|
|
260
|
+
if (typeDef) {
|
|
261
|
+
if (typeDef !== 'OperationResult') {
|
|
262
|
+
if (resp.partial) {
|
|
263
|
+
file.addImport('ts-gems', ['PartialDTO']);
|
|
264
|
+
typeDef = `PartialDTO<${typeDef}>`;
|
|
265
|
+
}
|
|
266
|
+
else {
|
|
267
|
+
file.addImport('ts-gems', ['DTO']);
|
|
268
|
+
typeDef = `DTO<${typeDef}>`;
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
if (typeDef && resp.isArray)
|
|
273
|
+
typeDef += '[]';
|
|
274
|
+
if (resp.contentType && type_is_1.default.is(String(resp.contentType), [common_1.MimeTypes.opra_response_json])) {
|
|
275
|
+
file.addImport('@opra/common', ['OperationResult']);
|
|
276
|
+
typeDef = typeDef ? `OperationResult<${typeDef}>` : 'OperationResult';
|
|
277
|
+
}
|
|
278
|
+
typeDef = typeDef || 'undefined';
|
|
279
|
+
if (!returnTypes.includes(typeDef))
|
|
280
|
+
returnTypes.push(typeDef);
|
|
281
|
+
}
|
|
282
|
+
operationBlock.head += `\n): HttpRequestObservable<${returnTypes.join(' | ') || 'any'}>{`;
|
|
283
|
+
operationBlock.body = `\n\t`;
|
|
284
|
+
operationBlock.body +=
|
|
285
|
+
`const url = this._prepareUrl('${operation.getFullUrl()}', {` + pathParams.map(p => p.name).join(', ') + '});';
|
|
286
|
+
operationBlock.body +=
|
|
287
|
+
`\nreturn this[kClient].request(url, { method: '${operation.method}'` +
|
|
288
|
+
(hasBody ? ', body: $body' : '') +
|
|
289
|
+
(queryParams.length ? ', params: $params as any' : '') +
|
|
290
|
+
(headerParams.length ? ', headers: $headers as any' : '') +
|
|
291
|
+
'});';
|
|
292
|
+
operationBlock.tail = `\b\n};\n`;
|
|
293
|
+
}
|
|
294
|
+
classBlock.tail = `\b}`;
|
|
295
|
+
return file;
|
|
296
|
+
}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.TsFile = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
|
-
const
|
|
5
|
+
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
6
6
|
const putil_flattentext_1 = tslib_1.__importDefault(require("putil-flattentext"));
|
|
7
7
|
const code_block_js_1 = require("../code-block.js");
|
|
8
8
|
class TsFile {
|
|
@@ -12,14 +12,14 @@ class TsFile {
|
|
|
12
12
|
this.exportFiles = {};
|
|
13
13
|
this.exportTypes = [];
|
|
14
14
|
this.code = new code_block_js_1.CodeBlock();
|
|
15
|
-
this.dirname =
|
|
15
|
+
this.dirname = node_path_1.default.dirname(filename);
|
|
16
16
|
this.code.header = '';
|
|
17
17
|
this.code.imports = '';
|
|
18
18
|
this.code.exports = '';
|
|
19
19
|
}
|
|
20
20
|
addImport(filename, items, typeImport) {
|
|
21
21
|
if (isLocalFile(filename)) {
|
|
22
|
-
filename =
|
|
22
|
+
filename = node_path_1.default.relative(this.dirname, node_path_1.default.resolve(this.dirname, filename));
|
|
23
23
|
if (!filename.startsWith('.'))
|
|
24
24
|
filename = './' + filename;
|
|
25
25
|
}
|
|
@@ -35,9 +35,9 @@ class TsFile {
|
|
|
35
35
|
imp.items.push(x);
|
|
36
36
|
});
|
|
37
37
|
}
|
|
38
|
-
addExport(filename, types) {
|
|
38
|
+
addExport(filename, types, namespace) {
|
|
39
39
|
if (isLocalFile(filename)) {
|
|
40
|
-
filename =
|
|
40
|
+
filename = node_path_1.default.relative(this.dirname, node_path_1.default.resolve(this.dirname, filename));
|
|
41
41
|
if (!filename.startsWith('.'))
|
|
42
42
|
filename = './' + filename;
|
|
43
43
|
}
|
|
@@ -45,10 +45,11 @@ class TsFile {
|
|
|
45
45
|
filename = filename.substring(0, filename.length - 5);
|
|
46
46
|
if (filename.endsWith('.ts') || filename.endsWith('.js'))
|
|
47
47
|
filename = filename.substring(0, filename.length - 3);
|
|
48
|
-
|
|
48
|
+
const key = (namespace ? namespace + ':' : '') + filename;
|
|
49
|
+
this.exportFiles[key] = this.exportFiles[key] || { filename, items: [], namespace };
|
|
49
50
|
types?.forEach(x => {
|
|
50
|
-
if (!this.exportFiles[filename].includes(x))
|
|
51
|
-
this.exportFiles[filename].push(x);
|
|
51
|
+
if (!this.exportFiles[filename].items.includes(x))
|
|
52
|
+
this.exportFiles[filename].items.push(x);
|
|
52
53
|
});
|
|
53
54
|
}
|
|
54
55
|
generate(options) {
|
|
@@ -76,18 +77,23 @@ class TsFile {
|
|
|
76
77
|
.join('\n');
|
|
77
78
|
this.code.exports = Object.keys(this.exportFiles)
|
|
78
79
|
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
|
79
|
-
.map(
|
|
80
|
-
const
|
|
80
|
+
.map(key => {
|
|
81
|
+
const exportFile = this.exportFiles[key];
|
|
82
|
+
const types = exportFile.items;
|
|
83
|
+
let filename = exportFile.filename;
|
|
81
84
|
if (!isPackageName(filename)) {
|
|
82
85
|
if (options?.importExt)
|
|
83
86
|
filename += '.js';
|
|
84
87
|
}
|
|
85
|
-
|
|
88
|
+
let out = `export ${types.length ? '{ ' + types.join(', ') + ' }' : '*'}`;
|
|
89
|
+
if (exportFile.namespace)
|
|
90
|
+
out += ` as ${exportFile.namespace}`;
|
|
91
|
+
return out + ` from '${filename}';`;
|
|
86
92
|
})
|
|
87
93
|
.join('\n');
|
|
88
94
|
if (this.code.imports || this.code.exports)
|
|
89
95
|
this.code.exports += '\n\n';
|
|
90
|
-
return ('/* #!oprimp_auto_generated!# !! Do NOT remove this line */\n/* eslint-disable */\n' +
|
|
96
|
+
return ('/* #!oprimp_auto_generated!# !! Do NOT remove this line */\n/* eslint-disable */\n// noinspection SpellCheckingInspection\n\n' +
|
|
91
97
|
(0, putil_flattentext_1.default)(String(this.code)));
|
|
92
98
|
}
|
|
93
99
|
}
|
|
@@ -6,13 +6,13 @@ const node_events_1 = require("node:events");
|
|
|
6
6
|
const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
|
|
7
7
|
const node_path_1 = tslib_1.__importDefault(require("node:path"));
|
|
8
8
|
const node_process_1 = tslib_1.__importDefault(require("node:process"));
|
|
9
|
-
const
|
|
9
|
+
const ansi_colors_1 = tslib_1.__importDefault(require("ansi-colors"));
|
|
10
10
|
const file_writer_js_1 = require("../file-writer.js");
|
|
11
|
-
const clean_directory_js_1 = require("./
|
|
12
|
-
const
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
11
|
+
const clean_directory_js_1 = require("./generators/clean-directory.js");
|
|
12
|
+
const generate_data_type_js_1 = require("./generators/generate-data-type.js");
|
|
13
|
+
const generate_document_js_1 = require("./generators/generate-document.js");
|
|
14
|
+
const generate_http_api_js_1 = require("./generators/generate-http-api.js");
|
|
15
|
+
const generate_http_controller_js_1 = require("./generators/generate-http-controller.js");
|
|
16
16
|
const ts_file_js_1 = require("./ts-file.js");
|
|
17
17
|
/**
|
|
18
18
|
* @class TsGenerator
|
|
@@ -24,14 +24,14 @@ class TsGenerator extends node_events_1.EventEmitter {
|
|
|
24
24
|
*/
|
|
25
25
|
constructor(init) {
|
|
26
26
|
super();
|
|
27
|
-
this._started = false;
|
|
28
27
|
this._files = {};
|
|
28
|
+
this._started = false;
|
|
29
29
|
this.serviceUrl = init.serviceUrl;
|
|
30
30
|
this.cwd = init.cwd || node_process_1.default.cwd();
|
|
31
31
|
this.outDir = init.outDir ? node_path_1.default.resolve(this.cwd, init.outDir) : this.cwd;
|
|
32
32
|
this.fileHeader = init.fileHeader || '';
|
|
33
33
|
this.writer = init.writer || new file_writer_js_1.FileWriter();
|
|
34
|
-
this.options = { importExt: !!init.importExt };
|
|
34
|
+
this.options = { importExt: !!init.importExt, referenceNamespaces: init.referenceNamespaces };
|
|
35
35
|
this._documentsMap = new Map();
|
|
36
36
|
this._filesMap = new WeakMap();
|
|
37
37
|
this.on('log', (message, ...args) => init.logger?.log?.(message, ...args));
|
|
@@ -46,10 +46,10 @@ class TsGenerator extends node_events_1.EventEmitter {
|
|
|
46
46
|
this.emit('start');
|
|
47
47
|
try {
|
|
48
48
|
this._started = true;
|
|
49
|
-
this.emit('log',
|
|
49
|
+
this.emit('log', ansi_colors_1.default.cyan('Removing old files..'));
|
|
50
50
|
this.cleanDirectory(this.outDir);
|
|
51
51
|
this._apiPath = '/api';
|
|
52
|
-
await this.
|
|
52
|
+
await this.generateDocument();
|
|
53
53
|
const { importExt } = this.options;
|
|
54
54
|
// Write files
|
|
55
55
|
for (const file of Object.values(this._files)) {
|
|
@@ -95,14 +95,14 @@ class TsGenerator extends node_events_1.EventEmitter {
|
|
|
95
95
|
exports.TsGenerator = TsGenerator;
|
|
96
96
|
(() => {
|
|
97
97
|
TsGenerator.prototype.cleanDirectory = clean_directory_js_1.cleanDirectory;
|
|
98
|
-
TsGenerator.prototype.
|
|
99
|
-
TsGenerator.prototype.
|
|
100
|
-
TsGenerator.prototype.
|
|
101
|
-
TsGenerator.prototype.
|
|
102
|
-
TsGenerator.prototype.
|
|
103
|
-
TsGenerator.prototype.
|
|
104
|
-
TsGenerator.prototype.
|
|
105
|
-
TsGenerator.prototype.
|
|
106
|
-
TsGenerator.prototype.
|
|
107
|
-
TsGenerator.prototype.
|
|
98
|
+
TsGenerator.prototype.generateDocument = generate_document_js_1.generateDocument;
|
|
99
|
+
TsGenerator.prototype.generateDataType = generate_data_type_js_1.generateDataType;
|
|
100
|
+
TsGenerator.prototype._generateTypeCode = generate_data_type_js_1._generateTypeCode;
|
|
101
|
+
TsGenerator.prototype._generateEnumTypeCode = generate_data_type_js_1._generateEnumTypeCode;
|
|
102
|
+
TsGenerator.prototype._generateComplexTypeCode = generate_data_type_js_1._generateComplexTypeCode;
|
|
103
|
+
TsGenerator.prototype._generateSimpleTypeCode = generate_data_type_js_1._generateSimpleTypeCode;
|
|
104
|
+
TsGenerator.prototype._generateMappedTypeCode = generate_data_type_js_1._generateMappedTypeCode;
|
|
105
|
+
TsGenerator.prototype._generateMixinTypeCode = generate_data_type_js_1._generateMixinTypeCode;
|
|
106
|
+
TsGenerator.prototype.generateHttpApi = generate_http_api_js_1.generateHttpApi;
|
|
107
|
+
TsGenerator.prototype.generateHttpController = generate_http_controller_js_1.generateHttpController;
|
|
108
108
|
})();
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.locateNamedType =
|
|
3
|
+
exports.locateNamedType = locateNamedType;
|
|
4
4
|
const common_1 = require("@opra/common");
|
|
5
5
|
function locateNamedType(type) {
|
|
6
6
|
if (!type)
|
|
@@ -14,4 +14,3 @@ function locateNamedType(type) {
|
|
|
14
14
|
return locateNamedType(type.base);
|
|
15
15
|
}
|
|
16
16
|
}
|
|
17
|
-
exports.locateNamedType = locateNamedType;
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.wrapJSDocString = wrapJSDocString;
|
|
4
|
+
exports.wrapQuotedString = wrapQuotedString;
|
|
5
|
+
exports.wrapStringArray = wrapStringArray;
|
|
6
|
+
exports.wrapTypeArray = wrapTypeArray;
|
|
4
7
|
const tslib_1 = require("tslib");
|
|
5
8
|
const js_string_escape_1 = tslib_1.__importDefault(require("js-string-escape"));
|
|
6
9
|
function wrapJSDocString(s, indent, currentColumn) {
|
|
@@ -14,7 +17,6 @@ function wrapJSDocString(s, indent, currentColumn) {
|
|
|
14
17
|
lineEnd: '',
|
|
15
18
|
});
|
|
16
19
|
}
|
|
17
|
-
exports.wrapJSDocString = wrapJSDocString;
|
|
18
20
|
function wrapQuotedString(s, indent, currentColumn) {
|
|
19
21
|
const arr = (0, js_string_escape_1.default)(s || '')
|
|
20
22
|
.split(' ')
|
|
@@ -28,17 +30,14 @@ function wrapQuotedString(s, indent, currentColumn) {
|
|
|
28
30
|
}) +
|
|
29
31
|
"'");
|
|
30
32
|
}
|
|
31
|
-
exports.wrapQuotedString = wrapQuotedString;
|
|
32
33
|
function wrapStringArray(arr, indent, currentColumn) {
|
|
33
34
|
const ar1 = arr.map((x, i, a) => "'" + x + "'" + (i < a.length - 1 ? ', ' : ''));
|
|
34
35
|
return '[' + _printLines(ar1, { indent, currentColumn }) + ']';
|
|
35
36
|
}
|
|
36
|
-
exports.wrapStringArray = wrapStringArray;
|
|
37
37
|
function wrapTypeArray(arr, indent, currentColumn) {
|
|
38
38
|
const ar1 = arr.map((x, i, a) => x + (i < a.length - 1 ? ' | ' : ''));
|
|
39
39
|
return _printLines(ar1, { indent, currentColumn });
|
|
40
40
|
}
|
|
41
|
-
exports.wrapTypeArray = wrapTypeArray;
|
|
42
41
|
function _printLines(arr, opts = {}) {
|
|
43
42
|
let s = '';
|
|
44
43
|
let line = '';
|
package/esm/file-writer.js
CHANGED
package/esm/oprimp-cli.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
+
import * as console from 'node:console';
|
|
2
|
+
import * as fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import * as process from 'node:process';
|
|
1
5
|
import { getStackFileName } from '@opra/common';
|
|
2
|
-
import
|
|
6
|
+
import colors from 'ansi-colors';
|
|
3
7
|
import { program } from 'commander';
|
|
4
|
-
import * as console from 'console';
|
|
5
|
-
import * as fs from 'fs';
|
|
6
|
-
import path from 'path';
|
|
7
|
-
import * as process from 'process';
|
|
8
8
|
import { TsGenerator } from './ts-generator/ts-generator.js';
|
|
9
9
|
const dirname = path.dirname(getStackFileName());
|
|
10
10
|
const pkgJson = JSON.parse(fs.readFileSync(path.resolve(dirname, '../package.json'), 'utf-8'));
|
|
@@ -13,20 +13,22 @@ program
|
|
|
13
13
|
.argument('<serviceUrl>', 'OPRA service url')
|
|
14
14
|
.argument('<outDir>', 'Output directory')
|
|
15
15
|
.option('--ext', 'Adds js extension to imports')
|
|
16
|
+
.option('--refns', 'Exports references with namespaces')
|
|
16
17
|
.option('--no-color', 'Disables colors in logs messages')
|
|
17
18
|
.action(async (serviceUrl, outDir, options) => {
|
|
18
19
|
if (!options.color)
|
|
19
|
-
|
|
20
|
+
colors.enabled = false;
|
|
20
21
|
const generator = new TsGenerator({
|
|
21
22
|
serviceUrl,
|
|
22
23
|
logger: console,
|
|
23
24
|
outDir,
|
|
24
25
|
importExt: options.ext,
|
|
26
|
+
referenceNamespaces: options.refns,
|
|
25
27
|
fileHeader: `/* Generated by OPRA Code Generator, Version ${pkgJson.version} */`,
|
|
26
28
|
});
|
|
27
29
|
await generator
|
|
28
30
|
.generate()
|
|
29
|
-
.then(() => console.log(
|
|
31
|
+
.then(() => console.log(colors.greenBright('Completed')))
|
|
30
32
|
.catch(e => console.error(e.message));
|
|
31
33
|
});
|
|
32
34
|
if (process.argv.length < 3)
|
package/esm/package.json
ADDED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
|
-
import
|
|
3
|
+
import colors from 'ansi-colors';
|
|
4
4
|
export function cleanDirectory(dirname) {
|
|
5
5
|
const rootDir = dirname;
|
|
6
6
|
const _cleanDirectory = (targetDir) => {
|
|
@@ -12,7 +12,7 @@ export function cleanDirectory(dirname) {
|
|
|
12
12
|
if (fs.statSync(absolutePath).isDirectory()) {
|
|
13
13
|
_cleanDirectory(absolutePath);
|
|
14
14
|
if (!fs.readdirSync(absolutePath).length) {
|
|
15
|
-
this.emit('verbose',
|
|
15
|
+
this.emit('verbose', colors.cyan(`Removing directory ${path.relative(absolutePath, rootDir)}`));
|
|
16
16
|
fs.rmdirSync(absolutePath);
|
|
17
17
|
}
|
|
18
18
|
continue;
|
|
@@ -20,7 +20,7 @@ export function cleanDirectory(dirname) {
|
|
|
20
20
|
if (path.extname(f) === '.ts') {
|
|
21
21
|
const contents = fs.readFileSync(absolutePath, 'utf-8');
|
|
22
22
|
if (contents.includes('#!oprimp_auto_generated!#')) {
|
|
23
|
-
this.emit('verbose',
|
|
23
|
+
this.emit('verbose', colors.cyan(`Removing file ${path.relative(absolutePath, rootDir)}`));
|
|
24
24
|
fs.unlinkSync(absolutePath);
|
|
25
25
|
}
|
|
26
26
|
}
|