@lerret/cli 0.1.8 → 0.1.10
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 +2 -2
- package/dist-studio/.bundle-stamp +8 -8
- package/dist-studio/assets/{asset-runtime-DQ3i9Nr6.js → asset-runtime-B5cPbIor.js} +1 -1
- package/dist-studio/assets/{cli-project-source-C85eHs9O.js → cli-project-source-BmwR4FYM.js} +1 -1
- package/dist-studio/assets/{dev-harness-Dgv20hhb.js → dev-harness-C-jJxqqM.js} +1 -1
- package/dist-studio/assets/{hosted-project-source-75SbhgPU.js → hosted-project-source-DYHsf9ks.js} +1 -1
- package/dist-studio/assets/{index-DUcLZ6GX.js → index-CXzX4BtL.js} +2 -2
- package/dist-studio/assets/{open-folder-tPC7IUFL.js → open-folder-BBui4dbb.js} +1 -1
- package/dist-studio/assets/{project-studio-Dvn5mggr.js → project-studio-C2LvtlHD.js} +2 -2
- package/dist-studio/index.html +2 -2
- package/package.json +1 -1
- package/src/dev.js +14 -14
- package/src/export.js +70 -36
- package/src/fs/node-backend.js +3 -3
- package/src/lerret.js +7 -7
- package/src/vite-plugin-lerret-project.js +6 -6
package/src/export.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
//
|
|
1
|
+
// `@lerret/cli export` — headless capture of a project's artboards to image files
|
|
2
2
|
// (FR37, FR38).
|
|
3
3
|
//
|
|
4
4
|
// Renders every artboard in scope through the EXACT same `captureArtboard`
|
|
5
|
-
// path the studio uses, so a
|
|
5
|
+
// path the studio uses, so a `@lerret/cli export` run produces a
|
|
6
6
|
// pixel-faithful match to what the same project produces from a click in the
|
|
7
7
|
// in-studio export buttons. The mechanism is:
|
|
8
8
|
//
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
// backend), then call `collectArtboards(model, scope)` to
|
|
16
16
|
// pick which artboards to capture.
|
|
17
17
|
// 3. Boot a Vite dev server programmatically against the studio source plus
|
|
18
|
-
// the same `vite-plugin-lerret-project`
|
|
18
|
+
// the same `vite-plugin-lerret-project` `@lerret/cli dev` uses — exactly the
|
|
19
19
|
// runtime that serves the studio so the project is mounted there.
|
|
20
20
|
// 4. Launch a headless Chromium through Playwright. Prefer the system
|
|
21
21
|
// `chrome`/`msedge` channel so `npx`-style invocations stay light; fall
|
|
@@ -91,7 +91,7 @@ import { lerretProjectPlugin } from './vite-plugin-lerret-project.js';
|
|
|
91
91
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
|
-
* The argv shape `parseArgs` produces for
|
|
94
|
+
* The argv shape `parseArgs` produces for `@lerret/cli export`.
|
|
95
95
|
*
|
|
96
96
|
* @typedef {object} ExportFlags
|
|
97
97
|
* @property {string | undefined} pathArg
|
|
@@ -188,15 +188,15 @@ export const ARTBOARD_SELECTORS = {
|
|
|
188
188
|
// ─────────────────────────────────────────────────────────────────────────────
|
|
189
189
|
|
|
190
190
|
/**
|
|
191
|
-
* Print
|
|
191
|
+
* Print `@lerret/cli export`'s usage banner.
|
|
192
192
|
*
|
|
193
193
|
* @returns {void}
|
|
194
194
|
*/
|
|
195
195
|
function printUsage() {
|
|
196
196
|
const lines = [
|
|
197
|
-
'lerret export — render a project (or page/group) headlessly to image files.',
|
|
197
|
+
'@lerret/cli export — render a project (or page/group) headlessly to image files.',
|
|
198
198
|
'',
|
|
199
|
-
'Usage: lerret export [path] [options]',
|
|
199
|
+
'Usage: @lerret/cli export [path] [options]',
|
|
200
200
|
'',
|
|
201
201
|
'Arguments:',
|
|
202
202
|
' path Project root, or a page/group folder inside `.lerret/`.',
|
|
@@ -219,7 +219,7 @@ function printUsage() {
|
|
|
219
219
|
}
|
|
220
220
|
|
|
221
221
|
/**
|
|
222
|
-
* Parse
|
|
222
|
+
* Parse `@lerret/cli export`'s argv. A separate function so tests can verify flag
|
|
223
223
|
* handling without booting Vite or Playwright.
|
|
224
224
|
*
|
|
225
225
|
* @param {string[]} argv Argv slice after the `export` subcommand.
|
|
@@ -401,7 +401,7 @@ export async function resolveScope({ pathArg, cwd, fs = createNodeBackend() }) {
|
|
|
401
401
|
|
|
402
402
|
// Canonicalize both ends so the path-arg comparisons below work even when
|
|
403
403
|
// the user supplied a symlinked path (the classic macOS `/tmp` →
|
|
404
|
-
// `/private/tmp` gotcha that
|
|
404
|
+
// `/private/tmp` gotcha that `@lerret/cli dev` also has to handle).
|
|
405
405
|
const projectRoot = toLerretPath(realpathOrSelf(projectResolution.projectRoot));
|
|
406
406
|
const lerretDir = toLerretPath(realpathOrSelf(projectResolution.lerretDir));
|
|
407
407
|
|
|
@@ -663,8 +663,15 @@ export function buildBaseFilename(artboard, extension) {
|
|
|
663
663
|
/**
|
|
664
664
|
* Compute the on-disk output path for one artboard.
|
|
665
665
|
*
|
|
666
|
-
* Structured (default): `<outDir>/<
|
|
667
|
-
*
|
|
666
|
+
* Structured (default): `<outDir>/<page>[/<group>[/…]]/<filename>` per the PRD —
|
|
667
|
+
* the page name (derived from `artboard.pagePath`) is always present, so that
|
|
668
|
+
* a project with `landing/heroes/Card1.jsx` and `social/Banner.jsx` writes to
|
|
669
|
+
* `out/landing/heroes/Card1.png` and `out/social/Banner.png` (and assets named
|
|
670
|
+
* the same in different pages cannot collide).
|
|
671
|
+
*
|
|
672
|
+
* Flat: `<outDir>/[<segments-joined-by---if-collision>]<filename>` — flat mode
|
|
673
|
+
* never used the page prefix; we leave it as-is so existing `--flat` users see
|
|
674
|
+
* no path change.
|
|
668
675
|
*
|
|
669
676
|
* For flat layout, collision disambiguation needs to know whether OTHER items
|
|
670
677
|
* in the same run would produce the same base filename. The caller supplies
|
|
@@ -676,7 +683,14 @@ export function buildBaseFilename(artboard, extension) {
|
|
|
676
683
|
* Output root, absolute and using forward slashes.
|
|
677
684
|
* @param {object} args.artboard
|
|
678
685
|
* @param {string[]} args.artboard.locationSegments
|
|
679
|
-
*
|
|
686
|
+
* Group chain — `[]` for an asset directly in a page. The page level is
|
|
687
|
+
* derived separately from `artboard.pagePath`, not carried here (the studio's
|
|
688
|
+
* ZIP exporter shares this field and intentionally omits the page prefix —
|
|
689
|
+
* see packages/studio/src/export/zip.js).
|
|
690
|
+
* @param {string} [args.artboard.pagePath]
|
|
691
|
+
* Full LerretPath of the containing page. The basename becomes the top-level
|
|
692
|
+
* folder in structured mode. When absent (older callers / hand-crafted
|
|
693
|
+
* artboards in tests), the page level is omitted gracefully.
|
|
680
694
|
* @param {string} args.filename
|
|
681
695
|
* The base filename, already extension-suffixed.
|
|
682
696
|
* @param {boolean} args.flat
|
|
@@ -699,14 +713,34 @@ export function buildOutputPath({ outDir, artboard, filename, flat, nameCount =
|
|
|
699
713
|
return joinForward(outDir, filename);
|
|
700
714
|
}
|
|
701
715
|
|
|
702
|
-
|
|
716
|
+
const pageName = pageNameFromPagePath(artboard.pagePath);
|
|
717
|
+
const structuredSegs = pageName ? [pageName, ...segments] : segments;
|
|
718
|
+
|
|
719
|
+
if (structuredSegs.length === 0) {
|
|
703
720
|
return joinForward(outDir, filename);
|
|
704
721
|
}
|
|
705
722
|
|
|
706
|
-
const safeSegs =
|
|
723
|
+
const safeSegs = structuredSegs.map(safeName);
|
|
707
724
|
return joinForward(outDir, ...safeSegs, filename);
|
|
708
725
|
}
|
|
709
726
|
|
|
727
|
+
/**
|
|
728
|
+
* Extract the page-folder name from an Artboard's `pagePath`. The path is a
|
|
729
|
+
* forward-slash LerretPath like `/proj/.lerret/landing`; the basename is the
|
|
730
|
+
* page-folder name (`landing`). Returns `null` when the input is missing or
|
|
731
|
+
* unusable so callers can fall back gracefully.
|
|
732
|
+
*
|
|
733
|
+
* @param {unknown} pagePath
|
|
734
|
+
* @returns {string | null}
|
|
735
|
+
*/
|
|
736
|
+
function pageNameFromPagePath(pagePath) {
|
|
737
|
+
if (typeof pagePath !== 'string' || pagePath.length === 0) return null;
|
|
738
|
+
const trimmed = pagePath.replace(/\/+$/, '');
|
|
739
|
+
const lastSlash = trimmed.lastIndexOf('/');
|
|
740
|
+
const name = lastSlash === -1 ? trimmed : trimmed.slice(lastSlash + 1);
|
|
741
|
+
return name.length > 0 ? name : null;
|
|
742
|
+
}
|
|
743
|
+
|
|
710
744
|
/**
|
|
711
745
|
* Join path segments using forward slashes, regardless of platform. The CLI
|
|
712
746
|
* normalizes every path to the contract's forward-slash form at its boundary
|
|
@@ -814,7 +848,7 @@ function readAssetVariants(asset) {
|
|
|
814
848
|
* 1. Try `playwright-core`'s `chromium.launch({ channel: 'chrome' })`. If
|
|
815
849
|
* the user has Google Chrome / Chromium / Edge installed in a standard
|
|
816
850
|
* location, this succeeds without downloading anything — keeping `npx
|
|
817
|
-
* lerret export` light, per the architecture decision.
|
|
851
|
+
* @lerret/cli export` light, per the architecture decision.
|
|
818
852
|
* 2. If the channel launch fails, try `playwright` (the full package,
|
|
819
853
|
* which ships its bundled browser when installed). Only present when
|
|
820
854
|
* the user opts in by installing the full `playwright` package.
|
|
@@ -896,7 +930,7 @@ export async function launchHeadlessBrowser() {
|
|
|
896
930
|
|
|
897
931
|
/**
|
|
898
932
|
* Boot a Vite dev server programmatically — same plugin / fs.allow shape as
|
|
899
|
-
*
|
|
933
|
+
* `@lerret/cli dev`, but with `server.open = false` and an undefined port (Vite
|
|
900
934
|
* picks a free one). The returned `address` is the URL to navigate to.
|
|
901
935
|
*
|
|
902
936
|
* @param {object} opts
|
|
@@ -940,7 +974,7 @@ export async function bootViteServer({ projectRoot, lerretDir, dataOverride, con
|
|
|
940
974
|
// imports of `react/jsx-dev-runtime`. The user's project has no
|
|
941
975
|
// `node_modules`, so those imports must resolve against the CLI's own
|
|
942
976
|
// React. Without these aliases the user's assets fail to load in
|
|
943
|
-
// `dist-studio/` mode and the studio renders empty slots —
|
|
977
|
+
// `dist-studio/` mode and the studio renders empty slots — `@lerret/cli dev`
|
|
944
978
|
// has the same shape; we keep them in lock-step.
|
|
945
979
|
const cliRequire = createRequire(import.meta.url);
|
|
946
980
|
const reactAliases = [
|
|
@@ -1092,7 +1126,7 @@ function formatLocation(segments) {
|
|
|
1092
1126
|
}
|
|
1093
1127
|
|
|
1094
1128
|
/**
|
|
1095
|
-
* Run
|
|
1129
|
+
* Run `@lerret/cli export`. Resolves the scope, boots Vite + Chromium, captures
|
|
1096
1130
|
* each artboard, writes the result to disk, and returns an exit code.
|
|
1097
1131
|
*
|
|
1098
1132
|
* @param {string[]} argv Argv slice after the `export` subcommand.
|
|
@@ -1110,7 +1144,7 @@ function formatLocation(segments) {
|
|
|
1110
1144
|
export async function runExport(argv, deps = {}) {
|
|
1111
1145
|
const { flags, error } = parseExportArgs(argv);
|
|
1112
1146
|
if (error) {
|
|
1113
|
-
process.stderr.write(
|
|
1147
|
+
process.stderr.write(`@lerret/cli export: ${error}\n\n`);
|
|
1114
1148
|
printUsage();
|
|
1115
1149
|
return 1;
|
|
1116
1150
|
}
|
|
@@ -1134,7 +1168,7 @@ export async function runExport(argv, deps = {}) {
|
|
|
1134
1168
|
cwd,
|
|
1135
1169
|
});
|
|
1136
1170
|
if (!overrideResult.ok) {
|
|
1137
|
-
process.stderr.write(
|
|
1171
|
+
process.stderr.write(`@lerret/cli export: ${overrideResult.error}\n`);
|
|
1138
1172
|
return 1;
|
|
1139
1173
|
}
|
|
1140
1174
|
const { dataOverride, configOverride } = overrideResult.overrides;
|
|
@@ -1142,7 +1176,7 @@ export async function runExport(argv, deps = {}) {
|
|
|
1142
1176
|
// 1. Resolve project + scope.
|
|
1143
1177
|
const scope = await resolveScope({ pathArg: flags.pathArg, cwd });
|
|
1144
1178
|
if (!scope.found) {
|
|
1145
|
-
process.stderr.write(
|
|
1179
|
+
process.stderr.write(`@lerret/cli export: ${scope.error}\n`);
|
|
1146
1180
|
return 1;
|
|
1147
1181
|
}
|
|
1148
1182
|
|
|
@@ -1151,14 +1185,14 @@ export async function runExport(argv, deps = {}) {
|
|
|
1151
1185
|
try {
|
|
1152
1186
|
baseArtboards = collectArtboards(scope.model, scope.scopePath);
|
|
1153
1187
|
} catch (err) {
|
|
1154
|
-
process.stderr.write(
|
|
1188
|
+
process.stderr.write(`@lerret/cli export: ${err && err.message ? err.message : String(err)}\n`);
|
|
1155
1189
|
return 1;
|
|
1156
1190
|
}
|
|
1157
1191
|
|
|
1158
1192
|
const expanded = expandArtboardVariants(baseArtboards);
|
|
1159
1193
|
if (expanded.length === 0) {
|
|
1160
1194
|
process.stderr.write(
|
|
1161
|
-
|
|
1195
|
+
`@lerret/cli export: no artboards found in scope (${scope.scopeKind}). Nothing to export.\n`,
|
|
1162
1196
|
);
|
|
1163
1197
|
return 1;
|
|
1164
1198
|
}
|
|
@@ -1178,7 +1212,7 @@ export async function runExport(argv, deps = {}) {
|
|
|
1178
1212
|
outDirAbs.startsWith(scope.lerretDir + '/')
|
|
1179
1213
|
) {
|
|
1180
1214
|
process.stderr.write(
|
|
1181
|
-
|
|
1215
|
+
`@lerret/cli export: refusing to write into the project's \`.lerret/\` directory ` +
|
|
1182
1216
|
`(${scope.lerretDir}). Pick an --out directory outside the project's .lerret/ tree.\n`,
|
|
1183
1217
|
);
|
|
1184
1218
|
return 1;
|
|
@@ -1189,7 +1223,7 @@ export async function runExport(argv, deps = {}) {
|
|
|
1189
1223
|
await ensureDirFn(outDirAbs);
|
|
1190
1224
|
} catch (err) {
|
|
1191
1225
|
process.stderr.write(
|
|
1192
|
-
|
|
1226
|
+
`@lerret/cli export: could not create output directory ${outDirAbs}: ` +
|
|
1193
1227
|
`${err && err.message ? err.message : String(err)}\n`,
|
|
1194
1228
|
);
|
|
1195
1229
|
return 1;
|
|
@@ -1206,10 +1240,10 @@ export async function runExport(argv, deps = {}) {
|
|
|
1206
1240
|
? ' [--config override active]'
|
|
1207
1241
|
: '';
|
|
1208
1242
|
process.stdout.write(
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1243
|
+
`@lerret/cli export: project ${scope.projectRoot}\n` +
|
|
1244
|
+
`@lerret/cli export: scope ${scope.scopeKind}${scope.scopePath ? ` (${scope.scopePath})` : ''}\n` +
|
|
1245
|
+
`@lerret/cli export: ${expanded.length} artboard${expanded.length === 1 ? '' : 's'} to capture (${flags.format})${overrideNote}\n` +
|
|
1246
|
+
`@lerret/cli export: writing to ${outDirAbs}${flags.flat ? ' (flat layout)' : ''}\n`,
|
|
1213
1247
|
);
|
|
1214
1248
|
|
|
1215
1249
|
const bootServer = deps.bootServer || bootViteServer;
|
|
@@ -1235,7 +1269,7 @@ export async function runExport(argv, deps = {}) {
|
|
|
1235
1269
|
url = booted.url;
|
|
1236
1270
|
} catch (err) {
|
|
1237
1271
|
process.stderr.write(
|
|
1238
|
-
|
|
1272
|
+
`@lerret/cli export: Vite dev server failed to start: ` +
|
|
1239
1273
|
`${err && err.message ? err.message : String(err)}\n`,
|
|
1240
1274
|
);
|
|
1241
1275
|
return 1;
|
|
@@ -1244,10 +1278,10 @@ export async function runExport(argv, deps = {}) {
|
|
|
1244
1278
|
try {
|
|
1245
1279
|
const launched = await launchBrowser();
|
|
1246
1280
|
browser = launched.browser;
|
|
1247
|
-
process.stdout.write(
|
|
1281
|
+
process.stdout.write(`@lerret/cli export: ${launched.launchedVia}\n`);
|
|
1248
1282
|
} catch (err) {
|
|
1249
1283
|
process.stderr.write(
|
|
1250
|
-
|
|
1284
|
+
`@lerret/cli export: ${err && err.message ? err.message : String(err)}\n`,
|
|
1251
1285
|
);
|
|
1252
1286
|
return 1;
|
|
1253
1287
|
}
|
|
@@ -1270,7 +1304,7 @@ export async function runExport(argv, deps = {}) {
|
|
|
1270
1304
|
await page.waitForSelector(firstSelector, { state: 'attached', timeout: 30000 });
|
|
1271
1305
|
} catch (err) {
|
|
1272
1306
|
process.stderr.write(
|
|
1273
|
-
|
|
1307
|
+
`@lerret/cli export: studio did not render any artboards within 30s ` +
|
|
1274
1308
|
`(${err && err.message ? err.message : String(err)}). The project may be empty or failed to load.\n`,
|
|
1275
1309
|
);
|
|
1276
1310
|
return 1;
|
|
@@ -1359,16 +1393,16 @@ export async function runExport(argv, deps = {}) {
|
|
|
1359
1393
|
// 7. Summary.
|
|
1360
1394
|
const summaryLines = [
|
|
1361
1395
|
'',
|
|
1362
|
-
|
|
1396
|
+
`@lerret/cli export: wrote ${writtenCount} of ${expanded.length} image${expanded.length === 1 ? '' : 's'} to ${outDirAbs}`,
|
|
1363
1397
|
];
|
|
1364
1398
|
if (failures.length > 0) {
|
|
1365
1399
|
summaryLines.push(
|
|
1366
|
-
|
|
1400
|
+
`@lerret/cli export: ${failures.length} artboard${failures.length === 1 ? '' : 's'} failed (see messages above)`,
|
|
1367
1401
|
);
|
|
1368
1402
|
}
|
|
1369
1403
|
if (allUnembeddedFonts.size > 0) {
|
|
1370
1404
|
summaryLines.push(
|
|
1371
|
-
|
|
1405
|
+
`@lerret/cli export: fonts not embedded: ${[...allUnembeddedFonts].sort().join(', ')}`,
|
|
1372
1406
|
);
|
|
1373
1407
|
}
|
|
1374
1408
|
process.stdout.write(summaryLines.join('\n') + '\n');
|
package/src/fs/node-backend.js
CHANGED
|
@@ -325,7 +325,7 @@ export { NODE_CAPABILITIES };
|
|
|
325
325
|
// realpath helper — CLI-internal, NOT part of the FilesystemAccess contract
|
|
326
326
|
// ---------------------------------------------------------------------------
|
|
327
327
|
//
|
|
328
|
-
//
|
|
328
|
+
// `@lerret/cli dev` configures Vite's `server.fs.allow`, which Vite enforces by
|
|
329
329
|
// comparing against the *real* (symlink-resolved) path of each request. On
|
|
330
330
|
// macOS `/tmp` is a symlink to `/private/tmp`, so an `--folder /tmp/foo`
|
|
331
331
|
// argument must be resolved to `/private/tmp/foo` before being added to
|
|
@@ -378,7 +378,7 @@ export function pathExists(path) {
|
|
|
378
378
|
/**
|
|
379
379
|
* Recursively create a directory (no-op if it already exists). Used by
|
|
380
380
|
* subsystems that need to materialize an output tree on disk — the bulk
|
|
381
|
-
*
|
|
381
|
+
* `@lerret/cli export` writer lands captured images under a user-
|
|
382
382
|
* specified `--out` directory and needs to mkdir intermediate folders for the
|
|
383
383
|
* structured layout. Kept in this file so the `fs` ban for the rest of the
|
|
384
384
|
* codebase is preserved (this is the sanctioned escape).
|
|
@@ -393,7 +393,7 @@ export async function ensureDir(lerretPath) {
|
|
|
393
393
|
|
|
394
394
|
/**
|
|
395
395
|
* Canonicalize the deepest existing prefix of a path, then re-attach the
|
|
396
|
-
* still-virtual trailing components. Used by
|
|
396
|
+
* still-virtual trailing components. Used by `@lerret/cli export` to compare a
|
|
397
397
|
* user-supplied `--out` directory against the project's `.lerret/` path even
|
|
398
398
|
* when `--out` does not yet exist on disk.
|
|
399
399
|
*
|
package/src/lerret.js
CHANGED
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
// node's built-in `util.parseArgs` — the architecture's explicit choice, no
|
|
6
6
|
// heavy CLI framework. Recognized subcommands:
|
|
7
7
|
//
|
|
8
|
-
// lerret dev [--port <n>] [--folder <path>] [--open | --no-open]
|
|
9
|
-
// lerret export [path] [--format png|jpg] [--out <dir>] [--flat]
|
|
8
|
+
// @lerret/cli dev [--port <n>] [--folder <path>] [--open | --no-open]
|
|
9
|
+
// @lerret/cli export [path] [--format png|jpg] [--out <dir>] [--flat]
|
|
10
10
|
//
|
|
11
11
|
// Adding a new subcommand is the act of importing one more module and adding
|
|
12
12
|
// an entry to the `SUBCOMMANDS` table below — the usage banner is derived
|
|
@@ -53,16 +53,16 @@ const SUBCOMMANDS = {
|
|
|
53
53
|
*/
|
|
54
54
|
function printUsage() {
|
|
55
55
|
const lines = [
|
|
56
|
-
'lerret — the design-canvas CLI',
|
|
56
|
+
'@lerret/cli — the design-canvas CLI',
|
|
57
57
|
'',
|
|
58
|
-
'Usage: lerret <command> [options]',
|
|
58
|
+
'Usage: @lerret/cli <command> [options]',
|
|
59
59
|
'',
|
|
60
60
|
'Commands:',
|
|
61
61
|
...Object.entries(SUBCOMMANDS).map(
|
|
62
62
|
([name, { describe }]) => ` ${name.padEnd(8)} ${describe}`,
|
|
63
63
|
),
|
|
64
64
|
'',
|
|
65
|
-
'Run
|
|
65
|
+
'Run `@lerret/cli <command> --help` for command-specific options.',
|
|
66
66
|
];
|
|
67
67
|
process.stdout.write(lines.join('\n') + '\n');
|
|
68
68
|
}
|
|
@@ -91,7 +91,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
91
91
|
if (!handler) {
|
|
92
92
|
// An unknown subcommand is a usage error — print the banner so the user
|
|
93
93
|
// can see what is valid, then exit non-zero.
|
|
94
|
-
process.stderr.write(
|
|
94
|
+
process.stderr.write(`@lerret/cli: unknown command "${command}"\n\n`);
|
|
95
95
|
printUsage();
|
|
96
96
|
return 1;
|
|
97
97
|
}
|
|
@@ -102,7 +102,7 @@ export async function main(argv = process.argv.slice(2)) {
|
|
|
102
102
|
} catch (err) {
|
|
103
103
|
// A genuine runtime failure inside a subcommand — surface a short error and
|
|
104
104
|
// exit non-zero. The subcommand owns its own error UX otherwise.
|
|
105
|
-
process.stderr.write(
|
|
105
|
+
process.stderr.write(`@lerret/cli ${command}: ${err && err.message ? err.message : String(err)}\n`);
|
|
106
106
|
return 1;
|
|
107
107
|
}
|
|
108
108
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// vite-plugin-lerret-project.js — the Vite plugin that exposes the user's
|
|
2
|
-
// `.lerret/` project to the studio in
|
|
2
|
+
// `.lerret/` project to the studio in `@lerret/cli dev` mode.
|
|
3
3
|
//
|
|
4
4
|
// ── Why a Vite plugin ──────────────────────────────────────────────────────
|
|
5
|
-
//
|
|
5
|
+
// `@lerret/cli dev` boots a Node-side Vite dev server pointed at the studio source
|
|
6
6
|
// (`packages/studio/`). The studio is a normal Vite-served SPA. To swap from
|
|
7
7
|
// the studio's standalone fixture project to a real user folder we need four
|
|
8
8
|
// things, and a Vite plugin owns all of them in one place:
|
|
@@ -71,7 +71,7 @@ import { startWatcher } from './watcher.js';
|
|
|
71
71
|
|
|
72
72
|
// ── Cascade-override helpers ─────────────────────────────────────────────────
|
|
73
73
|
//
|
|
74
|
-
// When `--config` is supplied to
|
|
74
|
+
// When `--config` is supplied to `@lerret/cli export`, its value is deep-merged
|
|
75
75
|
// into every entry of the cascade (the `cascadeEntries` the plugin exposes
|
|
76
76
|
// via the virtual module). We replicate the same deep-merge semantics that
|
|
77
77
|
// `computeCascadedConfig`'s internal `deepMerge` uses:
|
|
@@ -314,12 +314,12 @@ export function checkWritePath(requestPath, lerretDir) {
|
|
|
314
314
|
}
|
|
315
315
|
|
|
316
316
|
/**
|
|
317
|
-
* Create the
|
|
317
|
+
* Create the `@lerret/cli dev` / `@lerret/cli export` Vite plugin.
|
|
318
318
|
*
|
|
319
319
|
* @param {object} opts
|
|
320
320
|
* @param {string | null} opts.projectRoot
|
|
321
321
|
* The user's project root — the folder that directly contains `.lerret/`,
|
|
322
|
-
* or `null` if
|
|
322
|
+
* or `null` if `@lerret/cli dev` was invoked outside any project (no-folder
|
|
323
323
|
* fallback).
|
|
324
324
|
* @param {string | null} opts.lerretDir
|
|
325
325
|
* The user's `.lerret/` directory path, or `null` matching `projectRoot`.
|
|
@@ -433,7 +433,7 @@ export function lerretProjectPlugin({ projectRoot, lerretDir, dataOverride, conf
|
|
|
433
433
|
/**
|
|
434
434
|
* Inject a tiny inline script into the served `index.html` so the
|
|
435
435
|
* studio's `main.jsx` can synchronously detect that it is running
|
|
436
|
-
* under
|
|
436
|
+
* under `@lerret/cli dev`. Without this signal the studio would have to
|
|
437
437
|
* try a dynamic import of `virtual:lerret-project` — which the
|
|
438
438
|
* browser refuses with a CORS error (the bare specifier isn't a URL).
|
|
439
439
|
*
|