@uxf/scripts 11.109.0 → 11.109.1

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/README.md CHANGED
@@ -72,8 +72,6 @@ All-in-one dependency health check for projects using `@uxf/*` packages. Runs tw
72
72
 
73
73
  Supports **yarn**, **npm**, **pnpm**, and **bun**. The package manager is auto-detected from the lock file.
74
74
 
75
- Requires `tsx` or another tool to execute typescript (typically already available in your project's `devDependencies`).
76
-
77
75
  ```bash
78
76
  Usage:
79
77
  uxf-dependencies-check [options]
@@ -91,16 +89,16 @@ Build-time dependencies (`yargs`, `fast-glob`) are automatically ignored in the
91
89
 
92
90
  ```bash
93
91
  # Run both checks (exits with code 1 if issues found)
94
- npx tsx -dependencies-check
92
+ npx uxf-dependencies-check
95
93
 
96
94
  # Auto-install missing peer deps
97
- npx tsx uxf-dependencies-check --fix
95
+ npx uxf-dependencies-check --fix
98
96
 
99
97
  # Preview what would be installed
100
- npx tsx uxf-dependencies-check --dry-run
98
+ npx uxf-dependencies-check --dry-run
101
99
 
102
100
  # Ignore specific packages in conflict check
103
- npx tsx uxf-dependencies-check --exclude lodash dayjs
101
+ npx uxf-dependencies-check --exclude lodash dayjs
104
102
  ```
105
103
 
106
104
  ### What it checks
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const cli_1 = __importDefault(require("../src/uxf-dependencies-check/cli"));
8
+ (0, cli_1.default)()
9
+ .then((exitCode) => {
10
+ process.exitCode = exitCode;
11
+ })
12
+ .catch((e) => {
13
+ console.error(e); // eslint-disable-line no-console
14
+ process.exitCode = 1;
15
+ });
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@uxf/scripts",
3
- "version": "11.109.0",
3
+ "version": "11.109.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "uxf-audit": "bin/uxf-audit.js",
8
8
  "uxf-claude-sync": "bin/uxf-claude-sync.js",
9
- "uxf-dependencies-check": "bin/uxf-dependencies-check.ts",
9
+ "uxf-dependencies-check": "bin/uxf-dependencies-check.js",
10
10
  "uxf-i18n-namespaces-gen": "bin/uxf-i18n-namespaces-gen.js",
11
11
  "uxf-lunch": "bin/uxf-lunch.js",
12
12
  "uxf-push-notifier": "bin/uxf-push-notifier.js",
@@ -16,7 +16,7 @@
16
16
  "uxf-unused": "bin/uxf-unused.js"
17
17
  },
18
18
  "scripts": {
19
- "build": "",
19
+ "build": "tsc -P tsconfig.build.json && chmod +x ./bin/*",
20
20
  "run:mr-notifier": "GOOGLE_WEBHOOK_URL=<<TODO>> GITLAB_TOKEN=<<TODO>> CI_SERVER_URL=https://gitlab.uxf.cz node ./bin/uxf-merge-requests-notifier.js",
21
21
  "test": "./node_modules/.bin/eslint ./bin",
22
22
  "typecheck": "tsc --noEmit -p tsconfig.json"
@@ -0,0 +1,2 @@
1
+ declare const _default: () => Promise<number>;
2
+ export default _default;
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ const index_1 = require("./index");
37
+ exports.default = async () => {
38
+ const yargs = (await Promise.resolve().then(() => __importStar(require("yargs")))).default;
39
+ const { hideBin } = await Promise.resolve().then(() => __importStar(require("yargs/helpers")));
40
+ const args = hideBin(process.argv);
41
+ const isHelp = args.includes("--help") || args.includes("-h");
42
+ const cli = yargs(args)
43
+ .usage("Usage: uxf-dependencies-check [options]")
44
+ .option("fix", {
45
+ type: "boolean",
46
+ default: false,
47
+ describe: "Auto-install missing/mismatched peer dependencies",
48
+ })
49
+ .option("dry-run", {
50
+ type: "boolean",
51
+ default: false,
52
+ describe: "Show what would be installed without changes",
53
+ })
54
+ .option("exclude", {
55
+ alias: "e",
56
+ type: "array",
57
+ string: true,
58
+ default: [],
59
+ describe: "Packages to ignore in conflict check",
60
+ })
61
+ .strict()
62
+ .exitProcess(false);
63
+ try {
64
+ const argv = await cli.parse();
65
+ if (isHelp) {
66
+ return 0;
67
+ }
68
+ return await (0, index_1.checkUxfDependencies)({
69
+ isFix: Boolean(argv.fix),
70
+ isDryRun: Boolean(argv.dryRun),
71
+ exclude: argv.exclude,
72
+ });
73
+ }
74
+ catch {
75
+ // yargs prints its own error messages (e.g. unknown options with --strict)
76
+ return 1;
77
+ }
78
+ };
@@ -0,0 +1,7 @@
1
+ import type { Conflict, LockData } from "./types";
2
+ /**
3
+ * Collect the set of package names that are direct dependencies of any installed @uxf/* package.
4
+ * Only these are relevant for version conflict detection.
5
+ */
6
+ export declare function collectUxfDependencyNames(uxfPackages: string[], nodeModulesPath: string): Set<string>;
7
+ export declare function checkMultipleVersions(lockData: LockData, relevantPackages: Set<string>, excludedPackages?: Set<string>): Conflict[];
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.collectUxfDependencyNames = collectUxfDependencyNames;
7
+ exports.checkMultipleVersions = checkMultipleVersions;
8
+ const path_1 = __importDefault(require("path"));
9
+ const types_1 = require("./types");
10
+ /** Build-time / CLI-only dependencies that cannot cause runtime conflicts */
11
+ const IGNORED_PACKAGES = new Set(["yargs", "fast-glob"]);
12
+ /**
13
+ * Collect the set of package names that are direct dependencies of any installed @uxf/* package.
14
+ * Only these are relevant for version conflict detection.
15
+ */
16
+ function collectUxfDependencyNames(uxfPackages, nodeModulesPath) {
17
+ var _a, _b;
18
+ const depNames = new Set();
19
+ for (const uxfPkg of uxfPackages) {
20
+ const pkgJsonPath = path_1.default.join(nodeModulesPath, uxfPkg, "package.json");
21
+ const pkgJson = (0, types_1.readPackageJson)(pkgJsonPath);
22
+ if (!pkgJson) {
23
+ continue;
24
+ }
25
+ for (const name of Object.keys((_a = pkgJson.dependencies) !== null && _a !== void 0 ? _a : {})) {
26
+ depNames.add(name);
27
+ }
28
+ for (const name of Object.keys((_b = pkgJson.peerDependencies) !== null && _b !== void 0 ? _b : {})) {
29
+ depNames.add(name);
30
+ }
31
+ }
32
+ return depNames;
33
+ }
34
+ function checkMultipleVersions(lockData, relevantPackages, excludedPackages = new Set()) {
35
+ const allExcluded = new Set([...IGNORED_PACKAGES, ...excludedPackages]);
36
+ const conflicts = [];
37
+ for (const name of relevantPackages) {
38
+ if (allExcluded.has(name)) {
39
+ continue;
40
+ }
41
+ const versions = lockData.get(name);
42
+ if (versions && versions.size > 1) {
43
+ conflicts.push({ name, versions: Array.from(versions) });
44
+ }
45
+ }
46
+ return conflicts;
47
+ }
@@ -0,0 +1,6 @@
1
+ import type { PackageManager } from "./types";
2
+ export declare function detectPackageManager(cwd?: string): PackageManager;
3
+ export declare function getInstallCommand(pm: PackageManager): {
4
+ cmd: string;
5
+ addArg: string;
6
+ };
@@ -0,0 +1,37 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.detectPackageManager = detectPackageManager;
7
+ exports.getInstallCommand = getInstallCommand;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ const LOCK_FILES = [
11
+ { file: "bun.lock", pm: "bun" },
12
+ { file: "pnpm-lock.yaml", pm: "pnpm" },
13
+ { file: "yarn.lock", pm: "yarn" },
14
+ { file: "package-lock.json", pm: "npm" },
15
+ ];
16
+ function detectPackageManager(cwd = process.cwd()) {
17
+ for (const { file, pm } of LOCK_FILES) {
18
+ if (fs_1.default.existsSync(path_1.default.resolve(cwd, file))) {
19
+ return pm;
20
+ }
21
+ }
22
+ throw new Error("Could not detect package manager. Please run this command from a project root.");
23
+ }
24
+ function getInstallCommand(pm) {
25
+ switch (pm) {
26
+ case "yarn":
27
+ return { cmd: "yarn", addArg: "add" };
28
+ case "pnpm":
29
+ return { cmd: "pnpm", addArg: "add" };
30
+ case "bun":
31
+ return { cmd: "bun", addArg: "add" };
32
+ case "npm":
33
+ return { cmd: "npm", addArg: "install" };
34
+ default:
35
+ throw new Error(`Unsupported package manager: ${pm}`);
36
+ }
37
+ }
@@ -0,0 +1,7 @@
1
+ interface CheckOptions {
2
+ isFix: boolean;
3
+ isDryRun: boolean;
4
+ exclude: string[];
5
+ }
6
+ export declare function checkUxfDependencies(options: CheckOptions): Promise<number>;
7
+ export {};
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.checkUxfDependencies = checkUxfDependencies;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const conflict_check_1 = require("./conflict-check");
10
+ const detect_package_manager_1 = require("./detect-package-manager");
11
+ const lock_parsers_1 = require("./lock-parsers");
12
+ const peer_deps_1 = require("./peer-deps");
13
+ function readProjectPackageJson(cwd) {
14
+ try {
15
+ return JSON.parse(fs_1.default.readFileSync(path_1.default.resolve(cwd, "package.json"), "utf8"));
16
+ }
17
+ catch {
18
+ return null;
19
+ }
20
+ }
21
+ async function checkUxfDependencies(options) {
22
+ const cwd = process.cwd();
23
+ const pm = (0, detect_package_manager_1.detectPackageManager)(cwd);
24
+ const projectPkg = readProjectPackageJson(cwd);
25
+ if (!projectPkg) {
26
+ console.error("Could not read package.json in current directory."); // eslint-disable-line no-console
27
+ return 1;
28
+ }
29
+ const nodeModulesPath = path_1.default.resolve(cwd, "node_modules");
30
+ if (!fs_1.default.existsSync(nodeModulesPath)) {
31
+ console.error("node_modules not found. Run install first."); // eslint-disable-line no-console
32
+ return 1;
33
+ }
34
+ const uxfPackages = (0, peer_deps_1.findInstalledUxfPackages)(projectPkg);
35
+ if (uxfPackages.length === 0) {
36
+ console.log("No @uxf/* packages found in dependencies."); // eslint-disable-line no-console
37
+ return 0;
38
+ }
39
+ console.log(`Detected package manager: ${pm}`); // eslint-disable-line no-console
40
+ console.log(`Found ${uxfPackages.length} @uxf/* packages: ${uxfPackages.join(", ")}\n`); // eslint-disable-line no-console
41
+ let hasIssues = false;
42
+ // --- Conflict check (lock file) ---
43
+ // Only check dependencies of @uxf/* packages, not the entire lock file
44
+ try {
45
+ const lockData = await (0, lock_parsers_1.parseLockFile)(pm, cwd);
46
+ const relevantDeps = (0, conflict_check_1.collectUxfDependencyNames)(uxfPackages, nodeModulesPath);
47
+ const conflicts = (0, conflict_check_1.checkMultipleVersions)(lockData, relevantDeps, new Set(options.exclude));
48
+ if (conflicts.length > 0) {
49
+ console.log("Dependency version conflicts in @uxf/* packages:"); // eslint-disable-line no-console
50
+ for (const { name, versions } of conflicts) {
51
+ console.log(` ${name}: ${versions.join(", ")}`); // eslint-disable-line no-console
52
+ }
53
+ console.log(); // eslint-disable-line no-console
54
+ hasIssues = true;
55
+ }
56
+ else {
57
+ console.log("No dependency version conflicts found.\n"); // eslint-disable-line no-console
58
+ }
59
+ }
60
+ catch {
61
+ console.log("Could not parse lock file — skipping conflict check.\n"); // eslint-disable-line no-console
62
+ }
63
+ // --- Peer dependency check ---
64
+ const requiredPeerDeps = (0, peer_deps_1.collectRequiredPeerDeps)(uxfPackages, nodeModulesPath, projectPkg);
65
+ const { missing, mismatched } = (0, peer_deps_1.findMissingOrMismatchedDeps)(requiredPeerDeps, projectPkg);
66
+ if (missing.size === 0 && mismatched.size === 0) {
67
+ console.log("All peer dependencies are correctly installed."); // eslint-disable-line no-console
68
+ return hasIssues ? 1 : 0;
69
+ }
70
+ (0, peer_deps_1.printPeerDepsReport)(missing, mismatched);
71
+ hasIssues = true;
72
+ if (options.isDryRun || !options.isFix) {
73
+ (0, peer_deps_1.printSuggestedCommands)(missing, mismatched, pm);
74
+ return 1;
75
+ }
76
+ (0, peer_deps_1.installDeps)(missing, mismatched, pm);
77
+ console.log("\nAll peer dependencies are now installed."); // eslint-disable-line no-console
78
+ return 0;
79
+ }
@@ -0,0 +1,2 @@
1
+ import type { LockData, PackageManager } from "./types";
2
+ export declare function parseLockFile(pm: PackageManager, cwd?: string): Promise<LockData>;
@@ -0,0 +1,204 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.parseLockFile = parseLockFile;
40
+ const fs_1 = __importDefault(require("fs"));
41
+ const path_1 = __importDefault(require("path"));
42
+ /**
43
+ * Extract package name from a yarn.lock key like "@uxf/button@^1.0.0"
44
+ * Works for both Classic (v1) and Berry (v2+) key formats.
45
+ */
46
+ function extractPackageNameFromYarnKey(key) {
47
+ var _a;
48
+ const match = key.match(/^(@[^/]+\/[^@]+|[^@]+)@/);
49
+ return match ? ((_a = match.at(1)) !== null && _a !== void 0 ? _a : null) : null;
50
+ }
51
+ /**
52
+ * Extract package name from a node_modules path like "node_modules/@uxf/button"
53
+ */
54
+ function extractPackageNameFromPath(modulePath) {
55
+ var _a;
56
+ const match = modulePath.match(/node_modules\/(@[^/]+\/[^/]+|[^/]+)$/);
57
+ return match ? ((_a = match.at(1)) !== null && _a !== void 0 ? _a : null) : null;
58
+ }
59
+ function addToResult(result, name, version) {
60
+ const existing = result.get(name);
61
+ if (existing) {
62
+ existing.add(version);
63
+ }
64
+ else {
65
+ result.set(name, new Set([version]));
66
+ }
67
+ }
68
+ async function parseYarnLock(cwd) {
69
+ const YAML = await Promise.resolve().then(() => __importStar(require("yaml")));
70
+ const content = fs_1.default.readFileSync(path_1.default.resolve(cwd, "yarn.lock"), "utf8");
71
+ const parsed = YAML.parse(content);
72
+ const result = new Map();
73
+ for (const [key, entry] of Object.entries(parsed)) {
74
+ if (key === "__metadata") {
75
+ continue;
76
+ }
77
+ const entryObj = entry;
78
+ const name = extractPackageNameFromYarnKey(key);
79
+ const version = entryObj.version;
80
+ // Berry also has "resolution" field like "@uxf/core@npm:1.0.0" — extract version from it as fallback
81
+ const resolution = typeof entryObj.resolution === "string" ? entryObj.resolution : null;
82
+ if (!name) {
83
+ continue;
84
+ }
85
+ if (typeof version === "string") {
86
+ addToResult(result, name, version);
87
+ }
88
+ else if (resolution) {
89
+ // Berry resolution format: "package@npm:version" or "package@version"
90
+ const atIdx = resolution.lastIndexOf("@");
91
+ if (atIdx > 0) {
92
+ const resVersion = resolution.slice(atIdx + 1).replace(/^npm:/, "");
93
+ if (resVersion) {
94
+ addToResult(result, name, resVersion);
95
+ }
96
+ }
97
+ }
98
+ }
99
+ return result;
100
+ }
101
+ async function parsePackageLockJson(cwd) {
102
+ var _a;
103
+ const content = fs_1.default.readFileSync(path_1.default.resolve(cwd, "package-lock.json"), "utf8");
104
+ const parsed = JSON.parse(content);
105
+ const result = new Map();
106
+ // package-lock.json v3 uses "packages" with node_modules paths as keys
107
+ const packages = (_a = parsed.packages) !== null && _a !== void 0 ? _a : {};
108
+ for (const [pkgPath, entry] of Object.entries(packages)) {
109
+ if (!pkgPath || pkgPath === "") {
110
+ continue;
111
+ }
112
+ const name = extractPackageNameFromPath(pkgPath);
113
+ const version = entry.version;
114
+ if (!name || typeof version !== "string") {
115
+ continue;
116
+ }
117
+ addToResult(result, name, version);
118
+ }
119
+ return result;
120
+ }
121
+ async function parsePnpmLock(cwd) {
122
+ var _a, _b, _c;
123
+ const YAML = await Promise.resolve().then(() => __importStar(require("yaml")));
124
+ const content = fs_1.default.readFileSync(path_1.default.resolve(cwd, "pnpm-lock.yaml"), "utf8");
125
+ const parsed = YAML.parse(content);
126
+ const result = new Map();
127
+ // pnpm v9+ uses "snapshots" for resolved versions, older versions use "packages"
128
+ const lockfileVersion = String((_a = parsed.lockfileVersion) !== null && _a !== void 0 ? _a : "");
129
+ const isV9Plus = parseFloat(lockfileVersion) >= 9;
130
+ const packages = isV9Plus ? ((_b = parsed.snapshots) !== null && _b !== void 0 ? _b : {}) : ((_c = parsed.packages) !== null && _c !== void 0 ? _c : {});
131
+ for (const key of Object.keys(packages)) {
132
+ // Handle formats: "/@scope/name@version", "/name@version", "@scope/name@version", "name@version"
133
+ const cleaned = key.startsWith("/") ? key.slice(1) : key;
134
+ const atIdx = cleaned.startsWith("@") ? cleaned.indexOf("@", 1) : cleaned.indexOf("@");
135
+ if (atIdx === -1) {
136
+ continue;
137
+ }
138
+ const name = cleaned.slice(0, atIdx);
139
+ const version = cleaned
140
+ .slice(atIdx + 1)
141
+ .split("(")
142
+ .at(0); // strip peerDep suffixes like "(react@18.0.0)"
143
+ if (!name || !version) {
144
+ continue;
145
+ }
146
+ addToResult(result, name, version);
147
+ }
148
+ return result;
149
+ }
150
+ /**
151
+ * Strip JSONC comments (// line comments) from bun.lock content.
152
+ * bun.lock is a JSONC-like text format, not valid JSON.
153
+ */
154
+ function stripJsoncComments(content) {
155
+ return content.replace(/^\s*\/\/.*$/gm, "");
156
+ }
157
+ async function parseBunLock(cwd) {
158
+ var _a;
159
+ const content = fs_1.default.readFileSync(path_1.default.resolve(cwd, "bun.lock"), "utf8");
160
+ const parsed = JSON.parse(stripJsoncComments(content));
161
+ const result = new Map();
162
+ // bun.lock "packages" is a flat object: key is an ident like "@uxf/button",
163
+ // value is a tuple where the first element is "name@version" or just "version"
164
+ const packages = (_a = parsed.packages) !== null && _a !== void 0 ? _a : {};
165
+ for (const [key, value] of Object.entries(packages)) {
166
+ if (!key || key === "") {
167
+ continue;
168
+ }
169
+ const tuple = value;
170
+ if (!Array.isArray(tuple) || tuple.length === 0) {
171
+ continue;
172
+ }
173
+ const raw = String(tuple.at(0));
174
+ // The first element is typically "name@version" or just "version"
175
+ // The key itself is the package identifier
176
+ let name;
177
+ let version;
178
+ // If the raw value contains @, extract version after last @
179
+ const lastAt = raw.lastIndexOf("@");
180
+ if (lastAt > 0) {
181
+ name = raw.slice(0, lastAt);
182
+ version = raw.slice(lastAt + 1);
183
+ }
184
+ else {
185
+ // raw is just a version, key is the name
186
+ name = key;
187
+ version = raw;
188
+ }
189
+ if (!name || !version) {
190
+ continue;
191
+ }
192
+ addToResult(result, name, version);
193
+ }
194
+ return result;
195
+ }
196
+ const PARSERS = {
197
+ yarn: parseYarnLock,
198
+ npm: parsePackageLockJson,
199
+ pnpm: parsePnpmLock,
200
+ bun: parseBunLock,
201
+ };
202
+ async function parseLockFile(pm, cwd = process.cwd()) {
203
+ return PARSERS[pm](cwd);
204
+ }
@@ -0,0 +1,10 @@
1
+ import type { DepInfo, MismatchInfo, PackageJson, PackageManager } from "./types";
2
+ export declare function findInstalledUxfPackages(projectPkg: PackageJson): string[];
3
+ export declare function collectRequiredPeerDeps(uxfPackages: string[], nodeModulesPath: string, projectPkg: PackageJson): Map<string, DepInfo>;
4
+ export declare function findMissingOrMismatchedDeps(requiredPeerDeps: Map<string, DepInfo>, projectPkg: PackageJson): {
5
+ missing: Map<string, DepInfo>;
6
+ mismatched: Map<string, MismatchInfo>;
7
+ };
8
+ export declare function printPeerDepsReport(missing: Map<string, DepInfo>, mismatched: Map<string, MismatchInfo>): void;
9
+ export declare function printSuggestedCommands(missing: Map<string, DepInfo>, mismatched: Map<string, MismatchInfo>, pm: PackageManager): void;
10
+ export declare function installDeps(missing: Map<string, DepInfo>, mismatched: Map<string, MismatchInfo>, pm: PackageManager): void;
@@ -0,0 +1,168 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.findInstalledUxfPackages = findInstalledUxfPackages;
7
+ exports.collectRequiredPeerDeps = collectRequiredPeerDeps;
8
+ exports.findMissingOrMismatchedDeps = findMissingOrMismatchedDeps;
9
+ exports.printPeerDepsReport = printPeerDepsReport;
10
+ exports.printSuggestedCommands = printSuggestedCommands;
11
+ exports.installDeps = installDeps;
12
+ const child_process_1 = require("child_process");
13
+ const path_1 = __importDefault(require("path"));
14
+ const detect_package_manager_1 = require("./detect-package-manager");
15
+ const types_1 = require("./types");
16
+ /** Packages that consumers always install themselves — skip these in suggestions */
17
+ const CONSUMER_PROVIDED = new Set(["react", "react-dom", "next"]);
18
+ function findInstalledUxfPackages(projectPkg) {
19
+ const deps = { ...projectPkg.dependencies, ...projectPkg.devDependencies };
20
+ return Object.keys(deps).filter((name) => name.startsWith("@uxf/"));
21
+ }
22
+ function collectRequiredPeerDeps(uxfPackages, nodeModulesPath, projectPkg) {
23
+ var _a;
24
+ const prodDeps = new Set(Object.keys((_a = projectPkg.dependencies) !== null && _a !== void 0 ? _a : {}));
25
+ const peerDeps = new Map();
26
+ for (const uxfPkg of uxfPackages) {
27
+ const pkgJsonPath = path_1.default.join(nodeModulesPath, uxfPkg, "package.json");
28
+ const pkgJson = (0, types_1.readPackageJson)(pkgJsonPath);
29
+ if (!(pkgJson === null || pkgJson === void 0 ? void 0 : pkgJson.peerDependencies)) {
30
+ continue;
31
+ }
32
+ const isRequirerDev = !prodDeps.has(uxfPkg);
33
+ for (const [depName, depVersion] of Object.entries(pkgJson.peerDependencies)) {
34
+ if (!depVersion || depName.startsWith("@uxf/") || CONSUMER_PROVIDED.has(depName)) {
35
+ continue;
36
+ }
37
+ const existing = peerDeps.get(depName);
38
+ if (existing) {
39
+ existing.requiredBy.push(uxfPkg);
40
+ // If any requirer is a prod dependency, the peer dep should be prod too
41
+ if (!isRequirerDev) {
42
+ existing.isDev = false;
43
+ }
44
+ }
45
+ else {
46
+ peerDeps.set(depName, { version: depVersion, requiredBy: [uxfPkg], isDev: isRequirerDev });
47
+ }
48
+ }
49
+ }
50
+ return peerDeps;
51
+ }
52
+ function findMissingOrMismatchedDeps(requiredPeerDeps, projectPkg) {
53
+ const allProjectDeps = { ...projectPkg.dependencies, ...projectPkg.devDependencies };
54
+ const missing = new Map();
55
+ const mismatched = new Map();
56
+ for (const [depName, { version, requiredBy, isDev }] of requiredPeerDeps) {
57
+ const installedVersion = allProjectDeps[depName];
58
+ if (!installedVersion) {
59
+ missing.set(depName, { version, requiredBy, isDev });
60
+ }
61
+ else if (installedVersion !== version) {
62
+ mismatched.set(depName, { expected: version, actual: installedVersion, requiredBy, isDev });
63
+ }
64
+ }
65
+ return { missing, mismatched };
66
+ }
67
+ function printPeerDepsReport(missing, mismatched) {
68
+ if (missing.size > 0) {
69
+ console.log("Missing peer dependencies:"); // eslint-disable-line no-console
70
+ for (const [name, { version, requiredBy, isDev }] of missing) {
71
+ const devTag = isDev ? " [dev]" : "";
72
+ console.log(` ${name}@${version}${devTag} (required by ${requiredBy.join(", ")})`); // eslint-disable-line no-console
73
+ }
74
+ console.log(); // eslint-disable-line no-console
75
+ }
76
+ if (mismatched.size > 0) {
77
+ console.log("Version mismatches:"); // eslint-disable-line no-console
78
+ for (const [name, { expected, actual, requiredBy, isDev }] of mismatched) {
79
+ const devTag = isDev ? " [dev]" : "";
80
+ // eslint-disable-next-line no-console
81
+ console.log(` ${name}: installed ${actual}, expected ${expected}${devTag} (required by ${requiredBy.join(", ")})`);
82
+ }
83
+ console.log(); // eslint-disable-line no-console
84
+ }
85
+ }
86
+ function formatInstallArgs(packages) {
87
+ return Array.from(packages.entries()).map(([name, version]) => `${name}@${version}`);
88
+ }
89
+ function splitDepsByDevFlag(deps) {
90
+ const prod = new Map();
91
+ const dev = new Map();
92
+ for (const [name, info] of deps) {
93
+ if (info.isDev) {
94
+ dev.set(name, info.version);
95
+ }
96
+ else {
97
+ prod.set(name, info.version);
98
+ }
99
+ }
100
+ return { prod, dev };
101
+ }
102
+ function splitMismatchesByDevFlag(deps) {
103
+ const prod = new Map();
104
+ const dev = new Map();
105
+ for (const [name, info] of deps) {
106
+ if (info.isDev) {
107
+ dev.set(name, info.expected);
108
+ }
109
+ else {
110
+ prod.set(name, info.expected);
111
+ }
112
+ }
113
+ return { prod, dev };
114
+ }
115
+ function printSuggestedCommands(missing, mismatched, pm) {
116
+ const { cmd, addArg } = (0, detect_package_manager_1.getInstallCommand)(pm);
117
+ if (missing.size > 0) {
118
+ const { prod, dev } = splitDepsByDevFlag(missing);
119
+ if (prod.size > 0) {
120
+ const pkgs = formatInstallArgs(prod).join(" ");
121
+ console.log(`To install missing dependencies, run:\n ${cmd} ${addArg} ${pkgs}\n`); // eslint-disable-line no-console
122
+ }
123
+ if (dev.size > 0) {
124
+ const pkgs = formatInstallArgs(dev).join(" ");
125
+ console.log(`To install missing dev dependencies, run:\n ${cmd} ${addArg} -D ${pkgs}\n`); // eslint-disable-line no-console
126
+ }
127
+ }
128
+ if (mismatched.size > 0) {
129
+ const { prod, dev } = splitMismatchesByDevFlag(mismatched);
130
+ if (prod.size > 0) {
131
+ const pkgs = formatInstallArgs(prod).join(" ");
132
+ console.log(`To fix version mismatches, run:\n ${cmd} ${addArg} ${pkgs}\n`); // eslint-disable-line no-console
133
+ }
134
+ if (dev.size > 0) {
135
+ const pkgs = formatInstallArgs(dev).join(" ");
136
+ console.log(`To fix dev version mismatches, run:\n ${cmd} ${addArg} -D ${pkgs}\n`); // eslint-disable-line no-console
137
+ }
138
+ }
139
+ }
140
+ function installDeps(missing, mismatched, pm) {
141
+ const { cmd, addArg } = (0, detect_package_manager_1.getInstallCommand)(pm);
142
+ if (missing.size > 0) {
143
+ const { prod, dev } = splitDepsByDevFlag(missing);
144
+ if (prod.size > 0) {
145
+ const pkgs = formatInstallArgs(prod);
146
+ console.log("Installing missing dependencies..."); // eslint-disable-line no-console
147
+ (0, child_process_1.execFileSync)(cmd, [addArg, ...pkgs], { stdio: "inherit", cwd: process.cwd() });
148
+ }
149
+ if (dev.size > 0) {
150
+ const pkgs = formatInstallArgs(dev);
151
+ console.log("Installing missing dev dependencies..."); // eslint-disable-line no-console
152
+ (0, child_process_1.execFileSync)(cmd, [addArg, "-D", ...pkgs], { stdio: "inherit", cwd: process.cwd() });
153
+ }
154
+ }
155
+ if (mismatched.size > 0) {
156
+ const { prod, dev } = splitMismatchesByDevFlag(mismatched);
157
+ if (prod.size > 0) {
158
+ const pkgs = formatInstallArgs(prod);
159
+ console.log("Fixing version mismatches..."); // eslint-disable-line no-console
160
+ (0, child_process_1.execFileSync)(cmd, [addArg, ...pkgs], { stdio: "inherit", cwd: process.cwd() });
161
+ }
162
+ if (dev.size > 0) {
163
+ const pkgs = formatInstallArgs(dev);
164
+ console.log("Fixing dev version mismatches..."); // eslint-disable-line no-console
165
+ (0, child_process_1.execFileSync)(cmd, [addArg, "-D", ...pkgs], { stdio: "inherit", cwd: process.cwd() });
166
+ }
167
+ }
168
+ }
@@ -0,0 +1,27 @@
1
+ export type PackageManager = "yarn" | "npm" | "pnpm" | "bun";
2
+ export interface PackageJson {
3
+ dependencies?: Partial<Record<string, string>>;
4
+ devDependencies?: Partial<Record<string, string>>;
5
+ peerDependencies?: Partial<Record<string, string>>;
6
+ }
7
+ export interface DepInfo {
8
+ isDev: boolean;
9
+ requiredBy: string[];
10
+ version: string;
11
+ }
12
+ export interface MismatchInfo {
13
+ actual: string;
14
+ expected: string;
15
+ isDev: boolean;
16
+ requiredBy: string[];
17
+ }
18
+ export interface Conflict {
19
+ name: string;
20
+ versions: string[];
21
+ }
22
+ /**
23
+ * Normalized lock data: maps package name → set of resolved versions.
24
+ * Every lock file parser must return this shape.
25
+ */
26
+ export type LockData = Map<string, Set<string>>;
27
+ export declare function readPackageJson(filePath: string): PackageJson | null;
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.readPackageJson = readPackageJson;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ function readPackageJson(filePath) {
9
+ try {
10
+ return JSON.parse(fs_1.default.readFileSync(filePath, "utf8"));
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ }
@@ -1,11 +0,0 @@
1
- #!/usr/bin/env tsx
2
- import cli from "../src/uxf-dependencies-check/cli";
3
-
4
- cli()
5
- .then((exitCode) => {
6
- process.exitCode = exitCode;
7
- })
8
- .catch((e) => {
9
- console.error(e); // eslint-disable-line no-console
10
- process.exitCode = 1;
11
- });