nxds-cli 0.6.0 → 0.6.1

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.
Files changed (2) hide show
  1. package/dist/index.js +91 -37
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -4543,7 +4543,7 @@ async function fetchRelease(registry, version) {
4543
4543
  if (isNewerSchema(value)) {
4544
4544
  const release = version === "latest" ? "The latest nxds release" : `nxds ${version}`;
4545
4545
  throw new CliError(
4546
- `${release} needs a newer nxds-cli than ${"0.6.0"}. Run \`${CLI_COMMAND}\` to get the newest one.`
4546
+ `${release} needs a newer nxds-cli than ${"0.6.1"}. Run \`${CLI_COMMAND}\` to get the newest one.`
4547
4547
  );
4548
4548
  }
4549
4549
  const invalid2 = (problems) => new CliError(
@@ -6310,6 +6310,12 @@ function readPaths(file) {
6310
6310
  function stalePaths(existing, exported) {
6311
6311
  return existing.filter((file) => file.startsWith("project/")).filter((file) => !isPageGenerated(file.slice("project/".length))).filter((file) => !exported.has(file)).sort();
6312
6312
  }
6313
+ var EXPORT_NAMES = /* @__PURE__ */ new Set(["project", "files.json", "removed.json"]);
6314
+ var isRootName = (name) => name !== "" && name !== "." && name !== ".." && path10.basename(name) === name && !EXPORT_NAMES.has(name);
6315
+ var sha256 = (bytes) => createHash("sha256").update(bytes).digest("hex");
6316
+ var isEntryList = (value) => Array.isArray(value) && value.every(
6317
+ (entry) => typeof entry?.path === "string" && typeof entry.sha256 === "string"
6318
+ );
6313
6319
  function readManifest(root) {
6314
6320
  const file = path10.join(root, "files.json");
6315
6321
  if (!existsSync9(file)) {
@@ -6318,58 +6324,98 @@ function readManifest(root) {
6318
6324
  );
6319
6325
  }
6320
6326
  const value = readJson(file);
6321
- if (!Array.isArray(value) || !value.every(
6322
- (entry) => typeof entry?.path === "string" && typeof entry.sha256 === "string"
6323
- )) {
6327
+ if (!isEntryList(value?.project) || !isEntryList(value.root)) {
6324
6328
  throw new CliError(
6325
- `${file} must be a JSON array of { path, sha256 } entries.`
6329
+ `${file} must hold project and root, each a JSON array of { path, sha256 } entries.`
6326
6330
  );
6327
6331
  }
6328
- return value;
6332
+ return { project: value.project, root: value.root };
6329
6333
  }
6330
- function readProject2(root) {
6331
- const projectDir = path10.join(root, "project");
6334
+ function readEntries(dir, entries, prefix) {
6332
6335
  const files = /* @__PURE__ */ new Map();
6333
- for (const entry of readManifest(root)) {
6334
- const file = path10.join(projectDir, entry.path);
6335
- const relative = path10.relative(projectDir, file);
6336
- if (relative.split(path10.sep)[0] === ".." || path10.isAbsolute(relative)) {
6337
- throw new CliError(`files.json lists ${entry.path}, outside project/.`);
6338
- }
6336
+ for (const entry of entries) {
6337
+ const file = path10.join(dir, entry.path);
6339
6338
  if (!existsSync9(file) || !lstatSync(file).isFile()) {
6340
6339
  throw new CliError(
6341
- `project/${entry.path} is missing from the release, or isn't a regular file.`
6340
+ `${prefix}${entry.path} is missing from the release, or isn't a regular file.`
6342
6341
  );
6343
6342
  }
6344
6343
  const bytes = readFileSync5(file);
6345
- if (createHash("sha256").update(bytes).digest("hex") !== entry.sha256) {
6344
+ if (sha256(bytes) !== entry.sha256) {
6346
6345
  throw new CliError(
6347
- `project/${entry.path} doesn't match the release's files.json, so nothing was written.`
6346
+ `${prefix}${entry.path} doesn't match the release's files.json, so nothing was written.`
6348
6347
  );
6349
6348
  }
6350
6349
  files.set(entry.path, bytes);
6351
6350
  }
6352
6351
  return files;
6353
6352
  }
6354
- var ROOT_FILES = ["coverage.md", "SETUP.md"];
6355
- function readRootFiles(root) {
6356
- const files = /* @__PURE__ */ new Map();
6357
- for (const name of ROOT_FILES) {
6358
- const file = path10.join(root, name);
6359
- if (!existsSync9(file)) continue;
6360
- if (!lstatSync(file).isFile()) {
6361
- throw new CliError(`The release's ${name} isn't a regular file.`);
6353
+ function readRelease(root) {
6354
+ const manifest = readManifest(root);
6355
+ const projectDir = path10.join(root, "project");
6356
+ for (const { path: file } of manifest.project) {
6357
+ const relative = path10.relative(projectDir, path10.join(projectDir, file));
6358
+ if (relative.split(path10.sep)[0] === ".." || path10.isAbsolute(relative)) {
6359
+ throw new CliError(`files.json lists ${file}, outside project/.`);
6362
6360
  }
6363
- files.set(name, readFileSync5(file));
6364
6361
  }
6365
- return files;
6362
+ for (const { path: file } of manifest.root) {
6363
+ if (!isRootName(file)) {
6364
+ throw new CliError(
6365
+ `files.json lists ${file || "an empty path"} as a root file. A root file is one name beside project/, other than project, files.json and removed.json.`
6366
+ );
6367
+ }
6368
+ }
6369
+ if (!manifest.root.some((entry) => entry.path === "SETUP.md")) {
6370
+ throw new CliError(
6371
+ "The release's files.json lists no SETUP.md, so there's no guide to follow."
6372
+ );
6373
+ }
6374
+ return {
6375
+ files: readEntries(projectDir, manifest.project, "project/"),
6376
+ rootFiles: readEntries(root, manifest.root, "")
6377
+ };
6366
6378
  }
6367
- function writeRootFiles(out, files) {
6368
- for (const name of ROOT_FILES) {
6369
- const bytes = files.get(name);
6370
- if (bytes) writeFileSync3(path10.join(out, name), bytes);
6371
- else rmSync(path10.join(out, name), { force: true });
6379
+ function droppedRootFiles(out, rootFiles) {
6380
+ const file = path10.join(out, "files.json");
6381
+ if (!existsSync9(file)) return [];
6382
+ const value = readJson(file);
6383
+ if (!isEntryList(value?.root)) {
6384
+ throw new UsageError(
6385
+ `${file} must hold root, a JSON array of { path, sha256 } entries. Delete it, then run the command again.`
6386
+ );
6387
+ }
6388
+ return value.root.filter(
6389
+ (entry) => isRootName(entry.path) && !rootFiles.has(entry.path)
6390
+ );
6391
+ }
6392
+ function removeDroppedRootFiles(out, dropped) {
6393
+ const edited = [];
6394
+ for (const entry of dropped) {
6395
+ const file = path10.join(out, entry.path);
6396
+ if (!existsSync9(file)) continue;
6397
+ const unchanged = lstatSync(file).isFile() && sha256(readFileSync5(file)) === entry.sha256;
6398
+ if (unchanged) rmSync(file);
6399
+ else edited.push(entry.path);
6372
6400
  }
6401
+ return edited;
6402
+ }
6403
+ function writeRootFiles(out, rootFiles) {
6404
+ for (const [name, bytes] of rootFiles) {
6405
+ writeFileSync3(path10.join(out, name), bytes);
6406
+ }
6407
+ }
6408
+ var entriesOf = (files) => [...files].map(([file, bytes]) => ({ path: file, sha256: sha256(bytes) }));
6409
+ function writeManifest(out, files, rootFiles) {
6410
+ const manifest = {
6411
+ project: entriesOf(files),
6412
+ root: entriesOf(rootFiles)
6413
+ };
6414
+ writeFileSync3(
6415
+ path10.join(out, "files.json"),
6416
+ `${JSON.stringify(manifest, null, 2)}
6417
+ `
6418
+ );
6373
6419
  }
6374
6420
  function mergeIndex(files, currentFile) {
6375
6421
  const exported = files.get("design-system.json");
@@ -6446,15 +6492,17 @@ async function exportClaudeDesign(cwd, options) {
6446
6492
  options.release ?? "latest"
6447
6493
  );
6448
6494
  try {
6449
- const files = readProject2(pkg.root);
6450
- const rootFiles = readRootFiles(pkg.root);
6495
+ const { files, rootFiles } = readRelease(pkg.root);
6451
6496
  if (options.index) mergeIndex(files, path10.resolve(cwd, options.index));
6452
6497
  const exported = new Set(
6453
6498
  [...files.keys()].map((file) => `project/${file}`)
6454
6499
  );
6455
6500
  const removed = options.existing ? stalePaths(readPaths(path10.resolve(cwd, options.existing)), exported) : [];
6501
+ const dropped = droppedRootFiles(out, rootFiles);
6456
6502
  writeProject(out, files);
6503
+ const kept = removeDroppedRootFiles(out, dropped);
6457
6504
  writeRootFiles(out, rootFiles);
6505
+ writeManifest(out, files, rootFiles);
6458
6506
  const removedFile = path10.join(out, "removed.json");
6459
6507
  if (options.existing) {
6460
6508
  writeFileSync3(removedFile, `${JSON.stringify(removed, null, 2)}
@@ -6471,22 +6519,28 @@ async function exportClaudeDesign(cwd, options) {
6471
6519
  `The props the canvas can't set are in ${path10.join(relative, "coverage.md")}.`
6472
6520
  );
6473
6521
  }
6522
+ for (const name of kept) {
6523
+ lines2.push(
6524
+ `Kept ${path10.join(relative, name)}: this release doesn't ship it, and you edited it.`
6525
+ );
6526
+ }
6474
6527
  if (removed.length > 0) {
6475
6528
  lines2.push(
6476
6529
  `Remove the ${removed.length} files the system has and this release doesn't: they're listed in ${path10.join(relative, "removed.json")}.`
6477
6530
  );
6478
6531
  }
6479
6532
  lines2.push(
6480
- rootFiles.has("SETUP.md") ? `Read ${path10.join(relative, "SETUP.md")} and follow it. It publishes the system, installs it on a canvas and checks it.` : `Publish ${relative} as a Design System artifact in Claude, with ${relative} as the root.`
6533
+ `Read ${path10.join(relative, "SETUP.md")} and follow it. It publishes the system, installs it on a canvas and checks it.`
6481
6534
  );
6482
6535
  return {
6483
- ok: true,
6536
+ ok: kept.length === 0,
6484
6537
  lines: lines2,
6485
6538
  data: {
6486
6539
  version: pkg.version,
6487
6540
  out,
6488
6541
  files: files.size,
6489
6542
  removed,
6543
+ kept: kept.map((name) => path10.join(out, name)),
6490
6544
  root: [...rootFiles.keys()].map((name) => path10.join(out, name))
6491
6545
  }
6492
6546
  };
@@ -6922,7 +6976,7 @@ function program(done, write) {
6922
6976
  // Errors are printed once, by `main`, as text or JSON.
6923
6977
  outputError: () => {
6924
6978
  }
6925
- }).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.6.0", "-v, --version", "print the version").helpOption("-h, --help", "show help").helpCommand("help [command]", "show help for a command").option("--json", "print machine-readable JSON").option("--cwd <path>", "run in another folder").addOption(
6979
+ }).exitOverride().name(CLI_COMMAND).description("Add nxds to your app.").version("0.6.1", "-v, --version", "print the version").helpOption("-h, --help", "show help").helpCommand("help [command]", "show help for a command").option("--json", "print machine-readable JSON").option("--cwd <path>", "run in another folder").addOption(
6926
6980
  new Option(
6927
6981
  "--registry <url|path>",
6928
6982
  "where to get nxds releases (default: https://nxds.dev/r)"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nxds-cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.1",
4
4
  "type": "module",
5
5
  "description": "Install nxds components, blocks and setup into your app.",
6
6
  "keywords": [
@@ -45,9 +45,9 @@
45
45
  "@types/semver": "^7.8.0",
46
46
  "tsup": "^8.5.1",
47
47
  "typescript": "^5.9.3",
48
- "@nxds/claude-design": "0.13.0",
49
- "@nxds/core": "0.12.0",
50
- "@nxds/catalog": "0.0.1"
48
+ "@nxds/catalog": "0.0.1",
49
+ "@nxds/claude-design": "0.13.2",
50
+ "@nxds/core": "0.12.0"
51
51
  },
52
52
  "scripts": {
53
53
  "build": "tsup",