@avleon/cli 0.0.46 → 0.4.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/LICENSE +21 -0
- package/dist/bin.d.ts +2 -0
- package/dist/bin.js +10 -0
- package/dist/commands/build.d.ts +11 -0
- package/dist/commands/build.js +65 -0
- package/dist/commands/doctor.d.ts +10 -0
- package/dist/commands/doctor.js +96 -0
- package/dist/commands/new.d.ts +19 -0
- package/dist/commands/new.js +306 -0
- package/dist/commands/route-list.d.ts +19 -0
- package/dist/commands/route-list.js +160 -0
- package/dist/commands/serve.d.ts +17 -0
- package/dist/commands/serve.js +238 -0
- package/dist/commands/start.d.ts +10 -0
- package/dist/commands/start.js +43 -0
- package/dist/compiler.d.ts +24 -0
- package/dist/compiler.js +83 -0
- package/dist/errors.d.ts +8 -0
- package/dist/errors.js +16 -0
- package/dist/generators/make.d.ts +24 -0
- package/dist/generators/make.js +157 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +40 -15
- package/dist/program.d.ts +22 -0
- package/dist/program.js +178 -0
- package/dist/utils/entry.d.ts +15 -0
- package/dist/utils/entry.js +55 -0
- package/dist/utils/env-types.d.ts +8 -0
- package/dist/utils/env-types.js +19 -0
- package/dist/utils/log.d.ts +25 -0
- package/dist/utils/log.js +39 -0
- package/dist/utils/names.d.ts +27 -0
- package/dist/utils/names.js +58 -0
- package/dist/utils/process.d.ts +18 -0
- package/dist/utils/process.js +84 -0
- package/dist/utils/project.d.ts +17 -0
- package/dist/utils/project.js +91 -0
- package/dist/utils/stubs.d.ts +15 -0
- package/dist/utils/stubs.js +52 -0
- package/dist/utils/tsconfig.d.ts +13 -0
- package/dist/utils/tsconfig.js +102 -0
- package/package.json +63 -62
- package/readme.md +155 -66
- package/stubs/config/config.stub +9 -0
- package/stubs/controllers/basic-controller.stub +9 -12
- package/stubs/controllers/resource-controller.stub +45 -0
- package/stubs/controllers/rest-controller.stub +29 -34
- package/stubs/dtos/dto.stub +11 -0
- package/stubs/middlewares/middleware.stub +9 -0
- package/stubs/models/basic-model.stub +4 -6
- package/stubs/models/entity-model.stub +16 -23
- package/stubs/project/app-minimal.stub +7 -0
- package/stubs/project/app.stub +8 -0
- package/stubs/project/env.stub +3 -0
- package/stubs/project/gitignore.stub +5 -0
- package/stubs/project/home.controller.spec.stub +19 -0
- package/stubs/project/home.controller.stub +12 -0
- package/stubs/project/home.service.stub +8 -0
- package/stubs/project/openapi.config.stub +15 -0
- package/stubs/project/readme.stub +26 -0
- package/stubs/project/serve.stub +10 -0
- package/stubs/project/tsconfig.build.stub +4 -0
- package/stubs/project/tsconfig.stub +18 -0
- package/stubs/project/vitest-e2e.config.stub +10 -0
- package/stubs/project/vitest.config.stub +17 -0
- package/stubs/services/basic-service.stub +8 -9
- package/stubs/services/orm-rest-service.stub +61 -73
- package/stubs/services/rest-service.stub +34 -71
- package/dist/av-cli.js +0 -60
- package/dist/avcli.js +0 -26
- package/dist/cli.interface.js +0 -2
- package/dist/cli.js +0 -358
- package/dist/commands.js +0 -55
- package/dist/controller.js +0 -92
- package/dist/create.js +0 -498
- package/dist/helpers/file-helper.js +0 -30
- package/dist/helpers/path-helper.js +0 -21
- package/dist/paths.js +0 -32
- package/dist/scripts/serve.js +0 -290
- package/dist/serve.js +0 -311
- package/dist/service.js +0 -73
- package/stubs/app/app-controller.stub +0 -11
- package/stubs/app/app-minimal.stub +0 -17
- package/stubs/app/app-withdb.stub +0 -0
- package/stubs/basic-controller.stub +0 -7
- package/stubs/config.stub +0 -11
- package/stubs/controllers/orm-rest-controller.stub +0 -52
- package/stubs/model.stub +0 -0
- package/stubs/serve.stub +0 -10
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.makeModel = makeModel;
|
|
7
|
+
exports.makeService = makeService;
|
|
8
|
+
exports.makeController = makeController;
|
|
9
|
+
exports.makeConfig = makeConfig;
|
|
10
|
+
exports.makeMiddleware = makeMiddleware;
|
|
11
|
+
exports.makeDto = makeDto;
|
|
12
|
+
const fs_1 = __importDefault(require("fs"));
|
|
13
|
+
const path_1 = __importDefault(require("path"));
|
|
14
|
+
const errors_1 = require("../errors");
|
|
15
|
+
const log_1 = require("../utils/log");
|
|
16
|
+
const names_1 = require("../utils/names");
|
|
17
|
+
const project_1 = require("../utils/project");
|
|
18
|
+
const stubs_1 = require("../utils/stubs");
|
|
19
|
+
const DEFAULT_DIRS = {
|
|
20
|
+
model: "models",
|
|
21
|
+
service: "services",
|
|
22
|
+
controller: "controllers",
|
|
23
|
+
config: "config",
|
|
24
|
+
middleware: "middlewares",
|
|
25
|
+
dto: "dtos",
|
|
26
|
+
};
|
|
27
|
+
function targetDir(projectRoot, kind, dirs, root) {
|
|
28
|
+
const folder = root ? root.split(/[\\/]+/).filter(Boolean) : [DEFAULT_DIRS[kind]];
|
|
29
|
+
if (folder.some((p) => p === ".."))
|
|
30
|
+
throw new errors_1.CliError(`Invalid --root "${root}".`);
|
|
31
|
+
return path_1.default.join(projectRoot, "src", ...folder, ...dirs);
|
|
32
|
+
}
|
|
33
|
+
/** A relative module specifier from `fromFile` to `toFile` (without extension), always using `/`. */
|
|
34
|
+
function importPath(fromFile, toFile) {
|
|
35
|
+
let rel = path_1.default.relative(path_1.default.dirname(fromFile), toFile).replace(/\.ts$/, "").split(path_1.default.sep).join("/");
|
|
36
|
+
if (!rel.startsWith("."))
|
|
37
|
+
rel = "./" + rel;
|
|
38
|
+
return rel;
|
|
39
|
+
}
|
|
40
|
+
function write(file, content, force, label, projectRoot) {
|
|
41
|
+
(0, project_1.writeFileSafe)(file, content, force);
|
|
42
|
+
log_1.log.success(`${label} created: ${path_1.default.relative(projectRoot, file).split(path_1.default.sep).join("/")}`);
|
|
43
|
+
return file;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Write a dependency of the requested file (the model behind a service, or the
|
|
47
|
+
* service behind a controller). An existing file is always kept and reused.
|
|
48
|
+
*/
|
|
49
|
+
function ensureDependency(file, render, label, projectRoot) {
|
|
50
|
+
const rel = path_1.default.relative(projectRoot, file).split(path_1.default.sep).join("/");
|
|
51
|
+
if (fs_1.default.existsSync(file)) {
|
|
52
|
+
log_1.log.info(` ${label} exists, reusing: ${rel}`);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
write(file, render(), false, label, projectRoot);
|
|
56
|
+
}
|
|
57
|
+
function makeModel(name, opts = {}) {
|
|
58
|
+
const projectRoot = (0, project_1.requireProjectRoot)(opts.cwd ?? process.cwd());
|
|
59
|
+
const n = (0, names_1.resolveName)(name, "Model");
|
|
60
|
+
const file = path_1.default.join(targetDir(projectRoot, "model", n.dirs, opts.root), `${n.fileBase}.model.ts`);
|
|
61
|
+
return write(file, renderModel(n.base, opts.orm), opts.force, "Model", projectRoot);
|
|
62
|
+
}
|
|
63
|
+
function renderModel(model, orm) {
|
|
64
|
+
return (0, stubs_1.renderStub)(orm ? "models/entity-model.stub" : "models/basic-model.stub", {
|
|
65
|
+
Model: model,
|
|
66
|
+
table: (0, names_1.snakeCase)(model),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Write a resource service for `model` at `serviceFile`, plus the model under
|
|
71
|
+
* `src/models` if it does not exist yet, so the generated code compiles.
|
|
72
|
+
*/
|
|
73
|
+
function writeResourceService(projectRoot, serviceFile, serviceClass, model, orm, force, asDependency) {
|
|
74
|
+
const m = (0, names_1.resolveName)(model, "Model");
|
|
75
|
+
const modelFile = path_1.default.join(targetDir(projectRoot, "model", m.dirs), `${m.fileBase}.model.ts`);
|
|
76
|
+
const render = () => (0, stubs_1.renderStub)(orm ? "services/orm-rest-service.stub" : "services/rest-service.stub", {
|
|
77
|
+
ClassName: serviceClass,
|
|
78
|
+
Model: m.base,
|
|
79
|
+
modelVar: m.varName,
|
|
80
|
+
modelImport: importPath(serviceFile, modelFile),
|
|
81
|
+
});
|
|
82
|
+
if (asDependency)
|
|
83
|
+
ensureDependency(serviceFile, render, "Service", projectRoot);
|
|
84
|
+
else
|
|
85
|
+
write(serviceFile, render(), force, "Service", projectRoot);
|
|
86
|
+
ensureDependency(modelFile, () => renderModel(m.base, orm), "Model", projectRoot);
|
|
87
|
+
if (orm && !(0, project_1.installedVersion)("@avleon/data", projectRoot)) {
|
|
88
|
+
log_1.log.warn("The generated service uses @avleon/data. Install it: npm install @avleon/data typeorm");
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
function makeService(name, opts = {}) {
|
|
92
|
+
const projectRoot = (0, project_1.requireProjectRoot)(opts.cwd ?? process.cwd());
|
|
93
|
+
const n = (0, names_1.resolveName)(name, "Service");
|
|
94
|
+
const file = path_1.default.join(targetDir(projectRoot, "service", n.dirs, opts.root), `${n.fileBase}.service.ts`);
|
|
95
|
+
if (opts.resource && !opts.model) {
|
|
96
|
+
throw new errors_1.CliError("A resource service needs a model: pass -m <model> (or --model <model>).");
|
|
97
|
+
}
|
|
98
|
+
if (opts.model) {
|
|
99
|
+
writeResourceService(projectRoot, file, n.className, opts.model, opts.orm, opts.force, false);
|
|
100
|
+
return file;
|
|
101
|
+
}
|
|
102
|
+
return write(file, (0, stubs_1.renderStub)("services/basic-service.stub", { ClassName: n.className }), opts.force, "Service", projectRoot);
|
|
103
|
+
}
|
|
104
|
+
function makeController(name, opts = {}) {
|
|
105
|
+
const projectRoot = (0, project_1.requireProjectRoot)(opts.cwd ?? process.cwd());
|
|
106
|
+
const n = (0, names_1.resolveName)(name, "Controller");
|
|
107
|
+
const file = path_1.default.join(targetDir(projectRoot, "controller", n.dirs, opts.root), `${n.fileBase}.controller.ts`);
|
|
108
|
+
if (fs_1.default.existsSync(file) && !opts.force) {
|
|
109
|
+
throw new errors_1.CliError(`${file} already exists. Use -f or --force to overwrite it.`);
|
|
110
|
+
}
|
|
111
|
+
const route = [...n.dirs, `${n.fileBase}s`].join("/");
|
|
112
|
+
let content;
|
|
113
|
+
if (opts.model) {
|
|
114
|
+
const m = (0, names_1.resolveName)(opts.model, "Model");
|
|
115
|
+
const serviceClass = `${m.base}Service`;
|
|
116
|
+
const serviceFile = path_1.default.join(targetDir(projectRoot, "service", []), `${m.fileBase}.service.ts`);
|
|
117
|
+
content = (0, stubs_1.renderStub)("controllers/resource-controller.stub", {
|
|
118
|
+
ClassName: n.className,
|
|
119
|
+
route,
|
|
120
|
+
Model: m.base,
|
|
121
|
+
modelVar: m.varName,
|
|
122
|
+
ServiceClass: serviceClass,
|
|
123
|
+
serviceVar: `${m.varName}Service`,
|
|
124
|
+
serviceImport: importPath(file, serviceFile),
|
|
125
|
+
});
|
|
126
|
+
// Dependencies first, so a failure leaves no controller pointing at missing files.
|
|
127
|
+
writeResourceService(projectRoot, serviceFile, serviceClass, opts.model, opts.orm, false, true);
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
const stub = opts.resource ? "controllers/rest-controller.stub" : "controllers/basic-controller.stub";
|
|
131
|
+
content = (0, stubs_1.renderStub)(stub, { ClassName: n.className, route });
|
|
132
|
+
}
|
|
133
|
+
if (opts.basePath) {
|
|
134
|
+
content = content.replace(/@ApiController\s*\(([^)]*)\)/, "@ApiController");
|
|
135
|
+
}
|
|
136
|
+
write(file, content, opts.force, "Controller", projectRoot);
|
|
137
|
+
log_1.log.info(` Register it in your app: app.useControllers([..., ${n.className}])`);
|
|
138
|
+
return file;
|
|
139
|
+
}
|
|
140
|
+
function makeConfig(name, opts = {}) {
|
|
141
|
+
const projectRoot = (0, project_1.requireProjectRoot)(opts.cwd ?? process.cwd());
|
|
142
|
+
const n = (0, names_1.resolveName)(name, "Config");
|
|
143
|
+
const file = path_1.default.join(targetDir(projectRoot, "config", n.dirs, opts.root), `${n.fileBase}.config.ts`);
|
|
144
|
+
return write(file, (0, stubs_1.renderStub)("config/config.stub", { ClassName: n.className }), opts.force, "Config", projectRoot);
|
|
145
|
+
}
|
|
146
|
+
function makeMiddleware(name, opts = {}) {
|
|
147
|
+
const projectRoot = (0, project_1.requireProjectRoot)(opts.cwd ?? process.cwd());
|
|
148
|
+
const n = (0, names_1.resolveName)(name, "Middleware");
|
|
149
|
+
const file = path_1.default.join(targetDir(projectRoot, "middleware", n.dirs, opts.root), `${n.fileBase}.middleware.ts`);
|
|
150
|
+
return write(file, (0, stubs_1.renderStub)("middlewares/middleware.stub", { ClassName: n.className }), opts.force, "Middleware", projectRoot);
|
|
151
|
+
}
|
|
152
|
+
function makeDto(name, opts = {}) {
|
|
153
|
+
const projectRoot = (0, project_1.requireProjectRoot)(opts.cwd ?? process.cwd());
|
|
154
|
+
const n = (0, names_1.resolveName)(name, "Dto");
|
|
155
|
+
const file = path_1.default.join(targetDir(projectRoot, "dto", n.dirs, opts.root), `${n.fileBase}.dto.ts`);
|
|
156
|
+
return write(file, (0, stubs_1.renderStub)("dtos/dto.stub", { ClassName: n.className }), opts.force, "DTO", projectRoot);
|
|
157
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Library entry for `@avleon/cli`. Importing it has no side effects; the
|
|
3
|
+
* executable lives in `bin.ts`.
|
|
4
|
+
*/
|
|
5
|
+
export { runCli, createProgram, normalizeArgv } from "./program";
|
|
6
|
+
export type { RunOptions } from "./program";
|
|
7
|
+
export { CliError } from "./errors";
|
|
8
|
+
export { createApplication } from "./commands/new";
|
|
9
|
+
export type { NewOptions } from "./commands/new";
|
|
10
|
+
export { build } from "./commands/build";
|
|
11
|
+
export { serve } from "./commands/serve";
|
|
12
|
+
export { start } from "./commands/start";
|
|
13
|
+
export { doctor, runChecks } from "./commands/doctor";
|
|
14
|
+
export { routeList, scanRoutes } from "./commands/route-list";
|
|
15
|
+
export { makeModel, makeController, makeService, makeConfig, makeMiddleware, makeDto, } from "./generators/make";
|
|
16
|
+
export { resolveName, pascalCase, camelCase, kebabCase, snakeCase } from "./utils/names";
|
|
17
|
+
export { findProjectRoot } from "./utils/project";
|
package/dist/index.js
CHANGED
|
@@ -1,17 +1,42 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
-
if (k2 === undefined) k2 = k;
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
-
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
-
};
|
|
16
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
|
|
3
|
+
exports.findProjectRoot = exports.snakeCase = exports.kebabCase = exports.camelCase = exports.pascalCase = exports.resolveName = exports.makeDto = exports.makeMiddleware = exports.makeConfig = exports.makeService = exports.makeController = exports.makeModel = exports.scanRoutes = exports.routeList = exports.runChecks = exports.doctor = exports.start = exports.serve = exports.build = exports.createApplication = exports.CliError = exports.normalizeArgv = exports.createProgram = exports.runCli = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Library entry for `@avleon/cli`. Importing it has no side effects; the
|
|
6
|
+
* executable lives in `bin.ts`.
|
|
7
|
+
*/
|
|
8
|
+
var program_1 = require("./program");
|
|
9
|
+
Object.defineProperty(exports, "runCli", { enumerable: true, get: function () { return program_1.runCli; } });
|
|
10
|
+
Object.defineProperty(exports, "createProgram", { enumerable: true, get: function () { return program_1.createProgram; } });
|
|
11
|
+
Object.defineProperty(exports, "normalizeArgv", { enumerable: true, get: function () { return program_1.normalizeArgv; } });
|
|
12
|
+
var errors_1 = require("./errors");
|
|
13
|
+
Object.defineProperty(exports, "CliError", { enumerable: true, get: function () { return errors_1.CliError; } });
|
|
14
|
+
var new_1 = require("./commands/new");
|
|
15
|
+
Object.defineProperty(exports, "createApplication", { enumerable: true, get: function () { return new_1.createApplication; } });
|
|
16
|
+
var build_1 = require("./commands/build");
|
|
17
|
+
Object.defineProperty(exports, "build", { enumerable: true, get: function () { return build_1.build; } });
|
|
18
|
+
var serve_1 = require("./commands/serve");
|
|
19
|
+
Object.defineProperty(exports, "serve", { enumerable: true, get: function () { return serve_1.serve; } });
|
|
20
|
+
var start_1 = require("./commands/start");
|
|
21
|
+
Object.defineProperty(exports, "start", { enumerable: true, get: function () { return start_1.start; } });
|
|
22
|
+
var doctor_1 = require("./commands/doctor");
|
|
23
|
+
Object.defineProperty(exports, "doctor", { enumerable: true, get: function () { return doctor_1.doctor; } });
|
|
24
|
+
Object.defineProperty(exports, "runChecks", { enumerable: true, get: function () { return doctor_1.runChecks; } });
|
|
25
|
+
var route_list_1 = require("./commands/route-list");
|
|
26
|
+
Object.defineProperty(exports, "routeList", { enumerable: true, get: function () { return route_list_1.routeList; } });
|
|
27
|
+
Object.defineProperty(exports, "scanRoutes", { enumerable: true, get: function () { return route_list_1.scanRoutes; } });
|
|
28
|
+
var make_1 = require("./generators/make");
|
|
29
|
+
Object.defineProperty(exports, "makeModel", { enumerable: true, get: function () { return make_1.makeModel; } });
|
|
30
|
+
Object.defineProperty(exports, "makeController", { enumerable: true, get: function () { return make_1.makeController; } });
|
|
31
|
+
Object.defineProperty(exports, "makeService", { enumerable: true, get: function () { return make_1.makeService; } });
|
|
32
|
+
Object.defineProperty(exports, "makeConfig", { enumerable: true, get: function () { return make_1.makeConfig; } });
|
|
33
|
+
Object.defineProperty(exports, "makeMiddleware", { enumerable: true, get: function () { return make_1.makeMiddleware; } });
|
|
34
|
+
Object.defineProperty(exports, "makeDto", { enumerable: true, get: function () { return make_1.makeDto; } });
|
|
35
|
+
var names_1 = require("./utils/names");
|
|
36
|
+
Object.defineProperty(exports, "resolveName", { enumerable: true, get: function () { return names_1.resolveName; } });
|
|
37
|
+
Object.defineProperty(exports, "pascalCase", { enumerable: true, get: function () { return names_1.pascalCase; } });
|
|
38
|
+
Object.defineProperty(exports, "camelCase", { enumerable: true, get: function () { return names_1.camelCase; } });
|
|
39
|
+
Object.defineProperty(exports, "kebabCase", { enumerable: true, get: function () { return names_1.kebabCase; } });
|
|
40
|
+
Object.defineProperty(exports, "snakeCase", { enumerable: true, get: function () { return names_1.snakeCase; } });
|
|
41
|
+
var project_1 = require("./utils/project");
|
|
42
|
+
Object.defineProperty(exports, "findProjectRoot", { enumerable: true, get: function () { return project_1.findProjectRoot; } });
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Command } from "commander";
|
|
2
|
+
export type RunOptions = {
|
|
3
|
+
/** Working directory for the command. Defaults to `process.cwd()`. */
|
|
4
|
+
cwd?: string;
|
|
5
|
+
/** Override where commander writes help and errors (used by tests). */
|
|
6
|
+
writeOut?: (s: string) => void;
|
|
7
|
+
writeErr?: (s: string) => void;
|
|
8
|
+
};
|
|
9
|
+
/**
|
|
10
|
+
* Legacy spellings commander cannot express directly: `-rt` (multi-letter
|
|
11
|
+
* short flag) and `--rest` (second long name for `--resource`).
|
|
12
|
+
*/
|
|
13
|
+
export declare function normalizeArgv(args: string[]): string[];
|
|
14
|
+
export declare function createProgram(run?: RunOptions): {
|
|
15
|
+
program: Command;
|
|
16
|
+
exitCode: () => number;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Parse and run a command line (without the `node` and script entries).
|
|
20
|
+
* Resolves to the process exit code instead of exiting, so it can be tested.
|
|
21
|
+
*/
|
|
22
|
+
export declare function runCli(args: string[], run?: RunOptions): Promise<number>;
|
package/dist/program.js
ADDED
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.normalizeArgv = normalizeArgv;
|
|
4
|
+
exports.createProgram = createProgram;
|
|
5
|
+
exports.runCli = runCli;
|
|
6
|
+
const commander_1 = require("commander");
|
|
7
|
+
const build_1 = require("./commands/build");
|
|
8
|
+
const doctor_1 = require("./commands/doctor");
|
|
9
|
+
const new_1 = require("./commands/new");
|
|
10
|
+
const route_list_1 = require("./commands/route-list");
|
|
11
|
+
const serve_1 = require("./commands/serve");
|
|
12
|
+
const start_1 = require("./commands/start");
|
|
13
|
+
const errors_1 = require("./errors");
|
|
14
|
+
const make_1 = require("./generators/make");
|
|
15
|
+
const log_1 = require("./utils/log");
|
|
16
|
+
const stubs_1 = require("./utils/stubs");
|
|
17
|
+
/**
|
|
18
|
+
* Legacy spellings commander cannot express directly: `-rt` (multi-letter
|
|
19
|
+
* short flag) and `--rest` (second long name for `--resource`).
|
|
20
|
+
*/
|
|
21
|
+
function normalizeArgv(args) {
|
|
22
|
+
return args.map((a) => (a === "-rt" ? "--root" : a === "--rest" ? "--resource" : a));
|
|
23
|
+
}
|
|
24
|
+
function parseInteger(value) {
|
|
25
|
+
const n = Number(value);
|
|
26
|
+
if (!Number.isInteger(n) || n < 0)
|
|
27
|
+
throw new commander_1.InvalidArgumentError("Expected a non-negative integer.");
|
|
28
|
+
return n;
|
|
29
|
+
}
|
|
30
|
+
function parseList(value) {
|
|
31
|
+
return value
|
|
32
|
+
.split(",")
|
|
33
|
+
.map((s) => s.trim())
|
|
34
|
+
.filter(Boolean);
|
|
35
|
+
}
|
|
36
|
+
function createProgram(run = {}) {
|
|
37
|
+
const cwd = () => run.cwd ?? process.cwd();
|
|
38
|
+
let exitCode = 0;
|
|
39
|
+
const program = new commander_1.Command();
|
|
40
|
+
program
|
|
41
|
+
.name("avleon")
|
|
42
|
+
.description("Scaffold, run and build Avleon applications.")
|
|
43
|
+
.version((0, stubs_1.cliVersion)(), "-v, --version", "Print the CLI version")
|
|
44
|
+
.helpOption("-h, --help", "Show help")
|
|
45
|
+
.helpCommand("help [command]", "Show help for a command")
|
|
46
|
+
.showHelpAfterError("(run `avleon --help` for usage)")
|
|
47
|
+
.showSuggestionAfterError(true)
|
|
48
|
+
.exitOverride();
|
|
49
|
+
if (run.writeOut || run.writeErr) {
|
|
50
|
+
program.configureOutput({
|
|
51
|
+
...(run.writeOut ? { writeOut: run.writeOut } : {}),
|
|
52
|
+
...(run.writeErr ? { writeErr: run.writeErr } : {}),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
const sub = (name, description) => {
|
|
56
|
+
const cmd = program.command(name).description(description).helpOption("-h, --help", "Show help");
|
|
57
|
+
cmd.exitOverride();
|
|
58
|
+
if (run.writeOut || run.writeErr)
|
|
59
|
+
cmd.configureOutput(program.configureOutput());
|
|
60
|
+
return cmd;
|
|
61
|
+
};
|
|
62
|
+
// ── Project ─────────────────────────────────────────────────────────────
|
|
63
|
+
sub("new", "Create a new Avleon application")
|
|
64
|
+
.argument("<name>", "Project directory (created if missing); `.` for the current directory")
|
|
65
|
+
.option("-m, --minimal", "Minimal app: a single functional route, no controllers, services or tests")
|
|
66
|
+
.option("-f, --force", "Scaffold into a non-empty directory, overwriting generated files")
|
|
67
|
+
.option("-y, --yes", "Skip prompts and use defaults (npm, openapi)")
|
|
68
|
+
.option("--pm <manager>", `Package manager: ${new_1.PACKAGE_MANAGERS.join(", ")}`)
|
|
69
|
+
.option("--features <list>", `Comma-separated features: ${new_1.FEATURES.join(", ")}`, parseList)
|
|
70
|
+
.option("--skip-install", "Do not install dependencies (or set AVLEON_SKIP_INSTALL=1)")
|
|
71
|
+
.action(async (name, o) => {
|
|
72
|
+
await (0, new_1.createApplication)(name, { cwd: cwd(), ...o });
|
|
73
|
+
});
|
|
74
|
+
sub("serve", "Start the dev server: compile src/ with SWC, run the app, reload on changes")
|
|
75
|
+
.option("--entry <file>", "Entry file, overriding avleon.entry / main in package.json")
|
|
76
|
+
.option("--no-type-check", "Do not run `tsc --noEmit --watch` alongside the server")
|
|
77
|
+
.option("--debounce <ms>", "Wait this long for more file changes before reloading", parseInteger, 200)
|
|
78
|
+
.action(async (o) => {
|
|
79
|
+
await (0, serve_1.serve)({ cwd: cwd(), entry: o.entry, typeCheck: o.typeCheck, debounce: o.debounce });
|
|
80
|
+
});
|
|
81
|
+
sub("build", "Compile with tsc (tsconfig.build.json, else tsconfig.json) and copy assets")
|
|
82
|
+
.option("-p, --project <file>", "Use this tsconfig instead")
|
|
83
|
+
.action(async (o) => {
|
|
84
|
+
await (0, build_1.build)({ cwd: cwd(), project: o.project });
|
|
85
|
+
});
|
|
86
|
+
sub("start", "Run the compiled app in production (NODE_ENV=production unless set)")
|
|
87
|
+
.option("--entry <file>", "Entry file, overriding avleon.entry / main in package.json")
|
|
88
|
+
.action(async (o) => {
|
|
89
|
+
exitCode = await (0, start_1.start)({ cwd: cwd(), entry: o.entry });
|
|
90
|
+
});
|
|
91
|
+
sub("doctor", "Check Node.js, @avleon/core, reflect-metadata and decorator settings")
|
|
92
|
+
.action(() => {
|
|
93
|
+
exitCode = (0, doctor_1.doctor)(cwd());
|
|
94
|
+
});
|
|
95
|
+
sub("route:list", "List the app's routes")
|
|
96
|
+
.alias("routes")
|
|
97
|
+
.option("--json", "Print JSON")
|
|
98
|
+
.option("--static", "Scan @ApiController/@Get/@Post/... decorators in src/**/*.controller.ts instead of loading the code")
|
|
99
|
+
.addHelpText("after", "\nBy default the sources are compiled with SWC to node_modules/.cache/avleon and each\n" +
|
|
100
|
+
"*.controller.ts is loaded in a child process to read Avleon's route metadata, so\n" +
|
|
101
|
+
"@avleon/core must be installed. --static needs no dependencies but only understands\n" +
|
|
102
|
+
"string-literal paths.")
|
|
103
|
+
.action((o) => {
|
|
104
|
+
(0, route_list_1.routeList)({ cwd: cwd(), json: o.json, static: o.static });
|
|
105
|
+
});
|
|
106
|
+
// ── Generators ──────────────────────────────────────────────────────────
|
|
107
|
+
const make = (name, aliases, description) => sub(name, description)
|
|
108
|
+
.aliases(aliases)
|
|
109
|
+
.argument("<name>", "Name, optionally nested (e.g. admin/User)")
|
|
110
|
+
.option("-f, --force", "Overwrite the file if it exists");
|
|
111
|
+
make("make:model", ["m:m"], "Create a model in src/models/<name>.model.ts")
|
|
112
|
+
.option("--orm", "Generate a TypeORM entity")
|
|
113
|
+
.option("--root <dir>", "Folder under src/ to write to (also -rt)")
|
|
114
|
+
.action((name, o) => {
|
|
115
|
+
(0, make_1.makeModel)(name, { cwd: cwd(), ...o });
|
|
116
|
+
});
|
|
117
|
+
make("make:controller", ["m:c"], "Create a controller in src/controllers/<name>.controller.ts")
|
|
118
|
+
.option("-r, --resource", "Generate a REST skeleton (also --rest)")
|
|
119
|
+
.option("-m, --model <model>", "Back a REST controller with <model>: also creates its service and model if missing")
|
|
120
|
+
.option("--orm", "With -m, back the service with a TypeORM repository and entity")
|
|
121
|
+
.option("--root <dir>", "Folder under src/ to write to (also -rt)")
|
|
122
|
+
.option("--base-path", "Use @ApiController without a path prefix")
|
|
123
|
+
.action((name, o) => {
|
|
124
|
+
(0, make_1.makeController)(name, { cwd: cwd(), ...o });
|
|
125
|
+
});
|
|
126
|
+
make("make:service", ["m:s"], "Create a service in src/services/<name>.service.ts")
|
|
127
|
+
.option("-r, --resource", "Generate a resource (CRUD) service; requires -m (also --rest)")
|
|
128
|
+
.option("-m, --model <model>", "Model for a resource service; creates the model if missing")
|
|
129
|
+
.option("--orm", "Back the resource service with a TypeORM repository and entity")
|
|
130
|
+
.option("--root <dir>", "Folder under src/ to write to (also -rt)")
|
|
131
|
+
.action((name, o) => {
|
|
132
|
+
(0, make_1.makeService)(name, { cwd: cwd(), ...o });
|
|
133
|
+
});
|
|
134
|
+
make("make:config", ["m:cnf", "m:cfg"], "Create an @AppConfig class in src/config/<name>.config.ts")
|
|
135
|
+
.option("--root <dir>", "Folder under src/ to write to (also -rt)")
|
|
136
|
+
.action((name, o) => {
|
|
137
|
+
(0, make_1.makeConfig)(name, { cwd: cwd(), ...o });
|
|
138
|
+
});
|
|
139
|
+
make("make:middleware", ["m:mlwr", "m:mdlr"], "Create a middleware in src/middlewares/<name>.middleware.ts")
|
|
140
|
+
.option("--root <dir>", "Folder under src/ to write to (also -rt)")
|
|
141
|
+
.action((name, o) => {
|
|
142
|
+
(0, make_1.makeMiddleware)(name, { cwd: cwd(), ...o });
|
|
143
|
+
});
|
|
144
|
+
make("make:dto", ["m:dto"], "Create a class-validator DTO in src/dtos/<name>.dto.ts")
|
|
145
|
+
.option("--root <dir>", "Folder under src/ to write to (also -rt)")
|
|
146
|
+
.action((name, o) => {
|
|
147
|
+
(0, make_1.makeDto)(name, { cwd: cwd(), ...o });
|
|
148
|
+
});
|
|
149
|
+
return { program, exitCode: () => exitCode };
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Parse and run a command line (without the `node` and script entries).
|
|
153
|
+
* Resolves to the process exit code instead of exiting, so it can be tested.
|
|
154
|
+
*/
|
|
155
|
+
async function runCli(args, run = {}) {
|
|
156
|
+
const { program, exitCode } = createProgram(run);
|
|
157
|
+
const argv = normalizeArgv(args);
|
|
158
|
+
if (argv.length === 0) {
|
|
159
|
+
program.outputHelp();
|
|
160
|
+
return 0;
|
|
161
|
+
}
|
|
162
|
+
try {
|
|
163
|
+
await program.parseAsync(argv, { from: "user" });
|
|
164
|
+
return exitCode();
|
|
165
|
+
}
|
|
166
|
+
catch (err) {
|
|
167
|
+
if (err instanceof commander_1.CommanderError) {
|
|
168
|
+
// Help and version are reported as "errors" with exit code 0.
|
|
169
|
+
return err.exitCode;
|
|
170
|
+
}
|
|
171
|
+
if (err instanceof errors_1.CliError) {
|
|
172
|
+
log_1.log.error(err.message);
|
|
173
|
+
return err.exitCode;
|
|
174
|
+
}
|
|
175
|
+
log_1.log.error(err instanceof Error ? (err.stack ?? err.message) : String(err));
|
|
176
|
+
return 1;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export type ProjectLayout = {
|
|
2
|
+
root: string;
|
|
3
|
+
srcDir: string;
|
|
4
|
+
outDir: string;
|
|
5
|
+
compilerOptions: Record<string, any>;
|
|
6
|
+
tsconfig: string | null;
|
|
7
|
+
};
|
|
8
|
+
export declare function projectLayout(root: string, preferBuildConfig?: boolean): ProjectLayout;
|
|
9
|
+
/**
|
|
10
|
+
* Candidate entry files, most specific first: `--entry`, `avleon.entry` in
|
|
11
|
+
* package.json, `main` (mapped from `src/*.ts` to the output dir), then the
|
|
12
|
+
* conventional names in the output dir.
|
|
13
|
+
*/
|
|
14
|
+
export declare function entryCandidates(layout: ProjectLayout, pkg: Record<string, any>, explicit?: string): string[];
|
|
15
|
+
export declare function resolveEntry(candidates: string[], explicit?: string): string | null;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.projectLayout = projectLayout;
|
|
7
|
+
exports.entryCandidates = entryCandidates;
|
|
8
|
+
exports.resolveEntry = resolveEntry;
|
|
9
|
+
const fs_1 = __importDefault(require("fs"));
|
|
10
|
+
const path_1 = __importDefault(require("path"));
|
|
11
|
+
const tsconfig_1 = require("./tsconfig");
|
|
12
|
+
function projectLayout(root, preferBuildConfig = false) {
|
|
13
|
+
const tsconfig = (0, tsconfig_1.findTsConfig)(root, preferBuildConfig);
|
|
14
|
+
const compilerOptions = tsconfig ? (0, tsconfig_1.readTsConfig)(tsconfig).compilerOptions : {};
|
|
15
|
+
return {
|
|
16
|
+
root,
|
|
17
|
+
tsconfig,
|
|
18
|
+
compilerOptions,
|
|
19
|
+
srcDir: compilerOptions.rootDir ?? path_1.default.join(root, "src"),
|
|
20
|
+
outDir: compilerOptions.outDir ?? path_1.default.join(root, "dist"),
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const DEFAULT_ENTRIES = ["serve.js", "server.js", "main.js", "index.js"];
|
|
24
|
+
/**
|
|
25
|
+
* Candidate entry files, most specific first: `--entry`, `avleon.entry` in
|
|
26
|
+
* package.json, `main` (mapped from `src/*.ts` to the output dir), then the
|
|
27
|
+
* conventional names in the output dir.
|
|
28
|
+
*/
|
|
29
|
+
function entryCandidates(layout, pkg, explicit) {
|
|
30
|
+
const list = [];
|
|
31
|
+
const add = (p) => list.push(path_1.default.resolve(layout.root, p));
|
|
32
|
+
if (explicit)
|
|
33
|
+
add(explicit);
|
|
34
|
+
if (typeof pkg?.avleon?.entry === "string")
|
|
35
|
+
add(pkg.avleon.entry);
|
|
36
|
+
if (typeof pkg?.main === "string") {
|
|
37
|
+
const main = path_1.default.resolve(layout.root, pkg.main);
|
|
38
|
+
const rel = path_1.default.relative(layout.srcDir, main);
|
|
39
|
+
if (!rel.startsWith("..") && !path_1.default.isAbsolute(rel)) {
|
|
40
|
+
add(path_1.default.join(layout.outDir, rel).replace(/\.ts$/, ".js"));
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
add(main);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const name of DEFAULT_ENTRIES)
|
|
47
|
+
add(path_1.default.join(layout.outDir, name));
|
|
48
|
+
return [...new Set(list)];
|
|
49
|
+
}
|
|
50
|
+
function resolveEntry(candidates, explicit) {
|
|
51
|
+
// An explicit --entry must exist itself; no silent fallback.
|
|
52
|
+
if (explicit)
|
|
53
|
+
return fs_1.default.existsSync(candidates[0]) ? candidates[0] : null;
|
|
54
|
+
return candidates.find((c) => fs_1.default.existsSync(c)) ?? null;
|
|
55
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/** File name of the generated declarations that load the app's plugin types. */
|
|
2
|
+
export declare const ENV_TYPES_FILE = "avleon-env.d.ts";
|
|
3
|
+
/**
|
|
4
|
+
* Contents of `avleon-env.d.ts`. Each Avleon plugin adds its app methods
|
|
5
|
+
* (such as `app.useKnex()` from `@avleon/data`) through declaration merging,
|
|
6
|
+
* which TypeScript only sees once the plugin's types are part of the project.
|
|
7
|
+
*/
|
|
8
|
+
export declare function envTypesFile(plugins: string[]): string;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ENV_TYPES_FILE = void 0;
|
|
4
|
+
exports.envTypesFile = envTypesFile;
|
|
5
|
+
/** File name of the generated declarations that load the app's plugin types. */
|
|
6
|
+
exports.ENV_TYPES_FILE = "avleon-env.d.ts";
|
|
7
|
+
/**
|
|
8
|
+
* Contents of `avleon-env.d.ts`. Each Avleon plugin adds its app methods
|
|
9
|
+
* (such as `app.useKnex()` from `@avleon/data`) through declaration merging,
|
|
10
|
+
* which TypeScript only sees once the plugin's types are part of the project.
|
|
11
|
+
*/
|
|
12
|
+
function envTypesFile(plugins) {
|
|
13
|
+
return [
|
|
14
|
+
"// Generated by the Avleon CLI. Do not edit: it is rewritten when plugins change.",
|
|
15
|
+
"// It loads the types of the Avleon plugins this app depends on.",
|
|
16
|
+
...[...plugins].sort().map((name) => `/// <reference types="${name}" />`),
|
|
17
|
+
"",
|
|
18
|
+
].join("\n");
|
|
19
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const c: {
|
|
2
|
+
dim: (s: string) => string;
|
|
3
|
+
bold: (s: string) => string;
|
|
4
|
+
cyan: (s: string) => string;
|
|
5
|
+
green: (s: string) => string;
|
|
6
|
+
yellow: (s: string) => string;
|
|
7
|
+
red: (s: string) => string;
|
|
8
|
+
white: (s: string) => string;
|
|
9
|
+
};
|
|
10
|
+
export declare const icon: {
|
|
11
|
+
success: string;
|
|
12
|
+
error: string;
|
|
13
|
+
warn: string;
|
|
14
|
+
arrow: string;
|
|
15
|
+
};
|
|
16
|
+
export declare const log: {
|
|
17
|
+
info: (msg: string) => void;
|
|
18
|
+
step: (label: string, detail?: string) => void;
|
|
19
|
+
success: (msg: string) => void;
|
|
20
|
+
warn: (msg: string) => void;
|
|
21
|
+
error: (msg: string) => void;
|
|
22
|
+
section: (title: string) => void;
|
|
23
|
+
};
|
|
24
|
+
/** Timestamped, category-prefixed logging used by the long-running commands. */
|
|
25
|
+
export declare function tagged(category: string, color?: (s: string) => string): (message: string) => void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.log = exports.icon = exports.c = void 0;
|
|
4
|
+
exports.tagged = tagged;
|
|
5
|
+
const useColor = !process.env.NO_COLOR && (process.env.FORCE_COLOR !== undefined || process.stdout.isTTY === true);
|
|
6
|
+
const code = (open) => (s) => (useColor ? `\x1b[${open}m${s}\x1b[0m` : s);
|
|
7
|
+
exports.c = {
|
|
8
|
+
dim: code("90"),
|
|
9
|
+
bold: code("1"),
|
|
10
|
+
cyan: code("36"),
|
|
11
|
+
green: code("32"),
|
|
12
|
+
yellow: code("33"),
|
|
13
|
+
red: code("31"),
|
|
14
|
+
white: code("37"),
|
|
15
|
+
};
|
|
16
|
+
exports.icon = {
|
|
17
|
+
success: exports.c.green("✔"),
|
|
18
|
+
error: exports.c.red("✖"),
|
|
19
|
+
warn: exports.c.yellow("⚠"),
|
|
20
|
+
arrow: exports.c.dim("→"),
|
|
21
|
+
};
|
|
22
|
+
exports.log = {
|
|
23
|
+
info: (msg) => console.log(msg),
|
|
24
|
+
step: (label, detail) => console.log(` ${exports.icon.arrow} ${label.padEnd(30, " ")}${detail ? exports.c.dim(detail) : ""}`),
|
|
25
|
+
success: (msg) => console.log(`${exports.icon.success} ${msg}`),
|
|
26
|
+
warn: (msg) => console.warn(`${exports.icon.warn} ${exports.c.yellow(msg)}`),
|
|
27
|
+
error: (msg) => console.error(`${exports.icon.error} ${exports.c.red(msg)}`),
|
|
28
|
+
section: (title) => {
|
|
29
|
+
console.log(`\n${exports.c.bold(exports.c.cyan(` ${title}`))}`);
|
|
30
|
+
console.log(` ${"─".repeat(40)}`);
|
|
31
|
+
},
|
|
32
|
+
};
|
|
33
|
+
/** Timestamped, category-prefixed logging used by the long-running commands. */
|
|
34
|
+
function tagged(category, color = exports.c.white) {
|
|
35
|
+
return (message) => {
|
|
36
|
+
const ts = new Date().toTimeString().split(" ")[0];
|
|
37
|
+
console.log(`${exports.c.dim(`[${ts}]`)} ${color(`[${category}]`)} ${message}`);
|
|
38
|
+
};
|
|
39
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/** Split an identifier into words: `JwtAuth`, `jwt-auth`, `jwt_auth` and `jwtAuth` all give `[jwt, auth]`. */
|
|
2
|
+
export declare function words(input: string): string[];
|
|
3
|
+
export declare const pascalCase: (input: string) => string;
|
|
4
|
+
export declare const camelCase: (input: string) => string;
|
|
5
|
+
export declare const kebabCase: (input: string) => string;
|
|
6
|
+
export declare const snakeCase: (input: string) => string;
|
|
7
|
+
/** Human-readable title, e.g. `my_api` -> `My Api`. */
|
|
8
|
+
export declare const titleCase: (input: string) => string;
|
|
9
|
+
export type ResolvedName = {
|
|
10
|
+
/** Sub-directories requested in the name, e.g. `["admin"]` for `admin/User`. */
|
|
11
|
+
dirs: string[];
|
|
12
|
+
/** PascalCase name without the suffix, e.g. `JwtAuth`. */
|
|
13
|
+
base: string;
|
|
14
|
+
/** PascalCase class name with the suffix, e.g. `JwtAuthConfig`. */
|
|
15
|
+
className: string;
|
|
16
|
+
/** camelCase base, e.g. `jwtAuth`. */
|
|
17
|
+
varName: string;
|
|
18
|
+
/** kebab-case base, e.g. `jwt-auth`. */
|
|
19
|
+
fileBase: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Resolve a user-supplied artifact name (optionally nested, e.g. `admin/User`
|
|
23
|
+
* or `admin\User`) into class and file names. A trailing suffix such as
|
|
24
|
+
* `Controller` is dropped before it is re-added, so `UserController` and `User`
|
|
25
|
+
* give the same result.
|
|
26
|
+
*/
|
|
27
|
+
export declare function resolveName(input: string, suffix?: string): ResolvedName;
|