app-builder-lib 26.4.0 → 26.5.0

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.
Files changed (54) hide show
  1. package/out/asar/asarUtil.js +105 -73
  2. package/out/asar/asarUtil.js.map +1 -1
  3. package/out/macPackager.js +5 -0
  4. package/out/macPackager.js.map +1 -1
  5. package/out/node-module-collector/bunNodeModulesCollector.d.ts +4 -5
  6. package/out/node-module-collector/bunNodeModulesCollector.js +5 -9
  7. package/out/node-module-collector/bunNodeModulesCollector.js.map +1 -1
  8. package/out/node-module-collector/hoist.js +7 -4
  9. package/out/node-module-collector/hoist.js.map +1 -1
  10. package/out/node-module-collector/index.d.ts +5 -4
  11. package/out/node-module-collector/index.js +6 -3
  12. package/out/node-module-collector/index.js.map +1 -1
  13. package/out/node-module-collector/moduleManager.d.ts +52 -0
  14. package/out/node-module-collector/moduleManager.js +227 -0
  15. package/out/node-module-collector/moduleManager.js.map +1 -0
  16. package/out/node-module-collector/nodeModulesCollector.d.ts +97 -24
  17. package/out/node-module-collector/nodeModulesCollector.js +154 -183
  18. package/out/node-module-collector/nodeModulesCollector.js.map +1 -1
  19. package/out/node-module-collector/npmNodeModulesCollector.d.ts +3 -10
  20. package/out/node-module-collector/npmNodeModulesCollector.js +14 -88
  21. package/out/node-module-collector/npmNodeModulesCollector.js.map +1 -1
  22. package/out/node-module-collector/packageManager.d.ts +2 -1
  23. package/out/node-module-collector/packageManager.js +2 -0
  24. package/out/node-module-collector/packageManager.js.map +1 -1
  25. package/out/node-module-collector/pnpmNodeModulesCollector.d.ts +1 -1
  26. package/out/node-module-collector/pnpmNodeModulesCollector.js +14 -21
  27. package/out/node-module-collector/pnpmNodeModulesCollector.js.map +1 -1
  28. package/out/node-module-collector/traversalNodeModulesCollector.d.ts +18 -0
  29. package/out/node-module-collector/traversalNodeModulesCollector.js +119 -0
  30. package/out/node-module-collector/traversalNodeModulesCollector.js.map +1 -0
  31. package/out/node-module-collector/types.d.ts +5 -10
  32. package/out/node-module-collector/types.js.map +1 -1
  33. package/out/node-module-collector/yarnBerryNodeModulesCollector.js +3 -3
  34. package/out/node-module-collector/yarnBerryNodeModulesCollector.js.map +1 -1
  35. package/out/node-module-collector/yarnNodeModulesCollector.d.ts +1 -2
  36. package/out/node-module-collector/yarnNodeModulesCollector.js +4 -30
  37. package/out/node-module-collector/yarnNodeModulesCollector.js.map +1 -1
  38. package/out/options/macOptions.d.ts +5 -0
  39. package/out/options/macOptions.js.map +1 -1
  40. package/out/publish/PublishManager.js +3 -2
  41. package/out/publish/PublishManager.js.map +1 -1
  42. package/out/targets/archive.js.map +1 -1
  43. package/out/util/appFileCopier.js +16 -12
  44. package/out/util/appFileCopier.js.map +1 -1
  45. package/out/util/packageDependencies.js +2 -1
  46. package/out/util/packageDependencies.js.map +1 -1
  47. package/out/version.d.ts +1 -1
  48. package/out/version.js +1 -1
  49. package/out/version.js.map +1 -1
  50. package/package.json +9 -10
  51. package/scheme.json +7 -0
  52. package/out/node-module-collector/moduleCache.d.ts +0 -27
  53. package/out/node-module-collector/moduleCache.js +0 -65
  54. package/out/node-module-collector/moduleCache.js.map +0 -1
@@ -0,0 +1,52 @@
1
+ import { PackageJson } from "./types";
2
+ import * as fs from "fs-extra";
3
+ export type Package = {
4
+ packageDir: string;
5
+ packageJson: PackageJson;
6
+ };
7
+ type JsonCache = Record<string, Promise<PackageJson | null>>;
8
+ type RealPathCache = Record<string, Promise<string>>;
9
+ type ExistsCache = Record<string, Promise<boolean>>;
10
+ type LstatCache = Record<string, Promise<fs.Stats | null>>;
11
+ type PackageCache = Record<string, Promise<Package | null>>;
12
+ export declare class ModuleManager {
13
+ /** Cache for package.json contents (readJson) */
14
+ readonly json: JsonCache;
15
+ /** Cache for resolved real paths (if symlink, realpath; otherwise resolve) */
16
+ readonly realPath: RealPathCache;
17
+ /** Cache for file/directory existence checks */
18
+ readonly exists: ExistsCache;
19
+ /** Cache for lstat results */
20
+ readonly lstat: LstatCache;
21
+ /** Cache for package lookups (key: "packageName||fromDir||semverRange"). Use helper function `versionedCacheKey` */
22
+ readonly packageData: PackageCache;
23
+ private readonly jsonMap;
24
+ private readonly realPathMap;
25
+ private readonly existsMap;
26
+ private readonly lstatMap;
27
+ private readonly packageDataMap;
28
+ constructor();
29
+ private createAsyncProxy;
30
+ versionedCacheKey(pkg: {
31
+ name: string;
32
+ path: string;
33
+ semver?: string;
34
+ }): string;
35
+ protected locatePackageVersionFromCacheKey(key: string): Promise<Package | null>;
36
+ locatePackageVersion({ parentDir, pkgName, requiredRange }: {
37
+ parentDir: string;
38
+ pkgName: string;
39
+ requiredRange?: string;
40
+ }): Promise<Package | null>;
41
+ private semverSatisfies;
42
+ /**
43
+ * Upward search (hoisted)
44
+ */
45
+ private upwardSearch;
46
+ /**
47
+ * Breadth-first downward search from parentDir/node_modules
48
+ * Looks for node_modules/\*\/node_modules/pkgName (and deeper)
49
+ */
50
+ private downwardSearch;
51
+ }
52
+ export {};
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ModuleManager = void 0;
4
+ const builder_util_1 = require("builder-util");
5
+ const fs = require("fs-extra");
6
+ const path = require("path");
7
+ const semver = require("semver");
8
+ class ModuleManager {
9
+ constructor() {
10
+ this.jsonMap = new Map();
11
+ this.realPathMap = new Map();
12
+ this.existsMap = new Map();
13
+ this.lstatMap = new Map();
14
+ this.packageDataMap = new Map();
15
+ this.exists = this.createAsyncProxy(this.existsMap, (p) => (0, builder_util_1.exists)(p));
16
+ this.json = this.createAsyncProxy(this.jsonMap, (p) => fs.readJson(p).catch(() => null));
17
+ this.lstat = this.createAsyncProxy(this.lstatMap, (p) => fs.lstat(p).catch(() => null));
18
+ this.packageData = this.createAsyncProxy(this.packageDataMap, (p) => this.locatePackageVersionFromCacheKey(p).catch(() => null));
19
+ this.realPath = this.createAsyncProxy(this.realPathMap, async (p) => {
20
+ const filePath = path.resolve(p);
21
+ const stat = await this.lstat[filePath];
22
+ return (stat === null || stat === void 0 ? void 0 : stat.isSymbolicLink()) ? fs.realpath(filePath) : filePath;
23
+ });
24
+ }
25
+ // this allows dot-notation access while still supporting async retrieval
26
+ // e.g., cache.packageJson[somePath] returns Promise<PackageJson>
27
+ createAsyncProxy(map, compute) {
28
+ return new Proxy({}, {
29
+ async get(_, key) {
30
+ if (map.has(key)) {
31
+ return Promise.resolve(map.get(key));
32
+ }
33
+ return await Promise.resolve(compute(key)).then(value => {
34
+ map.set(key, value);
35
+ return value;
36
+ });
37
+ },
38
+ set(_, key, value) {
39
+ map.set(key, value);
40
+ return true;
41
+ },
42
+ has(_, key) {
43
+ return map.has(key);
44
+ },
45
+ });
46
+ }
47
+ versionedCacheKey(pkg) {
48
+ return [pkg.name, pkg.path, pkg.semver || ""].join("||");
49
+ }
50
+ async locatePackageVersionFromCacheKey(key) {
51
+ const [name, fromDir, semverRange] = key.split("||");
52
+ const result = await this.locatePackageVersion({ parentDir: fromDir, pkgName: name, requiredRange: semverRange });
53
+ if (result == null) {
54
+ return null;
55
+ }
56
+ return { ...result, packageDir: await this.realPath[result.packageDir] };
57
+ }
58
+ async locatePackageVersion({ parentDir, pkgName, requiredRange }) {
59
+ // 1) check direct parent node_modules/pkgName first
60
+ const direct = path.join(path.resolve(parentDir), "node_modules", pkgName, "package.json");
61
+ if (await this.exists[direct]) {
62
+ const json = await this.json[direct];
63
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
64
+ return { packageDir: path.dirname(direct), packageJson: json };
65
+ }
66
+ }
67
+ // 2) upward hoisted search, then 3) downward non-hoisted search
68
+ return (await this.upwardSearch(parentDir, pkgName, requiredRange)) || (await this.downwardSearch(parentDir, pkgName, requiredRange)) || null;
69
+ }
70
+ semverSatisfies(found, range) {
71
+ if ((0, builder_util_1.isEmptyOrSpaces)(range) || range === "*") {
72
+ return true;
73
+ }
74
+ if (range === found) {
75
+ return true;
76
+ }
77
+ if (semver.validRange(range) == null) {
78
+ // ignore, we can't verify non-semver ranges
79
+ // e.g. git urls, file:, patch:, etc. Example:
80
+ // "@ai-sdk/google": "patch:@ai-sdk/google@npm%3A2.0.43#~/.yarn/patches/@ai-sdk-google-npm-2.0.43-689ed559b3.patch"
81
+ builder_util_1.log.debug({ found, range }, "unable to validate semver version range, assuming match");
82
+ return true;
83
+ }
84
+ try {
85
+ return semver.satisfies(found, range);
86
+ }
87
+ catch {
88
+ // fallback: simple equality or basic prefix handling (^, ~)
89
+ if (range.startsWith("^") || range.startsWith("~")) {
90
+ const r = range.slice(1);
91
+ return r === found;
92
+ }
93
+ // if range is like "8.x" or "8.*" match major
94
+ const m = range.match(/^(\d+)[.(*|x)]*/);
95
+ const fm = found.match(/^(\d+)\./);
96
+ if (m && fm) {
97
+ return m[1] === fm[1];
98
+ }
99
+ return false;
100
+ }
101
+ }
102
+ /**
103
+ * Upward search (hoisted)
104
+ */
105
+ async upwardSearch(parentDir, pkgName, requiredRange) {
106
+ let current = path.resolve(parentDir);
107
+ const root = path.parse(current).root;
108
+ while (true) {
109
+ const candidate = path.join(current, "node_modules", pkgName, "package.json");
110
+ if (await this.exists[candidate]) {
111
+ const json = await this.json[candidate];
112
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
113
+ return { packageDir: path.dirname(candidate), packageJson: json };
114
+ }
115
+ // otherwise keep searching upward (we may find a different hoisted version)
116
+ }
117
+ if (current === root) {
118
+ break;
119
+ }
120
+ const parent = path.dirname(current);
121
+ if (parent === current) {
122
+ break;
123
+ }
124
+ current = parent;
125
+ }
126
+ return null;
127
+ }
128
+ /**
129
+ * Breadth-first downward search from parentDir/node_modules
130
+ * Looks for node_modules/\*\/node_modules/pkgName (and deeper)
131
+ */
132
+ async downwardSearch(parentDir, pkgName, requiredRange, maxExplored = 2000, maxDepth = 6) {
133
+ var _a, _b, _c, _d;
134
+ const start = path.join(path.resolve(parentDir), "node_modules");
135
+ if (!(await this.exists[start]) || !((_a = (await this.lstat[start])) === null || _a === void 0 ? void 0 : _a.isDirectory())) {
136
+ return null;
137
+ }
138
+ const visited = new Set();
139
+ const queue = [{ dir: start, depth: 0 }];
140
+ let explored = 0;
141
+ while (queue.length > 0) {
142
+ const { dir, depth } = queue.shift();
143
+ if (explored++ > maxExplored) {
144
+ break;
145
+ }
146
+ if (depth > maxDepth) {
147
+ continue;
148
+ }
149
+ let entries;
150
+ try {
151
+ entries = await fs.readdir(dir);
152
+ }
153
+ catch {
154
+ continue;
155
+ }
156
+ for (const entry of entries) {
157
+ if (entry.startsWith(".")) {
158
+ continue;
159
+ }
160
+ const entryPath = path.join(dir, entry);
161
+ // handle scoped packages @scope/name
162
+ if (entry.startsWith("@")) {
163
+ // queue the scope directory itself to explore its children
164
+ if ((await this.exists[entryPath]) && ((_b = (await this.lstat[entryPath])) === null || _b === void 0 ? void 0 : _b.isDirectory())) {
165
+ const scopeEntries = await fs.readdir(entryPath);
166
+ for (const sc of scopeEntries) {
167
+ const scPath = path.join(entryPath, sc);
168
+ // check scPath/node_modules/pkgName
169
+ const candidatePkgJson = path.join(scPath, "node_modules", pkgName, "package.json");
170
+ if (await this.exists[candidatePkgJson]) {
171
+ const json = await this.json[candidatePkgJson];
172
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
173
+ return { packageDir: path.dirname(candidatePkgJson), packageJson: json };
174
+ }
175
+ }
176
+ // enqueue scPath/node_modules to explore further
177
+ const scNodeModules = path.join(scPath, "node_modules");
178
+ if ((await this.exists[scNodeModules]) && ((_c = (await this.lstat[scNodeModules])) === null || _c === void 0 ? void 0 : _c.isDirectory())) {
179
+ if (!visited.has(scNodeModules)) {
180
+ visited.add(scNodeModules);
181
+ queue.push({ dir: scNodeModules, depth: depth + 1 });
182
+ }
183
+ }
184
+ }
185
+ }
186
+ continue;
187
+ }
188
+ // check for direct candidate: entry/node_modules/pkgName
189
+ try {
190
+ const stat = await this.lstat[entryPath];
191
+ if (!(stat === null || stat === void 0 ? void 0 : stat.isDirectory())) {
192
+ continue;
193
+ }
194
+ }
195
+ catch {
196
+ continue;
197
+ }
198
+ const candidatePkgJson = path.join(entryPath, "node_modules", pkgName, "package.json");
199
+ if (await this.exists[candidatePkgJson]) {
200
+ const json = await this.json[candidatePkgJson];
201
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
202
+ return { packageDir: path.dirname(candidatePkgJson), packageJson: json };
203
+ }
204
+ }
205
+ // also check entry/node_modules directly for pkgName (some layouts)
206
+ const candidateDirect = path.join(entryPath, pkgName, "package.json");
207
+ if (await this.exists[candidateDirect]) {
208
+ const json = await this.json[candidateDirect];
209
+ if (json && this.semverSatisfies(json.version, requiredRange)) {
210
+ return { packageDir: path.dirname(candidateDirect), packageJson: json };
211
+ }
212
+ }
213
+ // enqueue entry/node_modules for deeper traversal
214
+ const nextNodeModules = path.join(entryPath, "node_modules");
215
+ if ((await this.exists[nextNodeModules]) && ((_d = (await this.lstat[nextNodeModules])) === null || _d === void 0 ? void 0 : _d.isDirectory())) {
216
+ if (!visited.has(nextNodeModules)) {
217
+ visited.add(nextNodeModules);
218
+ queue.push({ dir: nextNodeModules, depth: depth + 1 });
219
+ }
220
+ }
221
+ }
222
+ }
223
+ return null;
224
+ }
225
+ }
226
+ exports.ModuleManager = ModuleManager;
227
+ //# sourceMappingURL=moduleManager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"moduleManager.js","sourceRoot":"","sources":["../../src/node-module-collector/moduleManager.ts"],"names":[],"mappings":"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","sourcesContent":["import { exists, isEmptyOrSpaces, log } from \"builder-util\"\nimport { PackageJson } from \"./types\"\nimport * as fs from \"fs-extra\"\nimport * as path from \"path\"\nimport * as semver from \"semver\"\n\nexport type Package = { packageDir: string; packageJson: PackageJson }\n\n// Type aliases for clarity\ntype JsonCache = Record<string, Promise<PackageJson | null>>\ntype RealPathCache = Record<string, Promise<string>>\ntype ExistsCache = Record<string, Promise<boolean>>\ntype LstatCache = Record<string, Promise<fs.Stats | null>>\ntype PackageCache = Record<string, Promise<Package | null>>\n\nexport class ModuleManager {\n /** Cache for package.json contents (readJson) */\n readonly json: JsonCache\n /** Cache for resolved real paths (if symlink, realpath; otherwise resolve) */\n readonly realPath: RealPathCache\n /** Cache for file/directory existence checks */\n readonly exists: ExistsCache\n /** Cache for lstat results */\n readonly lstat: LstatCache\n /** Cache for package lookups (key: \"packageName||fromDir||semverRange\"). Use helper function `versionedCacheKey` */\n readonly packageData: PackageCache\n\n private readonly jsonMap: Map<string, PackageJson | null> = new Map()\n private readonly realPathMap: Map<string, string> = new Map()\n private readonly existsMap: Map<string, boolean> = new Map()\n private readonly lstatMap: Map<string, fs.Stats | null> = new Map()\n private readonly packageDataMap: Map<string, Package | null> = new Map()\n\n constructor() {\n this.exists = this.createAsyncProxy(this.existsMap, (p: string) => exists(p))\n this.json = this.createAsyncProxy(this.jsonMap, (p: string) => fs.readJson(p).catch(() => null))\n this.lstat = this.createAsyncProxy(this.lstatMap, (p: string) => fs.lstat(p).catch(() => null))\n this.packageData = this.createAsyncProxy(this.packageDataMap, (p: string) => this.locatePackageVersionFromCacheKey(p).catch(() => null))\n this.realPath = this.createAsyncProxy(this.realPathMap, async (p: string) => {\n const filePath = path.resolve(p)\n const stat = await this.lstat[filePath]\n return stat?.isSymbolicLink() ? fs.realpath(filePath) : filePath\n })\n }\n\n // this allows dot-notation access while still supporting async retrieval\n // e.g., cache.packageJson[somePath] returns Promise<PackageJson>\n private createAsyncProxy<T>(map: Map<string, T>, compute: (key: string) => T | Promise<T>): Record<string, Promise<T>> {\n return new Proxy({} as Record<string, Promise<T>>, {\n async get(_, key: string) {\n if (map.has(key)) {\n return Promise.resolve(map.get(key)!)\n }\n return await Promise.resolve(compute(key)).then(value => {\n map.set(key, value)\n return value\n })\n },\n set(_, key: string, value: T) {\n map.set(key, value)\n return true\n },\n has(_, key: string) {\n return map.has(key)\n },\n })\n }\n\n versionedCacheKey(pkg: { name: string; path: string; semver?: string }): string {\n return [pkg.name, pkg.path, pkg.semver || \"\"].join(\"||\")\n }\n\n protected async locatePackageVersionFromCacheKey(key: string): Promise<Package | null> {\n const [name, fromDir, semverRange] = key.split(\"||\")\n const result = await this.locatePackageVersion({ parentDir: fromDir, pkgName: name, requiredRange: semverRange })\n if (result == null) {\n return null\n }\n return { ...result, packageDir: await this.realPath[result.packageDir] }\n }\n\n public async locatePackageVersion({ parentDir, pkgName, requiredRange }: { parentDir: string; pkgName: string; requiredRange?: string }): Promise<Package | null> {\n // 1) check direct parent node_modules/pkgName first\n const direct = path.join(path.resolve(parentDir), \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[direct]) {\n const json = await this.json[direct]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(direct), packageJson: json }\n }\n }\n\n // 2) upward hoisted search, then 3) downward non-hoisted search\n return (await this.upwardSearch(parentDir, pkgName, requiredRange)) || (await this.downwardSearch(parentDir, pkgName, requiredRange)) || null\n }\n\n private semverSatisfies(found: string, range?: string): boolean {\n if (isEmptyOrSpaces(range) || range === \"*\") {\n return true\n }\n\n if (range === found) {\n return true\n }\n\n if (semver.validRange(range) == null) {\n // ignore, we can't verify non-semver ranges\n // e.g. git urls, file:, patch:, etc. Example:\n // \"@ai-sdk/google\": \"patch:@ai-sdk/google@npm%3A2.0.43#~/.yarn/patches/@ai-sdk-google-npm-2.0.43-689ed559b3.patch\"\n log.debug({ found, range }, \"unable to validate semver version range, assuming match\")\n return true\n }\n\n try {\n return semver.satisfies(found, range)\n } catch {\n // fallback: simple equality or basic prefix handling (^, ~)\n if (range.startsWith(\"^\") || range.startsWith(\"~\")) {\n const r = range.slice(1)\n return r === found\n }\n // if range is like \"8.x\" or \"8.*\" match major\n const m = range.match(/^(\\d+)[.(*|x)]*/)\n const fm = found.match(/^(\\d+)\\./)\n if (m && fm) {\n return m[1] === fm[1]\n }\n return false\n }\n }\n\n /**\n * Upward search (hoisted)\n */\n private async upwardSearch(parentDir: string, pkgName: string, requiredRange?: string): Promise<Package | null> {\n let current = path.resolve(parentDir)\n const root = path.parse(current).root\n while (true) {\n const candidate = path.join(current, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidate]) {\n const json = await this.json[candidate]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidate), packageJson: json }\n }\n // otherwise keep searching upward (we may find a different hoisted version)\n }\n if (current === root) {\n break\n }\n const parent = path.dirname(current)\n if (parent === current) {\n break\n }\n current = parent\n }\n return null\n }\n\n /**\n * Breadth-first downward search from parentDir/node_modules\n * Looks for node_modules/\\*\\/node_modules/pkgName (and deeper)\n */\n private async downwardSearch(parentDir: string, pkgName: string, requiredRange?: string, maxExplored = 2000, maxDepth = 6): Promise<Package | null> {\n const start = path.join(path.resolve(parentDir), \"node_modules\")\n if (!(await this.exists[start]) || !(await this.lstat[start])?.isDirectory()) {\n return null\n }\n\n const visited = new Set<string>()\n const queue: Array<{ dir: string; depth: number }> = [{ dir: start, depth: 0 }]\n let explored = 0\n\n while (queue.length > 0) {\n const { dir, depth } = queue.shift()!\n if (explored++ > maxExplored) {\n break\n }\n if (depth > maxDepth) {\n continue\n }\n let entries: string[]\n try {\n entries = await fs.readdir(dir)\n } catch {\n continue\n }\n for (const entry of entries) {\n if (entry.startsWith(\".\")) {\n continue\n }\n const entryPath = path.join(dir, entry)\n // handle scoped packages @scope/name\n if (entry.startsWith(\"@\")) {\n // queue the scope directory itself to explore its children\n if ((await this.exists[entryPath]) && (await this.lstat[entryPath])?.isDirectory()) {\n const scopeEntries = await fs.readdir(entryPath)\n for (const sc of scopeEntries) {\n const scPath = path.join(entryPath, sc)\n // check scPath/node_modules/pkgName\n const candidatePkgJson = path.join(scPath, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidatePkgJson]) {\n const json = await this.json[candidatePkgJson]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidatePkgJson), packageJson: json }\n }\n }\n // enqueue scPath/node_modules to explore further\n const scNodeModules = path.join(scPath, \"node_modules\")\n if ((await this.exists[scNodeModules]) && (await this.lstat[scNodeModules])?.isDirectory()) {\n if (!visited.has(scNodeModules)) {\n visited.add(scNodeModules)\n queue.push({ dir: scNodeModules, depth: depth + 1 })\n }\n }\n }\n }\n continue\n }\n\n // check for direct candidate: entry/node_modules/pkgName\n try {\n const stat = await this.lstat[entryPath]\n if (!stat?.isDirectory()) {\n continue\n }\n } catch {\n continue\n }\n\n const candidatePkgJson = path.join(entryPath, \"node_modules\", pkgName, \"package.json\")\n if (await this.exists[candidatePkgJson]) {\n const json = await this.json[candidatePkgJson]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidatePkgJson), packageJson: json }\n }\n }\n\n // also check entry/node_modules directly for pkgName (some layouts)\n const candidateDirect = path.join(entryPath, pkgName, \"package.json\")\n if (await this.exists[candidateDirect]) {\n const json = await this.json[candidateDirect]\n if (json && this.semverSatisfies(json.version, requiredRange)) {\n return { packageDir: path.dirname(candidateDirect), packageJson: json }\n }\n }\n\n // enqueue entry/node_modules for deeper traversal\n const nextNodeModules = path.join(entryPath, \"node_modules\")\n if ((await this.exists[nextNodeModules]) && (await this.lstat[nextNodeModules])?.isDirectory()) {\n if (!visited.has(nextNodeModules)) {\n visited.add(nextNodeModules)\n queue.push({ dir: nextNodeModules, depth: depth + 1 })\n }\n }\n }\n }\n\n return null\n }\n}\n"]}
@@ -1,24 +1,33 @@
1
1
  import { TmpDir } from "builder-util";
2
- import { CancellationToken } from "builder-util-runtime";
3
2
  import { Lazy } from "lazy-val";
4
- import { ModuleCache } from "./moduleCache";
3
+ import { ModuleManager } from "./moduleManager";
5
4
  import { PM } from "./packageManager";
6
- import type { Dependency, DependencyGraph, NodeModuleInfo } from "./types";
7
- type Result = {
8
- packageDir: string;
9
- version: string;
10
- } | null;
5
+ import type { Dependency, DependencyGraph, NodeModuleInfo, PackageJson } from "./types";
11
6
  export declare abstract class NodeModulesCollector<ProdDepType extends Dependency<ProdDepType, OptionalDepType>, OptionalDepType> {
12
7
  protected readonly rootDir: string;
13
8
  private readonly tempDirManager;
14
9
  private readonly nodeModules;
15
10
  protected readonly allDependencies: Map<string, ProdDepType>;
16
11
  protected readonly productionGraph: DependencyGraph;
17
- protected readonly cache: ModuleCache;
12
+ protected readonly cache: ModuleManager;
18
13
  protected isHoisted: Lazy<boolean>;
19
14
  constructor(rootDir: string, tempDirManager: TmpDir);
20
- getNodeModules({ cancellationToken, packageName }: {
21
- cancellationToken: CancellationToken;
15
+ /**
16
+ * Retrieves and collects all Node.js modules for a given package.
17
+ *
18
+ * This method orchestrates the entire module collection process by:
19
+ * 1. Fetching the dependency tree from the package manager
20
+ * 2. Collecting all dependencies recursively
21
+ * 3. Extracting workspace references if applicable
22
+ * 4. Building a production dependency graph
23
+ * 5. Hoisting the dependencies to their final locations
24
+ * 6. Resolving and returning module information
25
+ *
26
+ * @param options - Configuration object
27
+ * @param options.packageName - The name of the package to collect modules for
28
+ * @returns Promise resolving to an array of NodeModuleInfo objects representing all collected modules
29
+ */
30
+ getNodeModules({ packageName }: {
22
31
  packageName: string;
23
32
  }): Promise<NodeModuleInfo[]>;
24
33
  abstract readonly installOptions: {
@@ -26,20 +35,81 @@ export declare abstract class NodeModulesCollector<ProdDepType extends Dependenc
26
35
  lockfile: string;
27
36
  };
28
37
  protected abstract getArgs(): string[];
29
- protected abstract parseDependenciesTree(jsonBlob: string): Promise<ProdDepType>;
30
38
  protected abstract extractProductionDependencyGraph(tree: Dependency<ProdDepType, OptionalDepType>, dependencyId: string): Promise<void>;
31
39
  protected abstract collectAllDependencies(tree: Dependency<ProdDepType, OptionalDepType>, appPackageName: string): Promise<void>;
40
+ /**
41
+ * Retrieves the dependency tree from the package manager.
42
+ *
43
+ * Executes the appropriate package manager command to fetch the dependency tree and writes
44
+ * the output to a temporary file. Includes retry logic to handle transient failures such as
45
+ * incomplete JSON output or missing files. Will retry up to 1 time with exponential backoff.
46
+ *
47
+ * @param pm - The package manager to use (npm, yarn, pnpm, etc.)
48
+ * @returns Promise resolving to the parsed dependency tree
49
+ * @throws {Error} If the dependency tree cannot be retrieved after retries
50
+ */
32
51
  protected getDependenciesTree(pm: PM): Promise<ProdDepType>;
52
+ /**
53
+ * Parses the dependencies tree from shell command output.
54
+ *
55
+ **/
56
+ protected parseDependenciesTree(shellOutput: string): ProdDepType | Promise<ProdDepType>;
57
+ /**
58
+ *
59
+ * This method attempts to extract and parse JSON data from shell output that may contain
60
+ * additional non-JSON content (like warnings or informational messages). It first tries
61
+ * to parse the entire output as JSON, and if that fails, it intelligently searches for
62
+ * JSON content within the output by:
63
+ * 1. Finding the first line that starts with `{` or `[`
64
+ * 2. Tracking bracket depth to find the matching closing bracket
65
+ * 3. Extracting only the valid JSON portion
66
+ *
67
+ * @param shellOutput - The raw output from a shell command, potentially containing JSON
68
+ * @returns The parsed dependencies tree object
69
+ * @throws {Error} If no JSON content is found in the output
70
+ * @throws {Error} If no matching closing bracket is found in the output
71
+ * @throws {SyntaxError} If the extracted content is not valid JSON
72
+ */
73
+ protected extractJsonFromPollutedOutput<T>(shellOutput: string): T;
33
74
  protected cacheKey(pkg: Pick<ProdDepType, "name" | "version" | "path">): string;
34
75
  protected packageVersionString(pkg: Pick<ProdDepType, "name" | "version">): string;
76
+ /**
77
+ * Determines if a given dependency is a production dependency of a package.
78
+ *
79
+ * Checks both the dependencies and optionalDependencies of a package to see if
80
+ * the specified dependency name is listed.
81
+ *
82
+ * @param depName - The name of the dependency to check
83
+ * @param pkg - The package to search for the dependency in
84
+ * @returns True if the dependency is found in either dependencies or optionalDependencies, false otherwise
85
+ */
35
86
  protected isProdDependency(depName: string, pkg: ProdDepType): boolean;
87
+ protected locatePackageWithVersion(depTree: Pick<ProdDepType, "name" | "version" | "path">): Promise<{
88
+ packageDir: string;
89
+ packageJson: PackageJson;
90
+ } | null>;
36
91
  /**
37
- * Parse a dependency identifier like "@scope/pkg@1.2.3" or "pkg@1.2.3"
92
+ * Parses a dependency identifier string into name and version components.
93
+ *
94
+ * Handles both scoped packages (e.g., "@scope/pkg@1.2.3") and regular packages (e.g., "pkg@1.2.3").
95
+ * If the identifier is malformed or cannot be parsed, defaults to treating the entire string as
96
+ * the package name with an "unknown" version.
38
97
  */
39
98
  protected parseNameVersion(identifier: string): {
40
99
  name: string;
41
100
  version: string;
42
101
  };
102
+ /**
103
+ * Retrieves the dependency tree and handles workspace package self-references.
104
+ *
105
+ * If the project is a workspace project, this method removes the root package's self-reference
106
+ * from the dependency tree to avoid circular dependencies. It promotes the root package's
107
+ * direct dependencies to the top level of the tree.
108
+ *
109
+ * @param tree - The original dependency tree
110
+ * @param packageName - The name of the package to check for and remove from the tree
111
+ * @returns Promise resolving to the pruned dependency tree
112
+ */
43
113
  protected getTreeFromWorkspaces(tree: ProdDepType, packageName: string): Promise<ProdDepType>;
44
114
  private transformToHoisterTree;
45
115
  private _getNodeModules;
@@ -47,18 +117,21 @@ export declare abstract class NodeModulesCollector<ProdDepType extends Dependenc
47
117
  stdout: string | undefined;
48
118
  stderr: string | undefined;
49
119
  }>;
50
- streamCollectorCommandToFile(command: string, args: string[], cwd: string, tempOutputFile: string): Promise<void>;
51
- protected locatePackageVersion(parentDir: string, pkgName: string, requiredRange?: string): Promise<Result | null>;
52
- protected readPackageVersion(pkgJsonPath: string): Promise<string | null>;
53
- protected semverSatisfies(found: string, range?: string): boolean;
54
120
  /**
55
- * Upward search (hoisted)
121
+ * Executes a command and streams its output to a file.
122
+ *
123
+ * Spawns a child process to execute the specified command with arguments, capturing stdout
124
+ * to a file. Handles Windows-specific quirks by wrapping .cmd files in a temporary .bat file
125
+ * when necessary. Enables corepack strict mode by default but allows process.env overrides.
126
+ *
127
+ * Special handling for `npm list` exit code 1, which is expected in certain scenarios.
128
+ *
129
+ * @param command - The command to execute
130
+ * @param args - Array of command-line arguments
131
+ * @param cwd - The working directory to execute the command in
132
+ * @param tempOutputFile - The path to the temporary file where stdout will be written
133
+ * @returns Promise that resolves when the command completes successfully or rejects if it fails
134
+ * @throws {Error} If the child process spawn fails or exits with a non-zero code
56
135
  */
57
- private upwardSearch;
58
- /**
59
- * Breadth-first downward search from parentDir/node_modules
60
- * Looks for node_modules/\*\/node_modules/pkgName (and deeper)
61
- */
62
- private downwardSearch;
136
+ streamCollectorCommandToFile(command: string, args: string[], cwd: string, tempOutputFile: string): Promise<void>;
63
137
  }
64
- export {};