@opra/cli 1.0.0-alpha.8 → 1.0.0-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/cjs/file-writer.js +2 -2
  2. package/cjs/oprimp-cli.js +11 -9
  3. package/cjs/ts-generator/{processors → generators}/clean-directory.js +4 -5
  4. package/cjs/ts-generator/generators/generate-data-type.js +258 -0
  5. package/cjs/ts-generator/generators/generate-document.js +64 -0
  6. package/cjs/ts-generator/{processors/process-http-api.js → generators/generate-http-api.js} +3 -4
  7. package/cjs/ts-generator/generators/generate-http-controller.js +296 -0
  8. package/cjs/ts-generator/ts-file.js +18 -12
  9. package/cjs/ts-generator/ts-generator.js +20 -20
  10. package/cjs/ts-generator/utils/locate-named-type.js +1 -2
  11. package/cjs/ts-generator/utils/string-utils.js +4 -5
  12. package/esm/file-writer.js +1 -1
  13. package/esm/oprimp-cli.js +9 -7
  14. package/esm/package.json +3 -0
  15. package/esm/ts-generator/{processors → generators}/clean-directory.js +3 -3
  16. package/esm/ts-generator/generators/generate-data-type.js +248 -0
  17. package/esm/ts-generator/{processors/process-document.js → generators/generate-document.js} +17 -12
  18. package/esm/ts-generator/{processors/process-http-api.js → generators/generate-http-api.js} +2 -2
  19. package/esm/ts-generator/generators/generate-http-controller.js +292 -0
  20. package/esm/ts-generator/ts-file.js +15 -9
  21. package/esm/ts-generator/ts-generator.js +20 -20
  22. package/package.json +28 -33
  23. package/types/file-writer.d.ts +1 -1
  24. package/types/index.d.cts +1 -0
  25. package/types/interfaces/service-generation-context.interface.d.ts +2 -2
  26. package/types/ts-generator/generators/generate-data-type.d.ts +41 -0
  27. package/types/ts-generator/{processors/process-document.d.ts → generators/generate-document.d.ts} +1 -1
  28. package/types/ts-generator/generators/generate-http-api.d.ts +3 -0
  29. package/types/ts-generator/generators/generate-http-controller.d.ts +3 -0
  30. package/types/ts-generator/ts-file.d.ts +6 -2
  31. package/types/ts-generator/ts-generator.d.ts +22 -20
  32. package/bin/bin/oprimp.mjs +0 -3
  33. package/cjs/ts-generator/processors/process-data-types.js +0 -262
  34. package/cjs/ts-generator/processors/process-document.js +0 -60
  35. package/cjs/ts-generator/processors/process-http-controller.js +0 -189
  36. package/esm/ts-generator/processors/process-data-types.js +0 -251
  37. package/esm/ts-generator/processors/process-http-controller.js +0 -184
  38. package/types/ts-generator/processors/process-data-types.d.ts +0 -30
  39. package/types/ts-generator/processors/process-http-api.d.ts +0 -3
  40. package/types/ts-generator/processors/process-http-controller.d.ts +0 -3
  41. /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
- this.exportFiles[filename] = this.exportFiles[filename] || [];
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(filename => {
76
- const types = this.exportFiles[filename];
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
- return `export ${types.length ? '{ ' + types.join(', ') + ' }' : '*'} from '${filename}';`;
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 chalk from 'chalk';
5
+ import colors from 'ansi-colors';
6
6
  import { FileWriter } from '../file-writer.js';
7
- import { cleanDirectory } from './processors/clean-directory.js';
8
- import { generateComplexTypeDefinition, generateEnumTypeDefinition, generateMappedTypeDefinition, generateMixinTypeDefinition, generateSimpleTypeDefinition, processDataType, resolveTypeNameOrDef, } from './processors/process-data-types.js';
9
- import { processDocument } from './processors/process-document.js';
10
- import { processHttpApi } from './processors/process-http-api.js';
11
- import { processHttpController } from './processors/process-http-controller.js';
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', chalk.cyan('Removing old files..'));
45
+ this.emit('log', colors.cyan('Removing old files..'));
46
46
  this.cleanDirectory(this.outDir);
47
47
  this._apiPath = '/api';
48
- await this.processDocument();
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.processDocument = processDocument;
94
- TsGenerator.prototype.processDataType = processDataType;
95
- TsGenerator.prototype.processHttpApi = processHttpApi;
96
- TsGenerator.prototype.processHttpController = processHttpController;
97
- TsGenerator.prototype.generateEnumTypeDefinition = generateEnumTypeDefinition;
98
- TsGenerator.prototype.generateComplexTypeDefinition = generateComplexTypeDefinition;
99
- TsGenerator.prototype.generateSimpleTypeDefinition = generateSimpleTypeDefinition;
100
- TsGenerator.prototype.generateMappedTypeDefinition = generateMappedTypeDefinition;
101
- TsGenerator.prototype.generateMixinTypeDefinition = generateMixinTypeDefinition;
102
- TsGenerator.prototype.resolveTypeNameOrDef = resolveTypeNameOrDef;
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-alpha.8",
3
+ "version": "1.0.0-beta.1",
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
- "@opra/client": "^1.0.0-alpha.8",
35
- "@opra/common": "^1.0.0-alpha.8",
36
- "chalk": "^5.3.0",
8
+ "@browsery/type-is": "^1.6.18-r5",
9
+ "@opra/client": "^1.0.0-beta.1",
10
+ "@opra/common": "^1.0.0-beta.1",
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
- "module": "./esm/index.js",
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
+ }
@@ -1,4 +1,4 @@
1
- import { IFileWriter } from './interfaces/file-writer.interface.js';
1
+ import type { IFileWriter } from './interfaces/file-writer.interface.js';
2
2
  export declare class FileWriter implements IFileWriter {
3
3
  writeFile(filename: string, contents: string): void;
4
4
  }
@@ -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 {};
@@ -1,6 +1,6 @@
1
1
  import { ApiDocument } from '@opra/common';
2
2
  import type { TsGenerator } from '../ts-generator';
3
- export declare function processDocument(this: TsGenerator, document?: string | ApiDocument, options?: {
3
+ export declare function generateDocument(this: TsGenerator, document?: string | ApiDocument, options?: {
4
4
  typesOnly?: boolean;
5
5
  }): Promise<{
6
6
  document: ApiDocument;
@@ -0,0 +1,3 @@
1
+ import { HttpApi } from '@opra/common';
2
+ import type { TsGenerator } from '../ts-generator';
3
+ export declare function generateHttpApi(this: TsGenerator, api: HttpApi): Promise<import("../ts-file.js").TsFile>;
@@ -0,0 +1,3 @@
1
+ import { HttpController } from '@opra/common';
2
+ import type { TsGenerator } from '../ts-generator';
3
+ export declare function generateHttpController(this: TsGenerator, controller: HttpController): Promise<import("../ts-file.js").TsFile>;
@@ -6,12 +6,16 @@ export declare class TsFile {
6
6
  items: string[];
7
7
  typeImport?: boolean;
8
8
  }>;
9
- exportFiles: Record<string, 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 './processors/clean-directory.js';
7
- import { generateComplexTypeDefinition, generateEnumTypeDefinition, generateMappedTypeDefinition, generateMixinTypeDefinition, generateSimpleTypeDefinition, processDataType, resolveTypeNameOrDef } from './processors/process-data-types.js';
8
- import { processDocument } from './processors/process-document.js';
9
- import { processHttpApi } from './processors/process-http-api.js';
10
- import { processHttpController } from './processors/process-http-controller.js';
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 processDocument: typeof processDocument;
32
- protected processDataType: typeof processDataType;
33
- protected processHttpApi: typeof processHttpApi;
34
- protected processHttpController: typeof processHttpController;
35
- protected generateEnumTypeDefinition: typeof generateEnumTypeDefinition;
36
- protected generateComplexTypeDefinition: typeof generateComplexTypeDefinition;
37
- protected generateSimpleTypeDefinition: typeof generateSimpleTypeDefinition;
38
- protected generateMappedTypeDefinition: typeof generateMappedTypeDefinition;
39
- protected generateMixinTypeDefinition: typeof generateMixinTypeDefinition;
40
- protected resolveTypeNameOrDef: typeof resolveTypeNameOrDef;
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
  /**
@@ -1,3 +0,0 @@
1
- #!/usr/bin/env node
2
- /* eslint-disable import-x/no-unresolved */
3
- import '../esm/oprimp-cli.js';
@@ -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;