@openrewrite/rewrite 8.68.0-20251202-082117 → 8.68.0-20251202-162533
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/javascript/assertions.d.ts +1 -0
- package/dist/javascript/assertions.d.ts.map +1 -1
- package/dist/javascript/assertions.js +82 -11
- package/dist/javascript/assertions.js.map +1 -1
- package/dist/javascript/dependency-workspace.d.ts +46 -5
- package/dist/javascript/dependency-workspace.d.ts.map +1 -1
- package/dist/javascript/dependency-workspace.js +70 -35
- package/dist/javascript/dependency-workspace.js.map +1 -1
- package/dist/javascript/index.d.ts +2 -0
- package/dist/javascript/index.d.ts.map +1 -1
- package/dist/javascript/index.js +2 -0
- package/dist/javascript/index.js.map +1 -1
- package/dist/javascript/node-resolution-result.d.ts +204 -0
- package/dist/javascript/node-resolution-result.d.ts.map +1 -0
- package/dist/javascript/node-resolution-result.js +723 -0
- package/dist/javascript/node-resolution-result.js.map +1 -0
- package/dist/javascript/package-json-parser.d.ts +143 -0
- package/dist/javascript/package-json-parser.d.ts.map +1 -0
- package/dist/javascript/package-json-parser.js +773 -0
- package/dist/javascript/package-json-parser.js.map +1 -0
- package/dist/javascript/templating/engine.js +1 -1
- package/dist/javascript/templating/engine.js.map +1 -1
- package/dist/json/parser.js +10 -1
- package/dist/json/parser.js.map +1 -1
- package/dist/json/tree.d.ts +1 -1
- package/dist/json/tree.js +1 -1
- package/dist/json/tree.js.map +1 -1
- package/dist/parser.d.ts +1 -1
- package/dist/parser.d.ts.map +1 -1
- package/dist/rpc/request/parse.d.ts +4 -0
- package/dist/rpc/request/parse.d.ts.map +1 -1
- package/dist/rpc/request/parse.js +17 -1
- package/dist/rpc/request/parse.js.map +1 -1
- package/dist/version.txt +1 -1
- package/package.json +5 -2
- package/src/javascript/assertions.ts +73 -15
- package/src/javascript/dependency-workspace.ts +124 -46
- package/src/javascript/index.ts +2 -0
- package/src/javascript/node-resolution-result.ts +905 -0
- package/src/javascript/package-json-parser.ts +845 -0
- package/src/javascript/templating/engine.ts +1 -1
- package/src/json/parser.ts +18 -1
- package/src/json/tree.ts +1 -1
- package/src/parser.ts +1 -1
- package/src/rpc/request/parse.ts +20 -2
|
@@ -0,0 +1,723 @@
|
|
|
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 __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
36
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
37
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
38
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
39
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
40
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
41
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
42
|
+
});
|
|
43
|
+
};
|
|
44
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
45
|
+
exports.NodeResolutionResultQueries = exports.NpmrcKind = exports.NpmrcScope = exports.PackageManager = exports.ResolvedDependencyKind = exports.DependencyKind = exports.NodeResolutionResultKind = void 0;
|
|
46
|
+
exports.createNodeResolutionResultMarker = createNodeResolutionResultMarker;
|
|
47
|
+
exports.findNodeResolutionResult = findNodeResolutionResult;
|
|
48
|
+
exports.readNpmrcConfigs = readNpmrcConfigs;
|
|
49
|
+
/*
|
|
50
|
+
* Copyright 2025 the original author or authors.
|
|
51
|
+
* <p>
|
|
52
|
+
* Licensed under the Moderne Source Available License (the "License");
|
|
53
|
+
* you may not use this file except in compliance with the License.
|
|
54
|
+
* You may obtain a copy of the License at
|
|
55
|
+
* <p>
|
|
56
|
+
* https://docs.moderne.io/licensing/moderne-source-available-license
|
|
57
|
+
* <p>
|
|
58
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
59
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
60
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
61
|
+
* See the License for the specific language governing permissions and
|
|
62
|
+
* limitations under the License.
|
|
63
|
+
*/
|
|
64
|
+
const markers_1 = require("../markers");
|
|
65
|
+
const uuid_1 = require("../uuid");
|
|
66
|
+
const reference_1 = require("../reference");
|
|
67
|
+
const rpc_1 = require("../rpc");
|
|
68
|
+
const immer_1 = require("immer");
|
|
69
|
+
const semver = __importStar(require("semver"));
|
|
70
|
+
const fsp = __importStar(require("fs/promises"));
|
|
71
|
+
const path = __importStar(require("path"));
|
|
72
|
+
const os_1 = require("os");
|
|
73
|
+
exports.NodeResolutionResultKind = "org.openrewrite.javascript.marker.NodeResolutionResult";
|
|
74
|
+
exports.DependencyKind = "org.openrewrite.javascript.marker.NodeResolutionResult$Dependency";
|
|
75
|
+
exports.ResolvedDependencyKind = "org.openrewrite.javascript.marker.NodeResolutionResult$ResolvedDependency";
|
|
76
|
+
/**
|
|
77
|
+
* Represents the package manager used by a Node.js project.
|
|
78
|
+
*/
|
|
79
|
+
var PackageManager;
|
|
80
|
+
(function (PackageManager) {
|
|
81
|
+
PackageManager["Npm"] = "Npm";
|
|
82
|
+
PackageManager["YarnClassic"] = "YarnClassic";
|
|
83
|
+
PackageManager["YarnBerry"] = "YarnBerry";
|
|
84
|
+
PackageManager["Pnpm"] = "Pnpm";
|
|
85
|
+
PackageManager["Bun"] = "Bun";
|
|
86
|
+
})(PackageManager || (exports.PackageManager = PackageManager = {}));
|
|
87
|
+
/**
|
|
88
|
+
* Represents the scope/source of an npmrc configuration.
|
|
89
|
+
* Listed from lowest to highest priority.
|
|
90
|
+
*/
|
|
91
|
+
var NpmrcScope;
|
|
92
|
+
(function (NpmrcScope) {
|
|
93
|
+
NpmrcScope["Global"] = "Global";
|
|
94
|
+
NpmrcScope["User"] = "User";
|
|
95
|
+
NpmrcScope["Project"] = "Project";
|
|
96
|
+
})(NpmrcScope || (exports.NpmrcScope = NpmrcScope = {}));
|
|
97
|
+
exports.NpmrcKind = "org.openrewrite.javascript.marker.NodeResolutionResult$Npmrc";
|
|
98
|
+
/**
|
|
99
|
+
* Creates a NodeResolutionResult marker from a package.json file.
|
|
100
|
+
* Should be called during parsing to attach to JS.CompilationUnit.
|
|
101
|
+
*
|
|
102
|
+
* All Dependency instances are wrapped with asRef() to enable
|
|
103
|
+
* reference deduplication during RPC serialization.
|
|
104
|
+
*
|
|
105
|
+
* @param path Path to the package.json file
|
|
106
|
+
* @param packageJsonContent Parsed package.json content
|
|
107
|
+
* @param packageLockContent Optional parsed package-lock.json content for resolution info
|
|
108
|
+
* @param workspacePackagePaths Optional resolved paths to workspace package.json files (only for workspace root)
|
|
109
|
+
* @param packageManager Optional package manager that was detected from lock file
|
|
110
|
+
* @param npmrcConfigs Optional npm configuration from various scopes
|
|
111
|
+
*/
|
|
112
|
+
function createNodeResolutionResultMarker(path, packageJsonContent, packageLockContent, workspacePackagePaths, packageManager, npmrcConfigs) {
|
|
113
|
+
// Cache for deduplicating resolved dependencies with the same name+version.
|
|
114
|
+
const resolvedDependencyCache = new Map();
|
|
115
|
+
// Index from package name to all resolved versions (for O(1) semver fallback lookup)
|
|
116
|
+
const nameToResolved = new Map();
|
|
117
|
+
// Map from lock file path to ResolvedDependency for path-based lookups.
|
|
118
|
+
// e.g., "node_modules/is-odd" -> ResolvedDependency for is-odd@3.0.1
|
|
119
|
+
const pathToResolved = new Map();
|
|
120
|
+
// Cache for deduplicating dependencies with the same name+versionConstraint+contextPath.
|
|
121
|
+
const dependencyCache = new Map();
|
|
122
|
+
/**
|
|
123
|
+
* Normalizes the engines field from package-lock.json.
|
|
124
|
+
* Some older packages have engines as an array like ["node >=0.6.0"] instead of
|
|
125
|
+
* the standard object format {"node": ">=0.6.0"}.
|
|
126
|
+
*/
|
|
127
|
+
function normalizeEngines(engines) {
|
|
128
|
+
if (!engines)
|
|
129
|
+
return undefined;
|
|
130
|
+
if (Array.isArray(engines)) {
|
|
131
|
+
// Convert array format to object format
|
|
132
|
+
// e.g., ["node >=0.6.0"] -> {"node": ">=0.6.0"}
|
|
133
|
+
const result = {};
|
|
134
|
+
for (const entry of engines) {
|
|
135
|
+
const spaceIdx = entry.indexOf(' ');
|
|
136
|
+
if (spaceIdx > 0) {
|
|
137
|
+
const key = entry.substring(0, spaceIdx);
|
|
138
|
+
result[key] = entry.substring(spaceIdx + 1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
142
|
+
}
|
|
143
|
+
return engines;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Extracts package name and optionally version from a package-lock.json path.
|
|
147
|
+
* e.g., "node_modules/@babel/core" -> { name: "@babel/core" }
|
|
148
|
+
* e.g., "node_modules/foo/node_modules/bar" -> { name: "bar" }
|
|
149
|
+
* e.g., "node_modules/is-odd@3.0.1" -> { name: "is-odd", version: "3.0.1" }
|
|
150
|
+
*/
|
|
151
|
+
function extractPackageInfo(pkgPath) {
|
|
152
|
+
// For nested packages, we want the last package name
|
|
153
|
+
const nodeModulesIndex = pkgPath.lastIndexOf('node_modules/');
|
|
154
|
+
if (nodeModulesIndex === -1)
|
|
155
|
+
return { name: pkgPath };
|
|
156
|
+
let nameWithVersion = pkgPath.slice(nodeModulesIndex + 'node_modules/'.length);
|
|
157
|
+
// Check if the path has a version suffix (e.g., "is-odd@3.0.1")
|
|
158
|
+
// Handle scoped packages (@scope/name@version) correctly
|
|
159
|
+
const atIndex = nameWithVersion.lastIndexOf('@');
|
|
160
|
+
if (atIndex > 0 && !nameWithVersion.substring(0, atIndex).includes('/')) {
|
|
161
|
+
// Not a scoped package, the @ is a version separator
|
|
162
|
+
return {
|
|
163
|
+
name: nameWithVersion.substring(0, atIndex),
|
|
164
|
+
version: nameWithVersion.substring(atIndex + 1)
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
else if (atIndex > 0) {
|
|
168
|
+
// Could be scoped package with version: @scope/name@version
|
|
169
|
+
const parts = nameWithVersion.split('@');
|
|
170
|
+
if (parts.length === 3 && parts[0] === '') {
|
|
171
|
+
// @scope/name@version -> ["", "scope/name", "version"]
|
|
172
|
+
return {
|
|
173
|
+
name: `@${parts[1]}`,
|
|
174
|
+
version: parts[2]
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
return { name: nameWithVersion };
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Creates or retrieves a ResolvedDependency from the cache.
|
|
182
|
+
* This ensures the same resolved package is reused across the dependency tree.
|
|
183
|
+
* Also maintains the nameToResolved index for O(1) name lookups.
|
|
184
|
+
*/
|
|
185
|
+
function getOrCreateResolvedDependency(name, version, pkgEntry) {
|
|
186
|
+
const key = `${name}@${version}`;
|
|
187
|
+
let resolved = resolvedDependencyCache.get(key);
|
|
188
|
+
if (!resolved) {
|
|
189
|
+
// Create a placeholder first - dependencies will be populated later
|
|
190
|
+
resolved = (0, reference_1.asRef)({
|
|
191
|
+
kind: exports.ResolvedDependencyKind,
|
|
192
|
+
name,
|
|
193
|
+
version,
|
|
194
|
+
dependencies: undefined,
|
|
195
|
+
devDependencies: undefined,
|
|
196
|
+
peerDependencies: undefined,
|
|
197
|
+
optionalDependencies: undefined,
|
|
198
|
+
engines: normalizeEngines(pkgEntry === null || pkgEntry === void 0 ? void 0 : pkgEntry.engines),
|
|
199
|
+
license: pkgEntry === null || pkgEntry === void 0 ? void 0 : pkgEntry.license,
|
|
200
|
+
});
|
|
201
|
+
resolvedDependencyCache.set(key, resolved);
|
|
202
|
+
// Maintain name index for O(1) lookup during semver fallback
|
|
203
|
+
const existing = nameToResolved.get(name);
|
|
204
|
+
if (existing) {
|
|
205
|
+
existing.push(resolved);
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
nameToResolved.set(name, [resolved]);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return resolved;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Resolves a dependency name from a given context path using Node.js-style resolution.
|
|
215
|
+
* Looks for the package in nested node_modules first, then walks up to parent directories.
|
|
216
|
+
* Falls back to semver matching when path-based resolution fails (e.g., for yarn/pnpm).
|
|
217
|
+
*
|
|
218
|
+
* @param name Package name to resolve
|
|
219
|
+
* @param versionConstraint Version constraint (e.g., "^3.0.1") for semver fallback
|
|
220
|
+
* @param contextPath The path of the parent package (e.g., "node_modules/is-even")
|
|
221
|
+
* Use "" for root-level dependencies
|
|
222
|
+
*/
|
|
223
|
+
function resolveFromContext(name, versionConstraint, contextPath) {
|
|
224
|
+
// Start from the context path and walk up looking for the package
|
|
225
|
+
let currentPath = contextPath;
|
|
226
|
+
while (true) {
|
|
227
|
+
// Try to find the package in node_modules at this level
|
|
228
|
+
const candidatePath = currentPath
|
|
229
|
+
? `${currentPath}/node_modules/${name}`
|
|
230
|
+
: `node_modules/${name}`;
|
|
231
|
+
const resolved = pathToResolved.get(candidatePath);
|
|
232
|
+
if (resolved) {
|
|
233
|
+
return resolved;
|
|
234
|
+
}
|
|
235
|
+
// Walk up to parent directory
|
|
236
|
+
if (!currentPath) {
|
|
237
|
+
break; // Already at root
|
|
238
|
+
}
|
|
239
|
+
// Remove the last /node_modules/pkg segment to go up one level
|
|
240
|
+
const lastNodeModules = currentPath.lastIndexOf('/node_modules/');
|
|
241
|
+
if (lastNodeModules === -1) {
|
|
242
|
+
currentPath = ''; // Try root level next
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
currentPath = currentPath.substring(0, lastNodeModules);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// Fallback: use semver matching to find a version that satisfies the constraint
|
|
249
|
+
// This is needed for yarn/pnpm which don't encode nesting in their lock files
|
|
250
|
+
const candidates = nameToResolved.get(name);
|
|
251
|
+
if (!candidates || candidates.length === 0) {
|
|
252
|
+
return undefined;
|
|
253
|
+
}
|
|
254
|
+
if (candidates.length === 1) {
|
|
255
|
+
return candidates[0];
|
|
256
|
+
}
|
|
257
|
+
// Multiple versions - use semver to find the best match
|
|
258
|
+
// First try to find one that satisfies the constraint
|
|
259
|
+
for (const candidate of candidates) {
|
|
260
|
+
try {
|
|
261
|
+
if (semver.satisfies(candidate.version, versionConstraint)) {
|
|
262
|
+
return candidate;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
catch (_a) {
|
|
266
|
+
// Invalid semver, skip this candidate for matching
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
// If no exact match, return the highest version as fallback (O(n) linear scan)
|
|
270
|
+
let maxCandidate = candidates[0];
|
|
271
|
+
for (let i = 1; i < candidates.length; i++) {
|
|
272
|
+
try {
|
|
273
|
+
if (semver.compare(candidates[i].version, maxCandidate.version) > 0) {
|
|
274
|
+
maxCandidate = candidates[i];
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch (_b) {
|
|
278
|
+
// Invalid semver, skip comparison
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return maxCandidate;
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Creates or retrieves a Dependency from the cache.
|
|
285
|
+
* Links to resolved dependency using path-based Node.js-style resolution.
|
|
286
|
+
*
|
|
287
|
+
* @param name Package name
|
|
288
|
+
* @param versionConstraint Version constraint from package.json
|
|
289
|
+
* @param contextPath The path context for resolution (parent package path)
|
|
290
|
+
*/
|
|
291
|
+
function getOrCreateDependency(name, versionConstraint, contextPath) {
|
|
292
|
+
// Resolve first to determine the actual resolved version
|
|
293
|
+
const resolved = resolveFromContext(name, versionConstraint, contextPath);
|
|
294
|
+
// Key by name, constraint, and resolved version (not context path).
|
|
295
|
+
// This allows sharing Dependency objects when different contexts resolve to the same version.
|
|
296
|
+
const resolvedKey = resolved ? `${resolved.name}@${resolved.version}` : 'unresolved';
|
|
297
|
+
const key = `${name}@${versionConstraint}@${resolvedKey}`;
|
|
298
|
+
let dep = dependencyCache.get(key);
|
|
299
|
+
if (!dep) {
|
|
300
|
+
dep = (0, reference_1.asRef)({
|
|
301
|
+
kind: exports.DependencyKind,
|
|
302
|
+
name,
|
|
303
|
+
versionConstraint,
|
|
304
|
+
resolved,
|
|
305
|
+
});
|
|
306
|
+
dependencyCache.set(key, dep);
|
|
307
|
+
}
|
|
308
|
+
return dep;
|
|
309
|
+
}
|
|
310
|
+
/**
|
|
311
|
+
* Parses dependencies from a Record, using the given context path for resolution.
|
|
312
|
+
*/
|
|
313
|
+
function parseDependencies(deps, contextPath) {
|
|
314
|
+
if (!deps)
|
|
315
|
+
return [];
|
|
316
|
+
return Object.entries(deps).map(([name, versionConstraint]) => getOrCreateDependency(name, versionConstraint, contextPath));
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Parses bundled dependencies (array of names with no version constraint).
|
|
320
|
+
*/
|
|
321
|
+
function parseBundledDependencies(deps, contextPath) {
|
|
322
|
+
if (!deps)
|
|
323
|
+
return [];
|
|
324
|
+
return deps.map(name => getOrCreateDependency(name, '*', contextPath));
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Parses package-lock.json to build a list of resolved dependencies.
|
|
328
|
+
* Two-pass approach:
|
|
329
|
+
* 1. First pass: Create all ResolvedDependency objects and build path->resolved map
|
|
330
|
+
* 2. Second pass: Populate dependencies using path-based resolution
|
|
331
|
+
*/
|
|
332
|
+
function parseResolutions(lockContent) {
|
|
333
|
+
if (!lockContent.packages)
|
|
334
|
+
return [];
|
|
335
|
+
const packages = lockContent.packages;
|
|
336
|
+
// First pass: Create all ResolvedDependency placeholders and build path map
|
|
337
|
+
const packageInfos = [];
|
|
338
|
+
for (const [pkgPath, pkgEntry] of Object.entries(packages)) {
|
|
339
|
+
// Skip the root package (empty string key)
|
|
340
|
+
if (pkgPath === '')
|
|
341
|
+
continue;
|
|
342
|
+
const pkgInfo = extractPackageInfo(pkgPath);
|
|
343
|
+
const name = pkgInfo.name;
|
|
344
|
+
// Use version from path if available, otherwise from entry
|
|
345
|
+
const version = pkgInfo.version || pkgEntry.version;
|
|
346
|
+
if (name && version) {
|
|
347
|
+
const resolved = getOrCreateResolvedDependency(name, version, pkgEntry);
|
|
348
|
+
pathToResolved.set(pkgPath, resolved);
|
|
349
|
+
packageInfos.push({ path: pkgPath, name, version, entry: pkgEntry });
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
// Second pass: Populate dependencies using path-based resolution.
|
|
353
|
+
// Note: Using castDraft here is safe because all objects are created within this
|
|
354
|
+
// parsing context and haven't been returned to callers yet. The objects in
|
|
355
|
+
// resolvedDependencyCache are plain JS objects marked with asRef() for RPC
|
|
356
|
+
// reference deduplication, not frozen Immer drafts.
|
|
357
|
+
for (const { path: pkgPath, name, version, entry } of packageInfos) {
|
|
358
|
+
const key = `${name}@${version}`;
|
|
359
|
+
const resolved = resolvedDependencyCache.get(key);
|
|
360
|
+
if (resolved) {
|
|
361
|
+
const mutableResolved = (0, immer_1.castDraft)(resolved);
|
|
362
|
+
if (entry.dependencies) {
|
|
363
|
+
mutableResolved.dependencies = parseDependencies(entry.dependencies, pkgPath);
|
|
364
|
+
}
|
|
365
|
+
if (entry.devDependencies) {
|
|
366
|
+
mutableResolved.devDependencies = parseDependencies(entry.devDependencies, pkgPath);
|
|
367
|
+
}
|
|
368
|
+
if (entry.peerDependencies) {
|
|
369
|
+
mutableResolved.peerDependencies = parseDependencies(entry.peerDependencies, pkgPath);
|
|
370
|
+
}
|
|
371
|
+
if (entry.optionalDependencies) {
|
|
372
|
+
mutableResolved.optionalDependencies = parseDependencies(entry.optionalDependencies, pkgPath);
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
// Return all unique resolved dependencies
|
|
377
|
+
return Array.from(resolvedDependencyCache.values());
|
|
378
|
+
}
|
|
379
|
+
// Parse resolved dependencies first (before dependencies) so we can link them
|
|
380
|
+
const resolvedDependencies = packageLockContent ? parseResolutions(packageLockContent) : [];
|
|
381
|
+
// Now parse dependencies from package.json - they resolve from root context ("")
|
|
382
|
+
const dependencies = parseDependencies(packageJsonContent.dependencies, '');
|
|
383
|
+
const devDependencies = parseDependencies(packageJsonContent.devDependencies, '');
|
|
384
|
+
const peerDependencies = parseDependencies(packageJsonContent.peerDependencies, '');
|
|
385
|
+
const optionalDependencies = parseDependencies(packageJsonContent.optionalDependencies, '');
|
|
386
|
+
const bundledDependencies = parseBundledDependencies(packageJsonContent.bundledDependencies || packageJsonContent.bundleDependencies, '');
|
|
387
|
+
return {
|
|
388
|
+
kind: exports.NodeResolutionResultKind,
|
|
389
|
+
id: (0, uuid_1.randomId)(),
|
|
390
|
+
name: packageJsonContent.name,
|
|
391
|
+
version: packageJsonContent.version,
|
|
392
|
+
description: packageJsonContent.description,
|
|
393
|
+
path,
|
|
394
|
+
workspacePackagePaths,
|
|
395
|
+
dependencies,
|
|
396
|
+
devDependencies,
|
|
397
|
+
peerDependencies,
|
|
398
|
+
optionalDependencies,
|
|
399
|
+
bundledDependencies,
|
|
400
|
+
resolvedDependencies,
|
|
401
|
+
packageManager,
|
|
402
|
+
engines: packageJsonContent.engines,
|
|
403
|
+
npmrcConfigs,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
/**
|
|
407
|
+
* Helper function to find a NodeResolutionResult marker on a compilation unit.
|
|
408
|
+
*/
|
|
409
|
+
function findNodeResolutionResult(cu) {
|
|
410
|
+
return (0, markers_1.findMarker)(cu, exports.NodeResolutionResultKind);
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Parses an .npmrc file content into a key-value map.
|
|
414
|
+
*
|
|
415
|
+
* .npmrc format:
|
|
416
|
+
* - Lines are key=value pairs
|
|
417
|
+
* - Lines starting with # or ; are comments
|
|
418
|
+
* - Empty lines are ignored
|
|
419
|
+
* - Values can contain ${VAR} or ${VAR:-default} for env variable substitution
|
|
420
|
+
*/
|
|
421
|
+
function parseNpmrc(content) {
|
|
422
|
+
const properties = {};
|
|
423
|
+
for (const line of content.split('\n')) {
|
|
424
|
+
const trimmed = line.trim();
|
|
425
|
+
// Skip comments and empty lines
|
|
426
|
+
if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith(';')) {
|
|
427
|
+
continue;
|
|
428
|
+
}
|
|
429
|
+
// Parse key=value
|
|
430
|
+
const eqIndex = trimmed.indexOf('=');
|
|
431
|
+
if (eqIndex === -1)
|
|
432
|
+
continue;
|
|
433
|
+
const key = trimmed.substring(0, eqIndex).trim();
|
|
434
|
+
const value = trimmed.substring(eqIndex + 1).trim();
|
|
435
|
+
if (key) {
|
|
436
|
+
properties[key] = value;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
return properties;
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Helper to check if a file exists asynchronously.
|
|
443
|
+
*/
|
|
444
|
+
function fileExists(filePath) {
|
|
445
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
446
|
+
try {
|
|
447
|
+
yield fsp.access(filePath);
|
|
448
|
+
return true;
|
|
449
|
+
}
|
|
450
|
+
catch (_a) {
|
|
451
|
+
return false;
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Reads .npmrc configurations from all scope levels.
|
|
457
|
+
* Returns an array of Npmrc objects, one for each scope that has configuration.
|
|
458
|
+
*
|
|
459
|
+
* Scopes (from lowest to highest priority):
|
|
460
|
+
* - Global: $PREFIX/etc/npmrc (npm's installation directory)
|
|
461
|
+
* - User: $HOME/.npmrc (user's home directory)
|
|
462
|
+
* - Project: .npmrc in project root (sibling of package.json)
|
|
463
|
+
* - Env: npm_config_* environment variables
|
|
464
|
+
*
|
|
465
|
+
* @param projectDir The project directory containing package.json
|
|
466
|
+
* @returns Promise resolving to array of Npmrc objects for each scope with configuration
|
|
467
|
+
*/
|
|
468
|
+
function readNpmrcConfigs(projectDir) {
|
|
469
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
470
|
+
const configs = [];
|
|
471
|
+
// 1. Global config: $PREFIX/etc/npmrc
|
|
472
|
+
// Try to get npm prefix from npm itself, fall back to common locations
|
|
473
|
+
const globalNpmrcPaths = [
|
|
474
|
+
// Try NPM_CONFIG_GLOBALCONFIG env var first
|
|
475
|
+
process.env.NPM_CONFIG_GLOBALCONFIG,
|
|
476
|
+
// Common global locations
|
|
477
|
+
'/usr/local/etc/npmrc',
|
|
478
|
+
'/etc/npmrc',
|
|
479
|
+
].filter(Boolean);
|
|
480
|
+
// Also try to detect from npm prefix if node is installed
|
|
481
|
+
const nodeDir = process.execPath ? path.dirname(path.dirname(process.execPath)) : undefined;
|
|
482
|
+
if (nodeDir) {
|
|
483
|
+
globalNpmrcPaths.unshift(path.join(nodeDir, 'etc', 'npmrc'));
|
|
484
|
+
}
|
|
485
|
+
for (const globalPath of globalNpmrcPaths) {
|
|
486
|
+
if (yield fileExists(globalPath)) {
|
|
487
|
+
try {
|
|
488
|
+
const content = yield fsp.readFile(globalPath, 'utf-8');
|
|
489
|
+
const properties = parseNpmrc(content);
|
|
490
|
+
if (Object.keys(properties).length > 0) {
|
|
491
|
+
configs.push({
|
|
492
|
+
kind: exports.NpmrcKind,
|
|
493
|
+
scope: NpmrcScope.Global,
|
|
494
|
+
properties
|
|
495
|
+
});
|
|
496
|
+
break; // Only use the first found global config
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
catch (_a) {
|
|
500
|
+
// Ignore read errors
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
// 2. User config: $HOME/.npmrc
|
|
505
|
+
const userNpmrcPath = process.env.NPM_CONFIG_USERCONFIG || path.join((0, os_1.homedir)(), '.npmrc');
|
|
506
|
+
if (yield fileExists(userNpmrcPath)) {
|
|
507
|
+
try {
|
|
508
|
+
const content = yield fsp.readFile(userNpmrcPath, 'utf-8');
|
|
509
|
+
const properties = parseNpmrc(content);
|
|
510
|
+
if (Object.keys(properties).length > 0) {
|
|
511
|
+
configs.push({
|
|
512
|
+
kind: exports.NpmrcKind,
|
|
513
|
+
scope: NpmrcScope.User,
|
|
514
|
+
properties
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
catch (_b) {
|
|
519
|
+
// Ignore read errors
|
|
520
|
+
}
|
|
521
|
+
}
|
|
522
|
+
// 3. Project config: .npmrc in project root
|
|
523
|
+
const projectNpmrcPath = path.join(projectDir, '.npmrc');
|
|
524
|
+
if (yield fileExists(projectNpmrcPath)) {
|
|
525
|
+
try {
|
|
526
|
+
const content = yield fsp.readFile(projectNpmrcPath, 'utf-8');
|
|
527
|
+
const properties = parseNpmrc(content);
|
|
528
|
+
if (Object.keys(properties).length > 0) {
|
|
529
|
+
configs.push({
|
|
530
|
+
kind: exports.NpmrcKind,
|
|
531
|
+
scope: NpmrcScope.Project,
|
|
532
|
+
properties
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
catch (_c) {
|
|
537
|
+
// Ignore read errors
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
// Note: We intentionally don't capture npm_config_* environment variables.
|
|
541
|
+
// While users can set config via env vars, npm also automatically injects
|
|
542
|
+
// many npm_config_* vars when running child processes, and there's no way
|
|
543
|
+
// to distinguish user-set vars from npm-injected ones at runtime.
|
|
544
|
+
return configs;
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Helper functions for querying dependencies
|
|
549
|
+
*/
|
|
550
|
+
var NodeResolutionResultQueries;
|
|
551
|
+
(function (NodeResolutionResultQueries) {
|
|
552
|
+
/**
|
|
553
|
+
* Get all dependency requests from all scopes.
|
|
554
|
+
*/
|
|
555
|
+
function getAllDependencies(project) {
|
|
556
|
+
return [
|
|
557
|
+
...project.dependencies,
|
|
558
|
+
...project.devDependencies,
|
|
559
|
+
...project.peerDependencies,
|
|
560
|
+
...project.optionalDependencies,
|
|
561
|
+
...project.bundledDependencies
|
|
562
|
+
];
|
|
563
|
+
}
|
|
564
|
+
NodeResolutionResultQueries.getAllDependencies = getAllDependencies;
|
|
565
|
+
/**
|
|
566
|
+
* Check if project has a specific dependency request, optionally filtered by scope.
|
|
567
|
+
*/
|
|
568
|
+
function hasDependency(project, packageName, scope) {
|
|
569
|
+
const deps = scope
|
|
570
|
+
? project[scope]
|
|
571
|
+
: getAllDependencies(project);
|
|
572
|
+
return deps.some(dep => dep.name === packageName);
|
|
573
|
+
}
|
|
574
|
+
NodeResolutionResultQueries.hasDependency = hasDependency;
|
|
575
|
+
/**
|
|
576
|
+
* Find a specific dependency request by name across all scopes.
|
|
577
|
+
*/
|
|
578
|
+
function findDependency(project, packageName) {
|
|
579
|
+
return getAllDependencies(project).find(dep => dep.name === packageName);
|
|
580
|
+
}
|
|
581
|
+
NodeResolutionResultQueries.findDependency = findDependency;
|
|
582
|
+
/**
|
|
583
|
+
* Get all dependency requests matching a predicate.
|
|
584
|
+
*/
|
|
585
|
+
function findDependencies(project, predicate) {
|
|
586
|
+
return getAllDependencies(project).filter(predicate);
|
|
587
|
+
}
|
|
588
|
+
NodeResolutionResultQueries.findDependencies = findDependencies;
|
|
589
|
+
/**
|
|
590
|
+
* Get all resolved dependencies with a specific name (handles multiple versions).
|
|
591
|
+
* Returns an empty array if no versions are found.
|
|
592
|
+
*
|
|
593
|
+
* For navigation, prefer using the Dependency.resolved property:
|
|
594
|
+
* @example
|
|
595
|
+
* const express = project.dependencies.find(d => d.name === 'express')?.resolved;
|
|
596
|
+
* const accepts = express?.dependencies?.find(d => d.name === 'accepts')?.resolved;
|
|
597
|
+
*/
|
|
598
|
+
function getAllResolvedVersions(project, packageName) {
|
|
599
|
+
return project.resolvedDependencies.filter(r => r.name === packageName);
|
|
600
|
+
}
|
|
601
|
+
NodeResolutionResultQueries.getAllResolvedVersions = getAllResolvedVersions;
|
|
602
|
+
})(NodeResolutionResultQueries || (exports.NodeResolutionResultQueries = NodeResolutionResultQueries = {}));
|
|
603
|
+
/**
|
|
604
|
+
* Register RPC codec for Npmrc.
|
|
605
|
+
*/
|
|
606
|
+
rpc_1.RpcCodecs.registerCodec(exports.NpmrcKind, {
|
|
607
|
+
rpcReceive(before, q) {
|
|
608
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
609
|
+
const draft = (0, immer_1.createDraft)(before);
|
|
610
|
+
draft.kind = exports.NpmrcKind;
|
|
611
|
+
draft.scope = yield q.receive(before.scope);
|
|
612
|
+
draft.properties = yield q.receive(before.properties);
|
|
613
|
+
return (0, immer_1.finishDraft)(draft);
|
|
614
|
+
});
|
|
615
|
+
},
|
|
616
|
+
rpcSend(after, q) {
|
|
617
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
618
|
+
yield q.getAndSend(after, a => a.scope);
|
|
619
|
+
yield q.getAndSend(after, a => a.properties);
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
});
|
|
623
|
+
/**
|
|
624
|
+
* Register RPC codec for Dependency.
|
|
625
|
+
*/
|
|
626
|
+
rpc_1.RpcCodecs.registerCodec(exports.DependencyKind, {
|
|
627
|
+
rpcReceive(before, q) {
|
|
628
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
629
|
+
const draft = (0, immer_1.createDraft)(before);
|
|
630
|
+
draft.kind = exports.DependencyKind;
|
|
631
|
+
draft.name = yield q.receive(before.name);
|
|
632
|
+
draft.versionConstraint = yield q.receive(before.versionConstraint);
|
|
633
|
+
draft.resolved = yield q.receive(before.resolved);
|
|
634
|
+
return (0, immer_1.finishDraft)(draft);
|
|
635
|
+
});
|
|
636
|
+
},
|
|
637
|
+
rpcSend(after, q) {
|
|
638
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
639
|
+
yield q.getAndSend(after, a => a.name);
|
|
640
|
+
yield q.getAndSend(after, a => a.versionConstraint);
|
|
641
|
+
yield q.getAndSend(after, a => a.resolved);
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
/**
|
|
646
|
+
* Register RPC codec for ResolvedDependency.
|
|
647
|
+
*/
|
|
648
|
+
rpc_1.RpcCodecs.registerCodec(exports.ResolvedDependencyKind, {
|
|
649
|
+
rpcReceive(before, q) {
|
|
650
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
651
|
+
const draft = (0, immer_1.createDraft)(before);
|
|
652
|
+
draft.kind = exports.ResolvedDependencyKind;
|
|
653
|
+
draft.name = yield q.receive(before.name);
|
|
654
|
+
draft.version = yield q.receive(before.version);
|
|
655
|
+
draft.dependencies = (yield q.receiveList(before.dependencies)) || undefined;
|
|
656
|
+
draft.devDependencies = (yield q.receiveList(before.devDependencies)) || undefined;
|
|
657
|
+
draft.peerDependencies = (yield q.receiveList(before.peerDependencies)) || undefined;
|
|
658
|
+
draft.optionalDependencies = (yield q.receiveList(before.optionalDependencies)) || undefined;
|
|
659
|
+
draft.engines = yield q.receive(before.engines);
|
|
660
|
+
draft.license = yield q.receive(before.license);
|
|
661
|
+
return (0, immer_1.finishDraft)(draft);
|
|
662
|
+
});
|
|
663
|
+
},
|
|
664
|
+
rpcSend(after, q) {
|
|
665
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
666
|
+
yield q.getAndSend(after, a => a.name);
|
|
667
|
+
yield q.getAndSend(after, a => a.version);
|
|
668
|
+
yield q.getAndSendList(after, a => (a.dependencies || []).map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
669
|
+
yield q.getAndSendList(after, a => (a.devDependencies || []).map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
670
|
+
yield q.getAndSendList(after, a => (a.peerDependencies || []).map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
671
|
+
yield q.getAndSendList(after, a => (a.optionalDependencies || []).map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
672
|
+
yield q.getAndSend(after, a => a.engines);
|
|
673
|
+
yield q.getAndSend(after, a => a.license);
|
|
674
|
+
});
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
/**
|
|
678
|
+
* Register RPC codec for NodeResolutionResult marker.
|
|
679
|
+
* This handles serialization/deserialization for communication between JS and Java.
|
|
680
|
+
*/
|
|
681
|
+
rpc_1.RpcCodecs.registerCodec(exports.NodeResolutionResultKind, {
|
|
682
|
+
rpcReceive(before, q) {
|
|
683
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
684
|
+
const draft = (0, immer_1.createDraft)(before);
|
|
685
|
+
draft.id = yield q.receive(before.id);
|
|
686
|
+
draft.name = yield q.receive(before.name);
|
|
687
|
+
draft.version = yield q.receive(before.version);
|
|
688
|
+
draft.description = yield q.receive(before.description);
|
|
689
|
+
draft.path = yield q.receive(before.path);
|
|
690
|
+
draft.workspacePackagePaths = yield q.receive(before.workspacePackagePaths);
|
|
691
|
+
draft.dependencies = (yield q.receiveList(before.dependencies)) || [];
|
|
692
|
+
draft.devDependencies = (yield q.receiveList(before.devDependencies)) || [];
|
|
693
|
+
draft.peerDependencies = (yield q.receiveList(before.peerDependencies)) || [];
|
|
694
|
+
draft.optionalDependencies = (yield q.receiveList(before.optionalDependencies)) || [];
|
|
695
|
+
draft.bundledDependencies = (yield q.receiveList(before.bundledDependencies)) || [];
|
|
696
|
+
draft.resolvedDependencies = (yield q.receiveList(before.resolvedDependencies)) || [];
|
|
697
|
+
draft.packageManager = yield q.receive(before.packageManager);
|
|
698
|
+
draft.engines = yield q.receive(before.engines);
|
|
699
|
+
draft.npmrcConfigs = (yield q.receiveList(before.npmrcConfigs)) || undefined;
|
|
700
|
+
return (0, immer_1.finishDraft)(draft);
|
|
701
|
+
});
|
|
702
|
+
},
|
|
703
|
+
rpcSend(after, q) {
|
|
704
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
705
|
+
yield q.getAndSend(after, a => a.id);
|
|
706
|
+
yield q.getAndSend(after, a => a.name);
|
|
707
|
+
yield q.getAndSend(after, a => a.version);
|
|
708
|
+
yield q.getAndSend(after, a => a.description);
|
|
709
|
+
yield q.getAndSend(after, a => a.path);
|
|
710
|
+
yield q.getAndSend(after, a => a.workspacePackagePaths);
|
|
711
|
+
yield q.getAndSendList(after, a => a.dependencies.map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
712
|
+
yield q.getAndSendList(after, a => a.devDependencies.map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
713
|
+
yield q.getAndSendList(after, a => a.peerDependencies.map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
714
|
+
yield q.getAndSendList(after, a => a.optionalDependencies.map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
715
|
+
yield q.getAndSendList(after, a => a.bundledDependencies.map(d => (0, reference_1.asRef)(d)), dep => `${dep.name}@${dep.versionConstraint}`);
|
|
716
|
+
yield q.getAndSendList(after, a => a.resolvedDependencies.map(r => (0, reference_1.asRef)(r)), resolved => `${resolved.name}@${resolved.version}`);
|
|
717
|
+
yield q.getAndSend(after, a => a.packageManager);
|
|
718
|
+
yield q.getAndSend(after, a => a.engines);
|
|
719
|
+
yield q.getAndSendList(after, a => a.npmrcConfigs || [], npmrc => npmrc.scope);
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
});
|
|
723
|
+
//# sourceMappingURL=node-resolution-result.js.map
|