@expressots/cli 3.0.0 ā 4.0.0-preview.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -95
- package/bin/cicd/cli.d.ts +6 -0
- package/bin/cicd/cli.js +126 -0
- package/bin/cicd/form.d.ts +29 -0
- package/bin/cicd/form.js +345 -0
- package/bin/cicd/generators/azure-devops.d.ts +2 -0
- package/bin/cicd/generators/azure-devops.js +370 -0
- package/bin/cicd/generators/bitbucket.d.ts +2 -0
- package/bin/cicd/generators/bitbucket.js +217 -0
- package/bin/cicd/generators/circleci.d.ts +2 -0
- package/bin/cicd/generators/circleci.js +274 -0
- package/bin/cicd/generators/github-actions.d.ts +14 -0
- package/bin/cicd/generators/github-actions.js +426 -0
- package/bin/cicd/generators/gitlab-ci.d.ts +2 -0
- package/bin/cicd/generators/gitlab-ci.js +237 -0
- package/bin/cicd/generators/index.d.ts +6 -0
- package/bin/cicd/generators/index.js +15 -0
- package/bin/cicd/generators/jenkins.d.ts +2 -0
- package/bin/cicd/generators/jenkins.js +248 -0
- package/bin/cicd/generators/template-loader.d.ts +17 -0
- package/bin/cicd/generators/template-loader.js +128 -0
- package/bin/cicd/index.d.ts +1 -0
- package/bin/cicd/index.js +5 -0
- package/bin/cli.d.ts +1 -1
- package/bin/cli.js +18 -3
- package/bin/commands/project.commands.d.ts +19 -6
- package/bin/commands/project.commands.js +390 -61
- package/bin/config/index.d.ts +5 -0
- package/bin/config/index.js +10 -0
- package/bin/config/manager.d.ts +98 -0
- package/bin/config/manager.js +222 -0
- package/bin/containerize/analyzers/bootstrap-analyzer.d.ts +46 -0
- package/bin/containerize/analyzers/bootstrap-analyzer.js +187 -0
- package/bin/containerize/analyzers/project-analyzer.d.ts +20 -0
- package/bin/containerize/analyzers/project-analyzer.js +150 -0
- package/bin/containerize/cli.d.ts +4 -0
- package/bin/containerize/cli.js +113 -0
- package/bin/containerize/form.d.ts +15 -0
- package/bin/containerize/form.js +154 -0
- package/bin/containerize/generators/ci-generator.d.ts +31 -0
- package/bin/containerize/generators/ci-generator.js +936 -0
- package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
- package/bin/containerize/generators/docker-compose-generator.js +186 -0
- package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
- package/bin/containerize/generators/dockerfile-generator.js +635 -0
- package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
- package/bin/containerize/generators/kubernetes-generator.js +133 -0
- package/bin/containerize/generators/template-loader.d.ts +36 -0
- package/bin/containerize/generators/template-loader.js +129 -0
- package/bin/containerize/index.d.ts +4 -0
- package/bin/containerize/index.js +13 -0
- package/bin/containerize/presets/preset-registry.d.ts +20 -0
- package/bin/containerize/presets/preset-registry.js +102 -0
- package/bin/costs/cli.d.ts +5 -0
- package/bin/costs/cli.js +183 -0
- package/bin/costs/form.d.ts +44 -0
- package/bin/costs/form.js +412 -0
- package/bin/costs/index.d.ts +4 -0
- package/bin/costs/index.js +25 -0
- package/bin/costs/pricing-manager.d.ts +84 -0
- package/bin/costs/pricing-manager.js +342 -0
- package/bin/costs/providers/index.d.ts +32 -0
- package/bin/costs/providers/index.js +153 -0
- package/bin/costs/sources/api-source.d.ts +10 -0
- package/bin/costs/sources/api-source.js +32 -0
- package/bin/costs/sources/index.d.ts +6 -0
- package/bin/costs/sources/index.js +15 -0
- package/bin/costs/sources/local-json-source.d.ts +23 -0
- package/bin/costs/sources/local-json-source.js +59 -0
- package/bin/costs/sources/remote-json-source.d.ts +11 -0
- package/bin/costs/sources/remote-json-source.js +53 -0
- package/bin/costs/types.d.ts +53 -0
- package/bin/costs/types.js +5 -0
- package/bin/dev/cli.d.ts +4 -0
- package/bin/dev/cli.js +134 -0
- package/bin/dev/form.d.ts +36 -0
- package/bin/dev/form.js +254 -0
- package/bin/dev/index.d.ts +1 -0
- package/bin/dev/index.js +5 -0
- package/bin/generate/cli.js +29 -2
- package/bin/generate/form.d.ts +5 -1
- package/bin/generate/form.js +3 -3
- package/bin/generate/templates/nonopinionated/config.tpl +12 -0
- package/bin/generate/templates/nonopinionated/event.tpl +10 -0
- package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
- package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
- package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
- package/bin/generate/templates/opinionated/config.tpl +47 -0
- package/bin/generate/templates/opinionated/entity.tpl +1 -8
- package/bin/generate/templates/opinionated/event.tpl +15 -0
- package/bin/generate/templates/opinionated/guard.tpl +41 -0
- package/bin/generate/templates/opinionated/handler.tpl +23 -0
- package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
- package/bin/generate/utils/command-utils.d.ts +7 -3
- package/bin/generate/utils/command-utils.js +95 -31
- package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
- package/bin/generate/utils/nonopininated-cmd.js +100 -1
- package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
- package/bin/generate/utils/opinionated-cmd.js +112 -7
- package/bin/generate/utils/string-utils.d.ts +6 -0
- package/bin/generate/utils/string-utils.js +13 -1
- package/bin/help/form.js +11 -3
- package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
- package/bin/migrate/analyzers/platform-detector.js +116 -0
- package/bin/migrate/cli.d.ts +6 -0
- package/bin/migrate/cli.js +96 -0
- package/bin/migrate/form.d.ts +25 -0
- package/bin/migrate/form.js +347 -0
- package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
- package/bin/migrate/generators/compose-to-k8s.js +324 -0
- package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
- package/bin/migrate/generators/compose-to-railway.js +138 -0
- package/bin/migrate/generators/compose-to-render.d.ts +2 -0
- package/bin/migrate/generators/compose-to-render.js +148 -0
- package/bin/migrate/generators/generic-migration.d.ts +9 -0
- package/bin/migrate/generators/generic-migration.js +221 -0
- package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
- package/bin/migrate/generators/heroku-to-fly.js +291 -0
- package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
- package/bin/migrate/generators/heroku-to-railway.js +283 -0
- package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
- package/bin/migrate/generators/heroku-to-render.js +148 -0
- package/bin/migrate/generators/index.d.ts +7 -0
- package/bin/migrate/generators/index.js +17 -0
- package/bin/migrate/generators/template-loader.d.ts +21 -0
- package/bin/migrate/generators/template-loader.js +59 -0
- package/bin/migrate/index.d.ts +1 -0
- package/bin/migrate/index.js +5 -0
- package/bin/new/cli.js +21 -6
- package/bin/new/form.d.ts +25 -4
- package/bin/new/form.js +285 -70
- package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
- package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
- package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
- package/bin/profile/analyzers/image-analyzer.js +85 -0
- package/bin/profile/cli.d.ts +4 -0
- package/bin/profile/cli.js +92 -0
- package/bin/profile/form.d.ts +56 -0
- package/bin/profile/form.js +400 -0
- package/bin/profile/index.d.ts +1 -0
- package/bin/profile/index.js +5 -0
- package/bin/profile/optimizers/index.d.ts +19 -0
- package/bin/profile/optimizers/index.js +137 -0
- package/bin/providers/add/form.d.ts +1 -1
- package/bin/providers/add/form.js +27 -6
- package/bin/providers/create/form.js +2 -1
- package/bin/scripts/form.js +27 -5
- package/bin/studio/cli.d.ts +15 -0
- package/bin/studio/cli.js +166 -0
- package/bin/studio/index.d.ts +5 -0
- package/bin/studio/index.js +9 -0
- package/bin/templates/cache.d.ts +54 -0
- package/bin/templates/cache.js +180 -0
- package/bin/templates/cli.d.ts +8 -0
- package/bin/templates/cli.js +292 -0
- package/bin/templates/fetcher.d.ts +49 -0
- package/bin/templates/fetcher.js +208 -0
- package/bin/templates/index.d.ts +11 -0
- package/bin/templates/index.js +37 -0
- package/bin/templates/manager.d.ts +116 -0
- package/bin/templates/manager.js +323 -0
- package/bin/templates/renderer.d.ts +49 -0
- package/bin/templates/renderer.js +204 -0
- package/bin/templates/types.d.ts +51 -0
- package/bin/templates/types.js +5 -0
- package/bin/utils/add-module-to-container.d.ts +2 -2
- package/bin/utils/add-module-to-container.js +15 -5
- package/bin/utils/cli-ui.d.ts +30 -3
- package/bin/utils/cli-ui.js +95 -13
- package/bin/utils/index.d.ts +4 -0
- package/bin/utils/index.js +4 -0
- package/bin/utils/input-validation.d.ts +50 -0
- package/bin/utils/input-validation.js +143 -0
- package/bin/utils/package-manager-commands.d.ts +24 -0
- package/bin/utils/package-manager-commands.js +50 -0
- package/bin/utils/safe-spawn.d.ts +35 -0
- package/bin/utils/safe-spawn.js +51 -0
- package/bin/utils/update-tsconfig-paths.d.ts +35 -0
- package/bin/utils/update-tsconfig-paths.js +286 -0
- package/package.json +154 -154
package/bin/cli.js
CHANGED
|
@@ -6,10 +6,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
6
6
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
7
|
exports.BUNDLE_VERSION = void 0;
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
-
const process_1 = require("process");
|
|
10
9
|
const yargs_1 = __importDefault(require("yargs"));
|
|
11
10
|
const helpers_1 = require("yargs/helpers");
|
|
12
11
|
const project_commands_1 = require("./commands/project.commands");
|
|
12
|
+
const containerize_1 = require("./containerize");
|
|
13
|
+
const cicd_1 = require("./cicd");
|
|
14
|
+
const migrate_1 = require("./migrate");
|
|
15
|
+
const profile_1 = require("./profile");
|
|
16
|
+
const dev_1 = require("./dev");
|
|
17
|
+
const costs_1 = require("./costs");
|
|
18
|
+
const templates_1 = require("./templates");
|
|
13
19
|
const generate_1 = require("./generate");
|
|
14
20
|
const cli_1 = require("./help/cli");
|
|
15
21
|
const info_1 = require("./info");
|
|
@@ -18,12 +24,13 @@ const providers_1 = require("./providers");
|
|
|
18
24
|
const cli_2 = require("./providers/create/cli");
|
|
19
25
|
const cli_ui_1 = require("./utils/cli-ui");
|
|
20
26
|
const scripts_1 = require("./scripts");
|
|
27
|
+
const studio_1 = require("./studio");
|
|
21
28
|
/**
|
|
22
29
|
* The current version of the ExpressoTS Bundle.
|
|
23
30
|
* core, adapters, and cli.
|
|
24
31
|
*/
|
|
25
|
-
exports.BUNDLE_VERSION = "
|
|
26
|
-
|
|
32
|
+
exports.BUNDLE_VERSION = "4.0.0-preview.2";
|
|
33
|
+
(0, cli_ui_1.printHeader)();
|
|
27
34
|
(0, yargs_1.default)((0, helpers_1.hideBin)(process.argv))
|
|
28
35
|
.scriptName("expressots")
|
|
29
36
|
.command((0, new_1.createProject)())
|
|
@@ -34,7 +41,15 @@ process_1.stdout.write(`\n${[chalk_1.default.bold.green("š Expressots")]}\n\n
|
|
|
34
41
|
.command((0, providers_1.addProviderCMD)())
|
|
35
42
|
.command((0, providers_1.removeProviderCMD)())
|
|
36
43
|
.command((0, generate_1.generateProject)())
|
|
44
|
+
.command((0, containerize_1.containerize)())
|
|
45
|
+
.command((0, cicd_1.cicdCommand)())
|
|
46
|
+
.command((0, migrate_1.migrateCommand)())
|
|
47
|
+
.command((0, profile_1.profileCommand)())
|
|
48
|
+
.command((0, dev_1.devContainerCommand)())
|
|
49
|
+
.command((0, costs_1.costsCommand)())
|
|
50
|
+
.command((0, templates_1.templatesCommand)())
|
|
37
51
|
.command((0, scripts_1.scriptsCommand)())
|
|
52
|
+
.command((0, studio_1.studioCommand)())
|
|
38
53
|
.command((0, info_1.infoProject)())
|
|
39
54
|
.command((0, cli_1.helpCommand)())
|
|
40
55
|
.demandCommand(1, "You need at least one command before moving on")
|
|
@@ -1,10 +1,18 @@
|
|
|
1
1
|
import { CommandModule } from "yargs";
|
|
2
|
+
/**
|
|
3
|
+
* Dev command options interface
|
|
4
|
+
*/
|
|
5
|
+
interface DevCommandOptions {
|
|
6
|
+
container?: boolean;
|
|
7
|
+
build?: boolean;
|
|
8
|
+
detach?: boolean;
|
|
9
|
+
}
|
|
2
10
|
/**
|
|
3
11
|
* Dev command module
|
|
4
|
-
* @type {CommandModule<object,
|
|
12
|
+
* @type {CommandModule<object, DevCommandOptions>}
|
|
5
13
|
* @returns The command module
|
|
6
14
|
*/
|
|
7
|
-
export declare const devCommand: CommandModule<object,
|
|
15
|
+
export declare const devCommand: CommandModule<object, DevCommandOptions>;
|
|
8
16
|
/**
|
|
9
17
|
* Build command module
|
|
10
18
|
* @type {CommandModule<object, object>}
|
|
@@ -18,9 +26,14 @@ export declare const buildCommand: CommandModule<object, object>;
|
|
|
18
26
|
*/
|
|
19
27
|
export declare const prodCommand: CommandModule<object, object>;
|
|
20
28
|
/**
|
|
21
|
-
*
|
|
22
|
-
* @param command The command to run
|
|
29
|
+
* Run command options
|
|
23
30
|
*/
|
|
24
|
-
|
|
31
|
+
interface RunCommandOptions {
|
|
25
32
|
command: string;
|
|
26
|
-
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Helper function to run a command
|
|
36
|
+
* @param options The command options
|
|
37
|
+
*/
|
|
38
|
+
export declare const runCommand: ({ command, }: RunCommandOptions) => Promise<void>;
|
|
39
|
+
export {};
|
|
@@ -31,8 +31,10 @@ const child_process_1 = require("child_process");
|
|
|
31
31
|
const fs_1 = require("fs");
|
|
32
32
|
const os_1 = __importDefault(require("os"));
|
|
33
33
|
const path_1 = __importStar(require("path"));
|
|
34
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
34
35
|
const cli_ui_1 = require("../utils/cli-ui");
|
|
35
36
|
const compiler_1 = __importDefault(require("../utils/compiler"));
|
|
37
|
+
const safe_spawn_1 = require("../utils/safe-spawn");
|
|
36
38
|
/**
|
|
37
39
|
* Helper function to load and extract outDir from tsconfig.build.json
|
|
38
40
|
*/
|
|
@@ -42,8 +44,15 @@ function getOutDir() {
|
|
|
42
44
|
(0, cli_ui_1.printError)("Cannot find tsconfig.build.json. Please create one in the root directory", "tsconfig-build-path");
|
|
43
45
|
process.exit(1);
|
|
44
46
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
+
let tsconfig;
|
|
48
|
+
try {
|
|
49
|
+
tsconfig = JSON.parse((0, fs_1.readFileSync)(tsconfigBuildPath, "utf-8"));
|
|
50
|
+
}
|
|
51
|
+
catch (err) {
|
|
52
|
+
(0, cli_ui_1.printError)(`Failed to parse tsconfig.build.json: ${err.message}`, "tsconfig-build-path");
|
|
53
|
+
process.exit(1);
|
|
54
|
+
}
|
|
55
|
+
const outDir = tsconfig.compilerOptions?.outDir;
|
|
47
56
|
if (!outDir) {
|
|
48
57
|
(0, cli_ui_1.printError)("Cannot find outDir in tsconfig.build.json. Please provide an outDir.", "tsconfig-build-path");
|
|
49
58
|
process.exit(1);
|
|
@@ -55,40 +64,63 @@ function getOutDir() {
|
|
|
55
64
|
return outDir;
|
|
56
65
|
}
|
|
57
66
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
const config = [
|
|
65
|
-
"--watch",
|
|
66
|
-
"-r",
|
|
67
|
-
"tsconfig-paths/register",
|
|
68
|
-
`./src/${entryPoint}.ts`,
|
|
69
|
-
];
|
|
70
|
-
return config;
|
|
71
|
-
}
|
|
72
|
-
/**
|
|
73
|
-
* Load the configuration from the compiler
|
|
74
|
-
* @param compiler The compiler to load the configuration from
|
|
75
|
-
* @returns The configuration
|
|
67
|
+
* Build the tsx watch arguments for development mode.
|
|
68
|
+
* Uses tsx's built-in --watch flag for reliable cross-platform file watching
|
|
69
|
+
* (avoids nodemon + SIGTERM issues on Windows).
|
|
70
|
+
*
|
|
71
|
+
* @param opinionated - Whether to use opinionated configuration
|
|
72
|
+
* @returns The tsx arguments array
|
|
76
73
|
*/
|
|
77
|
-
async function
|
|
78
|
-
const { entryPoint } = await compiler_1.default.loadConfig();
|
|
79
|
-
const
|
|
80
|
-
|
|
74
|
+
async function buildDevArgs(opinionated) {
|
|
75
|
+
const { entryPoint, sourceRoot } = await compiler_1.default.loadConfig();
|
|
76
|
+
const args = ["--watch"];
|
|
77
|
+
if (opinionated) {
|
|
78
|
+
args.push("-r", "tsconfig-paths/register");
|
|
79
|
+
}
|
|
80
|
+
// Honor `sourceRoot` from expressots.config.ts so projects whose
|
|
81
|
+
// source lives under a non-default folder (e.g. `api/` or
|
|
82
|
+
// `services/`) still resolve their entry point correctly.
|
|
83
|
+
args.push(`./${sourceRoot}/${entryPoint}.ts`);
|
|
84
|
+
return args;
|
|
81
85
|
}
|
|
82
86
|
/**
|
|
83
87
|
* Dev command module
|
|
84
|
-
* @type {CommandModule<object,
|
|
88
|
+
* @type {CommandModule<object, DevCommandOptions>}
|
|
85
89
|
* @returns The command module
|
|
86
90
|
*/
|
|
87
91
|
exports.devCommand = {
|
|
88
92
|
command: "dev",
|
|
89
93
|
describe: "Start development server.",
|
|
90
|
-
|
|
91
|
-
|
|
94
|
+
builder: {
|
|
95
|
+
container: {
|
|
96
|
+
alias: "c",
|
|
97
|
+
type: "boolean",
|
|
98
|
+
default: false,
|
|
99
|
+
description: "Run development inside Docker container",
|
|
100
|
+
},
|
|
101
|
+
build: {
|
|
102
|
+
alias: "b",
|
|
103
|
+
type: "boolean",
|
|
104
|
+
default: false,
|
|
105
|
+
description: "Rebuild container before starting (with --container)",
|
|
106
|
+
},
|
|
107
|
+
detach: {
|
|
108
|
+
alias: "d",
|
|
109
|
+
type: "boolean",
|
|
110
|
+
default: false,
|
|
111
|
+
description: "Run container in background (with --container)",
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
handler: async (argv) => {
|
|
115
|
+
if (argv.container) {
|
|
116
|
+
await runContainerDev({
|
|
117
|
+
build: argv.build ?? false,
|
|
118
|
+
detach: argv.detach ?? false,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
else {
|
|
122
|
+
await (0, exports.runCommand)({ command: "dev" });
|
|
123
|
+
}
|
|
92
124
|
},
|
|
93
125
|
};
|
|
94
126
|
/**
|
|
@@ -124,11 +156,15 @@ exports.prodCommand = {
|
|
|
124
156
|
*/
|
|
125
157
|
function execCmd(command, args, cwd = process.cwd()) {
|
|
126
158
|
return new Promise((resolve, reject) => {
|
|
127
|
-
|
|
159
|
+
// `safeSpawn` (cross-spawn) resolves Windows `.cmd` shims (npx,
|
|
160
|
+
// tsx, tsc, etc.) via PATHEXT and applies cmd.exe-aware escaping
|
|
161
|
+
// for every argv entry, while falling through to plain `spawn`
|
|
162
|
+
// with `shell: false` on Unix.
|
|
163
|
+
const proc = (0, safe_spawn_1.safeSpawn)(command, args, {
|
|
128
164
|
stdio: "inherit",
|
|
129
|
-
shell: true,
|
|
130
165
|
cwd,
|
|
131
166
|
});
|
|
167
|
+
proc.on("error", (err) => reject(err));
|
|
132
168
|
proc.on("close", (code) => {
|
|
133
169
|
if (code === 0) {
|
|
134
170
|
resolve();
|
|
@@ -153,47 +189,343 @@ const compileTypescript = async () => {
|
|
|
153
189
|
await execCmd("npx", ["tsc", "-p", "tsconfig.build.json"]);
|
|
154
190
|
(0, cli_ui_1.printSuccess)("Built successfully", "compile-typescript");
|
|
155
191
|
};
|
|
192
|
+
/**
|
|
193
|
+
* Transform path aliases to relative paths in compiled JavaScript files.
|
|
194
|
+
* This runs after TypeScript compilation to ensure production builds work
|
|
195
|
+
* without runtime path resolution.
|
|
196
|
+
*
|
|
197
|
+
* @param outDir - The output directory (e.g., "./dist")
|
|
198
|
+
*/
|
|
199
|
+
const transformPathAliases = async (outDir) => {
|
|
200
|
+
const tsconfigPath = (0, path_1.join)(process.cwd(), "tsconfig.build.json");
|
|
201
|
+
if (!(0, fs_1.existsSync)(tsconfigPath)) {
|
|
202
|
+
return; // No tsconfig.build.json, skip transformation
|
|
203
|
+
}
|
|
204
|
+
let tsconfig;
|
|
205
|
+
try {
|
|
206
|
+
tsconfig = JSON.parse((0, fs_1.readFileSync)(tsconfigPath, "utf-8"));
|
|
207
|
+
}
|
|
208
|
+
catch (err) {
|
|
209
|
+
(0, cli_ui_1.printError)(`Failed to parse tsconfig.build.json for path-alias transform: ${err.message}`, "transform-paths");
|
|
210
|
+
return;
|
|
211
|
+
}
|
|
212
|
+
const paths = tsconfig.compilerOptions?.paths;
|
|
213
|
+
const baseUrl = tsconfig.compilerOptions?.baseUrl;
|
|
214
|
+
if (!paths || !baseUrl) {
|
|
215
|
+
return; // No path aliases defined, skip
|
|
216
|
+
}
|
|
217
|
+
// Build regex patterns for each alias
|
|
218
|
+
const aliasPatterns = [];
|
|
219
|
+
for (const [alias, targets] of Object.entries(paths)) {
|
|
220
|
+
if (!Array.isArray(targets) || targets.length === 0)
|
|
221
|
+
continue;
|
|
222
|
+
// Convert @alias/* to regex pattern
|
|
223
|
+
// Matches: require("@alias/something") or require('@alias/something')
|
|
224
|
+
const aliasBase = alias.replace("/*", "");
|
|
225
|
+
const targetBase = targets[0].replace("/*", "");
|
|
226
|
+
// Pattern to match require("@alias/...") or require('@alias/...')
|
|
227
|
+
const pattern = new RegExp(`require\\(["']${aliasBase.replace("@", "\\@")}/([^"']+)["']\\)`, "g");
|
|
228
|
+
aliasPatterns.push({
|
|
229
|
+
pattern,
|
|
230
|
+
alias: aliasBase,
|
|
231
|
+
target: targetBase,
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
if (aliasPatterns.length === 0) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
// Recursively find all .js files in outDir
|
|
238
|
+
const findJsFiles = async (dir) => {
|
|
239
|
+
const files = [];
|
|
240
|
+
const entries = await fs_1.promises.readdir(dir, { withFileTypes: true });
|
|
241
|
+
for (const entry of entries) {
|
|
242
|
+
const fullPath = (0, path_1.join)(dir, entry.name);
|
|
243
|
+
if (entry.isDirectory()) {
|
|
244
|
+
files.push(...(await findJsFiles(fullPath)));
|
|
245
|
+
}
|
|
246
|
+
else if (entry.name.endsWith(".js")) {
|
|
247
|
+
files.push(fullPath);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return files;
|
|
251
|
+
};
|
|
252
|
+
const jsFiles = await findJsFiles(outDir);
|
|
253
|
+
let transformedCount = 0;
|
|
254
|
+
for (const file of jsFiles) {
|
|
255
|
+
let content = await fs_1.promises.readFile(file, "utf-8");
|
|
256
|
+
let modified = false;
|
|
257
|
+
// Get the directory of the current file relative to outDir
|
|
258
|
+
const fileDir = path_1.default.dirname(file);
|
|
259
|
+
for (const { pattern, alias, target } of aliasPatterns) {
|
|
260
|
+
// Calculate the relative path from this file to the target
|
|
261
|
+
const targetDir = (0, path_1.join)(outDir, baseUrl.replace("./", ""), target);
|
|
262
|
+
let relativePath = path_1.default.relative(fileDir, targetDir);
|
|
263
|
+
// Ensure it starts with ./ or ../
|
|
264
|
+
if (!relativePath.startsWith(".")) {
|
|
265
|
+
relativePath = "./" + relativePath;
|
|
266
|
+
}
|
|
267
|
+
// Replace Windows backslashes with forward slashes
|
|
268
|
+
relativePath = relativePath.replace(/\\/g, "/");
|
|
269
|
+
// Replace the alias with the relative path
|
|
270
|
+
const newContent = content.replace(pattern, (match, subPath) => {
|
|
271
|
+
modified = true;
|
|
272
|
+
return `require("${relativePath}/${subPath}")`;
|
|
273
|
+
});
|
|
274
|
+
if (newContent !== content) {
|
|
275
|
+
content = newContent;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
if (modified) {
|
|
279
|
+
await fs_1.promises.writeFile(file, content, "utf-8");
|
|
280
|
+
transformedCount++;
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
if (transformedCount > 0) {
|
|
284
|
+
(0, cli_ui_1.printSuccess)(`Path aliases resolved in ${transformedCount} files`, "transform-paths");
|
|
285
|
+
}
|
|
286
|
+
};
|
|
156
287
|
/**
|
|
157
288
|
* Helper function to copy files to the dist directory
|
|
158
289
|
*/
|
|
159
290
|
const copyFiles = async (outDir) => {
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
];
|
|
168
|
-
}
|
|
169
|
-
else {
|
|
170
|
-
filesToCopy = ["tsconfig.json", "package.json"];
|
|
291
|
+
// Only copy package.json - path aliases are resolved at build time
|
|
292
|
+
// No need for tsconfig files or register-path.js in production
|
|
293
|
+
const filesToCopy = ["package.json"];
|
|
294
|
+
for (const file of filesToCopy) {
|
|
295
|
+
if ((0, fs_1.existsSync)(file)) {
|
|
296
|
+
await fs_1.promises.copyFile(file, (0, path_1.join)(outDir, path_1.default.basename(file)));
|
|
297
|
+
}
|
|
171
298
|
}
|
|
172
|
-
filesToCopy.forEach((file) => {
|
|
173
|
-
fs_1.promises.copyFile(file, (0, path_1.join)(outDir, path_1.default.basename(file)));
|
|
174
|
-
});
|
|
175
299
|
};
|
|
176
300
|
/**
|
|
177
301
|
* Helper function to clear the screen
|
|
178
302
|
*/
|
|
179
303
|
const clearScreen = () => {
|
|
304
|
+
// `cls` and `clear` are built-ins / well-known executables.
|
|
305
|
+
// Invoking them via `shell: true` is safe here because there are no
|
|
306
|
+
// user-controlled args, but we keep `windowsHide: true` to suppress
|
|
307
|
+
// the Windows console flash.
|
|
180
308
|
const platform = os_1.default.platform();
|
|
181
309
|
const command = platform === "win32" ? "cls" : "clear";
|
|
182
|
-
(0, child_process_1.spawn)(command, { stdio: "inherit", shell: true });
|
|
310
|
+
(0, child_process_1.spawn)(command, [], { stdio: "inherit", shell: true, windowsHide: true });
|
|
183
311
|
};
|
|
312
|
+
/**
|
|
313
|
+
* Run development in Docker container with auto-setup
|
|
314
|
+
* This is the seamless "just works" experience
|
|
315
|
+
*/
|
|
316
|
+
async function runContainerDev(options) {
|
|
317
|
+
console.log(chalk_1.default.cyan("\nš³ ExpressoTS Container Development\n"));
|
|
318
|
+
const cwd = process.cwd();
|
|
319
|
+
const composeDevFile = (0, path_1.join)(cwd, "docker-compose.development.yml");
|
|
320
|
+
const dockerfileDevFile = (0, path_1.join)(cwd, "Dockerfile.development");
|
|
321
|
+
const dockerSetupFile = (0, path_1.join)(cwd, "docker-setup.js");
|
|
322
|
+
const dockerDepsDir = (0, path_1.join)(cwd, ".docker-deps");
|
|
323
|
+
const packageDockerJson = (0, path_1.join)(cwd, "package.docker.json");
|
|
324
|
+
// Check if Docker is running
|
|
325
|
+
if (!isDockerRunning()) {
|
|
326
|
+
console.log(chalk_1.default.red("ā Docker is not running."));
|
|
327
|
+
console.log(chalk_1.default.gray(" Please start Docker Desktop or Docker daemon."));
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
// Step 1: Auto-generate Docker files if missing
|
|
331
|
+
if (!(0, fs_1.existsSync)(dockerfileDevFile) || !(0, fs_1.existsSync)(composeDevFile)) {
|
|
332
|
+
console.log(chalk_1.default.yellow("š Docker files not found. Generating..."));
|
|
333
|
+
try {
|
|
334
|
+
// Import and run containerize
|
|
335
|
+
const { containerizeProject } = await Promise.resolve().then(() => __importStar(require("../containerize/form")));
|
|
336
|
+
await containerizeProject({
|
|
337
|
+
target: "docker",
|
|
338
|
+
environment: "development",
|
|
339
|
+
preset: "standard",
|
|
340
|
+
analyze: true,
|
|
341
|
+
skipCompose: false,
|
|
342
|
+
includeCi: false,
|
|
343
|
+
});
|
|
344
|
+
console.log();
|
|
345
|
+
}
|
|
346
|
+
catch (error) {
|
|
347
|
+
console.log(chalk_1.default.red("ā Failed to generate Docker files."));
|
|
348
|
+
console.log(chalk_1.default.gray(" Run manually: expressots containerize docker --env development"));
|
|
349
|
+
return;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Step 1.5: Check bootstrap config and create missing env files if needed
|
|
353
|
+
try {
|
|
354
|
+
const { analyzeBootstrapConfig, shouldCopyEnvFiles, getEnvFileForEnvironment, } = await Promise.resolve().then(() => __importStar(require("../containerize/analyzers/bootstrap-analyzer")));
|
|
355
|
+
const bootstrapConfig = await analyzeBootstrapConfig();
|
|
356
|
+
if (bootstrapConfig.hasEnvFileConfig &&
|
|
357
|
+
shouldCopyEnvFiles(bootstrapConfig)) {
|
|
358
|
+
const devEnvFile = getEnvFileForEnvironment(bootstrapConfig, "development");
|
|
359
|
+
// Check if required env file is missing
|
|
360
|
+
if (bootstrapConfig.missingEnvFiles.includes(devEnvFile)) {
|
|
361
|
+
console.log(chalk_1.default.yellow(`ā ļø Required env file missing: ${devEnvFile}`));
|
|
362
|
+
// Auto-create template if configured or prompt user
|
|
363
|
+
if (bootstrapConfig.autoCreateTemplate) {
|
|
364
|
+
console.log(chalk_1.default.gray(` Creating template ${devEnvFile}...`));
|
|
365
|
+
await createEnvTemplate(cwd, devEnvFile, "development", bootstrapConfig.requiredVariables);
|
|
366
|
+
console.log(chalk_1.default.green(` ā Created ${devEnvFile}`));
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
// Provide helpful instructions
|
|
370
|
+
console.log(chalk_1.default.cyan("\nš” To fix this, either:"));
|
|
371
|
+
console.log(chalk_1.default.gray(` 1. Create ${devEnvFile} with your environment variables`));
|
|
372
|
+
console.log(chalk_1.default.gray(` 2. Add autoCreateTemplate: true to envFileConfig in bootstrap`));
|
|
373
|
+
console.log(chalk_1.default.gray(` 3. Use skipFileLoading: true for container deployments`));
|
|
374
|
+
console.log();
|
|
375
|
+
// Still continue - the container might work if env vars are set in docker-compose
|
|
376
|
+
console.log(chalk_1.default.yellow(` ā ļø Container may fail if ${devEnvFile} is required`));
|
|
377
|
+
console.log();
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
// Show required variables that need to be set
|
|
381
|
+
if (bootstrapConfig.requiredVariables.length > 0) {
|
|
382
|
+
console.log(chalk_1.default.cyan("š Required environment variables:"));
|
|
383
|
+
bootstrapConfig.requiredVariables.forEach((varName) => {
|
|
384
|
+
console.log(chalk_1.default.gray(` ⢠${varName}`));
|
|
385
|
+
});
|
|
386
|
+
console.log(chalk_1.default.gray(` Set these in ${devEnvFile} or docker-compose.development.yml`));
|
|
387
|
+
console.log();
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
catch (error) {
|
|
392
|
+
// Non-fatal - continue with container startup
|
|
393
|
+
console.log(chalk_1.default.gray(" (Bootstrap analysis skipped)"));
|
|
394
|
+
}
|
|
395
|
+
// Step 2: Auto-run docker:setup if local dependencies exist
|
|
396
|
+
if ((0, fs_1.existsSync)(packageDockerJson) && (0, fs_1.existsSync)(dockerSetupFile)) {
|
|
397
|
+
// Check if .docker-deps needs to be updated
|
|
398
|
+
const needsSetup = !(0, fs_1.existsSync)(dockerDepsDir) || isDirEmpty(dockerDepsDir);
|
|
399
|
+
if (needsSetup) {
|
|
400
|
+
console.log(chalk_1.default.yellow("š¦ Setting up local dependencies..."));
|
|
401
|
+
try {
|
|
402
|
+
const setupResult = (0, safe_spawn_1.safeSpawnSync)(process.execPath, ["docker-setup.js"], {
|
|
403
|
+
cwd,
|
|
404
|
+
stdio: "inherit",
|
|
405
|
+
encoding: "utf-8",
|
|
406
|
+
});
|
|
407
|
+
if (setupResult.error)
|
|
408
|
+
throw setupResult.error;
|
|
409
|
+
if (typeof setupResult.status === "number" &&
|
|
410
|
+
setupResult.status !== 0) {
|
|
411
|
+
throw new Error(`exited with code ${setupResult.status}`);
|
|
412
|
+
}
|
|
413
|
+
console.log();
|
|
414
|
+
}
|
|
415
|
+
catch (error) {
|
|
416
|
+
console.log(chalk_1.default.red("ā Failed to setup local dependencies."));
|
|
417
|
+
console.log(chalk_1.default.gray(" Run manually: npm run docker:setup"));
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
// Step 3: Start the containers
|
|
423
|
+
console.log(chalk_1.default.yellow(`š Using docker-compose.development.yml`));
|
|
424
|
+
const args = ["-f", composeDevFile, "up"];
|
|
425
|
+
if (options.build) {
|
|
426
|
+
console.log(chalk_1.default.yellow("šØ Rebuilding containers..."));
|
|
427
|
+
args.splice(2, 0, "--build");
|
|
428
|
+
}
|
|
429
|
+
if (options.detach) {
|
|
430
|
+
args.push("-d");
|
|
431
|
+
}
|
|
432
|
+
console.log(chalk_1.default.yellow("š Starting development containers...\n"));
|
|
433
|
+
// Print dev info
|
|
434
|
+
console.log(chalk_1.default.bold("Development Environment:"));
|
|
435
|
+
console.log(` š App: http://localhost:3000`);
|
|
436
|
+
console.log(` š Debug: localhost:9229`);
|
|
437
|
+
console.log();
|
|
438
|
+
console.log(chalk_1.default.bold("Commands:"));
|
|
439
|
+
console.log(` ${chalk_1.default.gray("expressots dev -c")} Start containers`);
|
|
440
|
+
console.log(` ${chalk_1.default.gray("expressots dev -c -b")} Rebuild & start`);
|
|
441
|
+
console.log(` ${chalk_1.default.gray("expressots dev -c -d")} Start in background`);
|
|
442
|
+
console.log(` ${chalk_1.default.gray("docker-compose -f docker-compose.development.yml down")} Stop`);
|
|
443
|
+
console.log();
|
|
444
|
+
console.log(chalk_1.default.green("š Hot reload enabled - edit files to see changes"));
|
|
445
|
+
if (!options.detach) {
|
|
446
|
+
console.log(chalk_1.default.gray("Press Ctrl+C to stop\n"));
|
|
447
|
+
}
|
|
448
|
+
// Run docker-compose
|
|
449
|
+
runDockerComposeCommand(args, cwd, options.detach);
|
|
450
|
+
if (options.detach) {
|
|
451
|
+
console.log(chalk_1.default.green("\nā
Containers started in background."));
|
|
452
|
+
console.log(chalk_1.default.gray(" View logs: docker-compose -f docker-compose.development.yml logs -f"));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Check if Docker is running
|
|
457
|
+
*/
|
|
458
|
+
function isDockerRunning() {
|
|
459
|
+
const result = (0, safe_spawn_1.safeSpawnSync)("docker", ["info"], {
|
|
460
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
461
|
+
});
|
|
462
|
+
return !result.error && result.status === 0;
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Check if directory is empty
|
|
466
|
+
*/
|
|
467
|
+
function isDirEmpty(dir) {
|
|
468
|
+
try {
|
|
469
|
+
const files = (0, fs_1.readdirSync)(dir);
|
|
470
|
+
return files.length === 0;
|
|
471
|
+
}
|
|
472
|
+
catch {
|
|
473
|
+
return true;
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
/**
|
|
477
|
+
* Create an environment template file
|
|
478
|
+
*/
|
|
479
|
+
async function createEnvTemplate(cwd, fileName, environment, requiredVariables) {
|
|
480
|
+
const filePath = (0, path_1.join)(cwd, fileName);
|
|
481
|
+
const commonVars = [
|
|
482
|
+
"PORT=3000",
|
|
483
|
+
`NODE_ENV=${environment}`,
|
|
484
|
+
"# Add your environment variables below",
|
|
485
|
+
];
|
|
486
|
+
const requiredVars = requiredVariables.map((key) => `${key}=`);
|
|
487
|
+
const template = [...commonVars, ...requiredVars].join("\n");
|
|
488
|
+
await fs_1.promises.writeFile(filePath, template, "utf-8");
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Run docker-compose command
|
|
492
|
+
*/
|
|
493
|
+
function runDockerComposeCommand(args, cwd, detach) {
|
|
494
|
+
// Try docker compose (v2) first, fall back to docker-compose (v1).
|
|
495
|
+
// `safeSpawnSync` (cross-spawn) handles platform-specific binary
|
|
496
|
+
// resolution and cmd.exe-aware argv escaping, so compose file paths
|
|
497
|
+
// and service names are forwarded as discrete arguments rather than
|
|
498
|
+
// re-interpreted by the OS shell.
|
|
499
|
+
const v2 = (0, safe_spawn_1.safeSpawnSync)("docker", ["compose", ...args], {
|
|
500
|
+
cwd,
|
|
501
|
+
stdio: "inherit",
|
|
502
|
+
});
|
|
503
|
+
if (v2.error || (typeof v2.status === "number" && v2.status !== 0)) {
|
|
504
|
+
const v1 = (0, safe_spawn_1.safeSpawnSync)("docker-compose", args, {
|
|
505
|
+
cwd,
|
|
506
|
+
stdio: "inherit",
|
|
507
|
+
});
|
|
508
|
+
if (v1.error || (typeof v1.status === "number" && v1.status !== 0)) {
|
|
509
|
+
console.log(chalk_1.default.red("Error running docker-compose"));
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
// `detach` is honored implicitly by docker compose itself when "-d"
|
|
513
|
+
// is present in `args`. The previous branch tried to switch between
|
|
514
|
+
// execSync and spawnSync for that case, which served no real
|
|
515
|
+
// purpose and made shell injection harder to reason about.
|
|
516
|
+
void detach;
|
|
517
|
+
}
|
|
184
518
|
/**
|
|
185
519
|
* Helper function to run a command
|
|
186
|
-
* @param
|
|
520
|
+
* @param options The command options
|
|
187
521
|
*/
|
|
188
522
|
const runCommand = async ({ command, }) => {
|
|
189
|
-
const { opinionated, entryPoint } = await compiler_1.default.loadConfig();
|
|
523
|
+
const { opinionated, entryPoint, sourceRoot } = await compiler_1.default.loadConfig();
|
|
190
524
|
const outDir = getOutDir();
|
|
191
525
|
try {
|
|
192
526
|
switch (command) {
|
|
193
527
|
case "dev":
|
|
194
|
-
execCmd("tsx", opinionated
|
|
195
|
-
? await opinionatedConfig()
|
|
196
|
-
: await nonOpinionatedConfig());
|
|
528
|
+
await execCmd("tsx", await buildDevArgs(opinionated));
|
|
197
529
|
break;
|
|
198
530
|
case "build":
|
|
199
531
|
if (!outDir) {
|
|
@@ -202,6 +534,10 @@ const runCommand = async ({ command, }) => {
|
|
|
202
534
|
}
|
|
203
535
|
await cleanDist(outDir);
|
|
204
536
|
await compileTypescript();
|
|
537
|
+
// Transform path aliases to relative paths for production
|
|
538
|
+
if (opinionated) {
|
|
539
|
+
await transformPathAliases(outDir);
|
|
540
|
+
}
|
|
205
541
|
await copyFiles(outDir);
|
|
206
542
|
break;
|
|
207
543
|
case "prod": {
|
|
@@ -209,19 +545,12 @@ const runCommand = async ({ command, }) => {
|
|
|
209
545
|
(0, cli_ui_1.printError)("Cannot run in prod mode. Please provide an outDir in tsconfig.build.json", "prod-command");
|
|
210
546
|
process.exit(1);
|
|
211
547
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
`./${outDir}/register-path.js`,
|
|
217
|
-
`./${outDir}/src/${entryPoint}.js`,
|
|
218
|
-
];
|
|
219
|
-
}
|
|
220
|
-
else {
|
|
221
|
-
config = [`./${outDir}/${entryPoint}.js`];
|
|
222
|
-
}
|
|
548
|
+
// Honor `sourceRoot` so the compiled entry-point path
|
|
549
|
+
// matches whatever folder the user configured (the TS
|
|
550
|
+
// compiler preserves the source tree under `outDir`).
|
|
551
|
+
const config = [`./${outDir}/${sourceRoot}/${entryPoint}.js`];
|
|
223
552
|
clearScreen();
|
|
224
|
-
execCmd("node", config);
|
|
553
|
+
await execCmd("node", config);
|
|
225
554
|
break;
|
|
226
555
|
}
|
|
227
556
|
default:
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Configuration exports
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.resetConfigManager = exports.getConfigManager = exports.ConfigManager = void 0;
|
|
7
|
+
var manager_1 = require("./manager");
|
|
8
|
+
Object.defineProperty(exports, "ConfigManager", { enumerable: true, get: function () { return manager_1.ConfigManager; } });
|
|
9
|
+
Object.defineProperty(exports, "getConfigManager", { enumerable: true, get: function () { return manager_1.getConfigManager; } });
|
|
10
|
+
Object.defineProperty(exports, "resetConfigManager", { enumerable: true, get: function () { return manager_1.resetConfigManager; } });
|