@chrisluyi/daas-cli 1.2.0 → 1.3.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/README.md +405 -0
- package/dist/index.js +206 -132
- package/package.json +6 -1
- package/dist/daas-bin +0 -0
package/README.md
ADDED
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
# daas-cli
|
|
2
|
+
|
|
3
|
+
Zero-config build/dev/test CLI for React micro-frontend (MFE) apps using [rsbuild](https://rsbuild.dev) + [Module Federation 2](https://module-federation.io).
|
|
4
|
+
|
|
5
|
+
MFE apps have **no build config files** — no `rsbuild.config.ts`, no `vitest.config.ts`. The CLI owns all of it.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Packages
|
|
10
|
+
|
|
11
|
+
| Package | Version | Description |
|
|
12
|
+
|---|---|---|
|
|
13
|
+
| [`@chrisluyi/daas-cli`](https://www.npmjs.com/package/@chrisluyi/daas-cli) | 1.1.0 | CLI binary — install this as your only devDependency |
|
|
14
|
+
| [`@chrisluyi/rsbuild-config`](https://www.npmjs.com/package/@chrisluyi/rsbuild-config) | 1.1.0 | rsbuild config factory + vitest config — arrives transitively |
|
|
15
|
+
| [`@chrisluyi/template`](https://www.npmjs.com/package/@chrisluyi/template) | 1.0.0 | MFE scaffold templates (services / containers / components structure) |
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
## Quickstart (3 commands)
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
mkdir my-mfe && cd my-mfe
|
|
23
|
+
echo '{"name":"my-mfe"}' > package.json
|
|
24
|
+
npx @chrisluyi/daas-cli init
|
|
25
|
+
bun install
|
|
26
|
+
daas dev
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Your MFE is now running at `http://localhost:3000` with Module Federation 2, React, hot-reload, and Vitest — zero config required.
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# In your MFE project
|
|
37
|
+
bun add -D @chrisluyi/daas-cli
|
|
38
|
+
|
|
39
|
+
# or npm
|
|
40
|
+
npm install -D @chrisluyi/daas-cli
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`daas-cli` is the **only** devDependency you need. It ships rsbuild, vitest, @testing-library/react, happy-dom, and all tooling as its own dependencies. Do not install these separately.
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Commands
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
daas init [--template default]
|
|
51
|
+
daas dev [target] [--port <n>] [--json]
|
|
52
|
+
daas build [target] [--json]
|
|
53
|
+
daas test [--json]
|
|
54
|
+
daas info [--json]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### `daas init`
|
|
58
|
+
|
|
59
|
+
Interactive scaffold powered by `@clack/prompts`. Prompts for remote config URL, port, and app name, then writes starter files.
|
|
60
|
+
|
|
61
|
+
```
|
|
62
|
+
┌ daas-cli — scaffold new MFE
|
|
63
|
+
│
|
|
64
|
+
◇ Remote config URL?
|
|
65
|
+
│ https://your-org.example.com/daas-config.json
|
|
66
|
+
│
|
|
67
|
+
◇ Dev server port?
|
|
68
|
+
│ 3001
|
|
69
|
+
│
|
|
70
|
+
◇ App name? (leave blank to use package.json name)
|
|
71
|
+
│ mfe-auth
|
|
72
|
+
│
|
|
73
|
+
◇ Does this app expose additional components beyond ./App?
|
|
74
|
+
│ No
|
|
75
|
+
│
|
|
76
|
+
◆ Scaffolding mfe-auth...
|
|
77
|
+
│ ✓ Created src/App.tsx
|
|
78
|
+
│ ✓ Created src/App.test.tsx
|
|
79
|
+
│ ✓ Created tsconfig.json
|
|
80
|
+
│ ✓ Updated package.json
|
|
81
|
+
│
|
|
82
|
+
└ Done! Run: bun install && daas dev
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**What gets created (minimal scaffold):**
|
|
86
|
+
|
|
87
|
+
```
|
|
88
|
+
src/
|
|
89
|
+
├── App.tsx # minimal React component
|
|
90
|
+
└── App.test.tsx # smoke test
|
|
91
|
+
tsconfig.json # jsx: react-jsx, strict mode
|
|
92
|
+
package.json # scripts + daas config injected
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**`--template default`** scaffolds the full opinionated structure:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
src/
|
|
99
|
+
├── App.tsx # entry — renders AppContainer
|
|
100
|
+
├── containers/
|
|
101
|
+
│ └── AppContainer.tsx # data-fetching component
|
|
102
|
+
├── components/
|
|
103
|
+
│ └── App.tsx # presentational component
|
|
104
|
+
├── services/
|
|
105
|
+
│ └── index.ts # service layer stub
|
|
106
|
+
└── config/
|
|
107
|
+
├── regions/ # per-region config (for v1.5 targets)
|
|
108
|
+
├── platforms/ # per-platform config
|
|
109
|
+
└── products/ # per-product config
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `daas dev`
|
|
113
|
+
|
|
114
|
+
Starts the rsbuild dev server with HMR and Module Federation 2 in remote mode.
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
daas dev # uses port from package.json#daas
|
|
118
|
+
daas dev --port 3002 # override port at runtime
|
|
119
|
+
daas dev sg-foo-mb-dev # v1.5: activate region/product/platform target
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `daas build`
|
|
123
|
+
|
|
124
|
+
Production build to `./dist`. Always fetches fresh remote config — fatal if network unavailable.
|
|
125
|
+
|
|
126
|
+
```bash
|
|
127
|
+
daas build
|
|
128
|
+
daas build sg-foo-mb-prod # v1.5: build for a specific target
|
|
129
|
+
daas build --json # machine-readable output (for CI / AI agents)
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### `daas test`
|
|
133
|
+
|
|
134
|
+
Runs Vitest with `happy-dom`, `@testing-library/react`, and `@testing-library/jest-dom` pre-configured. The following browser APIs are mocked automatically so MFE tests work without any extra setup:
|
|
135
|
+
|
|
136
|
+
- `window.matchMedia`
|
|
137
|
+
- `ResizeObserver`
|
|
138
|
+
- `IntersectionObserver`
|
|
139
|
+
- `window.scrollTo` / `scrollBy`
|
|
140
|
+
- `URL.createObjectURL` / `revokeObjectURL`
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
daas test
|
|
144
|
+
daas test --json
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**Writing tests** — import everything from `@chrisluyi/daas-cli/test` (no direct vitest or `@testing-library` imports needed):
|
|
148
|
+
|
|
149
|
+
```tsx
|
|
150
|
+
import { render, screen, describe, test, expect, userEvent } from "@chrisluyi/daas-cli/test"
|
|
151
|
+
import MyComponent from "./MyComponent"
|
|
152
|
+
|
|
153
|
+
describe("MyComponent", () => {
|
|
154
|
+
test("renders a button", async () => {
|
|
155
|
+
render(<MyComponent />)
|
|
156
|
+
await userEvent.click(screen.getByRole("button"))
|
|
157
|
+
expect(screen.getByText("Clicked!")).toBeInTheDocument()
|
|
158
|
+
})
|
|
159
|
+
})
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
**Adding extra setup** — append your own setup files after the built-in mocks via `package.json#daas.setupFiles`:
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"daas": {
|
|
167
|
+
"configUrl": "...",
|
|
168
|
+
"port": 3001,
|
|
169
|
+
"setupFiles": ["./src/test-setup.ts"]
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Your setup file can override any of the default mocks or add new ones.
|
|
175
|
+
|
|
176
|
+
### `daas info`
|
|
177
|
+
|
|
178
|
+
Prints the fully resolved project state — useful for debugging and AI agent diagnosis.
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
daas info --json
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
Example output:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"ok": true,
|
|
189
|
+
"command": "info",
|
|
190
|
+
"cliVersion": "1.1.0",
|
|
191
|
+
"appName": "mfe-auth",
|
|
192
|
+
"port": 3001,
|
|
193
|
+
"configUrl": "https://your-org.example.com/daas-config.json",
|
|
194
|
+
"manifest": {
|
|
195
|
+
"name": "mfe-auth",
|
|
196
|
+
"exposes": { "./App": "./src/App" }
|
|
197
|
+
},
|
|
198
|
+
"remoteJson": {
|
|
199
|
+
"version": "1.0.0",
|
|
200
|
+
"minCliVersion": "1.0.0",
|
|
201
|
+
"shared": { "react": "18.3.1", "react-dom": "18.3.1" },
|
|
202
|
+
"rsbuildConfigVersion": 1
|
|
203
|
+
},
|
|
204
|
+
"isMonorepo": false
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
---
|
|
209
|
+
|
|
210
|
+
## Per-App Config (`package.json#daas`)
|
|
211
|
+
|
|
212
|
+
All MFE-specific configuration lives in `package.json`:
|
|
213
|
+
|
|
214
|
+
```json
|
|
215
|
+
{
|
|
216
|
+
"name": "mfe-auth",
|
|
217
|
+
"scripts": {
|
|
218
|
+
"dev": "daas dev",
|
|
219
|
+
"build": "daas build",
|
|
220
|
+
"test": "daas test"
|
|
221
|
+
},
|
|
222
|
+
"devDependencies": {
|
|
223
|
+
"@chrisluyi/daas-cli": "^1.1.0"
|
|
224
|
+
},
|
|
225
|
+
"daas": {
|
|
226
|
+
"configUrl": "https://your-org.example.com/daas-config.json",
|
|
227
|
+
"port": 3001,
|
|
228
|
+
"coverage": {
|
|
229
|
+
"lines": 80,
|
|
230
|
+
"branches": 80
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
| Field | Required | Description |
|
|
237
|
+
|---|---|---|
|
|
238
|
+
| `configUrl` | Yes | URL of the remote JSON config owned by your platform team |
|
|
239
|
+
| `port` | Yes | Dev server port — must be unique per MFE in a monorepo |
|
|
240
|
+
| `coverage` | No | Vitest coverage thresholds |
|
|
241
|
+
| `setupFiles` | No | Extra Vitest setup files appended after the built-in browser mocks |
|
|
242
|
+
|
|
243
|
+
---
|
|
244
|
+
|
|
245
|
+
## Optional Manifest (`mf.manifest.json`)
|
|
246
|
+
|
|
247
|
+
Only needed when exposing more than just `./App`:
|
|
248
|
+
|
|
249
|
+
```json
|
|
250
|
+
{
|
|
251
|
+
"name": "mfe-auth",
|
|
252
|
+
"exposes": {
|
|
253
|
+
"./App": "./src/App",
|
|
254
|
+
"./LoginButton": "./src/components/LoginButton"
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
If absent, `name` derives from `package.json#name` (scope stripped), and `exposes` defaults to `{ "./App": "./src/App" }`.
|
|
260
|
+
|
|
261
|
+
---
|
|
262
|
+
|
|
263
|
+
## Remote JSON (served by your platform team)
|
|
264
|
+
|
|
265
|
+
The URL in `configUrl` must serve a JSON file like this:
|
|
266
|
+
|
|
267
|
+
```json
|
|
268
|
+
{
|
|
269
|
+
"version": "1.0.0",
|
|
270
|
+
"minCliVersion": "1.0.0",
|
|
271
|
+
"releaseNotesUrl": "https://your-org.example.com/daas-cli/releases",
|
|
272
|
+
"shared": {
|
|
273
|
+
"react": "18.3.1",
|
|
274
|
+
"react-dom": "18.3.1"
|
|
275
|
+
},
|
|
276
|
+
"rsbuildConfigVersion": 1
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
This controls which version of shared dependencies all your MFEs use via Module Federation 2's singleton negotiation. The CLI fetches this at dev startup (5-min cache) and always fresh at build time.
|
|
281
|
+
|
|
282
|
+
---
|
|
283
|
+
|
|
284
|
+
## Monorepo Support
|
|
285
|
+
|
|
286
|
+
`daas init` detects monorepos by walking parent directories for `bun.lockb` or `package.json#workspaces`. In a monorepo:
|
|
287
|
+
|
|
288
|
+
- `daas-cli` is **not** added to the app's `devDependencies` (it's resolved from the workspace root)
|
|
289
|
+
- Each MFE has its own `port` in `package.json#daas`
|
|
290
|
+
|
|
291
|
+
```
|
|
292
|
+
my-monorepo/
|
|
293
|
+
├── package.json # workspaces: ["packages/*"]
|
|
294
|
+
├── bun.lockb
|
|
295
|
+
└── packages/
|
|
296
|
+
├── mfe-auth/ # daas dev → port 3001
|
|
297
|
+
│ └── package.json # { "daas": { "port": 3001, ... } }
|
|
298
|
+
└── mfe-dashboard/ # daas dev → port 3002
|
|
299
|
+
└── package.json # { "daas": { "port": 3002, ... } }
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
## v1.5 — Multi-Region Target System
|
|
305
|
+
|
|
306
|
+
Target strings let you select region/product/platform/environment at dev and build time:
|
|
307
|
+
|
|
308
|
+
```
|
|
309
|
+
daas dev sg-foo-mb-dev
|
|
310
|
+
│ │ │ └─ environment (dev / staging / prod)
|
|
311
|
+
│ │ └──── platform (mb = mobile, wb = web, etc.)
|
|
312
|
+
│ └──────── product (may contain hyphens)
|
|
313
|
+
└──────────── region (sg, us, eu, …)
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
When a target is provided:
|
|
317
|
+
1. The CLI resolves a `TargetContext` from the string
|
|
318
|
+
2. `tsconfig.daas.json` is generated (gitignored) with path aliases:
|
|
319
|
+
- `@region-config` → `./src/config/regions/<region>`
|
|
320
|
+
- `@platform-config` → `./src/config/platforms/<platform>`
|
|
321
|
+
- `@product-config` → `./src/config/products/<product>`
|
|
322
|
+
3. Environment variables are injected at build time: `DAAS_REGION`, `DAAS_PRODUCT`, `DAAS_PLATFORM`, `DAAS_ENV`
|
|
323
|
+
|
|
324
|
+
Use `daas init --template default` to scaffold the config layer folder structure.
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Exit Codes
|
|
329
|
+
|
|
330
|
+
| Code | Meaning | What to do |
|
|
331
|
+
|---|---|---|
|
|
332
|
+
| `0` | Success | — |
|
|
333
|
+
| `1` | General error (build/test failure) | Check output above the JSON |
|
|
334
|
+
| `2` | Config error (missing `configUrl`, bad manifest) | Run `daas init` or fix `package.json#daas` |
|
|
335
|
+
| `3` | CLI too old (`minCliVersion` not met) | Upgrade `@chrisluyi/daas-cli` |
|
|
336
|
+
| `4` | Remote JSON fetch failed | Check network / VPN (only fatal in `build`) |
|
|
337
|
+
| `5` | Config version mismatch | Upgrade `@chrisluyi/daas-cli` |
|
|
338
|
+
|
|
339
|
+
---
|
|
340
|
+
|
|
341
|
+
## `--json` Output Contract
|
|
342
|
+
|
|
343
|
+
All commands except `init` support `--json` — always use this in CI and AI agent workflows.
|
|
344
|
+
|
|
345
|
+
**Success:**
|
|
346
|
+
```json
|
|
347
|
+
{
|
|
348
|
+
"ok": true,
|
|
349
|
+
"command": "build",
|
|
350
|
+
"appName": "mfe-auth",
|
|
351
|
+
"output": "./dist",
|
|
352
|
+
"cliVersion": "1.1.0"
|
|
353
|
+
}
|
|
354
|
+
```
|
|
355
|
+
|
|
356
|
+
**Error:**
|
|
357
|
+
```json
|
|
358
|
+
{
|
|
359
|
+
"ok": false,
|
|
360
|
+
"command": "build",
|
|
361
|
+
"exitCode": 4,
|
|
362
|
+
"error": "Could not fetch remote config: HTTP 503",
|
|
363
|
+
"suggestion": "Check network connectivity or VPN.",
|
|
364
|
+
"cliVersion": "1.1.0"
|
|
365
|
+
}
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
---
|
|
369
|
+
|
|
370
|
+
## AI Agent Support (Claude Code)
|
|
371
|
+
|
|
372
|
+
Register the bundled skill so Claude Code understands `daas-cli` without hallucinating commands:
|
|
373
|
+
|
|
374
|
+
```bash
|
|
375
|
+
# Per-project
|
|
376
|
+
mkdir -p .claude/skills
|
|
377
|
+
cp node_modules/@chrisluyi/daas-cli/skill.md .claude/skills/daas-cli.md
|
|
378
|
+
|
|
379
|
+
# Or globally
|
|
380
|
+
cp node_modules/@chrisluyi/daas-cli/skill.md ~/.claude/skills/daas-cli.md
|
|
381
|
+
```
|
|
382
|
+
|
|
383
|
+
**AI agent workflow:**
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
# 1. Always start here to understand current state
|
|
387
|
+
daas info --json
|
|
388
|
+
|
|
389
|
+
# 2. Run commands and parse stdout JSON
|
|
390
|
+
daas build --json
|
|
391
|
+
# { "ok": true, ... } or { "ok": false, "exitCode": N, "error": "...", "suggestion": "..." }
|
|
392
|
+
```
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
396
|
+
## Development (this repo)
|
|
397
|
+
|
|
398
|
+
```bash
|
|
399
|
+
bun install
|
|
400
|
+
bun test # run all tests
|
|
401
|
+
bun run build # build both packages to dist/
|
|
402
|
+
bun run lint # biome check
|
|
403
|
+
```
|
|
404
|
+
|
|
405
|
+
See [`docs/DEVELOPMENT.md`](docs/DEVELOPMENT.md) for the full release workflow.
|
package/dist/index.js
CHANGED
|
@@ -2311,12 +2311,12 @@ async function runMain(cmd, opts = {}) {
|
|
|
2311
2311
|
}
|
|
2312
2312
|
}
|
|
2313
2313
|
|
|
2314
|
-
// src/commands/
|
|
2315
|
-
import { createRsbuild } from "@rsbuild/core";
|
|
2314
|
+
// src/commands/build.ts
|
|
2316
2315
|
import { createConfig } from "@chrisluyi/rsbuild-config";
|
|
2316
|
+
import { createRsbuild } from "@rsbuild/core";
|
|
2317
2317
|
|
|
2318
2318
|
// src/daas-config.ts
|
|
2319
|
-
import {
|
|
2319
|
+
import { existsSync, readFileSync } from "fs";
|
|
2320
2320
|
import { resolve } from "path";
|
|
2321
2321
|
|
|
2322
2322
|
class ConfigError extends Error {
|
|
@@ -2344,7 +2344,7 @@ function readDaasConfig(cwd = process.cwd()) {
|
|
|
2344
2344
|
}
|
|
2345
2345
|
|
|
2346
2346
|
// src/manifest.ts
|
|
2347
|
-
import {
|
|
2347
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
2348
2348
|
import { resolve as resolve2 } from "path";
|
|
2349
2349
|
|
|
2350
2350
|
class ManifestError extends Error {
|
|
@@ -2387,6 +2387,33 @@ function stripScope(name) {
|
|
|
2387
2387
|
return name.replace(/^@[^/]+\//, "");
|
|
2388
2388
|
}
|
|
2389
2389
|
|
|
2390
|
+
// src/output.ts
|
|
2391
|
+
function formatSuccess(command, data) {
|
|
2392
|
+
return { ok: true, command, cliVersion: getCliVersion(), ...data };
|
|
2393
|
+
}
|
|
2394
|
+
function formatError(command, exitCode, error, suggestion) {
|
|
2395
|
+
return {
|
|
2396
|
+
ok: false,
|
|
2397
|
+
command,
|
|
2398
|
+
exitCode,
|
|
2399
|
+
error,
|
|
2400
|
+
suggestion,
|
|
2401
|
+
cliVersion: getCliVersion()
|
|
2402
|
+
};
|
|
2403
|
+
}
|
|
2404
|
+
function writeJsonSuccess(command, data) {
|
|
2405
|
+
process.stdout.write(`${JSON.stringify(formatSuccess(command, data))}
|
|
2406
|
+
`);
|
|
2407
|
+
}
|
|
2408
|
+
function writeJsonError(command, exitCode, error, suggestion) {
|
|
2409
|
+
process.stdout.write(`${JSON.stringify(formatError(command, exitCode, error, suggestion))}
|
|
2410
|
+
`);
|
|
2411
|
+
process.exit(exitCode);
|
|
2412
|
+
}
|
|
2413
|
+
function getCliVersion() {
|
|
2414
|
+
return process.env.DAAS_CLI_VERSION ?? "0.0.0";
|
|
2415
|
+
}
|
|
2416
|
+
|
|
2390
2417
|
// src/remote-config.ts
|
|
2391
2418
|
import { SUPPORTED_CONFIG_VERSION } from "@chrisluyi/rsbuild-config";
|
|
2392
2419
|
// src/fallback-config.json
|
|
@@ -2498,34 +2525,15 @@ function generateTsconfigDaas(cwd, target) {
|
|
|
2498
2525
|
extends: "./tsconfig.json",
|
|
2499
2526
|
compilerOptions: {
|
|
2500
2527
|
paths: {
|
|
2501
|
-
"@region-config": [`./src/config/regions/${target.region}`],
|
|
2528
|
+
"@region-config": [`./src/config/regions/${target.region}/config`],
|
|
2502
2529
|
"@platform-config": [`./src/config/platforms/${target.platform}`],
|
|
2503
|
-
"@product-config": [`./src/config/products/${target.product}`]
|
|
2530
|
+
"@product-config": [`./src/config/products/${target.product}`],
|
|
2531
|
+
"@regional": [`./src/config/regions/${target.region}/index`]
|
|
2504
2532
|
}
|
|
2505
2533
|
}
|
|
2506
2534
|
};
|
|
2507
|
-
writeFileSync(resolve3(cwd, "tsconfig.daas.json"), JSON.stringify(content, null, 2)
|
|
2508
|
-
`);
|
|
2509
|
-
}
|
|
2510
|
-
|
|
2511
|
-
// src/output.ts
|
|
2512
|
-
function formatSuccess(command, data) {
|
|
2513
|
-
return { ok: true, command, cliVersion: getCliVersion(), ...data };
|
|
2514
|
-
}
|
|
2515
|
-
function formatError(command, exitCode, error, suggestion) {
|
|
2516
|
-
return { ok: false, command, exitCode, error, suggestion, cliVersion: getCliVersion() };
|
|
2517
|
-
}
|
|
2518
|
-
function writeJsonSuccess(command, data) {
|
|
2519
|
-
process.stdout.write(JSON.stringify(formatSuccess(command, data)) + `
|
|
2520
|
-
`);
|
|
2521
|
-
}
|
|
2522
|
-
function writeJsonError(command, exitCode, error, suggestion) {
|
|
2523
|
-
process.stdout.write(JSON.stringify(formatError(command, exitCode, error, suggestion)) + `
|
|
2535
|
+
writeFileSync(resolve3(cwd, "tsconfig.daas.json"), `${JSON.stringify(content, null, 2)}
|
|
2524
2536
|
`);
|
|
2525
|
-
process.exit(exitCode);
|
|
2526
|
-
}
|
|
2527
|
-
function getCliVersion() {
|
|
2528
|
-
return process.env.DAAS_CLI_VERSION ?? "0.0.0";
|
|
2529
2537
|
}
|
|
2530
2538
|
|
|
2531
2539
|
// src/types.ts
|
|
@@ -2538,78 +2546,20 @@ var EXIT_CODES = {
|
|
|
2538
2546
|
CONFIG_VERSION_MISMATCH: 5
|
|
2539
2547
|
};
|
|
2540
2548
|
|
|
2541
|
-
// src/commands/dev.ts
|
|
2542
|
-
var devCommand = defineCommand({
|
|
2543
|
-
meta: { name: "dev", description: "Start MFE dev server" },
|
|
2544
|
-
args: {
|
|
2545
|
-
target: { type: "positional", description: "Build target (e.g. sg-foo-mb-dev)", required: false },
|
|
2546
|
-
port: { type: "string", description: "Override dev server port" },
|
|
2547
|
-
json: { type: "boolean", default: false, description: "Machine-readable JSON output" }
|
|
2548
|
-
},
|
|
2549
|
-
async run({ args }) {
|
|
2550
|
-
try {
|
|
2551
|
-
const daasConfig = readDaasConfig();
|
|
2552
|
-
const manifest = readManifest();
|
|
2553
|
-
const remoteMeta = await fetchRemoteConfig(daasConfig.configUrl, false);
|
|
2554
|
-
checkCliVersion(remoteMeta);
|
|
2555
|
-
const versionOk = checkConfigVersion(remoteMeta, false);
|
|
2556
|
-
if (!versionOk) {
|
|
2557
|
-
consola.warn("Config version mismatch \u2014 update daas-cli for full compatibility");
|
|
2558
|
-
}
|
|
2559
|
-
const port = args.port ? Number(args.port) : daasConfig.port;
|
|
2560
|
-
const target = args.target ? parseTarget(args.target) : undefined;
|
|
2561
|
-
if (target) {
|
|
2562
|
-
generateTsconfigDaas(process.cwd(), target);
|
|
2563
|
-
consola.info(`Target: ${args.target} (region=${target.region}, product=${target.product}, platform=${target.platform}, env=${target.environment})`);
|
|
2564
|
-
}
|
|
2565
|
-
const config = createConfig(manifest, remoteMeta, { mode: "development", port, target });
|
|
2566
|
-
consola.start(`Starting ${manifest.name} dev server...`);
|
|
2567
|
-
const rsbuild = await createRsbuild({ rsbuildConfig: config });
|
|
2568
|
-
const server = await rsbuild.createDevServer();
|
|
2569
|
-
await server.listen();
|
|
2570
|
-
consola.success(`Ready on http://localhost:${port}`);
|
|
2571
|
-
} catch (e2) {
|
|
2572
|
-
handleError("dev", e2, args.json);
|
|
2573
|
-
}
|
|
2574
|
-
}
|
|
2575
|
-
});
|
|
2576
|
-
function handleError(command, e2, json) {
|
|
2577
|
-
if (e2 instanceof CliVersionError) {
|
|
2578
|
-
if (json)
|
|
2579
|
-
writeJsonError(command, EXIT_CODES.CLI_TOO_OLD, e2.message, "Update daas-cli to the required version.");
|
|
2580
|
-
consola.fatal(e2.message);
|
|
2581
|
-
process.exit(EXIT_CODES.CLI_TOO_OLD);
|
|
2582
|
-
}
|
|
2583
|
-
if (e2 instanceof FetchError) {
|
|
2584
|
-
if (json)
|
|
2585
|
-
writeJsonError(command, EXIT_CODES.REMOTE_FETCH_FAILED, e2.message, "Check network or VPN.");
|
|
2586
|
-
consola.warn(`Remote config unavailable \u2014 using fallback. ${e2.message}`);
|
|
2587
|
-
process.exit(EXIT_CODES.REMOTE_FETCH_FAILED);
|
|
2588
|
-
}
|
|
2589
|
-
if (e2 instanceof TargetParseError) {
|
|
2590
|
-
if (json)
|
|
2591
|
-
writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Check target format: {region}-{product}-{platform}-{environment}");
|
|
2592
|
-
consola.fatal(e2.message);
|
|
2593
|
-
process.exit(EXIT_CODES.CONFIG_ERROR);
|
|
2594
|
-
}
|
|
2595
|
-
if (e2 instanceof ConfigError || e2 instanceof ManifestError) {
|
|
2596
|
-
if (json)
|
|
2597
|
-
writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Run daas init first.");
|
|
2598
|
-
consola.fatal(e2.message);
|
|
2599
|
-
process.exit(EXIT_CODES.CONFIG_ERROR);
|
|
2600
|
-
}
|
|
2601
|
-
consola.fatal(e2);
|
|
2602
|
-
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
2603
|
-
}
|
|
2604
|
-
|
|
2605
2549
|
// src/commands/build.ts
|
|
2606
|
-
import { createRsbuild as createRsbuild2 } from "@rsbuild/core";
|
|
2607
|
-
import { createConfig as createConfig2 } from "@chrisluyi/rsbuild-config";
|
|
2608
2550
|
var buildCommand = defineCommand({
|
|
2609
2551
|
meta: { name: "build", description: "Build MFE for production" },
|
|
2610
2552
|
args: {
|
|
2611
|
-
target: {
|
|
2612
|
-
|
|
2553
|
+
target: {
|
|
2554
|
+
type: "positional",
|
|
2555
|
+
description: "Build target (e.g. sg-foo-mb-prod)",
|
|
2556
|
+
required: false
|
|
2557
|
+
},
|
|
2558
|
+
json: {
|
|
2559
|
+
type: "boolean",
|
|
2560
|
+
default: false,
|
|
2561
|
+
description: "Machine-readable JSON output"
|
|
2562
|
+
}
|
|
2613
2563
|
},
|
|
2614
2564
|
async run({ args }) {
|
|
2615
2565
|
const json = args.json;
|
|
@@ -2624,8 +2574,11 @@ var buildCommand = defineCommand({
|
|
|
2624
2574
|
const target = args.target ? parseTarget(args.target) : undefined;
|
|
2625
2575
|
if (target)
|
|
2626
2576
|
generateTsconfigDaas(process.cwd(), target);
|
|
2627
|
-
const config =
|
|
2628
|
-
|
|
2577
|
+
const config = createConfig(manifest, remoteMeta, {
|
|
2578
|
+
mode: "production",
|
|
2579
|
+
target
|
|
2580
|
+
});
|
|
2581
|
+
const rsbuild = await createRsbuild({ rsbuildConfig: config });
|
|
2629
2582
|
await rsbuild.build();
|
|
2630
2583
|
if (json)
|
|
2631
2584
|
writeJsonSuccess("build", { appName: manifest.name, output: "./dist" });
|
|
@@ -2667,41 +2620,87 @@ var buildCommand = defineCommand({
|
|
|
2667
2620
|
}
|
|
2668
2621
|
});
|
|
2669
2622
|
|
|
2670
|
-
// src/commands/
|
|
2671
|
-
import {
|
|
2672
|
-
import {
|
|
2673
|
-
var
|
|
2674
|
-
meta: { name: "
|
|
2623
|
+
// src/commands/dev.ts
|
|
2624
|
+
import { createConfig as createConfig2 } from "@chrisluyi/rsbuild-config";
|
|
2625
|
+
import { createRsbuild as createRsbuild2 } from "@rsbuild/core";
|
|
2626
|
+
var devCommand = defineCommand({
|
|
2627
|
+
meta: { name: "dev", description: "Start MFE dev server" },
|
|
2675
2628
|
args: {
|
|
2676
|
-
|
|
2629
|
+
target: {
|
|
2630
|
+
type: "positional",
|
|
2631
|
+
description: "Build target (e.g. sg-foo-mb-dev)",
|
|
2632
|
+
required: false
|
|
2633
|
+
},
|
|
2634
|
+
port: { type: "string", description: "Override dev server port" },
|
|
2635
|
+
json: {
|
|
2636
|
+
type: "boolean",
|
|
2637
|
+
default: false,
|
|
2638
|
+
description: "Machine-readable JSON output"
|
|
2639
|
+
}
|
|
2677
2640
|
},
|
|
2678
2641
|
async run({ args }) {
|
|
2679
|
-
const json = args.json;
|
|
2680
2642
|
try {
|
|
2681
|
-
const manifest = readManifest();
|
|
2682
2643
|
const daasConfig = readDaasConfig();
|
|
2683
|
-
const
|
|
2684
|
-
const
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
writeJsonSuccess("test", { appName: manifest.name, passed: !failed });
|
|
2644
|
+
const manifest = readManifest();
|
|
2645
|
+
const remoteMeta = await fetchRemoteConfig(daasConfig.configUrl, false);
|
|
2646
|
+
checkCliVersion(remoteMeta);
|
|
2647
|
+
const versionOk = checkConfigVersion(remoteMeta, false);
|
|
2648
|
+
if (!versionOk) {
|
|
2649
|
+
consola.warn("Config version mismatch \u2014 update daas-cli for full compatibility");
|
|
2690
2650
|
}
|
|
2691
|
-
|
|
2692
|
-
|
|
2651
|
+
const port = args.port ? Number(args.port) : daasConfig.port;
|
|
2652
|
+
const target = args.target ? parseTarget(args.target) : undefined;
|
|
2653
|
+
if (target) {
|
|
2654
|
+
generateTsconfigDaas(process.cwd(), target);
|
|
2655
|
+
consola.info(`Target: ${args.target} (region=${target.region}, product=${target.product}, platform=${target.platform}, env=${target.environment})`);
|
|
2656
|
+
}
|
|
2657
|
+
const config = createConfig2(manifest, remoteMeta, {
|
|
2658
|
+
mode: "development",
|
|
2659
|
+
port,
|
|
2660
|
+
target
|
|
2661
|
+
});
|
|
2662
|
+
consola.start(`Starting ${manifest.name} dev server...`);
|
|
2663
|
+
const rsbuild = await createRsbuild2({ rsbuildConfig: config });
|
|
2664
|
+
const server = await rsbuild.createDevServer();
|
|
2665
|
+
await server.listen();
|
|
2666
|
+
consola.success(`Ready on http://localhost:${port}`);
|
|
2693
2667
|
} catch (e2) {
|
|
2694
|
-
|
|
2695
|
-
writeJsonError("test", EXIT_CODES.GENERAL_ERROR, e2.message, "Check test configuration");
|
|
2696
|
-
consola.fatal(e2);
|
|
2697
|
-
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
2668
|
+
handleError("dev", e2, args.json);
|
|
2698
2669
|
}
|
|
2699
2670
|
}
|
|
2700
2671
|
});
|
|
2672
|
+
function handleError(command, e2, json) {
|
|
2673
|
+
if (e2 instanceof CliVersionError) {
|
|
2674
|
+
if (json)
|
|
2675
|
+
writeJsonError(command, EXIT_CODES.CLI_TOO_OLD, e2.message, "Update daas-cli to the required version.");
|
|
2676
|
+
consola.fatal(e2.message);
|
|
2677
|
+
process.exit(EXIT_CODES.CLI_TOO_OLD);
|
|
2678
|
+
}
|
|
2679
|
+
if (e2 instanceof FetchError) {
|
|
2680
|
+
if (json)
|
|
2681
|
+
writeJsonError(command, EXIT_CODES.REMOTE_FETCH_FAILED, e2.message, "Check network or VPN.");
|
|
2682
|
+
consola.warn(`Remote config unavailable \u2014 using fallback. ${e2.message}`);
|
|
2683
|
+
process.exit(EXIT_CODES.REMOTE_FETCH_FAILED);
|
|
2684
|
+
}
|
|
2685
|
+
if (e2 instanceof TargetParseError) {
|
|
2686
|
+
if (json)
|
|
2687
|
+
writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Check target format: {region}-{product}-{platform}-{environment}");
|
|
2688
|
+
consola.fatal(e2.message);
|
|
2689
|
+
process.exit(EXIT_CODES.CONFIG_ERROR);
|
|
2690
|
+
}
|
|
2691
|
+
if (e2 instanceof ConfigError || e2 instanceof ManifestError) {
|
|
2692
|
+
if (json)
|
|
2693
|
+
writeJsonError(command, EXIT_CODES.CONFIG_ERROR, e2.message, "Run daas init first.");
|
|
2694
|
+
consola.fatal(e2.message);
|
|
2695
|
+
process.exit(EXIT_CODES.CONFIG_ERROR);
|
|
2696
|
+
}
|
|
2697
|
+
consola.fatal(e2);
|
|
2698
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
2699
|
+
}
|
|
2701
2700
|
|
|
2702
2701
|
// src/init/monorepo.ts
|
|
2703
2702
|
import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
|
|
2704
|
-
import { resolve as resolve4
|
|
2703
|
+
import { dirname, resolve as resolve4 } from "path";
|
|
2705
2704
|
function detectMonorepo(startDir) {
|
|
2706
2705
|
let dir = startDir;
|
|
2707
2706
|
for (let i2 = 0;i2 < 10; i2++) {
|
|
@@ -2727,7 +2726,11 @@ function detectMonorepo(startDir) {
|
|
|
2727
2726
|
var infoCommand = defineCommand({
|
|
2728
2727
|
meta: { name: "info", description: "Show resolved MFE project state" },
|
|
2729
2728
|
args: {
|
|
2730
|
-
json: {
|
|
2729
|
+
json: {
|
|
2730
|
+
type: "boolean",
|
|
2731
|
+
default: false,
|
|
2732
|
+
description: "Machine-readable JSON output"
|
|
2733
|
+
}
|
|
2731
2734
|
},
|
|
2732
2735
|
async run({ args }) {
|
|
2733
2736
|
const json = args.json;
|
|
@@ -2766,6 +2769,9 @@ var infoCommand = defineCommand({
|
|
|
2766
2769
|
});
|
|
2767
2770
|
|
|
2768
2771
|
// src/commands/init.ts
|
|
2772
|
+
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
2773
|
+
import { createRequire } from "module";
|
|
2774
|
+
import { resolve as resolve6 } from "path";
|
|
2769
2775
|
import { scaffold } from "@chrisluyi/template";
|
|
2770
2776
|
|
|
2771
2777
|
// ../../node_modules/.bun/@clack+core@0.3.5/node_modules/@clack/core/dist/index.mjs
|
|
@@ -3258,12 +3264,8 @@ var de = () => {
|
|
|
3258
3264
|
return process.on("uncaughtExceptionMonitor", () => $2(2)), process.on("unhandledRejection", () => $2(2)), process.on("SIGINT", () => $2(1)), process.on("SIGTERM", () => $2(1)), process.on("exit", $2), { start: l3, stop: u3, message: m3 };
|
|
3259
3265
|
};
|
|
3260
3266
|
|
|
3261
|
-
// src/commands/init.ts
|
|
3262
|
-
import { existsSync as existsSync6, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "fs";
|
|
3263
|
-
import { resolve as resolve6 } from "path";
|
|
3264
|
-
|
|
3265
3267
|
// src/init/copy-template.ts
|
|
3266
|
-
import { existsSync as existsSync4,
|
|
3268
|
+
import { copyFileSync, existsSync as existsSync4, mkdirSync, readdirSync } from "fs";
|
|
3267
3269
|
import { dirname as dirname2, join } from "path";
|
|
3268
3270
|
import { fileURLToPath } from "url";
|
|
3269
3271
|
var __dirname2 = dirname2(fileURLToPath(import.meta.url));
|
|
@@ -3280,7 +3282,9 @@ async function copyTemplate(destDir) {
|
|
|
3280
3282
|
mkdirSync(join(destDir, "src"), { recursive: true });
|
|
3281
3283
|
}
|
|
3282
3284
|
if (existsSync4(dest)) {
|
|
3283
|
-
const overwrite = await se({
|
|
3285
|
+
const overwrite = await se({
|
|
3286
|
+
message: `${destFile} already exists. Overwrite?`
|
|
3287
|
+
});
|
|
3284
3288
|
if (!overwrite) {
|
|
3285
3289
|
result.skipped.push(destFile);
|
|
3286
3290
|
continue;
|
|
@@ -3293,7 +3297,7 @@ async function copyTemplate(destDir) {
|
|
|
3293
3297
|
}
|
|
3294
3298
|
|
|
3295
3299
|
// src/init/package-json.ts
|
|
3296
|
-
import {
|
|
3300
|
+
import { existsSync as existsSync5, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "fs";
|
|
3297
3301
|
import { resolve as resolve5 } from "path";
|
|
3298
3302
|
function updatePackageJson(cwd, opts) {
|
|
3299
3303
|
const pkgPath = resolve5(cwd, "package.json");
|
|
@@ -3304,6 +3308,17 @@ function updatePackageJson(cwd, opts) {
|
|
|
3304
3308
|
build: "daas build",
|
|
3305
3309
|
test: "daas test"
|
|
3306
3310
|
};
|
|
3311
|
+
pkg.dependencies = {
|
|
3312
|
+
...pkg.dependencies ?? {},
|
|
3313
|
+
"@radix-ui/react-tabs": "^1.1.0",
|
|
3314
|
+
...opts.isFullTemplate ? {
|
|
3315
|
+
"@chrisluyi/template": `^${opts.templateVersion ?? opts.cliVersion ?? "1.0.0"}`,
|
|
3316
|
+
"@tanstack/react-query": "^5.0.0",
|
|
3317
|
+
zustand: "^5.0.0",
|
|
3318
|
+
immer: "^10.0.0",
|
|
3319
|
+
zod: "^3.23.0"
|
|
3320
|
+
} : {}
|
|
3321
|
+
};
|
|
3307
3322
|
if (!opts.isMonorepo) {
|
|
3308
3323
|
pkg.devDependencies = {
|
|
3309
3324
|
...pkg.devDependencies ?? {},
|
|
@@ -3311,7 +3326,7 @@ function updatePackageJson(cwd, opts) {
|
|
|
3311
3326
|
};
|
|
3312
3327
|
}
|
|
3313
3328
|
pkg.daas = { configUrl: opts.configUrl, port: opts.port };
|
|
3314
|
-
writeFileSync2(pkgPath, JSON.stringify(pkg, null, 2)
|
|
3329
|
+
writeFileSync2(pkgPath, `${JSON.stringify(pkg, null, 2)}
|
|
3315
3330
|
`);
|
|
3316
3331
|
}
|
|
3317
3332
|
|
|
@@ -3320,7 +3335,10 @@ var KNOWN_TEMPLATES = ["default"];
|
|
|
3320
3335
|
var initCommand = defineCommand({
|
|
3321
3336
|
meta: { name: "init", description: "Scaffold a new MFE app" },
|
|
3322
3337
|
args: {
|
|
3323
|
-
template: {
|
|
3338
|
+
template: {
|
|
3339
|
+
type: "string",
|
|
3340
|
+
description: "Template name. Use 'default' for the full services/containers/components structure."
|
|
3341
|
+
}
|
|
3324
3342
|
},
|
|
3325
3343
|
async run({ args }) {
|
|
3326
3344
|
if (!process.stdin.isTTY) {
|
|
@@ -3364,7 +3382,9 @@ var initCommand = defineCommand({
|
|
|
3364
3382
|
appName,
|
|
3365
3383
|
onConflict: async (relPath) => {
|
|
3366
3384
|
s2.stop("");
|
|
3367
|
-
const overwrite = await se({
|
|
3385
|
+
const overwrite = await se({
|
|
3386
|
+
message: `${relPath} already exists. Overwrite?`
|
|
3387
|
+
});
|
|
3368
3388
|
s2.start(`Scaffolding ${appName}...`);
|
|
3369
3389
|
return overwrite;
|
|
3370
3390
|
}
|
|
@@ -3380,11 +3400,17 @@ var initCommand = defineCommand({
|
|
|
3380
3400
|
s2.message(`\u2713 Created ${f4}`);
|
|
3381
3401
|
for (const f4 of skipped)
|
|
3382
3402
|
s2.message(`\u2014 Skipped ${f4} (kept existing)`);
|
|
3383
|
-
updatePackageJson(cwd, {
|
|
3403
|
+
updatePackageJson(cwd, {
|
|
3404
|
+
configUrl,
|
|
3405
|
+
port,
|
|
3406
|
+
isMonorepo,
|
|
3407
|
+
isFullTemplate: useFullTemplate,
|
|
3408
|
+
templateVersion: getTemplateVersion()
|
|
3409
|
+
});
|
|
3384
3410
|
s2.message("\u2713 Updated package.json");
|
|
3385
3411
|
if (hasExtraExposes) {
|
|
3386
3412
|
const manifest = { name: appName, exposes: { "./App": "./src/App" } };
|
|
3387
|
-
writeFileSync3(resolve6(cwd, "mf.manifest.json"), JSON.stringify(manifest, null, 2)
|
|
3413
|
+
writeFileSync3(resolve6(cwd, "mf.manifest.json"), `${JSON.stringify(manifest, null, 2)}
|
|
3388
3414
|
`);
|
|
3389
3415
|
s2.message("\u2713 Created mf.manifest.json (add extra exposes as needed)");
|
|
3390
3416
|
}
|
|
@@ -3392,6 +3418,15 @@ var initCommand = defineCommand({
|
|
|
3392
3418
|
$e(isMonorepo ? "Run: daas dev" : "Run: bun install && daas dev");
|
|
3393
3419
|
}
|
|
3394
3420
|
});
|
|
3421
|
+
function getTemplateVersion() {
|
|
3422
|
+
try {
|
|
3423
|
+
const req = createRequire(import.meta.url);
|
|
3424
|
+
const pkg = req("@chrisluyi/template/package.json");
|
|
3425
|
+
return pkg.version ?? "1.0.0";
|
|
3426
|
+
} catch {
|
|
3427
|
+
return "1.0.0";
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3395
3430
|
function getPackageName(cwd) {
|
|
3396
3431
|
const pkgPath = resolve6(cwd, "package.json");
|
|
3397
3432
|
if (!existsSync6(pkgPath))
|
|
@@ -3404,6 +3439,45 @@ function getPackageName(cwd) {
|
|
|
3404
3439
|
}
|
|
3405
3440
|
}
|
|
3406
3441
|
|
|
3442
|
+
// src/commands/test.ts
|
|
3443
|
+
import { createVitestConfig } from "@chrisluyi/rsbuild-config/vitest";
|
|
3444
|
+
import { startVitest } from "vitest/node";
|
|
3445
|
+
var testCommand = defineCommand({
|
|
3446
|
+
meta: { name: "test", description: "Run MFE tests" },
|
|
3447
|
+
args: {
|
|
3448
|
+
json: {
|
|
3449
|
+
type: "boolean",
|
|
3450
|
+
default: false,
|
|
3451
|
+
description: "Machine-readable JSON output"
|
|
3452
|
+
}
|
|
3453
|
+
},
|
|
3454
|
+
async run({ args }) {
|
|
3455
|
+
const json = args.json;
|
|
3456
|
+
try {
|
|
3457
|
+
const manifest = readManifest();
|
|
3458
|
+
const daasConfig = readDaasConfig();
|
|
3459
|
+
const config = createVitestConfig(manifest, {
|
|
3460
|
+
coverage: daasConfig.coverage,
|
|
3461
|
+
setupFiles: daasConfig.setupFiles
|
|
3462
|
+
});
|
|
3463
|
+
const vitest = await startVitest("test", [], config);
|
|
3464
|
+
const failed = vitest?.state.getFiles().some((f4) => f4.result?.state === "fail") ?? false;
|
|
3465
|
+
if (json) {
|
|
3466
|
+
if (failed)
|
|
3467
|
+
writeJsonError("test", EXIT_CODES.GENERAL_ERROR, "Tests failed", "Check test output above");
|
|
3468
|
+
writeJsonSuccess("test", { appName: manifest.name, passed: !failed });
|
|
3469
|
+
}
|
|
3470
|
+
if (failed)
|
|
3471
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
3472
|
+
} catch (e3) {
|
|
3473
|
+
if (json)
|
|
3474
|
+
writeJsonError("test", EXIT_CODES.GENERAL_ERROR, e3.message, "Check test configuration");
|
|
3475
|
+
consola.fatal(e3);
|
|
3476
|
+
process.exit(EXIT_CODES.GENERAL_ERROR);
|
|
3477
|
+
}
|
|
3478
|
+
}
|
|
3479
|
+
});
|
|
3480
|
+
|
|
3407
3481
|
// src/index.ts
|
|
3408
3482
|
var main = defineCommand({
|
|
3409
3483
|
meta: {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chrisluyi/daas-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"daas": "./dist/index.js"
|
|
@@ -31,6 +31,11 @@
|
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"typescript": "^5.5.0"
|
|
33
33
|
},
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/Chris-LuYi/daas-cli",
|
|
37
|
+
"directory": "packages/cli"
|
|
38
|
+
},
|
|
34
39
|
"publishConfig": {
|
|
35
40
|
"access": "public"
|
|
36
41
|
}
|
package/dist/daas-bin
DELETED
|
Binary file
|