ecopages 0.2.0-alpha.30 → 0.2.0-alpha.31

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/bin/cli.js CHANGED
@@ -1,260 +1,224 @@
1
1
  #!/usr/bin/env node
2
-
3
- import { defineCommand, runMain } from 'citty';
4
- import { downloadTemplate } from 'giget';
5
- import { existsSync, readFileSync, writeFileSync } from 'node:fs';
6
- import { spawn } from 'node:child_process';
7
- import { join } from 'node:path';
8
- import { Logger } from '@ecopages/logger';
9
- import { createLaunchPlan, launchPlanRequiresExistingEntryFile } from './launch-plan.js';
10
-
11
- const logger = new Logger('[ecopages:cli]', { debug: process.env.ECOPAGES_LOGGER_DEBUG === 'true' });
12
-
13
- const pkg = JSON.parse(readFileSync(new URL('../package.json', import.meta.url), 'utf-8'));
14
-
2
+ import { defineCommand, runMain } from "citty";
3
+ import { downloadTemplate } from "giget";
4
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
5
+ import { spawn } from "node:child_process";
6
+ import { join } from "node:path";
7
+ import { Logger } from "@ecopages/logger";
8
+ import { createLaunchPlan, launchPlanRequiresExistingEntryFile } from "./launch-plan.js";
9
+ const logger = new Logger("[ecopages:cli]", { debug: process.env.ECOPAGES_LOGGER_DEBUG === "true" });
10
+ const pkg = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf-8"));
15
11
  function runLaunchPlan(launchPlan) {
16
- if (Object.keys(launchPlan.envOverrides).length > 0) {
17
- logger.debug(`Environment overrides: ${JSON.stringify(launchPlan.envOverrides)}`);
18
- }
19
-
20
- logger.debug(`Runtime: ${launchPlan.runtime}`);
21
- logger.debug(`Running: ${launchPlan.command} ${launchPlan.commandArgs.join(' ')}`);
22
-
23
- const child = spawn(launchPlan.command, launchPlan.commandArgs, {
24
- stdio: 'inherit',
25
- env: launchPlan.env,
26
- });
27
-
28
- child.on('error', (error) => {
29
- if (error && error.code === 'ENOENT') {
30
- const hint =
31
- launchPlan.runtime === 'bun'
32
- ? 'Install Bun from https://bun.sh to continue.'
33
- : 'Reinstall ecopages and its dependencies so the packaged tsx runtime is available for Node.js launches.';
34
- logger.error(`Command not found: ${launchPlan.command}. ${hint}`);
35
- process.exit(1);
36
- }
37
-
38
- logger.error(`Failed to run command: ${error.message}`);
39
- process.exit(1);
40
- });
41
-
42
- child.on('exit', (code) => {
43
- process.exit(code || 0);
44
- });
12
+ if (Object.keys(launchPlan.envOverrides).length > 0) {
13
+ logger.debug(`Environment overrides: ${JSON.stringify(launchPlan.envOverrides)}`);
14
+ }
15
+ logger.debug(`Runtime: ${launchPlan.runtime}`);
16
+ logger.debug(`Running: ${launchPlan.command} ${launchPlan.commandArgs.join(" ")}`);
17
+ const child = spawn(launchPlan.command, launchPlan.commandArgs, {
18
+ stdio: "inherit",
19
+ env: launchPlan.env
20
+ });
21
+ child.on("error", (error) => {
22
+ if (error && error.code === "ENOENT") {
23
+ const hint = launchPlan.runtime === "bun" ? "Install Bun from https://bun.sh to continue." : "Reinstall ecopages and its dependencies so the packaged tsx runtime is available for Node.js launches.";
24
+ logger.error(`Command not found: ${launchPlan.command}. ${hint}`);
25
+ process.exit(1);
26
+ }
27
+ logger.error(`Failed to run command: ${error.message}`);
28
+ process.exit(1);
29
+ });
30
+ child.on("exit", (code) => {
31
+ process.exit(code || 0);
32
+ });
45
33
  }
46
-
47
- /**
48
- * Launch the entry file via the detected or forced runtime (bun or node).
49
- * Automatically detects eco.config.ts and applies preloads.
50
- * @param {string[]} args - Arguments to pass to the entry file
51
- * @param {object} options - CLI options (watch, hot, port, hostname, etc.)
52
- * @param {string} entryFile - Entry file to run
53
- */
54
- async function runEntryCommand(args, options = {}, entryFile = 'app.ts') {
55
- let launchPlan;
56
-
57
- try {
58
- launchPlan = await createLaunchPlan(args, options, entryFile);
59
- } catch (error) {
60
- const message = error instanceof Error ? error.message : String(error);
61
- logger.error(message);
62
- process.exit(1);
63
- }
64
-
65
- if (launchPlanRequiresExistingEntryFile(launchPlan) && !existsSync(entryFile)) {
66
- logger.error(`Error: Entry file "${entryFile}" not found in the current directory.`);
67
- process.exit(1);
68
- }
69
-
70
- runLaunchPlan(launchPlan);
34
+ async function runEntryCommand(args, options = {}, entryFile = "app.ts") {
35
+ let launchPlan;
36
+ try {
37
+ launchPlan = await createLaunchPlan(args, options, entryFile);
38
+ } catch (error) {
39
+ const message = error instanceof Error ? error.message : String(error);
40
+ logger.error(message);
41
+ process.exit(1);
42
+ }
43
+ if (launchPlanRequiresExistingEntryFile(launchPlan) && !existsSync(entryFile)) {
44
+ logger.error(`Error: Entry file "${entryFile}" not found in the current directory.`);
45
+ process.exit(1);
46
+ }
47
+ runLaunchPlan(launchPlan);
71
48
  }
72
-
73
- /** Shared server argument definitions for citty commands. */
74
49
  const serverArgs = {
75
- entry: {
76
- type: 'positional',
77
- description: 'Entry file',
78
- default: 'app.ts',
79
- },
80
- port: {
81
- type: 'string',
82
- alias: ['p'],
83
- description: 'Override ECOPAGES_PORT',
84
- },
85
- hostname: {
86
- type: 'string',
87
- alias: ['n'],
88
- description: 'Override ECOPAGES_HOSTNAME',
89
- },
90
- 'base-url': {
91
- type: 'string',
92
- alias: ['b'],
93
- description: 'Override ECOPAGES_BASE_URL',
94
- },
95
- debug: {
96
- type: 'boolean',
97
- alias: ['d'],
98
- description: 'Enable debug logging (ECOPAGES_LOGGER_DEBUG=true)',
99
- },
100
- 'react-fast-refresh': {
101
- type: 'boolean',
102
- alias: ['r'],
103
- description: 'Enable React Fast Refresh for HMR',
104
- },
105
- runtime: {
106
- type: 'string',
107
- description: 'Force a specific runtime (bun or node)',
108
- },
50
+ entry: {
51
+ type: "positional",
52
+ description: "Entry file",
53
+ default: "app.ts"
54
+ },
55
+ port: {
56
+ type: "string",
57
+ alias: ["p"],
58
+ description: "Override ECOPAGES_PORT"
59
+ },
60
+ hostname: {
61
+ type: "string",
62
+ alias: ["n"],
63
+ description: "Override ECOPAGES_HOSTNAME"
64
+ },
65
+ "base-url": {
66
+ type: "string",
67
+ alias: ["b"],
68
+ description: "Override ECOPAGES_BASE_URL"
69
+ },
70
+ debug: {
71
+ type: "boolean",
72
+ alias: ["d"],
73
+ description: "Enable debug logging (ECOPAGES_LOGGER_DEBUG=true)"
74
+ },
75
+ "react-fast-refresh": {
76
+ type: "boolean",
77
+ alias: ["r"],
78
+ description: "Enable React Fast Refresh for HMR"
79
+ },
80
+ runtime: {
81
+ type: "string",
82
+ description: "Force a specific runtime (bun or node)"
83
+ }
109
84
  };
110
-
111
85
  const initCommand = defineCommand({
112
- meta: {
113
- name: 'init',
114
- description: 'Initialize a new project from a template',
115
- },
116
- args: {
117
- dir: {
118
- type: 'positional',
119
- description: 'Target directory name',
120
- required: true,
121
- },
122
- template: {
123
- type: 'string',
124
- description: 'Template name from ecopages/examples/',
125
- default: 'starter-jsx',
126
- },
127
- repo: {
128
- type: 'string',
129
- description: 'GitHub repo (user/repo)',
130
- default: 'ecopages/ecopages',
131
- },
132
- },
133
- async run({ args }) {
134
- const { dir, template, repo } = args;
135
-
136
- if (existsSync(dir)) {
137
- logger.error(`Target directory already exists: ${dir}`);
138
- process.exit(1);
139
- }
140
-
141
- logger.info(`Creating target directory '${dir}'...`);
142
-
143
- try {
144
- await downloadTemplate(`github:${repo}/examples/${template}`, {
145
- dir,
146
- force: true,
147
- });
148
-
149
- const pkgPath = join(dir, 'package.json');
150
- if (existsSync(pkgPath)) {
151
- const projectPkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
152
- projectPkg.name = dir;
153
- writeFileSync(pkgPath, JSON.stringify(projectPkg, null, 2) + '\n');
154
- logger.info(`Renamed project to '${dir}'`);
155
- }
156
-
157
- logger.info('Project initialized! Run `bun install && bun dev` to start.');
158
- } catch (err) {
159
- logger.error(`Failed to fetch template: ${err.message}`);
160
- process.exit(1);
161
- }
162
- },
86
+ meta: {
87
+ name: "init",
88
+ description: "Initialize a new project from a template"
89
+ },
90
+ args: {
91
+ dir: {
92
+ type: "positional",
93
+ description: "Target directory name",
94
+ required: true
95
+ },
96
+ template: {
97
+ type: "string",
98
+ description: "Template name from ecopages/examples/",
99
+ default: "starter-jsx"
100
+ },
101
+ repo: {
102
+ type: "string",
103
+ description: "GitHub repo (user/repo)",
104
+ default: "ecopages/ecopages"
105
+ }
106
+ },
107
+ async run({ args }) {
108
+ const { dir, template, repo } = args;
109
+ if (existsSync(dir)) {
110
+ logger.error(`Target directory already exists: ${dir}`);
111
+ process.exit(1);
112
+ }
113
+ logger.info(`Creating target directory '${dir}'...`);
114
+ try {
115
+ await downloadTemplate(`github:${repo}/examples/${template}`, {
116
+ dir,
117
+ force: true
118
+ });
119
+ const pkgPath = join(dir, "package.json");
120
+ if (existsSync(pkgPath)) {
121
+ const projectPkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
122
+ projectPkg.name = dir;
123
+ writeFileSync(pkgPath, JSON.stringify(projectPkg, null, 2) + "\n");
124
+ logger.info(`Renamed project to '${dir}'`);
125
+ }
126
+ logger.info("Project initialized! Run `bun install && bun dev` to start.");
127
+ } catch (err) {
128
+ logger.error(`Failed to fetch template: ${err.message}`);
129
+ process.exit(1);
130
+ }
131
+ }
163
132
  });
164
-
165
133
  const devCommand = defineCommand({
166
- meta: {
167
- name: 'dev',
168
- description: 'Start the development server',
169
- },
170
- args: serverArgs,
171
- async run({ args }) {
172
- await runEntryCommand(['--dev'], { ...args, nodeEnv: 'development' }, args.entry);
173
- },
134
+ meta: {
135
+ name: "dev",
136
+ description: "Start the development server"
137
+ },
138
+ args: serverArgs,
139
+ async run({ args }) {
140
+ await runEntryCommand(["--dev"], { ...args, nodeEnv: "development" }, args.entry);
141
+ }
174
142
  });
175
-
176
143
  const devWatchCommand = defineCommand({
177
- meta: {
178
- name: 'dev:watch',
179
- description: 'Start the development server with watch mode (restarts on file changes)',
180
- },
181
- args: serverArgs,
182
- async run({ args }) {
183
- await runEntryCommand(['--dev'], { ...args, watch: true, nodeEnv: 'development' }, args.entry);
184
- },
144
+ meta: {
145
+ name: "dev:watch",
146
+ description: "Start the development server with watch mode (restarts on file changes)"
147
+ },
148
+ args: serverArgs,
149
+ async run({ args }) {
150
+ await runEntryCommand(["--dev"], { ...args, watch: true, nodeEnv: "development" }, args.entry);
151
+ }
185
152
  });
186
-
187
153
  const devHotCommand = defineCommand({
188
- meta: {
189
- name: 'dev:hot',
190
- description: 'Start the development server with hot reload (HMR without restart)',
191
- },
192
- args: serverArgs,
193
- async run({ args }) {
194
- await runEntryCommand(['--dev'], { ...args, hot: true, nodeEnv: 'development' }, args.entry);
195
- },
154
+ meta: {
155
+ name: "dev:hot",
156
+ description: "Start the development server with hot reload (HMR without restart)"
157
+ },
158
+ args: serverArgs,
159
+ async run({ args }) {
160
+ await runEntryCommand(["--dev"], { ...args, hot: true, nodeEnv: "development" }, args.entry);
161
+ }
196
162
  });
197
-
198
163
  const buildCommand = defineCommand({
199
- meta: {
200
- name: 'build',
201
- description: 'Build the project for production',
202
- },
203
- args: {
204
- entry: {
205
- type: 'positional',
206
- description: 'Entry file',
207
- default: 'app.ts',
208
- },
209
- runtime: {
210
- type: 'string',
211
- description: 'Force a specific runtime (bun or node)',
212
- },
213
- },
214
- async run({ args }) {
215
- await runEntryCommand(['--build'], { nodeEnv: 'production', ...args }, args.entry);
216
- },
164
+ meta: {
165
+ name: "build",
166
+ description: "Build the project for production"
167
+ },
168
+ args: {
169
+ entry: {
170
+ type: "positional",
171
+ description: "Entry file",
172
+ default: "app.ts"
173
+ },
174
+ runtime: {
175
+ type: "string",
176
+ description: "Force a specific runtime (bun or node)"
177
+ }
178
+ },
179
+ async run({ args }) {
180
+ await runEntryCommand(["--build"], { nodeEnv: "production", ...args }, args.entry);
181
+ }
217
182
  });
218
-
219
183
  const startCommand = defineCommand({
220
- meta: {
221
- name: 'start',
222
- description: 'Start the production server',
223
- },
224
- args: serverArgs,
225
- async run({ args }) {
226
- await runEntryCommand([], { ...args, nodeEnv: 'production' }, args.entry);
227
- },
184
+ meta: {
185
+ name: "start",
186
+ description: "Start the production server"
187
+ },
188
+ args: serverArgs,
189
+ async run({ args }) {
190
+ await runEntryCommand([], { ...args, nodeEnv: "production" }, args.entry);
191
+ }
228
192
  });
229
-
230
193
  const previewCommand = defineCommand({
231
- meta: {
232
- name: 'preview',
233
- description: 'Preview the production build',
234
- },
235
- args: serverArgs,
236
- async run({ args }) {
237
- await runEntryCommand(['--preview'], { ...args, nodeEnv: 'production' }, args.entry);
238
- },
194
+ meta: {
195
+ name: "preview",
196
+ description: "Preview the production build"
197
+ },
198
+ args: serverArgs,
199
+ async run({ args }) {
200
+ await runEntryCommand(["--preview"], { ...args, nodeEnv: "production" }, args.entry);
201
+ }
239
202
  });
240
-
241
- export const mainCommand = defineCommand({
242
- meta: {
243
- name: 'ecopages',
244
- version: pkg.version,
245
- description: 'Ecopages CLI utilities',
246
- },
247
- subCommands: {
248
- init: initCommand,
249
- dev: devCommand,
250
- 'dev:watch': devWatchCommand,
251
- 'dev:hot': devHotCommand,
252
- build: buildCommand,
253
- start: startCommand,
254
- preview: previewCommand,
255
- },
203
+ const mainCommand = defineCommand({
204
+ meta: {
205
+ name: "ecopages",
206
+ version: pkg.version,
207
+ description: "Ecopages CLI utilities"
208
+ },
209
+ subCommands: {
210
+ init: initCommand,
211
+ dev: devCommand,
212
+ "dev:watch": devWatchCommand,
213
+ "dev:hot": devHotCommand,
214
+ build: buildCommand,
215
+ start: startCommand,
216
+ preview: previewCommand
217
+ }
256
218
  });
257
-
258
219
  if (!process.env.VITEST) {
259
- runMain(mainCommand);
220
+ runMain(mainCommand);
260
221
  }
222
+ export {
223
+ mainCommand
224
+ };