@akii09/pdfx-cli 0.1.3 → 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 +792 -275
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6,6 +6,9 @@ var __export = (target, all) => {
|
|
|
6
6
|
};
|
|
7
7
|
|
|
8
8
|
// src/index.ts
|
|
9
|
+
import { readFileSync } from "fs";
|
|
10
|
+
import { join } from "path";
|
|
11
|
+
import { fileURLToPath } from "url";
|
|
9
12
|
import { Command } from "commander";
|
|
10
13
|
|
|
11
14
|
// src/commands/add.ts
|
|
@@ -489,8 +492,8 @@ function getErrorMap() {
|
|
|
489
492
|
|
|
490
493
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/helpers/parseUtil.js
|
|
491
494
|
var makeIssue = (params) => {
|
|
492
|
-
const { data, path:
|
|
493
|
-
const fullPath = [...
|
|
495
|
+
const { data, path: path12, errorMaps, issueData } = params;
|
|
496
|
+
const fullPath = [...path12, ...issueData.path || []];
|
|
494
497
|
const fullIssue = {
|
|
495
498
|
...issueData,
|
|
496
499
|
path: fullPath
|
|
@@ -606,11 +609,11 @@ var errorUtil;
|
|
|
606
609
|
|
|
607
610
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/types.js
|
|
608
611
|
var ParseInputLazyPath = class {
|
|
609
|
-
constructor(parent, value,
|
|
612
|
+
constructor(parent, value, path12, key) {
|
|
610
613
|
this._cachedPath = [];
|
|
611
614
|
this.parent = parent;
|
|
612
615
|
this.data = value;
|
|
613
|
-
this._path =
|
|
616
|
+
this._path = path12;
|
|
614
617
|
this._key = key;
|
|
615
618
|
}
|
|
616
619
|
get path() {
|
|
@@ -989,11 +992,11 @@ function datetimeRegex(args) {
|
|
|
989
992
|
regex = `${regex}(${opts.join("|")})`;
|
|
990
993
|
return new RegExp(`^${regex}$`);
|
|
991
994
|
}
|
|
992
|
-
function isValidIP(ip,
|
|
993
|
-
if ((
|
|
995
|
+
function isValidIP(ip, version2) {
|
|
996
|
+
if ((version2 === "v4" || !version2) && ipv4Regex.test(ip)) {
|
|
994
997
|
return true;
|
|
995
998
|
}
|
|
996
|
-
if ((
|
|
999
|
+
if ((version2 === "v6" || !version2) && ipv6Regex.test(ip)) {
|
|
997
1000
|
return true;
|
|
998
1001
|
}
|
|
999
1002
|
return false;
|
|
@@ -1020,11 +1023,11 @@ function isValidJWT(jwt, alg) {
|
|
|
1020
1023
|
return false;
|
|
1021
1024
|
}
|
|
1022
1025
|
}
|
|
1023
|
-
function isValidCidr(ip,
|
|
1024
|
-
if ((
|
|
1026
|
+
function isValidCidr(ip, version2) {
|
|
1027
|
+
if ((version2 === "v4" || !version2) && ipv4CidrRegex.test(ip)) {
|
|
1025
1028
|
return true;
|
|
1026
1029
|
}
|
|
1027
|
-
if ((
|
|
1030
|
+
if ((version2 === "v6" || !version2) && ipv6CidrRegex.test(ip)) {
|
|
1028
1031
|
return true;
|
|
1029
1032
|
}
|
|
1030
1033
|
return false;
|
|
@@ -4151,7 +4154,8 @@ var registryFileTypes = [
|
|
|
4151
4154
|
"registry:component",
|
|
4152
4155
|
"registry:lib",
|
|
4153
4156
|
"registry:style",
|
|
4154
|
-
"registry:template"
|
|
4157
|
+
"registry:template",
|
|
4158
|
+
"registry:block"
|
|
4155
4159
|
];
|
|
4156
4160
|
var registryFileSchema = external_exports.object({
|
|
4157
4161
|
path: external_exports.string().min(1),
|
|
@@ -4498,14 +4502,14 @@ function getInstalledVersion(packageName, cwd = process.cwd()) {
|
|
|
4498
4502
|
...pkg.dependencies,
|
|
4499
4503
|
...pkg.devDependencies
|
|
4500
4504
|
};
|
|
4501
|
-
const
|
|
4502
|
-
if (!
|
|
4503
|
-
return semver.clean(
|
|
4505
|
+
const version2 = deps[packageName];
|
|
4506
|
+
if (!version2) return null;
|
|
4507
|
+
return semver.clean(version2) || semver.coerce(version2)?.version || null;
|
|
4504
4508
|
}
|
|
4505
4509
|
function validateReactPdfRenderer(cwd = process.cwd()) {
|
|
4506
|
-
const
|
|
4510
|
+
const version2 = getInstalledVersion("@react-pdf/renderer", cwd);
|
|
4507
4511
|
const required = REQUIRED_VERSIONS["@react-pdf/renderer"];
|
|
4508
|
-
if (!
|
|
4512
|
+
if (!version2) {
|
|
4509
4513
|
return {
|
|
4510
4514
|
valid: false,
|
|
4511
4515
|
installed: false,
|
|
@@ -4513,19 +4517,19 @@ function validateReactPdfRenderer(cwd = process.cwd()) {
|
|
|
4513
4517
|
message: "@react-pdf/renderer is not installed"
|
|
4514
4518
|
};
|
|
4515
4519
|
}
|
|
4516
|
-
const isCompatible = semver.satisfies(
|
|
4520
|
+
const isCompatible = semver.satisfies(version2, required);
|
|
4517
4521
|
return {
|
|
4518
4522
|
valid: isCompatible,
|
|
4519
4523
|
installed: true,
|
|
4520
|
-
currentVersion:
|
|
4524
|
+
currentVersion: version2,
|
|
4521
4525
|
requiredVersion: required,
|
|
4522
|
-
message: isCompatible ? "@react-pdf/renderer version is compatible" : `@react-pdf/renderer version ${
|
|
4526
|
+
message: isCompatible ? "@react-pdf/renderer version is compatible" : `@react-pdf/renderer version ${version2} does not meet requirement ${required}`
|
|
4523
4527
|
};
|
|
4524
4528
|
}
|
|
4525
4529
|
function validateReact(cwd = process.cwd()) {
|
|
4526
|
-
const
|
|
4530
|
+
const version2 = getInstalledVersion("react", cwd);
|
|
4527
4531
|
const required = REQUIRED_VERSIONS.react;
|
|
4528
|
-
if (!
|
|
4532
|
+
if (!version2) {
|
|
4529
4533
|
return {
|
|
4530
4534
|
valid: false,
|
|
4531
4535
|
installed: false,
|
|
@@ -4533,26 +4537,26 @@ function validateReact(cwd = process.cwd()) {
|
|
|
4533
4537
|
message: "React is not installed"
|
|
4534
4538
|
};
|
|
4535
4539
|
}
|
|
4536
|
-
const isCompatible = semver.satisfies(
|
|
4540
|
+
const isCompatible = semver.satisfies(version2, required);
|
|
4537
4541
|
return {
|
|
4538
4542
|
valid: isCompatible,
|
|
4539
4543
|
installed: true,
|
|
4540
|
-
currentVersion:
|
|
4544
|
+
currentVersion: version2,
|
|
4541
4545
|
requiredVersion: required,
|
|
4542
|
-
message: isCompatible ? "React version is compatible" : `React version ${
|
|
4546
|
+
message: isCompatible ? "React version is compatible" : `React version ${version2} does not meet requirement ${required}`
|
|
4543
4547
|
};
|
|
4544
4548
|
}
|
|
4545
4549
|
function validateNodeVersion() {
|
|
4546
|
-
const
|
|
4550
|
+
const version2 = process.version;
|
|
4547
4551
|
const required = REQUIRED_VERSIONS.node;
|
|
4548
|
-
const cleanVersion = semver.clean(
|
|
4552
|
+
const cleanVersion = semver.clean(version2);
|
|
4549
4553
|
if (!cleanVersion) {
|
|
4550
4554
|
return {
|
|
4551
4555
|
valid: false,
|
|
4552
4556
|
installed: true,
|
|
4553
|
-
currentVersion:
|
|
4557
|
+
currentVersion: version2,
|
|
4554
4558
|
requiredVersion: required,
|
|
4555
|
-
message: `Unable to parse Node.js version: ${
|
|
4559
|
+
message: `Unable to parse Node.js version: ${version2}`
|
|
4556
4560
|
};
|
|
4557
4561
|
}
|
|
4558
4562
|
const isCompatible = semver.satisfies(cleanVersion, required);
|
|
@@ -4901,7 +4905,9 @@ async function fetchComponent(name, registryUrl) {
|
|
|
4901
4905
|
} catch (err) {
|
|
4902
4906
|
const isTimeout = err instanceof Error && err.name === "TimeoutError";
|
|
4903
4907
|
throw new NetworkError(
|
|
4904
|
-
isTimeout ?
|
|
4908
|
+
isTimeout ? `Registry request timed out after 10 seconds.
|
|
4909
|
+
${chalk.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${registryUrl}
|
|
4910
|
+
${chalk.dim("Verify the URL is correct and you have internet access.")}`
|
|
4905
4911
|
);
|
|
4906
4912
|
}
|
|
4907
4913
|
if (!response.ok) {
|
|
@@ -4991,6 +4997,12 @@ async function installComponent(name, config, force) {
|
|
|
4991
4997
|
return;
|
|
4992
4998
|
}
|
|
4993
4999
|
async function add(components, options = {}) {
|
|
5000
|
+
if (!components || components.length === 0) {
|
|
5001
|
+
console.error(chalk.red("Error: Component name required"));
|
|
5002
|
+
console.log(chalk.dim("Usage: pdfx add <component...>"));
|
|
5003
|
+
console.log(chalk.dim("Example: pdfx add heading text table\n"));
|
|
5004
|
+
process.exit(1);
|
|
5005
|
+
}
|
|
4994
5006
|
const reactPdfCheck = validateReactPdfRenderer();
|
|
4995
5007
|
if (!reactPdfCheck.installed) {
|
|
4996
5008
|
console.error(chalk.red("\nError: @react-pdf/renderer is not installed\n"));
|
|
@@ -5018,6 +5030,9 @@ async function add(components, options = {}) {
|
|
|
5018
5030
|
let config;
|
|
5019
5031
|
try {
|
|
5020
5032
|
config = readConfig(configPath);
|
|
5033
|
+
if (options.registry) {
|
|
5034
|
+
config = { ...config, registry: options.registry };
|
|
5035
|
+
}
|
|
5021
5036
|
} catch (error) {
|
|
5022
5037
|
if (error instanceof ConfigError) {
|
|
5023
5038
|
console.error(chalk.red(error.message));
|
|
@@ -5075,13 +5090,338 @@ async function add(components, options = {}) {
|
|
|
5075
5090
|
}
|
|
5076
5091
|
}
|
|
5077
5092
|
|
|
5078
|
-
// src/commands/
|
|
5079
|
-
import fs4 from "fs";
|
|
5093
|
+
// src/commands/block.ts
|
|
5080
5094
|
import path4 from "path";
|
|
5081
5095
|
import chalk2 from "chalk";
|
|
5082
5096
|
import ora2 from "ora";
|
|
5083
|
-
|
|
5084
|
-
|
|
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() {
|
|
5085
5425
|
const configPath = path4.join(process.cwd(), "pdfx.json");
|
|
5086
5426
|
if (!checkFileExists(configPath)) {
|
|
5087
5427
|
console.error(chalk2.red("Error: pdfx.json not found"));
|
|
@@ -5095,14 +5435,85 @@ async function diff(components) {
|
|
|
5095
5435
|
process.exit(1);
|
|
5096
5436
|
}
|
|
5097
5437
|
const config = configResult.data;
|
|
5098
|
-
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);
|
|
5099
5510
|
for (const componentName of components) {
|
|
5100
5511
|
const nameResult = componentNameSchema.safeParse(componentName);
|
|
5101
5512
|
if (!nameResult.success) {
|
|
5102
|
-
console.error(
|
|
5513
|
+
console.error(chalk3.red(`Invalid component name: "${componentName}"`));
|
|
5103
5514
|
continue;
|
|
5104
5515
|
}
|
|
5105
|
-
const spinner =
|
|
5516
|
+
const spinner = ora3(`Comparing ${componentName}...`).start();
|
|
5106
5517
|
try {
|
|
5107
5518
|
let response;
|
|
5108
5519
|
try {
|
|
@@ -5112,7 +5523,9 @@ async function diff(components) {
|
|
|
5112
5523
|
} catch (err) {
|
|
5113
5524
|
const isTimeout = err instanceof Error && err.name === "TimeoutError";
|
|
5114
5525
|
throw new NetworkError(
|
|
5115
|
-
isTimeout ?
|
|
5526
|
+
isTimeout ? `Registry request timed out after 10 seconds.
|
|
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.")}`
|
|
5116
5529
|
);
|
|
5117
5530
|
}
|
|
5118
5531
|
if (!response.ok) {
|
|
@@ -5127,28 +5540,33 @@ async function diff(components) {
|
|
|
5127
5540
|
}
|
|
5128
5541
|
const component = result.data;
|
|
5129
5542
|
spinner.stop();
|
|
5130
|
-
const componentSubDir =
|
|
5543
|
+
const componentSubDir = path5.join(targetDir, component.name);
|
|
5131
5544
|
for (const file of component.files) {
|
|
5132
|
-
const fileName =
|
|
5545
|
+
const fileName = path5.basename(file.path);
|
|
5133
5546
|
const localPath = safePath(componentSubDir, fileName);
|
|
5134
5547
|
if (!checkFileExists(localPath)) {
|
|
5135
|
-
console.log(
|
|
5548
|
+
console.log(chalk3.yellow(` ${fileName}: not installed locally`));
|
|
5136
5549
|
continue;
|
|
5137
5550
|
}
|
|
5138
5551
|
const localContent = fs4.readFileSync(localPath, "utf-8");
|
|
5139
5552
|
const registryContent = config.theme && (file.content.includes("pdfx-theme") || file.content.includes("pdfx-theme-context")) ? resolveThemeImport(
|
|
5140
|
-
|
|
5553
|
+
path5.join(config.componentDir, component.name),
|
|
5141
5554
|
config.theme,
|
|
5142
5555
|
file.content
|
|
5143
5556
|
) : file.content;
|
|
5144
5557
|
if (localContent === registryContent) {
|
|
5145
|
-
console.log(
|
|
5558
|
+
console.log(chalk3.green(` ${fileName}: up to date`));
|
|
5146
5559
|
} else {
|
|
5147
|
-
console.log(
|
|
5560
|
+
console.log(chalk3.yellow(` ${fileName}: differs from registry`));
|
|
5148
5561
|
const localLines = localContent.split("\n");
|
|
5149
5562
|
const registryLines = registryContent.split("\n");
|
|
5150
|
-
|
|
5151
|
-
console.log(
|
|
5563
|
+
const lineDiff = localLines.length - registryLines.length;
|
|
5564
|
+
console.log(chalk3.dim(` Local: ${localLines.length} lines`));
|
|
5565
|
+
console.log(chalk3.dim(` Registry: ${registryLines.length} lines`));
|
|
5566
|
+
if (lineDiff !== 0) {
|
|
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`;
|
|
5568
|
+
console.log(chalk3.dim(` \u2192 ${diffText}`));
|
|
5569
|
+
}
|
|
5152
5570
|
}
|
|
5153
5571
|
}
|
|
5154
5572
|
console.log();
|
|
@@ -5161,32 +5579,20 @@ async function diff(components) {
|
|
|
5161
5579
|
|
|
5162
5580
|
// src/commands/init.ts
|
|
5163
5581
|
import fs7 from "fs";
|
|
5164
|
-
import
|
|
5165
|
-
import
|
|
5166
|
-
import
|
|
5167
|
-
import
|
|
5168
|
-
|
|
5169
|
-
// src/constants.ts
|
|
5170
|
-
var DEFAULTS = {
|
|
5171
|
-
REGISTRY_URL: "https://pdfx.akashpise.dev/r",
|
|
5172
|
-
SCHEMA_URL: "https://pdfx.akashpise.dev/schema.json",
|
|
5173
|
-
COMPONENT_DIR: "./src/components/pdfx",
|
|
5174
|
-
THEME_FILE: "./src/lib/pdfx-theme.ts",
|
|
5175
|
-
TEMPLATE_DIR: "./src/templates/pdfx"
|
|
5176
|
-
};
|
|
5177
|
-
var REGISTRY_SUBPATHS = {
|
|
5178
|
-
TEMPLATES: "templates"
|
|
5179
|
-
};
|
|
5582
|
+
import path8 from "path";
|
|
5583
|
+
import chalk6 from "chalk";
|
|
5584
|
+
import ora5 from "ora";
|
|
5585
|
+
import prompts4 from "prompts";
|
|
5180
5586
|
|
|
5181
5587
|
// src/utils/install-dependencies.ts
|
|
5182
|
-
import
|
|
5588
|
+
import chalk4 from "chalk";
|
|
5183
5589
|
import { execa } from "execa";
|
|
5184
|
-
import
|
|
5185
|
-
import
|
|
5590
|
+
import ora4 from "ora";
|
|
5591
|
+
import prompts3 from "prompts";
|
|
5186
5592
|
|
|
5187
5593
|
// src/utils/package-manager.ts
|
|
5188
5594
|
import fs5 from "fs";
|
|
5189
|
-
import
|
|
5595
|
+
import path6 from "path";
|
|
5190
5596
|
var PACKAGE_MANAGERS = {
|
|
5191
5597
|
pnpm: {
|
|
5192
5598
|
name: "pnpm",
|
|
@@ -5213,7 +5619,7 @@ function detectPackageManager(cwd = process.cwd()) {
|
|
|
5213
5619
|
const managers = ["pnpm", "yarn", "bun", "npm"];
|
|
5214
5620
|
for (const manager of managers) {
|
|
5215
5621
|
const info = PACKAGE_MANAGERS[manager];
|
|
5216
|
-
const lockfilePath =
|
|
5622
|
+
const lockfilePath = path6.join(cwd, info.lockfile);
|
|
5217
5623
|
if (fs5.existsSync(lockfilePath)) {
|
|
5218
5624
|
return info;
|
|
5219
5625
|
}
|
|
@@ -5237,10 +5643,10 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
|
|
|
5237
5643
|
const pm = detectPackageManager(cwd);
|
|
5238
5644
|
const packageName = "@react-pdf/renderer";
|
|
5239
5645
|
const installCmd = getInstallCommand(pm.name, [packageName]);
|
|
5240
|
-
console.log(
|
|
5241
|
-
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}
|
|
5242
5648
|
`));
|
|
5243
|
-
const { shouldInstall } = await
|
|
5649
|
+
const { shouldInstall } = await prompts3({
|
|
5244
5650
|
type: "confirm",
|
|
5245
5651
|
name: "shouldInstall",
|
|
5246
5652
|
message: "Install @react-pdf/renderer now?",
|
|
@@ -5250,10 +5656,10 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
|
|
|
5250
5656
|
return {
|
|
5251
5657
|
success: false,
|
|
5252
5658
|
message: `Installation cancelled. Please install manually:
|
|
5253
|
-
${
|
|
5659
|
+
${chalk4.cyan(installCmd)}`
|
|
5254
5660
|
};
|
|
5255
5661
|
}
|
|
5256
|
-
const spinner =
|
|
5662
|
+
const spinner = ora4("Installing @react-pdf/renderer...").start();
|
|
5257
5663
|
try {
|
|
5258
5664
|
await execa(pm.name, ["add", packageName], {
|
|
5259
5665
|
cwd,
|
|
@@ -5270,7 +5676,7 @@ async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
|
|
|
5270
5676
|
return {
|
|
5271
5677
|
success: false,
|
|
5272
5678
|
message: `Installation failed: ${message}
|
|
5273
|
-
Try manually: ${
|
|
5679
|
+
Try manually: ${chalk4.cyan(installCmd)}`
|
|
5274
5680
|
};
|
|
5275
5681
|
}
|
|
5276
5682
|
}
|
|
@@ -5278,7 +5684,7 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
|
|
|
5278
5684
|
if (!validation.installed) {
|
|
5279
5685
|
const result = await promptAndInstallReactPdf(validation, cwd);
|
|
5280
5686
|
if (!result.success) {
|
|
5281
|
-
console.error(
|
|
5687
|
+
console.error(chalk4.red(`
|
|
5282
5688
|
${result.message}
|
|
5283
5689
|
`));
|
|
5284
5690
|
return false;
|
|
@@ -5287,10 +5693,10 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
|
|
|
5287
5693
|
}
|
|
5288
5694
|
if (!validation.valid) {
|
|
5289
5695
|
console.log(
|
|
5290
|
-
|
|
5696
|
+
chalk4.yellow(
|
|
5291
5697
|
`
|
|
5292
5698
|
\u26A0 ${validation.message}
|
|
5293
|
-
${
|
|
5699
|
+
${chalk4.dim("\u2192")} You may encounter compatibility issues
|
|
5294
5700
|
`
|
|
5295
5701
|
)
|
|
5296
5702
|
);
|
|
@@ -5299,13 +5705,13 @@ async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
|
|
|
5299
5705
|
}
|
|
5300
5706
|
|
|
5301
5707
|
// src/utils/pre-flight.ts
|
|
5302
|
-
import
|
|
5708
|
+
import chalk5 from "chalk";
|
|
5303
5709
|
|
|
5304
5710
|
// src/utils/environment-validator.ts
|
|
5305
5711
|
import fs6 from "fs";
|
|
5306
|
-
import
|
|
5712
|
+
import path7 from "path";
|
|
5307
5713
|
function validatePackageJson(cwd = process.cwd()) {
|
|
5308
|
-
const pkgPath =
|
|
5714
|
+
const pkgPath = path7.join(cwd, "package.json");
|
|
5309
5715
|
const exists = fs6.existsSync(pkgPath);
|
|
5310
5716
|
return {
|
|
5311
5717
|
valid: exists,
|
|
@@ -5314,7 +5720,7 @@ function validatePackageJson(cwd = process.cwd()) {
|
|
|
5314
5720
|
};
|
|
5315
5721
|
}
|
|
5316
5722
|
function validateReactProject(cwd = process.cwd()) {
|
|
5317
|
-
const pkgPath =
|
|
5723
|
+
const pkgPath = path7.join(cwd, "package.json");
|
|
5318
5724
|
if (!fs6.existsSync(pkgPath)) {
|
|
5319
5725
|
return {
|
|
5320
5726
|
valid: false,
|
|
@@ -5341,7 +5747,7 @@ function validateReactProject(cwd = process.cwd()) {
|
|
|
5341
5747
|
}
|
|
5342
5748
|
}
|
|
5343
5749
|
function validatePdfxConfig(cwd = process.cwd()) {
|
|
5344
|
-
const configPath =
|
|
5750
|
+
const configPath = path7.join(cwd, "pdfx.json");
|
|
5345
5751
|
const exists = fs6.existsSync(configPath);
|
|
5346
5752
|
return {
|
|
5347
5753
|
valid: true,
|
|
@@ -5366,43 +5772,43 @@ function runPreFlightChecks(cwd = process.cwd()) {
|
|
|
5366
5772
|
if (!environment.hasPackageJson.valid) {
|
|
5367
5773
|
blockingErrors.push(
|
|
5368
5774
|
`${environment.hasPackageJson.message}
|
|
5369
|
-
${
|
|
5775
|
+
${chalk5.dim("\u2192")} ${environment.hasPackageJson.fixCommand}`
|
|
5370
5776
|
);
|
|
5371
|
-
}
|
|
5372
|
-
if (!environment.isReactProject.valid) {
|
|
5777
|
+
} else if (!environment.isReactProject.valid) {
|
|
5373
5778
|
blockingErrors.push(
|
|
5374
5779
|
`${environment.isReactProject.message}
|
|
5375
|
-
${
|
|
5780
|
+
${chalk5.dim("\u2192")} ${environment.isReactProject.fixCommand}`
|
|
5376
5781
|
);
|
|
5782
|
+
} else {
|
|
5783
|
+
if (!dependencies.react.valid && dependencies.react.installed) {
|
|
5784
|
+
warnings.push(
|
|
5785
|
+
`${dependencies.react.message}
|
|
5786
|
+
${chalk5.dim("\u2192")} Current: ${dependencies.react.currentVersion}, Required: ${dependencies.react.requiredVersion}`
|
|
5787
|
+
);
|
|
5788
|
+
} else if (!dependencies.react.installed) {
|
|
5789
|
+
blockingErrors.push(
|
|
5790
|
+
`${dependencies.react.message}
|
|
5791
|
+
${chalk5.dim("\u2192")} Install React: npm install react react-dom`
|
|
5792
|
+
);
|
|
5793
|
+
}
|
|
5377
5794
|
}
|
|
5378
5795
|
if (!dependencies.nodeJs.valid) {
|
|
5379
5796
|
blockingErrors.push(
|
|
5380
5797
|
`${dependencies.nodeJs.message}
|
|
5381
|
-
${
|
|
5382
|
-
${
|
|
5383
|
-
);
|
|
5384
|
-
}
|
|
5385
|
-
if (!dependencies.react.valid && dependencies.react.installed) {
|
|
5386
|
-
warnings.push(
|
|
5387
|
-
`${dependencies.react.message}
|
|
5388
|
-
${chalk4.dim("\u2192")} Current: ${dependencies.react.currentVersion}, Required: ${dependencies.react.requiredVersion}`
|
|
5389
|
-
);
|
|
5390
|
-
} else if (!dependencies.react.installed) {
|
|
5391
|
-
blockingErrors.push(
|
|
5392
|
-
`${dependencies.react.message}
|
|
5393
|
-
${chalk4.dim("\u2192")} This should have been caught by React project check`
|
|
5798
|
+
${chalk5.dim("\u2192")} Current: ${dependencies.nodeJs.currentVersion}, Required: ${dependencies.nodeJs.requiredVersion}
|
|
5799
|
+
${chalk5.dim("\u2192")} Visit https://nodejs.org to upgrade`
|
|
5394
5800
|
);
|
|
5395
5801
|
}
|
|
5396
5802
|
if (dependencies.reactPdfRenderer.installed && !dependencies.reactPdfRenderer.valid) {
|
|
5397
5803
|
warnings.push(
|
|
5398
5804
|
`${dependencies.reactPdfRenderer.message}
|
|
5399
|
-
${
|
|
5805
|
+
${chalk5.dim("\u2192")} Consider upgrading: npm install @react-pdf/renderer@latest`
|
|
5400
5806
|
);
|
|
5401
5807
|
}
|
|
5402
5808
|
if (dependencies.typescript && !dependencies.typescript.valid) {
|
|
5403
5809
|
warnings.push(
|
|
5404
5810
|
`${dependencies.typescript.message}
|
|
5405
|
-
${
|
|
5811
|
+
${chalk5.dim("\u2192")} Install types: npm install -D @types/react-pdf`
|
|
5406
5812
|
);
|
|
5407
5813
|
}
|
|
5408
5814
|
return {
|
|
@@ -5414,70 +5820,88 @@ function runPreFlightChecks(cwd = process.cwd()) {
|
|
|
5414
5820
|
};
|
|
5415
5821
|
}
|
|
5416
5822
|
function displayPreFlightResults(result) {
|
|
5417
|
-
console.log(
|
|
5823
|
+
console.log(chalk5.bold("\n Pre-flight Checks:\n"));
|
|
5418
5824
|
if (result.blockingErrors.length > 0) {
|
|
5419
|
-
console.log(
|
|
5825
|
+
console.log(chalk5.red(" \u2717 Blocking Issues:\n"));
|
|
5420
5826
|
for (const error of result.blockingErrors) {
|
|
5421
|
-
console.log(
|
|
5827
|
+
console.log(chalk5.red(` \u2022 ${error}
|
|
5422
5828
|
`));
|
|
5423
5829
|
}
|
|
5424
5830
|
}
|
|
5425
5831
|
if (result.warnings.length > 0) {
|
|
5426
|
-
console.log(
|
|
5832
|
+
console.log(chalk5.yellow(" \u26A0 Warnings:\n"));
|
|
5427
5833
|
for (const warning of result.warnings) {
|
|
5428
|
-
console.log(
|
|
5834
|
+
console.log(chalk5.yellow(` \u2022 ${warning}
|
|
5429
5835
|
`));
|
|
5430
5836
|
}
|
|
5431
5837
|
}
|
|
5432
5838
|
if (result.blockingErrors.length === 0 && result.warnings.length === 0) {
|
|
5433
|
-
console.log(
|
|
5839
|
+
console.log(chalk5.green(" \u2713 All checks passed!\n"));
|
|
5434
5840
|
}
|
|
5435
5841
|
}
|
|
5436
5842
|
|
|
5437
5843
|
// src/commands/init.ts
|
|
5438
5844
|
async function init() {
|
|
5439
|
-
console.log(
|
|
5845
|
+
console.log(chalk6.bold.cyan("\n Welcome to the pdfx cli\n"));
|
|
5440
5846
|
const preFlightResult = runPreFlightChecks();
|
|
5441
5847
|
displayPreFlightResults(preFlightResult);
|
|
5442
5848
|
if (!preFlightResult.canProceed) {
|
|
5443
5849
|
console.error(
|
|
5444
|
-
|
|
5850
|
+
chalk6.red("\n Cannot proceed due to blocking issues. Please fix them and try again.\n")
|
|
5445
5851
|
);
|
|
5446
5852
|
process.exit(1);
|
|
5447
5853
|
}
|
|
5448
5854
|
const hasReactPdf = await ensureReactPdfRenderer(preFlightResult.dependencies.reactPdfRenderer);
|
|
5449
5855
|
if (!hasReactPdf) {
|
|
5450
5856
|
console.error(
|
|
5451
|
-
|
|
5857
|
+
chalk6.red("\n @react-pdf/renderer is required. Please install it and try again.\n")
|
|
5452
5858
|
);
|
|
5453
5859
|
process.exit(1);
|
|
5454
5860
|
}
|
|
5455
|
-
const existingConfig =
|
|
5861
|
+
const existingConfig = path8.join(process.cwd(), "pdfx.json");
|
|
5456
5862
|
if (fs7.existsSync(existingConfig)) {
|
|
5457
|
-
const { overwrite } = await
|
|
5863
|
+
const { overwrite } = await prompts4({
|
|
5458
5864
|
type: "confirm",
|
|
5459
5865
|
name: "overwrite",
|
|
5460
5866
|
message: "pdfx.json already exists. Overwrite?",
|
|
5461
5867
|
initial: false
|
|
5462
5868
|
});
|
|
5463
5869
|
if (!overwrite) {
|
|
5464
|
-
console.log(
|
|
5870
|
+
console.log(chalk6.yellow("Init cancelled \u2014 existing config preserved."));
|
|
5465
5871
|
return;
|
|
5466
5872
|
}
|
|
5467
5873
|
}
|
|
5468
|
-
const answers = await
|
|
5874
|
+
const answers = await prompts4(
|
|
5469
5875
|
[
|
|
5470
5876
|
{
|
|
5471
5877
|
type: "text",
|
|
5472
5878
|
name: "componentDir",
|
|
5473
5879
|
message: "Where should we install components?",
|
|
5474
|
-
initial: DEFAULTS.COMPONENT_DIR
|
|
5880
|
+
initial: DEFAULTS.COMPONENT_DIR,
|
|
5881
|
+
validate: (value) => {
|
|
5882
|
+
if (!value || value.trim().length === 0) {
|
|
5883
|
+
return "Component directory is required";
|
|
5884
|
+
}
|
|
5885
|
+
if (path8.isAbsolute(value)) {
|
|
5886
|
+
return "Please use a relative path (e.g., ./src/components/pdfx)";
|
|
5887
|
+
}
|
|
5888
|
+
if (!value.startsWith(".")) {
|
|
5889
|
+
return "Path should start with ./ or ../ (e.g., ./src/components/pdfx)";
|
|
5890
|
+
}
|
|
5891
|
+
return true;
|
|
5892
|
+
}
|
|
5475
5893
|
},
|
|
5476
5894
|
{
|
|
5477
5895
|
type: "text",
|
|
5478
5896
|
name: "registry",
|
|
5479
5897
|
message: "Registry URL:",
|
|
5480
|
-
initial: DEFAULTS.REGISTRY_URL
|
|
5898
|
+
initial: DEFAULTS.REGISTRY_URL,
|
|
5899
|
+
validate: (value) => {
|
|
5900
|
+
if (!value || !value.startsWith("http")) {
|
|
5901
|
+
return "Please enter a valid HTTP(S) URL";
|
|
5902
|
+
}
|
|
5903
|
+
return true;
|
|
5904
|
+
}
|
|
5481
5905
|
},
|
|
5482
5906
|
{
|
|
5483
5907
|
type: "select",
|
|
@@ -5506,18 +5930,30 @@ async function init() {
|
|
|
5506
5930
|
type: "text",
|
|
5507
5931
|
name: "themePath",
|
|
5508
5932
|
message: "Where should we create the theme file?",
|
|
5509
|
-
initial: DEFAULTS.THEME_FILE
|
|
5933
|
+
initial: DEFAULTS.THEME_FILE,
|
|
5934
|
+
validate: (value) => {
|
|
5935
|
+
if (!value || value.trim().length === 0) {
|
|
5936
|
+
return "Theme path is required";
|
|
5937
|
+
}
|
|
5938
|
+
if (path8.isAbsolute(value)) {
|
|
5939
|
+
return "Please use a relative path (e.g., ./src/lib/pdfx-theme.ts)";
|
|
5940
|
+
}
|
|
5941
|
+
if (!value.endsWith(".ts") && !value.endsWith(".tsx")) {
|
|
5942
|
+
return "Theme file must have .ts or .tsx extension (e.g., ./src/lib/pdfx-theme.ts)";
|
|
5943
|
+
}
|
|
5944
|
+
return true;
|
|
5945
|
+
}
|
|
5510
5946
|
}
|
|
5511
5947
|
],
|
|
5512
5948
|
{
|
|
5513
5949
|
onCancel: () => {
|
|
5514
|
-
console.log(
|
|
5950
|
+
console.log(chalk6.yellow("\nSetup cancelled."));
|
|
5515
5951
|
process.exit(0);
|
|
5516
5952
|
}
|
|
5517
5953
|
}
|
|
5518
5954
|
);
|
|
5519
5955
|
if (!answers.componentDir || !answers.registry) {
|
|
5520
|
-
console.error(
|
|
5956
|
+
console.error(chalk6.red("Missing required fields. Run pdfx init again."));
|
|
5521
5957
|
process.exit(1);
|
|
5522
5958
|
}
|
|
5523
5959
|
const config = {
|
|
@@ -5529,54 +5965,63 @@ async function init() {
|
|
|
5529
5965
|
const validation = configSchema.safeParse(config);
|
|
5530
5966
|
if (!validation.success) {
|
|
5531
5967
|
const issues = validation.error.issues.map((i) => i.message).join(", ");
|
|
5532
|
-
console.error(
|
|
5968
|
+
console.error(chalk6.red(`Invalid configuration: ${issues}`));
|
|
5533
5969
|
process.exit(1);
|
|
5534
5970
|
}
|
|
5535
|
-
const spinner =
|
|
5971
|
+
const spinner = ora5("Creating config and theme files...").start();
|
|
5536
5972
|
try {
|
|
5537
|
-
|
|
5973
|
+
const componentDirPath = path8.resolve(process.cwd(), answers.componentDir);
|
|
5974
|
+
ensureDir(componentDirPath);
|
|
5975
|
+
fs7.writeFileSync(path8.join(process.cwd(), "pdfx.json"), JSON.stringify(config, null, 2));
|
|
5538
5976
|
const presetName = answers.themePreset || "professional";
|
|
5539
5977
|
const preset = themePresets[presetName];
|
|
5540
|
-
const themePath =
|
|
5541
|
-
ensureDir(
|
|
5978
|
+
const themePath = path8.resolve(process.cwd(), config.theme);
|
|
5979
|
+
ensureDir(path8.dirname(themePath));
|
|
5542
5980
|
fs7.writeFileSync(themePath, generateThemeFile(preset), "utf-8");
|
|
5543
|
-
const contextPath =
|
|
5981
|
+
const contextPath = path8.join(path8.dirname(themePath), "pdfx-theme-context.tsx");
|
|
5544
5982
|
fs7.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
|
|
5545
5983
|
spinner.succeed(`Created pdfx.json + ${config.theme} (${presetName} theme)`);
|
|
5546
|
-
console.log(
|
|
5547
|
-
console.log(
|
|
5548
|
-
console.log(
|
|
5549
|
-
Components: ${
|
|
5550
|
-
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)}
|
|
5551
5989
|
`));
|
|
5552
5990
|
} catch (error) {
|
|
5553
5991
|
spinner.fail("Failed to create config");
|
|
5554
5992
|
const message = error instanceof Error ? error.message : String(error);
|
|
5555
|
-
console.error(
|
|
5993
|
+
console.error(chalk6.dim(` ${message}`));
|
|
5556
5994
|
process.exit(1);
|
|
5557
5995
|
}
|
|
5558
5996
|
}
|
|
5559
5997
|
|
|
5560
5998
|
// src/commands/list.ts
|
|
5561
|
-
import
|
|
5562
|
-
import
|
|
5563
|
-
import
|
|
5999
|
+
import path9 from "path";
|
|
6000
|
+
import chalk7 from "chalk";
|
|
6001
|
+
import ora6 from "ora";
|
|
5564
6002
|
var FETCH_TIMEOUT_MS2 = 1e4;
|
|
5565
6003
|
async function list() {
|
|
5566
|
-
const configPath =
|
|
5567
|
-
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
6004
|
+
const configPath = path9.join(process.cwd(), "pdfx.json");
|
|
6005
|
+
let config;
|
|
6006
|
+
let hasLocalProject = false;
|
|
6007
|
+
if (checkFileExists(configPath)) {
|
|
6008
|
+
const raw = readJsonFile(configPath);
|
|
6009
|
+
const configResult = configSchema.safeParse(raw);
|
|
6010
|
+
if (!configResult.success) {
|
|
6011
|
+
console.error(chalk7.red("Invalid pdfx.json"));
|
|
6012
|
+
process.exit(1);
|
|
6013
|
+
}
|
|
6014
|
+
config = configResult.data;
|
|
6015
|
+
hasLocalProject = true;
|
|
6016
|
+
} else {
|
|
6017
|
+
config = {
|
|
6018
|
+
registry: "https://pdfx.akashpise.dev/r",
|
|
6019
|
+
componentDir: "./src/components/pdfx",
|
|
6020
|
+
theme: "./src/lib/pdfx-theme.ts"
|
|
6021
|
+
};
|
|
6022
|
+
console.log(chalk7.dim("No pdfx.json found. Listing from default registry.\n"));
|
|
5577
6023
|
}
|
|
5578
|
-
const
|
|
5579
|
-
const spinner = ora5("Fetching component list...").start();
|
|
6024
|
+
const spinner = ora6("Fetching registry...").start();
|
|
5580
6025
|
try {
|
|
5581
6026
|
let response;
|
|
5582
6027
|
try {
|
|
@@ -5586,7 +6031,9 @@ async function list() {
|
|
|
5586
6031
|
} catch (err) {
|
|
5587
6032
|
const isTimeout = err instanceof Error && err.name === "TimeoutError";
|
|
5588
6033
|
throw new NetworkError(
|
|
5589
|
-
isTimeout ?
|
|
6034
|
+
isTimeout ? `Registry request timed out after 10 seconds.
|
|
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.")}`
|
|
5590
6037
|
);
|
|
5591
6038
|
}
|
|
5592
6039
|
if (!response.ok) {
|
|
@@ -5598,20 +6045,63 @@ async function list() {
|
|
|
5598
6045
|
throw new RegistryError("Invalid registry format");
|
|
5599
6046
|
}
|
|
5600
6047
|
spinner.stop();
|
|
5601
|
-
const targetDir = path8.resolve(process.cwd(), config.componentDir);
|
|
5602
6048
|
const components = result.data.items.filter((item) => item.type === "registry:ui");
|
|
5603
|
-
|
|
5604
|
-
|
|
5605
|
-
|
|
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"));
|
|
5606
6056
|
for (const item of components) {
|
|
5607
|
-
const componentSubDir =
|
|
6057
|
+
const componentSubDir = path9.join(componentBaseDir, item.name);
|
|
5608
6058
|
const localPath = safePath(componentSubDir, `pdfx-${item.name}.tsx`);
|
|
5609
|
-
const installed = checkFileExists(localPath);
|
|
5610
|
-
const status = installed ?
|
|
5611
|
-
console.log(` ${
|
|
5612
|
-
|
|
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}`);
|
|
6062
|
+
if (hasLocalProject) {
|
|
6063
|
+
console.log(` ${"".padEnd(20)} ${status}`);
|
|
6064
|
+
}
|
|
6065
|
+
console.log();
|
|
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
|
+
}
|
|
5613
6077
|
console.log();
|
|
5614
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();
|
|
5615
6105
|
} catch (error) {
|
|
5616
6106
|
const message = error instanceof Error ? error.message : String(error);
|
|
5617
6107
|
spinner.fail(message);
|
|
@@ -5620,18 +6110,18 @@ async function list() {
|
|
|
5620
6110
|
}
|
|
5621
6111
|
|
|
5622
6112
|
// src/commands/template.ts
|
|
5623
|
-
import
|
|
5624
|
-
import
|
|
5625
|
-
import
|
|
5626
|
-
import
|
|
5627
|
-
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) {
|
|
5628
6118
|
const raw = readJsonFile(configPath);
|
|
5629
6119
|
const result = configSchema.safeParse(raw);
|
|
5630
6120
|
if (!result.success) {
|
|
5631
6121
|
const issues = result.error.issues.map((i) => i.message).join(", ");
|
|
5632
6122
|
throw new ConfigError(
|
|
5633
6123
|
`Invalid pdfx.json: ${issues}`,
|
|
5634
|
-
`Fix the config or re-run ${
|
|
6124
|
+
`Fix the config or re-run ${chalk8.cyan("pdfx init")}`
|
|
5635
6125
|
);
|
|
5636
6126
|
}
|
|
5637
6127
|
return result.data;
|
|
@@ -5666,7 +6156,7 @@ async function fetchTemplate(name, registryUrl) {
|
|
|
5666
6156
|
}
|
|
5667
6157
|
return result.data;
|
|
5668
6158
|
}
|
|
5669
|
-
async function
|
|
6159
|
+
async function fetchComponent3(name, registryUrl) {
|
|
5670
6160
|
const url = `${registryUrl}/${name}.json`;
|
|
5671
6161
|
let response;
|
|
5672
6162
|
try {
|
|
@@ -5698,7 +6188,7 @@ async function fetchComponent2(name, registryUrl) {
|
|
|
5698
6188
|
}
|
|
5699
6189
|
function resolveTemplateImports(content, templateName, config) {
|
|
5700
6190
|
const cwd = process.cwd();
|
|
5701
|
-
const templateSubdir =
|
|
6191
|
+
const templateSubdir = path10.resolve(
|
|
5702
6192
|
cwd,
|
|
5703
6193
|
config.templateDir ?? DEFAULTS.TEMPLATE_DIR,
|
|
5704
6194
|
templateName
|
|
@@ -5706,38 +6196,38 @@ function resolveTemplateImports(content, templateName, config) {
|
|
|
5706
6196
|
let result = content.replace(
|
|
5707
6197
|
/from '\.\.\/\.\.\/components\/pdfx\/([a-z][a-z0-9-]*)\/pdfx-([a-z][a-z0-9-]*)'/g,
|
|
5708
6198
|
(_match, componentName) => {
|
|
5709
|
-
const absCompFile =
|
|
6199
|
+
const absCompFile = path10.resolve(
|
|
5710
6200
|
cwd,
|
|
5711
6201
|
config.componentDir,
|
|
5712
6202
|
componentName,
|
|
5713
6203
|
`pdfx-${componentName}`
|
|
5714
6204
|
);
|
|
5715
|
-
let rel =
|
|
6205
|
+
let rel = path10.relative(templateSubdir, absCompFile);
|
|
5716
6206
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
5717
6207
|
return `from '${rel}'`;
|
|
5718
6208
|
}
|
|
5719
6209
|
);
|
|
5720
6210
|
if (config.theme) {
|
|
5721
|
-
const absThemePath =
|
|
5722
|
-
let relTheme =
|
|
6211
|
+
const absThemePath = path10.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
|
|
6212
|
+
let relTheme = path10.relative(templateSubdir, absThemePath);
|
|
5723
6213
|
if (!relTheme.startsWith(".")) relTheme = `./${relTheme}`;
|
|
5724
|
-
const absContextPath =
|
|
5725
|
-
|
|
6214
|
+
const absContextPath = path10.join(
|
|
6215
|
+
path10.dirname(path10.resolve(cwd, config.theme)),
|
|
5726
6216
|
"pdfx-theme-context"
|
|
5727
6217
|
);
|
|
5728
|
-
let relContext =
|
|
6218
|
+
let relContext = path10.relative(templateSubdir, absContextPath);
|
|
5729
6219
|
if (!relContext.startsWith(".")) relContext = `./${relContext}`;
|
|
5730
6220
|
result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme'/g, `from '${relTheme}'`);
|
|
5731
6221
|
result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme-context'/g, `from '${relContext}'`);
|
|
5732
6222
|
}
|
|
5733
6223
|
return result;
|
|
5734
6224
|
}
|
|
5735
|
-
async function
|
|
6225
|
+
async function resolveConflict2(fileName, currentDecision) {
|
|
5736
6226
|
if (currentDecision === "overwrite-all") return "overwrite-all";
|
|
5737
|
-
const { action } = await
|
|
6227
|
+
const { action } = await prompts5({
|
|
5738
6228
|
type: "select",
|
|
5739
6229
|
name: "action",
|
|
5740
|
-
message: `${
|
|
6230
|
+
message: `${chalk8.yellow(fileName)} already exists. What would you like to do?`,
|
|
5741
6231
|
choices: [
|
|
5742
6232
|
{ title: "Skip", value: "skip", description: "Keep the existing file unchanged" },
|
|
5743
6233
|
{ title: "Overwrite", value: "overwrite", description: "Replace this file only" },
|
|
@@ -5752,20 +6242,20 @@ async function resolveConflict(fileName, currentDecision) {
|
|
|
5752
6242
|
if (!action) throw new ValidationError("Cancelled by user");
|
|
5753
6243
|
return action;
|
|
5754
6244
|
}
|
|
5755
|
-
async function
|
|
6245
|
+
async function ensurePeerComponents2(template, config, force) {
|
|
5756
6246
|
const installedPeers = [];
|
|
5757
6247
|
const peerWarnings = [];
|
|
5758
6248
|
if (!template.peerComponents || template.peerComponents.length === 0) {
|
|
5759
6249
|
return { installedPeers, peerWarnings };
|
|
5760
6250
|
}
|
|
5761
|
-
const componentBaseDir =
|
|
6251
|
+
const componentBaseDir = path10.resolve(process.cwd(), config.componentDir);
|
|
5762
6252
|
for (const componentName of template.peerComponents) {
|
|
5763
|
-
const componentDir =
|
|
5764
|
-
const expectedMain =
|
|
6253
|
+
const componentDir = path10.join(componentBaseDir, componentName);
|
|
6254
|
+
const expectedMain = path10.join(componentDir, `pdfx-${componentName}.tsx`);
|
|
5765
6255
|
if (checkFileExists(componentDir)) {
|
|
5766
6256
|
if (!checkFileExists(expectedMain)) {
|
|
5767
6257
|
peerWarnings.push(
|
|
5768
|
-
`${componentName}: directory exists but expected file missing (${
|
|
6258
|
+
`${componentName}: directory exists but expected file missing (${path10.basename(expectedMain)})`
|
|
5769
6259
|
);
|
|
5770
6260
|
} else {
|
|
5771
6261
|
peerWarnings.push(
|
|
@@ -5774,11 +6264,11 @@ async function ensurePeerComponents(template, config, force) {
|
|
|
5774
6264
|
}
|
|
5775
6265
|
continue;
|
|
5776
6266
|
}
|
|
5777
|
-
const component = await
|
|
6267
|
+
const component = await fetchComponent3(componentName, config.registry);
|
|
5778
6268
|
ensureDir(componentDir);
|
|
5779
|
-
const componentRelDir =
|
|
6269
|
+
const componentRelDir = path10.join(config.componentDir, component.name);
|
|
5780
6270
|
for (const file of component.files) {
|
|
5781
|
-
const fileName =
|
|
6271
|
+
const fileName = path10.basename(file.path);
|
|
5782
6272
|
const filePath = safePath(componentDir, fileName);
|
|
5783
6273
|
let content = file.content;
|
|
5784
6274
|
if (config.theme && (content.includes("pdfx-theme") || content.includes("pdfx-theme-context"))) {
|
|
@@ -5798,13 +6288,13 @@ async function ensurePeerComponents(template, config, force) {
|
|
|
5798
6288
|
}
|
|
5799
6289
|
async function installTemplate(name, config, force) {
|
|
5800
6290
|
const template = await fetchTemplate(name, config.registry);
|
|
5801
|
-
const peerResult = await
|
|
5802
|
-
const templateBaseDir =
|
|
5803
|
-
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);
|
|
5804
6294
|
ensureDir(templateDir);
|
|
5805
6295
|
const filesToWrite = [];
|
|
5806
6296
|
for (const file of template.files) {
|
|
5807
|
-
const fileName =
|
|
6297
|
+
const fileName = path10.basename(file.path);
|
|
5808
6298
|
const filePath = safePath(templateDir, fileName);
|
|
5809
6299
|
let content = file.content;
|
|
5810
6300
|
if (/\.(tsx?|jsx?)$/.test(fileName) && content.includes("../../")) {
|
|
@@ -5817,7 +6307,7 @@ async function installTemplate(name, config, force) {
|
|
|
5817
6307
|
const resolved = [];
|
|
5818
6308
|
for (const file of filesToWrite) {
|
|
5819
6309
|
if (checkFileExists(file.filePath)) {
|
|
5820
|
-
const decision = await
|
|
6310
|
+
const decision = await resolveConflict2(path10.basename(file.filePath), globalDecision);
|
|
5821
6311
|
if (decision === "overwrite-all") {
|
|
5822
6312
|
globalDecision = "overwrite-all";
|
|
5823
6313
|
}
|
|
@@ -5830,7 +6320,7 @@ async function installTemplate(name, config, force) {
|
|
|
5830
6320
|
if (!file.skip) {
|
|
5831
6321
|
writeFile(file.filePath, file.content);
|
|
5832
6322
|
} else {
|
|
5833
|
-
console.log(
|
|
6323
|
+
console.log(chalk8.dim(` skipped ${path10.basename(file.filePath)}`));
|
|
5834
6324
|
}
|
|
5835
6325
|
}
|
|
5836
6326
|
} else {
|
|
@@ -5839,49 +6329,49 @@ async function installTemplate(name, config, force) {
|
|
|
5839
6329
|
}
|
|
5840
6330
|
}
|
|
5841
6331
|
if (template.peerComponents && template.peerComponents.length > 0) {
|
|
5842
|
-
const componentBaseDir =
|
|
6332
|
+
const componentBaseDir = path10.resolve(process.cwd(), config.componentDir);
|
|
5843
6333
|
const missing = [];
|
|
5844
6334
|
for (const comp of template.peerComponents) {
|
|
5845
|
-
const compDir =
|
|
6335
|
+
const compDir = path10.join(componentBaseDir, comp);
|
|
5846
6336
|
if (!checkFileExists(compDir)) {
|
|
5847
6337
|
missing.push(comp);
|
|
5848
6338
|
}
|
|
5849
6339
|
}
|
|
5850
6340
|
if (missing.length > 0) {
|
|
5851
6341
|
console.log();
|
|
5852
|
-
console.log(
|
|
6342
|
+
console.log(chalk8.yellow(" Missing peer components:"));
|
|
5853
6343
|
for (const comp of missing) {
|
|
5854
|
-
console.log(
|
|
6344
|
+
console.log(chalk8.dim(` ${comp} \u2192 run: ${chalk8.cyan(`pdfx add ${comp}`)}`));
|
|
5855
6345
|
}
|
|
5856
6346
|
}
|
|
5857
6347
|
}
|
|
5858
6348
|
if (config.theme) {
|
|
5859
|
-
const absThemePath =
|
|
5860
|
-
const contextPath =
|
|
6349
|
+
const absThemePath = path10.resolve(process.cwd(), config.theme);
|
|
6350
|
+
const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
|
|
5861
6351
|
if (!checkFileExists(contextPath)) {
|
|
5862
|
-
ensureDir(
|
|
6352
|
+
ensureDir(path10.dirname(contextPath));
|
|
5863
6353
|
writeFile(contextPath, generateThemeContextFile());
|
|
5864
6354
|
}
|
|
5865
6355
|
}
|
|
5866
6356
|
return peerResult;
|
|
5867
6357
|
}
|
|
5868
6358
|
async function templateAdd(names, options = {}) {
|
|
5869
|
-
const configPath =
|
|
6359
|
+
const configPath = path10.join(process.cwd(), "pdfx.json");
|
|
5870
6360
|
if (!checkFileExists(configPath)) {
|
|
5871
|
-
console.error(
|
|
5872
|
-
console.log(
|
|
6361
|
+
console.error(chalk8.red("Error: pdfx.json not found"));
|
|
6362
|
+
console.log(chalk8.yellow("Run: pdfx init"));
|
|
5873
6363
|
process.exit(1);
|
|
5874
6364
|
}
|
|
5875
6365
|
let config;
|
|
5876
6366
|
try {
|
|
5877
|
-
config =
|
|
6367
|
+
config = readConfig3(configPath);
|
|
5878
6368
|
} catch (error) {
|
|
5879
6369
|
if (error instanceof ConfigError) {
|
|
5880
|
-
console.error(
|
|
5881
|
-
if (error.suggestion) console.log(
|
|
6370
|
+
console.error(chalk8.red(error.message));
|
|
6371
|
+
if (error.suggestion) console.log(chalk8.yellow(` Hint: ${error.suggestion}`));
|
|
5882
6372
|
} else {
|
|
5883
6373
|
const message = error instanceof Error ? error.message : String(error);
|
|
5884
|
-
console.error(
|
|
6374
|
+
console.error(chalk8.red(message));
|
|
5885
6375
|
}
|
|
5886
6376
|
process.exit(1);
|
|
5887
6377
|
}
|
|
@@ -5890,24 +6380,24 @@ async function templateAdd(names, options = {}) {
|
|
|
5890
6380
|
for (const templateName of names) {
|
|
5891
6381
|
const nameResult = componentNameSchema.safeParse(templateName);
|
|
5892
6382
|
if (!nameResult.success) {
|
|
5893
|
-
console.error(
|
|
6383
|
+
console.error(chalk8.red(`Invalid template name: "${templateName}"`));
|
|
5894
6384
|
console.log(
|
|
5895
|
-
|
|
6385
|
+
chalk8.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
|
|
5896
6386
|
);
|
|
5897
6387
|
failed.push(templateName);
|
|
5898
6388
|
continue;
|
|
5899
6389
|
}
|
|
5900
|
-
const spinner =
|
|
6390
|
+
const spinner = ora7(`Adding template ${templateName}...`).start();
|
|
5901
6391
|
try {
|
|
5902
6392
|
const result = await installTemplate(templateName, config, force);
|
|
5903
|
-
spinner.succeed(`Added template ${
|
|
6393
|
+
spinner.succeed(`Added template ${chalk8.cyan(templateName)}`);
|
|
5904
6394
|
if (result.installedPeers.length > 0) {
|
|
5905
6395
|
console.log(
|
|
5906
|
-
|
|
6396
|
+
chalk8.green(` Installed required components: ${result.installedPeers.join(", ")}`)
|
|
5907
6397
|
);
|
|
5908
6398
|
}
|
|
5909
6399
|
for (const warning of result.peerWarnings) {
|
|
5910
|
-
console.log(
|
|
6400
|
+
console.log(chalk8.yellow(` Warning: ${warning}`));
|
|
5911
6401
|
}
|
|
5912
6402
|
} catch (error) {
|
|
5913
6403
|
if (error instanceof ValidationError && error.message.includes("Cancelled")) {
|
|
@@ -5916,24 +6406,24 @@ async function templateAdd(names, options = {}) {
|
|
|
5916
6406
|
} else if (error instanceof NetworkError || error instanceof RegistryError || error instanceof ValidationError) {
|
|
5917
6407
|
spinner.fail(error.message);
|
|
5918
6408
|
if (error.suggestion) {
|
|
5919
|
-
console.log(
|
|
6409
|
+
console.log(chalk8.dim(` Hint: ${error.suggestion}`));
|
|
5920
6410
|
}
|
|
5921
6411
|
} else {
|
|
5922
6412
|
spinner.fail(`Failed to add template ${templateName}`);
|
|
5923
6413
|
const message = error instanceof Error ? error.message : String(error);
|
|
5924
|
-
console.error(
|
|
6414
|
+
console.error(chalk8.dim(` ${message}`));
|
|
5925
6415
|
}
|
|
5926
6416
|
failed.push(templateName);
|
|
5927
6417
|
}
|
|
5928
6418
|
}
|
|
5929
6419
|
console.log();
|
|
5930
6420
|
if (failed.length > 0) {
|
|
5931
|
-
console.log(
|
|
6421
|
+
console.log(chalk8.yellow(`Failed: ${failed.join(", ")}`));
|
|
5932
6422
|
}
|
|
5933
6423
|
if (failed.length < names.length) {
|
|
5934
|
-
const resolvedDir =
|
|
5935
|
-
console.log(
|
|
5936
|
-
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}
|
|
5937
6427
|
`));
|
|
5938
6428
|
}
|
|
5939
6429
|
if (failed.length > 0) {
|
|
@@ -5941,20 +6431,20 @@ async function templateAdd(names, options = {}) {
|
|
|
5941
6431
|
}
|
|
5942
6432
|
}
|
|
5943
6433
|
async function templateList() {
|
|
5944
|
-
const configPath =
|
|
6434
|
+
const configPath = path10.join(process.cwd(), "pdfx.json");
|
|
5945
6435
|
if (!checkFileExists(configPath)) {
|
|
5946
|
-
console.error(
|
|
5947
|
-
console.log(
|
|
6436
|
+
console.error(chalk8.red("Error: pdfx.json not found"));
|
|
6437
|
+
console.log(chalk8.yellow("Run: pdfx init"));
|
|
5948
6438
|
process.exit(1);
|
|
5949
6439
|
}
|
|
5950
6440
|
const raw = readJsonFile(configPath);
|
|
5951
6441
|
const configResult = configSchema.safeParse(raw);
|
|
5952
6442
|
if (!configResult.success) {
|
|
5953
|
-
console.error(
|
|
6443
|
+
console.error(chalk8.red("Invalid pdfx.json"));
|
|
5954
6444
|
process.exit(1);
|
|
5955
6445
|
}
|
|
5956
6446
|
const config = configResult.data;
|
|
5957
|
-
const spinner =
|
|
6447
|
+
const spinner = ora7("Fetching template list...").start();
|
|
5958
6448
|
try {
|
|
5959
6449
|
let response;
|
|
5960
6450
|
try {
|
|
@@ -5978,28 +6468,28 @@ async function templateList() {
|
|
|
5978
6468
|
spinner.stop();
|
|
5979
6469
|
const templates = result.data.items.filter((item) => item.type === "registry:template");
|
|
5980
6470
|
if (templates.length === 0) {
|
|
5981
|
-
console.log(
|
|
6471
|
+
console.log(chalk8.dim("\n No templates available in the registry.\n"));
|
|
5982
6472
|
return;
|
|
5983
6473
|
}
|
|
5984
|
-
const templateBaseDir =
|
|
6474
|
+
const templateBaseDir = path10.resolve(
|
|
5985
6475
|
process.cwd(),
|
|
5986
6476
|
config.templateDir ?? DEFAULTS.TEMPLATE_DIR
|
|
5987
6477
|
);
|
|
5988
|
-
console.log(
|
|
6478
|
+
console.log(chalk8.bold(`
|
|
5989
6479
|
Available Templates (${templates.length})
|
|
5990
6480
|
`));
|
|
5991
6481
|
for (const item of templates) {
|
|
5992
|
-
const templateDir =
|
|
6482
|
+
const templateDir = path10.join(templateBaseDir, item.name);
|
|
5993
6483
|
const installed = checkFileExists(templateDir);
|
|
5994
|
-
const status = installed ?
|
|
5995
|
-
console.log(` ${
|
|
6484
|
+
const status = installed ? chalk8.green("[installed]") : chalk8.dim("[not installed]");
|
|
6485
|
+
console.log(` ${chalk8.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
|
|
5996
6486
|
console.log(` ${"".padEnd(22)} ${status}`);
|
|
5997
6487
|
if (item.peerComponents && item.peerComponents.length > 0) {
|
|
5998
|
-
console.log(
|
|
6488
|
+
console.log(chalk8.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
|
|
5999
6489
|
}
|
|
6000
6490
|
console.log();
|
|
6001
6491
|
}
|
|
6002
|
-
console.log(
|
|
6492
|
+
console.log(chalk8.dim(` Install with: ${chalk8.cyan("pdfx template add <template-name>")}
|
|
6003
6493
|
`));
|
|
6004
6494
|
} catch (error) {
|
|
6005
6495
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -6010,14 +6500,22 @@ async function templateList() {
|
|
|
6010
6500
|
|
|
6011
6501
|
// src/commands/theme.ts
|
|
6012
6502
|
import fs8 from "fs";
|
|
6013
|
-
import
|
|
6014
|
-
import
|
|
6015
|
-
import
|
|
6016
|
-
import
|
|
6503
|
+
import path11 from "path";
|
|
6504
|
+
import chalk9 from "chalk";
|
|
6505
|
+
import ora8 from "ora";
|
|
6506
|
+
import prompts6 from "prompts";
|
|
6017
6507
|
import ts from "typescript";
|
|
6018
6508
|
async function themeInit() {
|
|
6019
|
-
|
|
6020
|
-
|
|
6509
|
+
const configPath = path11.join(process.cwd(), "pdfx.json");
|
|
6510
|
+
if (!fs8.existsSync(configPath)) {
|
|
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"));
|
|
6515
|
+
process.exit(1);
|
|
6516
|
+
}
|
|
6517
|
+
console.log(chalk9.bold.cyan("\n PDFx Theme Setup\n"));
|
|
6518
|
+
const answers = await prompts6(
|
|
6021
6519
|
[
|
|
6022
6520
|
{
|
|
6023
6521
|
type: "select",
|
|
@@ -6051,102 +6549,104 @@ async function themeInit() {
|
|
|
6051
6549
|
],
|
|
6052
6550
|
{
|
|
6053
6551
|
onCancel: () => {
|
|
6054
|
-
console.log(
|
|
6552
|
+
console.log(chalk9.yellow("\nTheme setup cancelled."));
|
|
6055
6553
|
process.exit(0);
|
|
6056
6554
|
}
|
|
6057
6555
|
}
|
|
6058
6556
|
);
|
|
6059
6557
|
if (!answers.preset || !answers.themePath) {
|
|
6060
|
-
console.error(
|
|
6558
|
+
console.error(chalk9.red("Missing required fields."));
|
|
6061
6559
|
process.exit(1);
|
|
6062
6560
|
}
|
|
6063
6561
|
const presetName = answers.preset;
|
|
6064
6562
|
const themePath = answers.themePath;
|
|
6065
6563
|
const preset = themePresets[presetName];
|
|
6066
|
-
const spinner =
|
|
6564
|
+
const spinner = ora8(`Scaffolding ${presetName} theme...`).start();
|
|
6067
6565
|
try {
|
|
6068
|
-
const absThemePath =
|
|
6069
|
-
ensureDir(
|
|
6566
|
+
const absThemePath = path11.resolve(process.cwd(), themePath);
|
|
6567
|
+
ensureDir(path11.dirname(absThemePath));
|
|
6070
6568
|
fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
|
|
6071
|
-
const contextPath =
|
|
6569
|
+
const contextPath = path11.join(path11.dirname(absThemePath), "pdfx-theme-context.tsx");
|
|
6072
6570
|
fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
|
|
6073
6571
|
spinner.succeed(`Created ${themePath} with ${presetName} theme`);
|
|
6074
|
-
const
|
|
6075
|
-
if (fs8.existsSync(
|
|
6572
|
+
const configPath2 = path11.join(process.cwd(), "pdfx.json");
|
|
6573
|
+
if (fs8.existsSync(configPath2)) {
|
|
6076
6574
|
try {
|
|
6077
|
-
const rawConfig = readJsonFile(
|
|
6575
|
+
const rawConfig = readJsonFile(configPath2);
|
|
6078
6576
|
const result = configSchema.safeParse(rawConfig);
|
|
6079
6577
|
if (result.success) {
|
|
6080
6578
|
const updatedConfig = { ...result.data, theme: themePath };
|
|
6081
|
-
fs8.writeFileSync(
|
|
6082
|
-
console.log(
|
|
6579
|
+
fs8.writeFileSync(configPath2, JSON.stringify(updatedConfig, null, 2), "utf-8");
|
|
6580
|
+
console.log(chalk9.green(" Updated pdfx.json with theme path"));
|
|
6083
6581
|
}
|
|
6084
6582
|
} catch {
|
|
6085
|
-
console.log(
|
|
6583
|
+
console.log(chalk9.yellow(' Could not update pdfx.json \u2014 add "theme" field manually'));
|
|
6086
6584
|
}
|
|
6087
6585
|
}
|
|
6088
|
-
console.log(
|
|
6586
|
+
console.log(chalk9.dim(`
|
|
6089
6587
|
Edit ${themePath} to customize your theme.
|
|
6090
6588
|
`));
|
|
6091
6589
|
} catch (error) {
|
|
6092
6590
|
spinner.fail("Failed to create theme file");
|
|
6093
6591
|
const message = error instanceof Error ? error.message : String(error);
|
|
6094
|
-
console.error(
|
|
6592
|
+
console.error(chalk9.dim(` ${message}`));
|
|
6095
6593
|
process.exit(1);
|
|
6096
6594
|
}
|
|
6097
6595
|
}
|
|
6098
6596
|
async function themeSwitch(presetName) {
|
|
6597
|
+
const resolvedPreset = presetName === "default" ? "professional" : presetName;
|
|
6099
6598
|
const validPresets = Object.keys(themePresets);
|
|
6100
|
-
if (!validPresets.includes(
|
|
6101
|
-
console.error(
|
|
6102
|
-
|
|
6103
|
-
|
|
6599
|
+
if (!validPresets.includes(resolvedPreset)) {
|
|
6600
|
+
console.error(chalk9.red(`\u2716 Invalid theme preset: "${presetName}"`));
|
|
6601
|
+
console.log(chalk9.dim(` Available presets: ${validPresets.join(", ")}, default
|
|
6602
|
+
`));
|
|
6603
|
+
console.log(chalk9.dim(" Usage: pdfx theme switch <preset>"));
|
|
6104
6604
|
process.exit(1);
|
|
6105
6605
|
}
|
|
6106
|
-
const validatedPreset =
|
|
6107
|
-
const configPath =
|
|
6606
|
+
const validatedPreset = resolvedPreset;
|
|
6607
|
+
const configPath = path11.join(process.cwd(), "pdfx.json");
|
|
6108
6608
|
if (!fs8.existsSync(configPath)) {
|
|
6109
|
-
console.error(
|
|
6609
|
+
console.error(chalk9.red('No pdfx.json found. Run "pdfx init" first.'));
|
|
6110
6610
|
process.exit(1);
|
|
6111
6611
|
}
|
|
6112
6612
|
const rawConfig = readJsonFile(configPath);
|
|
6113
6613
|
const result = configSchema.safeParse(rawConfig);
|
|
6114
6614
|
if (!result.success) {
|
|
6115
|
-
console.error(
|
|
6615
|
+
console.error(chalk9.red("Invalid pdfx.json configuration."));
|
|
6116
6616
|
process.exit(1);
|
|
6117
6617
|
}
|
|
6118
6618
|
const config = result.data;
|
|
6119
6619
|
if (!config.theme) {
|
|
6120
6620
|
console.error(
|
|
6121
|
-
|
|
6621
|
+
chalk9.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
|
|
6122
6622
|
);
|
|
6123
6623
|
process.exit(1);
|
|
6124
6624
|
}
|
|
6125
|
-
const answer = await
|
|
6625
|
+
const answer = await prompts6({
|
|
6126
6626
|
type: "confirm",
|
|
6127
6627
|
name: "confirm",
|
|
6128
6628
|
message: `This will overwrite ${config.theme} with the ${validatedPreset} preset. Continue?`,
|
|
6129
6629
|
initial: false
|
|
6130
6630
|
});
|
|
6131
6631
|
if (!answer.confirm) {
|
|
6132
|
-
console.log(
|
|
6632
|
+
console.log(chalk9.yellow("Cancelled."));
|
|
6133
6633
|
return;
|
|
6134
6634
|
}
|
|
6135
|
-
const spinner =
|
|
6635
|
+
const spinner = ora8(`Switching to ${validatedPreset} theme...`).start();
|
|
6136
6636
|
try {
|
|
6137
6637
|
const preset = themePresets[validatedPreset];
|
|
6138
|
-
const absThemePath =
|
|
6638
|
+
const absThemePath = path11.resolve(process.cwd(), config.theme);
|
|
6139
6639
|
fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
|
|
6140
|
-
const contextPath =
|
|
6640
|
+
const contextPath = path11.join(path11.dirname(absThemePath), "pdfx-theme-context.tsx");
|
|
6141
6641
|
if (!fs8.existsSync(contextPath)) {
|
|
6142
|
-
ensureDir(
|
|
6642
|
+
ensureDir(path11.dirname(contextPath));
|
|
6143
6643
|
fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
|
|
6144
6644
|
}
|
|
6145
6645
|
spinner.succeed(`Switched to ${validatedPreset} theme`);
|
|
6146
6646
|
} catch (error) {
|
|
6147
6647
|
spinner.fail("Failed to switch theme");
|
|
6148
6648
|
const message = error instanceof Error ? error.message : String(error);
|
|
6149
|
-
console.error(
|
|
6649
|
+
console.error(chalk9.dim(` ${message}`));
|
|
6150
6650
|
process.exit(1);
|
|
6151
6651
|
}
|
|
6152
6652
|
}
|
|
@@ -6214,54 +6714,68 @@ function parseThemeObject(themePath) {
|
|
|
6214
6714
|
throw new Error("No exported `theme` object found.");
|
|
6215
6715
|
}
|
|
6216
6716
|
async function themeValidate() {
|
|
6217
|
-
const configPath =
|
|
6717
|
+
const configPath = path11.join(process.cwd(), "pdfx.json");
|
|
6218
6718
|
if (!fs8.existsSync(configPath)) {
|
|
6219
|
-
console.error(
|
|
6719
|
+
console.error(chalk9.red('No pdfx.json found. Run "pdfx init" first.'));
|
|
6220
6720
|
process.exit(1);
|
|
6221
6721
|
}
|
|
6222
6722
|
const rawConfig = readJsonFile(configPath);
|
|
6223
6723
|
const configResult = configSchema.safeParse(rawConfig);
|
|
6224
6724
|
if (!configResult.success) {
|
|
6225
|
-
console.error(
|
|
6725
|
+
console.error(chalk9.red("Invalid pdfx.json configuration."));
|
|
6226
6726
|
process.exit(1);
|
|
6227
6727
|
}
|
|
6228
6728
|
if (!configResult.data.theme) {
|
|
6229
6729
|
console.error(
|
|
6230
|
-
|
|
6730
|
+
chalk9.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
|
|
6231
6731
|
);
|
|
6232
6732
|
process.exit(1);
|
|
6233
6733
|
}
|
|
6234
|
-
const absThemePath =
|
|
6734
|
+
const absThemePath = path11.resolve(process.cwd(), configResult.data.theme);
|
|
6235
6735
|
if (!fs8.existsSync(absThemePath)) {
|
|
6236
|
-
console.error(
|
|
6736
|
+
console.error(chalk9.red(`Theme file not found: ${configResult.data.theme}`));
|
|
6237
6737
|
process.exit(1);
|
|
6238
6738
|
}
|
|
6239
|
-
const spinner =
|
|
6739
|
+
const spinner = ora8("Validating theme file...").start();
|
|
6240
6740
|
try {
|
|
6241
6741
|
const parsedTheme = parseThemeObject(absThemePath);
|
|
6242
6742
|
const result = themeSchema.safeParse(parsedTheme);
|
|
6243
6743
|
if (!result.success) {
|
|
6244
|
-
const
|
|
6245
|
-
spinner.fail(
|
|
6744
|
+
const issues = result.error.issues.map((issue) => ` \u2192 ${chalk9.yellow(issue.path.join("."))}: ${issue.message}`).join("\n");
|
|
6745
|
+
spinner.fail("Theme validation failed");
|
|
6746
|
+
console.log(chalk9.red("\n Missing or invalid fields:\n"));
|
|
6747
|
+
console.log(issues);
|
|
6748
|
+
console.log(chalk9.dim("\n Fix these fields in your theme file and run validate again.\n"));
|
|
6246
6749
|
process.exit(1);
|
|
6247
6750
|
}
|
|
6248
6751
|
spinner.succeed("Theme file is valid");
|
|
6249
|
-
console.log(
|
|
6752
|
+
console.log(chalk9.dim(`
|
|
6250
6753
|
Validated: ${configResult.data.theme}
|
|
6251
6754
|
`));
|
|
6252
6755
|
} catch (error) {
|
|
6253
6756
|
spinner.fail("Failed to validate theme");
|
|
6254
6757
|
const message = error instanceof Error ? error.message : String(error);
|
|
6255
|
-
console.error(
|
|
6758
|
+
console.error(chalk9.dim(` ${message}`));
|
|
6256
6759
|
process.exit(1);
|
|
6257
6760
|
}
|
|
6258
6761
|
}
|
|
6259
6762
|
|
|
6260
6763
|
// src/index.ts
|
|
6261
6764
|
var program = new Command();
|
|
6262
|
-
|
|
6765
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
6766
|
+
var __dirname = join(__filename, "..");
|
|
6767
|
+
var packageJsonPath = join(__dirname, "../package.json");
|
|
6768
|
+
var version = "0.1.3";
|
|
6769
|
+
try {
|
|
6770
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
6771
|
+
version = pkg.version;
|
|
6772
|
+
} catch {
|
|
6773
|
+
}
|
|
6774
|
+
program.name("pdfx").description("CLI for PDFx components").version(version);
|
|
6263
6775
|
program.command("init").description("Initialize pdfx in your project").action(init);
|
|
6264
|
-
program.command("add <components...>").description("Add components to your project").option("-f, --force", "Overwrite existing files without prompting").
|
|
6776
|
+
program.command("add <components...>").description("Add components to your project").option("-f, --force", "Overwrite existing files without prompting").option("-r, --registry <url>", "Override registry URL").action(
|
|
6777
|
+
(components, options) => add(components, options)
|
|
6778
|
+
);
|
|
6265
6779
|
program.command("list").description("List available components from registry").action(list);
|
|
6266
6780
|
program.command("diff <components...>").description("Compare local components with registry versions").action(diff);
|
|
6267
6781
|
var themeCmd = program.command("theme").description("Manage PDF themes");
|
|
@@ -6271,4 +6785,7 @@ themeCmd.command("validate").description("Validate your theme file").action(them
|
|
|
6271
6785
|
var templateCmd = program.command("template").description("Manage PDF templates");
|
|
6272
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));
|
|
6273
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);
|
|
6274
6791
|
program.parse();
|