@buildvision/nest-sdk-generator 1.1.3
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/.prettierrc +6 -0
- package/LICENSE.md +9 -0
- package/README.md +353 -0
- package/build/analyzer/builtin.d.ts +2 -0
- package/build/analyzer/builtin.js +11 -0
- package/build/analyzer/classdeps.d.ts +6 -0
- package/build/analyzer/classdeps.js +27 -0
- package/build/analyzer/controller.d.ts +26 -0
- package/build/analyzer/controller.js +103 -0
- package/build/analyzer/controllers.d.ts +7 -0
- package/build/analyzer/controllers.js +79 -0
- package/build/analyzer/decorator.d.ts +10 -0
- package/build/analyzer/decorator.js +29 -0
- package/build/analyzer/extractor.d.ts +107 -0
- package/build/analyzer/extractor.js +349 -0
- package/build/analyzer/index.d.ts +16 -0
- package/build/analyzer/index.js +101 -0
- package/build/analyzer/methods.d.ts +42 -0
- package/build/analyzer/methods.js +115 -0
- package/build/analyzer/module.d.ts +11 -0
- package/build/analyzer/module.js +41 -0
- package/build/analyzer/params.d.ts +38 -0
- package/build/analyzer/params.js +163 -0
- package/build/analyzer/route.d.ts +53 -0
- package/build/analyzer/route.js +131 -0
- package/build/analyzer/typedeps.d.ts +49 -0
- package/build/analyzer/typedeps.js +86 -0
- package/build/bin.d.ts +2 -0
- package/build/bin.js +39 -0
- package/build/config.d.ts +44 -0
- package/build/config.js +31 -0
- package/build/generator/genmodules.d.ts +24 -0
- package/build/generator/genmodules.js +134 -0
- package/build/generator/gentypes.d.ts +10 -0
- package/build/generator/gentypes.js +62 -0
- package/build/generator/index.d.ts +6 -0
- package/build/generator/index.js +83 -0
- package/build/generator/prettier.d.ts +16 -0
- package/build/generator/prettier.js +43 -0
- package/build/generator/sdk-interface.d.ts +1 -0
- package/build/generator/sdk-interface.js +36 -0
- package/build/logging.d.ts +6 -0
- package/build/logging.js +37 -0
- package/build/tsconfig.tsbuildinfo +1 -0
- package/build/utils.d.ts +9 -0
- package/build/utils.js +56 -0
- package/package.json +34 -0
- package/src/analyzer/builtin.ts +9 -0
- package/src/analyzer/classdeps.ts +37 -0
- package/src/analyzer/controller.ts +135 -0
- package/src/analyzer/controllers.ts +117 -0
- package/src/analyzer/decorator.ts +29 -0
- package/src/analyzer/extractor.ts +491 -0
- package/src/analyzer/index.ts +136 -0
- package/src/analyzer/methods.ts +166 -0
- package/src/analyzer/module.ts +56 -0
- package/src/analyzer/params.ts +241 -0
- package/src/analyzer/route.ts +156 -0
- package/src/analyzer/typedeps.ts +130 -0
- package/src/bin.ts +33 -0
- package/src/config.ts +89 -0
- package/src/generator/genmodules.ts +163 -0
- package/src/generator/gentypes.ts +73 -0
- package/src/generator/index.ts +92 -0
- package/src/generator/prettier.ts +46 -0
- package/src/generator/sdk-interface.ts +32 -0
- package/src/logging.ts +35 -0
- package/src/utils.ts +61 -0
- package/tsconfig.json +26 -0
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file Entrypoint of the source API analyzer, used to generate the final SDK
|
|
4
|
+
*/
|
|
5
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
6
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
7
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
8
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
9
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
10
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
11
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
12
|
+
});
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.analyzerCli = void 0;
|
|
16
|
+
const fs = require("fs");
|
|
17
|
+
const path = require("path");
|
|
18
|
+
const ts_morph_1 = require("ts-morph");
|
|
19
|
+
const logging_1 = require("../logging");
|
|
20
|
+
const builtin_1 = require("./builtin");
|
|
21
|
+
const controllers_1 = require("./controllers");
|
|
22
|
+
const extractor_1 = require("./extractor");
|
|
23
|
+
function analyzerCli(config) {
|
|
24
|
+
var _a, _b;
|
|
25
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
const started = Date.now();
|
|
27
|
+
const sourcePath = path.resolve(process.cwd(), config.apiInputPath);
|
|
28
|
+
if (!sourcePath)
|
|
29
|
+
(0, logging_1.panic)('Please provide a source directory');
|
|
30
|
+
if (!fs.existsSync(sourcePath))
|
|
31
|
+
(0, logging_1.panic)('Provided source path {magentaBright} does not exist', sourcePath);
|
|
32
|
+
if (!fs.lstatSync(sourcePath).isDirectory())
|
|
33
|
+
(0, logging_1.panic)('Provided source path is not a directory');
|
|
34
|
+
(0, logging_1.debug)(`Analyzing from source directory {yellow}`, sourcePath);
|
|
35
|
+
if (config.jsonOutput) {
|
|
36
|
+
const jsonOutputParentDir = path.dirname(path.resolve(process.cwd(), config.jsonOutput));
|
|
37
|
+
if (!fs.existsSync(jsonOutputParentDir)) {
|
|
38
|
+
(0, logging_1.panic)("Output file's parent directory {magentaBright} does not exist.", jsonOutputParentDir);
|
|
39
|
+
}
|
|
40
|
+
(0, logging_1.debug)('Writing output to {yellow}', config.jsonOutput, config.jsonPrettyOutput ? 'beautified' : 'minified');
|
|
41
|
+
}
|
|
42
|
+
// ====== Find & parse 'tsconfig.json' ====== //
|
|
43
|
+
if (config.tsconfigFile && config.tsconfigFile.includes('/')) {
|
|
44
|
+
(0, logging_1.panic)('Provided tsconfig file name contains slashes');
|
|
45
|
+
}
|
|
46
|
+
const tsConfigFileName = (_a = config.tsconfigFile) !== null && _a !== void 0 ? _a : 'tsconfig.json';
|
|
47
|
+
const tsConfigFilePath = path.join(sourcePath, tsConfigFileName);
|
|
48
|
+
if (!fs.existsSync(tsConfigFilePath)) {
|
|
49
|
+
(0, logging_1.panic)('No {yellow} file found in provided source path {yellow}', tsConfigFileName, sourcePath);
|
|
50
|
+
}
|
|
51
|
+
// Create a 'ts-morph' project
|
|
52
|
+
const project = new ts_morph_1.Project({
|
|
53
|
+
tsConfigFilePath,
|
|
54
|
+
});
|
|
55
|
+
// Get the list of all TypeScript files in the source directory
|
|
56
|
+
const sourceTSFiles = project.getSourceFiles().map((file) => path.relative(sourcePath, file.getFilePath()));
|
|
57
|
+
(0, logging_1.debug)(`Found {magentaBright} source files.`, sourceTSFiles.length);
|
|
58
|
+
// Add them
|
|
59
|
+
(0, logging_1.debug)('\nAdding them to the source project...');
|
|
60
|
+
let progressByTenth = 0;
|
|
61
|
+
let strLen = sourceTSFiles.length.toString().length;
|
|
62
|
+
const hasProgress = (filesTreated) => filesTreated / sourceTSFiles.length >= (progressByTenth + 1) / 10;
|
|
63
|
+
const controllers = [];
|
|
64
|
+
for (let i = 0; i < sourceTSFiles.length; i++) {
|
|
65
|
+
const file = sourceTSFiles[i];
|
|
66
|
+
if (file.endsWith('.controller.ts')) {
|
|
67
|
+
controllers.push(file);
|
|
68
|
+
}
|
|
69
|
+
if (hasProgress(i + 1)) {
|
|
70
|
+
while (hasProgress(i + 1))
|
|
71
|
+
progressByTenth++;
|
|
72
|
+
(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' : '');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
(0, logging_1.debug)('All files were added successfully.\n');
|
|
76
|
+
const modules = (0, controllers_1.analyzeControllers)(controllers, sourcePath, project);
|
|
77
|
+
// Builtin magic types are concatenated **after** the configuration's ones, as this allows users to
|
|
78
|
+
// override the builtin ones if they want. Do **not** change the concatenation order!
|
|
79
|
+
const magicTypes = ((_b = config.magicTypes) !== null && _b !== void 0 ? _b : []).concat(builtin_1.builtinMagicTypes);
|
|
80
|
+
const typesCache = new extractor_1.TypesExtractor(project, sourcePath, magicTypes);
|
|
81
|
+
const typesToExtract = (0, extractor_1.locateTypesFile)((0, extractor_1.flattenSdkResolvedTypes)(modules));
|
|
82
|
+
(0, logging_1.debug)('\n==== Extracting {} type' + (typesToExtract.length > 1 ? 's' : '') + ' ====\n', typesToExtract.length);
|
|
83
|
+
for (const loc of typesToExtract) {
|
|
84
|
+
const result = typesCache.extractType(loc);
|
|
85
|
+
if (result instanceof Error) {
|
|
86
|
+
(0, logging_1.panic)(result.message);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const content = {
|
|
90
|
+
modules,
|
|
91
|
+
types: typesCache.extracted,
|
|
92
|
+
};
|
|
93
|
+
if (config.jsonOutput) {
|
|
94
|
+
fs.writeFileSync(config.jsonOutput, JSON.stringify(content, (_, v) => (v instanceof Map ? Object.fromEntries(v) : v), config.jsonPrettyOutput ? 4 : 0), 'utf8');
|
|
95
|
+
}
|
|
96
|
+
(0, logging_1.debug)('\n===== Done in {green}! ====', ((Date.now() - started) / 1000).toFixed(2) + 's');
|
|
97
|
+
return content;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
exports.analyzerCli = analyzerCli;
|
|
101
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYW5hbHl6ZXIvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOztHQUVHOzs7Ozs7Ozs7Ozs7QUFFSCx5QkFBd0I7QUFDeEIsNkJBQTRCO0FBQzVCLHVDQUFrQztBQUVsQyx3Q0FBeUM7QUFDekMsdUNBQTZDO0FBQzdDLCtDQUE4RDtBQUM5RCwyQ0FBNkc7QUFhN0csU0FBc0IsV0FBVyxDQUFDLE1BQWM7OztRQUM5QyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUE7UUFFMUIsTUFBTSxVQUFVLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsTUFBTSxDQUFDLFlBQVksQ0FBQyxDQUFBO1FBRW5FLElBQUksQ0FBQyxVQUFVO1lBQUUsSUFBQSxlQUFLLEVBQUMsbUNBQW1DLENBQUMsQ0FBQTtRQUUzRCxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUM7WUFBRSxJQUFBLGVBQUssRUFBQyxxREFBcUQsRUFBRSxVQUFVLENBQUMsQ0FBQTtRQUN4RyxJQUFJLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxXQUFXLEVBQUU7WUFBRSxJQUFBLGVBQUssRUFBQyx5Q0FBeUMsQ0FBQyxDQUFBO1FBRTdGLElBQUEsZUFBSyxFQUFDLDBDQUEwQyxFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBRTdELElBQUksTUFBTSxDQUFDLFVBQVUsRUFBRTtZQUNyQixNQUFNLG1CQUFtQixHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEVBQUUsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUE7WUFFeEYsSUFBSSxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsbUJBQW1CLENBQUMsRUFBRTtnQkFDdkMsSUFB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
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Analyzer for the source API's methods
|
|
3
|
+
*/
|
|
4
|
+
import { ClassDeclaration } from 'ts-morph';
|
|
5
|
+
import { SdkMethodParams } from './params';
|
|
6
|
+
import { Route } from './route';
|
|
7
|
+
import { ResolvedTypeDeps } from './typedeps';
|
|
8
|
+
/**
|
|
9
|
+
* SDK interface for a single controller's method
|
|
10
|
+
*/
|
|
11
|
+
export interface SdkMethod {
|
|
12
|
+
/** Method's name */
|
|
13
|
+
readonly name: string;
|
|
14
|
+
/** Method's HTTP method (e.g. GET / POST) */
|
|
15
|
+
readonly httpMethod: SdkHttpMethod;
|
|
16
|
+
/** Method's return type with resolved dependencies */
|
|
17
|
+
readonly returnType: ResolvedTypeDeps;
|
|
18
|
+
/** Method's parsed route */
|
|
19
|
+
readonly route: Route;
|
|
20
|
+
/** Method's URI path */
|
|
21
|
+
readonly uriPath: string;
|
|
22
|
+
/** Method's parameters */
|
|
23
|
+
readonly params: SdkMethodParams;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* HTTP method of a controller's method
|
|
27
|
+
*/
|
|
28
|
+
export declare enum SdkHttpMethod {
|
|
29
|
+
Get = "GET",
|
|
30
|
+
Post = "POST",
|
|
31
|
+
Put = "PUT",
|
|
32
|
+
Patch = "PATCH",
|
|
33
|
+
Delete = "DELETE"
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Generate a SDK interface for a controller
|
|
37
|
+
* @param controllerClass The class declaration of the controller
|
|
38
|
+
* @param controllerUriPrefix Optional URI prefix for this controller (e.g. `@Controller("registrationName")`)
|
|
39
|
+
* @param filePath Path to the controller's file
|
|
40
|
+
* @param absoluteSrcPath Absolute path to the source directory
|
|
41
|
+
*/
|
|
42
|
+
export declare function analyzeMethods(controllerClass: ClassDeclaration, controllerUriPrefix: string | null, filePath: string, absoluteSrcPath: string): SdkMethod[] | Error;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file Analyzer for the source API's methods
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.analyzeMethods = exports.SdkHttpMethod = void 0;
|
|
7
|
+
const chalk_1 = require("chalk");
|
|
8
|
+
const ts_morph_1 = require("ts-morph");
|
|
9
|
+
const logging_1 = require("../logging");
|
|
10
|
+
const params_1 = require("./params");
|
|
11
|
+
const route_1 = require("./route");
|
|
12
|
+
const typedeps_1 = require("./typedeps");
|
|
13
|
+
/**
|
|
14
|
+
* HTTP method of a controller's method
|
|
15
|
+
*/
|
|
16
|
+
var SdkHttpMethod;
|
|
17
|
+
(function (SdkHttpMethod) {
|
|
18
|
+
SdkHttpMethod["Get"] = "GET";
|
|
19
|
+
SdkHttpMethod["Post"] = "POST";
|
|
20
|
+
SdkHttpMethod["Put"] = "PUT";
|
|
21
|
+
SdkHttpMethod["Patch"] = "PATCH";
|
|
22
|
+
SdkHttpMethod["Delete"] = "DELETE";
|
|
23
|
+
})(SdkHttpMethod = exports.SdkHttpMethod || (exports.SdkHttpMethod = {}));
|
|
24
|
+
/**
|
|
25
|
+
* Generate a SDK interface for a controller
|
|
26
|
+
* @param controllerClass The class declaration of the controller
|
|
27
|
+
* @param controllerUriPrefix Optional URI prefix for this controller (e.g. `@Controller("registrationName")`)
|
|
28
|
+
* @param filePath Path to the controller's file
|
|
29
|
+
* @param absoluteSrcPath Absolute path to the source directory
|
|
30
|
+
*/
|
|
31
|
+
function analyzeMethods(controllerClass, controllerUriPrefix, filePath, absoluteSrcPath) {
|
|
32
|
+
// Output variable
|
|
33
|
+
const collected = new Array();
|
|
34
|
+
// Get the list of all methods
|
|
35
|
+
const methods = controllerClass.forEachChildAsArray().filter((node) => node instanceof ts_morph_1.MethodDeclaration);
|
|
36
|
+
for (const method of methods) {
|
|
37
|
+
const methodName = method.getName();
|
|
38
|
+
(0, logging_1.debug)('├─ Found method: {yellow}', methodName);
|
|
39
|
+
// Get the HTTP decorator(s) of the method
|
|
40
|
+
const decorators = method.getDecorators().filter((dec) => Object.keys(SdkHttpMethod).includes(dec.getName()));
|
|
41
|
+
// We expect to have exactly one HTTP decorator
|
|
42
|
+
if (decorators.length > 1) {
|
|
43
|
+
// If there is more than one decorator, that's invalid, so we can't analyze the method
|
|
44
|
+
return new Error((0, logging_1.format)('├─── Detected multiple HTTP decorators on method: {yellow}' + decorators.map((dec) => dec.getName()).join(',')));
|
|
45
|
+
}
|
|
46
|
+
else if (decorators.length === 0) {
|
|
47
|
+
// 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
|
|
48
|
+
(0, logging_1.debug)('├─── Skipping this method as it does not have an HTTP decorator');
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
// Get the HTTP decorator
|
|
52
|
+
const dec = decorators[0];
|
|
53
|
+
// We need to put a '@ts-ignore' here because TypeScript doesn't like indexing an enumeration with a string key, although this works fine
|
|
54
|
+
// @ts-ignore
|
|
55
|
+
const httpMethod = SdkHttpMethod[dec.getName()];
|
|
56
|
+
(0, logging_1.debug)('├─── Detected HTTP method: {magentaBright}', httpMethod.toLocaleUpperCase());
|
|
57
|
+
// Get the arguments provided to the HTTP decorator (we expect one, the URI path)
|
|
58
|
+
const decArgs = dec.getArguments();
|
|
59
|
+
// The method's URI path
|
|
60
|
+
let uriPath;
|
|
61
|
+
// We expect the decorator to have exactly one argument
|
|
62
|
+
if (decArgs.length > 1) {
|
|
63
|
+
// If we have more than one argument, that's invalid (or at least not supported here), so we can't analyze the method
|
|
64
|
+
return new Error(`Multiple (${decArgs.length}) arguments were provided to the HTTP decorator`);
|
|
65
|
+
}
|
|
66
|
+
else if (decArgs.length === 0) {
|
|
67
|
+
// If there is no argument, we take the method's name as the URI path
|
|
68
|
+
(0, logging_1.debug)('├─── No argument found for decorator, using base URI path.');
|
|
69
|
+
uriPath = '';
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// If we have exactly one argument, hurray! That's our URI path.
|
|
73
|
+
const uriNameDec = decArgs[0];
|
|
74
|
+
// Variables are not supported
|
|
75
|
+
if (!ts_morph_1.Node.isStringLiteral(uriNameDec)) {
|
|
76
|
+
return new Error((0, logging_1.format)('├─── The argument provided to the HTTP decorator is not a string literal:\n>> {cyan}', uriNameDec.getText()));
|
|
77
|
+
}
|
|
78
|
+
// Update the method's URI path
|
|
79
|
+
uriPath = uriNameDec.getLiteralText();
|
|
80
|
+
(0, logging_1.debug)('├─── Detected argument in HTTP decorator, mapping this method to custom URI name');
|
|
81
|
+
}
|
|
82
|
+
(0, logging_1.debug)('├─── Detected URI name: {yellow}', uriPath);
|
|
83
|
+
// Analyze the method's URI
|
|
84
|
+
const route = (0, route_1.analyzeUri)(controllerUriPrefix ? (uriPath ? `/${controllerUriPrefix}/${uriPath}` : `/` + controllerUriPrefix) : uriPath);
|
|
85
|
+
if (route instanceof Error) {
|
|
86
|
+
return new Error('├─── Detected unsupported URI format:\n' +
|
|
87
|
+
route.message
|
|
88
|
+
.split('\n')
|
|
89
|
+
.map((line) => '├───── ' + line)
|
|
90
|
+
.join('\n'));
|
|
91
|
+
}
|
|
92
|
+
(0, logging_1.debug)('├─── Parsed URI name to route: {yellow}', (0, route_1.debugUri)(route, chalk_1.blue));
|
|
93
|
+
// Analyze the method's arguments
|
|
94
|
+
(0, logging_1.debug)('├─── Analyzing arguments...');
|
|
95
|
+
const params = (0, params_1.analyzeParams)(httpMethod, route, method.getParameters(), filePath, absoluteSrcPath);
|
|
96
|
+
if (params instanceof Error)
|
|
97
|
+
return params;
|
|
98
|
+
// Get the method's return type
|
|
99
|
+
(0, logging_1.debug)('├─── Resolving return type...');
|
|
100
|
+
const returnType = (0, typedeps_1.resolveTypeDependencies)(method.getReturnType(), filePath, absoluteSrcPath);
|
|
101
|
+
(0, logging_1.debug)('├─── Detected return type: {cyan}', returnType.resolvedType);
|
|
102
|
+
// Success!
|
|
103
|
+
collected.push({
|
|
104
|
+
name: methodName,
|
|
105
|
+
httpMethod,
|
|
106
|
+
returnType,
|
|
107
|
+
route,
|
|
108
|
+
uriPath,
|
|
109
|
+
params,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
return collected;
|
|
113
|
+
}
|
|
114
|
+
exports.analyzeMethods = analyzeMethods;
|
|
115
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWV0aG9kcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hbmFseXplci9tZXRob2RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7R0FFRzs7O0FBRUgsaUNBQTRCO0FBQzVCLHVDQUFvRTtBQUNwRSx3Q0FBMEM7QUFDMUMscUNBQXlEO0FBQ3pELG1DQUFxRDtBQUNyRCx5Q0FBc0U7QUF5QnRFOztHQUVHO0FBQ0gsSUFBWSxhQU1YO0FBTkQsV0FBWSxhQUFhO0lBQ3ZCLDRCQUFXLENBQUE7SUFDWCw4QkFBYSxDQUFBO0lBQ2IsNEJBQVcsQ0FBQTtJQUNYLGdDQUFlLENBQUE7SUFDZixrQ0FBaUIsQ0FBQTtBQUNuQixDQUFDLEVBTlcsYUFBYSxHQUFiLHFCQUFhLEtBQWIscUJBQWEsUUFNeEI7QUFFRDs7Ozs7O0dBTUc7QUFDSCxTQUFnQixjQUFjLENBQzVCLGVBQWlDLEVBQ2pDLG1CQUFrQyxFQUNsQyxRQUFnQixFQUNoQixlQUF1QjtJQUV2QixrQkFBa0I7SUFDbEIsTUFBTSxTQUFTLEdBQUcsSUFBSSxLQUFLLEVBQWEsQ0FBQTtJQUV4Qyw4QkFBOEI7SUFDOUIsTUFBTSxPQUFPLEdBQUcsZUFBZSxDQUFDLG1CQUFtQixFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLFlBQVksNEJBQWlCLENBQXdCLENBQUE7SUFFaEksS0FBSyxNQUFNLE1BQU0sSUFBSSxPQUFPLEVBQUU7UUFDNUIsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFBO1FBRW5DLElBQUEsZUFBSyxFQUFDLDJCQUEyQixFQUFFLFVBQVUsQ0FBQyxDQUFBO1FBRTlDLDBDQUEwQztRQUMxQyxNQUFNLFVBQVUsR0FBRyxNQUFNLENBQUMsYUFBYSxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxDQUFDLFFB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
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Analyzer for the source API's modules
|
|
3
|
+
*/
|
|
4
|
+
import { Project } from 'ts-morph';
|
|
5
|
+
/**
|
|
6
|
+
* Get the name of a module
|
|
7
|
+
* @param project TS-Morph project the module is contained in
|
|
8
|
+
* @param modulePath Path to the module's file
|
|
9
|
+
* @param sourcePath Path to the TypeScript root directory
|
|
10
|
+
*/
|
|
11
|
+
export declare function getModuleName(project: Project, modulePath: string, sourcePath: string): string;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file Analyzer for the source API's modules
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.getModuleName = void 0;
|
|
7
|
+
const path = require("path");
|
|
8
|
+
const ts_morph_1 = require("ts-morph");
|
|
9
|
+
const logging_1 = require("../logging");
|
|
10
|
+
/**
|
|
11
|
+
* Get the name of a module
|
|
12
|
+
* @param project TS-Morph project the module is contained in
|
|
13
|
+
* @param modulePath Path to the module's file
|
|
14
|
+
* @param sourcePath Path to the TypeScript root directory
|
|
15
|
+
*/
|
|
16
|
+
function getModuleName(project, modulePath, sourcePath) {
|
|
17
|
+
// Prepare the source file to analyze
|
|
18
|
+
const file = project.getSourceFileOrThrow(path.resolve(sourcePath, modulePath));
|
|
19
|
+
// Find the module class declaration
|
|
20
|
+
const classDecl = file.forEachChildAsArray().find((node) => ts_morph_1.Node.isClassDeclaration(node) && node.getDecorators().length > 0);
|
|
21
|
+
if (!classDecl) {
|
|
22
|
+
(0, logging_1.panic)('No class declaration found in module at {yellow}', modulePath);
|
|
23
|
+
}
|
|
24
|
+
if (!ts_morph_1.Node.isClassDeclaration(classDecl))
|
|
25
|
+
(0, logging_1.panic)('Internal error: found class declaration statement which is not an instance of ClassDeclaration');
|
|
26
|
+
const moduleName = classDecl.getName();
|
|
27
|
+
if (moduleName === undefined) {
|
|
28
|
+
(0, logging_1.panic)('Internal error: failed to retrieve name of declared class');
|
|
29
|
+
}
|
|
30
|
+
const decorators = classDecl.getDecorators();
|
|
31
|
+
if (decorators.length > 1) {
|
|
32
|
+
(0, logging_1.panic)(`Found multiple decorators on module class {yellow} declared at {yellow}`, moduleName, modulePath);
|
|
33
|
+
}
|
|
34
|
+
const decName = decorators[0].getName();
|
|
35
|
+
if (decName !== 'Module') {
|
|
36
|
+
(0, logging_1.panic)((0, logging_1.format)(`The decorator on module class {yellow} was expected to be a {yellow}, found an {yellow} instead\nModule path is: {yellow}`, moduleName, '@Module', '@' + decName, modulePath));
|
|
37
|
+
}
|
|
38
|
+
return moduleName.substr(0, 1).toLocaleLowerCase() + moduleName.substr(1);
|
|
39
|
+
}
|
|
40
|
+
exports.getModuleName = getModuleName;
|
|
41
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FuYWx5emVyL21vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7OztBQUVILDZCQUE0QjtBQUM1Qix1Q0FBd0M7QUFDeEMsd0NBQTBDO0FBRTFDOzs7OztHQUtHO0FBQ0gsU0FBZ0IsYUFBYSxDQUFDLE9BQWdCLEVBQUUsVUFBa0IsRUFBRSxVQUFrQjtJQUNwRixxQ0FBcUM7SUFDckMsTUFBTSxJQUFJLEdBQUcsT0FBTyxDQUFDLG9CQUFvQixDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVSxFQUFFLFVBQVUsQ0FBQyxDQUFDLENBQUE7SUFFL0Usb0NBQW9DO0lBQ3BDLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsZUFBSSxDQUFDLGtCQUFrQixDQUFDLElBQUksQ0FBQyxJQUFJLElBQUksQ0FBQyxhQUFhLEVBQUUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUE7SUFFN0gsSUFBSSxDQUFDLFNBQVMsRUFBRTtRQUNkLElBQUEsZUFBSyxFQUFDLGtEQUFrRCxFQUFFLFVBQVUsQ0FBQyxDQUFBO0tBQ3RFO0lBRUQsSUFBSSxDQUFDLGVBQUksQ0FBQyxrQkFBa0IsQ0FBQyxTQUFTLENBQUM7UUFDckMsSUFBQSxlQUFLLEVBQUMsZ0dBQWdHLENBQUMsQ0FBQTtJQUV6RyxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUE7SUFFdEMsSUFBSSxVQUFVLEtBQUssU0FBUyxFQUFFO1FBQzVCLElBQUEsZUFBSyxFQUFDLDJEQUEyRCxDQUFDLENBQUE7S0FDbkU7SUFFRCxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsYUFBYSxFQUFFLENBQUE7SUFFNUMsSUFBSSxVQUFVLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRTtRQUN6QixJQUFBLGVBQUssRUFBQyx5RUFBeUUsRUFBRSxVQUFVLEVBQUUsVUFBVSxDQUFDLENBQUE7S0FDekc7SUFFRCxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUE7SUFFdkMsSUFBSSxPQUFPLEtBQUssUUFBUSxFQUFFO1FBQ3hCLElBQUEsZUFBSyxFQUNILElBQUEsZ0JBQU0sRUFDSiwySEFBMkgsRUFDM0gsVUFBVSxFQUNWLFNBQVMsRUFDVCxHQUFHLEdBQUcsT0FBTyxFQUNiLFVBQVUsQ0FDWCxDQUNGLENBQUE7S0FDRjtJQUVELE9BQU8sVUFBVSxDQUFDLE1BQU0sQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsaUJBQWlCLEVBQUUsR0FBRyxVQUFVLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFBO0FBQzNFLENBQUM7QUF6Q0Qsc0NBeUNDIn0=
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Analyzer for the source API's controllers' methods' parameters
|
|
3
|
+
*/
|
|
4
|
+
import { ParameterDeclaration } from 'ts-morph';
|
|
5
|
+
import { SdkHttpMethod } from './methods';
|
|
6
|
+
import { Route } from './route';
|
|
7
|
+
import { ResolvedTypeDeps } from './typedeps';
|
|
8
|
+
/**
|
|
9
|
+
* SDK interface for a controller's method's parameters
|
|
10
|
+
*/
|
|
11
|
+
export interface SdkMethodParams {
|
|
12
|
+
/** Route parameters */
|
|
13
|
+
parameters: Map<string, ResolvedTypeDeps> | null;
|
|
14
|
+
/** Query parameters */
|
|
15
|
+
query: Map<string, ResolvedTypeDeps> | null;
|
|
16
|
+
/** Body parameters */
|
|
17
|
+
body: SdkMethodBodyParam | null;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Single body parameter in a SDK's method
|
|
21
|
+
*/
|
|
22
|
+
export declare type SdkMethodBodyParam = {
|
|
23
|
+
full: true;
|
|
24
|
+
type: ResolvedTypeDeps;
|
|
25
|
+
} | {
|
|
26
|
+
full: false;
|
|
27
|
+
fields: Map<string, ResolvedTypeDeps>;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Generate a SDK interface for a controller's method's parameters
|
|
31
|
+
* @param httpMethod The method's HTTP method
|
|
32
|
+
* @param route The method's route
|
|
33
|
+
* @param args The method's arguments
|
|
34
|
+
* @param filePath Path to the controller's file
|
|
35
|
+
* @param absoluteSrcPath Absolute path to the source directory
|
|
36
|
+
* @returns A SDK interface for the method's parameters
|
|
37
|
+
*/
|
|
38
|
+
export declare function analyzeParams(httpMethod: SdkHttpMethod, route: Route, args: ParameterDeclaration[], filePath: string, absoluteSrcPath: string): SdkMethodParams | Error;
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @file Analyzer for the source API's controllers' methods' parameters
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.analyzeParams = void 0;
|
|
7
|
+
const logging_1 = require("../logging");
|
|
8
|
+
const decorator_1 = require("./decorator");
|
|
9
|
+
const methods_1 = require("./methods");
|
|
10
|
+
const route_1 = require("./route");
|
|
11
|
+
const typedeps_1 = require("./typedeps");
|
|
12
|
+
/**
|
|
13
|
+
* Generate a SDK interface for a controller's method's parameters
|
|
14
|
+
* @param httpMethod The method's HTTP method
|
|
15
|
+
* @param route The method's route
|
|
16
|
+
* @param args The method's arguments
|
|
17
|
+
* @param filePath Path to the controller's file
|
|
18
|
+
* @param absoluteSrcPath Absolute path to the source directory
|
|
19
|
+
* @returns A SDK interface for the method's parameters
|
|
20
|
+
*/
|
|
21
|
+
function analyzeParams(httpMethod, route, args, filePath, absoluteSrcPath) {
|
|
22
|
+
var _a, _b, _c, _d;
|
|
23
|
+
// The collected informations we will return
|
|
24
|
+
const collected = {
|
|
25
|
+
parameters: null,
|
|
26
|
+
query: null,
|
|
27
|
+
body: null,
|
|
28
|
+
};
|
|
29
|
+
// Get the named parameters of the route
|
|
30
|
+
const routeParams = (0, route_1.paramsOfRoute)(route);
|
|
31
|
+
// Treat all arguments (to not confuse with the route's parameters)
|
|
32
|
+
for (const arg of args) {
|
|
33
|
+
const name = arg.getName();
|
|
34
|
+
(0, logging_1.debug)('├───── Detected argument: {yellow}', name);
|
|
35
|
+
// Arguments are collected as soon as they have a decorator like @Query() or @Body()
|
|
36
|
+
const decs = arg.getDecorators();
|
|
37
|
+
if (decs.length === 0) {
|
|
38
|
+
// If we have no argument, this is not an argument we are interested in, so we just skip it
|
|
39
|
+
(0, logging_1.debug)('├───── Skipping this argument as it does not have a decorator');
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
else if (decs.length > 1) {
|
|
43
|
+
// If we have more than one decorator, this could mean we have for instance an @NotEmpty() @Query() or something like this,
|
|
44
|
+
// which is currently not supported.
|
|
45
|
+
return new Error('Skipping this argument as it has multiple decorators, which is currently not supported');
|
|
46
|
+
}
|
|
47
|
+
// Get the only decrator
|
|
48
|
+
const dec = decs[0];
|
|
49
|
+
const decName = dec.getName();
|
|
50
|
+
// Treat the @Param() decorator
|
|
51
|
+
if (decName === 'Param') {
|
|
52
|
+
(0, logging_1.debug)('├───── Detected decorator {blue}', '@Param');
|
|
53
|
+
// We expect a single string argument for this decorator,
|
|
54
|
+
// which is the route parameter's name
|
|
55
|
+
const paramName = (0, decorator_1.expectSingleStrLitDecorator)(dec);
|
|
56
|
+
if (paramName instanceof Error)
|
|
57
|
+
return paramName;
|
|
58
|
+
// If there is no argument, this argument is a global receiver which maps the full set of parameters
|
|
59
|
+
// We theorically *could* extract the type informations from this object type, but this would be insanely complex
|
|
60
|
+
// So, we just skip it as it's a lot more simple, and is not commonly used anyway as it has a set of downsides
|
|
61
|
+
if (paramName === null) {
|
|
62
|
+
(0, logging_1.warn)('├───── Skipping this argument as it is a generic parameters receiver, which is currently not supported');
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
// Ensure the specified parameter appears in the method's route
|
|
66
|
+
if (!routeParams.includes(paramName))
|
|
67
|
+
return new Error((0, logging_1.format)('├───── Cannot map unknown parameter {yellow}', paramName));
|
|
68
|
+
(0, logging_1.debug)('├───── Mapping argument to parameter: {yellow}', paramName);
|
|
69
|
+
// Get the route parameter's type
|
|
70
|
+
const typ = (0, typedeps_1.resolveTypeDependencies)(arg.getType(), filePath, absoluteSrcPath);
|
|
71
|
+
(0, logging_1.debug)('├───── Detected parameter type: {yellow} ({magentaBright} dependencies)', typ.resolvedType, typ.dependencies.size);
|
|
72
|
+
// Update the method's route parameters
|
|
73
|
+
if (paramName in {}) {
|
|
74
|
+
return new Error((0, logging_1.format)(`Detected @Param() field whose name {yellow} collides with a JavaScript's native object property`, paramName));
|
|
75
|
+
}
|
|
76
|
+
(_a = collected.parameters) !== null && _a !== void 0 ? _a : (collected.parameters = new Map());
|
|
77
|
+
collected.parameters.set(paramName, typ);
|
|
78
|
+
}
|
|
79
|
+
// Treat the @Query() decorator
|
|
80
|
+
else if (decName === 'Query') {
|
|
81
|
+
(0, logging_1.debug)('├───── Detected decorator {blue}', '@Query');
|
|
82
|
+
// We expect a single string argument for this decorator,
|
|
83
|
+
// which is the query parameter's name
|
|
84
|
+
const queryName = (0, decorator_1.expectSingleStrLitDecorator)(dec);
|
|
85
|
+
if (queryName instanceof Error)
|
|
86
|
+
return queryName;
|
|
87
|
+
// If there is no argument, this argument is a global receiver which maps the full set of parameters
|
|
88
|
+
// We theorically *could* extract the type informations from this object type, but this would be insanely complex
|
|
89
|
+
// So, we just skip it as it's a lot more simple, and is not commonly used anyway as it has a set of downsides
|
|
90
|
+
if (queryName === null) {
|
|
91
|
+
(0, logging_1.warn)('├───── Skipping this argument as it is a generic query receiver');
|
|
92
|
+
continue;
|
|
93
|
+
}
|
|
94
|
+
(0, logging_1.debug)('├───── Mapping argument to query: {yellow}', queryName);
|
|
95
|
+
// Get the parameter's type
|
|
96
|
+
const typ = (0, typedeps_1.resolveTypeDependencies)(arg.getType(), filePath, absoluteSrcPath);
|
|
97
|
+
(0, logging_1.debug)(`├───── Detected query type: {yellow} ({magentaBright} dependencies)`, typ.resolvedType, typ.dependencies.size);
|
|
98
|
+
// Update the method's query parameter
|
|
99
|
+
if (queryName in {}) {
|
|
100
|
+
return new Error((0, logging_1.format)(`Detected @Query() field whose name {yellow} collides with a JavaScript's native object property`, queryName));
|
|
101
|
+
}
|
|
102
|
+
(_b = collected.query) !== null && _b !== void 0 ? _b : (collected.query = new Map());
|
|
103
|
+
collected.query.set(queryName, typ);
|
|
104
|
+
}
|
|
105
|
+
// Treat the @Body() decorator
|
|
106
|
+
else if (decName === 'Body') {
|
|
107
|
+
(0, logging_1.debug)('├───── Detected decorator {blue}', '@Body');
|
|
108
|
+
// GET requests cannot have a BODY
|
|
109
|
+
if (httpMethod === methods_1.SdkHttpMethod.Get) {
|
|
110
|
+
return new Error('GET requests cannot have a BODY!');
|
|
111
|
+
}
|
|
112
|
+
// We expect a single string argument for this decorator,
|
|
113
|
+
// which is the body field's name
|
|
114
|
+
const fieldName = (0, decorator_1.expectSingleStrLitDecorator)(dec);
|
|
115
|
+
if (fieldName instanceof Error)
|
|
116
|
+
return fieldName;
|
|
117
|
+
// Get the field's type
|
|
118
|
+
const typ = (0, typedeps_1.resolveTypeDependencies)(arg.getType(), filePath, absoluteSrcPath);
|
|
119
|
+
const depsCount = typ.dependencies.size;
|
|
120
|
+
(0, logging_1.debug)(`├───── Detected BODY type: {cyan} ({magentaBright} ${depsCount === 0 ? 'no dependency' : depsCount > 1 ? 'dependencies' : 'dependency'})`, typ.resolvedType, depsCount);
|
|
121
|
+
// If there no name was provided to the decorator, then the decorator is a generic receiver which means it maps to the full body type
|
|
122
|
+
// This also means we can map the BODY type to this argument's type
|
|
123
|
+
if (fieldName === null) {
|
|
124
|
+
const body = collected.body;
|
|
125
|
+
// If we previously had an @Body(<name>) decorator on another argument, we have an important risk of mistyping
|
|
126
|
+
// => e.g. `@Body("a") a: string, @Body() body: { a: number }` is invalid as the type for the `a` field mismatches
|
|
127
|
+
// => It's easy to make an error as the @Body() type is often hidden behind a DTO
|
|
128
|
+
// But that's extremely complex to check automatically, so we just display a warning instead
|
|
129
|
+
// Also, that's not the kind of thing we make on purpose very often, so it's more likely it's an error, which makes it even more important
|
|
130
|
+
// to display a warning here.
|
|
131
|
+
if ((body === null || body === void 0 ? void 0 : body.full) === false)
|
|
132
|
+
(0, logging_1.warn)('├───── Detected full @Body() decorator after a single parameter. This is considered a bad practice, avoid it if you can!');
|
|
133
|
+
// Having two generic @Body() decorators is meaningless and will likey lead to errors, so we return a precise error here
|
|
134
|
+
else if (body === null || body === void 0 ? void 0 : body.full) {
|
|
135
|
+
return new Error((0, logging_1.format)(`Detected two @Body() decorators: found {yellow} previously, while method argument {yellow} indicates type {yellow}`, body.type.resolvedType, name, typ.resolvedType));
|
|
136
|
+
}
|
|
137
|
+
(0, logging_1.debug)("├───── Mapping argument to full request's body");
|
|
138
|
+
// Update the whole BODY type
|
|
139
|
+
collected.body = { full: true, type: typ };
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
// Here we have an @Body(<string>) decorator
|
|
143
|
+
// If we previously had an @Body() decorator, this can lead to several types of errors (see the big comment above for more informations)
|
|
144
|
+
if ((_c = collected.body) === null || _c === void 0 ? void 0 : _c.full) {
|
|
145
|
+
(0, logging_1.warn)('├───── Detected single @Body() decorator after a full parameter. This is considered a bad practice, avoid it if you can!');
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
(0, logging_1.debug)('├───── Mapping argument to BODY field: {yellow}', fieldName);
|
|
149
|
+
// Update the BODY type by adding the current field to it
|
|
150
|
+
if (fieldName in {}) {
|
|
151
|
+
return new Error((0, logging_1.format)(`Detected @Body() field whose name {yellow} collides with a JavaScript's native object property`, fieldName));
|
|
152
|
+
}
|
|
153
|
+
(_d = collected.body) !== null && _d !== void 0 ? _d : (collected.body = { full: false, fields: new Map() });
|
|
154
|
+
collected.body.fields.set(fieldName, typ);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Success!
|
|
160
|
+
return collected;
|
|
161
|
+
}
|
|
162
|
+
exports.analyzeParams = analyzeParams;
|
|
163
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicGFyYW1zLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2FuYWx5emVyL3BhcmFtcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7O0dBRUc7OztBQUdILHdDQUFnRDtBQUNoRCwyQ0FBeUQ7QUFDekQsdUNBQXlDO0FBQ3pDLG1DQUE4QztBQUM5Qyx5Q0FBc0U7QUFxQnRFOzs7Ozs7OztHQVFHO0FBQ0gsU0FBZ0IsYUFBYSxDQUMzQixVQUF5QixFQUN6QixLQUFZLEVBQ1osSUFBNEIsRUFDNUIsUUFBZ0IsRUFDaEIsZUFBdUI7O0lBRXZCLDRDQUE0QztJQUM1QyxNQUFNLFNBQVMsR0FBb0I7UUFDakMsVUFBVSxFQUFFLElBQUk7UUFDaEIsS0FBSyxFQUFFLElBQUk7UUFDWCxJQUFJLEVBQUUsSUFBSTtLQUNYLENBQUE7SUFFRCx3Q0FBd0M7SUFDeEMsTUFBTSxXQUFXLEdBQUcsSUFBQSxxQkFBYSxFQUFDLEtBQUssQ0FBQyxDQUFBO0lBRXhDLG1FQUFtRTtJQUNuRSxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksRUFBRTtRQUN0QixNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUE7UUFFMUIsSUFBQSxlQUFLLEVBQUMsb0NBQW9DLEVBQUUsSUFBSSxDQUFDLENBQUE7UUFFakQsb0ZBQW9GO1FBQ3BGLE1BQU0sSUFBSSxHQUFHLEdBQUcsQ0FBQyxhQUFhLEVBQUUsQ0FBQTtRQUVoQyxJQUFJLElBQUksQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ3JCLDJGQUEyRjtZQUMzRixJQUFBLGVBQUssRUFBQywrREFBK0QsQ0FBQyxDQUFBO1lBQ3RFLFNBQVE7U0FDVDthQUFNLElBQUksSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDMUIsMkhBQTJIO1lBQzNILHFDQUFxQztZQUNyQyxPQUFPLElBQUksS0FBSyxDQUFDLHdGQUF3RixDQUFDLENBQUE7U0FDM0c7UUFFRCx3QkFBd0I7UUFDeEIs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
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Analyzer for the source API's routes in controller methods
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* A single URI part
|
|
6
|
+
*/
|
|
7
|
+
export declare type RoutePart = {
|
|
8
|
+
readonly segment: string;
|
|
9
|
+
} | {
|
|
10
|
+
readonly param: string;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* A parsed URI path
|
|
14
|
+
*/
|
|
15
|
+
export interface Route {
|
|
16
|
+
/** Is this an absolute route? (routes starting with a '/') */
|
|
17
|
+
readonly isRoot: boolean;
|
|
18
|
+
/** The route's parts */
|
|
19
|
+
readonly parts: RoutePart[];
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Analyze an URI path
|
|
23
|
+
* @param uriPath The URI path to analyze
|
|
24
|
+
*/
|
|
25
|
+
export declare function analyzeUri(uriPath: string): Route | Error;
|
|
26
|
+
/**
|
|
27
|
+
* Get the named parameters of a parsed route
|
|
28
|
+
* @param route
|
|
29
|
+
*/
|
|
30
|
+
export declare function paramsOfRoute(route: Route): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Convert a route back to its original string
|
|
33
|
+
* @param route
|
|
34
|
+
*/
|
|
35
|
+
export declare function unparseRoute(route: Route): string;
|
|
36
|
+
/**
|
|
37
|
+
* Pretty-print a route
|
|
38
|
+
*/
|
|
39
|
+
export declare function debugUri(route: Route, color: (str: string) => string): string;
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a route by providing its required parameters
|
|
42
|
+
* @param route
|
|
43
|
+
* @param params
|
|
44
|
+
*/
|
|
45
|
+
export declare function resolveRoute(route: Route, params: {
|
|
46
|
+
[name: string]: string;
|
|
47
|
+
}): string | Error;
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a route by providing its required parameters through a callback
|
|
50
|
+
* @param route
|
|
51
|
+
* @param paramsProvider
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveRouteWith(route: Route, paramsProvider: (param: string) => string | null): string | Error;
|