@opra/cli 1.26.2 → 1.26.4
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/README.md +125 -2
- package/code-block.d.ts +10 -0
- package/code-block.js +10 -0
- package/file-writer.d.ts +11 -0
- package/file-writer.js +11 -0
- package/interfaces/file-writer.interface.d.ts +12 -0
- package/interfaces/logger.interface.d.ts +35 -0
- package/oprimp-cli.js +1 -1
- package/package.json +3 -3
- package/ts-generator/generators/clean-directory.d.ts +5 -0
- package/ts-generator/generators/clean-directory.js +5 -0
- package/ts-generator/generators/generate-data-type.d.ts +52 -0
- package/ts-generator/generators/generate-data-type.js +56 -4
- package/ts-generator/generators/generate-document.d.ts +7 -0
- package/ts-generator/generators/generate-document.js +7 -0
- package/ts-generator/generators/generate-http-api.d.ts +6 -0
- package/ts-generator/generators/generate-http-api.js +6 -0
- package/ts-generator/generators/generate-http-controller.d.ts +6 -0
- package/ts-generator/generators/generate-http-controller.js +30 -27
- package/ts-generator/ts-file.d.ts +35 -0
- package/ts-generator/ts-file.js +35 -0
- package/ts-generator/ts-generator.d.ts +38 -3
- package/ts-generator/ts-generator.js +24 -2
- package/ts-generator/utils/locate-named-type.d.ts +6 -0
- package/ts-generator/utils/locate-named-type.js +6 -0
- package/ts-generator/utils/string-utils.d.ts +32 -0
- package/ts-generator/utils/string-utils.js +32 -0
package/README.md
CHANGED
|
@@ -1,3 +1,126 @@
|
|
|
1
|
-
# @opra/
|
|
1
|
+
# @opra/cli
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[![NPM Version][npm-image]][npm-url]
|
|
4
|
+
[![NPM Downloads][downloads-image]][downloads-url]
|
|
5
|
+
[![CI Tests][ci-test-image]][ci-test-url]
|
|
6
|
+
[![Test Coverage][coveralls-image]][coveralls-url]
|
|
7
|
+
|
|
8
|
+
`@opra/cli` is a command-line tool for OPRA (Open Protocol for Restfull APIs). It currently features `oprimp`, a
|
|
9
|
+
TypeScript code generator that creates client-side models and API services from an OPRA service.
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
You can install `@opra/cli` globally or as a development dependency in your project.
|
|
14
|
+
|
|
15
|
+
### Global Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install -g @opra/cli
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Local Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install --save-dev @opra/cli
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## CLI Usage: oprimp
|
|
28
|
+
|
|
29
|
+
The `oprimp` tool generates TypeScript code from an OPRA service URL.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
oprimp <serviceUrl> <outDir> [options]
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Arguments
|
|
36
|
+
|
|
37
|
+
- `serviceUrl`: The URL of the OPRA service (e.g., `http://localhost:3000/opra`).
|
|
38
|
+
- `outDir`: The output directory where the generated files will be saved.
|
|
39
|
+
|
|
40
|
+
### Options
|
|
41
|
+
|
|
42
|
+
- `--ext`: Adds `.js` extension to imports. This is useful for ESM projects.
|
|
43
|
+
- `--refns`: Exports referenced API documentation with namespaces.
|
|
44
|
+
- `--no-color`: Disables colors in log messages.
|
|
45
|
+
- `-v, --version`: Displays the version number.
|
|
46
|
+
- `-h, --help`: Displays help information.
|
|
47
|
+
|
|
48
|
+
### Examples
|
|
49
|
+
|
|
50
|
+
#### Basic Usage
|
|
51
|
+
|
|
52
|
+
Generate TypeScript code from a local OPRA service:
|
|
53
|
+
|
|
54
|
+
```bash
|
|
55
|
+
npx oprimp http://localhost:3000/opra ./src/generated
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### ESM Projects
|
|
59
|
+
|
|
60
|
+
If your project uses ESM and requires file extensions in imports:
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
npx oprimp http://localhost:3000/opra ./src/generated --ext
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## Programmatic Usage
|
|
67
|
+
|
|
68
|
+
You can also use the `TsGenerator` class programmatically in your scripts.
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { TsGenerator } from '@opra/cli';
|
|
72
|
+
|
|
73
|
+
async function generate() {
|
|
74
|
+
const generator = new TsGenerator({
|
|
75
|
+
serviceUrl: 'http://localhost:3000/opra',
|
|
76
|
+
outDir: './src/generated',
|
|
77
|
+
importExt: true, // Optional: add .js extensions
|
|
78
|
+
fileHeader: '/* Generated by OPRA */', // Optional: add a header to files
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
await generator.generate();
|
|
82
|
+
console.log('Generation completed!');
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
generate().catch(console.error);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### TsGenerator Options
|
|
89
|
+
|
|
90
|
+
| Option | Type | Description |
|
|
91
|
+
|-----------------------|-----------|----------------------------------------------------------------|
|
|
92
|
+
| `serviceUrl` | `string` | **Required**. The URL of the OPRA service. |
|
|
93
|
+
| `outDir` | `string` | **Required**. The output directory for the generated files. |
|
|
94
|
+
| `cwd` | `string` | The current working directory. Defaults to `process.cwd()`. |
|
|
95
|
+
| `logger` | `ILogger` | Logger instance for outputting information. |
|
|
96
|
+
| `fileHeader` | `string` | Optional header text to add to the top of each generated file. |
|
|
97
|
+
| `importExt` | `boolean` | Whether to add `.js` extension to imports. |
|
|
98
|
+
| `referenceNamespaces` | `boolean` | Whether to export references with namespaces. |
|
|
99
|
+
|
|
100
|
+
## Support
|
|
101
|
+
|
|
102
|
+
You can report bugs and discuss features on the [GitHub issues](https://github.com/panates/opra/issues) page.
|
|
103
|
+
|
|
104
|
+
## Node Compatibility
|
|
105
|
+
|
|
106
|
+
- node >= 20.x
|
|
107
|
+
|
|
108
|
+
## License
|
|
109
|
+
|
|
110
|
+
Available under [MIT](LICENSE) license.
|
|
111
|
+
|
|
112
|
+
[npm-image]: https://img.shields.io/npm/v/@opra/cli
|
|
113
|
+
|
|
114
|
+
[npm-url]: https://npmjs.org/package/@opra/cli
|
|
115
|
+
|
|
116
|
+
[downloads-image]: https://img.shields.io/npm/dm/@opra/cli.svg
|
|
117
|
+
|
|
118
|
+
[downloads-url]: https://npmjs.org/package/@opra/cli
|
|
119
|
+
|
|
120
|
+
[ci-test-image]: https://github.com/panates/opra/actions/workflows/test.yml/badge.svg
|
|
121
|
+
|
|
122
|
+
[ci-test-url]: https://github.com/panates/opra/actions/workflows/test.yml
|
|
123
|
+
|
|
124
|
+
[coveralls-image]: https://coveralls.io/repos/github/panates/opra/badge.svg?branch=main
|
|
125
|
+
|
|
126
|
+
[coveralls-url]: https://coveralls.io/github/panates/opra?branch=main
|
package/code-block.d.ts
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeBlock
|
|
3
|
+
*
|
|
4
|
+
* A class representing a block of code, which can be composed of multiple segments.
|
|
5
|
+
*/
|
|
1
6
|
export declare class CodeBlock {
|
|
2
7
|
[index: string]: any;
|
|
8
|
+
/**
|
|
9
|
+
* Concatenates all segments of the code block into a single string.
|
|
10
|
+
*
|
|
11
|
+
* @returns The full code as a string.
|
|
12
|
+
*/
|
|
3
13
|
toString(): string;
|
|
4
14
|
[Symbol.toStringTag](): string;
|
|
5
15
|
}
|
package/code-block.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CodeBlock
|
|
3
|
+
*
|
|
4
|
+
* A class representing a block of code, which can be composed of multiple segments.
|
|
5
|
+
*/
|
|
1
6
|
export class CodeBlock {
|
|
7
|
+
/**
|
|
8
|
+
* Concatenates all segments of the code block into a single string.
|
|
9
|
+
*
|
|
10
|
+
* @returns The full code as a string.
|
|
11
|
+
*/
|
|
2
12
|
toString() {
|
|
3
13
|
// if (this.content) return this.content;
|
|
4
14
|
let out = '';
|
package/file-writer.d.ts
CHANGED
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { IFileWriter } from './interfaces/file-writer.interface.js';
|
|
2
|
+
/**
|
|
3
|
+
* FileWriter
|
|
4
|
+
*
|
|
5
|
+
* Implementation of IFileWriter that uses node:fs to write files.
|
|
6
|
+
*/
|
|
2
7
|
export declare class FileWriter implements IFileWriter {
|
|
8
|
+
/**
|
|
9
|
+
* Writes contents to a file.
|
|
10
|
+
*
|
|
11
|
+
* @param filename - The path to the file to write.
|
|
12
|
+
* @param contents - The string content to write to the file.
|
|
13
|
+
*/
|
|
3
14
|
writeFile(filename: string, contents: string): void;
|
|
4
15
|
}
|
package/file-writer.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
|
+
/**
|
|
3
|
+
* FileWriter
|
|
4
|
+
*
|
|
5
|
+
* Implementation of IFileWriter that uses node:fs to write files.
|
|
6
|
+
*/
|
|
2
7
|
export class FileWriter {
|
|
8
|
+
/**
|
|
9
|
+
* Writes contents to a file.
|
|
10
|
+
*
|
|
11
|
+
* @param filename - The path to the file to write.
|
|
12
|
+
* @param contents - The string content to write to the file.
|
|
13
|
+
*/
|
|
3
14
|
writeFile(filename, contents) {
|
|
4
15
|
fs.writeFileSync(filename, contents, 'utf-8');
|
|
5
16
|
}
|
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IFileWriter
|
|
3
|
+
*
|
|
4
|
+
* Interface for file writing operations.
|
|
5
|
+
*/
|
|
1
6
|
export interface IFileWriter {
|
|
7
|
+
/**
|
|
8
|
+
* Writes contents to a file.
|
|
9
|
+
*
|
|
10
|
+
* @param filename - The path to the file to write.
|
|
11
|
+
* @param contents - The string content to write to the file.
|
|
12
|
+
* @returns A promise that resolves when the file is written, or void if synchronous.
|
|
13
|
+
*/
|
|
2
14
|
writeFile(filename: string, contents: string): Promise<void> | void;
|
|
3
15
|
}
|
|
@@ -1,7 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ILogger
|
|
3
|
+
*
|
|
4
|
+
* Interface for logging operations within the CLI.
|
|
5
|
+
*/
|
|
1
6
|
export interface ILogger {
|
|
7
|
+
/**
|
|
8
|
+
* Logs a general message.
|
|
9
|
+
*
|
|
10
|
+
* @param message - The message to log.
|
|
11
|
+
* @param optionalParams - Additional parameters for the log message.
|
|
12
|
+
*/
|
|
2
13
|
log(message: any, ...optionalParams: any[]): any;
|
|
14
|
+
/**
|
|
15
|
+
* Logs an error message.
|
|
16
|
+
*
|
|
17
|
+
* @param message - The error message to log.
|
|
18
|
+
* @param optionalParams - Additional parameters for the error message.
|
|
19
|
+
*/
|
|
3
20
|
error(message: any, ...optionalParams: any[]): any;
|
|
21
|
+
/**
|
|
22
|
+
* Logs a warning message.
|
|
23
|
+
*
|
|
24
|
+
* @param message - The warning message to log.
|
|
25
|
+
* @param optionalParams - Additional parameters for the warning message.
|
|
26
|
+
*/
|
|
4
27
|
warn(message: any, ...optionalParams: any[]): any;
|
|
28
|
+
/**
|
|
29
|
+
* Logs a debug message.
|
|
30
|
+
*
|
|
31
|
+
* @param message - The debug message to log.
|
|
32
|
+
* @param optionalParams - Additional parameters for the debug message.
|
|
33
|
+
*/
|
|
5
34
|
debug?(message: any, ...optionalParams: any[]): any;
|
|
35
|
+
/**
|
|
36
|
+
* Logs a verbose message.
|
|
37
|
+
*
|
|
38
|
+
* @param message - The verbose message to log.
|
|
39
|
+
* @param optionalParams - Additional parameters for the verbose message.
|
|
40
|
+
*/
|
|
6
41
|
verbose?(message: any, ...optionalParams: any[]): any;
|
|
7
42
|
}
|
package/oprimp-cli.js
CHANGED
|
@@ -15,7 +15,7 @@ program
|
|
|
15
15
|
.argument('<serviceUrl>', 'OPRA service url')
|
|
16
16
|
.argument('<outDir>', 'Output directory')
|
|
17
17
|
.option('--ext', 'Adds js extension to imports')
|
|
18
|
-
.option('--refns', 'Exports
|
|
18
|
+
.option('--refns', 'Exports referenced API documentation with namespaces')
|
|
19
19
|
.option('--no-color', 'Disables colors in logs messages')
|
|
20
20
|
.action(async (serviceUrl, outDir, options) => {
|
|
21
21
|
if (!options.color)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opra/cli",
|
|
3
|
-
"version": "1.26.
|
|
3
|
+
"version": "1.26.4",
|
|
4
4
|
"description": "Opra CLI tools",
|
|
5
5
|
"author": "Panates",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,8 +15,8 @@
|
|
|
15
15
|
"tslib": "^2.8.1"
|
|
16
16
|
},
|
|
17
17
|
"peerDependencies": {
|
|
18
|
-
"@opra/client": "^1.26.
|
|
19
|
-
"@opra/common": "^1.26.
|
|
18
|
+
"@opra/client": "^1.26.4",
|
|
19
|
+
"@opra/common": "^1.26.4"
|
|
20
20
|
},
|
|
21
21
|
"type": "module",
|
|
22
22
|
"module": "./index.js",
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import colors from 'ansi-colors';
|
|
4
|
+
/**
|
|
5
|
+
* Cleans the output directory.
|
|
6
|
+
*
|
|
7
|
+
* @param dirname - The directory to clean.
|
|
8
|
+
*/
|
|
4
9
|
export function cleanDirectory(dirname) {
|
|
5
10
|
const rootDir = dirname;
|
|
6
11
|
const _cleanDirectory = (targetDir) => {
|
|
@@ -14,37 +14,89 @@ export type generateDataTypeResult = {
|
|
|
14
14
|
kind: 'embedded';
|
|
15
15
|
code: string;
|
|
16
16
|
};
|
|
17
|
+
/**
|
|
18
|
+
* Generates TypeScript code for a given data type.
|
|
19
|
+
*
|
|
20
|
+
* @param dataType - The data type to generate code for.
|
|
21
|
+
* @param intent - The generation intent (root, extends, typeDef).
|
|
22
|
+
* @param currentFile - The current file being generated.
|
|
23
|
+
* @returns A promise that resolves to the generation result.
|
|
24
|
+
* @throws {@link TypeError} If currentFile is not provided for embedded generation.
|
|
25
|
+
*/
|
|
17
26
|
export declare function generateDataType(this: TsGenerator, dataType: DataType, intent: Intent, currentFile?: TsFile): Promise<generateDataTypeResult>;
|
|
18
27
|
/**
|
|
28
|
+
* Generates the TypeScript type definition for a data type.
|
|
19
29
|
*
|
|
30
|
+
* @param currentFile - The current file being generated.
|
|
31
|
+
* @param dataType - The data type to generate code for.
|
|
32
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
33
|
+
* @param intent - The generation intent.
|
|
34
|
+
* @throws {@link TypeError} If name is required but not provided.
|
|
20
35
|
*/
|
|
21
36
|
export declare function _generateTypeCode(this: TsGenerator, currentFile: TsFile, dataType: DataType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
22
37
|
/**
|
|
38
|
+
* Generates code for an array type.
|
|
23
39
|
*
|
|
40
|
+
* @param currentFile - The current file being generated.
|
|
41
|
+
* @param dataType - The array data type.
|
|
42
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
43
|
+
* @param intent - The generation intent.
|
|
44
|
+
* @throws {@link TypeError} If array type is attempted to be extended.
|
|
24
45
|
*/
|
|
25
46
|
export declare function _generateArrayTypeCode(this: TsGenerator, currentFile: TsFile, dataType: ArrayType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
26
47
|
/**
|
|
48
|
+
* Generates code for a complex type.
|
|
27
49
|
*
|
|
50
|
+
* @param currentFile - The current file being generated.
|
|
51
|
+
* @param dataType - The complex data type.
|
|
52
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
53
|
+
* @param intent - The generation intent.
|
|
28
54
|
*/
|
|
29
55
|
export declare function _generateComplexTypeCode(this: TsGenerator, currentFile: TsFile, dataType: ComplexType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
30
56
|
/**
|
|
57
|
+
* Generates code for an enum type.
|
|
31
58
|
*
|
|
59
|
+
* @param currentFile - The current file being generated.
|
|
60
|
+
* @param dataType - The enum data type.
|
|
61
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
62
|
+
* @param intent - The generation intent.
|
|
32
63
|
*/
|
|
33
64
|
export declare function _generateEnumTypeCode(this: TsGenerator, currentFile: TsFile, dataType: EnumType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
34
65
|
/**
|
|
66
|
+
* Generates code for a mapped type.
|
|
35
67
|
*
|
|
68
|
+
* @param currentFile - The current file being generated.
|
|
69
|
+
* @param dataType - The mapped data type.
|
|
70
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
71
|
+
* @param intent - The generation intent.
|
|
36
72
|
*/
|
|
37
73
|
export declare function _generateMappedTypeCode(this: TsGenerator, currentFile: TsFile, dataType: MappedType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
38
74
|
/**
|
|
75
|
+
* Generates code for a mixin type.
|
|
39
76
|
*
|
|
77
|
+
* @param currentFile - The current file being generated.
|
|
78
|
+
* @param dataType - The mixin data type.
|
|
79
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
80
|
+
* @param intent - The generation intent.
|
|
40
81
|
*/
|
|
41
82
|
export declare function _generateMixinTypeCode(this: TsGenerator, currentFile: TsFile, dataType: MixinType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
42
83
|
/**
|
|
84
|
+
* Generates code for a simple type.
|
|
43
85
|
*
|
|
86
|
+
* @param currentFile - The current file being generated.
|
|
87
|
+
* @param dataType - The simple data type.
|
|
88
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
89
|
+
* @param intent - The generation intent.
|
|
44
90
|
*/
|
|
45
91
|
export declare function _generateSimpleTypeCode(this: TsGenerator, currentFile: TsFile, dataType: SimpleType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
46
92
|
/**
|
|
93
|
+
* Generates code for a union type.
|
|
47
94
|
*
|
|
95
|
+
* @param currentFile - The current file being generated.
|
|
96
|
+
* @param dataType - The union data type.
|
|
97
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
98
|
+
* @param intent - The generation intent.
|
|
99
|
+
* @throws {@link TypeError} If union type is attempted to be extended.
|
|
48
100
|
*/
|
|
49
101
|
export declare function _generateUnionTypeCode(this: TsGenerator, currentFile: TsFile, dataType: UnionType, codeBlock: CodeBlock, intent?: Intent): Promise<void>;
|
|
50
102
|
export {};
|
|
@@ -12,6 +12,15 @@ const internalTypeNames = [
|
|
|
12
12
|
'string',
|
|
13
13
|
'object',
|
|
14
14
|
];
|
|
15
|
+
/**
|
|
16
|
+
* Generates TypeScript code for a given data type.
|
|
17
|
+
*
|
|
18
|
+
* @param dataType - The data type to generate code for.
|
|
19
|
+
* @param intent - The generation intent (root, extends, typeDef).
|
|
20
|
+
* @param currentFile - The current file being generated.
|
|
21
|
+
* @returns A promise that resolves to the generation result.
|
|
22
|
+
* @throws {@link TypeError} If currentFile is not provided for embedded generation.
|
|
23
|
+
*/
|
|
15
24
|
export async function generateDataType(dataType, intent, currentFile) {
|
|
16
25
|
const doc = dataType.node.getDocument();
|
|
17
26
|
if (doc.id !== this._document?.id) {
|
|
@@ -24,7 +33,7 @@ export async function generateDataType(dataType, intent, currentFile) {
|
|
|
24
33
|
if (dataType instanceof ComplexType &&
|
|
25
34
|
dataType.ctor === OperationResult) {
|
|
26
35
|
if (currentFile)
|
|
27
|
-
currentFile.addImport('@opra/common', [typeName]);
|
|
36
|
+
currentFile.addImport('@opra/common', [typeName], true);
|
|
28
37
|
return { kind: 'internal', typeName: dataType.name };
|
|
29
38
|
}
|
|
30
39
|
if (internalTypeNames.includes(typeName))
|
|
@@ -32,7 +41,7 @@ export async function generateDataType(dataType, intent, currentFile) {
|
|
|
32
41
|
let file = this._filesMap.get(dataType);
|
|
33
42
|
if (file) {
|
|
34
43
|
if (currentFile)
|
|
35
|
-
currentFile.addImport(file.filename, [typeName]);
|
|
44
|
+
currentFile.addImport(file.filename, [typeName], true);
|
|
36
45
|
return { kind: 'named', file, typeName: dataType.name };
|
|
37
46
|
}
|
|
38
47
|
if (dataType instanceof SimpleType)
|
|
@@ -45,7 +54,7 @@ export async function generateDataType(dataType, intent, currentFile) {
|
|
|
45
54
|
this._filesMap.set(dataType, file);
|
|
46
55
|
if (file.exportTypes.includes(typeName)) {
|
|
47
56
|
if (currentFile)
|
|
48
|
-
currentFile.addImport(file.filename, [typeName]);
|
|
57
|
+
currentFile.addImport(file.filename, [typeName], true);
|
|
49
58
|
return { kind: 'named', file, typeName: dataType.name };
|
|
50
59
|
}
|
|
51
60
|
file.exportTypes.push(typeName);
|
|
@@ -62,7 +71,7 @@ export async function generateDataType(dataType, intent, currentFile) {
|
|
|
62
71
|
codeBlock.type_end = '\n\n';
|
|
63
72
|
typesIndexTs.addExport(file.filename);
|
|
64
73
|
if (currentFile)
|
|
65
|
-
currentFile.addImport(file.filename, [typeName]);
|
|
74
|
+
currentFile.addImport(file.filename, [typeName], true);
|
|
66
75
|
return { kind: 'named', file, typeName };
|
|
67
76
|
}
|
|
68
77
|
if (!currentFile)
|
|
@@ -77,7 +86,13 @@ export async function generateDataType(dataType, intent, currentFile) {
|
|
|
77
86
|
}
|
|
78
87
|
}
|
|
79
88
|
/**
|
|
89
|
+
* Generates the TypeScript type definition for a data type.
|
|
80
90
|
*
|
|
91
|
+
* @param currentFile - The current file being generated.
|
|
92
|
+
* @param dataType - The data type to generate code for.
|
|
93
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
94
|
+
* @param intent - The generation intent.
|
|
95
|
+
* @throws {@link TypeError} If name is required but not provided.
|
|
81
96
|
*/
|
|
82
97
|
export async function _generateTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
83
98
|
if (intent === 'root' && !dataType.name) {
|
|
@@ -110,7 +125,13 @@ export async function _generateTypeCode(currentFile, dataType, codeBlock, intent
|
|
|
110
125
|
throw new TypeError(`${dataType.kind} data types can not be directly exported`);
|
|
111
126
|
}
|
|
112
127
|
/**
|
|
128
|
+
* Generates code for an array type.
|
|
113
129
|
*
|
|
130
|
+
* @param currentFile - The current file being generated.
|
|
131
|
+
* @param dataType - The array data type.
|
|
132
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
133
|
+
* @param intent - The generation intent.
|
|
134
|
+
* @throws {@link TypeError} If array type is attempted to be extended.
|
|
114
135
|
*/
|
|
115
136
|
export async function _generateArrayTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
116
137
|
if (intent === 'extends')
|
|
@@ -129,7 +150,12 @@ export async function _generateArrayTypeCode(currentFile, dataType, codeBlock, i
|
|
|
129
150
|
intent === 'root' ? `type ${dataType.name} = ${out}[]` : `${out}[]`;
|
|
130
151
|
}
|
|
131
152
|
/**
|
|
153
|
+
* Generates code for a complex type.
|
|
132
154
|
*
|
|
155
|
+
* @param currentFile - The current file being generated.
|
|
156
|
+
* @param dataType - The complex data type.
|
|
157
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
158
|
+
* @param intent - The generation intent.
|
|
133
159
|
*/
|
|
134
160
|
export async function _generateComplexTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
135
161
|
let out = intent === 'root' ? `interface ${dataType.name} ` : '';
|
|
@@ -214,7 +240,12 @@ export async function _generateComplexTypeCode(currentFile, dataType, codeBlock,
|
|
|
214
240
|
codeBlock.typeDef = out + '\b}';
|
|
215
241
|
}
|
|
216
242
|
/**
|
|
243
|
+
* Generates code for an enum type.
|
|
217
244
|
*
|
|
245
|
+
* @param currentFile - The current file being generated.
|
|
246
|
+
* @param dataType - The enum data type.
|
|
247
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
248
|
+
* @param intent - The generation intent.
|
|
218
249
|
*/
|
|
219
250
|
export async function _generateEnumTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
220
251
|
if (intent === 'root') {
|
|
@@ -244,7 +275,12 @@ export async function _generateEnumTypeCode(currentFile, dataType, codeBlock, in
|
|
|
244
275
|
')';
|
|
245
276
|
}
|
|
246
277
|
/**
|
|
278
|
+
* Generates code for a mapped type.
|
|
247
279
|
*
|
|
280
|
+
* @param currentFile - The current file being generated.
|
|
281
|
+
* @param dataType - The mapped data type.
|
|
282
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
283
|
+
* @param intent - The generation intent.
|
|
248
284
|
*/
|
|
249
285
|
export async function _generateMappedTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
250
286
|
let out = intent === 'root' ? `type ${dataType.name} = ` : '';
|
|
@@ -304,7 +340,12 @@ export async function _generateMappedTypeCode(currentFile, dataType, codeBlock,
|
|
|
304
340
|
codeBlock.typeDef = out;
|
|
305
341
|
}
|
|
306
342
|
/**
|
|
343
|
+
* Generates code for a mixin type.
|
|
307
344
|
*
|
|
345
|
+
* @param currentFile - The current file being generated.
|
|
346
|
+
* @param dataType - The mixin data type.
|
|
347
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
348
|
+
* @param intent - The generation intent.
|
|
308
349
|
*/
|
|
309
350
|
export async function _generateMixinTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
310
351
|
const outArray = [];
|
|
@@ -328,7 +369,12 @@ export async function _generateMixinTypeCode(currentFile, dataType, codeBlock, i
|
|
|
328
369
|
codeBlock.typeDef = outArray.join(' & ');
|
|
329
370
|
}
|
|
330
371
|
/**
|
|
372
|
+
* Generates code for a simple type.
|
|
331
373
|
*
|
|
374
|
+
* @param currentFile - The current file being generated.
|
|
375
|
+
* @param dataType - The simple data type.
|
|
376
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
377
|
+
* @param intent - The generation intent.
|
|
332
378
|
*/
|
|
333
379
|
export async function _generateSimpleTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
334
380
|
if (intent !== 'typeDef' && dataType.properties) {
|
|
@@ -343,7 +389,13 @@ export async function _generateSimpleTypeCode(currentFile, dataType, codeBlock,
|
|
|
343
389
|
codeBlock.typeDef = intent === 'root' ? out + ';' : out;
|
|
344
390
|
}
|
|
345
391
|
/**
|
|
392
|
+
* Generates code for a union type.
|
|
346
393
|
*
|
|
394
|
+
* @param currentFile - The current file being generated.
|
|
395
|
+
* @param dataType - The union data type.
|
|
396
|
+
* @param codeBlock - The code block to add the generated code to.
|
|
397
|
+
* @param intent - The generation intent.
|
|
398
|
+
* @throws {@link TypeError} If union type is attempted to be extended.
|
|
347
399
|
*/
|
|
348
400
|
export async function _generateUnionTypeCode(currentFile, dataType, codeBlock, intent) {
|
|
349
401
|
if (intent === 'extends')
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { ApiDocument } from '@opra/common';
|
|
2
2
|
import type { TsGenerator } from '../ts-generator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates the document and its references.
|
|
5
|
+
*
|
|
6
|
+
* @param document - The document to generate.
|
|
7
|
+
* @param options - Generation options.
|
|
8
|
+
* @returns An object containing the generated document and its generator.
|
|
9
|
+
*/
|
|
3
10
|
export declare function generateDocument(this: TsGenerator, document?: string | ApiDocument, options?: {
|
|
4
11
|
typesOnly?: boolean;
|
|
5
12
|
}): Promise<{
|
|
@@ -3,6 +3,13 @@ import { OpraHttpClient } from '@opra/client';
|
|
|
3
3
|
import { BUILTIN, HttpApi } from '@opra/common';
|
|
4
4
|
import colors from 'ansi-colors';
|
|
5
5
|
import { pascalCase } from 'putil-varhelpers';
|
|
6
|
+
/**
|
|
7
|
+
* Generates the document and its references.
|
|
8
|
+
*
|
|
9
|
+
* @param document - The document to generate.
|
|
10
|
+
* @param options - Generation options.
|
|
11
|
+
* @returns An object containing the generated document and its generator.
|
|
12
|
+
*/
|
|
6
13
|
export async function generateDocument(document, options) {
|
|
7
14
|
if (!document || typeof document === 'string') {
|
|
8
15
|
if (document) {
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import { HttpApi } from '@opra/common';
|
|
2
2
|
import type { TsGenerator } from '../ts-generator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates TypeScript code for an HTTP API.
|
|
5
|
+
*
|
|
6
|
+
* @param api - The HTTP API to generate code for.
|
|
7
|
+
* @returns A promise that resolves to the generated TsFile.
|
|
8
|
+
*/
|
|
3
9
|
export declare function generateHttpApi(this: TsGenerator, api: HttpApi): Promise<import("../ts-file.js").TsFile>;
|
|
@@ -3,6 +3,12 @@ import { camelCase, pascalCase } from 'putil-varhelpers';
|
|
|
3
3
|
import { CodeBlock } from '../../code-block.js';
|
|
4
4
|
import { httpControllerNodeScript } from '../http-controller-node.js';
|
|
5
5
|
import { wrapJSDocString } from '../utils/string-utils.js';
|
|
6
|
+
/**
|
|
7
|
+
* Generates TypeScript code for an HTTP API.
|
|
8
|
+
*
|
|
9
|
+
* @param api - The HTTP API to generate code for.
|
|
10
|
+
* @returns A promise that resolves to the generated TsFile.
|
|
11
|
+
*/
|
|
6
12
|
export async function generateHttpApi(api) {
|
|
7
13
|
let file = this._filesMap.get(api);
|
|
8
14
|
if (file)
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import { HttpController } from '@opra/common';
|
|
2
2
|
import type { TsGenerator } from '../ts-generator.js';
|
|
3
|
+
/**
|
|
4
|
+
* Generates TypeScript code for an HTTP controller.
|
|
5
|
+
*
|
|
6
|
+
* @param controller - The HTTP controller to generate code for.
|
|
7
|
+
* @returns A promise that resolves to the generated TsFile.
|
|
8
|
+
*/
|
|
3
9
|
export declare function generateHttpController(this: TsGenerator, controller: HttpController): Promise<import("../ts-file.js").TsFile>;
|
|
@@ -5,21 +5,26 @@ import { camelCase, pascalCase } from 'putil-varhelpers';
|
|
|
5
5
|
import { CodeBlock } from '../../code-block.js';
|
|
6
6
|
import { locateNamedType } from '../utils/locate-named-type.js';
|
|
7
7
|
import { wrapJSDocString } from '../utils/string-utils.js';
|
|
8
|
+
/**
|
|
9
|
+
* Generates TypeScript code for an HTTP controller.
|
|
10
|
+
*
|
|
11
|
+
* @param controller - The HTTP controller to generate code for.
|
|
12
|
+
* @returns A promise that resolves to the generated TsFile.
|
|
13
|
+
*/
|
|
8
14
|
export async function generateHttpController(controller) {
|
|
9
15
|
let file = this._filesMap.get(controller);
|
|
10
16
|
if (file)
|
|
11
17
|
return file;
|
|
18
|
+
/**
|
|
19
|
+
* Generates parameter documentation for JSDoc.
|
|
20
|
+
*
|
|
21
|
+
* @param name - The name of the parameter.
|
|
22
|
+
* @param type - The data type of the parameter.
|
|
23
|
+
* @param options - Additional options for the parameter.
|
|
24
|
+
* @returns A promise that resolves to the documentation string.
|
|
25
|
+
*/
|
|
12
26
|
const generateParamDoc = async (name, type, options) => {
|
|
13
|
-
let
|
|
14
|
-
if (type) {
|
|
15
|
-
const xt = await this.generateDataType(type, 'typeDef', file);
|
|
16
|
-
typeDef = xt.kind === 'embedded' ? 'object' : xt.typeName;
|
|
17
|
-
}
|
|
18
|
-
else
|
|
19
|
-
typeDef = 'any';
|
|
20
|
-
if (options?.isArray)
|
|
21
|
-
typeDef += '[]';
|
|
22
|
-
let out = `\n * @param {${typeDef}} ` + (options?.required ? name : `[${name}]`);
|
|
27
|
+
let out = `\n * @param - ` + (options?.required ? name : `[${name}]`);
|
|
23
28
|
if (options?.description)
|
|
24
29
|
out += ` - ${wrapJSDocString(options?.description)}`;
|
|
25
30
|
if (type instanceof ComplexType && type.embedded) {
|
|
@@ -49,8 +54,7 @@ export async function generateHttpController(controller) {
|
|
|
49
54
|
classBlock.properties = '';
|
|
50
55
|
const classConstBlock = (classBlock.classConstBlock = new CodeBlock());
|
|
51
56
|
classConstBlock.head = `\n/**
|
|
52
|
-
* @param
|
|
53
|
-
* @constructor
|
|
57
|
+
* @param client - OpraHttpClient instance to operate
|
|
54
58
|
*/
|
|
55
59
|
constructor(client: OpraHttpClient) {`;
|
|
56
60
|
classConstBlock.body = `\n\tsuper(client);`;
|
|
@@ -69,7 +73,7 @@ constructor(client: OpraHttpClient) {`;
|
|
|
69
73
|
classConstBlock.body += `\nthis.${property} = new ${childClassName}(client);`;
|
|
70
74
|
}
|
|
71
75
|
}
|
|
72
|
-
|
|
76
|
+
/* Process operations */
|
|
73
77
|
const mergedControllerParams = [...controller.parameters];
|
|
74
78
|
let _base = controller;
|
|
75
79
|
while (_base.owner instanceof HttpController) {
|
|
@@ -107,7 +111,7 @@ constructor(client: OpraHttpClient) {`;
|
|
|
107
111
|
* @apiUrl ${path.posix.join(this.serviceUrl, operation.getFullUrl())}
|
|
108
112
|
*/\n`;
|
|
109
113
|
operationBlock.head = `${operation.name}(`;
|
|
110
|
-
|
|
114
|
+
/* Process operation parameters */
|
|
111
115
|
const pathParams = [];
|
|
112
116
|
const queryParams = [];
|
|
113
117
|
const headerParams = [];
|
|
@@ -129,7 +133,7 @@ constructor(client: OpraHttpClient) {`;
|
|
|
129
133
|
queryParams.push(...Object.values(queryParamsMap));
|
|
130
134
|
headerParams.push(...Object.values(headerParamsMap));
|
|
131
135
|
}
|
|
132
|
-
|
|
136
|
+
/* Process path parameters and add as function arguments */
|
|
133
137
|
let argIndex = 0;
|
|
134
138
|
for (const prm of pathParams) {
|
|
135
139
|
let typeDef;
|
|
@@ -145,11 +149,11 @@ constructor(client: OpraHttpClient) {`;
|
|
|
145
149
|
operationBlock.head += ', ';
|
|
146
150
|
operationBlock.head += `${prm.name}: ${typeDef}`;
|
|
147
151
|
operationBlock.doc.parameters +=
|
|
148
|
-
`\n * @param
|
|
152
|
+
`\n * @param ` +
|
|
149
153
|
(prm.required ? prm.name : `[${prm.name}]`) +
|
|
150
154
|
(prm.description ? ' - ' + wrapJSDocString(prm.description || '') : '');
|
|
151
155
|
}
|
|
152
|
-
|
|
156
|
+
/* Process requestBody and add as function argument ($body) */
|
|
153
157
|
let hasBody = false;
|
|
154
158
|
if (operation.requestBody?.content.length) {
|
|
155
159
|
if (argIndex++ > 0)
|
|
@@ -157,12 +161,11 @@ constructor(client: OpraHttpClient) {`;
|
|
|
157
161
|
let typeArr = [];
|
|
158
162
|
for (const content of operation.requestBody.content) {
|
|
159
163
|
if (content.type) {
|
|
160
|
-
|
|
164
|
+
/* Generate JSDoc for parameter */
|
|
161
165
|
operationBlock.doc.parameters += await generateParamDoc('$body', content.type, {
|
|
162
166
|
required: operation.requestBody.required,
|
|
163
167
|
description: content.description || content.type.description,
|
|
164
168
|
});
|
|
165
|
-
/** */
|
|
166
169
|
const xt = await this.generateDataType(content.type, 'typeDef', file);
|
|
167
170
|
let typeDef = xt.kind === 'embedded' ? xt.code : xt.typeName;
|
|
168
171
|
if (typeDef === 'any') {
|
|
@@ -171,11 +174,11 @@ constructor(client: OpraHttpClient) {`;
|
|
|
171
174
|
}
|
|
172
175
|
if (xt.kind === 'named') {
|
|
173
176
|
if (operation.requestBody.partial) {
|
|
174
|
-
file.addImport('ts-gems', ['PartialDTO']);
|
|
177
|
+
file.addImport('ts-gems', ['PartialDTO'], true);
|
|
175
178
|
typeDef = `PartialDTO<${typeDef}>`;
|
|
176
179
|
}
|
|
177
180
|
else {
|
|
178
|
-
file.addImport('ts-gems', ['DTO']);
|
|
181
|
+
file.addImport('ts-gems', ['DTO'], true);
|
|
179
182
|
typeDef = `DTO<${typeDef}>`;
|
|
180
183
|
}
|
|
181
184
|
}
|
|
@@ -201,7 +204,7 @@ constructor(client: OpraHttpClient) {`;
|
|
|
201
204
|
// operationBlock.doc.parameters += `\n * @param {${typeDef}} $body - Http body` + bodyFields;
|
|
202
205
|
hasBody = true;
|
|
203
206
|
}
|
|
204
|
-
|
|
207
|
+
/* process query params */
|
|
205
208
|
const isQueryRequired = queryParams.find(p => p.required);
|
|
206
209
|
const isHeadersRequired = queryParams.find(p => p.required);
|
|
207
210
|
if (queryParams.length) {
|
|
@@ -212,7 +215,7 @@ constructor(client: OpraHttpClient) {`;
|
|
|
212
215
|
(isHeadersRequired || isQueryRequired ? '' : '?') +
|
|
213
216
|
': {\n\t';
|
|
214
217
|
operationBlock.doc.parameters +=
|
|
215
|
-
'\n * @param
|
|
218
|
+
'\n * @param $params - Available parameters for the operation';
|
|
216
219
|
let hasAdditionalFields = false;
|
|
217
220
|
for (const prm of queryParams) {
|
|
218
221
|
if (typeof prm.name !== 'string') {
|
|
@@ -236,7 +239,7 @@ constructor(client: OpraHttpClient) {`;
|
|
|
236
239
|
}
|
|
237
240
|
operationBlock.head += '\b}\b';
|
|
238
241
|
}
|
|
239
|
-
|
|
242
|
+
/* process header params */
|
|
240
243
|
if (headerParams.length) {
|
|
241
244
|
// eslint-disable-next-line no-useless-assignment
|
|
242
245
|
if (argIndex++ > 0)
|
|
@@ -275,11 +278,11 @@ constructor(client: OpraHttpClient) {`;
|
|
|
275
278
|
if (isArray)
|
|
276
279
|
typeDef = typeDef.substring(0, typeDef.length - 2);
|
|
277
280
|
if (resp.partial) {
|
|
278
|
-
file.addImport('ts-gems', ['PartialDTO']);
|
|
281
|
+
file.addImport('ts-gems', ['PartialDTO'], true);
|
|
279
282
|
typeDef = `PartialDTO<${typeDef}>`;
|
|
280
283
|
}
|
|
281
284
|
else {
|
|
282
|
-
file.addImport('ts-gems', ['DTO']);
|
|
285
|
+
file.addImport('ts-gems', ['DTO'], true);
|
|
283
286
|
typeDef = `DTO<${typeDef}>`;
|
|
284
287
|
}
|
|
285
288
|
if (isArray)
|
|
@@ -292,7 +295,7 @@ constructor(client: OpraHttpClient) {`;
|
|
|
292
295
|
typeIs.is(String(resp.contentType), [MimeTypes.opra_response_json]) &&
|
|
293
296
|
!(resp.type instanceof ComplexType &&
|
|
294
297
|
resp.type.base?.ctor === OperationResult)) {
|
|
295
|
-
file.addImport('@opra/common', ['OperationResult']);
|
|
298
|
+
file.addImport('@opra/common', ['OperationResult'], true);
|
|
296
299
|
typeDef = typeDef ? `OperationResult<${typeDef}>` : 'OperationResult';
|
|
297
300
|
}
|
|
298
301
|
typeDef = typeDef || 'undefined';
|
|
@@ -1,21 +1,56 @@
|
|
|
1
1
|
import { CodeBlock } from '../code-block.js';
|
|
2
|
+
/**
|
|
3
|
+
* TsFile
|
|
4
|
+
*
|
|
5
|
+
* A class representing a TypeScript source file, managing its imports, exports, and content.
|
|
6
|
+
*/
|
|
2
7
|
export declare class TsFile {
|
|
3
8
|
readonly filename: string;
|
|
9
|
+
/** The directory name of the file. */
|
|
4
10
|
readonly dirname: string;
|
|
11
|
+
/** Map of imports where key is the module path. */
|
|
5
12
|
imports: Record<string, {
|
|
6
13
|
items: string[];
|
|
7
14
|
typeImport?: boolean;
|
|
8
15
|
}>;
|
|
16
|
+
/** Map of exports where key is the module path. */
|
|
9
17
|
exportFiles: Record<string, {
|
|
10
18
|
filename: string;
|
|
11
19
|
items: string[];
|
|
12
20
|
namespace?: string;
|
|
13
21
|
}>;
|
|
22
|
+
/** List of types to be exported. */
|
|
14
23
|
exportTypes: string[];
|
|
24
|
+
/** The code block representing the file's content. */
|
|
15
25
|
code: CodeBlock;
|
|
26
|
+
/**
|
|
27
|
+
* Initializes a new TsFile instance.
|
|
28
|
+
*
|
|
29
|
+
* @param filename - The name of the file.
|
|
30
|
+
*/
|
|
16
31
|
constructor(filename: string);
|
|
32
|
+
/**
|
|
33
|
+
* Adds an import statement to the file.
|
|
34
|
+
*
|
|
35
|
+
* @param filename - The module to import from.
|
|
36
|
+
* @param items - The specific items to import.
|
|
37
|
+
* @param typeImport - Whether it is a type-only import.
|
|
38
|
+
*/
|
|
17
39
|
addImport(filename: string, items?: string[], typeImport?: boolean): void;
|
|
40
|
+
/**
|
|
41
|
+
* Adds an export statement to the file.
|
|
42
|
+
*
|
|
43
|
+
* @param filename - The module to export from.
|
|
44
|
+
* @param types - The specific items to export.
|
|
45
|
+
* @param namespace - The namespace to export as.
|
|
46
|
+
*/
|
|
18
47
|
addExport(filename: string, types?: string[], namespace?: string): void;
|
|
48
|
+
/**
|
|
49
|
+
* Generates the file content as a string.
|
|
50
|
+
*
|
|
51
|
+
* @param options - Generation options.
|
|
52
|
+
* @returns The generated TypeScript code.
|
|
53
|
+
*/
|
|
19
54
|
generate(options?: {
|
|
20
55
|
importExt?: boolean;
|
|
21
56
|
}): string;
|
package/ts-generator/ts-file.js
CHANGED
|
@@ -1,13 +1,28 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import flattenText from 'putil-flattentext';
|
|
3
3
|
import { CodeBlock } from '../code-block.js';
|
|
4
|
+
/**
|
|
5
|
+
* TsFile
|
|
6
|
+
*
|
|
7
|
+
* A class representing a TypeScript source file, managing its imports, exports, and content.
|
|
8
|
+
*/
|
|
4
9
|
export class TsFile {
|
|
5
10
|
filename;
|
|
11
|
+
/** The directory name of the file. */
|
|
6
12
|
dirname;
|
|
13
|
+
/** Map of imports where key is the module path. */
|
|
7
14
|
imports = {};
|
|
15
|
+
/** Map of exports where key is the module path. */
|
|
8
16
|
exportFiles = {};
|
|
17
|
+
/** List of types to be exported. */
|
|
9
18
|
exportTypes = [];
|
|
19
|
+
/** The code block representing the file's content. */
|
|
10
20
|
code = new CodeBlock();
|
|
21
|
+
/**
|
|
22
|
+
* Initializes a new TsFile instance.
|
|
23
|
+
*
|
|
24
|
+
* @param filename - The name of the file.
|
|
25
|
+
*/
|
|
11
26
|
constructor(filename) {
|
|
12
27
|
this.filename = filename;
|
|
13
28
|
this.dirname = path.dirname(filename);
|
|
@@ -15,6 +30,13 @@ export class TsFile {
|
|
|
15
30
|
this.code.imports = '';
|
|
16
31
|
this.code.exports = '';
|
|
17
32
|
}
|
|
33
|
+
/**
|
|
34
|
+
* Adds an import statement to the file.
|
|
35
|
+
*
|
|
36
|
+
* @param filename - The module to import from.
|
|
37
|
+
* @param items - The specific items to import.
|
|
38
|
+
* @param typeImport - Whether it is a type-only import.
|
|
39
|
+
*/
|
|
18
40
|
addImport(filename, items, typeImport) {
|
|
19
41
|
if (isLocalFile(filename)) {
|
|
20
42
|
filename = path.relative(this.dirname, path.resolve(this.dirname, filename));
|
|
@@ -36,6 +58,13 @@ export class TsFile {
|
|
|
36
58
|
imp.items.push(x);
|
|
37
59
|
});
|
|
38
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* Adds an export statement to the file.
|
|
63
|
+
*
|
|
64
|
+
* @param filename - The module to export from.
|
|
65
|
+
* @param types - The specific items to export.
|
|
66
|
+
* @param namespace - The namespace to export as.
|
|
67
|
+
*/
|
|
39
68
|
addExport(filename, types, namespace) {
|
|
40
69
|
if (isLocalFile(filename)) {
|
|
41
70
|
filename = path.relative(this.dirname, path.resolve(this.dirname, filename));
|
|
@@ -57,6 +86,12 @@ export class TsFile {
|
|
|
57
86
|
this.exportFiles[filename].items.push(x);
|
|
58
87
|
});
|
|
59
88
|
}
|
|
89
|
+
/**
|
|
90
|
+
* Generates the file content as a string.
|
|
91
|
+
*
|
|
92
|
+
* @param options - Generation options.
|
|
93
|
+
* @returns The generated TypeScript code.
|
|
94
|
+
*/
|
|
60
95
|
generate(options) {
|
|
61
96
|
this.code.imports = Object.keys(this.imports)
|
|
62
97
|
.sort((a, b) => {
|
|
@@ -9,22 +9,37 @@ import { generateHttpApi } from './generators/generate-http-api.js';
|
|
|
9
9
|
import { generateHttpController } from './generators/generate-http-controller.js';
|
|
10
10
|
import { TsFile } from './ts-file.js';
|
|
11
11
|
/**
|
|
12
|
-
*
|
|
12
|
+
* TsGenerator
|
|
13
|
+
*
|
|
14
|
+
* A class responsible for generating TypeScript code from an OPRA API document.
|
|
13
15
|
*/
|
|
14
16
|
export declare namespace TsGenerator {
|
|
17
|
+
/**
|
|
18
|
+
* Configuration options for TsGenerator.
|
|
19
|
+
*/
|
|
15
20
|
interface Options {
|
|
21
|
+
/** The URL of the OPRA service. */
|
|
16
22
|
serviceUrl: string;
|
|
23
|
+
/** The output directory for the generated files. */
|
|
17
24
|
outDir: string;
|
|
25
|
+
/** The current working directory. Defaults to process.cwd(). */
|
|
18
26
|
cwd?: string;
|
|
27
|
+
/** Logger instance for outputting information. */
|
|
19
28
|
logger?: ILogger;
|
|
29
|
+
/** File writer instance. Defaults to FileWriter. */
|
|
20
30
|
writer?: IFileWriter;
|
|
31
|
+
/** Optional header to add to each generated file. */
|
|
21
32
|
fileHeader?: string;
|
|
33
|
+
/** Whether to add .js extension to imports. */
|
|
22
34
|
importExt?: boolean;
|
|
35
|
+
/** Whether to export references with namespaces. */
|
|
23
36
|
referenceNamespaces?: boolean;
|
|
24
37
|
}
|
|
25
38
|
}
|
|
26
39
|
/**
|
|
27
|
-
*
|
|
40
|
+
* TsGenerator
|
|
41
|
+
*
|
|
42
|
+
* Main class for managing the TypeScript code generation process.
|
|
28
43
|
*/
|
|
29
44
|
export declare class TsGenerator extends EventEmitter {
|
|
30
45
|
protected cleanDirectory: typeof cleanDirectory;
|
|
@@ -63,12 +78,32 @@ export declare class TsGenerator extends EventEmitter {
|
|
|
63
78
|
};
|
|
64
79
|
fileHeader: string;
|
|
65
80
|
/**
|
|
81
|
+
* Initializes a new TsGenerator instance.
|
|
66
82
|
*
|
|
67
|
-
* @
|
|
83
|
+
* @param init - Configuration options.
|
|
68
84
|
*/
|
|
69
85
|
constructor(init: TsGenerator.Options);
|
|
86
|
+
/**
|
|
87
|
+
* Starts the code generation process.
|
|
88
|
+
*
|
|
89
|
+
* @throws {@link Error} If generation fails.
|
|
90
|
+
*/
|
|
70
91
|
generate(): Promise<void>;
|
|
92
|
+
/**
|
|
93
|
+
* Retrieves a file from the internal cache by its path.
|
|
94
|
+
*
|
|
95
|
+
* @param filePath - The path of the file to retrieve.
|
|
96
|
+
* @returns The TsFile instance or undefined if not found.
|
|
97
|
+
*/
|
|
71
98
|
protected getFile(filePath: string): TsFile;
|
|
99
|
+
/**
|
|
100
|
+
* Adds a new file to the generator or returns an existing one.
|
|
101
|
+
*
|
|
102
|
+
* @param filePath - The path of the file to add.
|
|
103
|
+
* @param returnExists - Whether to return the file if it already exists instead of throwing.
|
|
104
|
+
* @returns The newly created or existing TsFile instance.
|
|
105
|
+
* @throws {@link Error} If the file already exists and returnExists is false.
|
|
106
|
+
*/
|
|
72
107
|
protected addFile(filePath: string, returnExists?: boolean): TsFile;
|
|
73
108
|
protected extend(): TsGenerator;
|
|
74
109
|
}
|
|
@@ -11,7 +11,9 @@ import { generateHttpApi } from './generators/generate-http-api.js';
|
|
|
11
11
|
import { generateHttpController } from './generators/generate-http-controller.js';
|
|
12
12
|
import { TsFile } from './ts-file.js';
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
14
|
+
* TsGenerator
|
|
15
|
+
*
|
|
16
|
+
* Main class for managing the TypeScript code generation process.
|
|
15
17
|
*/
|
|
16
18
|
export class TsGenerator extends EventEmitter {
|
|
17
19
|
_files = {};
|
|
@@ -26,8 +28,9 @@ export class TsGenerator extends EventEmitter {
|
|
|
26
28
|
options;
|
|
27
29
|
fileHeader;
|
|
28
30
|
/**
|
|
31
|
+
* Initializes a new TsGenerator instance.
|
|
29
32
|
*
|
|
30
|
-
* @
|
|
33
|
+
* @param init - Configuration options.
|
|
31
34
|
*/
|
|
32
35
|
constructor(init) {
|
|
33
36
|
super();
|
|
@@ -49,6 +52,11 @@ export class TsGenerator extends EventEmitter {
|
|
|
49
52
|
this.on('warn', (message, ...args) => init.logger?.warn?.(message, ...args));
|
|
50
53
|
this.on('verbose', (message, ...args) => init.logger?.verbose?.(message, ...args));
|
|
51
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Starts the code generation process.
|
|
57
|
+
*
|
|
58
|
+
* @throws {@link Error} If generation fails.
|
|
59
|
+
*/
|
|
52
60
|
async generate() {
|
|
53
61
|
if (this._started)
|
|
54
62
|
return;
|
|
@@ -77,9 +85,23 @@ export class TsGenerator extends EventEmitter {
|
|
|
77
85
|
this.emit('finish');
|
|
78
86
|
}
|
|
79
87
|
}
|
|
88
|
+
/**
|
|
89
|
+
* Retrieves a file from the internal cache by its path.
|
|
90
|
+
*
|
|
91
|
+
* @param filePath - The path of the file to retrieve.
|
|
92
|
+
* @returns The TsFile instance or undefined if not found.
|
|
93
|
+
*/
|
|
80
94
|
getFile(filePath) {
|
|
81
95
|
return this._files[filePath];
|
|
82
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Adds a new file to the generator or returns an existing one.
|
|
99
|
+
*
|
|
100
|
+
* @param filePath - The path of the file to add.
|
|
101
|
+
* @param returnExists - Whether to return the file if it already exists instead of throwing.
|
|
102
|
+
* @returns The newly created or existing TsFile instance.
|
|
103
|
+
* @throws {@link Error} If the file already exists and returnExists is false.
|
|
104
|
+
*/
|
|
83
105
|
addFile(filePath, returnExists) {
|
|
84
106
|
if (!(filePath.startsWith('.') || filePath.startsWith('/')))
|
|
85
107
|
filePath = './' + filePath;
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
import { DataType } from '@opra/common';
|
|
2
|
+
/**
|
|
3
|
+
* Locates the first named type in the inheritance chain of a data type.
|
|
4
|
+
*
|
|
5
|
+
* @param type - The data type to start from.
|
|
6
|
+
* @returns The found named DataType instance, or undefined if not found.
|
|
7
|
+
*/
|
|
2
8
|
export declare function locateNamedType(type?: DataType): DataType | undefined;
|
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { ComplexType, EnumType, MappedType, SimpleType, } from '@opra/common';
|
|
2
|
+
/**
|
|
3
|
+
* Locates the first named type in the inheritance chain of a data type.
|
|
4
|
+
*
|
|
5
|
+
* @param type - The data type to start from.
|
|
6
|
+
* @returns The found named DataType instance, or undefined if not found.
|
|
7
|
+
*/
|
|
2
8
|
export function locateNamedType(type) {
|
|
3
9
|
if (!type)
|
|
4
10
|
return;
|
|
@@ -1,4 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wraps a string for use in JSDoc comments.
|
|
3
|
+
*
|
|
4
|
+
* @param s - The string to wrap.
|
|
5
|
+
* @param indent - The number of spaces for indentation.
|
|
6
|
+
* @param currentColumn - The current column position.
|
|
7
|
+
* @returns The wrapped JSDoc string.
|
|
8
|
+
*/
|
|
1
9
|
export declare function wrapJSDocString(s: string, indent?: number, currentColumn?: number): string;
|
|
10
|
+
/**
|
|
11
|
+
* Wraps a string as a quoted string, potentially splitting it across multiple lines.
|
|
12
|
+
*
|
|
13
|
+
* @param s - The string to wrap.
|
|
14
|
+
* @param indent - The number of spaces for indentation.
|
|
15
|
+
* @param currentColumn - The current column position.
|
|
16
|
+
* @returns The wrapped quoted string.
|
|
17
|
+
*/
|
|
2
18
|
export declare function wrapQuotedString(s: string, indent?: number, currentColumn?: number): string;
|
|
19
|
+
/**
|
|
20
|
+
* Wraps an array of strings as a TypeScript array representation.
|
|
21
|
+
*
|
|
22
|
+
* @param arr - The array of strings.
|
|
23
|
+
* @param indent - The number of spaces for indentation.
|
|
24
|
+
* @param currentColumn - The current column position.
|
|
25
|
+
* @returns The string representation of the array.
|
|
26
|
+
*/
|
|
3
27
|
export declare function wrapStringArray(arr: string[], indent?: number, currentColumn?: number): string;
|
|
28
|
+
/**
|
|
29
|
+
* Wraps an array of types as a TypeScript union type representation.
|
|
30
|
+
*
|
|
31
|
+
* @param arr - The array of type names.
|
|
32
|
+
* @param indent - The number of spaces for indentation.
|
|
33
|
+
* @param currentColumn - The current column position.
|
|
34
|
+
* @returns The string representation of the union type.
|
|
35
|
+
*/
|
|
4
36
|
export declare function wrapTypeArray(arr: string[], indent?: number, currentColumn?: number): string;
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import jsStringEscape from 'js-string-escape';
|
|
2
|
+
/**
|
|
3
|
+
* Wraps a string for use in JSDoc comments.
|
|
4
|
+
*
|
|
5
|
+
* @param s - The string to wrap.
|
|
6
|
+
* @param indent - The number of spaces for indentation.
|
|
7
|
+
* @param currentColumn - The current column position.
|
|
8
|
+
* @returns The wrapped JSDoc string.
|
|
9
|
+
*/
|
|
2
10
|
export function wrapJSDocString(s, indent, currentColumn) {
|
|
3
11
|
const arr = (s || '')
|
|
4
12
|
.split(/[ \n\r]/)
|
|
@@ -10,6 +18,14 @@ export function wrapJSDocString(s, indent, currentColumn) {
|
|
|
10
18
|
lineEnd: '',
|
|
11
19
|
});
|
|
12
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Wraps a string as a quoted string, potentially splitting it across multiple lines.
|
|
23
|
+
*
|
|
24
|
+
* @param s - The string to wrap.
|
|
25
|
+
* @param indent - The number of spaces for indentation.
|
|
26
|
+
* @param currentColumn - The current column position.
|
|
27
|
+
* @returns The wrapped quoted string.
|
|
28
|
+
*/
|
|
13
29
|
export function wrapQuotedString(s, indent, currentColumn) {
|
|
14
30
|
const arr = jsStringEscape(s || '')
|
|
15
31
|
.split(' ')
|
|
@@ -23,10 +39,26 @@ export function wrapQuotedString(s, indent, currentColumn) {
|
|
|
23
39
|
}) +
|
|
24
40
|
"'");
|
|
25
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Wraps an array of strings as a TypeScript array representation.
|
|
44
|
+
*
|
|
45
|
+
* @param arr - The array of strings.
|
|
46
|
+
* @param indent - The number of spaces for indentation.
|
|
47
|
+
* @param currentColumn - The current column position.
|
|
48
|
+
* @returns The string representation of the array.
|
|
49
|
+
*/
|
|
26
50
|
export function wrapStringArray(arr, indent, currentColumn) {
|
|
27
51
|
const ar1 = arr.map((x, i, a) => "'" + x + "'" + (i < a.length - 1 ? ', ' : ''));
|
|
28
52
|
return '[' + _printLines(ar1, { indent, currentColumn }) + ']';
|
|
29
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* Wraps an array of types as a TypeScript union type representation.
|
|
56
|
+
*
|
|
57
|
+
* @param arr - The array of type names.
|
|
58
|
+
* @param indent - The number of spaces for indentation.
|
|
59
|
+
* @param currentColumn - The current column position.
|
|
60
|
+
* @returns The string representation of the union type.
|
|
61
|
+
*/
|
|
30
62
|
export function wrapTypeArray(arr, indent, currentColumn) {
|
|
31
63
|
const ar1 = arr.map((x, i, a) => x + (i < a.length - 1 ? ' | ' : ''));
|
|
32
64
|
return _printLines(ar1, { indent, currentColumn });
|