@akii09/pdfx-cli 0.1.2 → 0.1.4
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 +728 -235
- package/package.json +4 -1
package/dist/index.js
CHANGED
|
@@ -6,10 +6,13 @@ 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
|
|
12
|
-
import
|
|
15
|
+
import path3 from "path";
|
|
13
16
|
|
|
14
17
|
// ../../node_modules/.pnpm/zod@3.25.76/node_modules/zod/v3/external.js
|
|
15
18
|
var external_exports = {};
|
|
@@ -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: path11, errorMaps, issueData } = params;
|
|
496
|
+
const fullPath = [...path11, ...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, path11, key) {
|
|
610
613
|
this._cachedPath = [];
|
|
611
614
|
this.parent = parent;
|
|
612
615
|
this.data = value;
|
|
613
|
-
this._path =
|
|
616
|
+
this._path = path11;
|
|
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;
|
|
@@ -4461,30 +4464,156 @@ import chalk from "chalk";
|
|
|
4461
4464
|
import ora from "ora";
|
|
4462
4465
|
import prompts from "prompts";
|
|
4463
4466
|
|
|
4464
|
-
// src/utils/
|
|
4465
|
-
import
|
|
4467
|
+
// src/utils/dependency-validator.ts
|
|
4468
|
+
import fs2 from "fs";
|
|
4466
4469
|
import path from "path";
|
|
4470
|
+
import semver from "semver";
|
|
4471
|
+
|
|
4472
|
+
// src/utils/read-json.ts
|
|
4473
|
+
import fs from "fs";
|
|
4474
|
+
function readJsonFile(filePath) {
|
|
4475
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
4476
|
+
try {
|
|
4477
|
+
return JSON.parse(raw);
|
|
4478
|
+
} catch (error) {
|
|
4479
|
+
const details = error instanceof Error ? error.message : String(error);
|
|
4480
|
+
throw new ConfigError(`Invalid JSON in ${filePath}: ${details}`);
|
|
4481
|
+
}
|
|
4482
|
+
}
|
|
4483
|
+
|
|
4484
|
+
// src/utils/dependency-validator.ts
|
|
4485
|
+
var REQUIRED_VERSIONS = {
|
|
4486
|
+
"@react-pdf/renderer": ">=3.0.0",
|
|
4487
|
+
react: ">=16.8.0",
|
|
4488
|
+
node: ">=24.0.0"
|
|
4489
|
+
};
|
|
4490
|
+
function getPackageJson(cwd = process.cwd()) {
|
|
4491
|
+
const pkgPath = path.join(cwd, "package.json");
|
|
4492
|
+
if (!fs2.existsSync(pkgPath)) {
|
|
4493
|
+
return null;
|
|
4494
|
+
}
|
|
4495
|
+
return readJsonFile(pkgPath);
|
|
4496
|
+
}
|
|
4497
|
+
function getInstalledVersion(packageName, cwd = process.cwd()) {
|
|
4498
|
+
const pkg = getPackageJson(cwd);
|
|
4499
|
+
if (!pkg) return null;
|
|
4500
|
+
const deps = {
|
|
4501
|
+
...pkg.dependencies,
|
|
4502
|
+
...pkg.devDependencies
|
|
4503
|
+
};
|
|
4504
|
+
const version2 = deps[packageName];
|
|
4505
|
+
if (!version2) return null;
|
|
4506
|
+
return semver.clean(version2) || semver.coerce(version2)?.version || null;
|
|
4507
|
+
}
|
|
4508
|
+
function validateReactPdfRenderer(cwd = process.cwd()) {
|
|
4509
|
+
const version2 = getInstalledVersion("@react-pdf/renderer", cwd);
|
|
4510
|
+
const required = REQUIRED_VERSIONS["@react-pdf/renderer"];
|
|
4511
|
+
if (!version2) {
|
|
4512
|
+
return {
|
|
4513
|
+
valid: false,
|
|
4514
|
+
installed: false,
|
|
4515
|
+
requiredVersion: required,
|
|
4516
|
+
message: "@react-pdf/renderer is not installed"
|
|
4517
|
+
};
|
|
4518
|
+
}
|
|
4519
|
+
const isCompatible = semver.satisfies(version2, required);
|
|
4520
|
+
return {
|
|
4521
|
+
valid: isCompatible,
|
|
4522
|
+
installed: true,
|
|
4523
|
+
currentVersion: version2,
|
|
4524
|
+
requiredVersion: required,
|
|
4525
|
+
message: isCompatible ? "@react-pdf/renderer version is compatible" : `@react-pdf/renderer version ${version2} does not meet requirement ${required}`
|
|
4526
|
+
};
|
|
4527
|
+
}
|
|
4528
|
+
function validateReact(cwd = process.cwd()) {
|
|
4529
|
+
const version2 = getInstalledVersion("react", cwd);
|
|
4530
|
+
const required = REQUIRED_VERSIONS.react;
|
|
4531
|
+
if (!version2) {
|
|
4532
|
+
return {
|
|
4533
|
+
valid: false,
|
|
4534
|
+
installed: false,
|
|
4535
|
+
requiredVersion: required,
|
|
4536
|
+
message: "React is not installed"
|
|
4537
|
+
};
|
|
4538
|
+
}
|
|
4539
|
+
const isCompatible = semver.satisfies(version2, required);
|
|
4540
|
+
return {
|
|
4541
|
+
valid: isCompatible,
|
|
4542
|
+
installed: true,
|
|
4543
|
+
currentVersion: version2,
|
|
4544
|
+
requiredVersion: required,
|
|
4545
|
+
message: isCompatible ? "React version is compatible" : `React version ${version2} does not meet requirement ${required}`
|
|
4546
|
+
};
|
|
4547
|
+
}
|
|
4548
|
+
function validateNodeVersion() {
|
|
4549
|
+
const version2 = process.version;
|
|
4550
|
+
const required = REQUIRED_VERSIONS.node;
|
|
4551
|
+
const cleanVersion = semver.clean(version2);
|
|
4552
|
+
if (!cleanVersion) {
|
|
4553
|
+
return {
|
|
4554
|
+
valid: false,
|
|
4555
|
+
installed: true,
|
|
4556
|
+
currentVersion: version2,
|
|
4557
|
+
requiredVersion: required,
|
|
4558
|
+
message: `Unable to parse Node.js version: ${version2}`
|
|
4559
|
+
};
|
|
4560
|
+
}
|
|
4561
|
+
const isCompatible = semver.satisfies(cleanVersion, required);
|
|
4562
|
+
return {
|
|
4563
|
+
valid: isCompatible,
|
|
4564
|
+
installed: true,
|
|
4565
|
+
currentVersion: cleanVersion,
|
|
4566
|
+
requiredVersion: required,
|
|
4567
|
+
message: isCompatible ? "Node.js version is compatible" : `Node.js version ${cleanVersion} does not meet requirement ${required}`
|
|
4568
|
+
};
|
|
4569
|
+
}
|
|
4570
|
+
function validateTypeScript(cwd = process.cwd()) {
|
|
4571
|
+
const tsVersion = getInstalledVersion("typescript", cwd);
|
|
4572
|
+
if (!tsVersion) {
|
|
4573
|
+
return null;
|
|
4574
|
+
}
|
|
4575
|
+
const typesInstalled = getInstalledVersion("@types/react-pdf", cwd);
|
|
4576
|
+
return {
|
|
4577
|
+
valid: !!typesInstalled,
|
|
4578
|
+
installed: !!typesInstalled,
|
|
4579
|
+
currentVersion: typesInstalled || void 0,
|
|
4580
|
+
requiredVersion: "latest",
|
|
4581
|
+
message: typesInstalled ? "TypeScript types for @react-pdf/renderer are installed" : "@types/react-pdf is recommended for TypeScript projects"
|
|
4582
|
+
};
|
|
4583
|
+
}
|
|
4584
|
+
function validateDependencies(cwd = process.cwd()) {
|
|
4585
|
+
return {
|
|
4586
|
+
reactPdfRenderer: validateReactPdfRenderer(cwd),
|
|
4587
|
+
react: validateReact(cwd),
|
|
4588
|
+
nodeJs: validateNodeVersion(),
|
|
4589
|
+
typescript: validateTypeScript(cwd) || void 0
|
|
4590
|
+
};
|
|
4591
|
+
}
|
|
4592
|
+
|
|
4593
|
+
// src/utils/file-system.ts
|
|
4594
|
+
import fs3 from "fs";
|
|
4595
|
+
import path2 from "path";
|
|
4467
4596
|
function ensureDir(dir) {
|
|
4468
|
-
if (!
|
|
4469
|
-
|
|
4597
|
+
if (!fs3.existsSync(dir)) {
|
|
4598
|
+
fs3.mkdirSync(dir, { recursive: true });
|
|
4470
4599
|
}
|
|
4471
4600
|
}
|
|
4472
4601
|
function writeFile(filePath, content) {
|
|
4473
|
-
const dir =
|
|
4602
|
+
const dir = path2.dirname(filePath);
|
|
4474
4603
|
ensureDir(dir);
|
|
4475
|
-
|
|
4604
|
+
fs3.writeFileSync(filePath, content, "utf-8");
|
|
4476
4605
|
}
|
|
4477
4606
|
function checkFileExists(filePath) {
|
|
4478
|
-
return
|
|
4607
|
+
return fs3.existsSync(filePath);
|
|
4479
4608
|
}
|
|
4480
4609
|
function normalizePath(...segments) {
|
|
4481
|
-
return
|
|
4610
|
+
return path2.resolve(...segments);
|
|
4482
4611
|
}
|
|
4483
4612
|
function isPathWithinDirectory(resolvedPath, targetDir) {
|
|
4484
4613
|
const normalizedTarget = normalizePath(targetDir);
|
|
4485
4614
|
const normalizedResolved = normalizePath(resolvedPath);
|
|
4486
4615
|
if (normalizedResolved === normalizedTarget) return true;
|
|
4487
|
-
const prefix = normalizedTarget.endsWith(
|
|
4616
|
+
const prefix = normalizedTarget.endsWith(path2.sep) ? normalizedTarget : normalizedTarget + path2.sep;
|
|
4488
4617
|
return normalizedResolved.startsWith(prefix);
|
|
4489
4618
|
}
|
|
4490
4619
|
function safePath(targetDir, fileName) {
|
|
@@ -4754,18 +4883,6 @@ export function useSafeMemo<T>(factory: () => T, deps: DependencyList): T {
|
|
|
4754
4883
|
`;
|
|
4755
4884
|
}
|
|
4756
4885
|
|
|
4757
|
-
// src/utils/read-json.ts
|
|
4758
|
-
import fs2 from "fs";
|
|
4759
|
-
function readJsonFile(filePath) {
|
|
4760
|
-
const raw = fs2.readFileSync(filePath, "utf-8");
|
|
4761
|
-
try {
|
|
4762
|
-
return JSON.parse(raw);
|
|
4763
|
-
} catch (error) {
|
|
4764
|
-
const details = error instanceof Error ? error.message : String(error);
|
|
4765
|
-
throw new ConfigError(`Invalid JSON in ${filePath}: ${details}`);
|
|
4766
|
-
}
|
|
4767
|
-
}
|
|
4768
|
-
|
|
4769
4886
|
// src/commands/add.ts
|
|
4770
4887
|
function readConfig(configPath) {
|
|
4771
4888
|
const raw = readJsonFile(configPath);
|
|
@@ -4787,7 +4904,9 @@ async function fetchComponent(name, registryUrl) {
|
|
|
4787
4904
|
} catch (err) {
|
|
4788
4905
|
const isTimeout = err instanceof Error && err.name === "TimeoutError";
|
|
4789
4906
|
throw new NetworkError(
|
|
4790
|
-
isTimeout ?
|
|
4907
|
+
isTimeout ? `Registry request timed out after 10 seconds.
|
|
4908
|
+
${chalk.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${registryUrl}
|
|
4909
|
+
${chalk.dim("Verify the URL is correct and you have internet access.")}`
|
|
4791
4910
|
);
|
|
4792
4911
|
}
|
|
4793
4912
|
if (!response.ok) {
|
|
@@ -4810,15 +4929,15 @@ async function fetchComponent(name, registryUrl) {
|
|
|
4810
4929
|
return result.data;
|
|
4811
4930
|
}
|
|
4812
4931
|
function resolveThemeImport(componentDir, themePath, fileContent) {
|
|
4813
|
-
const absComponentDir =
|
|
4814
|
-
const absThemePath =
|
|
4932
|
+
const absComponentDir = path3.resolve(process.cwd(), componentDir);
|
|
4933
|
+
const absThemePath = path3.resolve(process.cwd(), themePath);
|
|
4815
4934
|
const themeImportTarget = absThemePath.replace(/\.tsx?$/, "");
|
|
4816
|
-
let relativePath =
|
|
4935
|
+
let relativePath = path3.relative(absComponentDir, themeImportTarget);
|
|
4817
4936
|
if (!relativePath.startsWith(".")) {
|
|
4818
4937
|
relativePath = `./${relativePath}`;
|
|
4819
4938
|
}
|
|
4820
|
-
const absContextPath =
|
|
4821
|
-
let relativeContextPath =
|
|
4939
|
+
const absContextPath = path3.join(path3.dirname(absThemePath), "pdfx-theme-context");
|
|
4940
|
+
let relativeContextPath = path3.relative(absComponentDir, absContextPath);
|
|
4822
4941
|
if (!relativeContextPath.startsWith(".")) {
|
|
4823
4942
|
relativeContextPath = `./${relativeContextPath}`;
|
|
4824
4943
|
}
|
|
@@ -4834,13 +4953,13 @@ function resolveThemeImport(componentDir, themePath, fileContent) {
|
|
|
4834
4953
|
}
|
|
4835
4954
|
async function installComponent(name, config, force) {
|
|
4836
4955
|
const component = await fetchComponent(name, config.registry);
|
|
4837
|
-
const targetDir =
|
|
4838
|
-
const componentDir =
|
|
4956
|
+
const targetDir = path3.resolve(process.cwd(), config.componentDir);
|
|
4957
|
+
const componentDir = path3.join(targetDir, component.name);
|
|
4839
4958
|
ensureDir(componentDir);
|
|
4840
|
-
const componentRelDir =
|
|
4959
|
+
const componentRelDir = path3.join(config.componentDir, component.name);
|
|
4841
4960
|
const filesToWrite = [];
|
|
4842
4961
|
for (const file of component.files) {
|
|
4843
|
-
const fileName =
|
|
4962
|
+
const fileName = path3.basename(file.path);
|
|
4844
4963
|
const filePath = safePath(componentDir, fileName);
|
|
4845
4964
|
let content = file.content;
|
|
4846
4965
|
if (config.theme && (content.includes("pdfx-theme") || content.includes("pdfx-theme-context"))) {
|
|
@@ -4851,7 +4970,7 @@ async function installComponent(name, config, force) {
|
|
|
4851
4970
|
if (!force) {
|
|
4852
4971
|
const existing = filesToWrite.filter((f) => checkFileExists(f.filePath));
|
|
4853
4972
|
if (existing.length > 0) {
|
|
4854
|
-
const fileNames = existing.map((f) =>
|
|
4973
|
+
const fileNames = existing.map((f) => path3.basename(f.filePath)).join(", ");
|
|
4855
4974
|
const { overwrite } = await prompts({
|
|
4856
4975
|
type: "confirm",
|
|
4857
4976
|
name: "overwrite",
|
|
@@ -4867,17 +4986,41 @@ async function installComponent(name, config, force) {
|
|
|
4867
4986
|
writeFile(file.filePath, file.content);
|
|
4868
4987
|
}
|
|
4869
4988
|
if (config.theme) {
|
|
4870
|
-
const absThemePath =
|
|
4871
|
-
const contextPath =
|
|
4989
|
+
const absThemePath = path3.resolve(process.cwd(), config.theme);
|
|
4990
|
+
const contextPath = path3.join(path3.dirname(absThemePath), "pdfx-theme-context.tsx");
|
|
4872
4991
|
if (!checkFileExists(contextPath)) {
|
|
4873
|
-
ensureDir(
|
|
4992
|
+
ensureDir(path3.dirname(contextPath));
|
|
4874
4993
|
writeFile(contextPath, generateThemeContextFile());
|
|
4875
4994
|
}
|
|
4876
4995
|
}
|
|
4877
4996
|
return;
|
|
4878
4997
|
}
|
|
4879
4998
|
async function add(components, options = {}) {
|
|
4880
|
-
|
|
4999
|
+
if (!components || components.length === 0) {
|
|
5000
|
+
console.error(chalk.red("Error: Component name required"));
|
|
5001
|
+
console.log(chalk.dim("Usage: pdfx add <component...>"));
|
|
5002
|
+
console.log(chalk.dim("Example: pdfx add heading text table\n"));
|
|
5003
|
+
process.exit(1);
|
|
5004
|
+
}
|
|
5005
|
+
const reactPdfCheck = validateReactPdfRenderer();
|
|
5006
|
+
if (!reactPdfCheck.installed) {
|
|
5007
|
+
console.error(chalk.red("\nError: @react-pdf/renderer is not installed\n"));
|
|
5008
|
+
console.log(chalk.yellow(" PDFx components require @react-pdf/renderer to work.\n"));
|
|
5009
|
+
console.log(chalk.cyan(" Run: pdfx init"));
|
|
5010
|
+
console.log(chalk.dim(" or install manually: npm install @react-pdf/renderer\n"));
|
|
5011
|
+
process.exit(1);
|
|
5012
|
+
}
|
|
5013
|
+
if (!reactPdfCheck.valid) {
|
|
5014
|
+
console.log(
|
|
5015
|
+
chalk.yellow(
|
|
5016
|
+
`
|
|
5017
|
+
\u26A0 Warning: ${reactPdfCheck.message}
|
|
5018
|
+
${chalk.dim("\u2192")} You may encounter compatibility issues
|
|
5019
|
+
`
|
|
5020
|
+
)
|
|
5021
|
+
);
|
|
5022
|
+
}
|
|
5023
|
+
const configPath = path3.join(process.cwd(), "pdfx.json");
|
|
4881
5024
|
if (!checkFileExists(configPath)) {
|
|
4882
5025
|
console.error(chalk.red("Error: pdfx.json not found"));
|
|
4883
5026
|
console.log(chalk.yellow("Run: pdfx init"));
|
|
@@ -4886,6 +5029,9 @@ async function add(components, options = {}) {
|
|
|
4886
5029
|
let config;
|
|
4887
5030
|
try {
|
|
4888
5031
|
config = readConfig(configPath);
|
|
5032
|
+
if (options.registry) {
|
|
5033
|
+
config = { ...config, registry: options.registry };
|
|
5034
|
+
}
|
|
4889
5035
|
} catch (error) {
|
|
4890
5036
|
if (error instanceof ConfigError) {
|
|
4891
5037
|
console.error(chalk.red(error.message));
|
|
@@ -4933,7 +5079,7 @@ async function add(components, options = {}) {
|
|
|
4933
5079
|
console.log(chalk.yellow(`Failed to add: ${failed.join(", ")}`));
|
|
4934
5080
|
}
|
|
4935
5081
|
if (failed.length < components.length) {
|
|
4936
|
-
const resolvedDir =
|
|
5082
|
+
const resolvedDir = path3.resolve(process.cwd(), config.componentDir);
|
|
4937
5083
|
console.log(chalk.green("Done!"));
|
|
4938
5084
|
console.log(chalk.dim(`Components installed to: ${resolvedDir}
|
|
4939
5085
|
`));
|
|
@@ -4944,13 +5090,13 @@ async function add(components, options = {}) {
|
|
|
4944
5090
|
}
|
|
4945
5091
|
|
|
4946
5092
|
// src/commands/diff.ts
|
|
4947
|
-
import
|
|
4948
|
-
import
|
|
5093
|
+
import fs4 from "fs";
|
|
5094
|
+
import path4 from "path";
|
|
4949
5095
|
import chalk2 from "chalk";
|
|
4950
5096
|
import ora2 from "ora";
|
|
4951
5097
|
var FETCH_TIMEOUT_MS = 1e4;
|
|
4952
5098
|
async function diff(components) {
|
|
4953
|
-
const configPath =
|
|
5099
|
+
const configPath = path4.join(process.cwd(), "pdfx.json");
|
|
4954
5100
|
if (!checkFileExists(configPath)) {
|
|
4955
5101
|
console.error(chalk2.red("Error: pdfx.json not found"));
|
|
4956
5102
|
console.log(chalk2.yellow("Run: pdfx init"));
|
|
@@ -4963,7 +5109,7 @@ async function diff(components) {
|
|
|
4963
5109
|
process.exit(1);
|
|
4964
5110
|
}
|
|
4965
5111
|
const config = configResult.data;
|
|
4966
|
-
const targetDir =
|
|
5112
|
+
const targetDir = path4.resolve(process.cwd(), config.componentDir);
|
|
4967
5113
|
for (const componentName of components) {
|
|
4968
5114
|
const nameResult = componentNameSchema.safeParse(componentName);
|
|
4969
5115
|
if (!nameResult.success) {
|
|
@@ -4980,7 +5126,9 @@ async function diff(components) {
|
|
|
4980
5126
|
} catch (err) {
|
|
4981
5127
|
const isTimeout = err instanceof Error && err.name === "TimeoutError";
|
|
4982
5128
|
throw new NetworkError(
|
|
4983
|
-
isTimeout ?
|
|
5129
|
+
isTimeout ? `Registry request timed out after 10 seconds.
|
|
5130
|
+
${chalk2.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
|
|
5131
|
+
${chalk2.dim("Verify the URL is correct and you have internet access.")}`
|
|
4984
5132
|
);
|
|
4985
5133
|
}
|
|
4986
5134
|
if (!response.ok) {
|
|
@@ -4995,17 +5143,17 @@ async function diff(components) {
|
|
|
4995
5143
|
}
|
|
4996
5144
|
const component = result.data;
|
|
4997
5145
|
spinner.stop();
|
|
4998
|
-
const componentSubDir =
|
|
5146
|
+
const componentSubDir = path4.join(targetDir, component.name);
|
|
4999
5147
|
for (const file of component.files) {
|
|
5000
|
-
const fileName =
|
|
5148
|
+
const fileName = path4.basename(file.path);
|
|
5001
5149
|
const localPath = safePath(componentSubDir, fileName);
|
|
5002
5150
|
if (!checkFileExists(localPath)) {
|
|
5003
5151
|
console.log(chalk2.yellow(` ${fileName}: not installed locally`));
|
|
5004
5152
|
continue;
|
|
5005
5153
|
}
|
|
5006
|
-
const localContent =
|
|
5154
|
+
const localContent = fs4.readFileSync(localPath, "utf-8");
|
|
5007
5155
|
const registryContent = config.theme && (file.content.includes("pdfx-theme") || file.content.includes("pdfx-theme-context")) ? resolveThemeImport(
|
|
5008
|
-
|
|
5156
|
+
path4.join(config.componentDir, component.name),
|
|
5009
5157
|
config.theme,
|
|
5010
5158
|
file.content
|
|
5011
5159
|
) : file.content;
|
|
@@ -5015,8 +5163,13 @@ async function diff(components) {
|
|
|
5015
5163
|
console.log(chalk2.yellow(` ${fileName}: differs from registry`));
|
|
5016
5164
|
const localLines = localContent.split("\n");
|
|
5017
5165
|
const registryLines = registryContent.split("\n");
|
|
5166
|
+
const lineDiff = localLines.length - registryLines.length;
|
|
5018
5167
|
console.log(chalk2.dim(` Local: ${localLines.length} lines`));
|
|
5019
5168
|
console.log(chalk2.dim(` Registry: ${registryLines.length} lines`));
|
|
5169
|
+
if (lineDiff !== 0) {
|
|
5170
|
+
const diffText = lineDiff > 0 ? `${Math.abs(lineDiff)} line${Math.abs(lineDiff) > 1 ? "s" : ""} added locally` : `${Math.abs(lineDiff)} line${Math.abs(lineDiff) > 1 ? "s" : ""} removed locally`;
|
|
5171
|
+
console.log(chalk2.dim(` \u2192 ${diffText}`));
|
|
5172
|
+
}
|
|
5020
5173
|
}
|
|
5021
5174
|
}
|
|
5022
5175
|
console.log();
|
|
@@ -5028,11 +5181,11 @@ async function diff(components) {
|
|
|
5028
5181
|
}
|
|
5029
5182
|
|
|
5030
5183
|
// src/commands/init.ts
|
|
5031
|
-
import
|
|
5032
|
-
import
|
|
5033
|
-
import
|
|
5034
|
-
import
|
|
5035
|
-
import
|
|
5184
|
+
import fs7 from "fs";
|
|
5185
|
+
import path7 from "path";
|
|
5186
|
+
import chalk5 from "chalk";
|
|
5187
|
+
import ora4 from "ora";
|
|
5188
|
+
import prompts3 from "prompts";
|
|
5036
5189
|
|
|
5037
5190
|
// src/constants.ts
|
|
5038
5191
|
var DEFAULTS = {
|
|
@@ -5046,35 +5199,324 @@ var REGISTRY_SUBPATHS = {
|
|
|
5046
5199
|
TEMPLATES: "templates"
|
|
5047
5200
|
};
|
|
5048
5201
|
|
|
5202
|
+
// src/utils/install-dependencies.ts
|
|
5203
|
+
import chalk3 from "chalk";
|
|
5204
|
+
import { execa } from "execa";
|
|
5205
|
+
import ora3 from "ora";
|
|
5206
|
+
import prompts2 from "prompts";
|
|
5207
|
+
|
|
5208
|
+
// src/utils/package-manager.ts
|
|
5209
|
+
import fs5 from "fs";
|
|
5210
|
+
import path5 from "path";
|
|
5211
|
+
var PACKAGE_MANAGERS = {
|
|
5212
|
+
pnpm: {
|
|
5213
|
+
name: "pnpm",
|
|
5214
|
+
lockfile: "pnpm-lock.yaml",
|
|
5215
|
+
installCommand: "pnpm add"
|
|
5216
|
+
},
|
|
5217
|
+
yarn: {
|
|
5218
|
+
name: "yarn",
|
|
5219
|
+
lockfile: "yarn.lock",
|
|
5220
|
+
installCommand: "yarn add"
|
|
5221
|
+
},
|
|
5222
|
+
bun: {
|
|
5223
|
+
name: "bun",
|
|
5224
|
+
lockfile: "bun.lockb",
|
|
5225
|
+
installCommand: "bun add"
|
|
5226
|
+
},
|
|
5227
|
+
npm: {
|
|
5228
|
+
name: "npm",
|
|
5229
|
+
lockfile: "package-lock.json",
|
|
5230
|
+
installCommand: "npm install"
|
|
5231
|
+
}
|
|
5232
|
+
};
|
|
5233
|
+
function detectPackageManager(cwd = process.cwd()) {
|
|
5234
|
+
const managers = ["pnpm", "yarn", "bun", "npm"];
|
|
5235
|
+
for (const manager of managers) {
|
|
5236
|
+
const info = PACKAGE_MANAGERS[manager];
|
|
5237
|
+
const lockfilePath = path5.join(cwd, info.lockfile);
|
|
5238
|
+
if (fs5.existsSync(lockfilePath)) {
|
|
5239
|
+
return info;
|
|
5240
|
+
}
|
|
5241
|
+
}
|
|
5242
|
+
return PACKAGE_MANAGERS.npm;
|
|
5243
|
+
}
|
|
5244
|
+
function getInstallCommand(packageManager, packages, devDependency = false) {
|
|
5245
|
+
const pm = PACKAGE_MANAGERS[packageManager];
|
|
5246
|
+
const devFlag = devDependency ? packageManager === "npm" ? "--save-dev" : "-D" : "";
|
|
5247
|
+
return `${pm.installCommand} ${packages.join(" ")} ${devFlag}`.trim();
|
|
5248
|
+
}
|
|
5249
|
+
|
|
5250
|
+
// src/utils/install-dependencies.ts
|
|
5251
|
+
async function promptAndInstallReactPdf(validation, cwd = process.cwd()) {
|
|
5252
|
+
if (validation.installed && validation.valid) {
|
|
5253
|
+
return {
|
|
5254
|
+
success: true,
|
|
5255
|
+
message: "@react-pdf/renderer is already installed and compatible"
|
|
5256
|
+
};
|
|
5257
|
+
}
|
|
5258
|
+
const pm = detectPackageManager(cwd);
|
|
5259
|
+
const packageName = "@react-pdf/renderer";
|
|
5260
|
+
const installCmd = getInstallCommand(pm.name, [packageName]);
|
|
5261
|
+
console.log(chalk3.yellow("\n \u26A0 @react-pdf/renderer is required but not installed\n"));
|
|
5262
|
+
console.log(chalk3.dim(` This command will run: ${installCmd}
|
|
5263
|
+
`));
|
|
5264
|
+
const { shouldInstall } = await prompts2({
|
|
5265
|
+
type: "confirm",
|
|
5266
|
+
name: "shouldInstall",
|
|
5267
|
+
message: "Install @react-pdf/renderer now?",
|
|
5268
|
+
initial: true
|
|
5269
|
+
});
|
|
5270
|
+
if (!shouldInstall) {
|
|
5271
|
+
return {
|
|
5272
|
+
success: false,
|
|
5273
|
+
message: `Installation cancelled. Please install manually:
|
|
5274
|
+
${chalk3.cyan(installCmd)}`
|
|
5275
|
+
};
|
|
5276
|
+
}
|
|
5277
|
+
const spinner = ora3("Installing @react-pdf/renderer...").start();
|
|
5278
|
+
try {
|
|
5279
|
+
await execa(pm.name, ["add", packageName], {
|
|
5280
|
+
cwd,
|
|
5281
|
+
stdio: "pipe"
|
|
5282
|
+
});
|
|
5283
|
+
spinner.succeed("Installed @react-pdf/renderer");
|
|
5284
|
+
return {
|
|
5285
|
+
success: true,
|
|
5286
|
+
message: "@react-pdf/renderer installed successfully"
|
|
5287
|
+
};
|
|
5288
|
+
} catch (error) {
|
|
5289
|
+
spinner.fail("Failed to install @react-pdf/renderer");
|
|
5290
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
5291
|
+
return {
|
|
5292
|
+
success: false,
|
|
5293
|
+
message: `Installation failed: ${message}
|
|
5294
|
+
Try manually: ${chalk3.cyan(installCmd)}`
|
|
5295
|
+
};
|
|
5296
|
+
}
|
|
5297
|
+
}
|
|
5298
|
+
async function ensureReactPdfRenderer(validation, cwd = process.cwd()) {
|
|
5299
|
+
if (!validation.installed) {
|
|
5300
|
+
const result = await promptAndInstallReactPdf(validation, cwd);
|
|
5301
|
+
if (!result.success) {
|
|
5302
|
+
console.error(chalk3.red(`
|
|
5303
|
+
${result.message}
|
|
5304
|
+
`));
|
|
5305
|
+
return false;
|
|
5306
|
+
}
|
|
5307
|
+
return true;
|
|
5308
|
+
}
|
|
5309
|
+
if (!validation.valid) {
|
|
5310
|
+
console.log(
|
|
5311
|
+
chalk3.yellow(
|
|
5312
|
+
`
|
|
5313
|
+
\u26A0 ${validation.message}
|
|
5314
|
+
${chalk3.dim("\u2192")} You may encounter compatibility issues
|
|
5315
|
+
`
|
|
5316
|
+
)
|
|
5317
|
+
);
|
|
5318
|
+
}
|
|
5319
|
+
return true;
|
|
5320
|
+
}
|
|
5321
|
+
|
|
5322
|
+
// src/utils/pre-flight.ts
|
|
5323
|
+
import chalk4 from "chalk";
|
|
5324
|
+
|
|
5325
|
+
// src/utils/environment-validator.ts
|
|
5326
|
+
import fs6 from "fs";
|
|
5327
|
+
import path6 from "path";
|
|
5328
|
+
function validatePackageJson(cwd = process.cwd()) {
|
|
5329
|
+
const pkgPath = path6.join(cwd, "package.json");
|
|
5330
|
+
const exists = fs6.existsSync(pkgPath);
|
|
5331
|
+
return {
|
|
5332
|
+
valid: exists,
|
|
5333
|
+
message: exists ? "package.json found" : "No package.json found in current directory",
|
|
5334
|
+
fixCommand: exists ? void 0 : 'Run "npm init" or "pnpm init" to create a package.json'
|
|
5335
|
+
};
|
|
5336
|
+
}
|
|
5337
|
+
function validateReactProject(cwd = process.cwd()) {
|
|
5338
|
+
const pkgPath = path6.join(cwd, "package.json");
|
|
5339
|
+
if (!fs6.existsSync(pkgPath)) {
|
|
5340
|
+
return {
|
|
5341
|
+
valid: false,
|
|
5342
|
+
message: "Cannot validate React project without package.json"
|
|
5343
|
+
};
|
|
5344
|
+
}
|
|
5345
|
+
try {
|
|
5346
|
+
const pkg = readJsonFile(pkgPath);
|
|
5347
|
+
const deps = {
|
|
5348
|
+
...pkg.dependencies,
|
|
5349
|
+
...pkg.devDependencies
|
|
5350
|
+
};
|
|
5351
|
+
const hasReact = "react" in deps;
|
|
5352
|
+
return {
|
|
5353
|
+
valid: hasReact,
|
|
5354
|
+
message: hasReact ? "React is installed" : "This does not appear to be a React project",
|
|
5355
|
+
fixCommand: hasReact ? void 0 : "Install React: npx create-vite@latest or npx create-react-app"
|
|
5356
|
+
};
|
|
5357
|
+
} catch {
|
|
5358
|
+
return {
|
|
5359
|
+
valid: false,
|
|
5360
|
+
message: "Failed to read package.json"
|
|
5361
|
+
};
|
|
5362
|
+
}
|
|
5363
|
+
}
|
|
5364
|
+
function validatePdfxConfig(cwd = process.cwd()) {
|
|
5365
|
+
const configPath = path6.join(cwd, "pdfx.json");
|
|
5366
|
+
const exists = fs6.existsSync(configPath);
|
|
5367
|
+
return {
|
|
5368
|
+
valid: true,
|
|
5369
|
+
// Not blocking
|
|
5370
|
+
message: exists ? "pdfx.json already exists (will prompt to overwrite)" : "No existing pdfx.json"
|
|
5371
|
+
};
|
|
5372
|
+
}
|
|
5373
|
+
function validateEnvironment(cwd = process.cwd()) {
|
|
5374
|
+
return {
|
|
5375
|
+
hasPackageJson: validatePackageJson(cwd),
|
|
5376
|
+
isReactProject: validateReactProject(cwd),
|
|
5377
|
+
hasPdfxConfig: validatePdfxConfig(cwd)
|
|
5378
|
+
};
|
|
5379
|
+
}
|
|
5380
|
+
|
|
5381
|
+
// src/utils/pre-flight.ts
|
|
5382
|
+
function runPreFlightChecks(cwd = process.cwd()) {
|
|
5383
|
+
const environment = validateEnvironment(cwd);
|
|
5384
|
+
const dependencies = validateDependencies(cwd);
|
|
5385
|
+
const blockingErrors = [];
|
|
5386
|
+
const warnings = [];
|
|
5387
|
+
if (!environment.hasPackageJson.valid) {
|
|
5388
|
+
blockingErrors.push(
|
|
5389
|
+
`${environment.hasPackageJson.message}
|
|
5390
|
+
${chalk4.dim("\u2192")} ${environment.hasPackageJson.fixCommand}`
|
|
5391
|
+
);
|
|
5392
|
+
} else if (!environment.isReactProject.valid) {
|
|
5393
|
+
blockingErrors.push(
|
|
5394
|
+
`${environment.isReactProject.message}
|
|
5395
|
+
${chalk4.dim("\u2192")} ${environment.isReactProject.fixCommand}`
|
|
5396
|
+
);
|
|
5397
|
+
} else {
|
|
5398
|
+
if (!dependencies.react.valid && dependencies.react.installed) {
|
|
5399
|
+
warnings.push(
|
|
5400
|
+
`${dependencies.react.message}
|
|
5401
|
+
${chalk4.dim("\u2192")} Current: ${dependencies.react.currentVersion}, Required: ${dependencies.react.requiredVersion}`
|
|
5402
|
+
);
|
|
5403
|
+
} else if (!dependencies.react.installed) {
|
|
5404
|
+
blockingErrors.push(
|
|
5405
|
+
`${dependencies.react.message}
|
|
5406
|
+
${chalk4.dim("\u2192")} Install React: npm install react react-dom`
|
|
5407
|
+
);
|
|
5408
|
+
}
|
|
5409
|
+
}
|
|
5410
|
+
if (!dependencies.nodeJs.valid) {
|
|
5411
|
+
blockingErrors.push(
|
|
5412
|
+
`${dependencies.nodeJs.message}
|
|
5413
|
+
${chalk4.dim("\u2192")} Current: ${dependencies.nodeJs.currentVersion}, Required: ${dependencies.nodeJs.requiredVersion}
|
|
5414
|
+
${chalk4.dim("\u2192")} Visit https://nodejs.org to upgrade`
|
|
5415
|
+
);
|
|
5416
|
+
}
|
|
5417
|
+
if (dependencies.reactPdfRenderer.installed && !dependencies.reactPdfRenderer.valid) {
|
|
5418
|
+
warnings.push(
|
|
5419
|
+
`${dependencies.reactPdfRenderer.message}
|
|
5420
|
+
${chalk4.dim("\u2192")} Consider upgrading: npm install @react-pdf/renderer@latest`
|
|
5421
|
+
);
|
|
5422
|
+
}
|
|
5423
|
+
if (dependencies.typescript && !dependencies.typescript.valid) {
|
|
5424
|
+
warnings.push(
|
|
5425
|
+
`${dependencies.typescript.message}
|
|
5426
|
+
${chalk4.dim("\u2192")} Install types: npm install -D @types/react-pdf`
|
|
5427
|
+
);
|
|
5428
|
+
}
|
|
5429
|
+
return {
|
|
5430
|
+
environment,
|
|
5431
|
+
dependencies,
|
|
5432
|
+
blockingErrors,
|
|
5433
|
+
warnings,
|
|
5434
|
+
canProceed: blockingErrors.length === 0
|
|
5435
|
+
};
|
|
5436
|
+
}
|
|
5437
|
+
function displayPreFlightResults(result) {
|
|
5438
|
+
console.log(chalk4.bold("\n Pre-flight Checks:\n"));
|
|
5439
|
+
if (result.blockingErrors.length > 0) {
|
|
5440
|
+
console.log(chalk4.red(" \u2717 Blocking Issues:\n"));
|
|
5441
|
+
for (const error of result.blockingErrors) {
|
|
5442
|
+
console.log(chalk4.red(` \u2022 ${error}
|
|
5443
|
+
`));
|
|
5444
|
+
}
|
|
5445
|
+
}
|
|
5446
|
+
if (result.warnings.length > 0) {
|
|
5447
|
+
console.log(chalk4.yellow(" \u26A0 Warnings:\n"));
|
|
5448
|
+
for (const warning of result.warnings) {
|
|
5449
|
+
console.log(chalk4.yellow(` \u2022 ${warning}
|
|
5450
|
+
`));
|
|
5451
|
+
}
|
|
5452
|
+
}
|
|
5453
|
+
if (result.blockingErrors.length === 0 && result.warnings.length === 0) {
|
|
5454
|
+
console.log(chalk4.green(" \u2713 All checks passed!\n"));
|
|
5455
|
+
}
|
|
5456
|
+
}
|
|
5457
|
+
|
|
5049
5458
|
// src/commands/init.ts
|
|
5050
5459
|
async function init() {
|
|
5051
|
-
console.log(
|
|
5052
|
-
const
|
|
5053
|
-
|
|
5054
|
-
|
|
5460
|
+
console.log(chalk5.bold.cyan("\n Welcome to the pdfx cli\n"));
|
|
5461
|
+
const preFlightResult = runPreFlightChecks();
|
|
5462
|
+
displayPreFlightResults(preFlightResult);
|
|
5463
|
+
if (!preFlightResult.canProceed) {
|
|
5464
|
+
console.error(
|
|
5465
|
+
chalk5.red("\n Cannot proceed due to blocking issues. Please fix them and try again.\n")
|
|
5466
|
+
);
|
|
5467
|
+
process.exit(1);
|
|
5468
|
+
}
|
|
5469
|
+
const hasReactPdf = await ensureReactPdfRenderer(preFlightResult.dependencies.reactPdfRenderer);
|
|
5470
|
+
if (!hasReactPdf) {
|
|
5471
|
+
console.error(
|
|
5472
|
+
chalk5.red("\n @react-pdf/renderer is required. Please install it and try again.\n")
|
|
5473
|
+
);
|
|
5474
|
+
process.exit(1);
|
|
5475
|
+
}
|
|
5476
|
+
const existingConfig = path7.join(process.cwd(), "pdfx.json");
|
|
5477
|
+
if (fs7.existsSync(existingConfig)) {
|
|
5478
|
+
const { overwrite } = await prompts3({
|
|
5055
5479
|
type: "confirm",
|
|
5056
5480
|
name: "overwrite",
|
|
5057
5481
|
message: "pdfx.json already exists. Overwrite?",
|
|
5058
5482
|
initial: false
|
|
5059
5483
|
});
|
|
5060
5484
|
if (!overwrite) {
|
|
5061
|
-
console.log(
|
|
5485
|
+
console.log(chalk5.yellow("Init cancelled \u2014 existing config preserved."));
|
|
5062
5486
|
return;
|
|
5063
5487
|
}
|
|
5064
5488
|
}
|
|
5065
|
-
const answers = await
|
|
5489
|
+
const answers = await prompts3(
|
|
5066
5490
|
[
|
|
5067
5491
|
{
|
|
5068
5492
|
type: "text",
|
|
5069
5493
|
name: "componentDir",
|
|
5070
5494
|
message: "Where should we install components?",
|
|
5071
|
-
initial: DEFAULTS.COMPONENT_DIR
|
|
5495
|
+
initial: DEFAULTS.COMPONENT_DIR,
|
|
5496
|
+
validate: (value) => {
|
|
5497
|
+
if (!value || value.trim().length === 0) {
|
|
5498
|
+
return "Component directory is required";
|
|
5499
|
+
}
|
|
5500
|
+
if (path7.isAbsolute(value)) {
|
|
5501
|
+
return "Please use a relative path (e.g., ./src/components/pdfx)";
|
|
5502
|
+
}
|
|
5503
|
+
if (!value.startsWith(".")) {
|
|
5504
|
+
return "Path should start with ./ or ../ (e.g., ./src/components/pdfx)";
|
|
5505
|
+
}
|
|
5506
|
+
return true;
|
|
5507
|
+
}
|
|
5072
5508
|
},
|
|
5073
5509
|
{
|
|
5074
5510
|
type: "text",
|
|
5075
5511
|
name: "registry",
|
|
5076
5512
|
message: "Registry URL:",
|
|
5077
|
-
initial: DEFAULTS.REGISTRY_URL
|
|
5513
|
+
initial: DEFAULTS.REGISTRY_URL,
|
|
5514
|
+
validate: (value) => {
|
|
5515
|
+
if (!value || !value.startsWith("http")) {
|
|
5516
|
+
return "Please enter a valid HTTP(S) URL";
|
|
5517
|
+
}
|
|
5518
|
+
return true;
|
|
5519
|
+
}
|
|
5078
5520
|
},
|
|
5079
5521
|
{
|
|
5080
5522
|
type: "select",
|
|
@@ -5103,18 +5545,30 @@ async function init() {
|
|
|
5103
5545
|
type: "text",
|
|
5104
5546
|
name: "themePath",
|
|
5105
5547
|
message: "Where should we create the theme file?",
|
|
5106
|
-
initial: DEFAULTS.THEME_FILE
|
|
5548
|
+
initial: DEFAULTS.THEME_FILE,
|
|
5549
|
+
validate: (value) => {
|
|
5550
|
+
if (!value || value.trim().length === 0) {
|
|
5551
|
+
return "Theme path is required";
|
|
5552
|
+
}
|
|
5553
|
+
if (path7.isAbsolute(value)) {
|
|
5554
|
+
return "Please use a relative path (e.g., ./src/lib/pdfx-theme.ts)";
|
|
5555
|
+
}
|
|
5556
|
+
if (!value.endsWith(".ts") && !value.endsWith(".tsx")) {
|
|
5557
|
+
return "Theme file must have .ts or .tsx extension (e.g., ./src/lib/pdfx-theme.ts)";
|
|
5558
|
+
}
|
|
5559
|
+
return true;
|
|
5560
|
+
}
|
|
5107
5561
|
}
|
|
5108
5562
|
],
|
|
5109
5563
|
{
|
|
5110
5564
|
onCancel: () => {
|
|
5111
|
-
console.log(
|
|
5565
|
+
console.log(chalk5.yellow("\nSetup cancelled."));
|
|
5112
5566
|
process.exit(0);
|
|
5113
5567
|
}
|
|
5114
5568
|
}
|
|
5115
5569
|
);
|
|
5116
5570
|
if (!answers.componentDir || !answers.registry) {
|
|
5117
|
-
console.error(
|
|
5571
|
+
console.error(chalk5.red("Missing required fields. Run pdfx init again."));
|
|
5118
5572
|
process.exit(1);
|
|
5119
5573
|
}
|
|
5120
5574
|
const config = {
|
|
@@ -5126,54 +5580,63 @@ async function init() {
|
|
|
5126
5580
|
const validation = configSchema.safeParse(config);
|
|
5127
5581
|
if (!validation.success) {
|
|
5128
5582
|
const issues = validation.error.issues.map((i) => i.message).join(", ");
|
|
5129
|
-
console.error(
|
|
5583
|
+
console.error(chalk5.red(`Invalid configuration: ${issues}`));
|
|
5130
5584
|
process.exit(1);
|
|
5131
5585
|
}
|
|
5132
|
-
const spinner =
|
|
5586
|
+
const spinner = ora4("Creating config and theme files...").start();
|
|
5133
5587
|
try {
|
|
5134
|
-
|
|
5588
|
+
const componentDirPath = path7.resolve(process.cwd(), answers.componentDir);
|
|
5589
|
+
ensureDir(componentDirPath);
|
|
5590
|
+
fs7.writeFileSync(path7.join(process.cwd(), "pdfx.json"), JSON.stringify(config, null, 2));
|
|
5135
5591
|
const presetName = answers.themePreset || "professional";
|
|
5136
5592
|
const preset = themePresets[presetName];
|
|
5137
|
-
const themePath =
|
|
5138
|
-
ensureDir(
|
|
5139
|
-
|
|
5140
|
-
const contextPath =
|
|
5141
|
-
|
|
5593
|
+
const themePath = path7.resolve(process.cwd(), config.theme);
|
|
5594
|
+
ensureDir(path7.dirname(themePath));
|
|
5595
|
+
fs7.writeFileSync(themePath, generateThemeFile(preset), "utf-8");
|
|
5596
|
+
const contextPath = path7.join(path7.dirname(themePath), "pdfx-theme-context.tsx");
|
|
5597
|
+
fs7.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
|
|
5142
5598
|
spinner.succeed(`Created pdfx.json + ${config.theme} (${presetName} theme)`);
|
|
5143
|
-
console.log(
|
|
5144
|
-
console.log(
|
|
5145
|
-
console.log(
|
|
5146
|
-
Components: ${
|
|
5147
|
-
console.log(
|
|
5599
|
+
console.log(chalk5.green("\nSuccess! You can now run:"));
|
|
5600
|
+
console.log(chalk5.cyan(" pdfx add heading"));
|
|
5601
|
+
console.log(chalk5.dim(`
|
|
5602
|
+
Components: ${path7.resolve(process.cwd(), answers.componentDir)}`));
|
|
5603
|
+
console.log(chalk5.dim(` Theme: ${path7.resolve(process.cwd(), config.theme)}
|
|
5148
5604
|
`));
|
|
5149
5605
|
} catch (error) {
|
|
5150
5606
|
spinner.fail("Failed to create config");
|
|
5151
5607
|
const message = error instanceof Error ? error.message : String(error);
|
|
5152
|
-
console.error(
|
|
5608
|
+
console.error(chalk5.dim(` ${message}`));
|
|
5153
5609
|
process.exit(1);
|
|
5154
5610
|
}
|
|
5155
5611
|
}
|
|
5156
5612
|
|
|
5157
5613
|
// src/commands/list.ts
|
|
5158
|
-
import
|
|
5159
|
-
import
|
|
5160
|
-
import
|
|
5614
|
+
import path8 from "path";
|
|
5615
|
+
import chalk6 from "chalk";
|
|
5616
|
+
import ora5 from "ora";
|
|
5161
5617
|
var FETCH_TIMEOUT_MS2 = 1e4;
|
|
5162
5618
|
async function list() {
|
|
5163
|
-
const configPath =
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
|
|
5167
|
-
|
|
5168
|
-
|
|
5169
|
-
|
|
5170
|
-
|
|
5171
|
-
|
|
5172
|
-
|
|
5173
|
-
|
|
5619
|
+
const configPath = path8.join(process.cwd(), "pdfx.json");
|
|
5620
|
+
let config;
|
|
5621
|
+
let hasLocalProject = false;
|
|
5622
|
+
if (checkFileExists(configPath)) {
|
|
5623
|
+
const raw = readJsonFile(configPath);
|
|
5624
|
+
const configResult = configSchema.safeParse(raw);
|
|
5625
|
+
if (!configResult.success) {
|
|
5626
|
+
console.error(chalk6.red("Invalid pdfx.json"));
|
|
5627
|
+
process.exit(1);
|
|
5628
|
+
}
|
|
5629
|
+
config = configResult.data;
|
|
5630
|
+
hasLocalProject = true;
|
|
5631
|
+
} else {
|
|
5632
|
+
config = {
|
|
5633
|
+
registry: "https://pdfx.akashpise.dev/r",
|
|
5634
|
+
componentDir: "./src/components/pdfx",
|
|
5635
|
+
theme: "./src/lib/pdfx-theme.ts"
|
|
5636
|
+
};
|
|
5637
|
+
console.log(chalk6.dim("No pdfx.json found. Listing components from default registry.\n"));
|
|
5174
5638
|
}
|
|
5175
|
-
const
|
|
5176
|
-
const spinner = ora4("Fetching component list...").start();
|
|
5639
|
+
const spinner = ora5("Fetching component list...").start();
|
|
5177
5640
|
try {
|
|
5178
5641
|
let response;
|
|
5179
5642
|
try {
|
|
@@ -5183,7 +5646,9 @@ async function list() {
|
|
|
5183
5646
|
} catch (err) {
|
|
5184
5647
|
const isTimeout = err instanceof Error && err.name === "TimeoutError";
|
|
5185
5648
|
throw new NetworkError(
|
|
5186
|
-
isTimeout ?
|
|
5649
|
+
isTimeout ? `Registry request timed out after 10 seconds.
|
|
5650
|
+
${chalk6.dim("Check your internet connection or try again later.")}` : `Could not reach registry at ${config.registry}
|
|
5651
|
+
${chalk6.dim("Verify the URL is correct and you have internet access.")}`
|
|
5187
5652
|
);
|
|
5188
5653
|
}
|
|
5189
5654
|
if (!response.ok) {
|
|
@@ -5195,18 +5660,22 @@ async function list() {
|
|
|
5195
5660
|
throw new RegistryError("Invalid registry format");
|
|
5196
5661
|
}
|
|
5197
5662
|
spinner.stop();
|
|
5198
|
-
const targetDir = path5.resolve(process.cwd(), config.componentDir);
|
|
5199
5663
|
const components = result.data.items.filter((item) => item.type === "registry:ui");
|
|
5200
|
-
console.log(
|
|
5664
|
+
console.log(chalk6.bold(`
|
|
5201
5665
|
Available Components (${components.length})
|
|
5202
5666
|
`));
|
|
5203
5667
|
for (const item of components) {
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5668
|
+
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
|
+
console.log(` ${"".padEnd(20)} ${status}`);
|
|
5676
|
+
} else {
|
|
5677
|
+
console.log(` ${chalk6.cyan(item.name.padEnd(20))} ${item.description}`);
|
|
5678
|
+
}
|
|
5210
5679
|
console.log();
|
|
5211
5680
|
}
|
|
5212
5681
|
} catch (error) {
|
|
@@ -5217,10 +5686,10 @@ async function list() {
|
|
|
5217
5686
|
}
|
|
5218
5687
|
|
|
5219
5688
|
// src/commands/template.ts
|
|
5220
|
-
import
|
|
5221
|
-
import
|
|
5222
|
-
import
|
|
5223
|
-
import
|
|
5689
|
+
import path9 from "path";
|
|
5690
|
+
import chalk7 from "chalk";
|
|
5691
|
+
import ora6 from "ora";
|
|
5692
|
+
import prompts4 from "prompts";
|
|
5224
5693
|
function readConfig2(configPath) {
|
|
5225
5694
|
const raw = readJsonFile(configPath);
|
|
5226
5695
|
const result = configSchema.safeParse(raw);
|
|
@@ -5228,7 +5697,7 @@ function readConfig2(configPath) {
|
|
|
5228
5697
|
const issues = result.error.issues.map((i) => i.message).join(", ");
|
|
5229
5698
|
throw new ConfigError(
|
|
5230
5699
|
`Invalid pdfx.json: ${issues}`,
|
|
5231
|
-
`Fix the config or re-run ${
|
|
5700
|
+
`Fix the config or re-run ${chalk7.cyan("pdfx init")}`
|
|
5232
5701
|
);
|
|
5233
5702
|
}
|
|
5234
5703
|
return result.data;
|
|
@@ -5295,7 +5764,7 @@ async function fetchComponent2(name, registryUrl) {
|
|
|
5295
5764
|
}
|
|
5296
5765
|
function resolveTemplateImports(content, templateName, config) {
|
|
5297
5766
|
const cwd = process.cwd();
|
|
5298
|
-
const templateSubdir =
|
|
5767
|
+
const templateSubdir = path9.resolve(
|
|
5299
5768
|
cwd,
|
|
5300
5769
|
config.templateDir ?? DEFAULTS.TEMPLATE_DIR,
|
|
5301
5770
|
templateName
|
|
@@ -5303,26 +5772,26 @@ function resolveTemplateImports(content, templateName, config) {
|
|
|
5303
5772
|
let result = content.replace(
|
|
5304
5773
|
/from '\.\.\/\.\.\/components\/pdfx\/([a-z][a-z0-9-]*)\/pdfx-([a-z][a-z0-9-]*)'/g,
|
|
5305
5774
|
(_match, componentName) => {
|
|
5306
|
-
const absCompFile =
|
|
5775
|
+
const absCompFile = path9.resolve(
|
|
5307
5776
|
cwd,
|
|
5308
5777
|
config.componentDir,
|
|
5309
5778
|
componentName,
|
|
5310
5779
|
`pdfx-${componentName}`
|
|
5311
5780
|
);
|
|
5312
|
-
let rel =
|
|
5781
|
+
let rel = path9.relative(templateSubdir, absCompFile);
|
|
5313
5782
|
if (!rel.startsWith(".")) rel = `./${rel}`;
|
|
5314
5783
|
return `from '${rel}'`;
|
|
5315
5784
|
}
|
|
5316
5785
|
);
|
|
5317
5786
|
if (config.theme) {
|
|
5318
|
-
const absThemePath =
|
|
5319
|
-
let relTheme =
|
|
5787
|
+
const absThemePath = path9.resolve(cwd, config.theme).replace(/\.tsx?$/, "");
|
|
5788
|
+
let relTheme = path9.relative(templateSubdir, absThemePath);
|
|
5320
5789
|
if (!relTheme.startsWith(".")) relTheme = `./${relTheme}`;
|
|
5321
|
-
const absContextPath =
|
|
5322
|
-
|
|
5790
|
+
const absContextPath = path9.join(
|
|
5791
|
+
path9.dirname(path9.resolve(cwd, config.theme)),
|
|
5323
5792
|
"pdfx-theme-context"
|
|
5324
5793
|
);
|
|
5325
|
-
let relContext =
|
|
5794
|
+
let relContext = path9.relative(templateSubdir, absContextPath);
|
|
5326
5795
|
if (!relContext.startsWith(".")) relContext = `./${relContext}`;
|
|
5327
5796
|
result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme'/g, `from '${relTheme}'`);
|
|
5328
5797
|
result = result.replace(/from '\.\.\/\.\.\/lib\/pdfx-theme-context'/g, `from '${relContext}'`);
|
|
@@ -5331,10 +5800,10 @@ function resolveTemplateImports(content, templateName, config) {
|
|
|
5331
5800
|
}
|
|
5332
5801
|
async function resolveConflict(fileName, currentDecision) {
|
|
5333
5802
|
if (currentDecision === "overwrite-all") return "overwrite-all";
|
|
5334
|
-
const { action } = await
|
|
5803
|
+
const { action } = await prompts4({
|
|
5335
5804
|
type: "select",
|
|
5336
5805
|
name: "action",
|
|
5337
|
-
message: `${
|
|
5806
|
+
message: `${chalk7.yellow(fileName)} already exists. What would you like to do?`,
|
|
5338
5807
|
choices: [
|
|
5339
5808
|
{ title: "Skip", value: "skip", description: "Keep the existing file unchanged" },
|
|
5340
5809
|
{ title: "Overwrite", value: "overwrite", description: "Replace this file only" },
|
|
@@ -5355,14 +5824,14 @@ async function ensurePeerComponents(template, config, force) {
|
|
|
5355
5824
|
if (!template.peerComponents || template.peerComponents.length === 0) {
|
|
5356
5825
|
return { installedPeers, peerWarnings };
|
|
5357
5826
|
}
|
|
5358
|
-
const componentBaseDir =
|
|
5827
|
+
const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
|
|
5359
5828
|
for (const componentName of template.peerComponents) {
|
|
5360
|
-
const componentDir =
|
|
5361
|
-
const expectedMain =
|
|
5829
|
+
const componentDir = path9.join(componentBaseDir, componentName);
|
|
5830
|
+
const expectedMain = path9.join(componentDir, `pdfx-${componentName}.tsx`);
|
|
5362
5831
|
if (checkFileExists(componentDir)) {
|
|
5363
5832
|
if (!checkFileExists(expectedMain)) {
|
|
5364
5833
|
peerWarnings.push(
|
|
5365
|
-
`${componentName}: directory exists but expected file missing (${
|
|
5834
|
+
`${componentName}: directory exists but expected file missing (${path9.basename(expectedMain)})`
|
|
5366
5835
|
);
|
|
5367
5836
|
} else {
|
|
5368
5837
|
peerWarnings.push(
|
|
@@ -5373,9 +5842,9 @@ async function ensurePeerComponents(template, config, force) {
|
|
|
5373
5842
|
}
|
|
5374
5843
|
const component = await fetchComponent2(componentName, config.registry);
|
|
5375
5844
|
ensureDir(componentDir);
|
|
5376
|
-
const componentRelDir =
|
|
5845
|
+
const componentRelDir = path9.join(config.componentDir, component.name);
|
|
5377
5846
|
for (const file of component.files) {
|
|
5378
|
-
const fileName =
|
|
5847
|
+
const fileName = path9.basename(file.path);
|
|
5379
5848
|
const filePath = safePath(componentDir, fileName);
|
|
5380
5849
|
let content = file.content;
|
|
5381
5850
|
if (config.theme && (content.includes("pdfx-theme") || content.includes("pdfx-theme-context"))) {
|
|
@@ -5396,12 +5865,12 @@ async function ensurePeerComponents(template, config, force) {
|
|
|
5396
5865
|
async function installTemplate(name, config, force) {
|
|
5397
5866
|
const template = await fetchTemplate(name, config.registry);
|
|
5398
5867
|
const peerResult = await ensurePeerComponents(template, config, force);
|
|
5399
|
-
const templateBaseDir =
|
|
5400
|
-
const templateDir =
|
|
5868
|
+
const templateBaseDir = path9.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
|
|
5869
|
+
const templateDir = path9.join(templateBaseDir, template.name);
|
|
5401
5870
|
ensureDir(templateDir);
|
|
5402
5871
|
const filesToWrite = [];
|
|
5403
5872
|
for (const file of template.files) {
|
|
5404
|
-
const fileName =
|
|
5873
|
+
const fileName = path9.basename(file.path);
|
|
5405
5874
|
const filePath = safePath(templateDir, fileName);
|
|
5406
5875
|
let content = file.content;
|
|
5407
5876
|
if (/\.(tsx?|jsx?)$/.test(fileName) && content.includes("../../")) {
|
|
@@ -5414,7 +5883,7 @@ async function installTemplate(name, config, force) {
|
|
|
5414
5883
|
const resolved = [];
|
|
5415
5884
|
for (const file of filesToWrite) {
|
|
5416
5885
|
if (checkFileExists(file.filePath)) {
|
|
5417
|
-
const decision = await resolveConflict(
|
|
5886
|
+
const decision = await resolveConflict(path9.basename(file.filePath), globalDecision);
|
|
5418
5887
|
if (decision === "overwrite-all") {
|
|
5419
5888
|
globalDecision = "overwrite-all";
|
|
5420
5889
|
}
|
|
@@ -5427,7 +5896,7 @@ async function installTemplate(name, config, force) {
|
|
|
5427
5896
|
if (!file.skip) {
|
|
5428
5897
|
writeFile(file.filePath, file.content);
|
|
5429
5898
|
} else {
|
|
5430
|
-
console.log(
|
|
5899
|
+
console.log(chalk7.dim(` skipped ${path9.basename(file.filePath)}`));
|
|
5431
5900
|
}
|
|
5432
5901
|
}
|
|
5433
5902
|
} else {
|
|
@@ -5436,37 +5905,37 @@ async function installTemplate(name, config, force) {
|
|
|
5436
5905
|
}
|
|
5437
5906
|
}
|
|
5438
5907
|
if (template.peerComponents && template.peerComponents.length > 0) {
|
|
5439
|
-
const componentBaseDir =
|
|
5908
|
+
const componentBaseDir = path9.resolve(process.cwd(), config.componentDir);
|
|
5440
5909
|
const missing = [];
|
|
5441
5910
|
for (const comp of template.peerComponents) {
|
|
5442
|
-
const compDir =
|
|
5911
|
+
const compDir = path9.join(componentBaseDir, comp);
|
|
5443
5912
|
if (!checkFileExists(compDir)) {
|
|
5444
5913
|
missing.push(comp);
|
|
5445
5914
|
}
|
|
5446
5915
|
}
|
|
5447
5916
|
if (missing.length > 0) {
|
|
5448
5917
|
console.log();
|
|
5449
|
-
console.log(
|
|
5918
|
+
console.log(chalk7.yellow(" Missing peer components:"));
|
|
5450
5919
|
for (const comp of missing) {
|
|
5451
|
-
console.log(
|
|
5920
|
+
console.log(chalk7.dim(` ${comp} \u2192 run: ${chalk7.cyan(`pdfx add ${comp}`)}`));
|
|
5452
5921
|
}
|
|
5453
5922
|
}
|
|
5454
5923
|
}
|
|
5455
5924
|
if (config.theme) {
|
|
5456
|
-
const absThemePath =
|
|
5457
|
-
const contextPath =
|
|
5925
|
+
const absThemePath = path9.resolve(process.cwd(), config.theme);
|
|
5926
|
+
const contextPath = path9.join(path9.dirname(absThemePath), "pdfx-theme-context.tsx");
|
|
5458
5927
|
if (!checkFileExists(contextPath)) {
|
|
5459
|
-
ensureDir(
|
|
5928
|
+
ensureDir(path9.dirname(contextPath));
|
|
5460
5929
|
writeFile(contextPath, generateThemeContextFile());
|
|
5461
5930
|
}
|
|
5462
5931
|
}
|
|
5463
5932
|
return peerResult;
|
|
5464
5933
|
}
|
|
5465
5934
|
async function templateAdd(names, options = {}) {
|
|
5466
|
-
const configPath =
|
|
5935
|
+
const configPath = path9.join(process.cwd(), "pdfx.json");
|
|
5467
5936
|
if (!checkFileExists(configPath)) {
|
|
5468
|
-
console.error(
|
|
5469
|
-
console.log(
|
|
5937
|
+
console.error(chalk7.red("Error: pdfx.json not found"));
|
|
5938
|
+
console.log(chalk7.yellow("Run: pdfx init"));
|
|
5470
5939
|
process.exit(1);
|
|
5471
5940
|
}
|
|
5472
5941
|
let config;
|
|
@@ -5474,11 +5943,11 @@ async function templateAdd(names, options = {}) {
|
|
|
5474
5943
|
config = readConfig2(configPath);
|
|
5475
5944
|
} catch (error) {
|
|
5476
5945
|
if (error instanceof ConfigError) {
|
|
5477
|
-
console.error(
|
|
5478
|
-
if (error.suggestion) console.log(
|
|
5946
|
+
console.error(chalk7.red(error.message));
|
|
5947
|
+
if (error.suggestion) console.log(chalk7.yellow(` Hint: ${error.suggestion}`));
|
|
5479
5948
|
} else {
|
|
5480
5949
|
const message = error instanceof Error ? error.message : String(error);
|
|
5481
|
-
console.error(
|
|
5950
|
+
console.error(chalk7.red(message));
|
|
5482
5951
|
}
|
|
5483
5952
|
process.exit(1);
|
|
5484
5953
|
}
|
|
@@ -5487,24 +5956,24 @@ async function templateAdd(names, options = {}) {
|
|
|
5487
5956
|
for (const templateName of names) {
|
|
5488
5957
|
const nameResult = componentNameSchema.safeParse(templateName);
|
|
5489
5958
|
if (!nameResult.success) {
|
|
5490
|
-
console.error(
|
|
5959
|
+
console.error(chalk7.red(`Invalid template name: "${templateName}"`));
|
|
5491
5960
|
console.log(
|
|
5492
|
-
|
|
5961
|
+
chalk7.dim(' Names must be lowercase alphanumeric with hyphens (e.g., "invoice-classic")')
|
|
5493
5962
|
);
|
|
5494
5963
|
failed.push(templateName);
|
|
5495
5964
|
continue;
|
|
5496
5965
|
}
|
|
5497
|
-
const spinner =
|
|
5966
|
+
const spinner = ora6(`Adding template ${templateName}...`).start();
|
|
5498
5967
|
try {
|
|
5499
5968
|
const result = await installTemplate(templateName, config, force);
|
|
5500
|
-
spinner.succeed(`Added template ${
|
|
5969
|
+
spinner.succeed(`Added template ${chalk7.cyan(templateName)}`);
|
|
5501
5970
|
if (result.installedPeers.length > 0) {
|
|
5502
5971
|
console.log(
|
|
5503
|
-
|
|
5972
|
+
chalk7.green(` Installed required components: ${result.installedPeers.join(", ")}`)
|
|
5504
5973
|
);
|
|
5505
5974
|
}
|
|
5506
5975
|
for (const warning of result.peerWarnings) {
|
|
5507
|
-
console.log(
|
|
5976
|
+
console.log(chalk7.yellow(` Warning: ${warning}`));
|
|
5508
5977
|
}
|
|
5509
5978
|
} catch (error) {
|
|
5510
5979
|
if (error instanceof ValidationError && error.message.includes("Cancelled")) {
|
|
@@ -5513,24 +5982,24 @@ async function templateAdd(names, options = {}) {
|
|
|
5513
5982
|
} else if (error instanceof NetworkError || error instanceof RegistryError || error instanceof ValidationError) {
|
|
5514
5983
|
spinner.fail(error.message);
|
|
5515
5984
|
if (error.suggestion) {
|
|
5516
|
-
console.log(
|
|
5985
|
+
console.log(chalk7.dim(` Hint: ${error.suggestion}`));
|
|
5517
5986
|
}
|
|
5518
5987
|
} else {
|
|
5519
5988
|
spinner.fail(`Failed to add template ${templateName}`);
|
|
5520
5989
|
const message = error instanceof Error ? error.message : String(error);
|
|
5521
|
-
console.error(
|
|
5990
|
+
console.error(chalk7.dim(` ${message}`));
|
|
5522
5991
|
}
|
|
5523
5992
|
failed.push(templateName);
|
|
5524
5993
|
}
|
|
5525
5994
|
}
|
|
5526
5995
|
console.log();
|
|
5527
5996
|
if (failed.length > 0) {
|
|
5528
|
-
console.log(
|
|
5997
|
+
console.log(chalk7.yellow(`Failed: ${failed.join(", ")}`));
|
|
5529
5998
|
}
|
|
5530
5999
|
if (failed.length < names.length) {
|
|
5531
|
-
const resolvedDir =
|
|
5532
|
-
console.log(
|
|
5533
|
-
console.log(
|
|
6000
|
+
const resolvedDir = path9.resolve(process.cwd(), config.templateDir ?? DEFAULTS.TEMPLATE_DIR);
|
|
6001
|
+
console.log(chalk7.green("Done!"));
|
|
6002
|
+
console.log(chalk7.dim(`Templates installed to: ${resolvedDir}
|
|
5534
6003
|
`));
|
|
5535
6004
|
}
|
|
5536
6005
|
if (failed.length > 0) {
|
|
@@ -5538,20 +6007,20 @@ async function templateAdd(names, options = {}) {
|
|
|
5538
6007
|
}
|
|
5539
6008
|
}
|
|
5540
6009
|
async function templateList() {
|
|
5541
|
-
const configPath =
|
|
6010
|
+
const configPath = path9.join(process.cwd(), "pdfx.json");
|
|
5542
6011
|
if (!checkFileExists(configPath)) {
|
|
5543
|
-
console.error(
|
|
5544
|
-
console.log(
|
|
6012
|
+
console.error(chalk7.red("Error: pdfx.json not found"));
|
|
6013
|
+
console.log(chalk7.yellow("Run: pdfx init"));
|
|
5545
6014
|
process.exit(1);
|
|
5546
6015
|
}
|
|
5547
6016
|
const raw = readJsonFile(configPath);
|
|
5548
6017
|
const configResult = configSchema.safeParse(raw);
|
|
5549
6018
|
if (!configResult.success) {
|
|
5550
|
-
console.error(
|
|
6019
|
+
console.error(chalk7.red("Invalid pdfx.json"));
|
|
5551
6020
|
process.exit(1);
|
|
5552
6021
|
}
|
|
5553
6022
|
const config = configResult.data;
|
|
5554
|
-
const spinner =
|
|
6023
|
+
const spinner = ora6("Fetching template list...").start();
|
|
5555
6024
|
try {
|
|
5556
6025
|
let response;
|
|
5557
6026
|
try {
|
|
@@ -5575,28 +6044,28 @@ async function templateList() {
|
|
|
5575
6044
|
spinner.stop();
|
|
5576
6045
|
const templates = result.data.items.filter((item) => item.type === "registry:template");
|
|
5577
6046
|
if (templates.length === 0) {
|
|
5578
|
-
console.log(
|
|
6047
|
+
console.log(chalk7.dim("\n No templates available in the registry.\n"));
|
|
5579
6048
|
return;
|
|
5580
6049
|
}
|
|
5581
|
-
const templateBaseDir =
|
|
6050
|
+
const templateBaseDir = path9.resolve(
|
|
5582
6051
|
process.cwd(),
|
|
5583
6052
|
config.templateDir ?? DEFAULTS.TEMPLATE_DIR
|
|
5584
6053
|
);
|
|
5585
|
-
console.log(
|
|
6054
|
+
console.log(chalk7.bold(`
|
|
5586
6055
|
Available Templates (${templates.length})
|
|
5587
6056
|
`));
|
|
5588
6057
|
for (const item of templates) {
|
|
5589
|
-
const templateDir =
|
|
6058
|
+
const templateDir = path9.join(templateBaseDir, item.name);
|
|
5590
6059
|
const installed = checkFileExists(templateDir);
|
|
5591
|
-
const status = installed ?
|
|
5592
|
-
console.log(` ${
|
|
6060
|
+
const status = installed ? chalk7.green("[installed]") : chalk7.dim("[not installed]");
|
|
6061
|
+
console.log(` ${chalk7.cyan(item.name.padEnd(22))} ${item.description ?? ""}`);
|
|
5593
6062
|
console.log(` ${"".padEnd(22)} ${status}`);
|
|
5594
6063
|
if (item.peerComponents && item.peerComponents.length > 0) {
|
|
5595
|
-
console.log(
|
|
6064
|
+
console.log(chalk7.dim(` ${"".padEnd(22)} requires: ${item.peerComponents.join(", ")}`));
|
|
5596
6065
|
}
|
|
5597
6066
|
console.log();
|
|
5598
6067
|
}
|
|
5599
|
-
console.log(
|
|
6068
|
+
console.log(chalk7.dim(` Install with: ${chalk7.cyan("pdfx template add <template-name>")}
|
|
5600
6069
|
`));
|
|
5601
6070
|
} catch (error) {
|
|
5602
6071
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -5606,15 +6075,23 @@ async function templateList() {
|
|
|
5606
6075
|
}
|
|
5607
6076
|
|
|
5608
6077
|
// src/commands/theme.ts
|
|
5609
|
-
import
|
|
5610
|
-
import
|
|
5611
|
-
import
|
|
5612
|
-
import
|
|
5613
|
-
import
|
|
6078
|
+
import fs8 from "fs";
|
|
6079
|
+
import path10 from "path";
|
|
6080
|
+
import chalk8 from "chalk";
|
|
6081
|
+
import ora7 from "ora";
|
|
6082
|
+
import prompts5 from "prompts";
|
|
5614
6083
|
import ts from "typescript";
|
|
5615
6084
|
async function themeInit() {
|
|
5616
|
-
|
|
5617
|
-
|
|
6085
|
+
const configPath = path10.join(process.cwd(), "pdfx.json");
|
|
6086
|
+
if (!fs8.existsSync(configPath)) {
|
|
6087
|
+
console.error(chalk8.red("\nError: pdfx.json not found"));
|
|
6088
|
+
console.log(chalk8.yellow("\n PDFx is not initialized in this project.\n"));
|
|
6089
|
+
console.log(chalk8.cyan(" Run: pdfx init"));
|
|
6090
|
+
console.log(chalk8.dim(" This will set up your project configuration and theme.\n"));
|
|
6091
|
+
process.exit(1);
|
|
6092
|
+
}
|
|
6093
|
+
console.log(chalk8.bold.cyan("\n PDFx Theme Setup\n"));
|
|
6094
|
+
const answers = await prompts5(
|
|
5618
6095
|
[
|
|
5619
6096
|
{
|
|
5620
6097
|
type: "select",
|
|
@@ -5648,102 +6125,104 @@ async function themeInit() {
|
|
|
5648
6125
|
],
|
|
5649
6126
|
{
|
|
5650
6127
|
onCancel: () => {
|
|
5651
|
-
console.log(
|
|
6128
|
+
console.log(chalk8.yellow("\nTheme setup cancelled."));
|
|
5652
6129
|
process.exit(0);
|
|
5653
6130
|
}
|
|
5654
6131
|
}
|
|
5655
6132
|
);
|
|
5656
6133
|
if (!answers.preset || !answers.themePath) {
|
|
5657
|
-
console.error(
|
|
6134
|
+
console.error(chalk8.red("Missing required fields."));
|
|
5658
6135
|
process.exit(1);
|
|
5659
6136
|
}
|
|
5660
6137
|
const presetName = answers.preset;
|
|
5661
6138
|
const themePath = answers.themePath;
|
|
5662
6139
|
const preset = themePresets[presetName];
|
|
5663
|
-
const spinner =
|
|
6140
|
+
const spinner = ora7(`Scaffolding ${presetName} theme...`).start();
|
|
5664
6141
|
try {
|
|
5665
|
-
const absThemePath =
|
|
5666
|
-
ensureDir(
|
|
5667
|
-
|
|
5668
|
-
const contextPath =
|
|
5669
|
-
|
|
6142
|
+
const absThemePath = path10.resolve(process.cwd(), themePath);
|
|
6143
|
+
ensureDir(path10.dirname(absThemePath));
|
|
6144
|
+
fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
|
|
6145
|
+
const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
|
|
6146
|
+
fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
|
|
5670
6147
|
spinner.succeed(`Created ${themePath} with ${presetName} theme`);
|
|
5671
|
-
const
|
|
5672
|
-
if (
|
|
6148
|
+
const configPath2 = path10.join(process.cwd(), "pdfx.json");
|
|
6149
|
+
if (fs8.existsSync(configPath2)) {
|
|
5673
6150
|
try {
|
|
5674
|
-
const rawConfig = readJsonFile(
|
|
6151
|
+
const rawConfig = readJsonFile(configPath2);
|
|
5675
6152
|
const result = configSchema.safeParse(rawConfig);
|
|
5676
6153
|
if (result.success) {
|
|
5677
6154
|
const updatedConfig = { ...result.data, theme: themePath };
|
|
5678
|
-
|
|
5679
|
-
console.log(
|
|
6155
|
+
fs8.writeFileSync(configPath2, JSON.stringify(updatedConfig, null, 2), "utf-8");
|
|
6156
|
+
console.log(chalk8.green(" Updated pdfx.json with theme path"));
|
|
5680
6157
|
}
|
|
5681
6158
|
} catch {
|
|
5682
|
-
console.log(
|
|
6159
|
+
console.log(chalk8.yellow(' Could not update pdfx.json \u2014 add "theme" field manually'));
|
|
5683
6160
|
}
|
|
5684
6161
|
}
|
|
5685
|
-
console.log(
|
|
6162
|
+
console.log(chalk8.dim(`
|
|
5686
6163
|
Edit ${themePath} to customize your theme.
|
|
5687
6164
|
`));
|
|
5688
6165
|
} catch (error) {
|
|
5689
6166
|
spinner.fail("Failed to create theme file");
|
|
5690
6167
|
const message = error instanceof Error ? error.message : String(error);
|
|
5691
|
-
console.error(
|
|
6168
|
+
console.error(chalk8.dim(` ${message}`));
|
|
5692
6169
|
process.exit(1);
|
|
5693
6170
|
}
|
|
5694
6171
|
}
|
|
5695
6172
|
async function themeSwitch(presetName) {
|
|
6173
|
+
const resolvedPreset = presetName === "default" ? "professional" : presetName;
|
|
5696
6174
|
const validPresets = Object.keys(themePresets);
|
|
5697
|
-
if (!validPresets.includes(
|
|
5698
|
-
console.error(
|
|
5699
|
-
|
|
5700
|
-
|
|
6175
|
+
if (!validPresets.includes(resolvedPreset)) {
|
|
6176
|
+
console.error(chalk8.red(`\u2716 Invalid theme preset: "${presetName}"`));
|
|
6177
|
+
console.log(chalk8.dim(` Available presets: ${validPresets.join(", ")}, default
|
|
6178
|
+
`));
|
|
6179
|
+
console.log(chalk8.dim(" Usage: pdfx theme switch <preset>"));
|
|
5701
6180
|
process.exit(1);
|
|
5702
6181
|
}
|
|
5703
|
-
const validatedPreset =
|
|
5704
|
-
const configPath =
|
|
5705
|
-
if (!
|
|
5706
|
-
console.error(
|
|
6182
|
+
const validatedPreset = resolvedPreset;
|
|
6183
|
+
const configPath = path10.join(process.cwd(), "pdfx.json");
|
|
6184
|
+
if (!fs8.existsSync(configPath)) {
|
|
6185
|
+
console.error(chalk8.red('No pdfx.json found. Run "pdfx init" first.'));
|
|
5707
6186
|
process.exit(1);
|
|
5708
6187
|
}
|
|
5709
6188
|
const rawConfig = readJsonFile(configPath);
|
|
5710
6189
|
const result = configSchema.safeParse(rawConfig);
|
|
5711
6190
|
if (!result.success) {
|
|
5712
|
-
console.error(
|
|
6191
|
+
console.error(chalk8.red("Invalid pdfx.json configuration."));
|
|
5713
6192
|
process.exit(1);
|
|
5714
6193
|
}
|
|
5715
6194
|
const config = result.data;
|
|
5716
6195
|
if (!config.theme) {
|
|
5717
6196
|
console.error(
|
|
5718
|
-
|
|
6197
|
+
chalk8.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
|
|
5719
6198
|
);
|
|
5720
6199
|
process.exit(1);
|
|
5721
6200
|
}
|
|
5722
|
-
const answer = await
|
|
6201
|
+
const answer = await prompts5({
|
|
5723
6202
|
type: "confirm",
|
|
5724
6203
|
name: "confirm",
|
|
5725
6204
|
message: `This will overwrite ${config.theme} with the ${validatedPreset} preset. Continue?`,
|
|
5726
6205
|
initial: false
|
|
5727
6206
|
});
|
|
5728
6207
|
if (!answer.confirm) {
|
|
5729
|
-
console.log(
|
|
6208
|
+
console.log(chalk8.yellow("Cancelled."));
|
|
5730
6209
|
return;
|
|
5731
6210
|
}
|
|
5732
|
-
const spinner =
|
|
6211
|
+
const spinner = ora7(`Switching to ${validatedPreset} theme...`).start();
|
|
5733
6212
|
try {
|
|
5734
6213
|
const preset = themePresets[validatedPreset];
|
|
5735
|
-
const absThemePath =
|
|
5736
|
-
|
|
5737
|
-
const contextPath =
|
|
5738
|
-
if (!
|
|
5739
|
-
ensureDir(
|
|
5740
|
-
|
|
6214
|
+
const absThemePath = path10.resolve(process.cwd(), config.theme);
|
|
6215
|
+
fs8.writeFileSync(absThemePath, generateThemeFile(preset), "utf-8");
|
|
6216
|
+
const contextPath = path10.join(path10.dirname(absThemePath), "pdfx-theme-context.tsx");
|
|
6217
|
+
if (!fs8.existsSync(contextPath)) {
|
|
6218
|
+
ensureDir(path10.dirname(contextPath));
|
|
6219
|
+
fs8.writeFileSync(contextPath, generateThemeContextFile(), "utf-8");
|
|
5741
6220
|
}
|
|
5742
6221
|
spinner.succeed(`Switched to ${validatedPreset} theme`);
|
|
5743
6222
|
} catch (error) {
|
|
5744
6223
|
spinner.fail("Failed to switch theme");
|
|
5745
6224
|
const message = error instanceof Error ? error.message : String(error);
|
|
5746
|
-
console.error(
|
|
6225
|
+
console.error(chalk8.dim(` ${message}`));
|
|
5747
6226
|
process.exit(1);
|
|
5748
6227
|
}
|
|
5749
6228
|
}
|
|
@@ -5785,7 +6264,7 @@ function toPlainValue(node) {
|
|
|
5785
6264
|
return void 0;
|
|
5786
6265
|
}
|
|
5787
6266
|
function parseThemeObject(themePath) {
|
|
5788
|
-
const content =
|
|
6267
|
+
const content = fs8.readFileSync(themePath, "utf-8");
|
|
5789
6268
|
const sourceFile = ts.createSourceFile(
|
|
5790
6269
|
themePath,
|
|
5791
6270
|
content,
|
|
@@ -5811,54 +6290,68 @@ function parseThemeObject(themePath) {
|
|
|
5811
6290
|
throw new Error("No exported `theme` object found.");
|
|
5812
6291
|
}
|
|
5813
6292
|
async function themeValidate() {
|
|
5814
|
-
const configPath =
|
|
5815
|
-
if (!
|
|
5816
|
-
console.error(
|
|
6293
|
+
const configPath = path10.join(process.cwd(), "pdfx.json");
|
|
6294
|
+
if (!fs8.existsSync(configPath)) {
|
|
6295
|
+
console.error(chalk8.red('No pdfx.json found. Run "pdfx init" first.'));
|
|
5817
6296
|
process.exit(1);
|
|
5818
6297
|
}
|
|
5819
6298
|
const rawConfig = readJsonFile(configPath);
|
|
5820
6299
|
const configResult = configSchema.safeParse(rawConfig);
|
|
5821
6300
|
if (!configResult.success) {
|
|
5822
|
-
console.error(
|
|
6301
|
+
console.error(chalk8.red("Invalid pdfx.json configuration."));
|
|
5823
6302
|
process.exit(1);
|
|
5824
6303
|
}
|
|
5825
6304
|
if (!configResult.data.theme) {
|
|
5826
6305
|
console.error(
|
|
5827
|
-
|
|
6306
|
+
chalk8.red('No theme path in pdfx.json. Run "pdfx theme init" to set up theming.')
|
|
5828
6307
|
);
|
|
5829
6308
|
process.exit(1);
|
|
5830
6309
|
}
|
|
5831
|
-
const absThemePath =
|
|
5832
|
-
if (!
|
|
5833
|
-
console.error(
|
|
6310
|
+
const absThemePath = path10.resolve(process.cwd(), configResult.data.theme);
|
|
6311
|
+
if (!fs8.existsSync(absThemePath)) {
|
|
6312
|
+
console.error(chalk8.red(`Theme file not found: ${configResult.data.theme}`));
|
|
5834
6313
|
process.exit(1);
|
|
5835
6314
|
}
|
|
5836
|
-
const spinner =
|
|
6315
|
+
const spinner = ora7("Validating theme file...").start();
|
|
5837
6316
|
try {
|
|
5838
6317
|
const parsedTheme = parseThemeObject(absThemePath);
|
|
5839
6318
|
const result = themeSchema.safeParse(parsedTheme);
|
|
5840
6319
|
if (!result.success) {
|
|
5841
|
-
const
|
|
5842
|
-
spinner.fail(
|
|
6320
|
+
const issues = result.error.issues.map((issue) => ` \u2192 ${chalk8.yellow(issue.path.join("."))}: ${issue.message}`).join("\n");
|
|
6321
|
+
spinner.fail("Theme validation failed");
|
|
6322
|
+
console.log(chalk8.red("\n Missing or invalid fields:\n"));
|
|
6323
|
+
console.log(issues);
|
|
6324
|
+
console.log(chalk8.dim("\n Fix these fields in your theme file and run validate again.\n"));
|
|
5843
6325
|
process.exit(1);
|
|
5844
6326
|
}
|
|
5845
6327
|
spinner.succeed("Theme file is valid");
|
|
5846
|
-
console.log(
|
|
6328
|
+
console.log(chalk8.dim(`
|
|
5847
6329
|
Validated: ${configResult.data.theme}
|
|
5848
6330
|
`));
|
|
5849
6331
|
} catch (error) {
|
|
5850
6332
|
spinner.fail("Failed to validate theme");
|
|
5851
6333
|
const message = error instanceof Error ? error.message : String(error);
|
|
5852
|
-
console.error(
|
|
6334
|
+
console.error(chalk8.dim(` ${message}`));
|
|
5853
6335
|
process.exit(1);
|
|
5854
6336
|
}
|
|
5855
6337
|
}
|
|
5856
6338
|
|
|
5857
6339
|
// src/index.ts
|
|
5858
6340
|
var program = new Command();
|
|
5859
|
-
|
|
6341
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
6342
|
+
var __dirname = join(__filename, "..");
|
|
6343
|
+
var packageJsonPath = join(__dirname, "../package.json");
|
|
6344
|
+
var version = "0.1.3";
|
|
6345
|
+
try {
|
|
6346
|
+
const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
|
|
6347
|
+
version = pkg.version;
|
|
6348
|
+
} catch {
|
|
6349
|
+
}
|
|
6350
|
+
program.name("pdfx").description("CLI for PDFx components").version(version);
|
|
5860
6351
|
program.command("init").description("Initialize pdfx in your project").action(init);
|
|
5861
|
-
program.command("add <components...>").description("Add components to your project").option("-f, --force", "Overwrite existing files without prompting").
|
|
6352
|
+
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(
|
|
6353
|
+
(components, options) => add(components, options)
|
|
6354
|
+
);
|
|
5862
6355
|
program.command("list").description("List available components from registry").action(list);
|
|
5863
6356
|
program.command("diff <components...>").description("Compare local components with registry versions").action(diff);
|
|
5864
6357
|
var themeCmd = program.command("theme").description("Manage PDF themes");
|