@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 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 one further chance, and only under
171
- * a `workspace:` SPECIFIER: pnpm resolved that edge through the workspace, so
172
- * the target directory is known to belong to a workspace package, and
173
- * {@link owningImporter} names it. The specifier is what makes this a
174
- * resolution rather than a guess — a hand-written `link:../vendor/stub`
175
- * specifier names a directory pnpm never claimed was a workspace package, and
176
- * attributing it to whichever importer happens to contain it would answer with
177
- * the wrong package's peers instead of admitting it could not name the edge.
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
- * The snapshot path ({@link resolveEdges}) deliberately does NOT do this: a
180
- * snapshot body records `name: link:<path>` with no specifier beside it, so the
181
- * evidence this rule turns on is not available there.
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.1",
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.0",
44
+ "@effected/npm": "^0.11.1",
45
45
  "@effected/semver": "^0.5.0",
46
- "@effected/yaml": "^0.10.0",
46
+ "@effected/yaml": "^0.11.0",
47
47
  "effect": "4.0.0-rc.109"
48
48
  },
49
49
  "engines": {
@@ -5,7 +5,7 @@
5
5
  "toolPackages": [
6
6
  {
7
7
  "packageName": "@microsoft/api-extractor",
8
- "packageVersion": "7.58.12"
8
+ "packageVersion": "7.59.0"
9
9
  }
10
10
  ]
11
11
  }