@akii09/pdfx-cli 0.1.4 → 0.1.6

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 +688 -237
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -492,8 +492,8 @@ function getErrorMap() {
492
492
 
493
493
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
494
494
  var makeIssue = (params) => {
495
- const { data, path: path11, errorMaps, issueData } = params;
496
- const fullPath = [...path11, ...issueData.path || []];
495
+ const { data, path: path12, errorMaps, issueData } = params;
496
+ const fullPath = [...path12, ...issueData.path || []];
497
497
  const fullIssue = {
498
498
  ...issueData,
499
499
  path: fullPath
@@ -609,11 +609,11 @@ var errorUtil;
609
609
 
610
610
  // ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
611
611
  var ParseInputLazyPath = class {
612
- constructor(parent, value, path11, key) {
612
+ constructor(parent, value, path12, key) {
613
613
  this._cachedPath = [];
614
614
  this.parent = parent;
615
615
  this.data = value;
616
- this._path = path11;
616
+ this._path = path12;
617
617
  this._key = key;
618
618
  }
619
619
  get path() {
@@ -4148,13 +4148,16 @@ var configSchema = external_exports.object({
4148
4148
  registry: external_exports.string().url("registry must be a valid URL"),
4149
4149
  theme: external_exports.string().min(1).optional(),
4150
4150
  /** Directory where templates are installed. Defaults to ./src/templates/pdfx */
4151
- templateDir: external_exports.string().min(1).optional()
4151
+ templateDir: external_exports.string().min(1).optional(),
4152
+ /** Directory where blocks are installed. Defaults to ./src/blocks/pdfx */
4153
+ blockDir: external_exports.string().min(1).optional()
4152
4154
  });
4153
4155
  var registryFileTypes = [
4154
4156
  "registry:component",
4155
4157
  "registry:lib",
4156
4158
  "registry:style",
4157
- "registry:template"
4159
+ "registry:template",
4160
+ "registry:block"
4158
4161
  ];
4159
4162
  var registryFileSchema = external_exports.object({
4160
4163
  path: external_exports.string().min(1),
@@ -5089,13 +5092,339 @@ async function add(components, options = {}) {
5089
5092
  }
5090
5093
  }
5091
5094
 
5092
- // src/commands/diff.ts
5093
- import fs4 from "fs";
5095
+ // src/commands/block.ts
5094
5096
  import path4 from "path";
5095
5097
  import chalk2 from "chalk";
5096
5098
  import ora2 from "ora";
5097
- var FETCH_TIMEOUT_MS = 1e4;
5098
- async function diff(components) {
5099
+ import prompts2 from "prompts";
5100
+
5101
+ // src/constants.ts
5102
+ var DEFAULTS = {
5103
+ REGISTRY_URL: "https://pdfx.akashpise.dev/r",
5104
+ SCHEMA_URL: "https://pdfx.akashpise.dev/schema.json",
5105
+ COMPONENT_DIR: "./src/components/pdfx",
5106
+ THEME_FILE: "./src/lib/pdfx-theme.ts",
5107
+ TEMPLATE_DIR: "./src/templates/pdfx",
5108
+ BLOCK_DIR: "./src/blocks/pdfx"
5109
+ };
5110
+ var REGISTRY_SUBPATHS = {
5111
+ TEMPLATES: "templates"
5112
+ };
5113
+
5114
+ // src/commands/block.ts
5115
+ function readConfig2(configPath) {
5116
+ const raw = readJsonFile(configPath);
5117
+ const result = configSchema.safeParse(raw);
5118
+ if (!result.success) {
5119
+ const issues = result.error.issues.map((i) => i.message).join(", ");
5120
+ throw new ConfigError(
5121
+ `Invalid pdfx.json: ${issues}`,
5122
+ `Fix the config or re-run ${chalk2.cyan("pdfx init")}`
5123
+ );
5124
+ }
5125
+ return result.data;
5126
+ }
5127
+ async function fetchBlock(name, registryUrl) {
5128
+ const url = `${registryUrl}/${REGISTRY_SUBPATHS.TEMPLATES}/${name}.json`;
5129
+ let response;
5130
+ try {
5131
+ response = await fetch(url, { signal: AbortSignal.timeout(1e4) });
5132
+ } catch (err) {
5133
+ const isTimeout = err instanceof Error && err.name === "TimeoutError";
5134
+ throw new NetworkError(
5135
+ isTimeout ? "Registry request timed out" : `Could not reach ${registryUrl}`
5136
+ );
5137
+ }
5138
+ if (!response.ok) {
5139
+ throw new RegistryError(
5140
+ response.status === 404 ? `Block "${name}" not found in registry` : `Registry returned HTTP ${response.status}`
5141
+ );
5142
+ }
5143
+ let data;
5144
+ try {
5145
+ data = await response.json();
5146
+ } catch {
5147
+ throw new RegistryError(`Invalid response for "${name}": not valid JSON`);
5148
+ }
5149
+ const result = registryItemSchema.safeParse(data);
5150
+ if (!result.success) {
5151
+ throw new RegistryError(
5152
+ `Invalid registry entry for "${name}": ${result.error.issues[0]?.message}`
5153
+ );
5154
+ }
5155
+ return result.data;
5156
+ }
5157
+ async function fetchComponent2(name, registryUrl) {
5158
+ const url = `${registryUrl}/${name}.json`;
5159
+ let response;
5160
+ try {
5161
+ response = await fetch(url, { signal: AbortSignal.timeout(1e4) });
5162
+ } catch (err) {
5163
+ const isTimeout = err instanceof Error && err.name === "TimeoutError";
5164
+ throw new NetworkError(
5165
+ isTimeout ? "Registry request timed out" : `Could not reach ${registryUrl}`
5166
+ );
5167
+ }
5168
+ if (!response.ok) {
5169
+ throw new RegistryError(
5170
+ response.status === 404 ? `Component "${name}" not found in registry` : `Registry returned HTTP ${response.status}`
5171
+ );
5172
+ }
5173
+ let data;
5174
+ try {
5175
+ data = await response.json();
5176
+ } catch {
5177
+ throw new RegistryError(`Invalid response for "${name}": not valid JSON`);
5178
+ }
5179
+ const result = registryItemSchema.safeParse(data);
5180
+ if (!result.success) {
5181
+ throw new RegistryError(
5182
+ `Invalid registry entry for "${name}": ${result.error.issues[0]?.message}`
5183
+ );
5184
+ }
5185
+ return result.data;
5186
+ }
5187
+ function resolveBlockImports(content, blockName, config) {
5188
+ const cwd = process.cwd();
5189
+ const blockSubdir = path4.resolve(cwd, config.blockDir ?? DEFAULTS.BLOCK_DIR, blockName);
5190
+ let result = content.replace(
5191
+ /from '\.\.\/\.\.\/components\/pdfx\/([a-z][a-z0-9-]*)\/pdfx-([a-z][a-z0-9-]*)'/g,
5192
+ (_match, componentName) => {
5193
+ const absCompFile = path4.resolve(
5194
+ cwd,
5195
+ config.componentDir,
5196
+ componentName,
5197
+ `pdfx-${componentName}`
5198
+ );
5199
+ let rel = path4.relative(blockSubdir, absCompFile);
5200
+ if (!rel.startsWith(".")) rel = `./${rel}`;
5201
+ return `from '${rel}'`;
5202
+ }
5203
+ );
5204
+ if (config.theme) {
5205
+ const absThemePath = path4.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
5206
+ let relTheme = path4.relative(blockSubdir, absThemePath);
5207
+ if (!relTheme.startsWith(".")) relTheme = `./${relTheme}`;
5208
+ const absContextPath = path4.join(
5209
+ path4.dirname(path4.resolve(cwd, config.theme)),
5210
+ "pdfx-theme-context"
5211
+ );
5212
+ let relContext = path4.relative(blockSubdir, absContextPath);
5213
+ if (!relContext.startsWith(".")) relContext = `./${relContext}`;
5214
+ result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme'/g, `from '${relTheme}'`);
5215
+ result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme-context'/g, `from '${relContext}'`);
5216
+ }
5217
+ return result;
5218
+ }
5219
+ async function resolveConflict(fileName, currentDecision) {
5220
+ if (currentDecision === "overwrite-all") return "overwrite-all";
5221
+ const { action } = await prompts2({
5222
+ type: "select",
5223
+ name: "action",
5224
+ message: `${chalk2.yellow(fileName)} already exists. What would you like to do?`,
5225
+ choices: [
5226
+ { title: "Skip", value: "skip", description: "Keep the existing file unchanged" },
5227
+ { title: "Overwrite", value: "overwrite", description: "Replace this file only" },
5228
+ {
5229
+ title: "Overwrite all",
5230
+ value: "overwrite-all",
5231
+ description: "Replace all conflicting files"
5232
+ }
5233
+ ],
5234
+ initial: 0
5235
+ });
5236
+ if (!action) throw new ValidationError("Cancelled by user");
5237
+ return action;
5238
+ }
5239
+ async function ensurePeerComponents(block, config, force) {
5240
+ const installedPeers = [];
5241
+ const peerWarnings = [];
5242
+ if (!block.peerComponents || block.peerComponents.length === 0) {
5243
+ return { installedPeers, peerWarnings };
5244
+ }
5245
+ const componentBaseDir = path4.resolve(process.cwd(), config.componentDir);
5246
+ for (const componentName of block.peerComponents) {
5247
+ const componentDir = path4.join(componentBaseDir, componentName);
5248
+ const expectedMain = path4.join(componentDir, `pdfx-${componentName}.tsx`);
5249
+ if (checkFileExists(componentDir)) {
5250
+ if (!checkFileExists(expectedMain)) {
5251
+ peerWarnings.push(
5252
+ `${componentName}: directory exists but expected file missing (${path4.basename(expectedMain)})`
5253
+ );
5254
+ } else {
5255
+ peerWarnings.push(
5256
+ `${componentName}: already exists, skipped install (use "pdfx diff ${componentName}" to verify freshness)`
5257
+ );
5258
+ }
5259
+ continue;
5260
+ }
5261
+ const component = await fetchComponent2(componentName, config.registry);
5262
+ ensureDir(componentDir);
5263
+ const componentRelDir = path4.join(config.componentDir, component.name);
5264
+ for (const file of component.files) {
5265
+ const fileName = path4.basename(file.path);
5266
+ const filePath = safePath(componentDir, fileName);
5267
+ let content = file.content;
5268
+ if (config.theme && (content.includes("pdfx-theme") || content.includes("pdfx-theme-context"))) {
5269
+ content = resolveThemeImport(componentRelDir, config.theme, content);
5270
+ }
5271
+ if (checkFileExists(filePath) && !force) {
5272
+ peerWarnings.push(
5273
+ `${componentName}: skipped writing ${fileName} because it already exists (use --force to overwrite)`
5274
+ );
5275
+ continue;
5276
+ }
5277
+ writeFile(filePath, content);
5278
+ }
5279
+ installedPeers.push(componentName);
5280
+ }
5281
+ return { installedPeers, peerWarnings };
5282
+ }
5283
+ async function installBlock(name, config, force) {
5284
+ const block = await fetchBlock(name, config.registry);
5285
+ const peerResult = await ensurePeerComponents(block, config, force);
5286
+ const blockBaseDir = path4.resolve(process.cwd(), config.blockDir ?? DEFAULTS.BLOCK_DIR);
5287
+ const blockDir = path4.join(blockBaseDir, block.name);
5288
+ ensureDir(blockDir);
5289
+ const filesToWrite = [];
5290
+ for (const file of block.files) {
5291
+ const fileName = path4.basename(file.path);
5292
+ const filePath = safePath(blockDir, fileName);
5293
+ let content = file.content;
5294
+ if (/\.(tsx?|jsx?)$/.test(fileName) && content.includes("../../")) {
5295
+ content = resolveBlockImports(content, block.name, config);
5296
+ }
5297
+ filesToWrite.push({ filePath, content });
5298
+ }
5299
+ if (!force) {
5300
+ let globalDecision = null;
5301
+ const resolved = [];
5302
+ for (const file of filesToWrite) {
5303
+ if (checkFileExists(file.filePath)) {
5304
+ const decision = await resolveConflict(path4.basename(file.filePath), globalDecision);
5305
+ if (decision === "overwrite-all") {
5306
+ globalDecision = "overwrite-all";
5307
+ }
5308
+ resolved.push({ ...file, skip: decision === "skip" });
5309
+ } else {
5310
+ resolved.push({ ...file, skip: false });
5311
+ }
5312
+ }
5313
+ for (const file of resolved) {
5314
+ if (!file.skip) {
5315
+ writeFile(file.filePath, file.content);
5316
+ } else {
5317
+ console.log(chalk2.dim(` skipped ${path4.basename(file.filePath)}`));
5318
+ }
5319
+ }
5320
+ } else {
5321
+ for (const file of filesToWrite) {
5322
+ writeFile(file.filePath, file.content);
5323
+ }
5324
+ }
5325
+ if (block.peerComponents && block.peerComponents.length > 0) {
5326
+ const componentBaseDir = path4.resolve(process.cwd(), config.componentDir);
5327
+ const missing = [];
5328
+ for (const comp of block.peerComponents) {
5329
+ const compDir = path4.join(componentBaseDir, comp);
5330
+ if (!checkFileExists(compDir)) {
5331
+ missing.push(comp);
5332
+ }
5333
+ }
5334
+ if (missing.length > 0) {
5335
+ console.log();
5336
+ console.log(chalk2.yellow(" Missing peer components:"));
5337
+ for (const comp of missing) {
5338
+ console.log(chalk2.dim(` ${comp} \u2192 run: ${chalk2.cyan(`pdfx add ${comp}`)}`));
5339
+ }
5340
+ }
5341
+ }
5342
+ if (config.theme) {
5343
+ const absThemePath = path4.resolve(process.cwd(), config.theme);
5344
+ const contextPath = path4.join(path4.dirname(absThemePath), "pdfx-theme-context.tsx");
5345
+ if (!checkFileExists(contextPath)) {
5346
+ ensureDir(path4.dirname(contextPath));
5347
+ writeFile(contextPath, generateThemeContextFile());
5348
+ }
5349
+ }
5350
+ return peerResult;
5351
+ }
5352
+ async function blockAdd(names, options = {}) {
5353
+ const configPath = path4.join(process.cwd(), "pdfx.json");
5354
+ if (!checkFileExists(configPath)) {
5355
+ console.error(chalk2.red("Error: pdfx.json not found"));
5356
+ console.log(chalk2.yellow("Run: pdfx init"));
5357
+ process.exit(1);
5358
+ }
5359
+ let config;
5360
+ try {
5361
+ config = readConfig2(configPath);
5362
+ } catch (error) {
5363
+ if (error instanceof ConfigError) {
5364
+ console.error(chalk2.red(error.message));
5365
+ if (error.suggestion) console.log(chalk2.yellow(` Hint: ${error.suggestion}`));
5366
+ } else {
5367
+ const message = error instanceof Error ? error.message : String(error);
5368
+ console.error(chalk2.red(message));
5369
+ }
5370
+ process.exit(1);
5371
+ }
5372
+ const force = options.force ?? false;
5373
+ const failed = [];
5374
+ for (const blockName of names) {
5375
+ const nameResult = componentNameSchema.safeParse(blockName);
5376
+ if (!nameResult.success) {
5377
+ console.error(chalk2.red(`Invalid block name: "${blockName}"`));
5378
+ console.log(
5379
+ chalk2.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
5380
+ );
5381
+ failed.push(blockName);
5382
+ continue;
5383
+ }
5384
+ const spinner = ora2(`Adding block ${blockName}...`).start();
5385
+ try {
5386
+ const result = await installBlock(blockName, config, force);
5387
+ spinner.succeed(`Added block ${chalk2.cyan(blockName)}`);
5388
+ if (result.installedPeers.length > 0) {
5389
+ console.log(
5390
+ chalk2.green(` Installed required components: ${result.installedPeers.join(", ")}`)
5391
+ );
5392
+ }
5393
+ for (const warning of result.peerWarnings) {
5394
+ console.log(chalk2.yellow(` Warning: ${warning}`));
5395
+ }
5396
+ } catch (error) {
5397
+ if (error instanceof ValidationError && error.message.includes("Cancelled")) {
5398
+ spinner.info("Cancelled");
5399
+ process.exit(0);
5400
+ } else if (error instanceof NetworkError || error instanceof RegistryError || error instanceof ValidationError) {
5401
+ spinner.fail(error.message);
5402
+ if (error.suggestion) {
5403
+ console.log(chalk2.dim(` Hint: ${error.suggestion}`));
5404
+ }
5405
+ } else {
5406
+ spinner.fail(`Failed to add block ${blockName}`);
5407
+ const message = error instanceof Error ? error.message : String(error);
5408
+ console.error(chalk2.dim(` ${message}`));
5409
+ }
5410
+ failed.push(blockName);
5411
+ }
5412
+ }
5413
+ console.log();
5414
+ if (failed.length > 0) {
5415
+ console.log(chalk2.yellow(`Failed: ${failed.join(", ")}`));
5416
+ }
5417
+ if (failed.length < names.length) {
5418
+ const resolvedDir = path4.resolve(process.cwd(), config.blockDir ?? DEFAULTS.BLOCK_DIR);
5419
+ console.log(chalk2.green("Done!"));
5420
+ console.log(chalk2.dim(`Blocks installed to: ${resolvedDir}
5421
+ `));
5422
+ }
5423
+ if (failed.length > 0) {
5424
+ process.exit(1);
5425
+ }
5426
+ }
5427
+ async function blockList() {
5099
5428
  const configPath = path4.join(process.cwd(), "pdfx.json");
5100
5429
  if (!checkFileExists(configPath)) {
5101
5430
  console.error(chalk2.red("Error: pdfx.json not found"));
@@ -5109,14 +5438,85 @@ async function diff(components) {
5109
5438
  process.exit(1);
5110
5439
  }
5111
5440
  const config = configResult.data;
5112
- const targetDir = path4.resolve(process.cwd(), config.componentDir);
5441
+ const spinner = ora2("Fetching block list...").start();
5442
+ try {
5443
+ let response;
5444
+ try {
5445
+ response = await fetch(`${config.registry}/index.json`, {
5446
+ signal: AbortSignal.timeout(1e4)
5447
+ });
5448
+ } catch (err) {
5449
+ const isTimeout = err instanceof Error && err.name === "TimeoutError";
5450
+ throw new NetworkError(
5451
+ isTimeout ? "Registry request timed out" : `Could not reach ${config.registry}`
5452
+ );
5453
+ }
5454
+ if (!response.ok) {
5455
+ throw new RegistryError(`Registry returned HTTP ${response.status}`);
5456
+ }
5457
+ const data = await response.json();
5458
+ const result = registrySchema.safeParse(data);
5459
+ if (!result.success) {
5460
+ throw new RegistryError("Invalid registry format");
5461
+ }
5462
+ spinner.stop();
5463
+ const blocks = result.data.items.filter((item) => item.type === "registry:block");
5464
+ if (blocks.length === 0) {
5465
+ console.log(chalk2.dim("\n No blocks available in the registry.\n"));
5466
+ return;
5467
+ }
5468
+ const blockBaseDir = path4.resolve(process.cwd(), config.blockDir ?? DEFAULTS.BLOCK_DIR);
5469
+ console.log(chalk2.bold(`
5470
+ Available Blocks (${blocks.length})
5471
+ `));
5472
+ for (const item of blocks) {
5473
+ const blockDir = path4.join(blockBaseDir, item.name);
5474
+ const installed = checkFileExists(blockDir);
5475
+ const status = installed ? chalk2.green("[installed]") : chalk2.dim("[not installed]");
5476
+ console.log(` ${chalk2.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
5477
+ console.log(` ${"".padEnd(22)} ${status}`);
5478
+ if (item.peerComponents && item.peerComponents.length > 0) {
5479
+ console.log(chalk2.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
5480
+ }
5481
+ console.log();
5482
+ }
5483
+ console.log(chalk2.dim(` Install with: ${chalk2.cyan("pdfx block add <block-name>")}
5484
+ `));
5485
+ } catch (error) {
5486
+ const message = error instanceof Error ? error.message : String(error);
5487
+ spinner.fail(message);
5488
+ process.exit(1);
5489
+ }
5490
+ }
5491
+
5492
+ // src/commands/diff.ts
5493
+ import fs4 from "fs";
5494
+ import path5 from "path";
5495
+ import chalk3 from "chalk";
5496
+ import ora3 from "ora";
5497
+ var FETCH_TIMEOUT_MS = 1e4;
5498
+ async function diff(components) {
5499
+ const configPath = path5.join(process.cwd(), "pdfx.json");
5500
+ if (!checkFileExists(configPath)) {
5501
+ console.error(chalk3.red("Error: pdfx.json not found"));
5502
+ console.log(chalk3.yellow("Run: pdfx init"));
5503
+ process.exit(1);
5504
+ }
5505
+ const raw = readJsonFile(configPath);
5506
+ const configResult = configSchema.safeParse(raw);
5507
+ if (!configResult.success) {
5508
+ console.error(chalk3.red("Invalid pdfx.json"));
5509
+ process.exit(1);
5510
+ }
5511
+ const config = configResult.data;
5512
+ const targetDir = path5.resolve(process.cwd(), config.componentDir);
5113
5513
  for (const componentName of components) {
5114
5514
  const nameResult = componentNameSchema.safeParse(componentName);
5115
5515
  if (!nameResult.success) {
5116
- console.error(chalk2.red(`Invalid component name: "${componentName}"`));
5516
+ console.error(chalk3.red(`Invalid component name: "${componentName}"`));
5117
5517
  continue;
5118
5518
  }
5119
- const spinner = ora2(`Comparing ${componentName}...`).start();
5519
+ const spinner = ora3(`Comparing ${componentName}...`).start();
5120
5520
  try {
5121
5521
  let response;
5122
5522
  try {
@@ -5127,8 +5527,8 @@ async function diff(components) {
5127
5527
  const isTimeout = err instanceof Error && err.name === "TimeoutError";
5128
5528
  throw new NetworkError(
5129
5529
  isTimeout ? `Registry request timed out after 10 seconds.
5130
- ${chalk2.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
5131
- ${chalk2.dim("Verify the URL is correct and you have internet access.")}`
5530
+ ${chalk3.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
5531
+ ${chalk3.dim("Verify the URL is correct and you have internet access.")}`
5132
5532
  );
5133
5533
  }
5134
5534
  if (!response.ok) {
@@ -5143,32 +5543,32 @@ async function diff(components) {
5143
5543
  }
5144
5544
  const component = result.data;
5145
5545
  spinner.stop();
5146
- const componentSubDir = path4.join(targetDir, component.name);
5546
+ const componentSubDir = path5.join(targetDir, component.name);
5147
5547
  for (const file of component.files) {
5148
- const fileName = path4.basename(file.path);
5548
+ const fileName = path5.basename(file.path);
5149
5549
  const localPath = safePath(componentSubDir, fileName);
5150
5550
  if (!checkFileExists(localPath)) {
5151
- console.log(chalk2.yellow(` ${fileName}: not installed locally`));
5551
+ console.log(chalk3.yellow(` ${fileName}: not installed locally`));
5152
5552
  continue;
5153
5553
  }
5154
5554
  const localContent = fs4.readFileSync(localPath, "utf-8");
5155
5555
  const registryContent = config.theme && (file.content.includes("pdfx-theme") || file.content.includes("pdfx-theme-context")) ? resolveThemeImport(
5156
- path4.join(config.componentDir, component.name),
5556
+ path5.join(config.componentDir, component.name),
5157
5557
  config.theme,
5158
5558
  file.content
5159
5559
  ) : file.content;
5160
5560
  if (localContent === registryContent) {
5161
- console.log(chalk2.green(` ${fileName}: up to date`));
5561
+ console.log(chalk3.green(` ${fileName}: up to date`));
5162
5562
  } else {
5163
- console.log(chalk2.yellow(` ${fileName}: differs from registry`));
5563
+ console.log(chalk3.yellow(` ${fileName}: differs from registry`));
5164
5564
  const localLines = localContent.split("\n");
5165
5565
  const registryLines = registryContent.split("\n");
5166
5566
  const lineDiff = localLines.length - registryLines.length;
5167
- console.log(chalk2.dim(` Local: ${localLines.length} lines`));
5168
- console.log(chalk2.dim(` Registry: ${registryLines.length} lines`));
5567
+ console.log(chalk3.dim(` Local: ${localLines.length} lines`));
5568
+ console.log(chalk3.dim(` Registry: ${registryLines.length} lines`));
5169
5569
  if (lineDiff !== 0) {
5170
5570
  const diffText = lineDiff > 0 ? `${Math.abs(lineDiff)} line${Math.abs(lineDiff) > 1 ? "s" : ""} added locally` : `${Math.abs(lineDiff)} line${Math.abs(lineDiff) > 1 ? "s" : ""} removed locally`;
5171
- console.log(chalk2.dim(` \u2192 ${diffText}`));
5571
+ console.log(chalk3.dim(` \u2192 ${diffText}`));
5172
5572
  }
5173
5573
  }
5174
5574
  }
@@ -5182,32 +5582,20 @@ async function diff(components) {
5182
5582
 
5183
5583
  // src/commands/init.ts
5184
5584
  import fs7 from "fs";
5185
- import path7 from "path";
5186
- import chalk5 from "chalk";
5187
- import ora4 from "ora";
5188
- import prompts3 from "prompts";
5189
-
5190
- // src/constants.ts
5191
- var DEFAULTS = {
5192
- REGISTRY_URL: "https://pdfx.akashpise.dev/r",
5193
- SCHEMA_URL: "https://pdfx.akashpise.dev/schema.json",
5194
- COMPONENT_DIR: "./src/components/pdfx",
5195
- THEME_FILE: "./src/lib/pdfx-theme.ts",
5196
- TEMPLATE_DIR: "./src/templates/pdfx"
5197
- };
5198
- var REGISTRY_SUBPATHS = {
5199
- TEMPLATES: "templates"
5200
- };
5585
+ import path8 from "path";
5586
+ import chalk6 from "chalk";
5587
+ import ora5 from "ora";
5588
+ import prompts4 from "prompts";
5201
5589
 
5202
5590
  // src/utils/install-dependencies.ts
5203
- import chalk3 from "chalk";
5591
+ import chalk4 from "chalk";
5204
5592
  import { execa } from "execa";
5205
- import ora3 from "ora";
5206
- import prompts2 from "prompts";
5593
+ import ora4 from "ora";
5594
+ import prompts3 from "prompts";
5207
5595
 
5208
5596
  // src/utils/package-manager.ts
5209
5597
  import fs5 from "fs";
5210
- import path5 from "path";
5598
+ import path6 from "path";
5211
5599
  var PACKAGE_MANAGERS = {
5212
5600
  pnpm: {
5213
5601
  name: "pnpm",
@@ -5234,7 +5622,7 @@ function detectPackageManager(cwd = process.cwd()) {
5234
5622
  const managers = ["pnpm", "yarn", "bun", "npm"];
5235
5623
  for (const manager of managers) {
5236
5624
  const info = PACKAGE_MANAGERS[manager];
5237
- const lockfilePath = path5.join(cwd, info.lockfile);
5625
+ const lockfilePath = path6.join(cwd, info.lockfile);
5238
5626
  if (fs5.existsSync(lockfilePath)) {
5239
5627
  return info;
5240
5628
  }
@@ -5258,10 +5646,10 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
5258
5646
  const pm = detectPackageManager(cwd);
5259
5647
  const packageName = "@react-pdf/renderer";
5260
5648
  const installCmd = getInstallCommand(pm.name, [packageName]);
5261
- console.log(chalk3.yellow("\n \u26A0 @react-pdf/renderer is required but not installed\n"));
5262
- console.log(chalk3.dim(` This command will run: ${installCmd}
5649
+ console.log(chalk4.yellow("\n \u26A0 @react-pdf/renderer is required but not installed\n"));
5650
+ console.log(chalk4.dim(` This command will run: ${installCmd}
5263
5651
  `));
5264
- const { shouldInstall } = await prompts2({
5652
+ const { shouldInstall } = await prompts3({
5265
5653
  type: "confirm",
5266
5654
  name: "shouldInstall",
5267
5655
  message: "Install @react-pdf/renderer now?",
@@ -5271,10 +5659,10 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
5271
5659
  return {
5272
5660
  success: false,
5273
5661
  message: `Installation cancelled. Please install manually:
5274
- ${chalk3.cyan(installCmd)}`
5662
+ ${chalk4.cyan(installCmd)}`
5275
5663
  };
5276
5664
  }
5277
- const spinner = ora3("Installing @react-pdf/renderer...").start();
5665
+ const spinner = ora4("Installing @react-pdf/renderer...").start();
5278
5666
  try {
5279
5667
  await execa(pm.name, ["add", packageName], {
5280
5668
  cwd,
@@ -5291,7 +5679,7 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
5291
5679
  return {
5292
5680
  success: false,
5293
5681
  message: `Installation failed: ${message}
5294
- Try manually: ${chalk3.cyan(installCmd)}`
5682
+ Try manually: ${chalk4.cyan(installCmd)}`
5295
5683
  };
5296
5684
  }
5297
5685
  }
@@ -5299,7 +5687,7 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
5299
5687
  if (!validation.installed) {
5300
5688
  const result = await promptAndInstallReactPdf(validation, cwd);
5301
5689
  if (!result.success) {
5302
- console.error(chalk3.red(`
5690
+ console.error(chalk4.red(`
5303
5691
  ${result.message}
5304
5692
  `));
5305
5693
  return false;
@@ -5308,10 +5696,10 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
5308
5696
  }
5309
5697
  if (!validation.valid) {
5310
5698
  console.log(
5311
- chalk3.yellow(
5699
+ chalk4.yellow(
5312
5700
  `
5313
5701
  \u26A0 ${validation.message}
5314
- ${chalk3.dim("\u2192")} You may encounter compatibility issues
5702
+ ${chalk4.dim("\u2192")} You may encounter compatibility issues
5315
5703
  `
5316
5704
  )
5317
5705
  );
@@ -5320,13 +5708,13 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
5320
5708
  }
5321
5709
 
5322
5710
  // src/utils/pre-flight.ts
5323
- import chalk4 from "chalk";
5711
+ import chalk5 from "chalk";
5324
5712
 
5325
5713
  // src/utils/environment-validator.ts
5326
5714
  import fs6 from "fs";
5327
- import path6 from "path";
5715
+ import path7 from "path";
5328
5716
  function validatePackageJson(cwd = process.cwd()) {
5329
- const pkgPath = path6.join(cwd, "package.json");
5717
+ const pkgPath = path7.join(cwd, "package.json");
5330
5718
  const exists = fs6.existsSync(pkgPath);
5331
5719
  return {
5332
5720
  valid: exists,
@@ -5335,7 +5723,7 @@ function validatePackageJson(cwd = process.cwd()) {
5335
5723
  };
5336
5724
  }
5337
5725
  function validateReactProject(cwd = process.cwd()) {
5338
- const pkgPath = path6.join(cwd, "package.json");
5726
+ const pkgPath = path7.join(cwd, "package.json");
5339
5727
  if (!fs6.existsSync(pkgPath)) {
5340
5728
  return {
5341
5729
  valid: false,
@@ -5362,7 +5750,7 @@ function validateReactProject(cwd = process.cwd()) {
5362
5750
  }
5363
5751
  }
5364
5752
  function validatePdfxConfig(cwd = process.cwd()) {
5365
- const configPath = path6.join(cwd, "pdfx.json");
5753
+ const configPath = path7.join(cwd, "pdfx.json");
5366
5754
  const exists = fs6.existsSync(configPath);
5367
5755
  return {
5368
5756
  valid: true,
@@ -5387,43 +5775,43 @@ function runPreFlightChecks(cwd = process.cwd()) {
5387
5775
  if (!environment.hasPackageJson.valid) {
5388
5776
  blockingErrors.push(
5389
5777
  `${environment.hasPackageJson.message}
5390
- ${chalk4.dim("\u2192")} ${environment.hasPackageJson.fixCommand}`
5778
+ ${chalk5.dim("\u2192")} ${environment.hasPackageJson.fixCommand}`
5391
5779
  );
5392
5780
  } else if (!environment.isReactProject.valid) {
5393
5781
  blockingErrors.push(
5394
5782
  `${environment.isReactProject.message}
5395
- ${chalk4.dim("\u2192")} ${environment.isReactProject.fixCommand}`
5783
+ ${chalk5.dim("\u2192")} ${environment.isReactProject.fixCommand}`
5396
5784
  );
5397
5785
  } else {
5398
5786
  if (!dependencies.react.valid && dependencies.react.installed) {
5399
5787
  warnings.push(
5400
5788
  `${dependencies.react.message}
5401
- ${chalk4.dim("\u2192")} Current: ${dependencies.react.currentVersion}, Required: ${dependencies.react.requiredVersion}`
5789
+ ${chalk5.dim("\u2192")} Current: ${dependencies.react.currentVersion}, Required: ${dependencies.react.requiredVersion}`
5402
5790
  );
5403
5791
  } else if (!dependencies.react.installed) {
5404
5792
  blockingErrors.push(
5405
5793
  `${dependencies.react.message}
5406
- ${chalk4.dim("\u2192")} Install React: npm install react react-dom`
5794
+ ${chalk5.dim("\u2192")} Install React: npm install react react-dom`
5407
5795
  );
5408
5796
  }
5409
5797
  }
5410
5798
  if (!dependencies.nodeJs.valid) {
5411
5799
  blockingErrors.push(
5412
5800
  `${dependencies.nodeJs.message}
5413
- ${chalk4.dim("\u2192")} Current: ${dependencies.nodeJs.currentVersion}, Required: ${dependencies.nodeJs.requiredVersion}
5414
- ${chalk4.dim("\u2192")} Visit https://nodejs.org to upgrade`
5801
+ ${chalk5.dim("\u2192")} Current: ${dependencies.nodeJs.currentVersion}, Required: ${dependencies.nodeJs.requiredVersion}
5802
+ ${chalk5.dim("\u2192")} Visit https://nodejs.org to upgrade`
5415
5803
  );
5416
5804
  }
5417
5805
  if (dependencies.reactPdfRenderer.installed && !dependencies.reactPdfRenderer.valid) {
5418
5806
  warnings.push(
5419
5807
  `${dependencies.reactPdfRenderer.message}
5420
- ${chalk4.dim("\u2192")} Consider upgrading: npm install @react-pdf/renderer@latest`
5808
+ ${chalk5.dim("\u2192")} Consider upgrading: npm install @react-pdf/renderer@latest`
5421
5809
  );
5422
5810
  }
5423
5811
  if (dependencies.typescript && !dependencies.typescript.valid) {
5424
5812
  warnings.push(
5425
5813
  `${dependencies.typescript.message}
5426
- ${chalk4.dim("\u2192")} Install types: npm install -D @types/react-pdf`
5814
+ ${chalk5.dim("\u2192")} Install types: npm install -D @types/react-pdf`
5427
5815
  );
5428
5816
  }
5429
5817
  return {
@@ -5435,58 +5823,58 @@ function runPreFlightChecks(cwd = process.cwd()) {
5435
5823
  };
5436
5824
  }
5437
5825
  function displayPreFlightResults(result) {
5438
- console.log(chalk4.bold("\n Pre-flight Checks:\n"));
5826
+ console.log(chalk5.bold("\n Pre-flight Checks:\n"));
5439
5827
  if (result.blockingErrors.length > 0) {
5440
- console.log(chalk4.red(" \u2717 Blocking Issues:\n"));
5828
+ console.log(chalk5.red(" \u2717 Blocking Issues:\n"));
5441
5829
  for (const error of result.blockingErrors) {
5442
- console.log(chalk4.red(` \u2022 ${error}
5830
+ console.log(chalk5.red(` \u2022 ${error}
5443
5831
  `));
5444
5832
  }
5445
5833
  }
5446
5834
  if (result.warnings.length > 0) {
5447
- console.log(chalk4.yellow(" \u26A0 Warnings:\n"));
5835
+ console.log(chalk5.yellow(" \u26A0 Warnings:\n"));
5448
5836
  for (const warning of result.warnings) {
5449
- console.log(chalk4.yellow(` \u2022 ${warning}
5837
+ console.log(chalk5.yellow(` \u2022 ${warning}
5450
5838
  `));
5451
5839
  }
5452
5840
  }
5453
5841
  if (result.blockingErrors.length === 0 && result.warnings.length === 0) {
5454
- console.log(chalk4.green(" \u2713 All checks passed!\n"));
5842
+ console.log(chalk5.green(" \u2713 All checks passed!\n"));
5455
5843
  }
5456
5844
  }
5457
5845
 
5458
5846
  // src/commands/init.ts
5459
5847
  async function init() {
5460
- console.log(chalk5.bold.cyan("\n Welcome to the pdfx cli\n"));
5848
+ console.log(chalk6.bold.cyan("\n Welcome to the pdfx cli\n"));
5461
5849
  const preFlightResult = runPreFlightChecks();
5462
5850
  displayPreFlightResults(preFlightResult);
5463
5851
  if (!preFlightResult.canProceed) {
5464
5852
  console.error(
5465
- chalk5.red("\n Cannot proceed due to blocking issues. Please fix them and try again.\n")
5853
+ chalk6.red("\n Cannot proceed due to blocking issues. Please fix them and try again.\n")
5466
5854
  );
5467
5855
  process.exit(1);
5468
5856
  }
5469
5857
  const hasReactPdf = await ensureReactPdfRenderer(preFlightResult.dependencies.reactPdfRenderer);
5470
5858
  if (!hasReactPdf) {
5471
5859
  console.error(
5472
- chalk5.red("\n @react-pdf/renderer is required. Please install it and try again.\n")
5860
+ chalk6.red("\n @react-pdf/renderer is required. Please install it and try again.\n")
5473
5861
  );
5474
5862
  process.exit(1);
5475
5863
  }
5476
- const existingConfig = path7.join(process.cwd(), "pdfx.json");
5864
+ const existingConfig = path8.join(process.cwd(), "pdfx.json");
5477
5865
  if (fs7.existsSync(existingConfig)) {
5478
- const { overwrite } = await prompts3({
5866
+ const { overwrite } = await prompts4({
5479
5867
  type: "confirm",
5480
5868
  name: "overwrite",
5481
5869
  message: "pdfx.json already exists. Overwrite?",
5482
5870
  initial: false
5483
5871
  });
5484
5872
  if (!overwrite) {
5485
- console.log(chalk5.yellow("Init cancelled \u2014 existing config preserved."));
5873
+ console.log(chalk6.yellow("Init cancelled \u2014 existing config preserved."));
5486
5874
  return;
5487
5875
  }
5488
5876
  }
5489
- const answers = await prompts3(
5877
+ const answers = await prompts4(
5490
5878
  [
5491
5879
  {
5492
5880
  type: "text",
@@ -5497,7 +5885,7 @@ async function init() {
5497
5885
  if (!value || value.trim().length === 0) {
5498
5886
  return "Component directory is required";
5499
5887
  }
5500
- if (path7.isAbsolute(value)) {
5888
+ if (path8.isAbsolute(value)) {
5501
5889
  return "Please use a relative path (e.g., ./src/components/pdfx)";
5502
5890
  }
5503
5891
  if (!value.startsWith(".")) {
@@ -5506,6 +5894,24 @@ async function init() {
5506
5894
  return true;
5507
5895
  }
5508
5896
  },
5897
+ {
5898
+ type: "text",
5899
+ name: "blockDir",
5900
+ message: "Where should we install blocks?",
5901
+ initial: DEFAULTS.BLOCK_DIR,
5902
+ validate: (value) => {
5903
+ if (!value || value.trim().length === 0) {
5904
+ return "Block directory is required";
5905
+ }
5906
+ if (path8.isAbsolute(value)) {
5907
+ return "Please use a relative path (e.g., ./src/blocks/pdfx)";
5908
+ }
5909
+ if (!value.startsWith(".")) {
5910
+ return "Path should start with ./ or ../ (e.g., ./src/blocks/pdfx)";
5911
+ }
5912
+ return true;
5913
+ }
5914
+ },
5509
5915
  {
5510
5916
  type: "text",
5511
5917
  name: "registry",
@@ -5550,7 +5956,7 @@ async function init() {
5550
5956
  if (!value || value.trim().length === 0) {
5551
5957
  return "Theme path is required";
5552
5958
  }
5553
- if (path7.isAbsolute(value)) {
5959
+ if (path8.isAbsolute(value)) {
5554
5960
  return "Please use a relative path (e.g., ./src/lib/pdfx-theme.ts)";
5555
5961
  }
5556
5962
  if (!value.endsWith(".ts") && !value.endsWith(".tsx")) {
@@ -5562,68 +5968,71 @@ async function init() {
5562
5968
  ],
5563
5969
  {
5564
5970
  onCancel: () => {
5565
- console.log(chalk5.yellow("\nSetup cancelled."));
5971
+ console.log(chalk6.yellow("\nSetup cancelled."));
5566
5972
  process.exit(0);
5567
5973
  }
5568
5974
  }
5569
5975
  );
5570
5976
  if (!answers.componentDir || !answers.registry) {
5571
- console.error(chalk5.red("Missing required fields. Run pdfx init again."));
5977
+ console.error(chalk6.red("Missing required fields. Run pdfx init again."));
5572
5978
  process.exit(1);
5573
5979
  }
5574
5980
  const config = {
5575
5981
  $schema: DEFAULTS.SCHEMA_URL,
5576
5982
  componentDir: answers.componentDir,
5577
5983
  registry: answers.registry,
5578
- theme: answers.themePath || DEFAULTS.THEME_FILE
5984
+ theme: answers.themePath || DEFAULTS.THEME_FILE,
5985
+ blockDir: answers.blockDir || DEFAULTS.BLOCK_DIR
5579
5986
  };
5580
5987
  const validation = configSchema.safeParse(config);
5581
5988
  if (!validation.success) {
5582
5989
  const issues = validation.error.issues.map((i) => i.message).join(", ");
5583
- console.error(chalk5.red(`Invalid configuration: ${issues}`));
5990
+ console.error(chalk6.red(`Invalid configuration: ${issues}`));
5584
5991
  process.exit(1);
5585
5992
  }
5586
- const spinner = ora4("Creating config and theme files...").start();
5993
+ const spinner = ora5("Creating config and theme files...").start();
5587
5994
  try {
5588
- const componentDirPath = path7.resolve(process.cwd(), answers.componentDir);
5995
+ const componentDirPath = path8.resolve(process.cwd(), answers.componentDir);
5589
5996
  ensureDir(componentDirPath);
5590
- fs7.writeFileSync(path7.join(process.cwd(), "pdfx.json"), JSON.stringify(config, null, 2));
5997
+ fs7.writeFileSync(path8.join(process.cwd(), "pdfx.json"), JSON.stringify(config, null, 2));
5591
5998
  const presetName = answers.themePreset || "professional";
5592
5999
  const preset = themePresets[presetName];
5593
- const themePath = path7.resolve(process.cwd(), config.theme);
5594
- ensureDir(path7.dirname(themePath));
6000
+ const themePath = path8.resolve(process.cwd(), config.theme);
6001
+ ensureDir(path8.dirname(themePath));
5595
6002
  fs7.writeFileSync(themePath, generateThemeFile(preset), "utf-8");
5596
- const contextPath = path7.join(path7.dirname(themePath), "pdfx-theme-context.tsx");
6003
+ const contextPath = path8.join(path8.dirname(themePath), "pdfx-theme-context.tsx");
5597
6004
  fs7.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
5598
6005
  spinner.succeed(`Created pdfx.json + ${config.theme} (${presetName} theme)`);
5599
- console.log(chalk5.green("\nSuccess! You can now run:"));
5600
- console.log(chalk5.cyan(" pdfx add heading"));
5601
- console.log(chalk5.dim(`
5602
- Components: ${path7.resolve(process.cwd(), answers.componentDir)}`));
5603
- console.log(chalk5.dim(` Theme: ${path7.resolve(process.cwd(), config.theme)}
6006
+ console.log(chalk6.green("\nSuccess! You can now run:"));
6007
+ console.log(chalk6.cyan(" pdfx add heading"));
6008
+ console.log(chalk6.cyan(" pdfx block add invoice-classic"));
6009
+ console.log(chalk6.dim(`
6010
+ Components: ${path8.resolve(process.cwd(), answers.componentDir)}`));
6011
+ console.log(chalk6.dim(` Blocks: ${path8.resolve(process.cwd(), config.blockDir)}`));
6012
+ console.log(chalk6.dim(` Theme: ${path8.resolve(process.cwd(), config.theme)}
5604
6013
  `));
5605
6014
  } catch (error) {
5606
6015
  spinner.fail("Failed to create config");
5607
6016
  const message = error instanceof Error ? error.message : String(error);
5608
- console.error(chalk5.dim(` ${message}`));
6017
+ console.error(chalk6.dim(` ${message}`));
5609
6018
  process.exit(1);
5610
6019
  }
5611
6020
  }
5612
6021
 
5613
6022
  // src/commands/list.ts
5614
- import path8 from "path";
5615
- import chalk6 from "chalk";
5616
- import ora5 from "ora";
6023
+ import path9 from "path";
6024
+ import chalk7 from "chalk";
6025
+ import ora6 from "ora";
5617
6026
  var FETCH_TIMEOUT_MS2 = 1e4;
5618
6027
  async function list() {
5619
- const configPath = path8.join(process.cwd(), "pdfx.json");
6028
+ const configPath = path9.join(process.cwd(), "pdfx.json");
5620
6029
  let config;
5621
6030
  let hasLocalProject = false;
5622
6031
  if (checkFileExists(configPath)) {
5623
6032
  const raw = readJsonFile(configPath);
5624
6033
  const configResult = configSchema.safeParse(raw);
5625
6034
  if (!configResult.success) {
5626
- console.error(chalk6.red("Invalid pdfx.json"));
6035
+ console.error(chalk7.red("Invalid pdfx.json"));
5627
6036
  process.exit(1);
5628
6037
  }
5629
6038
  config = configResult.data;
@@ -5634,9 +6043,9 @@ async function list() {
5634
6043
  componentDir: "./src/components/pdfx",
5635
6044
  theme: "./src/lib/pdfx-theme.ts"
5636
6045
  };
5637
- console.log(chalk6.dim("No pdfx.json found. Listing components from default registry.\n"));
6046
+ console.log(chalk7.dim("No pdfx.json found. Listing from default registry.\n"));
5638
6047
  }
5639
- const spinner = ora5("Fetching component list...").start();
6048
+ const spinner = ora6("Fetching registry...").start();
5640
6049
  try {
5641
6050
  let response;
5642
6051
  try {
@@ -5647,8 +6056,8 @@ async function list() {
5647
6056
  const isTimeout = err instanceof Error && err.name === "TimeoutError";
5648
6057
  throw new NetworkError(
5649
6058
  isTimeout ? `Registry request timed out after 10 seconds.
5650
- ${chalk6.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
5651
- ${chalk6.dim("Verify the URL is correct and you have internet access.")}`
6059
+ ${chalk7.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
6060
+ ${chalk7.dim("Verify the URL is correct and you have internet access.")}`
5652
6061
  );
5653
6062
  }
5654
6063
  if (!response.ok) {
@@ -5661,23 +6070,62 @@ async function list() {
5661
6070
  }
5662
6071
  spinner.stop();
5663
6072
  const components = result.data.items.filter((item) => item.type === "registry:ui");
5664
- console.log(chalk6.bold(`
5665
- Available Components (${components.length})
5666
- `));
6073
+ const templates = result.data.items.filter((item) => item.type === "registry:template");
6074
+ const blocks = result.data.items.filter((item) => item.type === "registry:block");
6075
+ const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
6076
+ const templateBaseDir = path9.resolve(process.cwd(), config.templateDir ?? "./src/templates");
6077
+ console.log(chalk7.bold(`
6078
+ Components (${components.length})`));
6079
+ console.log(chalk7.dim(" Install with: pdfx add <component>\n"));
5667
6080
  for (const item of components) {
6081
+ const componentSubDir = path9.join(componentBaseDir, item.name);
6082
+ const localPath = safePath(componentSubDir, `pdfx-${item.name}.tsx`);
6083
+ const installed = hasLocalProject && checkFileExists(localPath);
6084
+ const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6085
+ console.log(` ${chalk7.cyan(item.name.padEnd(20))} ${item.description}`);
5668
6086
  if (hasLocalProject) {
5669
- const targetDir = path8.resolve(process.cwd(), config.componentDir);
5670
- const componentSubDir = path8.join(targetDir, item.name);
5671
- const localPath = safePath(componentSubDir, `pdfx-${item.name}.tsx`);
5672
- const installed = checkFileExists(localPath);
5673
- const status = installed ? chalk6.green("[installed]") : chalk6.dim("[not installed]");
5674
- console.log(` ${chalk6.cyan(item.name.padEnd(20))} ${item.description}`);
5675
6087
  console.log(` ${"".padEnd(20)} ${status}`);
5676
- } else {
5677
- console.log(` ${chalk6.cyan(item.name.padEnd(20))} ${item.description}`);
5678
6088
  }
5679
6089
  console.log();
5680
6090
  }
6091
+ console.log(chalk7.bold(` Templates (${templates.length})`));
6092
+ console.log(chalk7.dim(" Data-driven. Install with: pdfx template add <template>\n"));
6093
+ for (const item of templates) {
6094
+ const templateDir = path9.join(templateBaseDir, item.name);
6095
+ const installed = hasLocalProject && checkFileExists(templateDir);
6096
+ const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6097
+ console.log(` ${chalk7.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6098
+ if (hasLocalProject) {
6099
+ console.log(` ${"".padEnd(22)} ${status}`);
6100
+ }
6101
+ console.log();
6102
+ }
6103
+ console.log(chalk7.bold(` Blocks (${blocks.length})`));
6104
+ console.log(chalk7.dim(" Copy-paste designs. Install with: pdfx block add <block>\n"));
6105
+ for (const item of blocks) {
6106
+ const blockDir = path9.join(templateBaseDir, item.name);
6107
+ const installed = hasLocalProject && checkFileExists(blockDir);
6108
+ const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6109
+ console.log(` ${chalk7.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6110
+ if (hasLocalProject) {
6111
+ console.log(` ${"".padEnd(22)} ${status}`);
6112
+ }
6113
+ if (item.peerComponents && item.peerComponents.length > 0) {
6114
+ console.log(chalk7.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
6115
+ }
6116
+ console.log();
6117
+ }
6118
+ console.log(chalk7.dim(" Quick Start:"));
6119
+ console.log(
6120
+ chalk7.dim(` pdfx add heading table ${chalk7.dim("# Add components")}`)
6121
+ );
6122
+ console.log(
6123
+ chalk7.dim(` pdfx template add invoice-template ${chalk7.dim("# Add data-driven template")}`)
6124
+ );
6125
+ console.log(
6126
+ chalk7.dim(` pdfx block add invoice-classic ${chalk7.dim("# Add copy-paste block")}`)
6127
+ );
6128
+ console.log();
5681
6129
  } catch (error) {
5682
6130
  const message = error instanceof Error ? error.message : String(error);
5683
6131
  spinner.fail(message);
@@ -5686,18 +6134,18 @@ async function list() {
5686
6134
  }
5687
6135
 
5688
6136
  // src/commands/template.ts
5689
- import path9 from "path";
5690
- import chalk7 from "chalk";
5691
- import ora6 from "ora";
5692
- import prompts4 from "prompts";
5693
- function readConfig2(configPath) {
6137
+ import path10 from "path";
6138
+ import chalk8 from "chalk";
6139
+ import ora7 from "ora";
6140
+ import prompts5 from "prompts";
6141
+ function readConfig3(configPath) {
5694
6142
  const raw = readJsonFile(configPath);
5695
6143
  const result = configSchema.safeParse(raw);
5696
6144
  if (!result.success) {
5697
6145
  const issues = result.error.issues.map((i) => i.message).join(", ");
5698
6146
  throw new ConfigError(
5699
6147
  `Invalid pdfx.json: ${issues}`,
5700
- `Fix the config or re-run ${chalk7.cyan("pdfx init")}`
6148
+ `Fix the config or re-run ${chalk8.cyan("pdfx init")}`
5701
6149
  );
5702
6150
  }
5703
6151
  return result.data;
@@ -5732,7 +6180,7 @@ async function fetchTemplate(name, registryUrl) {
5732
6180
  }
5733
6181
  return result.data;
5734
6182
  }
5735
- async function fetchComponent2(name, registryUrl) {
6183
+ async function fetchComponent3(name, registryUrl) {
5736
6184
  const url = `${registryUrl}/${name}.json`;
5737
6185
  let response;
5738
6186
  try {
@@ -5764,7 +6212,7 @@ async function fetchComponent2(name, registryUrl) {
5764
6212
  }
5765
6213
  function resolveTemplateImports(content, templateName, config) {
5766
6214
  const cwd = process.cwd();
5767
- const templateSubdir = path9.resolve(
6215
+ const templateSubdir = path10.resolve(
5768
6216
  cwd,
5769
6217
  config.templateDir ?? DEFAULTS.TEMPLATE_DIR,
5770
6218
  templateName
@@ -5772,38 +6220,38 @@ function resolveTemplateImports(content, templateName, config) {
5772
6220
  let result = content.replace(
5773
6221
  /from '\.\.\/\.\.\/components\/pdfx\/([a-z][a-z0-9-]*)\/pdfx-([a-z][a-z0-9-]*)'/g,
5774
6222
  (_match, componentName) => {
5775
- const absCompFile = path9.resolve(
6223
+ const absCompFile = path10.resolve(
5776
6224
  cwd,
5777
6225
  config.componentDir,
5778
6226
  componentName,
5779
6227
  `pdfx-${componentName}`
5780
6228
  );
5781
- let rel = path9.relative(templateSubdir, absCompFile);
6229
+ let rel = path10.relative(templateSubdir, absCompFile);
5782
6230
  if (!rel.startsWith(".")) rel = `./${rel}`;
5783
6231
  return `from '${rel}'`;
5784
6232
  }
5785
6233
  );
5786
6234
  if (config.theme) {
5787
- const absThemePath = path9.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
5788
- let relTheme = path9.relative(templateSubdir, absThemePath);
6235
+ const absThemePath = path10.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
6236
+ let relTheme = path10.relative(templateSubdir, absThemePath);
5789
6237
  if (!relTheme.startsWith(".")) relTheme = `./${relTheme}`;
5790
- const absContextPath = path9.join(
5791
- path9.dirname(path9.resolve(cwd, config.theme)),
6238
+ const absContextPath = path10.join(
6239
+ path10.dirname(path10.resolve(cwd, config.theme)),
5792
6240
  "pdfx-theme-context"
5793
6241
  );
5794
- let relContext = path9.relative(templateSubdir, absContextPath);
6242
+ let relContext = path10.relative(templateSubdir, absContextPath);
5795
6243
  if (!relContext.startsWith(".")) relContext = `./${relContext}`;
5796
6244
  result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme'/g, `from '${relTheme}'`);
5797
6245
  result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme-context'/g, `from '${relContext}'`);
5798
6246
  }
5799
6247
  return result;
5800
6248
  }
5801
- async function resolveConflict(fileName, currentDecision) {
6249
+ async function resolveConflict2(fileName, currentDecision) {
5802
6250
  if (currentDecision === "overwrite-all") return "overwrite-all";
5803
- const { action } = await prompts4({
6251
+ const { action } = await prompts5({
5804
6252
  type: "select",
5805
6253
  name: "action",
5806
- message: `${chalk7.yellow(fileName)} already exists. What would you like to do?`,
6254
+ message: `${chalk8.yellow(fileName)} already exists. What would you like to do?`,
5807
6255
  choices: [
5808
6256
  { title: "Skip", value: "skip", description: "Keep the existing file unchanged" },
5809
6257
  { title: "Overwrite", value: "overwrite", description: "Replace this file only" },
@@ -5818,20 +6266,20 @@ async function resolveConflict(fileName, currentDecision) {
5818
6266
  if (!action) throw new ValidationError("Cancelled by user");
5819
6267
  return action;
5820
6268
  }
5821
- async function ensurePeerComponents(template, config, force) {
6269
+ async function ensurePeerComponents2(template, config, force) {
5822
6270
  const installedPeers = [];
5823
6271
  const peerWarnings = [];
5824
6272
  if (!template.peerComponents || template.peerComponents.length === 0) {
5825
6273
  return { installedPeers, peerWarnings };
5826
6274
  }
5827
- const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
6275
+ const componentBaseDir = path10.resolve(process.cwd(), config.componentDir);
5828
6276
  for (const componentName of template.peerComponents) {
5829
- const componentDir = path9.join(componentBaseDir, componentName);
5830
- const expectedMain = path9.join(componentDir, `pdfx-${componentName}.tsx`);
6277
+ const componentDir = path10.join(componentBaseDir, componentName);
6278
+ const expectedMain = path10.join(componentDir, `pdfx-${componentName}.tsx`);
5831
6279
  if (checkFileExists(componentDir)) {
5832
6280
  if (!checkFileExists(expectedMain)) {
5833
6281
  peerWarnings.push(
5834
- `${componentName}: directory exists but expected file missing (${path9.basename(expectedMain)})`
6282
+ `${componentName}: directory exists but expected file missing (${path10.basename(expectedMain)})`
5835
6283
  );
5836
6284
  } else {
5837
6285
  peerWarnings.push(
@@ -5840,11 +6288,11 @@ async function ensurePeerComponents(template, config, force) {
5840
6288
  }
5841
6289
  continue;
5842
6290
  }
5843
- const component = await fetchComponent2(componentName, config.registry);
6291
+ const component = await fetchComponent3(componentName, config.registry);
5844
6292
  ensureDir(componentDir);
5845
- const componentRelDir = path9.join(config.componentDir, component.name);
6293
+ const componentRelDir = path10.join(config.componentDir, component.name);
5846
6294
  for (const file of component.files) {
5847
- const fileName = path9.basename(file.path);
6295
+ const fileName = path10.basename(file.path);
5848
6296
  const filePath = safePath(componentDir, fileName);
5849
6297
  let content = file.content;
5850
6298
  if (config.theme && (content.includes("pdfx-theme") || content.includes("pdfx-theme-context"))) {
@@ -5864,13 +6312,13 @@ async function ensurePeerComponents(template, config, force) {
5864
6312
  }
5865
6313
  async function installTemplate(name, config, force) {
5866
6314
  const template = await fetchTemplate(name, config.registry);
5867
- const peerResult = await ensurePeerComponents(template, config, force);
5868
- const templateBaseDir = path9.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
5869
- const templateDir = path9.join(templateBaseDir, template.name);
6315
+ const peerResult = await ensurePeerComponents2(template, config, force);
6316
+ const templateBaseDir = path10.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
6317
+ const templateDir = path10.join(templateBaseDir, template.name);
5870
6318
  ensureDir(templateDir);
5871
6319
  const filesToWrite = [];
5872
6320
  for (const file of template.files) {
5873
- const fileName = path9.basename(file.path);
6321
+ const fileName = path10.basename(file.path);
5874
6322
  const filePath = safePath(templateDir, fileName);
5875
6323
  let content = file.content;
5876
6324
  if (/\.(tsx?|jsx?)$/.test(fileName) && content.includes("../../")) {
@@ -5883,7 +6331,7 @@ async function installTemplate(name, config, force) {
5883
6331
  const resolved = [];
5884
6332
  for (const file of filesToWrite) {
5885
6333
  if (checkFileExists(file.filePath)) {
5886
- const decision = await resolveConflict(path9.basename(file.filePath), globalDecision);
6334
+ const decision = await resolveConflict2(path10.basename(file.filePath), globalDecision);
5887
6335
  if (decision === "overwrite-all") {
5888
6336
  globalDecision = "overwrite-all";
5889
6337
  }
@@ -5896,7 +6344,7 @@ async function installTemplate(name, config, force) {
5896
6344
  if (!file.skip) {
5897
6345
  writeFile(file.filePath, file.content);
5898
6346
  } else {
5899
- console.log(chalk7.dim(` skipped ${path9.basename(file.filePath)}`));
6347
+ console.log(chalk8.dim(` skipped ${path10.basename(file.filePath)}`));
5900
6348
  }
5901
6349
  }
5902
6350
  } else {
@@ -5905,49 +6353,49 @@ async function installTemplate(name, config, force) {
5905
6353
  }
5906
6354
  }
5907
6355
  if (template.peerComponents && template.peerComponents.length > 0) {
5908
- const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
6356
+ const componentBaseDir = path10.resolve(process.cwd(), config.componentDir);
5909
6357
  const missing = [];
5910
6358
  for (const comp of template.peerComponents) {
5911
- const compDir = path9.join(componentBaseDir, comp);
6359
+ const compDir = path10.join(componentBaseDir, comp);
5912
6360
  if (!checkFileExists(compDir)) {
5913
6361
  missing.push(comp);
5914
6362
  }
5915
6363
  }
5916
6364
  if (missing.length > 0) {
5917
6365
  console.log();
5918
- console.log(chalk7.yellow(" Missing peer components:"));
6366
+ console.log(chalk8.yellow(" Missing peer components:"));
5919
6367
  for (const comp of missing) {
5920
- console.log(chalk7.dim(` ${comp} \u2192 run: ${chalk7.cyan(`pdfx add ${comp}`)}`));
6368
+ console.log(chalk8.dim(` ${comp} \u2192 run: ${chalk8.cyan(`pdfx add ${comp}`)}`));
5921
6369
  }
5922
6370
  }
5923
6371
  }
5924
6372
  if (config.theme) {
5925
- const absThemePath = path9.resolve(process.cwd(), config.theme);
5926
- const contextPath = path9.join(path9.dirname(absThemePath), "pdfx-theme-context.tsx");
6373
+ const absThemePath = path10.resolve(process.cwd(), config.theme);
6374
+ const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
5927
6375
  if (!checkFileExists(contextPath)) {
5928
- ensureDir(path9.dirname(contextPath));
6376
+ ensureDir(path10.dirname(contextPath));
5929
6377
  writeFile(contextPath, generateThemeContextFile());
5930
6378
  }
5931
6379
  }
5932
6380
  return peerResult;
5933
6381
  }
5934
6382
  async function templateAdd(names, options = {}) {
5935
- const configPath = path9.join(process.cwd(), "pdfx.json");
6383
+ const configPath = path10.join(process.cwd(), "pdfx.json");
5936
6384
  if (!checkFileExists(configPath)) {
5937
- console.error(chalk7.red("Error: pdfx.json not found"));
5938
- console.log(chalk7.yellow("Run: pdfx init"));
6385
+ console.error(chalk8.red("Error: pdfx.json not found"));
6386
+ console.log(chalk8.yellow("Run: pdfx init"));
5939
6387
  process.exit(1);
5940
6388
  }
5941
6389
  let config;
5942
6390
  try {
5943
- config = readConfig2(configPath);
6391
+ config = readConfig3(configPath);
5944
6392
  } catch (error) {
5945
6393
  if (error instanceof ConfigError) {
5946
- console.error(chalk7.red(error.message));
5947
- if (error.suggestion) console.log(chalk7.yellow(` Hint: ${error.suggestion}`));
6394
+ console.error(chalk8.red(error.message));
6395
+ if (error.suggestion) console.log(chalk8.yellow(` Hint: ${error.suggestion}`));
5948
6396
  } else {
5949
6397
  const message = error instanceof Error ? error.message : String(error);
5950
- console.error(chalk7.red(message));
6398
+ console.error(chalk8.red(message));
5951
6399
  }
5952
6400
  process.exit(1);
5953
6401
  }
@@ -5956,24 +6404,24 @@ async function templateAdd(names, options = {}) {
5956
6404
  for (const templateName of names) {
5957
6405
  const nameResult = componentNameSchema.safeParse(templateName);
5958
6406
  if (!nameResult.success) {
5959
- console.error(chalk7.red(`Invalid template name: "${templateName}"`));
6407
+ console.error(chalk8.red(`Invalid template name: "${templateName}"`));
5960
6408
  console.log(
5961
- chalk7.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
6409
+ chalk8.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
5962
6410
  );
5963
6411
  failed.push(templateName);
5964
6412
  continue;
5965
6413
  }
5966
- const spinner = ora6(`Adding template ${templateName}...`).start();
6414
+ const spinner = ora7(`Adding template ${templateName}...`).start();
5967
6415
  try {
5968
6416
  const result = await installTemplate(templateName, config, force);
5969
- spinner.succeed(`Added template ${chalk7.cyan(templateName)}`);
6417
+ spinner.succeed(`Added template ${chalk8.cyan(templateName)}`);
5970
6418
  if (result.installedPeers.length > 0) {
5971
6419
  console.log(
5972
- chalk7.green(` Installed required components: ${result.installedPeers.join(", ")}`)
6420
+ chalk8.green(` Installed required components: ${result.installedPeers.join(", ")}`)
5973
6421
  );
5974
6422
  }
5975
6423
  for (const warning of result.peerWarnings) {
5976
- console.log(chalk7.yellow(` Warning: ${warning}`));
6424
+ console.log(chalk8.yellow(` Warning: ${warning}`));
5977
6425
  }
5978
6426
  } catch (error) {
5979
6427
  if (error instanceof ValidationError && error.message.includes("Cancelled")) {
@@ -5982,24 +6430,24 @@ async function templateAdd(names, options = {}) {
5982
6430
  } else if (error instanceof NetworkError || error instanceof RegistryError || error instanceof ValidationError) {
5983
6431
  spinner.fail(error.message);
5984
6432
  if (error.suggestion) {
5985
- console.log(chalk7.dim(` Hint: ${error.suggestion}`));
6433
+ console.log(chalk8.dim(` Hint: ${error.suggestion}`));
5986
6434
  }
5987
6435
  } else {
5988
6436
  spinner.fail(`Failed to add template ${templateName}`);
5989
6437
  const message = error instanceof Error ? error.message : String(error);
5990
- console.error(chalk7.dim(` ${message}`));
6438
+ console.error(chalk8.dim(` ${message}`));
5991
6439
  }
5992
6440
  failed.push(templateName);
5993
6441
  }
5994
6442
  }
5995
6443
  console.log();
5996
6444
  if (failed.length > 0) {
5997
- console.log(chalk7.yellow(`Failed: ${failed.join(", ")}`));
6445
+ console.log(chalk8.yellow(`Failed: ${failed.join(", ")}`));
5998
6446
  }
5999
6447
  if (failed.length < names.length) {
6000
- const resolvedDir = path9.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
6001
- console.log(chalk7.green("Done!"));
6002
- console.log(chalk7.dim(`Templates installed to: ${resolvedDir}
6448
+ const resolvedDir = path10.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
6449
+ console.log(chalk8.green("Done!"));
6450
+ console.log(chalk8.dim(`Templates installed to: ${resolvedDir}
6003
6451
  `));
6004
6452
  }
6005
6453
  if (failed.length > 0) {
@@ -6007,20 +6455,20 @@ async function templateAdd(names, options = {}) {
6007
6455
  }
6008
6456
  }
6009
6457
  async function templateList() {
6010
- const configPath = path9.join(process.cwd(), "pdfx.json");
6458
+ const configPath = path10.join(process.cwd(), "pdfx.json");
6011
6459
  if (!checkFileExists(configPath)) {
6012
- console.error(chalk7.red("Error: pdfx.json not found"));
6013
- console.log(chalk7.yellow("Run: pdfx init"));
6460
+ console.error(chalk8.red("Error: pdfx.json not found"));
6461
+ console.log(chalk8.yellow("Run: pdfx init"));
6014
6462
  process.exit(1);
6015
6463
  }
6016
6464
  const raw = readJsonFile(configPath);
6017
6465
  const configResult = configSchema.safeParse(raw);
6018
6466
  if (!configResult.success) {
6019
- console.error(chalk7.red("Invalid pdfx.json"));
6467
+ console.error(chalk8.red("Invalid pdfx.json"));
6020
6468
  process.exit(1);
6021
6469
  }
6022
6470
  const config = configResult.data;
6023
- const spinner = ora6("Fetching template list...").start();
6471
+ const spinner = ora7("Fetching template list...").start();
6024
6472
  try {
6025
6473
  let response;
6026
6474
  try {
@@ -6044,28 +6492,28 @@ async function templateList() {
6044
6492
  spinner.stop();
6045
6493
  const templates = result.data.items.filter((item) => item.type === "registry:template");
6046
6494
  if (templates.length === 0) {
6047
- console.log(chalk7.dim("\n No templates available in the registry.\n"));
6495
+ console.log(chalk8.dim("\n No templates available in the registry.\n"));
6048
6496
  return;
6049
6497
  }
6050
- const templateBaseDir = path9.resolve(
6498
+ const templateBaseDir = path10.resolve(
6051
6499
  process.cwd(),
6052
6500
  config.templateDir ?? DEFAULTS.TEMPLATE_DIR
6053
6501
  );
6054
- console.log(chalk7.bold(`
6502
+ console.log(chalk8.bold(`
6055
6503
  Available Templates (${templates.length})
6056
6504
  `));
6057
6505
  for (const item of templates) {
6058
- const templateDir = path9.join(templateBaseDir, item.name);
6506
+ const templateDir = path10.join(templateBaseDir, item.name);
6059
6507
  const installed = checkFileExists(templateDir);
6060
- const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
6061
- console.log(` ${chalk7.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6508
+ const status = installed ? chalk8.green("[installed]") : chalk8.dim("[not installed]");
6509
+ console.log(` ${chalk8.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
6062
6510
  console.log(` ${"".padEnd(22)} ${status}`);
6063
6511
  if (item.peerComponents && item.peerComponents.length > 0) {
6064
- console.log(chalk7.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
6512
+ console.log(chalk8.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
6065
6513
  }
6066
6514
  console.log();
6067
6515
  }
6068
- console.log(chalk7.dim(` Install with: ${chalk7.cyan("pdfx template add <template-name>")}
6516
+ console.log(chalk8.dim(` Install with: ${chalk8.cyan("pdfx template add <template-name>")}
6069
6517
  `));
6070
6518
  } catch (error) {
6071
6519
  const message = error instanceof Error ? error.message : String(error);
@@ -6076,22 +6524,22 @@ async function templateList() {
6076
6524
 
6077
6525
  // src/commands/theme.ts
6078
6526
  import fs8 from "fs";
6079
- import path10 from "path";
6080
- import chalk8 from "chalk";
6081
- import ora7 from "ora";
6082
- import prompts5 from "prompts";
6527
+ import path11 from "path";
6528
+ import chalk9 from "chalk";
6529
+ import ora8 from "ora";
6530
+ import prompts6 from "prompts";
6083
6531
  import ts from "typescript";
6084
6532
  async function themeInit() {
6085
- const configPath = path10.join(process.cwd(), "pdfx.json");
6533
+ const configPath = path11.join(process.cwd(), "pdfx.json");
6086
6534
  if (!fs8.existsSync(configPath)) {
6087
- console.error(chalk8.red("\nError: pdfx.json not found"));
6088
- console.log(chalk8.yellow("\n PDFx is not initialized in this project.\n"));
6089
- console.log(chalk8.cyan(" Run: pdfx init"));
6090
- console.log(chalk8.dim(" This will set up your project configuration and theme.\n"));
6535
+ console.error(chalk9.red("\nError: pdfx.json not found"));
6536
+ console.log(chalk9.yellow("\n PDFx is not initialized in this project.\n"));
6537
+ console.log(chalk9.cyan(" Run: pdfx init"));
6538
+ console.log(chalk9.dim(" This will set up your project configuration and theme.\n"));
6091
6539
  process.exit(1);
6092
6540
  }
6093
- console.log(chalk8.bold.cyan("\n PDFx Theme Setup\n"));
6094
- const answers = await prompts5(
6541
+ console.log(chalk9.bold.cyan("\n PDFx Theme Setup\n"));
6542
+ const answers = await prompts6(
6095
6543
  [
6096
6544
  {
6097
6545
  type: "select",
@@ -6125,27 +6573,27 @@ async function themeInit() {
6125
6573
  ],
6126
6574
  {
6127
6575
  onCancel: () => {
6128
- console.log(chalk8.yellow("\nTheme setup cancelled."));
6576
+ console.log(chalk9.yellow("\nTheme setup cancelled."));
6129
6577
  process.exit(0);
6130
6578
  }
6131
6579
  }
6132
6580
  );
6133
6581
  if (!answers.preset || !answers.themePath) {
6134
- console.error(chalk8.red("Missing required fields."));
6582
+ console.error(chalk9.red("Missing required fields."));
6135
6583
  process.exit(1);
6136
6584
  }
6137
6585
  const presetName = answers.preset;
6138
6586
  const themePath = answers.themePath;
6139
6587
  const preset = themePresets[presetName];
6140
- const spinner = ora7(`Scaffolding ${presetName} theme...`).start();
6588
+ const spinner = ora8(`Scaffolding ${presetName} theme...`).start();
6141
6589
  try {
6142
- const absThemePath = path10.resolve(process.cwd(), themePath);
6143
- ensureDir(path10.dirname(absThemePath));
6590
+ const absThemePath = path11.resolve(process.cwd(), themePath);
6591
+ ensureDir(path11.dirname(absThemePath));
6144
6592
  fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
6145
- const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
6593
+ const contextPath = path11.join(path11.dirname(absThemePath), "pdfx-theme-context.tsx");
6146
6594
  fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
6147
6595
  spinner.succeed(`Created ${themePath} with ${presetName} theme`);
6148
- const configPath2 = path10.join(process.cwd(), "pdfx.json");
6596
+ const configPath2 = path11.join(process.cwd(), "pdfx.json");
6149
6597
  if (fs8.existsSync(configPath2)) {
6150
6598
  try {
6151
6599
  const rawConfig = readJsonFile(configPath2);
@@ -6153,19 +6601,19 @@ async function themeInit() {
6153
6601
  if (result.success) {
6154
6602
  const updatedConfig = { ...result.data, theme: themePath };
6155
6603
  fs8.writeFileSync(configPath2, JSON.stringify(updatedConfig, null, 2), "utf-8");
6156
- console.log(chalk8.green(" Updated pdfx.json with theme path"));
6604
+ console.log(chalk9.green(" Updated pdfx.json with theme path"));
6157
6605
  }
6158
6606
  } catch {
6159
- console.log(chalk8.yellow(' Could not update pdfx.json \u2014 add "theme" field manually'));
6607
+ console.log(chalk9.yellow(' Could not update pdfx.json \u2014 add "theme" field manually'));
6160
6608
  }
6161
6609
  }
6162
- console.log(chalk8.dim(`
6610
+ console.log(chalk9.dim(`
6163
6611
  Edit ${themePath} to customize your theme.
6164
6612
  `));
6165
6613
  } catch (error) {
6166
6614
  spinner.fail("Failed to create theme file");
6167
6615
  const message = error instanceof Error ? error.message : String(error);
6168
- console.error(chalk8.dim(` ${message}`));
6616
+ console.error(chalk9.dim(` ${message}`));
6169
6617
  process.exit(1);
6170
6618
  }
6171
6619
  }
@@ -6173,56 +6621,56 @@ async function themeSwitch(presetName) {
6173
6621
  const resolvedPreset = presetName === "default" ? "professional" : presetName;
6174
6622
  const validPresets = Object.keys(themePresets);
6175
6623
  if (!validPresets.includes(resolvedPreset)) {
6176
- console.error(chalk8.red(`\u2716 Invalid theme preset: "${presetName}"`));
6177
- console.log(chalk8.dim(` Available presets: ${validPresets.join(", ")}, default
6624
+ console.error(chalk9.red(`\u2716 Invalid theme preset: "${presetName}"`));
6625
+ console.log(chalk9.dim(` Available presets: ${validPresets.join(", ")}, default
6178
6626
  `));
6179
- console.log(chalk8.dim(" Usage: pdfx theme switch <preset>"));
6627
+ console.log(chalk9.dim(" Usage: pdfx theme switch <preset>"));
6180
6628
  process.exit(1);
6181
6629
  }
6182
6630
  const validatedPreset = resolvedPreset;
6183
- const configPath = path10.join(process.cwd(), "pdfx.json");
6631
+ const configPath = path11.join(process.cwd(), "pdfx.json");
6184
6632
  if (!fs8.existsSync(configPath)) {
6185
- console.error(chalk8.red('No pdfx.json found. Run "pdfx init" first.'));
6633
+ console.error(chalk9.red('No pdfx.json found. Run "pdfx init" first.'));
6186
6634
  process.exit(1);
6187
6635
  }
6188
6636
  const rawConfig = readJsonFile(configPath);
6189
6637
  const result = configSchema.safeParse(rawConfig);
6190
6638
  if (!result.success) {
6191
- console.error(chalk8.red("Invalid pdfx.json configuration."));
6639
+ console.error(chalk9.red("Invalid pdfx.json configuration."));
6192
6640
  process.exit(1);
6193
6641
  }
6194
6642
  const config = result.data;
6195
6643
  if (!config.theme) {
6196
6644
  console.error(
6197
- chalk8.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6645
+ chalk9.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6198
6646
  );
6199
6647
  process.exit(1);
6200
6648
  }
6201
- const answer = await prompts5({
6649
+ const answer = await prompts6({
6202
6650
  type: "confirm",
6203
6651
  name: "confirm",
6204
6652
  message: `This will overwrite ${config.theme} with the ${validatedPreset} preset. Continue?`,
6205
6653
  initial: false
6206
6654
  });
6207
6655
  if (!answer.confirm) {
6208
- console.log(chalk8.yellow("Cancelled."));
6656
+ console.log(chalk9.yellow("Cancelled."));
6209
6657
  return;
6210
6658
  }
6211
- const spinner = ora7(`Switching to ${validatedPreset} theme...`).start();
6659
+ const spinner = ora8(`Switching to ${validatedPreset} theme...`).start();
6212
6660
  try {
6213
6661
  const preset = themePresets[validatedPreset];
6214
- const absThemePath = path10.resolve(process.cwd(), config.theme);
6662
+ const absThemePath = path11.resolve(process.cwd(), config.theme);
6215
6663
  fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
6216
- const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
6664
+ const contextPath = path11.join(path11.dirname(absThemePath), "pdfx-theme-context.tsx");
6217
6665
  if (!fs8.existsSync(contextPath)) {
6218
- ensureDir(path10.dirname(contextPath));
6666
+ ensureDir(path11.dirname(contextPath));
6219
6667
  fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
6220
6668
  }
6221
6669
  spinner.succeed(`Switched to ${validatedPreset} theme`);
6222
6670
  } catch (error) {
6223
6671
  spinner.fail("Failed to switch theme");
6224
6672
  const message = error instanceof Error ? error.message : String(error);
6225
- console.error(chalk8.dim(` ${message}`));
6673
+ console.error(chalk9.dim(` ${message}`));
6226
6674
  process.exit(1);
6227
6675
  }
6228
6676
  }
@@ -6290,48 +6738,48 @@ function parseThemeObject(themePath) {
6290
6738
  throw new Error("No exported `theme` object found.");
6291
6739
  }
6292
6740
  async function themeValidate() {
6293
- const configPath = path10.join(process.cwd(), "pdfx.json");
6741
+ const configPath = path11.join(process.cwd(), "pdfx.json");
6294
6742
  if (!fs8.existsSync(configPath)) {
6295
- console.error(chalk8.red('No pdfx.json found. Run "pdfx init" first.'));
6743
+ console.error(chalk9.red('No pdfx.json found. Run "pdfx init" first.'));
6296
6744
  process.exit(1);
6297
6745
  }
6298
6746
  const rawConfig = readJsonFile(configPath);
6299
6747
  const configResult = configSchema.safeParse(rawConfig);
6300
6748
  if (!configResult.success) {
6301
- console.error(chalk8.red("Invalid pdfx.json configuration."));
6749
+ console.error(chalk9.red("Invalid pdfx.json configuration."));
6302
6750
  process.exit(1);
6303
6751
  }
6304
6752
  if (!configResult.data.theme) {
6305
6753
  console.error(
6306
- chalk8.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6754
+ chalk9.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
6307
6755
  );
6308
6756
  process.exit(1);
6309
6757
  }
6310
- const absThemePath = path10.resolve(process.cwd(), configResult.data.theme);
6758
+ const absThemePath = path11.resolve(process.cwd(), configResult.data.theme);
6311
6759
  if (!fs8.existsSync(absThemePath)) {
6312
- console.error(chalk8.red(`Theme file not found: ${configResult.data.theme}`));
6760
+ console.error(chalk9.red(`Theme file not found: ${configResult.data.theme}`));
6313
6761
  process.exit(1);
6314
6762
  }
6315
- const spinner = ora7("Validating theme file...").start();
6763
+ const spinner = ora8("Validating theme file...").start();
6316
6764
  try {
6317
6765
  const parsedTheme = parseThemeObject(absThemePath);
6318
6766
  const result = themeSchema.safeParse(parsedTheme);
6319
6767
  if (!result.success) {
6320
- const issues = result.error.issues.map((issue) => ` \u2192 ${chalk8.yellow(issue.path.join("."))}: ${issue.message}`).join("\n");
6768
+ const issues = result.error.issues.map((issue) => ` \u2192 ${chalk9.yellow(issue.path.join("."))}: ${issue.message}`).join("\n");
6321
6769
  spinner.fail("Theme validation failed");
6322
- console.log(chalk8.red("\n Missing or invalid fields:\n"));
6770
+ console.log(chalk9.red("\n Missing or invalid fields:\n"));
6323
6771
  console.log(issues);
6324
- console.log(chalk8.dim("\n Fix these fields in your theme file and run validate again.\n"));
6772
+ console.log(chalk9.dim("\n Fix these fields in your theme file and run validate again.\n"));
6325
6773
  process.exit(1);
6326
6774
  }
6327
6775
  spinner.succeed("Theme file is valid");
6328
- console.log(chalk8.dim(`
6776
+ console.log(chalk9.dim(`
6329
6777
  Validated: ${configResult.data.theme}
6330
6778
  `));
6331
6779
  } catch (error) {
6332
6780
  spinner.fail("Failed to validate theme");
6333
6781
  const message = error instanceof Error ? error.message : String(error);
6334
- console.error(chalk8.dim(` ${message}`));
6782
+ console.error(chalk9.dim(` ${message}`));
6335
6783
  process.exit(1);
6336
6784
  }
6337
6785
  }
@@ -6361,4 +6809,7 @@ themeCmd.command("validate").description("Validate your theme file").action(them
6361
6809
  var templateCmd = program.command("template").description("Manage PDF templates");
6362
6810
  templateCmd.command("add <templates...>").description("Add a template to your project").option("-f, --force", "Overwrite existing files without prompting").action((templates, options) => templateAdd(templates, options));
6363
6811
  templateCmd.command("list").description("List available templates from registry").action(templateList);
6812
+ var blockCmd = program.command("block").description("Manage PDF blocks (copy-paste designs)");
6813
+ blockCmd.command("add <blocks...>").description("Add a block to your project").option("-f, --force", "Overwrite existing files without prompting").action((blocks, options) => blockAdd(blocks, options));
6814
+ blockCmd.command("list").description("List available blocks from registry").action(blockList);
6364
6815
  program.parse();