@tokiui/cli 0.2.1 → 0.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.
Files changed (2) hide show
  1. package/dist/index.js +99 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -266,11 +266,12 @@ function resolveRegistryRef() {
266
266
  }
267
267
  return envRef;
268
268
  }
269
- return `cli-v${"0.2.1"}`;
269
+ return `cli-v${"0.3.0"}`;
270
270
  }
271
271
  var REGISTRY_REF = resolveRegistryRef();
272
272
  var REGISTRY_BASE = `${ALLOWED_FETCH_ORIGIN}${REGISTRY_REF}/packages/registry`;
273
273
  var SOURCE_BASE = `${ALLOWED_FETCH_ORIGIN}${REGISTRY_REF}/packages/ui/src`;
274
+ var BLOCK_BASE = `${ALLOWED_FETCH_ORIGIN}${REGISTRY_REF}/apps/docs/src/registry/blocks`;
274
275
  async function safeFetch(url) {
275
276
  if (!url.startsWith(ALLOWED_FETCH_ORIGIN)) {
276
277
  throw new Error(
@@ -358,6 +359,31 @@ async function fetchComponentSource(name, file) {
358
359
  if (!res.ok) throw new Error(`Failed to fetch source for ${name}/${file}`);
359
360
  return res.text();
360
361
  }
362
+ function assertRegistryBlock(data) {
363
+ const obj = data;
364
+ const valid = typeof data === "object" && data !== null && typeof obj.name === "string" && Array.isArray(obj.files) && Array.isArray(obj.dependencies) && Array.isArray(obj.registryDependencies) && obj.files.every((f) => typeof f === "string") && obj.dependencies.every((d) => typeof d === "string") && obj.registryDependencies.every((d) => typeof d === "string");
365
+ if (!valid) {
366
+ throw new Error(
367
+ `Received an invalid block definition for "${String(obj.name ?? "unknown")}" from the registry.`
368
+ );
369
+ }
370
+ }
371
+ async function fetchBlock(name) {
372
+ assertSafeComponentName(name);
373
+ const res = await safeFetch(`${BLOCK_BASE}/${name}/block.json`);
374
+ if (res.status === 404) return null;
375
+ if (!res.ok) throw new Error(`Failed to fetch block "${name}": ${res.statusText}`);
376
+ const data = await res.json();
377
+ assertRegistryBlock(data);
378
+ return data;
379
+ }
380
+ async function fetchBlockSource(name, file) {
381
+ assertSafeComponentName(name);
382
+ assertSafeFilePath(file);
383
+ const res = await safeFetch(`${BLOCK_BASE}/${name}/${file}`);
384
+ if (!res.ok) throw new Error(`Failed to fetch source for block ${name}/${file}`);
385
+ return res.text();
386
+ }
361
387
 
362
388
  // src/utils/transforms.ts
363
389
  function transformImports(source, libDir) {
@@ -370,14 +396,14 @@ var addCommand = new import_commander2.Command("add").description("Add a compone
370
396
  const config = getConfig(cwd);
371
397
  if (!config) {
372
398
  console.log(
373
- import_kleur2.default.red("No tokiui.json found. Run `npx tokiui init` first.")
399
+ import_kleur2.default.red("No tokiui.json found. Run `npx @tokiui/cli init` first.")
374
400
  );
375
401
  process.exit(1);
376
402
  }
377
403
  const libAlias = config.libAlias ?? `@/${config.libDir}`;
378
404
  let componentName = componentArg;
379
405
  if (!componentName) {
380
- const spinner = (0, import_ora2.default)("Fetching component list...").start();
406
+ const spinner = (0, import_ora2.default)("Fetching registry...").start();
381
407
  const index = await fetchRegistryIndex().catch(() => {
382
408
  spinner.fail("Failed to fetch registry");
383
409
  process.exit(1);
@@ -386,8 +412,11 @@ var addCommand = new import_commander2.Command("add").description("Add a compone
386
412
  const answer = await (0, import_prompts2.default)({
387
413
  type: "multiselect",
388
414
  name: "components",
389
- message: "Which components would you like to add?",
390
- choices: index.components.map((c) => ({ title: c.label, value: c.name })),
415
+ message: "Which components or blocks would you like to add?",
416
+ choices: [
417
+ ...index.components.map((c) => ({ title: c.label, value: c.name })),
418
+ ...(index.blocks ?? []).map((b) => ({ title: `${b.label} \xB7 block`, value: b.name }))
419
+ ],
391
420
  min: 1
392
421
  });
393
422
  if (!answer.components?.length) {
@@ -396,12 +425,20 @@ var addCommand = new import_commander2.Command("add").description("Add a compone
396
425
  }
397
426
  const visited = /* @__PURE__ */ new Set();
398
427
  for (const name of answer.components) {
399
- await installComponent(name, cwd, config.componentsDir, libAlias, visited);
428
+ await install(name, cwd, config.componentsDir, libAlias, visited);
400
429
  }
401
430
  return;
402
431
  }
403
- await installComponent(componentName, cwd, config.componentsDir, libAlias, /* @__PURE__ */ new Set());
432
+ await install(componentName, cwd, config.componentsDir, libAlias, /* @__PURE__ */ new Set());
404
433
  });
434
+ async function install(name, cwd, componentsDir, libAlias, visited) {
435
+ const block = await fetchBlock(name).catch(() => null);
436
+ if (block) {
437
+ await installBlock(block, cwd, componentsDir, libAlias, visited);
438
+ return;
439
+ }
440
+ await installComponent(name, cwd, componentsDir, libAlias, visited);
441
+ }
405
442
  async function installComponent(name, cwd, componentsDir, libAlias, visited) {
406
443
  if (visited.has(name)) return;
407
444
  visited.add(name);
@@ -457,6 +494,61 @@ async function installComponent(name, cwd, componentsDir, libAlias, visited) {
457
494
  }
458
495
  spinner.succeed(`Added ${import_kleur2.default.bold(name)}`);
459
496
  }
497
+ async function installBlock(block, cwd, componentsDir, libAlias, visited) {
498
+ const spinner = (0, import_ora2.default)(`Adding block ${block.name}...`).start();
499
+ if (block.registryDependencies.length > 0) {
500
+ spinner.stop();
501
+ for (const dep of block.registryDependencies) {
502
+ await installComponent(dep, cwd, componentsDir, libAlias, visited);
503
+ }
504
+ spinner.start(`Adding block ${block.name}...`);
505
+ }
506
+ const blockDir = import_path3.default.join(import_path3.default.dirname(componentsDir), "blocks", block.name);
507
+ for (const file of block.files) {
508
+ try {
509
+ assertSafeFilePath(file);
510
+ } catch (err) {
511
+ spinner.fail(`Security: ${err instanceof Error ? err.message : String(err)}`);
512
+ process.exit(1);
513
+ }
514
+ const source = await fetchBlockSource(block.name, file);
515
+ const transformed = transformImports(source, libAlias);
516
+ const destPath = import_path3.default.join(cwd, blockDir, file);
517
+ if (import_fs_extra3.default.existsSync(destPath)) {
518
+ spinner.stop();
519
+ const { overwrite } = await (0, import_prompts2.default)({
520
+ type: "confirm",
521
+ name: "overwrite",
522
+ message: `${import_path3.default.join(blockDir, file)} already exists. Overwrite?`,
523
+ initial: false
524
+ });
525
+ if (!overwrite) {
526
+ console.log(import_kleur2.default.dim(`Skipped ${file}`));
527
+ spinner.start(`Adding block ${block.name}...`);
528
+ continue;
529
+ }
530
+ spinner.start(`Adding block ${block.name}...`);
531
+ }
532
+ await import_fs_extra3.default.ensureDir(import_path3.default.dirname(destPath));
533
+ await import_fs_extra3.default.writeFile(destPath, transformed);
534
+ }
535
+ if (block.dependencies.length > 0) {
536
+ for (const dep of block.dependencies) {
537
+ try {
538
+ assertSafeDependency(dep);
539
+ } catch (err) {
540
+ spinner.fail(`Security: ${err instanceof Error ? err.message : String(err)}`);
541
+ process.exit(1);
542
+ }
543
+ }
544
+ console.log(import_kleur2.default.dim(` Installing: ${block.dependencies.join(", ")}`));
545
+ const pm = detectPackageManager(cwd);
546
+ const installCmd = pm === "npm" ? "install" : "add";
547
+ await (0, import_execa2.execa)(pm, [installCmd, ...block.dependencies], { cwd });
548
+ }
549
+ spinner.succeed(`Added block ${import_kleur2.default.bold(block.name)} \u2192 ${blockDir}/`);
550
+ console.log(import_kleur2.default.dim(` Import ${import_path3.default.join(blockDir, "page.tsx")} into a route to use it.`));
551
+ }
460
552
 
461
553
  // src/commands/theme.ts
462
554
  var import_commander3 = require("commander");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tokiui/cli",
3
- "version": "0.2.1",
3
+ "version": "0.3.0",
4
4
  "description": "CLI for adding tokiui components to your project",
5
5
  "license": "MIT",
6
6
  "author": "Topher Gacad",