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