@effected/lockfiles 0.6.1 → 0.6.3
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/internal/pnpm.js +55 -17
- package/package.json +3 -3
- package/tsdoc-metadata.json +1 -1
package/internal/pnpm.js
CHANGED
|
@@ -14,7 +14,8 @@ const PnpmImporter = Schema.Struct({
|
|
|
14
14
|
dependencies: PnpmImporterDeps,
|
|
15
15
|
devDependencies: PnpmImporterDeps,
|
|
16
16
|
peerDependencies: PnpmImporterDeps,
|
|
17
|
-
optionalDependencies: PnpmImporterDeps
|
|
17
|
+
optionalDependencies: PnpmImporterDeps,
|
|
18
|
+
publishDirectory: Schema.optionalKey(Schema.String)
|
|
18
19
|
});
|
|
19
20
|
/**
|
|
20
21
|
* The version gate's own input: `lockfileVersion` and nothing else.
|
|
@@ -89,9 +90,23 @@ const parsePnpm = (content) => Effect.gen(function* () {
|
|
|
89
90
|
* resolution, which names no instance in this lockfile, from becoming a
|
|
90
91
|
* plausible lie.
|
|
91
92
|
*
|
|
93
|
+
* A failed composition gets one second reading: the recorded version ITSELF as
|
|
94
|
+
* an instance id. That is how pnpm spells an `npm:` alias — the dependency
|
|
95
|
+
* `typescript-classic: npm:typescript@^6.0.3` is recorded as
|
|
96
|
+
* `typescript-classic: typescript@6.0.3`, the referenced instance's own key,
|
|
97
|
+
* peer suffix included when one applies. Still compose-then-verify, not a
|
|
98
|
+
* guess: a plain version (`6.0.3`) can never be an instance id, because ids
|
|
99
|
+
* always carry a name, so the reading admits exactly the alias shape.
|
|
100
|
+
*
|
|
101
|
+
* Unlike {@link resolveImporterEdges}, there is no `workspace:`-specifier
|
|
102
|
+
* ancestor walk here — a snapshot body records no specifier, so that evidence
|
|
103
|
+
* does not exist on this path. The publish-directory map needs no specifier:
|
|
104
|
+
* the importer entry's own `publishDirectory` declaration is exact evidence,
|
|
105
|
+
* available to both paths, and is consulted unconditionally.
|
|
106
|
+
*
|
|
92
107
|
* @internal
|
|
93
108
|
*/
|
|
94
|
-
const resolveEdges = (sections, instanceIds) => {
|
|
109
|
+
const resolveEdges = (sections, instanceIds, publishDirTargets) => {
|
|
95
110
|
const edges = /* @__PURE__ */ new Map();
|
|
96
111
|
const unnameable = /* @__PURE__ */ new Set();
|
|
97
112
|
for (const section of sections) {
|
|
@@ -101,11 +116,13 @@ const resolveEdges = (sections, instanceIds) => {
|
|
|
101
116
|
if (version.startsWith(LINK_PREFIX)) {
|
|
102
117
|
const target = resolveLinkTarget("", version.slice(LINK_PREFIX.length));
|
|
103
118
|
if (target !== void 0 && instanceIds.has(target)) edges.set(name, target);
|
|
119
|
+
else if (target !== void 0 && publishDirTargets.has(target)) edges.set(name, publishDirTargets.get(target));
|
|
104
120
|
else unnameable.add(name);
|
|
105
121
|
continue;
|
|
106
122
|
}
|
|
107
123
|
const bare = `${name}@${version}`;
|
|
108
124
|
if (instanceIds.has(bare)) edges.set(name, bare);
|
|
125
|
+
else if (instanceIds.has(version)) edges.set(name, version);
|
|
109
126
|
else unnameable.add(name);
|
|
110
127
|
}
|
|
111
128
|
}
|
|
@@ -121,6 +138,13 @@ const LINK_PREFIX = "link:";
|
|
|
121
138
|
* workspace edge can name the workspace importer's instance id.
|
|
122
139
|
* Total: a target that walks above the root yields `undefined`.
|
|
123
140
|
*
|
|
141
|
+
* A target that normalizes to NOTHING — `link:.` recorded root-relative —
|
|
142
|
+
* also yields `undefined` rather than the root importer's ".": the root
|
|
143
|
+
* importer deliberately emits no `ResolvedPackage` row (its path cannot serve
|
|
144
|
+
* as a package name), so mapping the empty target to "." would hand back an id
|
|
145
|
+
* no row carries, and no pnpm output recording that shape has been observed.
|
|
146
|
+
* The edge stays honestly unnameable instead.
|
|
147
|
+
*
|
|
124
148
|
* @internal
|
|
125
149
|
*/
|
|
126
150
|
const resolveLinkTarget = (importerPath, target) => {
|
|
@@ -167,22 +191,28 @@ const owningImporter = (target, importerPaths) => {
|
|
|
167
191
|
* naming another importer — normalized against this importer's own path. Both
|
|
168
192
|
* are checked against the lockfile's instance ids before being emitted.
|
|
169
193
|
*
|
|
170
|
-
* A `link:` target that is no importer gets
|
|
171
|
-
*
|
|
172
|
-
* the
|
|
173
|
-
*
|
|
174
|
-
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
*
|
|
194
|
+
* A `link:` target that is no importer gets two further chances. First the
|
|
195
|
+
* publish-directory map: an importer that DECLARES `publishDirectory` has told
|
|
196
|
+
* the lockfile exactly which build directory its links point at, so a target
|
|
197
|
+
* matching a declared publish directory names that importer on evidence, no
|
|
198
|
+
* specifier required — {@link resolveEdges} consults the same map for the same
|
|
199
|
+
* reason. Then, and only under a `workspace:` SPECIFIER, the ancestor walk:
|
|
200
|
+
* pnpm resolved that edge through the workspace, so the target directory is
|
|
201
|
+
* known to belong to a workspace package, and {@link owningImporter} names it.
|
|
202
|
+
* The specifier is what makes the walk a resolution rather than a guess — a
|
|
203
|
+
* hand-written `link:../vendor/stub` specifier names a directory pnpm never
|
|
204
|
+
* claimed was a workspace package, and attributing it to whichever importer
|
|
205
|
+
* happens to contain it would answer with the wrong package's peers instead of
|
|
206
|
+
* admitting it could not name the edge. The snapshot path has no specifier and
|
|
207
|
+
* therefore no walk; the publish-directory map is the evidence it does get.
|
|
178
208
|
*
|
|
179
|
-
*
|
|
180
|
-
*
|
|
181
|
-
*
|
|
209
|
+
* A failed `name@version` composition gets the same alias reading as
|
|
210
|
+
* {@link resolveEdges}: the recorded version itself as an instance id, which is
|
|
211
|
+
* how pnpm spells `npm:` aliases.
|
|
182
212
|
*
|
|
183
213
|
* @internal
|
|
184
214
|
*/
|
|
185
|
-
const resolveImporterEdges = (importer, importerPath, instanceIds, importerPaths) => {
|
|
215
|
+
const resolveImporterEdges = (importer, importerPath, instanceIds, importerPaths, publishDirTargets) => {
|
|
186
216
|
const edges = /* @__PURE__ */ new Map();
|
|
187
217
|
const unnameable = /* @__PURE__ */ new Set();
|
|
188
218
|
for (const group of importerDepGroups(importer)) {
|
|
@@ -191,13 +221,14 @@ const resolveImporterEdges = (importer, importerPath, instanceIds, importerPaths
|
|
|
191
221
|
if (name === "") continue;
|
|
192
222
|
if (info.version.startsWith(LINK_PREFIX)) {
|
|
193
223
|
const target = resolveLinkTarget(importerPath, info.version.slice(5));
|
|
194
|
-
const owner = target === void 0 ? void 0 : instanceIds.has(target) ? target : info.specifier.startsWith(WORKSPACE_PREFIX) ? owningImporter(target, importerPaths) : void 0;
|
|
224
|
+
const owner = target === void 0 ? void 0 : instanceIds.has(target) ? target : publishDirTargets.get(target) ?? (info.specifier.startsWith(WORKSPACE_PREFIX) ? owningImporter(target, importerPaths) : void 0);
|
|
195
225
|
if (owner !== void 0) edges.set(name, owner);
|
|
196
226
|
else unnameable.add(name);
|
|
197
227
|
continue;
|
|
198
228
|
}
|
|
199
229
|
const bare = `${name}@${info.version}`;
|
|
200
230
|
if (instanceIds.has(bare)) edges.set(name, bare);
|
|
231
|
+
else if (instanceIds.has(info.version)) edges.set(name, info.version);
|
|
201
232
|
else unnameable.add(name);
|
|
202
233
|
}
|
|
203
234
|
}
|
|
@@ -253,6 +284,13 @@ const toFields = (raw) => Effect.gen(function* () {
|
|
|
253
284
|
...Object.keys(raw.importers)
|
|
254
285
|
]);
|
|
255
286
|
const importerPaths = new Set(Object.keys(raw.importers).filter((path) => path !== "." && path !== ""));
|
|
287
|
+
const publishDirTargets = /* @__PURE__ */ new Map();
|
|
288
|
+
for (const [importerPath, importer] of Object.entries(raw.importers)) {
|
|
289
|
+
if (importerPath === "") continue;
|
|
290
|
+
if (importer.publishDirectory === void 0) continue;
|
|
291
|
+
const key = resolveLinkTarget(importerPath, importer.publishDirectory);
|
|
292
|
+
if (key !== void 0) publishDirTargets.set(key, importerPath);
|
|
293
|
+
}
|
|
256
294
|
const emitted = /* @__PURE__ */ new Set();
|
|
257
295
|
for (const [importerPath, importer] of Object.entries(raw.importers)) {
|
|
258
296
|
if (importerPath === "." || importerPath === "") continue;
|
|
@@ -262,7 +300,7 @@ const toFields = (raw) => Effect.gen(function* () {
|
|
|
262
300
|
instanceId: importerPath,
|
|
263
301
|
isWorkspace: true,
|
|
264
302
|
relativePath: importerPath,
|
|
265
|
-
...resolveImporterEdges(importer, importerPath, instanceIds, importerPaths)
|
|
303
|
+
...resolveImporterEdges(importer, importerPath, instanceIds, importerPaths, publishDirTargets)
|
|
266
304
|
}));
|
|
267
305
|
}
|
|
268
306
|
const emit = (instanceId, meta, edges) => Effect.gen(function* () {
|
|
@@ -280,7 +318,7 @@ const toFields = (raw) => Effect.gen(function* () {
|
|
|
280
318
|
...integrity !== void 0 ? { integrity } : {},
|
|
281
319
|
isWorkspace: false,
|
|
282
320
|
...peerDeclarations(meta?.peerDependencies, meta?.peerDependenciesMeta),
|
|
283
|
-
...resolveEdges(edges, instanceIds)
|
|
321
|
+
...resolveEdges(edges, instanceIds, publishDirTargets)
|
|
284
322
|
}));
|
|
285
323
|
});
|
|
286
324
|
if (snapshots) for (const [key, snapshot] of Object.entries(snapshots)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effected/lockfiles",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Pure lockfile parsing for bun, npm, pnpm and yarn Berry into one unified Effect schema model, with pure integrity checking against workspace manifests.",
|
|
6
6
|
"keywords": [
|
|
@@ -41,9 +41,9 @@
|
|
|
41
41
|
},
|
|
42
42
|
"peerDependencies": {
|
|
43
43
|
"@effected/jsonc": "^0.7.0",
|
|
44
|
-
"@effected/npm": "^0.11.
|
|
44
|
+
"@effected/npm": "^0.11.1",
|
|
45
45
|
"@effected/semver": "^0.5.0",
|
|
46
|
-
"@effected/yaml": "^0.
|
|
46
|
+
"@effected/yaml": "^0.11.0",
|
|
47
47
|
"effect": "4.0.0-rc.109"
|
|
48
48
|
},
|
|
49
49
|
"engines": {
|