@tokiui/cli 0.2.0 → 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.
- package/dist/index.js +99 -7
- 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.
|
|
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
|
|
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:
|
|
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
|
|
428
|
+
await install(name, cwd, config.componentsDir, libAlias, visited);
|
|
400
429
|
}
|
|
401
430
|
return;
|
|
402
431
|
}
|
|
403
|
-
await
|
|
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");
|