@opra/cli 1.0.0-alpha.9 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import path from 'path';
|
|
1
|
+
import path from 'node:path';
|
|
2
2
|
import flattenText from 'putil-flattentext';
|
|
3
3
|
import { CodeBlock } from '../code-block.js';
|
|
4
4
|
export class TsFile {
|
|
@@ -31,7 +31,7 @@ export class TsFile {
|
|
|
31
31
|
imp.items.push(x);
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
|
-
addExport(filename, types) {
|
|
34
|
+
addExport(filename, types, namespace) {
|
|
35
35
|
if (isLocalFile(filename)) {
|
|
36
36
|
filename = path.relative(this.dirname, path.resolve(this.dirname, filename));
|
|
37
37
|
if (!filename.startsWith('.'))
|
|
@@ -41,10 +41,11 @@ export class TsFile {
|
|
|
41
41
|
filename = filename.substring(0, filename.length - 5);
|
|
42
42
|
if (filename.endsWith('.ts') || filename.endsWith('.js'))
|
|
43
43
|
filename = filename.substring(0, filename.length - 3);
|
|
44
|
-
|
|
44
|
+
const key = (namespace ? namespace + ':' : '') + filename;
|
|
45
|
+
this.exportFiles[key] = this.exportFiles[key] || { filename, items: [], namespace };
|
|
45
46
|
types?.forEach(x => {
|
|
46
|
-
if (!this.exportFiles[filename].includes(x))
|
|
47
|
-
this.exportFiles[filename].push(x);
|
|
47
|
+
if (!this.exportFiles[filename].items.includes(x))
|
|
48
|
+
this.exportFiles[filename].items.push(x);
|
|
48
49
|
});
|
|
49
50
|
}
|
|
50
51
|
generate(options) {
|
|
@@ -72,18 +73,23 @@ export class TsFile {
|
|
|
72
73
|
.join('\n');
|
|
73
74
|
this.code.exports = Object.keys(this.exportFiles)
|
|
74
75
|
.sort((a, b) => a.toLowerCase().localeCompare(b.toLowerCase()))
|
|
75
|
-
.map(
|
|
76
|
-
const
|
|
76
|
+
.map(key => {
|
|
77
|
+
const exportFile = this.exportFiles[key];
|
|
78
|
+
const types = exportFile.items;
|
|
79
|
+
let filename = exportFile.filename;
|
|
77
80
|
if (!isPackageName(filename)) {
|
|
78
81
|
if (options?.importExt)
|
|
79
82
|
filename += '.js';
|
|
80
83
|
}
|
|
81
|
-
|
|
84
|
+
let out = `export ${types.length ? '{ ' + types.join(', ') + ' }' : '*'}`;
|
|
85
|
+
if (exportFile.namespace)
|
|
86
|
+
out += ` as ${exportFile.namespace}`;
|
|
87
|
+
return out + ` from '${filename}';`;
|
|
82
88
|
})
|
|
83
89
|
.join('\n');
|
|
84
90
|
if (this.code.imports || this.code.exports)
|
|
85
91
|
this.code.exports += '\n\n';
|
|
86
|
-
return ('/* #!oprimp_auto_generated!# !! Do NOT remove this line */\n/* eslint-disable */\n' +
|
|
92
|
+
return ('/* #!oprimp_auto_generated!# !! Do NOT remove this line */\n/* eslint-disable */\n// noinspection SpellCheckingInspection\n\n' +
|
|
87
93
|
flattenText(String(this.code)));
|
|
88
94
|
}
|
|
89
95
|
}
|
|
@@ -2,13 +2,13 @@ import { EventEmitter } from 'node:events';
|
|
|
2
2
|
import fs from 'node:fs';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
import process from 'node:process';
|
|
5
|
-
import
|
|
5
|
+
import colors from 'ansi-colors';
|
|
6
6
|
import { FileWriter } from '../file-writer.js';
|
|
7
|
-
import { cleanDirectory } from './
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
7
|
+
import { cleanDirectory } from './generators/clean-directory.js';
|
|
8
|
+
import { _generateComplexTypeCode, _generateEnumTypeCode, _generateMappedTypeCode, _generateMixinTypeCode, _generateSimpleTypeCode, _generateTypeCode, generateDataType, } from './generators/generate-data-type.js';
|
|
9
|
+
import { generateDocument } from './generators/generate-document.js';
|
|
10
|
+
import { generateHttpApi } from './generators/generate-http-api.js';
|
|
11
|
+
import { generateHttpController } from './generators/generate-http-controller.js';
|
|
12
12
|
import { TsFile } from './ts-file.js';
|
|
13
13
|
/**
|
|
14
14
|
* @class TsGenerator
|
|
@@ -20,14 +20,14 @@ export class TsGenerator extends EventEmitter {
|
|
|
20
20
|
*/
|
|
21
21
|
constructor(init) {
|
|
22
22
|
super();
|
|
23
|
-
this._started = false;
|
|
24
23
|
this._files = {};
|
|
24
|
+
this._started = false;
|
|
25
25
|
this.serviceUrl = init.serviceUrl;
|
|
26
26
|
this.cwd = init.cwd || process.cwd();
|
|
27
27
|
this.outDir = init.outDir ? path.resolve(this.cwd, init.outDir) : this.cwd;
|
|
28
28
|
this.fileHeader = init.fileHeader || '';
|
|
29
29
|
this.writer = init.writer || new FileWriter();
|
|
30
|
-
this.options = { importExt: !!init.importExt };
|
|
30
|
+
this.options = { importExt: !!init.importExt, referenceNamespaces: init.referenceNamespaces };
|
|
31
31
|
this._documentsMap = new Map();
|
|
32
32
|
this._filesMap = new WeakMap();
|
|
33
33
|
this.on('log', (message, ...args) => init.logger?.log?.(message, ...args));
|
|
@@ -42,10 +42,10 @@ export class TsGenerator extends EventEmitter {
|
|
|
42
42
|
this.emit('start');
|
|
43
43
|
try {
|
|
44
44
|
this._started = true;
|
|
45
|
-
this.emit('log',
|
|
45
|
+
this.emit('log', colors.cyan('Removing old files..'));
|
|
46
46
|
this.cleanDirectory(this.outDir);
|
|
47
47
|
this._apiPath = '/api';
|
|
48
|
-
await this.
|
|
48
|
+
await this.generateDocument();
|
|
49
49
|
const { importExt } = this.options;
|
|
50
50
|
// Write files
|
|
51
51
|
for (const file of Object.values(this._files)) {
|
|
@@ -90,14 +90,14 @@ export class TsGenerator extends EventEmitter {
|
|
|
90
90
|
}
|
|
91
91
|
(() => {
|
|
92
92
|
TsGenerator.prototype.cleanDirectory = cleanDirectory;
|
|
93
|
-
TsGenerator.prototype.
|
|
94
|
-
TsGenerator.prototype.
|
|
95
|
-
TsGenerator.prototype.
|
|
96
|
-
TsGenerator.prototype.
|
|
97
|
-
TsGenerator.prototype.
|
|
98
|
-
TsGenerator.prototype.
|
|
99
|
-
TsGenerator.prototype.
|
|
100
|
-
TsGenerator.prototype.
|
|
101
|
-
TsGenerator.prototype.
|
|
102
|
-
TsGenerator.prototype.
|
|
93
|
+
TsGenerator.prototype.generateDocument = generateDocument;
|
|
94
|
+
TsGenerator.prototype.generateDataType = generateDataType;
|
|
95
|
+
TsGenerator.prototype._generateTypeCode = _generateTypeCode;
|
|
96
|
+
TsGenerator.prototype._generateEnumTypeCode = _generateEnumTypeCode;
|
|
97
|
+
TsGenerator.prototype._generateComplexTypeCode = _generateComplexTypeCode;
|
|
98
|
+
TsGenerator.prototype._generateSimpleTypeCode = _generateSimpleTypeCode;
|
|
99
|
+
TsGenerator.prototype._generateMappedTypeCode = _generateMappedTypeCode;
|
|
100
|
+
TsGenerator.prototype._generateMixinTypeCode = _generateMixinTypeCode;
|
|
101
|
+
TsGenerator.prototype.generateHttpApi = generateHttpApi;
|
|
102
|
+
TsGenerator.prototype.generateHttpController = generateHttpController;
|
|
103
103
|
})();
|
package/package.json
CHANGED
|
@@ -1,51 +1,46 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/cli",
|
|
3
|
-
"version": "1.0.0-
|
|
3
|
+
"version": "1.0.0-beta.2",
|
|
4
4
|
"description": "Opra CLI tools",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
7
|
-
"repository": {
|
|
8
|
-
"type": "git",
|
|
9
|
-
"url": "https://github.com/panates/opra.git",
|
|
10
|
-
"directory": "packages/client"
|
|
11
|
-
},
|
|
12
|
-
"scripts": {
|
|
13
|
-
"compile": "tsc",
|
|
14
|
-
"prebuild": "npm run check && npm run lint && npm run clean",
|
|
15
|
-
"build": "npm run build:cjs && npm run build:esm",
|
|
16
|
-
"build:cjs": "tsc -b tsconfig-build-cjs.json",
|
|
17
|
-
"build:esm": "tsc -b tsconfig-build-esm.json",
|
|
18
|
-
"postbuild": "npm run copy:files && npm run copy:bin",
|
|
19
|
-
"copy:files": "cp README.md package.json ../../LICENSE ../../build/cli && cp ../../package.cjs.json ../../build/cli/cjs/package.json",
|
|
20
|
-
"copy:bin": "cp -R bin ../../build/cli/bin",
|
|
21
|
-
"lint": "eslint . --max-warnings=0",
|
|
22
|
-
"lint:fix": "eslint . --max-warnings=0 --fix",
|
|
23
|
-
"format": "prettier . --write --log-level=warn",
|
|
24
|
-
"check": "madge --circular src/**",
|
|
25
|
-
"test": "jest --passWithNoTests",
|
|
26
|
-
"cover": "jest --passWithNoTests --collect-coverage",
|
|
27
|
-
"clean": "npm run clean:src && npm run clean:test && npm run clean:dist && npm run clean:cover",
|
|
28
|
-
"clean:src": "ts-cleanup -s src --all",
|
|
29
|
-
"clean:test": "ts-cleanup -s test --all",
|
|
30
|
-
"clean:dist": "rimraf ../../build/client",
|
|
31
|
-
"clean:cover": "rimraf ../../coverage/client"
|
|
32
|
-
},
|
|
33
7
|
"dependencies": {
|
|
34
|
-
"@
|
|
35
|
-
"@opra/
|
|
36
|
-
"
|
|
8
|
+
"@browsery/type-is": "^1.6.18-r5",
|
|
9
|
+
"@opra/client": "^1.0.0-beta.2",
|
|
10
|
+
"@opra/common": "^1.0.0-beta.2",
|
|
11
|
+
"ansi-colors": "^4.1.3",
|
|
37
12
|
"commander": "^12.0.0",
|
|
38
13
|
"js-string-escape": "^1.0.1",
|
|
39
14
|
"putil-flattentext": "^2.1.1",
|
|
40
|
-
"putil-varhelpers": "^1.6.5"
|
|
15
|
+
"putil-varhelpers": "^1.6.5",
|
|
16
|
+
"tslib": "^2.7.0"
|
|
41
17
|
},
|
|
42
18
|
"type": "module",
|
|
43
|
-
"
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"import": {
|
|
22
|
+
"types": "./types/index.d.ts",
|
|
23
|
+
"default": "./esm/index.js"
|
|
24
|
+
},
|
|
25
|
+
"require": {
|
|
26
|
+
"types": "./types/index.d.cts",
|
|
27
|
+
"default": "./cjs/index.js"
|
|
28
|
+
},
|
|
29
|
+
"default": "./esm/index.js"
|
|
30
|
+
},
|
|
31
|
+
"./package.json": "./package.json"
|
|
32
|
+
},
|
|
44
33
|
"main": "./cjs/index.js",
|
|
34
|
+
"module": "./esm/index.js",
|
|
45
35
|
"types": "./types/index.d.ts",
|
|
46
36
|
"bin": {
|
|
47
37
|
"oprimp": "bin/oprimp.mjs"
|
|
48
38
|
},
|
|
39
|
+
"repository": {
|
|
40
|
+
"type": "git",
|
|
41
|
+
"url": "https://github.com/panates/opra.git",
|
|
42
|
+
"directory": "packages/client"
|
|
43
|
+
},
|
|
49
44
|
"engines": {
|
|
50
45
|
"node": ">=18.0",
|
|
51
46
|
"npm": ">=7.0.0"
|
|
@@ -64,4 +59,4 @@
|
|
|
64
59
|
"tool",
|
|
65
60
|
"oprimp"
|
|
66
61
|
]
|
|
67
|
-
}
|
|
62
|
+
}
|
package/types/file-writer.d.ts
CHANGED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ts-generator/index.js';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApiDocument } from '@opra/common';
|
|
2
|
-
import { IFileWriter } from './file-writer.interface.js';
|
|
3
|
-
import { ILogger } from './logger.interface.js';
|
|
2
|
+
import type { IFileWriter } from './file-writer.interface.js';
|
|
3
|
+
import type { ILogger } from './logger.interface.js';
|
|
4
4
|
export interface ServiceGenerationContext {
|
|
5
5
|
serviceUrl: string;
|
|
6
6
|
document: ApiDocument;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { ComplexType, DataType, EnumType, MappedType, MixinType, SimpleType } from '@opra/common';
|
|
2
|
+
import { TsFile } from '../ts-file.js';
|
|
3
|
+
import type { TsGenerator } from '../ts-generator';
|
|
4
|
+
type Intent = 'root' | 'extends' | 'typeDef';
|
|
5
|
+
export type generateDataTypeResult = {
|
|
6
|
+
kind: 'internal';
|
|
7
|
+
typeName: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'named';
|
|
10
|
+
typeName: string;
|
|
11
|
+
file: TsFile;
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'embedded';
|
|
14
|
+
code: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function generateDataType(this: TsGenerator, dataType: DataType, intent: Intent, currentFile?: TsFile): Promise<generateDataTypeResult>;
|
|
17
|
+
/**
|
|
18
|
+
*
|
|
19
|
+
*/
|
|
20
|
+
export declare function _generateTypeCode(this: TsGenerator, currentFile: TsFile, dataType: DataType, intent?: Intent): Promise<string>;
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
export declare function _generateEnumTypeCode(this: TsGenerator, currentFile: TsFile, dataType: EnumType, intent?: Intent): Promise<string>;
|
|
25
|
+
/**
|
|
26
|
+
*
|
|
27
|
+
*/
|
|
28
|
+
export declare function _generateComplexTypeCode(this: TsGenerator, currentFile: TsFile, dataType: ComplexType, intent?: Intent): Promise<string>;
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
*/
|
|
32
|
+
export declare function _generateSimpleTypeCode(this: TsGenerator, currentFile: TsFile, dataType: SimpleType, intent?: Intent): Promise<string>;
|
|
33
|
+
/**
|
|
34
|
+
*
|
|
35
|
+
*/
|
|
36
|
+
export declare function _generateMixinTypeCode(this: TsGenerator, currentFile: TsFile, dataType: MixinType, intent?: Intent): Promise<string>;
|
|
37
|
+
/**
|
|
38
|
+
*
|
|
39
|
+
*/
|
|
40
|
+
export declare function _generateMappedTypeCode(this: TsGenerator, currentFile: TsFile, dataType: MappedType, intent?: Intent): Promise<string>;
|
|
41
|
+
export {};
|
package/types/ts-generator/{processors/process-document.d.ts → generators/generate-document.d.ts}
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ApiDocument } from '@opra/common';
|
|
2
2
|
import type { TsGenerator } from '../ts-generator';
|
|
3
|
-
export declare function
|
|
3
|
+
export declare function generateDocument(this: TsGenerator, document?: string | ApiDocument, options?: {
|
|
4
4
|
typesOnly?: boolean;
|
|
5
5
|
}): Promise<{
|
|
6
6
|
document: ApiDocument;
|
|
@@ -6,12 +6,16 @@ export declare class TsFile {
|
|
|
6
6
|
items: string[];
|
|
7
7
|
typeImport?: boolean;
|
|
8
8
|
}>;
|
|
9
|
-
exportFiles: Record<string,
|
|
9
|
+
exportFiles: Record<string, {
|
|
10
|
+
filename: string;
|
|
11
|
+
items: string[];
|
|
12
|
+
namespace?: string;
|
|
13
|
+
}>;
|
|
10
14
|
exportTypes: string[];
|
|
11
15
|
code: CodeBlock;
|
|
12
16
|
constructor(filename: string);
|
|
13
17
|
addImport(filename: string, items?: string[], typeImport?: boolean): void;
|
|
14
|
-
addExport(filename: string, types?: string[]): void;
|
|
18
|
+
addExport(filename: string, types?: string[], namespace?: string): void;
|
|
15
19
|
generate(options?: {
|
|
16
20
|
importExt?: boolean;
|
|
17
21
|
}): string;
|
|
@@ -1,13 +1,12 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
1
|
import { EventEmitter } from 'node:events';
|
|
3
2
|
import { ApiDocument } from '@opra/common';
|
|
4
|
-
import { IFileWriter } from '../interfaces/file-writer.interface.js';
|
|
5
|
-
import { ILogger } from '../interfaces/logger.interface.js';
|
|
6
|
-
import { cleanDirectory } from './
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
3
|
+
import type { IFileWriter } from '../interfaces/file-writer.interface.js';
|
|
4
|
+
import type { ILogger } from '../interfaces/logger.interface.js';
|
|
5
|
+
import { cleanDirectory } from './generators/clean-directory.js';
|
|
6
|
+
import { _generateComplexTypeCode, _generateEnumTypeCode, _generateMappedTypeCode, _generateMixinTypeCode, _generateSimpleTypeCode, _generateTypeCode, generateDataType } from './generators/generate-data-type.js';
|
|
7
|
+
import { generateDocument } from './generators/generate-document.js';
|
|
8
|
+
import { generateHttpApi } from './generators/generate-http-api.js';
|
|
9
|
+
import { generateHttpController } from './generators/generate-http-controller.js';
|
|
11
10
|
import { TsFile } from './ts-file.js';
|
|
12
11
|
/**
|
|
13
12
|
* @namespace TsGenerator
|
|
@@ -21,6 +20,7 @@ export declare namespace TsGenerator {
|
|
|
21
20
|
writer?: IFileWriter;
|
|
22
21
|
fileHeader?: string;
|
|
23
22
|
importExt?: boolean;
|
|
23
|
+
referenceNamespaces?: boolean;
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
/**
|
|
@@ -28,23 +28,24 @@ export declare namespace TsGenerator {
|
|
|
28
28
|
*/
|
|
29
29
|
export declare class TsGenerator extends EventEmitter {
|
|
30
30
|
protected cleanDirectory: typeof cleanDirectory;
|
|
31
|
-
protected
|
|
32
|
-
protected
|
|
33
|
-
protected
|
|
34
|
-
protected
|
|
35
|
-
protected
|
|
36
|
-
protected
|
|
37
|
-
protected
|
|
38
|
-
protected
|
|
39
|
-
protected
|
|
40
|
-
protected
|
|
41
|
-
protected _started: boolean;
|
|
42
|
-
protected _document?: ApiDocument;
|
|
31
|
+
protected generateDocument: typeof generateDocument;
|
|
32
|
+
protected generateDataType: typeof generateDataType;
|
|
33
|
+
protected _generateTypeCode: typeof _generateTypeCode;
|
|
34
|
+
protected _generateEnumTypeCode: typeof _generateEnumTypeCode;
|
|
35
|
+
protected _generateComplexTypeCode: typeof _generateComplexTypeCode;
|
|
36
|
+
protected _generateSimpleTypeCode: typeof _generateSimpleTypeCode;
|
|
37
|
+
protected _generateMappedTypeCode: typeof _generateMappedTypeCode;
|
|
38
|
+
protected _generateMixinTypeCode: typeof _generateMixinTypeCode;
|
|
39
|
+
protected generateHttpApi: typeof generateHttpApi;
|
|
40
|
+
protected generateHttpController: typeof generateHttpController;
|
|
43
41
|
protected _documentRoot: string;
|
|
44
42
|
protected _typesRoot: string;
|
|
43
|
+
protected _typesNamespace: string;
|
|
45
44
|
protected _apiPath: string;
|
|
46
45
|
protected _fileHeaderDocInfo: string;
|
|
47
46
|
protected _files: Record<string, TsFile>;
|
|
47
|
+
protected _started: boolean;
|
|
48
|
+
protected _document?: ApiDocument;
|
|
48
49
|
protected _documentsMap: Map<string, {
|
|
49
50
|
document: ApiDocument;
|
|
50
51
|
generator: TsGenerator;
|
|
@@ -56,6 +57,7 @@ export declare class TsGenerator extends EventEmitter {
|
|
|
56
57
|
readonly writer: IFileWriter;
|
|
57
58
|
readonly options: {
|
|
58
59
|
importExt: boolean;
|
|
60
|
+
referenceNamespaces?: boolean;
|
|
59
61
|
};
|
|
60
62
|
fileHeader: string;
|
|
61
63
|
/**
|
package/bin/bin/oprimp.mjs
DELETED
|
@@ -1,262 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.resolveTypeNameOrDef = exports.generateMappedTypeDefinition = exports.generateMixinTypeDefinition = exports.generateSimpleTypeDefinition = exports.generateComplexTypeDefinition = exports.generateEnumTypeDefinition = exports.processDataType = void 0;
|
|
4
|
-
const tslib_1 = require("tslib");
|
|
5
|
-
const common_1 = require("@opra/common");
|
|
6
|
-
const path_1 = tslib_1.__importDefault(require("path"));
|
|
7
|
-
const code_block_js_1 = require("../../code-block.js");
|
|
8
|
-
const string_utils_js_1 = require("../utils/string-utils.js");
|
|
9
|
-
const internalTypeNames = ['any', 'boolean', 'bigint', 'number', 'null', 'string', 'object'];
|
|
10
|
-
async function processDataType(dataType) {
|
|
11
|
-
const doc = dataType.node.getDocument();
|
|
12
|
-
if (doc.id !== this._document?.id) {
|
|
13
|
-
const { generator } = await this.processDocument(doc);
|
|
14
|
-
return await generator.processDataType(dataType);
|
|
15
|
-
}
|
|
16
|
-
const typeName = dataType.name;
|
|
17
|
-
if (typeName && internalTypeNames.includes(typeName))
|
|
18
|
-
return;
|
|
19
|
-
if (!typeName)
|
|
20
|
-
throw new TypeError(`DataType has no name`);
|
|
21
|
-
let file = this._filesMap.get(dataType);
|
|
22
|
-
if (file)
|
|
23
|
-
return file;
|
|
24
|
-
if (dataType instanceof common_1.SimpleType)
|
|
25
|
-
file = this.addFile(path_1.default.join(this._documentRoot, '/simple-types.ts'), true);
|
|
26
|
-
else {
|
|
27
|
-
if (dataType instanceof common_1.EnumType)
|
|
28
|
-
file = this.addFile(path_1.default.join(this._typesRoot, 'enums', typeName + '.ts'));
|
|
29
|
-
else
|
|
30
|
-
file = this.addFile(path_1.default.join(this._typesRoot, 'types', typeName + '.ts'));
|
|
31
|
-
}
|
|
32
|
-
this._filesMap.set(dataType, file);
|
|
33
|
-
file = this._filesMap.get(dataType);
|
|
34
|
-
if (file.exportTypes.includes(typeName))
|
|
35
|
-
return file;
|
|
36
|
-
file.exportTypes.push(typeName);
|
|
37
|
-
const typesIndexTs = this.addFile(path_1.default.join(this._typesRoot, 'index.ts'), true);
|
|
38
|
-
const indexTs = this.addFile('/index.ts', true);
|
|
39
|
-
indexTs.addExport(typesIndexTs.filename);
|
|
40
|
-
const codeBlock = (file.code['type_' + typeName] = new code_block_js_1.CodeBlock());
|
|
41
|
-
codeBlock.head = `/**\n * ${typeName}`;
|
|
42
|
-
if (dataType.description)
|
|
43
|
-
codeBlock.head += `\n * ${(0, string_utils_js_1.wrapJSDocString)(dataType.description || '')}`;
|
|
44
|
-
codeBlock.head += `
|
|
45
|
-
* @url ${path_1.default.posix.join(doc.url || this.serviceUrl, '$schema', '#types/' + typeName)}
|
|
46
|
-
*/
|
|
47
|
-
export `;
|
|
48
|
-
if (dataType instanceof common_1.EnumType)
|
|
49
|
-
codeBlock.typeDef = await this.generateEnumTypeDefinition(dataType, 'scope');
|
|
50
|
-
else if (dataType instanceof common_1.ComplexType) {
|
|
51
|
-
codeBlock.typeDef = await this.generateComplexTypeDefinition(dataType, file, 'scope');
|
|
52
|
-
}
|
|
53
|
-
else if (dataType instanceof common_1.SimpleType) {
|
|
54
|
-
codeBlock.typeDef = await this.generateSimpleTypeDefinition(dataType, 'scope');
|
|
55
|
-
}
|
|
56
|
-
else if (dataType instanceof common_1.MappedType) {
|
|
57
|
-
codeBlock.typeDef = await this.generateMappedTypeDefinition(dataType, file, 'scope');
|
|
58
|
-
}
|
|
59
|
-
else if (dataType instanceof common_1.MixinType) {
|
|
60
|
-
codeBlock.typeDef = await this.generateMixinTypeDefinition(dataType, file, 'scope');
|
|
61
|
-
}
|
|
62
|
-
else
|
|
63
|
-
throw new TypeError(`${dataType.kind} data type (${typeName}) can not be directly exported`);
|
|
64
|
-
typesIndexTs.addExport(file.filename);
|
|
65
|
-
return file;
|
|
66
|
-
}
|
|
67
|
-
exports.processDataType = processDataType;
|
|
68
|
-
/**
|
|
69
|
-
*
|
|
70
|
-
*/
|
|
71
|
-
async function generateEnumTypeDefinition(dataType, intent) {
|
|
72
|
-
if (intent === 'field') {
|
|
73
|
-
return ('(' +
|
|
74
|
-
Object.keys(dataType.attributes)
|
|
75
|
-
.map(t => `'${t}'`)
|
|
76
|
-
.join(' | ') +
|
|
77
|
-
')');
|
|
78
|
-
}
|
|
79
|
-
if (intent !== 'scope')
|
|
80
|
-
throw new TypeError(`Can't generate EnumType for "${intent}" intent`);
|
|
81
|
-
if (!dataType.name)
|
|
82
|
-
throw new TypeError(`Name required to generate EnumType for "${intent}" intent`);
|
|
83
|
-
let out = `enum ${dataType.name} {\n\t`;
|
|
84
|
-
for (const [value, info] of Object.entries(dataType.attributes)) {
|
|
85
|
-
// Print JSDoc
|
|
86
|
-
let jsDoc = '';
|
|
87
|
-
if (dataType.attributes[value].description)
|
|
88
|
-
jsDoc += ` * ${dataType.attributes[value].description}\n`;
|
|
89
|
-
if (jsDoc)
|
|
90
|
-
out += `/**\n${jsDoc} */\n`;
|
|
91
|
-
out +=
|
|
92
|
-
`${info.alias || value} = ` + (typeof value === 'number' ? value : "'" + String(value).replace("'", "\\'") + "'");
|
|
93
|
-
out += ',\n\n';
|
|
94
|
-
}
|
|
95
|
-
return out + '\b}';
|
|
96
|
-
}
|
|
97
|
-
exports.generateEnumTypeDefinition = generateEnumTypeDefinition;
|
|
98
|
-
/**
|
|
99
|
-
*
|
|
100
|
-
*/
|
|
101
|
-
async function generateComplexTypeDefinition(dataType, file, intent) {
|
|
102
|
-
if (intent === 'scope' && !dataType.name) {
|
|
103
|
-
throw new TypeError(`Name required to generate ComplexType for "${intent}" intent`);
|
|
104
|
-
}
|
|
105
|
-
let out = intent === 'scope' ? `interface ${dataType.name} ` : '';
|
|
106
|
-
const ownFields = [...dataType.fields.values()].filter(f => f.origin === dataType);
|
|
107
|
-
if (dataType.base) {
|
|
108
|
-
const base = await this.resolveTypeNameOrDef(dataType.base, file, 'extends');
|
|
109
|
-
const omitBaseFields = dataType.base ? ownFields.filter(f => dataType.base.fields.has(f.name)) : [];
|
|
110
|
-
const baseDef = omitBaseFields.length
|
|
111
|
-
? `Omit<${base}, ${omitBaseFields.map(x => "'" + x.name + "'").join(' | ')}>`
|
|
112
|
-
: `${base}`;
|
|
113
|
-
if (intent === 'scope')
|
|
114
|
-
out += `extends ${baseDef} `;
|
|
115
|
-
else {
|
|
116
|
-
out += baseDef;
|
|
117
|
-
if (!ownFields.length)
|
|
118
|
-
return out;
|
|
119
|
-
out += ' & ';
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
out += '{\n\t';
|
|
123
|
-
let i = 0;
|
|
124
|
-
for (const field of ownFields) {
|
|
125
|
-
if (i++)
|
|
126
|
-
out += '\n';
|
|
127
|
-
// Print JSDoc
|
|
128
|
-
out += `/**\n * ${field.description || ''}\n`;
|
|
129
|
-
if (field.default)
|
|
130
|
-
out += ` * @default ` + field.default + '\n';
|
|
131
|
-
// if (field.format)
|
|
132
|
-
// jsDoc += ` * @format ` + field.format + '\n';
|
|
133
|
-
if (field.exclusive)
|
|
134
|
-
out += ` * @exclusive\n`;
|
|
135
|
-
if (field.readonly)
|
|
136
|
-
out += ` * @readonly\n`;
|
|
137
|
-
if (field.writeonly)
|
|
138
|
-
out += ` * @writeonly\n`;
|
|
139
|
-
if (field.deprecated) {
|
|
140
|
-
out += ` * @deprecated ` + (typeof field.deprecated === 'string' ? field.deprecated : '') + '\n';
|
|
141
|
-
}
|
|
142
|
-
out += ' */\n';
|
|
143
|
-
// Print field name
|
|
144
|
-
if (field.readonly)
|
|
145
|
-
out += 'readonly ';
|
|
146
|
-
out += `${field.name}${field.required ? '' : '?'}: `;
|
|
147
|
-
if (field.fixed) {
|
|
148
|
-
const t = typeof field.fixed;
|
|
149
|
-
out += `${t === 'number' || t === 'boolean' || t === 'bigint' ? field.fixed : "'" + field.fixed + "'"}\n`;
|
|
150
|
-
}
|
|
151
|
-
else {
|
|
152
|
-
out += (await this.resolveTypeNameOrDef(field.type, file, 'field')) + `${field.isArray ? '[]' : ''};\n`;
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
if (dataType.additionalFields)
|
|
156
|
-
out += '[key: string]: any;\n';
|
|
157
|
-
return out + '\b}';
|
|
158
|
-
}
|
|
159
|
-
exports.generateComplexTypeDefinition = generateComplexTypeDefinition;
|
|
160
|
-
/**
|
|
161
|
-
*
|
|
162
|
-
*/
|
|
163
|
-
async function generateSimpleTypeDefinition(dataType, intent) {
|
|
164
|
-
if (intent === 'scope' && !dataType.name) {
|
|
165
|
-
throw new TypeError(`Name required to generate SimpleType for "${intent}" intent`);
|
|
166
|
-
}
|
|
167
|
-
let out = intent === 'scope' ? `type ${dataType.name} = ` : '';
|
|
168
|
-
out += dataType.nameMappings.js || 'any';
|
|
169
|
-
return intent === 'scope' ? out + ';' : out;
|
|
170
|
-
}
|
|
171
|
-
exports.generateSimpleTypeDefinition = generateSimpleTypeDefinition;
|
|
172
|
-
/**
|
|
173
|
-
*
|
|
174
|
-
*/
|
|
175
|
-
async function generateMixinTypeDefinition(dataType, file, intent) {
|
|
176
|
-
return (await Promise.all(dataType.types.map(t => this.resolveTypeNameOrDef(t, file, intent))))
|
|
177
|
-
.map(t => (t.includes('|') ? '(' + t + ')' : t))
|
|
178
|
-
.join(intent === 'extends' ? ', ' : ' & ');
|
|
179
|
-
}
|
|
180
|
-
exports.generateMixinTypeDefinition = generateMixinTypeDefinition;
|
|
181
|
-
/**
|
|
182
|
-
*
|
|
183
|
-
*/
|
|
184
|
-
async function generateMappedTypeDefinition(dataType, file, intent) {
|
|
185
|
-
const typeDef = await this.resolveTypeNameOrDef(dataType.base, file, intent);
|
|
186
|
-
const pick = dataType.pick?.length ? dataType.pick : undefined;
|
|
187
|
-
const omit = !pick && dataType.omit?.length ? dataType.omit : undefined;
|
|
188
|
-
const partial = dataType.partial === true || (Array.isArray(dataType.partial) && dataType.partial.length > 0)
|
|
189
|
-
? dataType.partial
|
|
190
|
-
: undefined;
|
|
191
|
-
const required = dataType.required === true || (Array.isArray(dataType.required) && dataType.required.length > 0)
|
|
192
|
-
? dataType.required
|
|
193
|
-
: undefined;
|
|
194
|
-
if (!(pick || omit || partial || required))
|
|
195
|
-
return typeDef;
|
|
196
|
-
let out = '';
|
|
197
|
-
if (partial === true)
|
|
198
|
-
out += 'Partial<';
|
|
199
|
-
else if (partial) {
|
|
200
|
-
out += 'PartialSome<';
|
|
201
|
-
file.addExport('ts-gems', ['PartialSome']);
|
|
202
|
-
}
|
|
203
|
-
if (required === true)
|
|
204
|
-
out += 'Partial<';
|
|
205
|
-
else if (required) {
|
|
206
|
-
out += 'RequiredSome<';
|
|
207
|
-
file.addExport('ts-gems', ['RequiredSome']);
|
|
208
|
-
}
|
|
209
|
-
if (pick)
|
|
210
|
-
out += 'Pick<';
|
|
211
|
-
else if (omit)
|
|
212
|
-
out += 'Omit<';
|
|
213
|
-
out += typeDef;
|
|
214
|
-
if (omit || pick) {
|
|
215
|
-
out +=
|
|
216
|
-
', ' +
|
|
217
|
-
(omit || pick)
|
|
218
|
-
.filter(x => !!x)
|
|
219
|
-
.map(x => `'${x}'`)
|
|
220
|
-
.join(' | ') +
|
|
221
|
-
'>';
|
|
222
|
-
}
|
|
223
|
-
if (partial) {
|
|
224
|
-
if (Array.isArray(partial)) {
|
|
225
|
-
out +=
|
|
226
|
-
', ' +
|
|
227
|
-
partial
|
|
228
|
-
.filter(x => !!x)
|
|
229
|
-
.map(x => `'${x}'`)
|
|
230
|
-
.join(' | ');
|
|
231
|
-
}
|
|
232
|
-
out += '>';
|
|
233
|
-
}
|
|
234
|
-
return out;
|
|
235
|
-
}
|
|
236
|
-
exports.generateMappedTypeDefinition = generateMappedTypeDefinition;
|
|
237
|
-
/**
|
|
238
|
-
*
|
|
239
|
-
*/
|
|
240
|
-
async function resolveTypeNameOrDef(dataType, file, intent) {
|
|
241
|
-
if (dataType.name && !dataType.embedded) {
|
|
242
|
-
if (internalTypeNames.includes(dataType.name))
|
|
243
|
-
return dataType.name;
|
|
244
|
-
const f = await this.processDataType(dataType);
|
|
245
|
-
if (!f)
|
|
246
|
-
return '';
|
|
247
|
-
file.addImport(f.filename, [dataType.name], true);
|
|
248
|
-
return dataType.name;
|
|
249
|
-
}
|
|
250
|
-
if (dataType instanceof common_1.SimpleType)
|
|
251
|
-
return this.generateSimpleTypeDefinition(dataType, intent);
|
|
252
|
-
if (dataType instanceof common_1.EnumType)
|
|
253
|
-
return this.generateEnumTypeDefinition(dataType, intent);
|
|
254
|
-
if (dataType instanceof common_1.MixinType)
|
|
255
|
-
return this.generateMixinTypeDefinition(dataType, file, intent);
|
|
256
|
-
if (dataType instanceof common_1.MappedType)
|
|
257
|
-
return this.generateMappedTypeDefinition(dataType, file, intent);
|
|
258
|
-
if (dataType instanceof common_1.ComplexType)
|
|
259
|
-
return this.generateComplexTypeDefinition(dataType, file, intent);
|
|
260
|
-
return '';
|
|
261
|
-
}
|
|
262
|
-
exports.resolveTypeNameOrDef = resolveTypeNameOrDef;
|