@opra/cli 0.14.3 → 0.16.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.
Files changed (56) hide show
  1. package/bin/oprimp.mjs +1 -1
  2. package/cjs/api-exporter/api-exporter.js +107 -0
  3. package/cjs/{oprimp → api-exporter}/index.js +1 -1
  4. package/cjs/api-exporter/process-resources.js +50 -0
  5. package/cjs/api-exporter/process-types.js +215 -0
  6. package/cjs/api-exporter/ts-file.js +90 -0
  7. package/cjs/index.js +1 -1
  8. package/cjs/{oprimp.js → oprimp-cli.js} +8 -9
  9. package/esm/api-exporter/api-exporter.js +107 -0
  10. package/esm/api-exporter/file-writer.js +11 -0
  11. package/esm/api-exporter/index.js +4 -0
  12. package/esm/api-exporter/process-resources.js +50 -0
  13. package/esm/api-exporter/process-types.js +215 -0
  14. package/esm/api-exporter/ts-file.js +90 -0
  15. package/esm/index.js +4 -1
  16. package/esm/interfaces/file-writer.interface.js +2 -1
  17. package/esm/interfaces/logger.interface.js +2 -1
  18. package/esm/interfaces/service-generation-context.interface.js +2 -1
  19. package/esm/oprimp-cli.js +35 -0
  20. package/esm/utils/get-caller-file.util.js +5 -1
  21. package/esm/utils/string-utils.js +14 -6
  22. package/package.json +10 -10
  23. package/types/api-exporter/api-exporter.d.ts +46 -0
  24. package/types/api-exporter/index.d.ts +1 -0
  25. package/types/api-exporter/process-resources.d.ts +6 -0
  26. package/types/api-exporter/process-types.d.ts +54 -0
  27. package/types/api-exporter/ts-file.d.ts +18 -0
  28. package/types/index.d.ts +1 -0
  29. package/{esm → types}/interfaces/service-generation-context.interface.d.ts +2 -2
  30. package/cjs/oprimp/delete-files.js +0 -27
  31. package/cjs/oprimp/generate-service.js +0 -54
  32. package/cjs/oprimp/process-resoruces.js +0 -59
  33. package/cjs/oprimp/process-types.js +0 -130
  34. package/cjs/utils/ts-file.js +0 -55
  35. package/esm/index.d.ts +0 -1
  36. package/esm/oprimp/delete-files.d.ts +0 -1
  37. package/esm/oprimp/delete-files.js +0 -22
  38. package/esm/oprimp/file-writer.js +0 -6
  39. package/esm/oprimp/generate-service.d.ts +0 -13
  40. package/esm/oprimp/generate-service.js +0 -49
  41. package/esm/oprimp/index.d.ts +0 -1
  42. package/esm/oprimp/index.js +0 -1
  43. package/esm/oprimp/process-resoruces.d.ts +0 -2
  44. package/esm/oprimp/process-resoruces.js +0 -54
  45. package/esm/oprimp/process-types.d.ts +0 -2
  46. package/esm/oprimp/process-types.js +0 -125
  47. package/esm/oprimp.js +0 -33
  48. package/esm/utils/ts-file.d.ts +0 -11
  49. package/esm/utils/ts-file.js +0 -50
  50. /package/cjs/{oprimp → api-exporter}/file-writer.js +0 -0
  51. /package/{esm/oprimp → types/api-exporter}/file-writer.d.ts +0 -0
  52. /package/{esm → types}/interfaces/file-writer.interface.d.ts +0 -0
  53. /package/{esm → types}/interfaces/logger.interface.d.ts +0 -0
  54. /package/{esm/oprimp.d.ts → types/oprimp-cli.d.ts} +0 -0
  55. /package/{esm → types}/utils/get-caller-file.util.d.ts +0 -0
  56. /package/{esm → types}/utils/string-utils.d.ts +0 -0
package/bin/oprimp.mjs CHANGED
@@ -1,3 +1,3 @@
1
1
  #!/usr/bin/env node
2
- import '../esm/oprimp.js';
2
+ import '../esm/oprimp-cli.js';
3
3
 
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiExporter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
7
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
8
+ const node_process_1 = tslib_1.__importDefault(require("node:process"));
9
+ const node_client_1 = require("@opra/node-client");
10
+ const file_writer_js_1 = require("./file-writer.js");
11
+ const process_resources_js_1 = require("./process-resources.js");
12
+ const process_types_js_1 = require("./process-types.js");
13
+ const ts_file_js_1 = require("./ts-file.js");
14
+ class ApiExporter {
15
+ constructor(config) {
16
+ this.files = {};
17
+ this.client = new node_client_1.OpraHttpClient(config.serviceUrl);
18
+ this.cwd = config.cwd || node_process_1.default.cwd();
19
+ this.outDir = node_path_1.default.resolve(this.cwd, config.outDir);
20
+ this.logger = config.logger || {
21
+ log: () => void 0,
22
+ error: () => void 0,
23
+ debug: () => void 0,
24
+ warn: () => void 0,
25
+ verbose: () => void 0,
26
+ };
27
+ this.fileHeader = config.fileHeader || '';
28
+ this.importExt = config.importExt || '';
29
+ this.writer = config.writer || new file_writer_js_1.FileWriter();
30
+ // this.nsMap = nsMap || new ResponsiveMap(); // implement references later
31
+ }
32
+ async execute() {
33
+ this.logger.log(chalk_1.default.yellow('Fetching service metadata from'), chalk_1.default.whiteBright(this.client.serviceUrl));
34
+ this.document = await this.client.getMetadata();
35
+ this.logger.log(chalk_1.default.yellow('Retrieved service info:\n'), chalk_1.default.white('Title:'), chalk_1.default.magenta(this.document.info.title), '\n', chalk_1.default.white('Version:'), chalk_1.default.magenta(this.document.info.version), '\n', chalk_1.default.white('Resources:'), chalk_1.default.magenta(this.document.resources.size), 'resources found\n', chalk_1.default.white('Types:'), chalk_1.default.magenta(this.document.types.size), 'types found\n');
36
+ this.name = (this.name || this.document.info.title || 'Service1').replace(/[^\w_$]*/g, '');
37
+ this.name = this.name.charAt(0).toUpperCase() + this.name.substring(1);
38
+ this.fileHeader += `/*
39
+ * ${this.document.info.title}
40
+ * Version ${this.document.info.version}
41
+ * ${this.client.serviceUrl}
42
+ */`;
43
+ this.logger.log(chalk_1.default.yellow('Removing old files..'));
44
+ this.cleanDirectory(this.outDir);
45
+ this.logger.log(chalk_1.default.yellow(`Generating service interface ( ${chalk_1.default.whiteBright(this.name)} )`));
46
+ node_fs_1.default.mkdirSync(this.outDir, { recursive: true });
47
+ await this.processTypes();
48
+ await this.processResources();
49
+ // Write files
50
+ for (const file of Object.values(this.files)) {
51
+ const targetDir = node_path_1.default.dirname(file.filename);
52
+ node_fs_1.default.mkdirSync(targetDir, { recursive: true });
53
+ await this.writer.writeFile(file.filename, file.generate({ importExt: this.importExt }));
54
+ }
55
+ }
56
+ getFile(filePath) {
57
+ return this.files[node_path_1.default.resolve(node_path_1.default.join(this.outDir, filePath))];
58
+ }
59
+ addFile(filePath, returnExists) {
60
+ let file = this.getFile(filePath);
61
+ if (file) {
62
+ if (returnExists)
63
+ return file;
64
+ throw new Error(`File "${filePath}" already exists`);
65
+ }
66
+ file = new ts_file_js_1.TsFile(node_path_1.default.resolve(node_path_1.default.join(this.outDir, filePath)));
67
+ file.header = this.fileHeader;
68
+ this.files[file.filename] = file;
69
+ return file;
70
+ }
71
+ cleanDirectory(dirname) {
72
+ if (!node_fs_1.default.existsSync(dirname))
73
+ return;
74
+ const files = node_fs_1.default.readdirSync(dirname);
75
+ for (const f of files) {
76
+ const absolutePath = node_path_1.default.join(dirname, f);
77
+ if (node_fs_1.default.statSync(absolutePath).isDirectory()) {
78
+ this.cleanDirectory(absolutePath);
79
+ if (!node_fs_1.default.readdirSync(absolutePath).length)
80
+ node_fs_1.default.rmdirSync(absolutePath);
81
+ continue;
82
+ }
83
+ if (node_path_1.default.extname(f) === '.ts') {
84
+ const contents = node_fs_1.default.readFileSync(absolutePath, 'utf-8');
85
+ if (contents.includes('#!oprimp_auto_generated!#')) {
86
+ node_fs_1.default.unlinkSync(absolutePath);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ static async execute(config) {
92
+ const exporter = new ApiExporter(config);
93
+ await exporter.execute();
94
+ }
95
+ }
96
+ exports.ApiExporter = ApiExporter;
97
+ (() => {
98
+ ApiExporter.prototype.processResources = process_resources_js_1.processResources;
99
+ ApiExporter.prototype.processTypes = process_types_js_1.processTypes;
100
+ ApiExporter.prototype.generateTypeFile = process_types_js_1.generateTypeFile;
101
+ ApiExporter.prototype.generateComplexTypeDefinition = process_types_js_1.generateComplexTypeDefinition;
102
+ ApiExporter.prototype.generateSimpleTypeDefinition = process_types_js_1.generateSimpleTypeDefinition;
103
+ ApiExporter.prototype.resolveTypeNameOrDef = process_types_js_1.resolveTypeNameOrDef;
104
+ ApiExporter.prototype.generateEnumTypeDefinition = process_types_js_1.generateEnumTypeDefinition;
105
+ ApiExporter.prototype.generateUnionTypeDefinition = process_types_js_1.generateUnionTypeDefinition;
106
+ ApiExporter.prototype.generateMappedTypeDefinition = process_types_js_1.generateMappedTypeDefinition;
107
+ })();
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./generate-service.js"), exports);
4
+ tslib_1.__exportStar(require("./api-exporter.js"), exports);
@@ -0,0 +1,50 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processResources = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
7
+ const common_1 = require("@opra/common");
8
+ const string_utils_js_1 = require("../utils/string-utils.js");
9
+ /**
10
+ *
11
+ * @param targetDir
12
+ */
13
+ async function processResources(targetDir = '') {
14
+ this.logger.log(chalk_1.default.yellow('Processing resources'));
15
+ const { document } = this;
16
+ const serviceTs = this.addFile(node_path_1.default.join(targetDir, this.name + '.ts'));
17
+ serviceTs.addImportPackage('@opra/client', ['HttpServiceBase']);
18
+ const indexTs = this.addFile('/index.ts', true);
19
+ indexTs.addExportFile(serviceTs.filename);
20
+ serviceTs.content = `\nexport class ${this.name} extends HttpServiceBase {\n`;
21
+ for (const resource of document.resources.values()) {
22
+ serviceTs.content += `\n/**\n * ${(0, string_utils_js_1.wrapJSDocString)(resource.description || resource.name)}
23
+ * @url ${(0, common_1.joinPath)(this.client.serviceUrl, '$metadata#resources/' + resource.name)}
24
+ */`;
25
+ if (resource instanceof common_1.Collection) {
26
+ const typeName = resource.type.name || '';
27
+ serviceTs.addImportPackage('@opra/client', ['HttpCollectionNode']);
28
+ serviceTs.addImportFile('types/' + typeName, [typeName]);
29
+ const operations = Object.keys(resource.operations)
30
+ .map(x => `'${x}'`).join(' | ');
31
+ serviceTs.content += `
32
+ get ${resource.name}(): Pick<HttpCollectionNode<${typeName}>, ${operations}> {
33
+ return this.$client.collection('${resource.name}');
34
+ }\n`;
35
+ }
36
+ else if (resource instanceof common_1.Singleton) {
37
+ const typeName = resource.type.name || '';
38
+ serviceTs.addImportPackage('@opra/client', ['HttpSingletonNode']);
39
+ serviceTs.addImportFile('types/' + typeName, [typeName]);
40
+ const operations = Object.keys(resource.operations)
41
+ .map(x => `'${x}'`).join(' | ');
42
+ serviceTs.content += `
43
+ get ${resource.name}(): Pick<HttpSingletonNode<${typeName}>, ${operations}> {
44
+ return this.$client.singleton('${resource.name}');
45
+ }\n`;
46
+ }
47
+ }
48
+ serviceTs.content += '}';
49
+ }
50
+ exports.processResources = processResources;
@@ -0,0 +1,215 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateMappedTypeDefinition = exports.generateUnionTypeDefinition = exports.generateEnumTypeDefinition = exports.generateSimpleTypeDefinition = exports.generateComplexTypeDefinition = exports.resolveTypeNameOrDef = exports.generateTypeFile = exports.processTypes = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
7
+ const common_1 = require("@opra/common");
8
+ const string_utils_js_1 = require("../utils/string-utils.js");
9
+ const internalTypeNames = ['boolean', 'bigint', 'number', 'null', 'string'];
10
+ /**
11
+ *
12
+ * @param targetDir
13
+ */
14
+ async function processTypes(targetDir = '') {
15
+ this.logger.log(chalk_1.default.yellow('Processing types'));
16
+ const { document } = this;
17
+ const typesTs = this.addFile(node_path_1.default.join(targetDir, 'types.ts'));
18
+ for (const dataType of document.types.values()) {
19
+ const expFile = await this.generateTypeFile(dataType, targetDir);
20
+ typesTs.addExportFile(expFile.filename);
21
+ }
22
+ }
23
+ exports.processTypes = processTypes;
24
+ /**
25
+ *
26
+ * @param dataType
27
+ * @param targetDir
28
+ */
29
+ async function generateTypeFile(dataType, targetDir = '') {
30
+ const typeName = dataType.name;
31
+ if (!typeName)
32
+ throw new TypeError(`DataType has no name`);
33
+ let filePath;
34
+ if (dataType instanceof common_1.SimpleType)
35
+ filePath = '/simple-types.ts';
36
+ else if (dataType instanceof common_1.ComplexType)
37
+ filePath = `/types/${typeName}.ts`;
38
+ else if (dataType instanceof common_1.EnumType) {
39
+ filePath = `/enums/${typeName}.ts`;
40
+ }
41
+ else
42
+ throw new TypeError(`Unimplemented DataType (${dataType.kind})`);
43
+ const file = this.addFile(node_path_1.default.join(targetDir, filePath), true);
44
+ if (file.exportTypes.includes(typeName))
45
+ return file;
46
+ file.exportTypes.push(typeName);
47
+ const indexTs = this.addFile('/index.ts', true);
48
+ indexTs.addExportFile(file.filename);
49
+ file.content += `\n/**\n * ${(0, string_utils_js_1.wrapJSDocString)(dataType.description || typeName)}
50
+ * @type ${typeName}
51
+ * @kind ${dataType.kind}
52
+ * @url ${(0, common_1.joinPath)(this.client.serviceUrl, '$metadata#types/' + typeName)}
53
+ */\n`;
54
+ if (dataType instanceof common_1.SimpleType) {
55
+ file.content += `export type ${typeName} = ` + await this.generateSimpleTypeDefinition(file, dataType);
56
+ }
57
+ else if (dataType instanceof common_1.EnumType) {
58
+ file.content += `export enum ${typeName} ` + await this.generateEnumTypeDefinition(file, dataType);
59
+ }
60
+ else if (dataType instanceof common_1.ComplexType) {
61
+ file.content += `export class ${typeName} {
62
+ constructor(init?: Partial<I${typeName}>) {
63
+ if (init)
64
+ Object.assign(this, init);
65
+ }
66
+ }
67
+
68
+ export interface ${typeName} extends I${typeName} {
69
+ }
70
+
71
+ interface I${typeName} ${await this.generateComplexTypeDefinition(file, dataType, true)}
72
+ `;
73
+ }
74
+ return file;
75
+ }
76
+ exports.generateTypeFile = generateTypeFile;
77
+ /**
78
+ *
79
+ * @param file
80
+ * @param dataType
81
+ * @param forInterface
82
+ */
83
+ async function resolveTypeNameOrDef(file, dataType, forInterface) {
84
+ if (dataType.name) {
85
+ if (internalTypeNames.includes(dataType.name))
86
+ return dataType.name;
87
+ const f = await this.generateTypeFile(dataType);
88
+ file.addImportFile(f.filename, [dataType.name]);
89
+ return dataType.name;
90
+ }
91
+ if (dataType instanceof common_1.ComplexType)
92
+ return this.generateComplexTypeDefinition(file, dataType, forInterface);
93
+ if (dataType instanceof common_1.SimpleType)
94
+ return this.generateSimpleTypeDefinition(file, dataType);
95
+ if (dataType instanceof common_1.EnumType)
96
+ return this.generateEnumTypeDefinition(file, dataType);
97
+ if (dataType instanceof common_1.UnionType)
98
+ return this.generateUnionTypeDefinition(file, dataType, forInterface);
99
+ if (dataType instanceof common_1.MappedType)
100
+ return this.generateMappedTypeDefinition(file, dataType, forInterface);
101
+ return 'xxx';
102
+ }
103
+ exports.resolveTypeNameOrDef = resolveTypeNameOrDef;
104
+ /**
105
+ *
106
+ * @param file
107
+ * @param dataType
108
+ * @param forInterface
109
+ */
110
+ async function generateComplexTypeDefinition(file, dataType, forInterface) {
111
+ let out = '';
112
+ if (dataType.base) {
113
+ const base = await this.resolveTypeNameOrDef(file, dataType.base, forInterface);
114
+ out += forInterface ? `extends ${base} ` : `${base} & `;
115
+ }
116
+ out += '{\n\n\t';
117
+ for (const field of dataType.own.fields.values()) {
118
+ // Print JSDoc
119
+ let jsDoc = '';
120
+ if (field.description)
121
+ jsDoc += ` * ${field.description}\n`;
122
+ if (field.default)
123
+ jsDoc += ` * @default ` + field.default + '\n';
124
+ if (field.format)
125
+ jsDoc += ` * @format ` + field.format + '\n';
126
+ if (field.exclusive)
127
+ jsDoc += ` * @exclusive\n`;
128
+ if (field.deprecated)
129
+ jsDoc += ` * @deprecated ` + (typeof field.deprecated === 'string' ? field.deprecated : '') + '\n';
130
+ if (jsDoc)
131
+ out += `/**\n${jsDoc}*/\n`;
132
+ // Print field name
133
+ out += `${field.name}${field.required ? '' : '?'}: `;
134
+ if (field.fixed)
135
+ out += `${field.fixed}`;
136
+ else {
137
+ out += await this.resolveTypeNameOrDef(file, field.type) +
138
+ `${field.isArray ? '[]' : ''};\n\n`;
139
+ }
140
+ }
141
+ if (dataType.additionalFields)
142
+ out += '[key: string]: any;\n';
143
+ return out + '\b}';
144
+ }
145
+ exports.generateComplexTypeDefinition = generateComplexTypeDefinition;
146
+ /**
147
+ *
148
+ * @param file
149
+ * @param dataType
150
+ */
151
+ async function generateSimpleTypeDefinition(file, dataType) {
152
+ if (dataType.ctor === Boolean)
153
+ return 'boolean';
154
+ if (dataType.ctor === String)
155
+ return 'string';
156
+ if (dataType.ctor === Number)
157
+ return 'number';
158
+ if (dataType.ctor === Date)
159
+ return 'Date';
160
+ if (dataType.extendsFrom('bigint'))
161
+ return 'Date';
162
+ if (dataType.extendsFrom('object'))
163
+ return 'object';
164
+ return 'any';
165
+ }
166
+ exports.generateSimpleTypeDefinition = generateSimpleTypeDefinition;
167
+ /**
168
+ *
169
+ * @param file
170
+ * @param dataType
171
+ */
172
+ async function generateEnumTypeDefinition(file, dataType) {
173
+ let out = '{\n\t';
174
+ for (const [k, v] of Object.entries(dataType.values)) {
175
+ // Print JSDoc
176
+ let jsDoc = '';
177
+ if (dataType.meanings[k])
178
+ jsDoc += ` * ${dataType.meanings[k]}\n`;
179
+ if (jsDoc)
180
+ out += `/**\n${jsDoc}*/\n`;
181
+ out += `${k}`;
182
+ if (v)
183
+ out += ' = ' + (typeof v === 'number' ? v : ('"' + ('' + v).replace('"', '\\"')) + '"');
184
+ out += ',\n\n';
185
+ }
186
+ return out + '\b}';
187
+ }
188
+ exports.generateEnumTypeDefinition = generateEnumTypeDefinition;
189
+ /**
190
+ *
191
+ * @param file
192
+ * @param dataType
193
+ * @param forInterface
194
+ */
195
+ async function generateUnionTypeDefinition(file, dataType, forInterface) {
196
+ // let out = '';
197
+ return (await Promise.all(dataType.types
198
+ .map(t => this.resolveTypeNameOrDef(file, t, forInterface)))).join(forInterface ? ', ' : ' & ');
199
+ }
200
+ exports.generateUnionTypeDefinition = generateUnionTypeDefinition;
201
+ /**
202
+ *
203
+ * @param file
204
+ * @param dataType
205
+ * @param forInterface
206
+ */
207
+ async function generateMappedTypeDefinition(file, dataType, forInterface) {
208
+ return (dataType.pick ? 'Pick<' : 'Omit<') +
209
+ (await this.resolveTypeNameOrDef(file, dataType.type, forInterface)) +
210
+ ', ' +
211
+ (dataType.pick || dataType.omit || [])
212
+ .map(x => `'${x}'`).join(' | ') +
213
+ '>';
214
+ }
215
+ exports.generateMappedTypeDefinition = generateMappedTypeDefinition;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.setExt = exports.relativePath = exports.TsFile = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const path_1 = tslib_1.__importDefault(require("path"));
6
+ const putil_flattentext_1 = tslib_1.__importDefault(require("putil-flattentext"));
7
+ class TsFile {
8
+ constructor(filename) {
9
+ this.filename = filename;
10
+ this.importFiles = {};
11
+ this.exportFiles = {};
12
+ this.exportTypes = [];
13
+ this.header = '';
14
+ this.content = '';
15
+ this.addImportPackage = (name, types) => {
16
+ this.importFiles[name] = this.importFiles[name] || [];
17
+ types?.forEach(x => {
18
+ if (!this.importFiles[name].includes(x))
19
+ this.importFiles[name].push(x);
20
+ });
21
+ };
22
+ this.addImportFile = (filename, types) => {
23
+ filename = path_1.default.resolve(this.dirname, filename);
24
+ this.importFiles[filename] = this.importFiles[filename] || [];
25
+ types?.forEach(x => {
26
+ if (!this.importFiles[filename].includes(x))
27
+ this.importFiles[filename].push(x);
28
+ });
29
+ };
30
+ this.addExportFile = (filename, types) => {
31
+ filename = path_1.default.resolve(this.dirname, filename);
32
+ if (filename.endsWith('.ts') || filename.endsWith('.js'))
33
+ filename = setExt(filename, '');
34
+ this.exportFiles[filename] = this.exportFiles[filename] || [];
35
+ types?.forEach(x => {
36
+ if (!this.exportFiles[filename].includes(x))
37
+ this.exportFiles[filename].push(x);
38
+ });
39
+ };
40
+ this.dirname = path_1.default.dirname(filename);
41
+ }
42
+ generate(options) {
43
+ const dirname = path_1.default.dirname(this.filename);
44
+ let output = '/* #!oprimp_auto_generated!# !! Do NOT remove this line */\n' +
45
+ (this.header ? (0, putil_flattentext_1.default)(this.header) + '\n\n' : '\n');
46
+ const importStr = Object.keys(this.importFiles)
47
+ .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
48
+ .map(filename => {
49
+ const types = this.importFiles[filename];
50
+ let relFile = filename;
51
+ if (path_1.default.isAbsolute(filename)) {
52
+ relFile = relativePath(dirname, filename);
53
+ if (options?.importExt)
54
+ relFile = setExt(relFile, options.importExt);
55
+ }
56
+ return `import ${types.length ? '{' + types.join(', ') + '} from ' : ''}'${relFile}';`;
57
+ })
58
+ .join('\n');
59
+ if (importStr)
60
+ output += (0, putil_flattentext_1.default)(importStr) + '\n';
61
+ output += (0, putil_flattentext_1.default)(this.content);
62
+ const exportStr = Object.keys(this.exportFiles)
63
+ .sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
64
+ .map(filename => {
65
+ const types = this.exportFiles[filename];
66
+ let relFile = filename;
67
+ if (path_1.default.isAbsolute(filename)) {
68
+ relFile = relativePath(dirname, filename);
69
+ if (options?.importExt)
70
+ relFile = setExt(relFile, options.importExt);
71
+ }
72
+ return `export ${types.length ? '{' + types.join(', ') + '}' : '*'} from '${relFile}';`;
73
+ })
74
+ .join('\n');
75
+ if (exportStr)
76
+ output += (0, putil_flattentext_1.default)(exportStr) + '\n';
77
+ return output;
78
+ }
79
+ }
80
+ exports.TsFile = TsFile;
81
+ function relativePath(from, to) {
82
+ const s = path_1.default.relative(from, to);
83
+ return s.startsWith('.') ? s : ('./' + s);
84
+ }
85
+ exports.relativePath = relativePath;
86
+ function setExt(filename, ext) {
87
+ const e = path_1.default.extname(filename);
88
+ return filename.substring(0, filename.length - e.length) + (ext ? '.' + ext : '');
89
+ }
90
+ exports.setExt = setExt;
package/cjs/index.js CHANGED
@@ -1,4 +1,4 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./oprimp/index.js"), exports);
4
+ tslib_1.__exportStar(require("./api-exporter/index.js"), exports);
@@ -7,9 +7,10 @@ const console = tslib_1.__importStar(require("console"));
7
7
  const fs = tslib_1.__importStar(require("fs"));
8
8
  const path_1 = tslib_1.__importDefault(require("path"));
9
9
  const process = tslib_1.__importStar(require("process"));
10
- const generate_service_js_1 = require("./oprimp/generate-service.js");
10
+ const api_exporter_js_1 = require("./api-exporter/api-exporter.js");
11
11
  const get_caller_file_util_js_1 = require("./utils/get-caller-file.util.js");
12
- const pkgJson = JSON.parse(fs.readFileSync(path_1.default.resolve(path_1.default.dirname((0, get_caller_file_util_js_1.getCallerFile)()), '../package.json'), 'utf-8'));
12
+ const dirname = path_1.default.dirname((0, get_caller_file_util_js_1.getCallerFile)());
13
+ const pkgJson = JSON.parse(fs.readFileSync(path_1.default.resolve(dirname, '../package.json'), 'utf-8'));
13
14
  commander_1.program
14
15
  .version(pkgJson.version)
15
16
  .argument('<serviceUrl>', 'OPRA service url')
@@ -20,16 +21,14 @@ commander_1.program
20
21
  .action(async (serviceUrl, outDir, options) => {
21
22
  if (!options.color)
22
23
  chalk_1.default.level = 0;
23
- await (0, generate_service_js_1.generateService)({
24
+ await api_exporter_js_1.ApiExporter.execute({
24
25
  serviceUrl,
26
+ logger: console,
25
27
  outDir,
26
28
  name: options.name,
27
- extension: (options.ext ? '.js' : ''),
28
- fileHeader: '/*\n' +
29
- ' * Generated by OPRA Service Generator \n' +
30
- ' * Version: ' + pkgJson.version + '\n' +
31
- ' * ' + new Date() + '\n' +
32
- ' */'
29
+ importExt: (options.ext ? 'js' : ''),
30
+ fileHeader: '/* Generated by OPRA Service Generator, Version ' + pkgJson.version + '*/\n' +
31
+ '/* eslint-disable import/extensions,simple-import-sort/imports */\n'
33
32
  });
34
33
  console.log(chalk_1.default.greenBright('Completed'));
35
34
  });
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ApiExporter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const chalk_1 = tslib_1.__importDefault(require("chalk"));
6
+ const node_fs_1 = tslib_1.__importDefault(require("node:fs"));
7
+ const node_path_1 = tslib_1.__importDefault(require("node:path"));
8
+ const node_process_1 = tslib_1.__importDefault(require("node:process"));
9
+ const node_client_1 = require("@opra/node-client");
10
+ const file_writer_js_1 = require("./file-writer.js");
11
+ const process_resources_js_1 = require("./process-resources.js");
12
+ const process_types_js_1 = require("./process-types.js");
13
+ const ts_file_js_1 = require("./ts-file.js");
14
+ class ApiExporter {
15
+ constructor(config) {
16
+ this.files = {};
17
+ this.client = new node_client_1.OpraHttpClient(config.serviceUrl);
18
+ this.cwd = config.cwd || node_process_1.default.cwd();
19
+ this.outDir = node_path_1.default.resolve(this.cwd, config.outDir);
20
+ this.logger = config.logger || {
21
+ log: () => void 0,
22
+ error: () => void 0,
23
+ debug: () => void 0,
24
+ warn: () => void 0,
25
+ verbose: () => void 0,
26
+ };
27
+ this.fileHeader = config.fileHeader || '';
28
+ this.importExt = config.importExt || '';
29
+ this.writer = config.writer || new file_writer_js_1.FileWriter();
30
+ // this.nsMap = nsMap || new ResponsiveMap(); // implement references later
31
+ }
32
+ async execute() {
33
+ this.logger.log(chalk_1.default.yellow('Fetching service metadata from'), chalk_1.default.whiteBright(this.client.serviceUrl));
34
+ this.document = await this.client.getMetadata();
35
+ this.logger.log(chalk_1.default.yellow('Retrieved service info:\n'), chalk_1.default.white('Title:'), chalk_1.default.magenta(this.document.info.title), '\n', chalk_1.default.white('Version:'), chalk_1.default.magenta(this.document.info.version), '\n', chalk_1.default.white('Resources:'), chalk_1.default.magenta(this.document.resources.size), 'resources found\n', chalk_1.default.white('Types:'), chalk_1.default.magenta(this.document.types.size), 'types found\n');
36
+ this.name = (this.name || this.document.info.title || 'Service1').replace(/[^\w_$]*/g, '');
37
+ this.name = this.name.charAt(0).toUpperCase() + this.name.substring(1);
38
+ this.fileHeader += `/*
39
+ * ${this.document.info.title}
40
+ * Version ${this.document.info.version}
41
+ * ${this.client.serviceUrl}
42
+ */`;
43
+ this.logger.log(chalk_1.default.yellow('Removing old files..'));
44
+ this.cleanDirectory(this.outDir);
45
+ this.logger.log(chalk_1.default.yellow(`Generating service interface ( ${chalk_1.default.whiteBright(this.name)} )`));
46
+ node_fs_1.default.mkdirSync(this.outDir, { recursive: true });
47
+ await this.processTypes();
48
+ await this.processResources();
49
+ // Write files
50
+ for (const file of Object.values(this.files)) {
51
+ const targetDir = node_path_1.default.dirname(file.filename);
52
+ node_fs_1.default.mkdirSync(targetDir, { recursive: true });
53
+ await this.writer.writeFile(file.filename, file.generate({ importExt: this.importExt }));
54
+ }
55
+ }
56
+ getFile(filePath) {
57
+ return this.files[node_path_1.default.resolve(node_path_1.default.join(this.outDir, filePath))];
58
+ }
59
+ addFile(filePath, returnExists) {
60
+ let file = this.getFile(filePath);
61
+ if (file) {
62
+ if (returnExists)
63
+ return file;
64
+ throw new Error(`File "${filePath}" already exists`);
65
+ }
66
+ file = new ts_file_js_1.TsFile(node_path_1.default.resolve(node_path_1.default.join(this.outDir, filePath)));
67
+ file.header = this.fileHeader;
68
+ this.files[file.filename] = file;
69
+ return file;
70
+ }
71
+ cleanDirectory(dirname) {
72
+ if (!node_fs_1.default.existsSync(dirname))
73
+ return;
74
+ const files = node_fs_1.default.readdirSync(dirname);
75
+ for (const f of files) {
76
+ const absolutePath = node_path_1.default.join(dirname, f);
77
+ if (node_fs_1.default.statSync(absolutePath).isDirectory()) {
78
+ this.cleanDirectory(absolutePath);
79
+ if (!node_fs_1.default.readdirSync(absolutePath).length)
80
+ node_fs_1.default.rmdirSync(absolutePath);
81
+ continue;
82
+ }
83
+ if (node_path_1.default.extname(f) === '.ts') {
84
+ const contents = node_fs_1.default.readFileSync(absolutePath, 'utf-8');
85
+ if (contents.includes('#!oprimp_auto_generated!#')) {
86
+ node_fs_1.default.unlinkSync(absolutePath);
87
+ }
88
+ }
89
+ }
90
+ }
91
+ static async execute(config) {
92
+ const exporter = new ApiExporter(config);
93
+ await exporter.execute();
94
+ }
95
+ }
96
+ exports.ApiExporter = ApiExporter;
97
+ (() => {
98
+ ApiExporter.prototype.processResources = process_resources_js_1.processResources;
99
+ ApiExporter.prototype.processTypes = process_types_js_1.processTypes;
100
+ ApiExporter.prototype.generateTypeFile = process_types_js_1.generateTypeFile;
101
+ ApiExporter.prototype.generateComplexTypeDefinition = process_types_js_1.generateComplexTypeDefinition;
102
+ ApiExporter.prototype.generateSimpleTypeDefinition = process_types_js_1.generateSimpleTypeDefinition;
103
+ ApiExporter.prototype.resolveTypeNameOrDef = process_types_js_1.resolveTypeNameOrDef;
104
+ ApiExporter.prototype.generateEnumTypeDefinition = process_types_js_1.generateEnumTypeDefinition;
105
+ ApiExporter.prototype.generateUnionTypeDefinition = process_types_js_1.generateUnionTypeDefinition;
106
+ ApiExporter.prototype.generateMappedTypeDefinition = process_types_js_1.generateMappedTypeDefinition;
107
+ })();
@@ -0,0 +1,11 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.FileWriter = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const fs_1 = tslib_1.__importDefault(require("fs"));
6
+ class FileWriter {
7
+ writeFile(filename, contents) {
8
+ fs_1.default.writeFileSync(filename, contents, 'utf-8');
9
+ }
10
+ }
11
+ exports.FileWriter = FileWriter;
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ tslib_1.__exportStar(require("./api-exporter.js"), exports);