@uxf/scripts 11.111.0-canary.1 → 11.111.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
@@ -67,7 +67,7 @@ notify-push:
67
67
 
68
68
  All-in-one dependency health check for projects using `@uxf/*` packages. Runs two checks:
69
69
 
70
- 1. **Version conflict detection** — parses the lock file and reports dependencies of `@uxf/*` packages that resolve to multiple versions
70
+ 1. **Version conflict detection** — reports dependencies where the project and/or `@uxf/*` packages themselves resolve to different versions. Transitive-only duplicates (a dep pulled in by unrelated third-party packages at a different version) are ignored, since they don't affect `@uxf/*` compatibility.
71
71
  2. **Peer dependency check** — verifies that all `peerDependencies` of installed `@uxf/*` packages are present and version-matched
72
72
 
73
73
  Supports **yarn**, **npm**, **pnpm**, and **bun**. The package manager is auto-detected from the lock file.
@@ -103,13 +103,15 @@ npx uxf-dependencies-check --exclude lodash dayjs
103
103
 
104
104
  ### Ignoring known conflicts
105
105
 
106
- Some version conflicts are caused by third-party packages and cannot be resolved (e.g. `@udecode/plate-floating` pulling an old `@floating-ui/react`). Each `@uxf/*` package can declare known conflicts in its own `package.json`:
106
+ Transitive-only duplicates (caused by unrelated third-party packages, e.g. `@udecode/plate-floating` pulling an old `@floating-ui/react` alongside a newer one declared by an `@uxf/*` package) are filtered out automatically and do not need to be ignored.
107
+
108
+ For genuine declarer conflicts that you've consciously accepted — e.g. two `@uxf/*` packages that temporarily pin different versions of the same dep — each `@uxf/*` package can declare known conflicts in its own `package.json`:
107
109
 
108
110
  ```json
109
111
  {
110
112
  "name": "@uxf/wysiwyg",
111
113
  "uxf": {
112
- "ignoredConflicts": ["@floating-ui/react"]
114
+ "ignoredConflicts": ["some-shared-dep"]
113
115
  }
114
116
  }
115
117
  ```
@@ -118,7 +120,8 @@ Ignored conflicts are still printed as informational output but do **not** cause
118
120
 
119
121
  ### What it checks
120
122
 
121
- - Parses the lock file (yarn.lock / package-lock.json / pnpm-lock.yaml / bun.lock) to detect version conflicts
123
+ - Parses the lock file (yarn.lock / package-lock.json / pnpm-lock.yaml / bun.lock) to find dependencies with multiple installed versions
124
+ - For each candidate, resolves the version actually seen by each *declarer* (the project itself and any `@uxf/*` package that directly declares the dep). A conflict is reported only when these declarers land on different versions — transitive-only duplicates from unrelated third-party packages are filtered out
122
125
  - Scans all `@uxf/*` packages in your `dependencies` / `devDependencies`
123
126
  - Reads each package's `peerDependencies` from `node_modules`
124
127
  - Skips `@uxf/*`, `react`, `react-dom`, and `next` (you manage these yourself)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uxf/scripts",
3
- "version": "11.111.0-canary.1",
3
+ "version": "11.111.1",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -48,6 +48,6 @@
48
48
  "@types/react": "18.3.27",
49
49
  "@types/react-dom": "18.3.7",
50
50
  "@uxf/core": "11.110.0",
51
- "@uxf/ui": "11.111.0-canary.1"
51
+ "@uxf/ui": "11.111.0"
52
52
  }
53
53
  }
@@ -1,4 +1,4 @@
1
- import type { Conflict, LockData } from "./types";
1
+ import type { Conflict, LockData, PackageJson } from "./types";
2
2
  export interface UxfDepsInfo {
3
3
  depNames: Set<string>;
4
4
  ignoredConflicts: Set<string>;
@@ -13,3 +13,14 @@ export interface ConflictCheckResult {
13
13
  ignoredConflicts: Conflict[];
14
14
  }
15
15
  export declare function checkMultipleVersions(lockData: LockData, relevantPackages: Set<string>, excludedPackages?: Set<string>, ignoredPackages?: Set<string>): ConflictCheckResult;
16
+ /**
17
+ * For each candidate conflict, collect the set of versions actually resolved by the *declarers* —
18
+ * i.e. the project itself and any @uxf/* package that directly declares `name` in its
19
+ * `dependencies` or `peerDependencies`. Transitive-only duplicates (a package pulled in by a
20
+ * non-@uxf, non-project dependency at an unrelated version) are ignored.
21
+ *
22
+ * A conflict is kept only when declarers disagree on the resolved version. This narrows the check
23
+ * to what the tool actually cares about: compatibility between the project and @uxf/* packages,
24
+ * and between @uxf/* packages themselves.
25
+ */
26
+ export declare function filterToDeclarerConflicts(conflicts: Conflict[], projectPkg: PackageJson, uxfPackages: string[], nodeModulesPath: string): Conflict[];
@@ -5,8 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.collectUxfDepsInfo = collectUxfDepsInfo;
7
7
  exports.checkMultipleVersions = checkMultipleVersions;
8
+ exports.filterToDeclarerConflicts = filterToDeclarerConflicts;
8
9
  const path_1 = __importDefault(require("path"));
9
- const types_1 = require("./types");
10
+ const package_json_1 = require("./package-json");
10
11
  /** Build-time / CLI-only dependencies that cannot cause runtime conflicts */
11
12
  const IGNORED_PACKAGES = new Set(["yargs", "fast-glob"]);
12
13
  /**
@@ -19,7 +20,7 @@ function collectUxfDepsInfo(uxfPackages, nodeModulesPath) {
19
20
  const ignoredConflicts = new Set();
20
21
  for (const uxfPkg of uxfPackages) {
21
22
  const pkgJsonPath = path_1.default.join(nodeModulesPath, uxfPkg, "package.json");
22
- const pkgJson = (0, types_1.readPackageJson)(pkgJsonPath);
23
+ const pkgJson = (0, package_json_1.readPackageJson)(pkgJsonPath);
23
24
  if (!pkgJson) {
24
25
  continue;
25
26
  }
@@ -59,3 +60,80 @@ function checkMultipleVersions(lockData, relevantPackages, excludedPackages = ne
59
60
  }
60
61
  return { conflicts, ignoredConflicts };
61
62
  }
63
+ /**
64
+ * Resolve the version of `depName` as seen by a given declarer package. First checks the declarer's
65
+ * own nested `node_modules` (non-hoisted install), then falls back to the project-root `node_modules`
66
+ * (hoisted install). Returns null if neither location has the package installed.
67
+ */
68
+ function resolveDeclarerVersion(nodeModulesPath, declarerPkg, depName) {
69
+ const candidatePaths = [];
70
+ if (declarerPkg) {
71
+ candidatePaths.push(path_1.default.join(nodeModulesPath, declarerPkg, "node_modules", depName, "package.json"));
72
+ }
73
+ candidatePaths.push(path_1.default.join(nodeModulesPath, depName, "package.json"));
74
+ for (const p of candidatePaths) {
75
+ const pkg = (0, package_json_1.readPackageJson)(p);
76
+ if (pkg && typeof pkg.version === "string") {
77
+ return pkg.version;
78
+ }
79
+ }
80
+ return null;
81
+ }
82
+ /**
83
+ * For each candidate conflict, collect the set of versions actually resolved by the *declarers* —
84
+ * i.e. the project itself and any @uxf/* package that directly declares `name` in its
85
+ * `dependencies` or `peerDependencies`. Transitive-only duplicates (a package pulled in by a
86
+ * non-@uxf, non-project dependency at an unrelated version) are ignored.
87
+ *
88
+ * A conflict is kept only when declarers disagree on the resolved version. This narrows the check
89
+ * to what the tool actually cares about: compatibility between the project and @uxf/* packages,
90
+ * and between @uxf/* packages themselves.
91
+ */
92
+ function filterToDeclarerConflicts(conflicts, projectPkg, uxfPackages, nodeModulesPath) {
93
+ var _a, _b, _c;
94
+ if (conflicts.length === 0) {
95
+ return [];
96
+ }
97
+ const projectDeclared = {
98
+ ...projectPkg.dependencies,
99
+ ...projectPkg.devDependencies,
100
+ ...projectPkg.peerDependencies,
101
+ };
102
+ const uxfPkgJsons = new Map();
103
+ for (const uxfPkg of uxfPackages) {
104
+ const pkgJson = (0, package_json_1.readPackageJson)(path_1.default.join(nodeModulesPath, uxfPkg, "package.json"));
105
+ if (pkgJson) {
106
+ uxfPkgJsons.set(uxfPkg, pkgJson);
107
+ }
108
+ }
109
+ const result = [];
110
+ for (const conflict of conflicts) {
111
+ const { name } = conflict;
112
+ const resolvedVersions = new Set();
113
+ if (projectDeclared[name]) {
114
+ const resolved = resolveDeclarerVersion(nodeModulesPath, null, name);
115
+ if (resolved) {
116
+ resolvedVersions.add(resolved);
117
+ }
118
+ }
119
+ for (const [uxfPkg, pkgJson] of uxfPkgJsons) {
120
+ const declared = (_b = (_a = pkgJson.dependencies) === null || _a === void 0 ? void 0 : _a[name]) !== null && _b !== void 0 ? _b : (_c = pkgJson.peerDependencies) === null || _c === void 0 ? void 0 : _c[name];
121
+ if (!declared) {
122
+ continue;
123
+ }
124
+ const resolved = resolveDeclarerVersion(nodeModulesPath, uxfPkg, name);
125
+ if (resolved) {
126
+ resolvedVersions.add(resolved);
127
+ }
128
+ }
129
+ if (resolvedVersions.size === 0) {
130
+ // Could not resolve any declarer (edge case: non-node_modules install layout).
131
+ // Fall back to original lockfile versions rather than silently hiding the conflict.
132
+ result.push(conflict);
133
+ }
134
+ else if (resolvedVersions.size > 1) {
135
+ result.push({ name, versions: Array.from(resolvedVersions) });
136
+ }
137
+ }
138
+ return result;
139
+ }
@@ -43,8 +43,13 @@ async function checkUxfDependencies(options) {
43
43
  // Only check dependencies of @uxf/* packages, not the entire lock file
44
44
  try {
45
45
  const lockData = await (0, lock_parsers_1.parseLockFile)(pm, cwd);
46
- const { depNames, ignoredConflicts: packageIgnored } = (0, conflict_check_1.collectUxfDepsInfo)(uxfPackages, nodeModulesPath);
47
- const { conflicts, ignoredConflicts } = (0, conflict_check_1.checkMultipleVersions)(lockData, depNames, new Set(options.exclude), packageIgnored);
46
+ const uxfDepsInfo = (0, conflict_check_1.collectUxfDepsInfo)(uxfPackages, nodeModulesPath);
47
+ const conflictCheckResult = (0, conflict_check_1.checkMultipleVersions)(lockData, uxfDepsInfo.depNames, new Set(options.exclude), uxfDepsInfo.ignoredConflicts);
48
+ // Filter to real conflicts between declarers (project + @uxf packages). Transitive-only
49
+ // duplicates (e.g. `qs` pulled in by express at a different version than @uxf/core's qs)
50
+ // are ignored — they are not compatibility issues for @uxf/* packages.
51
+ const conflicts = (0, conflict_check_1.filterToDeclarerConflicts)(conflictCheckResult.conflicts, projectPkg, uxfPackages, nodeModulesPath);
52
+ const ignoredConflicts = (0, conflict_check_1.filterToDeclarerConflicts)(conflictCheckResult.ignoredConflicts, projectPkg, uxfPackages, nodeModulesPath);
48
53
  if (conflicts.length > 0) {
49
54
  console.log("Dependency version conflicts in @uxf/* packages:"); // eslint-disable-line no-console
50
55
  for (const { name, versions } of conflicts) {
@@ -0,0 +1,2 @@
1
+ import type { PackageJson } from "./types";
2
+ 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
+ }
@@ -12,7 +12,7 @@ exports.installDeps = installDeps;
12
12
  const child_process_1 = require("child_process");
13
13
  const path_1 = __importDefault(require("path"));
14
14
  const detect_package_manager_1 = require("./detect-package-manager");
15
- const types_1 = require("./types");
15
+ const package_json_1 = require("./package-json");
16
16
  /** Packages that consumers always install themselves — skip these in suggestions */
17
17
  const CONSUMER_PROVIDED = new Set(["react", "react-dom", "next"]);
18
18
  function findInstalledUxfPackages(projectPkg) {
@@ -25,7 +25,7 @@ function collectRequiredPeerDeps(uxfPackages, nodeModulesPath, projectPkg) {
25
25
  const peerDeps = new Map();
26
26
  for (const uxfPkg of uxfPackages) {
27
27
  const pkgJsonPath = path_1.default.join(nodeModulesPath, uxfPkg, "package.json");
28
- const pkgJson = (0, types_1.readPackageJson)(pkgJsonPath);
28
+ const pkgJson = (0, package_json_1.readPackageJson)(pkgJsonPath);
29
29
  if (!(pkgJson === null || pkgJson === void 0 ? void 0 : pkgJson.peerDependencies)) {
30
30
  continue;
31
31
  }
@@ -6,6 +6,7 @@ export interface PackageJson {
6
6
  uxf?: {
7
7
  ignoredConflicts?: string[];
8
8
  };
9
+ version?: string;
9
10
  }
10
11
  export interface DepInfo {
11
12
  isDev: boolean;
@@ -27,4 +28,3 @@ export interface Conflict {
27
28
  * Every lock file parser must return this shape.
28
29
  */
29
30
  export type LockData = Map<string, Set<string>>;
30
- export declare function readPackageJson(filePath: string): PackageJson | null;
@@ -1,15 +1,2 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  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
- }