@buildvision/nest-sdk-generator 2.3.0 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.js +1 -1
- package/.github/workflows/test.yml +35 -0
- package/README.md +402 -239
- package/build/analyzer/classdeps.js +36 -4
- package/build/analyzer/controller.d.ts +2 -14
- package/build/analyzer/controller.js +38 -18
- package/build/analyzer/controllers.d.ts +2 -2
- package/build/analyzer/controllers.js +37 -5
- package/build/analyzer/extractor.d.ts +2 -41
- package/build/analyzer/extractor.js +63 -66
- package/build/analyzer/index.d.ts +2 -6
- package/build/analyzer/index.js +107 -86
- package/build/analyzer/methods.d.ts +2 -30
- package/build/analyzer/methods.js +7 -16
- package/build/analyzer/module.js +36 -4
- package/build/analyzer/params.d.ts +3 -39
- package/build/analyzer/params.js +17 -37
- package/build/analyzer/route.js +8 -9
- package/build/analyzer/sdk.d.ts +146 -0
- package/build/analyzer/sdk.js +120 -0
- package/build/analyzer/typedeps.d.ts +15 -0
- package/build/analyzer/typedeps.js +62 -10
- package/build/bin.js +72 -25
- package/build/config.d.ts +13 -0
- package/build/config.js +36 -3
- package/build/engine/analyze.d.ts +16 -0
- package/build/engine/analyze.js +786 -0
- package/build/engine/ast.d.ts +24 -0
- package/build/engine/ast.js +100 -0
- package/build/engine/file-order.d.ts +17 -0
- package/build/engine/file-order.js +97 -0
- package/build/engine/host.d.ts +63 -0
- package/build/engine/host.js +16 -0
- package/build/engine/index.d.ts +15 -0
- package/build/engine/index.js +93 -0
- package/build/engine/ts-morph-compat-host.d.ts +8 -0
- package/build/engine/ts-morph-compat-host.js +18 -0
- package/build/engine/tsgo-host.d.ts +9 -0
- package/build/engine/tsgo-host.js +136 -0
- package/build/engine/typescript-host.d.ts +26 -0
- package/build/engine/typescript-host.js +142 -0
- package/build/generator/genmodules.d.ts +1 -4
- package/build/generator/genmodules.js +23 -27
- package/build/generator/gentypes.d.ts +1 -1
- package/build/generator/gentypes.js +36 -4
- package/build/generator/index.d.ts +1 -1
- package/build/generator/index.js +91 -69
- package/build/generator/prettier.js +43 -9
- package/build/generator/sdk-interface.d.ts +1 -1
- package/build/generator/sdk-interface.js +5 -5
- package/build/logging.d.ts +3 -0
- package/build/logging.js +17 -10
- package/build/rtk-query-generator/genmodules.d.ts +1 -4
- package/build/rtk-query-generator/genmodules.js +31 -33
- package/build/rtk-query-generator/index.d.ts +1 -1
- package/build/rtk-query-generator/index.js +87 -72
- package/build/rtk-query-generator/prettier.js +43 -9
- package/build/rtk-query-generator/sdk-interface.js +3 -4
- package/build/utils.js +38 -6
- package/package.json +29 -11
- package/src/analyzer/controller.ts +3 -31
- package/src/analyzer/controllers.ts +3 -2
- package/src/analyzer/extractor.ts +17 -86
- package/src/analyzer/index.ts +5 -11
- package/src/analyzer/methods.ts +5 -36
- package/src/analyzer/params.ts +13 -55
- package/src/analyzer/sdk.ts +247 -0
- package/src/analyzer/typedeps.ts +22 -4
- package/src/bin.ts +31 -6
- package/src/config.ts +15 -0
- package/src/engine/analyze.ts +1110 -0
- package/src/engine/ast.ts +105 -0
- package/src/engine/file-order.ts +104 -0
- package/src/engine/host.ts +79 -0
- package/src/engine/index.ts +79 -0
- package/src/engine/ts-morph-compat-host.ts +20 -0
- package/src/engine/tsgo-host.ts +119 -0
- package/src/engine/typescript-host.ts +159 -0
- package/src/generator/genmodules.ts +9 -4
- package/src/generator/gentypes.ts +1 -1
- package/src/generator/index.ts +1 -1
- package/src/logging.ts +10 -1
- package/src/rtk-query-generator/genmodules.ts +17 -9
- package/src/rtk-query-generator/index.ts +2 -12
- package/src/rtk-query-generator/sdk-interface.ts +2 -3
- package/tsconfig.json +7 -6
- package/build/analyzer/decorator.d.ts +0 -10
- package/build/analyzer/decorator.js +0 -29
- package/build/rtk-query-generator/gentypes.d.ts +0 -10
- package/build/rtk-query-generator/gentypes.js +0 -62
- package/build/tsconfig.tsbuildinfo +0 -1
- package/bun.lockb +0 -0
- package/src/rtk-query-generator/gentypes.ts +0 -74
- package/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,786 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file Source API analyzer running on top of an `AnalysisHost` (tsgo or in-process TypeScript)
|
|
4
|
+
*
|
|
5
|
+
* This is a port of the legacy ts-morph analyzer (`src/analyzer`). It performs the same operations, in the same
|
|
6
|
+
* order, with the same messages, so that given the same type checker it produces the same SDK content.
|
|
7
|
+
* The parity tests enforce this by running it against the TypeScript program ts-morph builds.
|
|
8
|
+
*/
|
|
9
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
12
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
13
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
14
|
+
}
|
|
15
|
+
Object.defineProperty(o, k2, desc);
|
|
16
|
+
}) : (function(o, m, k, k2) {
|
|
17
|
+
if (k2 === undefined) k2 = k;
|
|
18
|
+
o[k2] = m[k];
|
|
19
|
+
}));
|
|
20
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
21
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
22
|
+
}) : function(o, v) {
|
|
23
|
+
o["default"] = v;
|
|
24
|
+
});
|
|
25
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
26
|
+
var ownKeys = function(o) {
|
|
27
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
28
|
+
var ar = [];
|
|
29
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
30
|
+
return ar;
|
|
31
|
+
};
|
|
32
|
+
return ownKeys(o);
|
|
33
|
+
};
|
|
34
|
+
return function (mod) {
|
|
35
|
+
if (mod && mod.__esModule) return mod;
|
|
36
|
+
var result = {};
|
|
37
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
38
|
+
__setModuleDefault(result, mod);
|
|
39
|
+
return result;
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
42
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
43
|
+
exports.analyzeWithHost = analyzeWithHost;
|
|
44
|
+
const fs = __importStar(require("fs"));
|
|
45
|
+
const os = __importStar(require("os"));
|
|
46
|
+
const path = __importStar(require("path"));
|
|
47
|
+
const chalk = require("chalk");
|
|
48
|
+
const builtin_1 = require("../analyzer/builtin");
|
|
49
|
+
const route_1 = require("../analyzer/route");
|
|
50
|
+
const sdk_1 = require("../analyzer/sdk");
|
|
51
|
+
const typedeps_1 = require("../analyzer/typedeps");
|
|
52
|
+
const logging_1 = require("../logging");
|
|
53
|
+
const utils_1 = require("../utils");
|
|
54
|
+
const ast_1 = require("./ast");
|
|
55
|
+
/**
|
|
56
|
+
* Analyze the source API
|
|
57
|
+
* @param config Generator configuration
|
|
58
|
+
* @param createHost Creates the engine for a given tsconfig file
|
|
59
|
+
*/
|
|
60
|
+
async function analyzeWithHost(config, createHost) {
|
|
61
|
+
const started = Date.now();
|
|
62
|
+
const sourcePath = path.resolve(process.cwd(), config.apiInputPath);
|
|
63
|
+
if (!sourcePath)
|
|
64
|
+
(0, logging_1.panic)('Please provide a source directory');
|
|
65
|
+
if (!fs.existsSync(sourcePath))
|
|
66
|
+
(0, logging_1.panic)('Provided source path {magentaBright} does not exist', sourcePath);
|
|
67
|
+
if (!fs.lstatSync(sourcePath).isDirectory())
|
|
68
|
+
(0, logging_1.panic)('Provided source path is not a directory');
|
|
69
|
+
(0, logging_1.debug)(`Analyzing from source directory {yellow}`, sourcePath);
|
|
70
|
+
if (config.jsonOutput) {
|
|
71
|
+
const jsonOutputParentDir = path.dirname(path.resolve(process.cwd(), config.jsonOutput));
|
|
72
|
+
if (!fs.existsSync(jsonOutputParentDir)) {
|
|
73
|
+
(0, logging_1.panic)("Output file's parent directory {magentaBright} does not exist.", jsonOutputParentDir);
|
|
74
|
+
}
|
|
75
|
+
(0, logging_1.debug)('Writing output to {yellow}', config.jsonOutput, config.jsonPrettyOutput ? 'beautified' : 'minified');
|
|
76
|
+
}
|
|
77
|
+
// ====== Find & parse 'tsconfig.json' ====== //
|
|
78
|
+
if (config.tsconfigFile && config.tsconfigFile.includes('/')) {
|
|
79
|
+
(0, logging_1.panic)('Provided tsconfig file name contains slashes');
|
|
80
|
+
}
|
|
81
|
+
const tsConfigFileName = config.tsconfigFile ?? 'tsconfig.json';
|
|
82
|
+
const tsConfigFilePath = path.join(sourcePath, tsConfigFileName);
|
|
83
|
+
if (!fs.existsSync(tsConfigFilePath)) {
|
|
84
|
+
(0, logging_1.panic)('No {yellow} file found in provided source path {yellow}', tsConfigFileName, sourcePath);
|
|
85
|
+
}
|
|
86
|
+
const host = createHost(tsConfigFilePath);
|
|
87
|
+
try {
|
|
88
|
+
// Get the list of all TypeScript files in the source directory
|
|
89
|
+
const sourceTSFiles = host.getProjectFilePaths().map((file) => path.relative(sourcePath, file));
|
|
90
|
+
(0, logging_1.debug)(`Found {magentaBright} source files.`, sourceTSFiles.length);
|
|
91
|
+
// Add them
|
|
92
|
+
(0, logging_1.debug)('\nAdding them to the source project...');
|
|
93
|
+
let progressByTenth = 0;
|
|
94
|
+
const strLen = sourceTSFiles.length.toString().length;
|
|
95
|
+
const hasProgress = (filesTreated) => filesTreated / sourceTSFiles.length >= (progressByTenth + 1) / 10;
|
|
96
|
+
const controllers = [];
|
|
97
|
+
for (let i = 0; i < sourceTSFiles.length; i++) {
|
|
98
|
+
const file = sourceTSFiles[i];
|
|
99
|
+
if (file.endsWith('.controller.ts')) {
|
|
100
|
+
controllers.push(file);
|
|
101
|
+
}
|
|
102
|
+
if (hasProgress(i + 1)) {
|
|
103
|
+
while (hasProgress(i + 1))
|
|
104
|
+
progressByTenth++;
|
|
105
|
+
(0, logging_1.debug)('| Progress: {yellow} ({magentaBright} files) - {green} controller{} found', (progressByTenth * 10).toString().padStart(3, ' ') + '%', `${(i + 1).toString().padStart(strLen, ' ')} / ${sourceTSFiles.length}`, controllers.length.toString().padStart(strLen, ''), controllers.length > 1 ? 's' : '');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
(0, logging_1.debug)('All files were added successfully.\n');
|
|
109
|
+
const modules = analyzeControllers(host, controllers, sourcePath);
|
|
110
|
+
// Builtin magic types are concatenated **after** the configuration's ones, as this allows users to
|
|
111
|
+
// override the builtin ones if they want. Do **not** change the concatenation order!
|
|
112
|
+
const magicTypes = (config.magicTypes ?? []).concat(builtin_1.builtinMagicTypes);
|
|
113
|
+
const typesCache = new TypesExtractor(host, sourcePath, magicTypes);
|
|
114
|
+
const typesToExtract = (0, sdk_1.locateTypesFile)((0, sdk_1.flattenSdkResolvedTypes)(modules));
|
|
115
|
+
(0, logging_1.debug)('\n==== Extracting {} type' + (typesToExtract.length > 1 ? 's' : '') + ' ====\n', typesToExtract.length);
|
|
116
|
+
for (const loc of typesToExtract) {
|
|
117
|
+
const result = typesCache.extractType(loc);
|
|
118
|
+
if (result instanceof Error) {
|
|
119
|
+
(0, logging_1.panic)(result.message);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
const content = {
|
|
123
|
+
modules,
|
|
124
|
+
types: typesCache.extracted,
|
|
125
|
+
};
|
|
126
|
+
if (config.jsonOutput) {
|
|
127
|
+
fs.writeFileSync(config.jsonOutput, (0, sdk_1.serializeSdkContent)(content, !!config.jsonPrettyOutput), 'utf8');
|
|
128
|
+
}
|
|
129
|
+
(0, logging_1.debug)('\n===== Done in {green}! ====', ((Date.now() - started) / 1000).toFixed(2) + 's');
|
|
130
|
+
return content;
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
host.dispose();
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Get a source file from the program, throwing like ts-morph's `project.getSourceFileOrThrow()`
|
|
138
|
+
*/
|
|
139
|
+
function getSourceFileOrThrow(host, absolutePath) {
|
|
140
|
+
const file = host.getSourceFile(absolutePath);
|
|
141
|
+
if (!file) {
|
|
142
|
+
throw new Error(`Could not find source file in project at the provided path: ${absolutePath}`);
|
|
143
|
+
}
|
|
144
|
+
return file;
|
|
145
|
+
}
|
|
146
|
+
// =============================================================================================================== //
|
|
147
|
+
// Controllers & modules (see src/analyzer/controllers.ts, src/analyzer/controller.ts, src/analyzer/module.ts) //
|
|
148
|
+
// =============================================================================================================== //
|
|
149
|
+
function analyzeControllers(host, controllers, absoluteSrcPath) {
|
|
150
|
+
/** Hierarchised SDK informations */
|
|
151
|
+
const collected = new Map();
|
|
152
|
+
const usedControllerNames = new Set();
|
|
153
|
+
/**
|
|
154
|
+
* Modules cache: contains for a given directory the nearest module file's path and name
|
|
155
|
+
* This allows to avoid having to analyze the whole directory structure for each controller
|
|
156
|
+
*/
|
|
157
|
+
const modulesCache = new Map();
|
|
158
|
+
/**
|
|
159
|
+
* Path of the declared modules
|
|
160
|
+
* When a module is detected and put in the cache, its name is registered here along with its path
|
|
161
|
+
* This allows to ensure there is no name clash between two different modules
|
|
162
|
+
*/
|
|
163
|
+
const declaredModulesPath = new Map();
|
|
164
|
+
(0, logging_1.debug)(`Analyzing {yellow} controllers...`, controllers.length);
|
|
165
|
+
controllers.forEach((relativeControllerPath, i) => {
|
|
166
|
+
const absoluteControllerPath = path.resolve(absoluteSrcPath, relativeControllerPath);
|
|
167
|
+
(0, logging_1.debug)('\n{cyan} {yellow}: {magentaBright} {cyan}\n', '===== Analyzing controller', `${i + 1}/${controllers.length}`, relativeControllerPath, '=====');
|
|
168
|
+
const basePath = path.dirname(absoluteControllerPath);
|
|
169
|
+
let moduleName = modulesCache.get(basePath);
|
|
170
|
+
// Check if the module's name is in cache
|
|
171
|
+
if (!moduleName) {
|
|
172
|
+
// Else, find the nearest module file
|
|
173
|
+
const absoluteModulePath = (0, utils_1.findFileAbove)(/^.*\.module\.ts$/, path.resolve(absoluteSrcPath, basePath));
|
|
174
|
+
if (absoluteModulePath === null) {
|
|
175
|
+
(0, logging_1.panic)('No module file was found for controller at path: {yellow}', absoluteControllerPath);
|
|
176
|
+
}
|
|
177
|
+
const relativeModulePath = path.relative(absoluteSrcPath, absoluteModulePath);
|
|
178
|
+
// Get the module's name
|
|
179
|
+
moduleName = getModuleName(host, relativeModulePath, absoluteSrcPath);
|
|
180
|
+
(0, logging_1.debug)('Discovered module: {yellow}', moduleName);
|
|
181
|
+
// Ensure this module is unique
|
|
182
|
+
const cachedModulePath = declaredModulesPath.get(moduleName);
|
|
183
|
+
if (cachedModulePath) {
|
|
184
|
+
(0, logging_1.panic)(`Two modules were declared with the same name {yellow}:\n` + `- One in {yellow}\n` + `- One in {yellow}`, moduleName, cachedModulePath, relativeModulePath);
|
|
185
|
+
}
|
|
186
|
+
modulesCache.set(basePath, moduleName);
|
|
187
|
+
}
|
|
188
|
+
if (moduleName in {}) {
|
|
189
|
+
(0, logging_1.panic)(`Detected module whose name {yellow} collides with a JavaScript's native object property`, moduleName);
|
|
190
|
+
}
|
|
191
|
+
let moduleSdkInfos = collected.get(moduleName);
|
|
192
|
+
if (!moduleSdkInfos) {
|
|
193
|
+
moduleSdkInfos = new Map();
|
|
194
|
+
collected.set(moduleName, moduleSdkInfos);
|
|
195
|
+
}
|
|
196
|
+
if (i === 0) {
|
|
197
|
+
if (process.platform === 'linux' && os.release().toLocaleLowerCase().includes('microsoft') && absoluteSrcPath.startsWith('/mnt/')) {
|
|
198
|
+
(0, logging_1.warn)("NOTE: On WSL, the first type analysis on a project located in Windows's filesystem may take a long time to complete.");
|
|
199
|
+
(0, logging_1.warn)('Please consider moving your project to WSL, or running this tool directly from Windows');
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
const metadata = analyzeController(host, relativeControllerPath, absoluteSrcPath);
|
|
203
|
+
if (metadata instanceof Error) {
|
|
204
|
+
throw new Error((0, logging_1.format)('Failed to analyze controller at path {magenta}:\n{}', relativeControllerPath, metadata.message));
|
|
205
|
+
}
|
|
206
|
+
if (metadata) {
|
|
207
|
+
if (metadata.registrationName in {}) {
|
|
208
|
+
(0, logging_1.panic)(`Detected controller whose registration name {yellow} collides with a JavaScript's native object property`, metadata.registrationName);
|
|
209
|
+
}
|
|
210
|
+
// Ensure the each controller has a unique name across modules
|
|
211
|
+
if (usedControllerNames.has(metadata.className)) {
|
|
212
|
+
(0, logging_1.panic)(`Detected two controllers with the same name {yellow}. Second occurrence found in {yellow}`, metadata.registrationName, metadata.path);
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
usedControllerNames.add(metadata.className);
|
|
216
|
+
}
|
|
217
|
+
moduleSdkInfos.set(metadata.className, metadata);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
return collected;
|
|
221
|
+
}
|
|
222
|
+
function getModuleName(host, modulePath, sourcePath) {
|
|
223
|
+
const SK = host.SyntaxKind;
|
|
224
|
+
// Prepare the source file to analyze
|
|
225
|
+
const file = getSourceFileOrThrow(host, path.resolve(sourcePath, modulePath));
|
|
226
|
+
// Find the module class declaration
|
|
227
|
+
const classDecl = file.statements.find((node) => node.kind === SK.ClassDeclaration && (0, ast_1.getDecorators)(host, node).length > 0);
|
|
228
|
+
if (!classDecl) {
|
|
229
|
+
(0, logging_1.panic)('No class declaration found in module at {yellow}', modulePath);
|
|
230
|
+
}
|
|
231
|
+
const moduleName = (0, ast_1.nodeName)(classDecl, file);
|
|
232
|
+
if (moduleName === undefined) {
|
|
233
|
+
(0, logging_1.panic)('Internal error: failed to retrieve name of declared class');
|
|
234
|
+
}
|
|
235
|
+
const decorators = (0, ast_1.getDecorators)(host, classDecl);
|
|
236
|
+
const moduleDecorator = decorators.find((dec) => (0, ast_1.decoratorName)(host, dec, file) === 'Module');
|
|
237
|
+
if (!moduleDecorator) {
|
|
238
|
+
(0, logging_1.panic)((0, logging_1.format)(`Module class {yellow} is missing {yellow} decorator\nModule path is: {yellow}`, moduleName, '@Module', modulePath));
|
|
239
|
+
}
|
|
240
|
+
return moduleName;
|
|
241
|
+
}
|
|
242
|
+
function analyzeController(host, controllerPath, absoluteSrcPath) {
|
|
243
|
+
const SK = host.SyntaxKind;
|
|
244
|
+
(0, logging_1.debug)('Analyzing: {yellow}', controllerPath);
|
|
245
|
+
// Prepare the source file to analyze
|
|
246
|
+
const file = getSourceFileOrThrow(host, path.resolve(absoluteSrcPath, controllerPath));
|
|
247
|
+
// Find the controller class declaration
|
|
248
|
+
const classDecl = file.statements.find((node) => node.kind === SK.ClassDeclaration);
|
|
249
|
+
if (!classDecl) {
|
|
250
|
+
(0, logging_1.warn)('No controller found in this file.');
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
const className = (0, ast_1.nodeName)(classDecl, file);
|
|
254
|
+
if (className === undefined) {
|
|
255
|
+
return new Error('Internal error: failed to retrieve name of declared class');
|
|
256
|
+
}
|
|
257
|
+
// By default, a controller is registered under its class name
|
|
258
|
+
// This is unless it provides an argument to its @Controller() decorator
|
|
259
|
+
let registrationName = (0, sdk_1.camelcase)(className);
|
|
260
|
+
let controllerUriPrefix = null;
|
|
261
|
+
(0, logging_1.debug)('Found class declaration: {yellow}', className);
|
|
262
|
+
// Get the @Controller() decorator
|
|
263
|
+
const decorator = (0, ast_1.getDecorators)(host, classDecl).find((dec) => (0, ast_1.decoratorName)(host, dec, file) === 'Controller');
|
|
264
|
+
if (!decorator) {
|
|
265
|
+
(0, logging_1.warn)('Skipping this controller as it does not have a @Controller() decorator');
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
// Get the decorator's call expression
|
|
269
|
+
const decCallExpr = (0, ast_1.decoratorCallExpression)(host, decorator);
|
|
270
|
+
if (!decCallExpr) {
|
|
271
|
+
(0, logging_1.warn)('Skipping this controller as its @Controller() decorator is not called');
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
// Get the decorator's arguments
|
|
275
|
+
const decExpr = decCallExpr.arguments;
|
|
276
|
+
if (decExpr.length > 1) {
|
|
277
|
+
(0, logging_1.warn)('Skipping this controller as its @Controller() decorator is called with more than 1 argument');
|
|
278
|
+
return null;
|
|
279
|
+
}
|
|
280
|
+
// Get the first argument, which is expected to be the controller's registration name
|
|
281
|
+
// Example: `@Controller("SuperName")` will register the controller under the name "SuperName"
|
|
282
|
+
if (decExpr[0]) {
|
|
283
|
+
const nameArg = decExpr[0];
|
|
284
|
+
// Variables are not supported
|
|
285
|
+
if (!(0, ast_1.isStringLiteral)(host, nameArg)) {
|
|
286
|
+
(0, logging_1.warn)("Skipping this controller as its @Controller() decorator's argument is not a string literal");
|
|
287
|
+
return null;
|
|
288
|
+
}
|
|
289
|
+
// Update the registration name
|
|
290
|
+
registrationName = nameArg.text;
|
|
291
|
+
controllerUriPrefix = registrationName;
|
|
292
|
+
(0, logging_1.debug)('Registering controller {yellow} as {yellow} (as specified in @Controller())', className, registrationName);
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
// No argument was provided to the @Controller() decorator, so we stick with the original controller's name
|
|
296
|
+
(0, logging_1.debug)('@Controller() was called without argument, registering controller under name {yellow}', registrationName);
|
|
297
|
+
}
|
|
298
|
+
// Generate a SDK interface for the controller's methods
|
|
299
|
+
const methods = analyzeMethods(host, file, classDecl, controllerUriPrefix, controllerPath, absoluteSrcPath);
|
|
300
|
+
if (methods instanceof Error) {
|
|
301
|
+
return methods;
|
|
302
|
+
}
|
|
303
|
+
// Success!
|
|
304
|
+
(0, logging_1.debug)(`└─ Done for controller {yellow}`, controllerPath);
|
|
305
|
+
return {
|
|
306
|
+
path: controllerPath,
|
|
307
|
+
className,
|
|
308
|
+
registrationName,
|
|
309
|
+
methods,
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
// =============================================================================================================== //
|
|
313
|
+
// Methods & parameters (see src/analyzer/methods.ts, src/analyzer/params.ts) //
|
|
314
|
+
// =============================================================================================================== //
|
|
315
|
+
function analyzeMethods(host, sourceFile, controllerClass, controllerUriPrefix, filePath, absoluteSrcPath) {
|
|
316
|
+
// Output variable
|
|
317
|
+
const collected = new Array();
|
|
318
|
+
// Get the list of all methods
|
|
319
|
+
const methods = controllerClass.members.filter((node) => node.kind === host.SyntaxKind.MethodDeclaration);
|
|
320
|
+
for (const method of methods) {
|
|
321
|
+
const methodName = (0, ast_1.nodeName)(method, sourceFile);
|
|
322
|
+
(0, logging_1.debug)('├─ Found method: {yellow}', methodName);
|
|
323
|
+
// Get the HTTP decorator(s) of the method
|
|
324
|
+
const decorators = (0, ast_1.getDecorators)(host, method).filter((dec) => Object.keys(sdk_1.SdkHttpMethod).includes((0, ast_1.decoratorName)(host, dec, sourceFile)));
|
|
325
|
+
// We expect to have exactly one HTTP decorator
|
|
326
|
+
if (decorators.length > 1) {
|
|
327
|
+
// If there is more than one decorator, that's invalid, so we can't analyze the method
|
|
328
|
+
return new Error((0, logging_1.format)('├─── Detected multiple HTTP decorators on method: {yellow}' +
|
|
329
|
+
decorators.map((dec) => (0, ast_1.decoratorName)(host, dec, sourceFile)).join(',')));
|
|
330
|
+
}
|
|
331
|
+
else if (decorators.length === 0) {
|
|
332
|
+
// If there isn't any HTTP decorator, this is simply not a method available from the outside and so we won't generate an interface for it
|
|
333
|
+
(0, logging_1.debug)('├─── Skipping this method as it does not have an HTTP decorator');
|
|
334
|
+
continue;
|
|
335
|
+
}
|
|
336
|
+
// Get the HTTP decorator
|
|
337
|
+
const dec = decorators[0];
|
|
338
|
+
const httpMethod = sdk_1.SdkHttpMethod[(0, ast_1.decoratorName)(host, dec, sourceFile)];
|
|
339
|
+
(0, logging_1.debug)('├─── Detected HTTP method: {magentaBright}', httpMethod.toLocaleUpperCase());
|
|
340
|
+
// Get the arguments provided to the HTTP decorator (we expect one, the URI path)
|
|
341
|
+
const decArgs = (0, ast_1.decoratorArguments)(host, dec);
|
|
342
|
+
// The method's URI path
|
|
343
|
+
let uriPath;
|
|
344
|
+
// We expect the decorator to have exactly one argument
|
|
345
|
+
if (decArgs.length > 1) {
|
|
346
|
+
// If we have more than one argument, that's invalid (or at least not supported here), so we can't analyze the method
|
|
347
|
+
return new Error(`Multiple (${decArgs.length}) arguments were provided to the HTTP decorator`);
|
|
348
|
+
}
|
|
349
|
+
else if (decArgs.length === 0) {
|
|
350
|
+
// If there is no argument, we take the method's name as the URI path
|
|
351
|
+
(0, logging_1.debug)('├─── No argument found for decorator, using base URI path.');
|
|
352
|
+
uriPath = '';
|
|
353
|
+
}
|
|
354
|
+
else {
|
|
355
|
+
// If we have exactly one argument, hurray! That's our URI path.
|
|
356
|
+
const uriNameDec = decArgs[0];
|
|
357
|
+
// Variables are not supported
|
|
358
|
+
if (!(0, ast_1.isStringLiteral)(host, uriNameDec)) {
|
|
359
|
+
return new Error((0, logging_1.format)('├─── The argument provided to the HTTP decorator is not a string literal:\n>> {cyan}', (0, ast_1.nodeText)(uriNameDec, sourceFile)));
|
|
360
|
+
}
|
|
361
|
+
// Update the method's URI path
|
|
362
|
+
uriPath = uriNameDec.text;
|
|
363
|
+
(0, logging_1.debug)('├─── Detected argument in HTTP decorator, mapping this method to custom URI name');
|
|
364
|
+
}
|
|
365
|
+
(0, logging_1.debug)('├─── Detected URI name: {yellow}', uriPath);
|
|
366
|
+
// Analyze the method's URI
|
|
367
|
+
const route = (0, route_1.analyzeUri)(controllerUriPrefix ? (uriPath ? `/${controllerUriPrefix}/${uriPath}` : `/` + controllerUriPrefix) : uriPath);
|
|
368
|
+
if (route instanceof Error) {
|
|
369
|
+
return new Error('├─── Detected unsupported URI format:\n' +
|
|
370
|
+
route.message
|
|
371
|
+
.split('\n')
|
|
372
|
+
.map((line) => '├───── ' + line)
|
|
373
|
+
.join('\n'));
|
|
374
|
+
}
|
|
375
|
+
(0, logging_1.debug)('├─── Parsed URI name to route: {yellow}', (0, route_1.debugUri)(route, chalk.blue));
|
|
376
|
+
// Analyze the method's arguments
|
|
377
|
+
(0, logging_1.debug)('├─── Analyzing arguments...');
|
|
378
|
+
const params = extractParams({ host, sourceFile, controllerClass, httpMethod, route, method, filePath, absoluteSrcPath });
|
|
379
|
+
// Get the method's return type
|
|
380
|
+
(0, logging_1.debug)('├─── Resolving return type...');
|
|
381
|
+
const returnType = (0, typedeps_1.resolveTypeTextDependencies)(host.typeToString(host.getReturnTypeOfDeclaration(method)), filePath, absoluteSrcPath);
|
|
382
|
+
(0, logging_1.debug)('├─── Detected return type: {cyan}', returnType.resolvedType);
|
|
383
|
+
// Success!
|
|
384
|
+
collected.push({
|
|
385
|
+
name: methodName,
|
|
386
|
+
httpMethod,
|
|
387
|
+
returnType,
|
|
388
|
+
route,
|
|
389
|
+
uriPath,
|
|
390
|
+
params,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
return collected;
|
|
394
|
+
}
|
|
395
|
+
function extractParams(context) {
|
|
396
|
+
const { httpMethod, route } = context;
|
|
397
|
+
const { Body, Param, Query } = extractDecoratedArgs(context);
|
|
398
|
+
const resolvedParams = {
|
|
399
|
+
routeParams: mergeDecoratedArgs(Param),
|
|
400
|
+
queryParams: mergeDecoratedArgs(Query),
|
|
401
|
+
bodyParams: mergeDecoratedArgs(Body),
|
|
402
|
+
context,
|
|
403
|
+
};
|
|
404
|
+
/**
|
|
405
|
+
* Validate Body Params are not used in GET requests
|
|
406
|
+
*/
|
|
407
|
+
if (httpMethod === sdk_1.SdkHttpMethod.Get && resolvedParams.bodyParams) {
|
|
408
|
+
panicWithContext(`${httpMethod} request should not have @Body params, use @Query params instead`, context);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Validate Query Params are not used in non-GET requests
|
|
412
|
+
*/
|
|
413
|
+
if (httpMethod !== sdk_1.SdkHttpMethod.Get && resolvedParams.queryParams) {
|
|
414
|
+
panicWithContext(`${httpMethod} request should not have @Query params, use @Body params instead`, context);
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Validate Route Params exist in route URL
|
|
418
|
+
*/
|
|
419
|
+
const { routeParams } = resolvedParams;
|
|
420
|
+
if (routeParams) {
|
|
421
|
+
const allowedRouteParams = new Set((0, route_1.paramsFromRoute)(route));
|
|
422
|
+
// Like the legacy analyzer, this checks the keys of the resolved params object. For a generic `@Param()` argument,
|
|
423
|
+
// these are the keys of the resolved type's description (rawType, resolvedType...), which are rejected.
|
|
424
|
+
const usedRouteParams = Object.keys(routeParams);
|
|
425
|
+
for (const usedParam of usedRouteParams) {
|
|
426
|
+
if (!allowedRouteParams.has(usedParam)) {
|
|
427
|
+
panicWithContext(`Route param ${usedParam} does not appear in route URL`, context);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
return resolvedParams;
|
|
432
|
+
}
|
|
433
|
+
function extractDecoratedArgs(context) {
|
|
434
|
+
const decoratedArgs = {
|
|
435
|
+
[sdk_1.ArgDecorator.Param]: [],
|
|
436
|
+
[sdk_1.ArgDecorator.Query]: [],
|
|
437
|
+
[sdk_1.ArgDecorator.Body]: [],
|
|
438
|
+
};
|
|
439
|
+
const { controllerClass, host, method, sourceFile } = context;
|
|
440
|
+
const args = method.parameters;
|
|
441
|
+
for (const arg of args) {
|
|
442
|
+
const argName = (0, ast_1.nodeName)(arg, sourceFile);
|
|
443
|
+
(0, logging_1.debug)('├───── Detected argument: {yellow}', argName);
|
|
444
|
+
// Arguments are collected as soon as they have a decorator like @Query() or @Body()
|
|
445
|
+
const argDecorators = (0, ast_1.getDecorators)(host, arg).filter((dec) => Object.values(sdk_1.ArgDecorator).includes((0, ast_1.decoratorName)(host, dec, sourceFile)));
|
|
446
|
+
if (argDecorators.length === 0) {
|
|
447
|
+
// If we have no argument, this is not an argument we are interested in, so we just skip it
|
|
448
|
+
(0, logging_1.debug)('├───── Skipping this argument as it does not have a decorator');
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
else if (argDecorators.length > 1) {
|
|
452
|
+
(0, logging_1.panic)(`${(0, ast_1.nodeName)(controllerClass, sourceFile)} ${(0, ast_1.nodeName)(method, sourceFile)} has multiple decorators on argument ${argName} ${argDecorators
|
|
453
|
+
.map((dec) => (0, ast_1.decoratorName)(host, dec, sourceFile))
|
|
454
|
+
.join(', ')}`);
|
|
455
|
+
}
|
|
456
|
+
// Get the only decrator
|
|
457
|
+
const decorator = argDecorators[0];
|
|
458
|
+
const decoratorType = (0, ast_1.decoratorName)(host, decorator, sourceFile);
|
|
459
|
+
const argParamKey = extractArgParamKey({ ...context, arg, decorator });
|
|
460
|
+
const argType = host.getTypeAtLocation(arg);
|
|
461
|
+
if (!argParamKey && !host.isObjectType(argType)) {
|
|
462
|
+
(0, logging_1.panic)(`${(0, ast_1.nodeName)(controllerClass, sourceFile)} ${(0, ast_1.nodeName)(method, sourceFile)} generic controller argument ${decoratorType}() ${argName} must be an object type`);
|
|
463
|
+
}
|
|
464
|
+
decoratedArgs[decoratorType].push({
|
|
465
|
+
arg,
|
|
466
|
+
argParamKey,
|
|
467
|
+
decorator,
|
|
468
|
+
decoratorType,
|
|
469
|
+
context,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
return decoratedArgs;
|
|
473
|
+
}
|
|
474
|
+
function extractArgParamKey(context) {
|
|
475
|
+
const { arg, controllerClass, decorator, host, method, sourceFile } = context;
|
|
476
|
+
const decoratorArgs = (0, ast_1.decoratorArguments)(host, decorator);
|
|
477
|
+
if (decoratorArgs.length > 1) {
|
|
478
|
+
(0, logging_1.panic)(`${(0, ast_1.nodeName)(controllerClass, sourceFile)} ${(0, ast_1.nodeName)(method, sourceFile)} ${(0, ast_1.decoratorName)(host, decorator, sourceFile)}() ${(0, ast_1.nodeName)(arg, sourceFile)} argument decorator has multiple parameters`);
|
|
479
|
+
}
|
|
480
|
+
else if (decoratorArgs.length === 0) {
|
|
481
|
+
return null;
|
|
482
|
+
}
|
|
483
|
+
const decoratorArg = decoratorArgs[0];
|
|
484
|
+
if (!(0, ast_1.isStringLiteral)(host, decoratorArg)) {
|
|
485
|
+
(0, logging_1.panic)('The argument provided to the decorator is not a string literal:\n>>> {cyan}', (0, ast_1.nodeText)(arg, sourceFile));
|
|
486
|
+
}
|
|
487
|
+
const paramKey = decoratorArg.text;
|
|
488
|
+
if (paramKey in {}) {
|
|
489
|
+
panicWithContext(`${(0, ast_1.decoratorName)(host, decorator, sourceFile)}('${paramKey}') param name collides with JavaScript native object property`, context);
|
|
490
|
+
}
|
|
491
|
+
return paramKey;
|
|
492
|
+
}
|
|
493
|
+
function mergeDecoratedArgs(decoratedArgs) {
|
|
494
|
+
let genericParam = null;
|
|
495
|
+
const paramMap = {};
|
|
496
|
+
for (const decoratedArg of decoratedArgs) {
|
|
497
|
+
const { arg, argParamKey, context, decoratorType } = decoratedArg;
|
|
498
|
+
const resolvedType = (0, typedeps_1.resolveTypeTextDependencies)(context.host.typeToString(context.host.getTypeAtLocation(arg)), context.filePath, context.absoluteSrcPath);
|
|
499
|
+
if (argParamKey) {
|
|
500
|
+
if (paramMap[argParamKey]) {
|
|
501
|
+
panicWithContext(`${decoratorType}('${argParamKey}') used twice in controller method`, decoratedArg.context);
|
|
502
|
+
}
|
|
503
|
+
paramMap[argParamKey] = resolvedType;
|
|
504
|
+
}
|
|
505
|
+
else {
|
|
506
|
+
if (genericParam) {
|
|
507
|
+
panicWithContext(`${decoratorType}() used twice in controller method`, decoratedArg.context);
|
|
508
|
+
}
|
|
509
|
+
genericParam = resolvedType;
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
const hasArgsByKey = Object.keys(paramMap).length > 0;
|
|
513
|
+
if (genericParam && hasArgsByKey) {
|
|
514
|
+
panicWithContext(`Cannot mix generic and specific ${decoratedArgs[0].decoratorType}()`, decoratedArgs[0].context);
|
|
515
|
+
}
|
|
516
|
+
return hasArgsByKey ? paramMap : genericParam;
|
|
517
|
+
}
|
|
518
|
+
const panicWithContext = (message, context) => {
|
|
519
|
+
const { controllerClass, filePath, httpMethod, method, sourceFile } = context;
|
|
520
|
+
const ctx = {
|
|
521
|
+
controller: (0, ast_1.nodeName)(controllerClass, sourceFile),
|
|
522
|
+
method: (0, ast_1.nodeName)(method, sourceFile),
|
|
523
|
+
httpMethod,
|
|
524
|
+
filePath,
|
|
525
|
+
};
|
|
526
|
+
(0, logging_1.panic)(`${message}\n${JSON.stringify(ctx, null, 2)}`);
|
|
527
|
+
};
|
|
528
|
+
// =============================================================================================================== //
|
|
529
|
+
// Types extraction (see src/analyzer/extractor.ts, src/analyzer/classdeps.ts) //
|
|
530
|
+
// =============================================================================================================== //
|
|
531
|
+
function analyzeClassDeps(host, decl, sourceFile, relativeFilePath, absoluteSrcPath) {
|
|
532
|
+
if (path.isAbsolute(relativeFilePath)) {
|
|
533
|
+
(0, logging_1.unreachable)('Internal error: got absolute file path in class dependencies analyzer, when expecting a relative one (got {magentaBright})', relativeFilePath);
|
|
534
|
+
}
|
|
535
|
+
const toLookup = new Array();
|
|
536
|
+
for (const sup of (0, ast_1.getExtendsTypeNodes)(host, decl)) {
|
|
537
|
+
toLookup.push(host.getTypeAtLocation(sup));
|
|
538
|
+
}
|
|
539
|
+
for (const prop of (0, ast_1.getDeclarationProperties)(host, decl, sourceFile)) {
|
|
540
|
+
toLookup.push(host.getTypeAtLocation(prop));
|
|
541
|
+
}
|
|
542
|
+
return toLookup.map((type) => (0, typedeps_1.resolveTypeTextDependencies)(host.typeToString(type), relativeFilePath, absoluteSrcPath));
|
|
543
|
+
}
|
|
544
|
+
/**
|
|
545
|
+
* Types extractor
|
|
546
|
+
*/
|
|
547
|
+
class TypesExtractor {
|
|
548
|
+
host;
|
|
549
|
+
absoluteSrcPath;
|
|
550
|
+
magicTypes;
|
|
551
|
+
extracted;
|
|
552
|
+
constructor(
|
|
553
|
+
/** Analysis engine */
|
|
554
|
+
host,
|
|
555
|
+
/** Absolute source path */
|
|
556
|
+
absoluteSrcPath,
|
|
557
|
+
/** Magic types to replace non-portable types */
|
|
558
|
+
magicTypes,
|
|
559
|
+
/** Extracted types */
|
|
560
|
+
extracted = new Map()) {
|
|
561
|
+
this.host = host;
|
|
562
|
+
this.absoluteSrcPath = absoluteSrcPath;
|
|
563
|
+
this.magicTypes = magicTypes;
|
|
564
|
+
this.extracted = extracted;
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Find if a type has previously been extracted, without providing its extension
|
|
568
|
+
* @param loc
|
|
569
|
+
* @returns
|
|
570
|
+
*/
|
|
571
|
+
findExtractedTypeWithoutExt(loc) {
|
|
572
|
+
for (const ext of sdk_1.MODULE_EXTENSIONS) {
|
|
573
|
+
const typ = this.extracted.get(loc.relativePathNoExt + ext)?.get(loc.typename);
|
|
574
|
+
if (typ) {
|
|
575
|
+
return typ;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return null;
|
|
579
|
+
}
|
|
580
|
+
/**
|
|
581
|
+
* Find the relative file location of a type
|
|
582
|
+
* @param loc
|
|
583
|
+
* @returns
|
|
584
|
+
*/
|
|
585
|
+
findTypeRelativeFilePath(loc) {
|
|
586
|
+
if (path.isAbsolute(loc.relativePathNoExt)) {
|
|
587
|
+
(0, logging_1.unreachable)('Internal error: got absolute file path in types extractor, when expecting a relative one (got {magentaBright})', loc.relativePathNoExt);
|
|
588
|
+
}
|
|
589
|
+
const absolutePathNoExt = path.resolve(this.absoluteSrcPath, loc.relativePathNoExt);
|
|
590
|
+
const cached = this.findExtractedTypeWithoutExt(loc);
|
|
591
|
+
if (cached) {
|
|
592
|
+
return cached.relativePath;
|
|
593
|
+
}
|
|
594
|
+
let relativeFilePath = null;
|
|
595
|
+
for (const ext of sdk_1.MODULE_EXTENSIONS) {
|
|
596
|
+
if (this.host.getSourceFile(absolutePathNoExt + ext)) {
|
|
597
|
+
relativeFilePath = loc.relativePathNoExt + ext;
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
return (relativeFilePath ??
|
|
601
|
+
new Error((0, logging_1.format)('File {magenta} was not found (was expected to contain dependency type {yellow})', loc.relativePathNoExt, loc.typename)));
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Extract a type
|
|
605
|
+
* @param loc
|
|
606
|
+
* @param typesPath
|
|
607
|
+
* @returns
|
|
608
|
+
*/
|
|
609
|
+
extractType(loc, typesPath = []) {
|
|
610
|
+
const { host } = this;
|
|
611
|
+
const SK = host.SyntaxKind;
|
|
612
|
+
if (path.isAbsolute(loc.relativePathNoExt)) {
|
|
613
|
+
(0, logging_1.unreachable)('Internal error: got absolute file path in types extractor, when expecting a relative one (got {magentaBright})', loc.relativePathNoExt);
|
|
614
|
+
}
|
|
615
|
+
// Get the absolute path of the type's parent file
|
|
616
|
+
// We don't know its extension yet as imported file names in import statements don't have an extension
|
|
617
|
+
const absolutePathNoExt = path.resolve(this.absoluteSrcPath, loc.relativePathNoExt);
|
|
618
|
+
// If the type is already in cache, return it directly
|
|
619
|
+
const cached = this.findExtractedTypeWithoutExt(loc);
|
|
620
|
+
if (cached) {
|
|
621
|
+
return cached;
|
|
622
|
+
}
|
|
623
|
+
// Try to find the path with extension of the file and get it as a source file
|
|
624
|
+
// (like the legacy analyzer, the last matching extension wins)
|
|
625
|
+
let fileAndPath = null;
|
|
626
|
+
for (const ext of sdk_1.MODULE_EXTENSIONS) {
|
|
627
|
+
const sourceFile = host.getSourceFile(absolutePathNoExt + ext);
|
|
628
|
+
if (sourceFile) {
|
|
629
|
+
fileAndPath = [sourceFile, loc.relativePathNoExt + ext];
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
if (!fileAndPath) {
|
|
633
|
+
return new Error((0, logging_1.format)('File {magenta} was not found (was expected to contain dependency type {yellow})', loc.relativePathNoExt, loc.typename));
|
|
634
|
+
}
|
|
635
|
+
const [file, relativeFilePath] = fileAndPath;
|
|
636
|
+
// Use magic types to replace non-portable types
|
|
637
|
+
for (const magicType of this.magicTypes) {
|
|
638
|
+
if (relativeFilePath.endsWith(`node_modules/${magicType.nodeModuleFilePath}`) && loc.typename === magicType.typeName) {
|
|
639
|
+
(0, logging_1.debug)('-> '.repeat(typesPath.length + 1) +
|
|
640
|
+
'Found magic type {yellow} from external module file {magentaBright}, using provided placeholder.', loc.typename, relativeFilePath);
|
|
641
|
+
const extracted = {
|
|
642
|
+
content: '/** @file Magic placeholder from configuration file */\n\n' + magicType.placeholderContent,
|
|
643
|
+
relativePath: relativeFilePath,
|
|
644
|
+
relativePathNoExt: loc.relativePathNoExt,
|
|
645
|
+
typename: loc.typename,
|
|
646
|
+
typeParams: [],
|
|
647
|
+
dependencies: [],
|
|
648
|
+
};
|
|
649
|
+
typesPath.pop();
|
|
650
|
+
let types = this.extracted.get(relativeFilePath);
|
|
651
|
+
if (!types) {
|
|
652
|
+
types = new Map();
|
|
653
|
+
this.extracted.set(relativeFilePath, types);
|
|
654
|
+
}
|
|
655
|
+
types.set(loc.typename, extracted);
|
|
656
|
+
return extracted;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
(0, logging_1.debug)('-> '.repeat(typesPath.length + 1) + 'Extracting type {yellow} from file {magentaBright}...', loc.typename, relativeFilePath);
|
|
660
|
+
// Analyze the type's declaration
|
|
661
|
+
const decl = file.statements.find((node) => {
|
|
662
|
+
return ((node.kind === SK.EnumDeclaration ||
|
|
663
|
+
node.kind === SK.TypeAliasDeclaration ||
|
|
664
|
+
node.kind === SK.InterfaceDeclaration ||
|
|
665
|
+
node.kind === SK.ClassDeclaration ||
|
|
666
|
+
node.kind === SK.FunctionDeclaration) &&
|
|
667
|
+
(0, ast_1.nodeName)(node, file) === loc.typename);
|
|
668
|
+
});
|
|
669
|
+
if (!decl) {
|
|
670
|
+
return new Error((0, logging_1.format)(`Type {yellow} was not found in file {magenta}`, loc.typename, relativeFilePath));
|
|
671
|
+
}
|
|
672
|
+
// Handle a limitation of the tool: you can't import two types from two files at the same path with just two different extensions
|
|
673
|
+
// Example: importing a type named "User" from two files in the same directory called "user.entity.ts" and "user.entity.js"
|
|
674
|
+
const typ = this.findExtractedTypeWithoutExt(loc);
|
|
675
|
+
if (typ && typ.relativePath !== relativeFilePath) {
|
|
676
|
+
(0, logging_1.panic)('Found two conflicting files at same path but with different extensions:\n> {magentaBright}\n> {magentaBright}', typ.relativePath, relativeFilePath);
|
|
677
|
+
}
|
|
678
|
+
/** Resolved type's dependencies */
|
|
679
|
+
let resolvedDeps;
|
|
680
|
+
/** Type's parameters (e.g. <T>) */
|
|
681
|
+
let typeParams;
|
|
682
|
+
/** Type declaration */
|
|
683
|
+
let extractedDecl = (0, ast_1.nodeText)(decl, file);
|
|
684
|
+
// Handle enumerations
|
|
685
|
+
if (decl.kind === SK.EnumDeclaration) {
|
|
686
|
+
resolvedDeps = [];
|
|
687
|
+
typeParams = [];
|
|
688
|
+
}
|
|
689
|
+
// Handle type aliases
|
|
690
|
+
else if (decl.kind === SK.TypeAliasDeclaration) {
|
|
691
|
+
resolvedDeps = [(0, typedeps_1.resolveTypeTextDependencies)(host.typeToString(host.getTypeAtLocation(decl)), relativeFilePath, this.absoluteSrcPath)];
|
|
692
|
+
typeParams = [];
|
|
693
|
+
}
|
|
694
|
+
// Handle interfaces
|
|
695
|
+
else if (decl.kind === SK.InterfaceDeclaration) {
|
|
696
|
+
resolvedDeps = analyzeClassDeps(host, decl, file, relativeFilePath, this.absoluteSrcPath);
|
|
697
|
+
typeParams = (decl.typeParameters ?? []).map((tp) => (0, ast_1.nodeText)(tp, file));
|
|
698
|
+
}
|
|
699
|
+
// Handle classes
|
|
700
|
+
// Methods are not handled because they shouldn't be used as DTOs and won't be decodable from JSON in all cases
|
|
701
|
+
// This part is tricky as we remake the class from scratch using the informations we have on it, given we have to get rid
|
|
702
|
+
// of methods as well as removing decorators
|
|
703
|
+
else if (decl.kind === SK.ClassDeclaration) {
|
|
704
|
+
const classHead = (0, ast_1.nodeText)(decl, file).match(/\b(export[^{]+class[^{]+{)/);
|
|
705
|
+
if (!classHead) {
|
|
706
|
+
(0, logging_1.unreachable)('Internal error: failed to match class head in declaration: {yellow}', (0, ast_1.nodeText)(decl, file));
|
|
707
|
+
}
|
|
708
|
+
extractedDecl = classHead[1];
|
|
709
|
+
const index = host.getIndexType(host.getTypeAtLocation(decl), 'string') ?? host.getIndexType(host.getTypeAtLocation(decl), 'number');
|
|
710
|
+
if (index) {
|
|
711
|
+
extractedDecl += '\npublic [input: string | number]: ' + (0, typedeps_1.getImportResolvedTypeText)(host.typeToString(index));
|
|
712
|
+
}
|
|
713
|
+
// Export all members
|
|
714
|
+
for (const member of (0, ast_1.getClassMembers)(host, decl, file)) {
|
|
715
|
+
if (member.kind !== SK.PropertyDeclaration) {
|
|
716
|
+
(0, logging_1.warn)('Found non-property member in class {cyan}: {magenta}', (0, ast_1.nodeName)(decl, file) ?? '<anonymous>', (0, ast_1.nodeText)(member, file));
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
const memberType = host.getTypeAtLocation(member);
|
|
720
|
+
const memberText = (0, ast_1.nodeText)(member, file);
|
|
721
|
+
extractedDecl += `\npublic ${(0, ast_1.nodeName)(member, file)}${memberText.includes('?') ? '?' : memberText.includes('!:') ? '!' : ''}: ${(0, typedeps_1.getImportResolvedTypeText)(host.typeToString(memberType))};`;
|
|
722
|
+
}
|
|
723
|
+
extractedDecl += '\n}';
|
|
724
|
+
resolvedDeps = analyzeClassDeps(host, decl, file, relativeFilePath, this.absoluteSrcPath);
|
|
725
|
+
typeParams = (decl.typeParameters ?? []).map((tp) => (0, ast_1.nodeText)(tp, file));
|
|
726
|
+
}
|
|
727
|
+
// Handle functions
|
|
728
|
+
else if (decl.kind === SK.FunctionDeclaration) {
|
|
729
|
+
resolvedDeps = [];
|
|
730
|
+
typeParams = [];
|
|
731
|
+
}
|
|
732
|
+
// Handle unknown types
|
|
733
|
+
else {
|
|
734
|
+
(0, logging_1.panic)('Unknown node type when extracting types: ' + decl.kind);
|
|
735
|
+
}
|
|
736
|
+
/** Normalized dependencies */
|
|
737
|
+
const dependencies = [];
|
|
738
|
+
// Ensure we're not stuck in an infinite loop where we analyze a type A, then its dependency B, which itself depends on A, and so on
|
|
739
|
+
if (typesPath.includes(loc.typename)) {
|
|
740
|
+
(0, logging_1.unreachable)(`Internal error: infinite loop detected in types extracted: {yellow}`, typesPath.join(' -> '));
|
|
741
|
+
}
|
|
742
|
+
typesPath.push(loc.typename);
|
|
743
|
+
// Analyze all dependencies
|
|
744
|
+
for (const dependencyLoc of (0, sdk_1.locateTypesFile)(resolvedDeps)) {
|
|
745
|
+
// If the "dependency" is one of the type's parameters (e.g. "T"), ignore this part
|
|
746
|
+
if (typeParams.includes(dependencyLoc.typename)) {
|
|
747
|
+
continue;
|
|
748
|
+
}
|
|
749
|
+
// Find the dependency's relative path
|
|
750
|
+
let relativePath;
|
|
751
|
+
const cached = this.findExtractedTypeWithoutExt(dependencyLoc);
|
|
752
|
+
if (cached) {
|
|
753
|
+
relativePath = cached.relativePath;
|
|
754
|
+
}
|
|
755
|
+
else if (typesPath.includes(dependencyLoc.typename)) {
|
|
756
|
+
relativePath = this.findTypeRelativeFilePath(dependencyLoc);
|
|
757
|
+
}
|
|
758
|
+
else {
|
|
759
|
+
const extracted = this.extractType(dependencyLoc, typesPath);
|
|
760
|
+
relativePath = extracted instanceof Error ? extracted : extracted.relativePath;
|
|
761
|
+
}
|
|
762
|
+
if (relativePath instanceof Error) {
|
|
763
|
+
return new Error((0, logging_1.format)('├─ Failed to extract type {yellow} due to an error in dependency type {yellow}\nfrom file {magenta} :\n{}', loc.typename, dependencyLoc.typename, relativeFilePath, relativePath.message.replace(/^/gm, ' ')));
|
|
764
|
+
}
|
|
765
|
+
// Update dependencies
|
|
766
|
+
dependencies.push({ ...dependencyLoc, relativePath });
|
|
767
|
+
}
|
|
768
|
+
const extracted = {
|
|
769
|
+
...loc,
|
|
770
|
+
relativePath: relativeFilePath,
|
|
771
|
+
typeParams,
|
|
772
|
+
content: extractedDecl,
|
|
773
|
+
dependencies,
|
|
774
|
+
};
|
|
775
|
+
typesPath.pop();
|
|
776
|
+
let types = this.extracted.get(relativeFilePath);
|
|
777
|
+
if (!types) {
|
|
778
|
+
types = new Map();
|
|
779
|
+
this.extracted.set(relativeFilePath, types);
|
|
780
|
+
}
|
|
781
|
+
// Save the dependency
|
|
782
|
+
types.set(loc.typename, extracted);
|
|
783
|
+
return extracted;
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5hbHl6ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9lbmdpbmUvYW5hbHl6ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7Ozs7OztHQU1HOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFFSCxNQUFZLEVBQUUsK0JBQVU7QUFDeEIsTUFBWSxFQUFFLCtCQUFVO0FBQ3hCLE1BQVksSUFBSSxpQ0FBWTtBQUU1QixNQUFPLEtBQUssb0JBQW1CO0FBRS9CLGlEQUF1RDtBQUN2RCw2Q0FBZ0Y7QUFDaEYseUNBbUJ3QjtBQUN4QixtREFBK0c7QUFFL0csd0NBQW9FO0FBQ3BFLG9DQUF3QztBQUV4QywrQkFXYztBQUdkOzs7O0dBSUc7QUFDSSxLQUFLLDBCQUEwQixNQUFjLEVBQUUsVUFBc0Q7SUFDMUcsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEdBQUcsRUFBRSxDQUFBO0lBRTFCLE1BQU0sVUFBVSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLE1BQU0sQ0FBQyxZQUFZLENBQUMsQ0FBQTtJQUVuRSxJQUFJLENBQUMsVUFBVTtRQUFFLElBQUEsZUFBSyxFQUFDLG1DQUFtQyxDQUFDLENBQUE7SUFFM0QsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDO1FBQUUsSUFBQSxlQUFLLEVBQUMscURBQXFELEVBQUUsVUFBVSxDQUFDLENBQUE7SUFDeEcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsVUFBVSxDQUFDLENBQUMsV0FBVyxFQUFFO1FBQUUsSUFBQSxlQUFLLEVBQUMseUNBQXlDLENBQUMsQ0FBQTtJQUU3RixJQUFBLGVBQUssRUFBQywwQ0FBMEMsRUFBRSxVQUFVLENBQUMsQ0FBQTtJQUU3RCxJQUFJLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUN0QixNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQyxPQUFPLENB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
|