diff --git a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx
index 8b0fb3769e1..eec60868444 100644
--- a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx
+++ b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx
@@ -172,7 +172,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
Selected Dependency:{' '}
- {inspectDependency.name}: {inspectDependency.version}
+ {inspectDependency.name}: {inspectDependency.versionPath}
@@ -180,11 +180,11 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
package.json spec:{' '}
- {inspectDependency.dependencyType === LfxDependencyKind.Peer
+ {inspectDependency.dependencyKind === LfxDependencyKind.Peer
? `"${inspectDependency.peerDependencyMeta.version}" ${
inspectDependency.peerDependencyMeta.optional ? 'Optional' : 'Required'
} Peer`
- : inspectDependency.version}
+ : inspectDependency.versionPath}
@@ -204,7 +204,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
const renderPeerDependencies = (): JSX.Element | ReactNull => {
if (!selectedEntry) return ReactNull;
- const peerDeps = selectedEntry.dependencies.filter((d) => d.dependencyType === LfxDependencyKind.Peer);
+ const peerDeps = selectedEntry.dependencies.filter((d) => d.dependencyKind === LfxDependencyKind.Peer);
if (!peerDeps.length) {
return (
@@ -212,7 +212,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
);
}
- if (!inspectDependency || inspectDependency.dependencyType !== LfxDependencyKind.Peer) {
+ if (!inspectDependency || inspectDependency.dependencyKind !== LfxDependencyKind.Peer) {
return (
Select a peer dependency to view its influencers
@@ -337,14 +337,14 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
>
Name: {dependency.name}{' '}
- {dependency.dependencyType === LfxDependencyKind.Peer
+ {dependency.dependencyKind === LfxDependencyKind.Peer
? `${
dependency.peerDependencyMeta.optional ? '(Optional)' : '(Non-optional)'
} Peer Dependency`
: ''}
- Version: {dependency.version}
+ Version: {dependency.versionPath}
Entry ID: {dependency.entryId}
diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts
index 7632e332f8f..35baa33daca 100644
--- a/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts
+++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts
@@ -18,13 +18,13 @@ export interface IJsonPeerDependencyMeta {
export interface IJsonLfxDependency {
name: string;
- version: string;
+ versionPath: string;
entryId: string;
- dependencyType: LfxDependencyKind;
+ originalSpecifier: string;
+ dependencyKind: LfxDependencyKind;
+ peerDependencyMeta: IJsonPeerDependencyMeta;
resolvedEntryJsonId?: number;
-
- peerDependencyMeta: IJsonPeerDependencyMeta;
}
export enum LfxDependencyKind {
diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts
index 11ce9f58c98..a45371b7ba3 100644
--- a/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts
+++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts
@@ -6,39 +6,75 @@ import type { IJsonLfxWorkspace } from './IJsonLfxWorkspace';
export interface ILfxGraphDependencyOptions {
name: string;
- version: string;
- dependencyType: LfxDependencyKind;
- containingEntry: LfxGraphEntry;
- peerDependencyMeta: IJsonPeerDependencyMeta;
+ versionPath: string;
+
entryId: string;
+
+ originalSpecifier: string;
+ dependencyKind: LfxDependencyKind;
+ peerDependencyMeta: IJsonPeerDependencyMeta;
+
+ containingEntry: LfxGraphEntry;
}
/**
- * Represents a dependency listed under a LockfileEntry
- *
- * @remarks
- * Each dependency listed under a package in the lockfile should have a separate entry. These Dependencies
- * will link to the "containingEntry", which is the LockfileEntry that specified this dependency.
- * The "resolvedEntry" field is the corresponding LockfileEntry for this dependency, as all dependencies also have
- * their own entries in the pnpm lockfile.
+ * Represents an graph edge, which is an exact dependency version obtained from the lockfile.
*/
export class LfxGraphDependency {
+ /**
+ * The referenced package name.
+ * Example: `@scope/package-name`
+ */
public readonly name: string;
- public readonly version: string;
- public readonly dependencyType: LfxDependencyKind;
- public readonly containingEntry: LfxGraphEntry;
+
+ /**
+ * The lockfile's raw string that either indicates an external reference such as `link:../target-folder`,
+ * or else can be combined with the `name` field to construct an `entryId` found in the lockfile.
+ * The exact syntax varies between lockfile file format versions.
+ *
+ * Example: `link:../target-folder`
+ *
+ * Example: `1.0.0`
+ *
+ * Example: `1.0.0_@rushstack+m@1.0.0` (version 5.4)
+ * Example: `1.0.0(@rushstack/m@1.0.0)` (version 6.0 and 9.0)
+ */
+ public readonly versionPath: string;
+
+ /**
+ * If this dependency refers to an entry in the lockfile, this field should match a corresponding
+ * {@link LfxGraphEntry.entryId} and `resolvedEntry` will be defined (unless the loader encountered an error).
+ *
+ * For external references such as `link:../target-folder`, the `entryId` is the empty string.
+ */
public readonly entryId: string;
+
+ /**
+ * The lockfile sometimes records the original SemVer specifier that was used to choose the versionPath,
+ * usually either because it can change (e.g. a workspace project's dependencies) or because it's a peer dependency
+ * that affects graph relationships beyond the current node. If not, then `originalSpecifier` will be the
+ * empty string.
+ *
+ * @remarks
+ * Because this field is only available for certain dependencies, it is generally less useful than specifiers
+ * obtained from the package.json files.
+ */
+ public readonly originalSpecifier: string;
+ public readonly dependencyKind: LfxDependencyKind;
public readonly peerDependencyMeta: IJsonPeerDependencyMeta;
+ public readonly containingEntry: LfxGraphEntry;
public resolvedEntry: LfxGraphEntry | undefined = undefined;
public constructor(options: ILfxGraphDependencyOptions) {
this.name = options.name;
- this.version = options.version;
- this.dependencyType = options.dependencyType;
- this.containingEntry = options.containingEntry;
+ this.versionPath = options.versionPath;
this.entryId = options.entryId;
+ this.originalSpecifier = options.originalSpecifier;
+ this.dependencyKind = options.dependencyKind;
this.peerDependencyMeta = options.peerDependencyMeta;
+
+ this.containingEntry = options.containingEntry;
}
}
@@ -67,14 +103,19 @@ export class LfxGraphEntry {
public readonly kind: LfxGraphEntryKind;
/**
- * A unique (human-readable) identifier for this lockfile entry. For projects, this is just
- * `Project:` + the package json path for this project.
+ * A unique identifier for this lockfile entry, based on `rawEntryId` but adjusted to be unique for both
+ * project and external package entries.
*/
public readonly entryId: string;
/**
* The unique identifier assigned to this project/package in the lockfile.
* e.g. `/@emotion/core/10.3.1_qjwx5m6wssz3lnb35xwkc3pz6q:`
+ *
+ * @remarks
+ * In the `pnpm-lock.yaml` file, "importers" (workspace projects) and "packages" (external packages)
+ * are tracked separately, so it's not required for their keys to be unique. `entryId` solves this problem
+ * by adding a `project:` prefix for importers.
*/
public readonly rawEntryId: string;
diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts
index b175dbd2080..f2f4be485e9 100644
--- a/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts
+++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts
@@ -51,9 +51,10 @@ export function serializeToJson(graph: LfxGraph): IJsonLfxGraph {
for (const dependency of entry.dependencies) {
const jsonLfxDependency: IJsonLfxDependency = {
name: dependency.name,
- version: dependency.version,
+ versionPath: dependency.versionPath,
entryId: dependency.entryId,
- dependencyType: dependency.dependencyType,
+ originalSpecifier: dependency.originalSpecifier,
+ dependencyKind: dependency.dependencyKind,
peerDependencyMeta: {
name: dependency.peerDependencyMeta.name,
version: dependency.peerDependencyMeta.version,
@@ -111,15 +112,16 @@ export function deserializeFromJson(jsonLfxGraph: IJsonLfxGraph): LfxGraph {
for (const jsonLfxDependency of jsonLfxEntry.dependencies) {
const dependency: LfxGraphDependency = new LfxGraphDependency({
name: jsonLfxDependency.name,
- version: jsonLfxDependency.version,
- dependencyType: jsonLfxDependency.dependencyType,
- containingEntry: entry,
+ versionPath: jsonLfxDependency.versionPath,
entryId: jsonLfxDependency.entryId,
+ originalSpecifier: jsonLfxDependency.originalSpecifier,
+ dependencyKind: jsonLfxDependency.dependencyKind,
peerDependencyMeta: {
name: jsonLfxDependency.peerDependencyMeta.name,
version: jsonLfxDependency.peerDependencyMeta.version,
optional: jsonLfxDependency.peerDependencyMeta.optional
- }
+ },
+ containingEntry: entry
});
if (jsonLfxDependency.resolvedEntryJsonId) {
diff --git a/apps/lockfile-explorer/.vscode/launch.json b/apps/lockfile-explorer/.vscode/launch.json
index 2ee133e0e98..34810e71664 100644
--- a/apps/lockfile-explorer/.vscode/launch.json
+++ b/apps/lockfile-explorer/.vscode/launch.json
@@ -14,13 +14,20 @@
"console": "integratedTerminal",
"sourceMaps": true
},
- {
+ {
"type": "node",
"request": "launch",
"name": "Single Jest test",
"program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js",
"cwd": "${workspaceFolder}",
- "args": ["--debug", "test", "--clean", "-u", "--test-path-pattern", "lfxGraph-website-sample-1-v6.0.test"],
+ "args": [
+ "--debug",
+ "test",
+ "--clean",
+ "-u",
+ "--test-path-pattern",
+ "lfxGraph-website-sample-1-v5.4.test"
+ ],
"console": "integratedTerminal",
"sourceMaps": true
},
diff --git a/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts b/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts
index ba421861c21..ee493855030 100644
--- a/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts
+++ b/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts
@@ -22,7 +22,8 @@ type PeerDependenciesMeta = lockfileTypes.LockfilePackageInfo['peerDependenciesM
function createPackageLockfileDependency(options: {
name: string;
- version: string;
+ versionPath: string;
+ originalSpecifier: string;
kind: LfxDependencyKind;
containingEntry: LfxGraphEntry;
peerDependenciesMeta?: PeerDependenciesMeta;
@@ -31,8 +32,9 @@ function createPackageLockfileDependency(options: {
}): LfxGraphDependency {
const {
name,
- version,
- kind: dependencyType,
+ versionPath,
+ originalSpecifier,
+ kind: dependencyKind,
containingEntry,
peerDependenciesMeta,
pnpmLockfileVersion
@@ -40,15 +42,16 @@ function createPackageLockfileDependency(options: {
const result: ILfxGraphDependencyOptions = {
name,
- version,
- dependencyType,
- containingEntry,
+ versionPath,
entryId: '',
- peerDependencyMeta: {}
+ originalSpecifier,
+ dependencyKind,
+ peerDependencyMeta: {},
+ containingEntry
};
- if (version.startsWith('link:')) {
- const relativePath: string = version.substring('link:'.length);
+ if (versionPath.startsWith('link:')) {
+ const relativePath: string = versionPath.substring('link:'.length);
if (containingEntry.kind === LfxGraphEntryKind.Project) {
// TODO: Here we assume it's a "workspace:" link and try to resolve it to another workspace project,
@@ -63,80 +66,90 @@ function createPackageLockfileDependency(options: {
// This could be a link to anywhere on the local computer, so we don't expect it to have a lockfile entry
result.entryId = '';
}
- } else if (result.version.startsWith('/')) {
- result.entryId = version;
- } else if (result.dependencyType === LfxDependencyKind.Peer) {
- result.peerDependencyMeta = {
- name: result.name,
- version: version,
- optional: peerDependenciesMeta?.[result.name] ? peerDependenciesMeta[result.name].optional : false
- };
- result.entryId = 'Peer: ' + result.name;
+ } else if (result.versionPath.startsWith('/')) {
+ result.entryId = versionPath;
} else {
// Version 5.4: /@rushstack/m/1.0.0:
// Version 6.0: /@rushstack/m@1.0.0:
+ // Version 9.0: @rushstack/m@1.0.0:
//
// Version 5.4: /@rushstack/j/1.0.0_@rushstack+n@2.0.0
// Version 6.0: /@rushstack/j@1.0.0(@rushstack/n@2.0.0)
- const versionDelimiter: string = pnpmLockfileVersion === 54 ? '/' : '@';
- result.entryId = '/' + result.name + versionDelimiter + result.version;
+ // Version 9.0: @rushstack/j@1.0.0(@rushstack/n@2.0.0)
+ const versionDelimiter: string = pnpmLockfileVersion < 60 ? '/' : '@';
+ result.entryId =
+ (pnpmLockfileVersion < 90 ? '/' : '') + result.name + versionDelimiter + result.versionPath;
+ }
+
+ if (result.dependencyKind === LfxDependencyKind.Peer) {
+ result.peerDependencyMeta = {
+ name: result.name,
+ version: versionPath,
+ optional: peerDependenciesMeta?.[result.name] ? peerDependenciesMeta[result.name].optional : false
+ };
}
return new LfxGraphDependency(result);
}
-// v5.4 used this to parse projects ("importers") also
-function parsePackageDependencies(
- dependencies: LfxGraphDependency[],
- lockfileEntry: LfxGraphEntry,
- either: lockfileTypes.ProjectSnapshot | lockfileTypes.PackageSnapshot,
- pnpmLockfileVersion: PnpmLockfileVersion,
- workspace: IJsonLfxWorkspace
-): void {
+function parsePackageDependencies(options: {
+ dependencies: LfxGraphDependency[];
+ lockfileEntry: LfxGraphEntry;
+ /**
+ * Used to obtain versionPath exact references.
+ */
+ mainEntry: lockfileTypes.LockfilePackageSnapshot;
+ /**
+ * Used to obtain informational version ranges.
+ */
+ specifierEntry: lockfileTypes.LockfilePackageInfo | undefined;
+ pnpmLockfileVersion: PnpmLockfileVersion;
+ workspace: IJsonLfxWorkspace;
+}): void {
+ const { dependencies, lockfileEntry, mainEntry, specifierEntry, pnpmLockfileVersion, workspace } = options;
+
const node: Partial
=
- either as unknown as Partial;
+ mainEntry as unknown as Partial;
+
+ function createDependency(kind: LfxDependencyKind, packageName: string, versionPath: string): void {
+ let originalSpecifier: string | undefined = undefined;
+
+ if (specifierEntry && specifierEntry.peerDependencies) {
+ originalSpecifier = specifierEntry.peerDependencies[packageName];
+ if (originalSpecifier) {
+ kind = LfxDependencyKind.Peer;
+ }
+ }
+
+ dependencies.push(
+ createPackageLockfileDependency({
+ kind,
+ name: packageName,
+ versionPath,
+ originalSpecifier: originalSpecifier ?? '',
+ containingEntry: lockfileEntry,
+ peerDependenciesMeta: specifierEntry?.peerDependenciesMeta,
+ pnpmLockfileVersion,
+ workspace
+ })
+ );
+ }
+
if (node.dependencies) {
- for (const [packageName, version] of Object.entries(node.dependencies)) {
- dependencies.push(
- createPackageLockfileDependency({
- kind: LfxDependencyKind.Regular,
- name: packageName,
- version: version,
- containingEntry: lockfileEntry,
- pnpmLockfileVersion,
- workspace
- })
- );
+ for (const [packageName, versionPath] of Object.entries(node.dependencies)) {
+ createDependency(LfxDependencyKind.Regular, packageName, versionPath);
}
}
- if (node.devDependencies) {
- for (const [packageName, version] of Object.entries(node.devDependencies)) {
- dependencies.push(
- createPackageLockfileDependency({
- kind: LfxDependencyKind.Dev,
- name: packageName,
- version: version,
- containingEntry: lockfileEntry,
- pnpmLockfileVersion,
- workspace
- })
- );
+ if (node.optionalDependencies) {
+ for (const [packageName, versionPath] of Object.entries(node.optionalDependencies)) {
+ createDependency(LfxDependencyKind.Regular, packageName, versionPath);
}
}
- if (node.peerDependencies) {
- for (const [packageName, version] of Object.entries(node.peerDependencies)) {
- dependencies.push(
- createPackageLockfileDependency({
- kind: LfxDependencyKind.Peer,
- name: packageName,
- version: version,
- containingEntry: lockfileEntry,
- peerDependenciesMeta: node.peerDependenciesMeta,
- pnpmLockfileVersion,
- workspace
- })
- );
+ if (node.devDependencies) {
+ for (const [packageName, versionPath] of Object.entries(node.devDependencies)) {
+ createDependency(LfxDependencyKind.Dev, packageName, versionPath);
}
}
+
if (node.transitivePeerDependencies) {
for (const dep of node.transitivePeerDependencies) {
lockfileEntry.transitivePeerDependencies.add(dep);
@@ -144,6 +157,58 @@ function parsePackageDependencies(
}
}
+function parseProjectDependencies54(options: {
+ dependencies: LfxGraphDependency[];
+ lockfileEntry: LfxGraphEntry;
+ /**
+ * Used to obtain versionPath exact references and informational version ranges
+ */
+ mainEntry: lockfileTypes.ProjectSnapshot;
+ pnpmLockfileVersion: PnpmLockfileVersion;
+ workspace: IJsonLfxWorkspace;
+}): void {
+ const { dependencies, lockfileEntry, mainEntry, pnpmLockfileVersion, workspace } = options;
+
+ const node: Partial =
+ mainEntry as unknown as Partial;
+
+ function createDependency(kind: LfxDependencyKind, packageName: string, versionPath: string): void {
+ let originalSpecifier: string | undefined = undefined;
+
+ if (mainEntry.specifiers) {
+ originalSpecifier = mainEntry.specifiers[packageName];
+ }
+
+ dependencies.push(
+ createPackageLockfileDependency({
+ kind,
+ name: packageName,
+ versionPath,
+ originalSpecifier: originalSpecifier ?? '',
+ containingEntry: lockfileEntry,
+ pnpmLockfileVersion,
+ workspace
+ })
+ );
+ }
+
+ if (node.dependencies) {
+ for (const [packageName, versionPath] of Object.entries(node.dependencies)) {
+ createDependency(LfxDependencyKind.Regular, packageName, versionPath);
+ }
+ }
+ if (node.optionalDependencies) {
+ for (const [packageName, versionPath] of Object.entries(node.optionalDependencies)) {
+ createDependency(LfxDependencyKind.Regular, packageName, versionPath);
+ }
+ }
+ if (node.devDependencies) {
+ for (const [packageName, versionPath] of Object.entries(node.devDependencies)) {
+ createDependency(LfxDependencyKind.Dev, packageName, versionPath);
+ }
+ }
+}
+
function parseProjectDependencies60(
dependencies: LfxGraphDependency[],
lockfileEntry: LfxGraphEntry,
@@ -151,32 +216,37 @@ function parseProjectDependencies60(
pnpmLockfileVersion: PnpmLockfileVersion,
workspace: IJsonLfxWorkspace
): void {
+ function createDependency(
+ kind: LfxDependencyKind,
+ packageName: string,
+ specifierAndResolution: lockfileTypes.SpecifierAndResolution
+ ): void {
+ dependencies.push(
+ createPackageLockfileDependency({
+ kind,
+ name: packageName,
+ versionPath: specifierAndResolution.version,
+ originalSpecifier: specifierAndResolution.specifier,
+ containingEntry: lockfileEntry,
+ pnpmLockfileVersion,
+ workspace
+ })
+ );
+ }
+
if (snapshot.dependencies) {
for (const [packageName, specifierAndResolution] of Object.entries(snapshot.dependencies)) {
- dependencies.push(
- createPackageLockfileDependency({
- kind: LfxDependencyKind.Regular,
- name: packageName,
- version: specifierAndResolution.version,
- containingEntry: lockfileEntry,
- pnpmLockfileVersion,
- workspace
- })
- );
+ createDependency(LfxDependencyKind.Regular, packageName, specifierAndResolution);
+ }
+ }
+ if (snapshot.optionalDependencies) {
+ for (const [packageName, specifierAndResolution] of Object.entries(snapshot.optionalDependencies)) {
+ createDependency(LfxDependencyKind.Regular, packageName, specifierAndResolution);
}
}
if (snapshot.devDependencies) {
for (const [packageName, specifierAndResolution] of Object.entries(snapshot.devDependencies)) {
- dependencies.push(
- createPackageLockfileDependency({
- kind: LfxDependencyKind.Dev,
- name: packageName,
- version: specifierAndResolution.version,
- containingEntry: lockfileEntry,
- pnpmLockfileVersion,
- workspace
- })
- );
+ createDependency(LfxDependencyKind.Dev, packageName, specifierAndResolution);
}
}
}
@@ -228,38 +298,44 @@ function createProjectLockfileEntry(options: {
function createPackageLockfileEntry(options: {
rawEntryId: string;
- rawYamlData: lockfileTypes.PackageSnapshot;
workspace: IJsonLfxWorkspace;
pnpmLockfileVersion: PnpmLockfileVersion;
}): LfxGraphEntry {
- const { rawEntryId, rawYamlData, pnpmLockfileVersion, workspace } = options;
+ const { rawEntryId, pnpmLockfileVersion, workspace } = options;
const result: ILfxGraphEntryOptions = {
kind: LfxGraphEntryKind.Package,
- entryId: '',
- rawEntryId: '',
+ entryId: rawEntryId,
+ rawEntryId: rawEntryId,
packageJsonFolderPath: '',
entryPackageName: '',
- displayText: '',
+ displayText: rawEntryId,
entryPackageVersion: '',
entrySuffix: ''
};
- result.rawEntryId = rawEntryId;
-
// Example: pnpmLockfilePath = 'common/temp/my-subspace/pnpm-lock.yaml'
// Example: pnpmLockfileFolder = 'common/temp/my-subspace'
const pnpmLockfileFolder: string = workspace.pnpmLockfileFolder;
- result.displayText = rawEntryId;
+ let slashlessRawEntryId: string;
- if (!rawEntryId.startsWith('/')) {
- throw new Error('Expecting leading "/" in path: ' + JSON.stringify(rawEntryId));
+ if (pnpmLockfileVersion >= 90) {
+ // The leading slash is omitted starting in V9.0
+ if (rawEntryId.startsWith('/')) {
+ throw new Error('Not expecting leading "/" in path: ' + JSON.stringify(rawEntryId));
+ }
+ slashlessRawEntryId = rawEntryId;
+ } else {
+ if (!rawEntryId.startsWith('/')) {
+ throw new Error('Expecting leading "/" in path: ' + JSON.stringify(rawEntryId));
+ }
+ slashlessRawEntryId = rawEntryId.substring(1);
}
let dotPnpmSubfolder: string;
- if (pnpmLockfileVersion === 54) {
+ if (pnpmLockfileVersion < 60) {
const lastSlashIndex: number = rawEntryId.lastIndexOf('/');
if (lastSlashIndex < 0) {
throw new Error('Expecting "/" in path: ' + JSON.stringify(rawEntryId));
@@ -292,31 +368,32 @@ function createPackageLockfileEntry(options: {
(result.entrySuffix ? `_${result.entrySuffix}` : '');
} else {
// Example inputs:
- // /@rushstack/eslint-config@3.0.1
- // /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ // @rushstack/eslint-config@3.0.1
+ // @rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
let versionAtSignIndex: number;
- if (rawEntryId.startsWith('/@')) {
- versionAtSignIndex = rawEntryId.indexOf('@', 2);
+ if (slashlessRawEntryId.startsWith('@')) {
+ versionAtSignIndex = slashlessRawEntryId.indexOf('@', 1);
} else {
- versionAtSignIndex = rawEntryId.indexOf('@', 1);
+ versionAtSignIndex = slashlessRawEntryId.indexOf('@');
}
- const packageName: string = rawEntryId.substring(1, versionAtSignIndex);
+
+ const packageName: string = slashlessRawEntryId.substring(0, versionAtSignIndex);
result.entryPackageName = packageName;
- const leftParenIndex: number = rawEntryId.indexOf('(', versionAtSignIndex);
+ const leftParenIndex: number = slashlessRawEntryId.indexOf('(', versionAtSignIndex);
if (leftParenIndex < 0) {
- const version: string = rawEntryId.substring(versionAtSignIndex + 1);
+ const version: string = slashlessRawEntryId.substring(versionAtSignIndex + 1);
result.entryPackageVersion = version;
- // /@rushstack/eslint-config@3.0.1
+ // @rushstack/eslint-config@3.0.1
// --> @rushstack/eslint-config 3.0.1
result.displayText = packageName + ' ' + version;
} else {
- const version: string = rawEntryId.substring(versionAtSignIndex + 1, leftParenIndex);
+ const version: string = slashlessRawEntryId.substring(versionAtSignIndex + 1, leftParenIndex);
result.entryPackageVersion = version;
// "(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)"
- let suffix: string = rawEntryId.substring(leftParenIndex);
+ let suffix: string = slashlessRawEntryId.substring(leftParenIndex);
// Rewrite to:
// "@rushstack/m@1.0.0; @rushstack/n@2.0.0"
@@ -325,17 +402,16 @@ function createPackageLockfileEntry(options: {
suffix = Text.replaceAll(suffix, ')', '');
result.entrySuffix = suffix;
- // /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ // @rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
// --> @rushstack/l 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]
result.displayText = packageName + ' ' + version + ' [' + suffix + ']';
}
- // Example: /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ // Example: @rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
// --> @rushstack+l@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0
// @rushstack/l 1.0.0 (@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
- dotPnpmSubfolder = rawEntryId.substring(1);
- dotPnpmSubfolder = Text.replaceAll(dotPnpmSubfolder, '/', '+');
+ dotPnpmSubfolder = Text.replaceAll(slashlessRawEntryId, '/', '+');
dotPnpmSubfolder = Text.replaceAll(dotPnpmSubfolder, ')(', '_');
dotPnpmSubfolder = Text.replaceAll(dotPnpmSubfolder, '(', '_');
dotPnpmSubfolder = Text.replaceAll(dotPnpmSubfolder, ')', '');
@@ -351,13 +427,6 @@ function createPackageLockfileEntry(options: {
);
const lockfileEntry: LfxGraphEntry = new LfxGraphEntry(result);
- parsePackageDependencies(
- lockfileEntry.dependencies,
- lockfileEntry,
- rawYamlData,
- pnpmLockfileVersion,
- workspace
- );
return lockfileEntry;
}
@@ -381,10 +450,10 @@ export function generateLockfileGraph(lockfileJson: unknown, workspace: IJsonLfx
case '6.0':
pnpmLockfileVersion = 60;
break;
- //case '9':
- //case '9.0':
- // pnpmLockfileVersion = 90;
- // break;
+ case '9':
+ case '9.0':
+ pnpmLockfileVersion = 90;
+ break;
default:
throw new Error('Unsupported PNPM lockfile version ' + JSON.stringify(lockfile.lockfileVersion));
}
@@ -424,17 +493,18 @@ export function generateLockfileGraph(lockfileJson: unknown, workspace: IJsonLfx
pnpmLockfileVersion
});
- if (pnpmLockfileVersion === 54) {
+ if (pnpmLockfileVersion < 60) {
const lockfile54: lockfileTypes.LockfileObject = lockfileJson as lockfileTypes.LockfileObject;
const importerValue: lockfileTypes.ProjectSnapshot =
lockfile54.importers[importerKey as pnpmTypes.ProjectId];
- parsePackageDependencies(
- importer.dependencies,
- importer,
- importerValue,
+
+ parseProjectDependencies54({
+ dependencies: importer.dependencies,
+ lockfileEntry: importer,
+ mainEntry: importerValue,
pnpmLockfileVersion,
workspace
- );
+ });
} else {
const lockfile60: lockfileTypes.LockfileFile = lockfileJson as lockfileTypes.LockfileFile;
if (lockfile60.importers) {
@@ -456,21 +526,62 @@ export function generateLockfileGraph(lockfileJson: unknown, workspace: IJsonLfx
}
}
- const allPackages: LfxGraphEntry[] = [];
- if (lockfile.packages) {
- for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages ?? {})) {
- // const normalizedPath = new Path(dependencyKey).makeAbsolute('/').toString();
+ if (pnpmLockfileVersion < 90) {
+ if (lockfile.packages) {
+ for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages)) {
+ const lockfileEntry: LfxGraphEntry = createPackageLockfileEntry({
+ rawEntryId: dependencyKey,
+ workspace,
+ pnpmLockfileVersion
+ });
+ parsePackageDependencies({
+ dependencies: lockfileEntry.dependencies,
+ lockfileEntry: lockfileEntry,
+ mainEntry: dependencyValue,
+ specifierEntry: dependencyValue,
+ pnpmLockfileVersion,
+ workspace
+ });
+ allEntries.push(lockfileEntry);
+ allEntriesById.set(dependencyKey, lockfileEntry);
+ }
+ }
+ } else {
+ const packagesByKey: Map = new Map();
+ if (lockfile.packages) {
+ for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages)) {
+ packagesByKey.set(dependencyKey, dependencyValue);
+ }
+ }
- const currEntry: LfxGraphEntry = createPackageLockfileEntry({
- rawEntryId: dependencyKey,
- rawYamlData: dependencyValue as lockfileTypes.PackageSnapshot,
- workspace,
- pnpmLockfileVersion
- });
+ // In v9.0 format, the dependency graph for non-workspace packages is found under "snapshots" not "packages".
+ // (The "packages" section now stores other fields that are unrelated to the graph itself.)
+ const lockfile90: lockfileTypes.LockfileFile = lockfileJson as lockfileTypes.LockfileFile;
+ if (lockfile90.snapshots) {
+ for (const [dependencyKey, dependencyValue] of Object.entries(lockfile90.snapshots)) {
+ const lockfileEntry: LfxGraphEntry = createPackageLockfileEntry({
+ rawEntryId: dependencyKey,
+ workspace,
+ pnpmLockfileVersion
+ });
+
+ // Example: "@scope/my-package@1.0.0"
+ const packageInfoKey: string =
+ lockfileEntry.entryPackageName + '@' + lockfileEntry.entryPackageVersion;
+ const packageInfo: lockfileTypes.LockfilePackageInfo | undefined = packagesByKey.get(packageInfoKey);
+
+ parsePackageDependencies({
+ dependencies: lockfileEntry.dependencies,
+ lockfileEntry,
+ mainEntry: dependencyValue,
+ specifierEntry: packageInfo,
+ pnpmLockfileVersion,
+ workspace
+ });
- allPackages.push(currEntry);
- allEntries.push(currEntry);
- allEntriesById.set(dependencyKey, currEntry);
+ allEntries.push(lockfileEntry);
+ allEntriesById.set(lockfileEntry.entryId, lockfileEntry);
+ }
}
}
@@ -478,7 +589,7 @@ export function generateLockfileGraph(lockfileJson: unknown, workspace: IJsonLfx
for (const entry of allEntries) {
for (const dependency of entry.dependencies) {
// Peer dependencies do not have a matching entry
- if (dependency.dependencyType === LfxDependencyKind.Peer) {
+ if (dependency.dependencyKind === LfxDependencyKind.Peer) {
continue;
}
diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v5.4.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v5.4.test.ts.snap
index ff8058f4180..a8af1106857 100644
--- a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v5.4.test.ts.snap
+++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v5.4.test.ts.snap
@@ -3,159 +3,280 @@
exports[`lfxGraph-edge-cases-v5.4 loads a workspace 1`] = `
"entries:
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
+ entryId: /mime-db/1.54.0
+ name: mime-db
+ originalSpecifier: ^1.52.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 11
+ versionPath: 1.54.0
+ - dependencyKind: dev
+ entryId: /color-string/2.1.2
+ name: color-string
+ originalSpecifier: ^2.1.2
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
+ displayText: 'Project: dev-dependencies'
+ entryId: project:packages/dev-dependencies
+ entryPackageName: dev-dependencies
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 0
+ kind: 1
+ packageJsonFolderPath: packages/dev-dependencies
+ rawEntryId: packages/dev-dependencies
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
entryId: /color/5.0.2
name: color
+ originalSpecifier: ^5.0.2
peerDependencyMeta: {}
- resolvedEntryJsonId: 6
- version: 5.0.2
- displayText: 'Project: duplicate (duplicate-1/duplicate)'
- entryId: project:duplicate-1/duplicate
- entryPackageName: duplicate (duplicate-1/duplicate)
+ resolvedEntryJsonId: 9
+ versionPath: 5.0.2
+ displayText: 'Project: duplicate (packages/duplicate-1/duplicate)'
+ entryId: project:packages/duplicate-1/duplicate
+ entryPackageName: duplicate (packages/duplicate-1/duplicate)
entryPackageVersion: ''
entrySuffix: ''
- jsonId: 0
+ jsonId: 1
kind: 1
- packageJsonFolderPath: duplicate-1/duplicate
- rawEntryId: duplicate-1/duplicate
+ packageJsonFolderPath: packages/duplicate-1/duplicate
+ rawEntryId: packages/duplicate-1/duplicate
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /color-string/2.1.2
name: color-string
+ originalSpecifier: ^2.1.2
peerDependencyMeta: {}
- resolvedEntryJsonId: 5
- version: 2.1.2
- displayText: 'Project: duplicate (duplicate-2/duplicate)'
- entryId: project:duplicate-2/duplicate
- entryPackageName: duplicate (duplicate-2/duplicate)
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
+ displayText: 'Project: duplicate (packages/duplicate-2/duplicate)'
+ entryId: project:packages/duplicate-2/duplicate
+ entryPackageName: duplicate (packages/duplicate-2/duplicate)
entryPackageVersion: ''
entrySuffix: ''
- jsonId: 1
+ jsonId: 2
kind: 1
- packageJsonFolderPath: duplicate-2/duplicate
- rawEntryId: duplicate-2/duplicate
+ packageJsonFolderPath: packages/duplicate-2/duplicate
+ rawEntryId: packages/duplicate-2/duplicate
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /has-symbols/1.0.2
name: has-symbols
+ originalSpecifier: 1.0.2
peerDependencyMeta: {}
- resolvedEntryJsonId: 7
- version: 1.0.2
- - dependencyType: regular
- entryId: project:link-specifier/target-folder
+ resolvedEntryJsonId: 10
+ versionPath: 1.0.2
+ - dependencyKind: regular
+ entryId: project:packages/link-specifier/linker/packages/link-specifier/target-folder
name: target-folder
+ originalSpecifier: link:packages/link-specifier/target-folder
peerDependencyMeta: {}
- version: link:../target-folder
+ versionPath: link:packages/link-specifier/target-folder
displayText: 'Project: linker'
- entryId: project:link-specifier/linker
+ entryId: project:packages/link-specifier/linker
entryPackageName: linker
entryPackageVersion: ''
entrySuffix: ''
- jsonId: 2
+ jsonId: 3
kind: 1
- packageJsonFolderPath: link-specifier/linker
- rawEntryId: link-specifier/linker
+ packageJsonFolderPath: packages/link-specifier/linker
+ rawEntryId: packages/link-specifier/linker
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
+ entryId: /address/1.2.2
+ name: address
+ originalSpecifier: ^1.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 5
+ versionPath: 1.2.2
+ - dependencyKind: regular
+ entryId: /uri-js/4.4.1
+ name: uri-js
+ originalSpecifier: ^4.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 13
+ versionPath: 4.4.1
+ displayText: 'Project: pnpmfile-transforms'
+ entryId: project:packages/pnpmfile-transforms
+ entryPackageName: pnpmfile-transforms
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 4
+ kind: 1
+ packageJsonFolderPath: packages/pnpmfile-transforms
+ rawEntryId: packages/pnpmfile-transforms
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: address 1.2.2
+ entryId: /address/1.2.2
+ entryPackageName: address
+ entryPackageVersion: 1.2.2
+ entrySuffix: ''
+ jsonId: 5
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/address@1.2.2/node_modules/address
+ rawEntryId: /address/1.2.2
+ referrerJsonIds:
+ - 4
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
entryId: /color-name/2.0.2
name: color-name
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 4
- version: 2.0.2
+ resolvedEntryJsonId: 7
+ versionPath: 2.0.2
displayText: color-convert 3.1.2
- entryId: ''
+ entryId: /color-convert/3.1.2
entryPackageName: color-convert
entryPackageVersion: 3.1.2
entrySuffix: ''
- jsonId: 3
+ jsonId: 6
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color-convert@3.1.2/node_modules/color-convert
rawEntryId: /color-convert/3.1.2
referrerJsonIds:
- - 6
+ - 9
transitivePeerDependencies: []
- dependencies: []
displayText: color-name 2.0.2
- entryId: ''
+ entryId: /color-name/2.0.2
entryPackageName: color-name
entryPackageVersion: 2.0.2
entrySuffix: ''
- jsonId: 4
+ jsonId: 7
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color-name@2.0.2/node_modules/color-name
rawEntryId: /color-name/2.0.2
referrerJsonIds:
- - 3
- - 5
+ - 6
+ - 8
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /color-name/2.0.2
name: color-name
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 4
- version: 2.0.2
+ resolvedEntryJsonId: 7
+ versionPath: 2.0.2
displayText: color-string 2.1.2
- entryId: ''
+ entryId: /color-string/2.1.2
entryPackageName: color-string
entryPackageVersion: 2.1.2
entrySuffix: ''
- jsonId: 5
+ jsonId: 8
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color-string@2.1.2/node_modules/color-string
rawEntryId: /color-string/2.1.2
referrerJsonIds:
- - 1
- - 6
+ - 0
+ - 2
+ - 9
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /color-convert/3.1.2
name: color-convert
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 3
- version: 3.1.2
- - dependencyType: regular
+ resolvedEntryJsonId: 6
+ versionPath: 3.1.2
+ - dependencyKind: regular
entryId: /color-string/2.1.2
name: color-string
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 5
- version: 2.1.2
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
displayText: color 5.0.2
- entryId: ''
+ entryId: /color/5.0.2
entryPackageName: color
entryPackageVersion: 5.0.2
entrySuffix: ''
- jsonId: 6
+ jsonId: 9
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color@5.0.2/node_modules/color
rawEntryId: /color/5.0.2
referrerJsonIds:
- - 0
+ - 1
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: ''
name: target-folder
+ originalSpecifier: ''
peerDependencyMeta: {}
- version: link:link-specifier/target-folder
+ versionPath: link:link-specifier/target-folder
displayText: has-symbols 1.0.2
- entryId: ''
+ entryId: /has-symbols/1.0.2
entryPackageName: has-symbols
entryPackageVersion: 1.0.2
entrySuffix: ''
- jsonId: 7
+ jsonId: 10
kind: 2
packageJsonFolderPath: node_modules/.pnpm/has-symbols@1.0.2/node_modules/has-symbols
rawEntryId: /has-symbols/1.0.2
referrerJsonIds:
- - 2
+ - 3
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: mime-db 1.54.0
+ entryId: /mime-db/1.54.0
+ entryPackageName: mime-db
+ entryPackageVersion: 1.54.0
+ entrySuffix: ''
+ jsonId: 11
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db
+ rawEntryId: /mime-db/1.54.0
+ referrerJsonIds:
+ - 0
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: punycode 2.3.1
+ entryId: /punycode/2.3.1
+ entryPackageName: punycode
+ entryPackageVersion: 2.3.1
+ entrySuffix: ''
+ jsonId: 12
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/punycode@2.3.1/node_modules/punycode
+ rawEntryId: /punycode/2.3.1
+ referrerJsonIds:
+ - 13
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: /punycode/2.3.1
+ name: punycode
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 12
+ versionPath: 2.3.1
+ displayText: uri-js 4.4.1
+ entryId: /uri-js/4.4.1
+ entryPackageName: uri-js
+ entryPackageVersion: 4.4.1
+ entrySuffix: ''
+ jsonId: 13
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js
+ rawEntryId: /uri-js/4.4.1
+ referrerJsonIds:
+ - 4
transitivePeerDependencies: []
workspace:
pnpmLockfileFolder: ''
diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v6.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v6.0.test.ts.snap
index ff8058f4180..fd6f0c80fdd 100644
--- a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v6.0.test.ts.snap
+++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v6.0.test.ts.snap
@@ -1,161 +1,282 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`lfxGraph-edge-cases-v5.4 loads a workspace 1`] = `
+exports[`lfxGraph-edge-cases-v6.0 loads a workspace 1`] = `
"entries:
- dependencies:
- - dependencyType: regular
- entryId: /color/5.0.2
- name: color
+ - dependencyKind: regular
+ entryId: /mime-db@1.54.0
+ name: mime-db
+ originalSpecifier: ^1.52.0
peerDependencyMeta: {}
- resolvedEntryJsonId: 6
- version: 5.0.2
- displayText: 'Project: duplicate (duplicate-1/duplicate)'
- entryId: project:duplicate-1/duplicate
- entryPackageName: duplicate (duplicate-1/duplicate)
+ resolvedEntryJsonId: 11
+ versionPath: 1.54.0
+ - dependencyKind: dev
+ entryId: /color-string@2.1.2
+ name: color-string
+ originalSpecifier: ^2.1.2
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
+ displayText: 'Project: dev-dependencies'
+ entryId: project:packages/dev-dependencies
+ entryPackageName: dev-dependencies
entryPackageVersion: ''
entrySuffix: ''
jsonId: 0
kind: 1
- packageJsonFolderPath: duplicate-1/duplicate
- rawEntryId: duplicate-1/duplicate
+ packageJsonFolderPath: packages/dev-dependencies
+ rawEntryId: packages/dev-dependencies
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
- entryId: /color-string/2.1.2
- name: color-string
+ - dependencyKind: regular
+ entryId: /color@5.0.2
+ name: color
+ originalSpecifier: ^5.0.2
peerDependencyMeta: {}
- resolvedEntryJsonId: 5
- version: 2.1.2
- displayText: 'Project: duplicate (duplicate-2/duplicate)'
- entryId: project:duplicate-2/duplicate
- entryPackageName: duplicate (duplicate-2/duplicate)
+ resolvedEntryJsonId: 9
+ versionPath: 5.0.2
+ displayText: 'Project: duplicate (packages/duplicate-1/duplicate)'
+ entryId: project:packages/duplicate-1/duplicate
+ entryPackageName: duplicate (packages/duplicate-1/duplicate)
entryPackageVersion: ''
entrySuffix: ''
jsonId: 1
kind: 1
- packageJsonFolderPath: duplicate-2/duplicate
- rawEntryId: duplicate-2/duplicate
+ packageJsonFolderPath: packages/duplicate-1/duplicate
+ rawEntryId: packages/duplicate-1/duplicate
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
- entryId: /has-symbols/1.0.2
+ - dependencyKind: regular
+ entryId: /color-string@2.1.2
+ name: color-string
+ originalSpecifier: ^2.1.2
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
+ displayText: 'Project: duplicate (packages/duplicate-2/duplicate)'
+ entryId: project:packages/duplicate-2/duplicate
+ entryPackageName: duplicate (packages/duplicate-2/duplicate)
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 2
+ kind: 1
+ packageJsonFolderPath: packages/duplicate-2/duplicate
+ rawEntryId: packages/duplicate-2/duplicate
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: /has-symbols@1.0.2
name: has-symbols
+ originalSpecifier: 1.0.2
peerDependencyMeta: {}
- resolvedEntryJsonId: 7
- version: 1.0.2
- - dependencyType: regular
- entryId: project:link-specifier/target-folder
+ resolvedEntryJsonId: 10
+ versionPath: 1.0.2
+ - dependencyKind: regular
+ entryId: project:packages/link-specifier/linker/packages/link-specifier/target-folder
name: target-folder
+ originalSpecifier: link:packages/link-specifier/target-folder
peerDependencyMeta: {}
- version: link:../target-folder
+ versionPath: link:packages/link-specifier/target-folder
displayText: 'Project: linker'
- entryId: project:link-specifier/linker
+ entryId: project:packages/link-specifier/linker
entryPackageName: linker
entryPackageVersion: ''
entrySuffix: ''
- jsonId: 2
+ jsonId: 3
kind: 1
- packageJsonFolderPath: link-specifier/linker
- rawEntryId: link-specifier/linker
+ packageJsonFolderPath: packages/link-specifier/linker
+ rawEntryId: packages/link-specifier/linker
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
- entryId: /color-name/2.0.2
+ - dependencyKind: regular
+ entryId: /address@1.2.2
+ name: address
+ originalSpecifier: ^1.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 5
+ versionPath: 1.2.2
+ - dependencyKind: regular
+ entryId: /uri-js@4.4.1
+ name: uri-js
+ originalSpecifier: ^4.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 13
+ versionPath: 4.4.1
+ displayText: 'Project: pnpmfile-transforms'
+ entryId: project:packages/pnpmfile-transforms
+ entryPackageName: pnpmfile-transforms
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 4
+ kind: 1
+ packageJsonFolderPath: packages/pnpmfile-transforms
+ rawEntryId: packages/pnpmfile-transforms
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: address 1.2.2
+ entryId: /address@1.2.2
+ entryPackageName: address
+ entryPackageVersion: 1.2.2
+ entrySuffix: ''
+ jsonId: 5
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/address@1.2.2/node_modules/address
+ rawEntryId: /address@1.2.2
+ referrerJsonIds:
+ - 4
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: /color-name@2.0.2
name: color-name
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 4
- version: 2.0.2
+ resolvedEntryJsonId: 7
+ versionPath: 2.0.2
displayText: color-convert 3.1.2
- entryId: ''
+ entryId: /color-convert@3.1.2
entryPackageName: color-convert
entryPackageVersion: 3.1.2
entrySuffix: ''
- jsonId: 3
+ jsonId: 6
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color-convert@3.1.2/node_modules/color-convert
- rawEntryId: /color-convert/3.1.2
+ rawEntryId: /color-convert@3.1.2
referrerJsonIds:
- - 6
+ - 9
transitivePeerDependencies: []
- dependencies: []
displayText: color-name 2.0.2
- entryId: ''
+ entryId: /color-name@2.0.2
entryPackageName: color-name
entryPackageVersion: 2.0.2
entrySuffix: ''
- jsonId: 4
+ jsonId: 7
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color-name@2.0.2/node_modules/color-name
- rawEntryId: /color-name/2.0.2
+ rawEntryId: /color-name@2.0.2
referrerJsonIds:
- - 3
- - 5
+ - 6
+ - 8
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
- entryId: /color-name/2.0.2
+ - dependencyKind: regular
+ entryId: /color-name@2.0.2
name: color-name
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 4
- version: 2.0.2
+ resolvedEntryJsonId: 7
+ versionPath: 2.0.2
displayText: color-string 2.1.2
- entryId: ''
+ entryId: /color-string@2.1.2
entryPackageName: color-string
entryPackageVersion: 2.1.2
entrySuffix: ''
- jsonId: 5
+ jsonId: 8
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color-string@2.1.2/node_modules/color-string
- rawEntryId: /color-string/2.1.2
+ rawEntryId: /color-string@2.1.2
referrerJsonIds:
- - 1
- - 6
+ - 0
+ - 2
+ - 9
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
- entryId: /color-convert/3.1.2
+ - dependencyKind: regular
+ entryId: /color-convert@3.1.2
name: color-convert
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 3
- version: 3.1.2
- - dependencyType: regular
- entryId: /color-string/2.1.2
+ resolvedEntryJsonId: 6
+ versionPath: 3.1.2
+ - dependencyKind: regular
+ entryId: /color-string@2.1.2
name: color-string
+ originalSpecifier: ''
peerDependencyMeta: {}
- resolvedEntryJsonId: 5
- version: 2.1.2
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
displayText: color 5.0.2
- entryId: ''
+ entryId: /color@5.0.2
entryPackageName: color
entryPackageVersion: 5.0.2
entrySuffix: ''
- jsonId: 6
+ jsonId: 9
kind: 2
packageJsonFolderPath: node_modules/.pnpm/color@5.0.2/node_modules/color
- rawEntryId: /color/5.0.2
+ rawEntryId: /color@5.0.2
referrerJsonIds:
- - 0
+ - 1
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: ''
name: target-folder
+ originalSpecifier: ''
peerDependencyMeta: {}
- version: link:link-specifier/target-folder
+ versionPath: link:link-specifier/target-folder
displayText: has-symbols 1.0.2
- entryId: ''
+ entryId: /has-symbols@1.0.2
entryPackageName: has-symbols
entryPackageVersion: 1.0.2
entrySuffix: ''
- jsonId: 7
+ jsonId: 10
kind: 2
packageJsonFolderPath: node_modules/.pnpm/has-symbols@1.0.2/node_modules/has-symbols
- rawEntryId: /has-symbols/1.0.2
+ rawEntryId: /has-symbols@1.0.2
referrerJsonIds:
- - 2
+ - 3
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: mime-db 1.54.0
+ entryId: /mime-db@1.54.0
+ entryPackageName: mime-db
+ entryPackageVersion: 1.54.0
+ entrySuffix: ''
+ jsonId: 11
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db
+ rawEntryId: /mime-db@1.54.0
+ referrerJsonIds:
+ - 0
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: punycode 2.3.1
+ entryId: /punycode@2.3.1
+ entryPackageName: punycode
+ entryPackageVersion: 2.3.1
+ entrySuffix: ''
+ jsonId: 12
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/punycode@2.3.1/node_modules/punycode
+ rawEntryId: /punycode@2.3.1
+ referrerJsonIds:
+ - 13
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: /punycode@2.3.1
+ name: punycode
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 12
+ versionPath: 2.3.1
+ displayText: uri-js 4.4.1
+ entryId: /uri-js@4.4.1
+ entryPackageName: uri-js
+ entryPackageVersion: 4.4.1
+ entrySuffix: ''
+ jsonId: 13
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js
+ rawEntryId: /uri-js@4.4.1
+ referrerJsonIds:
+ - 4
transitivePeerDependencies: []
workspace:
pnpmLockfileFolder: ''
diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v9.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v9.0.test.ts.snap
new file mode 100644
index 00000000000..e2683f0e50d
--- /dev/null
+++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-edge-cases-v9.0.test.ts.snap
@@ -0,0 +1,287 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`lfxGraph-edge-cases-v9.0 loads a workspace 1`] = `
+"entries:
+ - dependencies:
+ - dependencyKind: regular
+ entryId: mime-db@1.54.0
+ name: mime-db
+ originalSpecifier: ^1.52.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 11
+ versionPath: 1.54.0
+ - dependencyKind: dev
+ entryId: color-string@2.1.2
+ name: color-string
+ originalSpecifier: ^2.1.2
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
+ displayText: 'Project: dev-dependencies'
+ entryId: project:packages/dev-dependencies
+ entryPackageName: dev-dependencies
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 0
+ kind: 1
+ packageJsonFolderPath: packages/dev-dependencies
+ rawEntryId: packages/dev-dependencies
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: color@5.0.2
+ name: color
+ originalSpecifier: ^5.0.2
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 9
+ versionPath: 5.0.2
+ displayText: 'Project: duplicate (packages/duplicate-1/duplicate)'
+ entryId: project:packages/duplicate-1/duplicate
+ entryPackageName: duplicate (packages/duplicate-1/duplicate)
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 1
+ kind: 1
+ packageJsonFolderPath: packages/duplicate-1/duplicate
+ rawEntryId: packages/duplicate-1/duplicate
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: color-string@2.1.2
+ name: color-string
+ originalSpecifier: ^2.1.2
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
+ displayText: 'Project: duplicate (packages/duplicate-2/duplicate)'
+ entryId: project:packages/duplicate-2/duplicate
+ entryPackageName: duplicate (packages/duplicate-2/duplicate)
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 2
+ kind: 1
+ packageJsonFolderPath: packages/duplicate-2/duplicate
+ rawEntryId: packages/duplicate-2/duplicate
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: has-symbols@1.0.2
+ name: has-symbols
+ originalSpecifier: 1.0.2
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 10
+ versionPath: 1.0.2
+ - dependencyKind: regular
+ entryId: project:packages/link-specifier/linker/packages/link-specifier/target-folder
+ name: target-folder
+ originalSpecifier: link:packages/link-specifier/target-folder
+ peerDependencyMeta: {}
+ versionPath: link:packages/link-specifier/target-folder
+ displayText: 'Project: linker'
+ entryId: project:packages/link-specifier/linker
+ entryPackageName: linker
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 3
+ kind: 1
+ packageJsonFolderPath: packages/link-specifier/linker
+ rawEntryId: packages/link-specifier/linker
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: address@1.2.2
+ name: address
+ originalSpecifier: ^1.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 5
+ versionPath: 1.2.2
+ - dependencyKind: regular
+ entryId: uri-js@4.4.1
+ name: uri-js
+ originalSpecifier: ^4.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 13
+ versionPath: 4.4.1
+ displayText: 'Project: pnpmfile-transforms'
+ entryId: project:packages/pnpmfile-transforms
+ entryPackageName: pnpmfile-transforms
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 4
+ kind: 1
+ packageJsonFolderPath: packages/pnpmfile-transforms
+ rawEntryId: packages/pnpmfile-transforms
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: address 1.2.2
+ entryId: address@1.2.2
+ entryPackageName: address
+ entryPackageVersion: 1.2.2
+ entrySuffix: ''
+ jsonId: 5
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/address@1.2.2/node_modules/address
+ rawEntryId: address@1.2.2
+ referrerJsonIds:
+ - 4
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: color-name@2.0.2
+ name: color-name
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 7
+ versionPath: 2.0.2
+ displayText: color-convert 3.1.2
+ entryId: color-convert@3.1.2
+ entryPackageName: color-convert
+ entryPackageVersion: 3.1.2
+ entrySuffix: ''
+ jsonId: 6
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/color-convert@3.1.2/node_modules/color-convert
+ rawEntryId: color-convert@3.1.2
+ referrerJsonIds:
+ - 9
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: color-name 2.0.2
+ entryId: color-name@2.0.2
+ entryPackageName: color-name
+ entryPackageVersion: 2.0.2
+ entrySuffix: ''
+ jsonId: 7
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/color-name@2.0.2/node_modules/color-name
+ rawEntryId: color-name@2.0.2
+ referrerJsonIds:
+ - 6
+ - 8
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: color-name@2.0.2
+ name: color-name
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 7
+ versionPath: 2.0.2
+ displayText: color-string 2.1.2
+ entryId: color-string@2.1.2
+ entryPackageName: color-string
+ entryPackageVersion: 2.1.2
+ entrySuffix: ''
+ jsonId: 8
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/color-string@2.1.2/node_modules/color-string
+ rawEntryId: color-string@2.1.2
+ referrerJsonIds:
+ - 0
+ - 2
+ - 9
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: color-convert@3.1.2
+ name: color-convert
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 6
+ versionPath: 3.1.2
+ - dependencyKind: regular
+ entryId: color-string@2.1.2
+ name: color-string
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 2.1.2
+ displayText: color 5.0.2
+ entryId: color@5.0.2
+ entryPackageName: color
+ entryPackageVersion: 5.0.2
+ entrySuffix: ''
+ jsonId: 9
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/color@5.0.2/node_modules/color
+ rawEntryId: color@5.0.2
+ referrerJsonIds:
+ - 1
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: ''
+ name: target-folder
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ versionPath: link:link-specifier/target-folder
+ displayText: has-symbols 1.0.2
+ entryId: has-symbols@1.0.2
+ entryPackageName: has-symbols
+ entryPackageVersion: 1.0.2
+ entrySuffix: ''
+ jsonId: 10
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/has-symbols@1.0.2/node_modules/has-symbols
+ rawEntryId: has-symbols@1.0.2
+ referrerJsonIds:
+ - 3
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: mime-db 1.54.0
+ entryId: mime-db@1.54.0
+ entryPackageName: mime-db
+ entryPackageVersion: 1.54.0
+ entrySuffix: ''
+ jsonId: 11
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/mime-db@1.54.0/node_modules/mime-db
+ rawEntryId: mime-db@1.54.0
+ referrerJsonIds:
+ - 0
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: punycode 2.3.1
+ entryId: punycode@2.3.1
+ entryPackageName: punycode
+ entryPackageVersion: 2.3.1
+ entrySuffix: ''
+ jsonId: 12
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/punycode@2.3.1/node_modules/punycode
+ rawEntryId: punycode@2.3.1
+ referrerJsonIds:
+ - 13
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: punycode@2.3.1
+ name: punycode
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 12
+ versionPath: 2.3.1
+ displayText: uri-js 4.4.1
+ entryId: uri-js@4.4.1
+ entryPackageName: uri-js
+ entryPackageVersion: 4.4.1
+ entrySuffix: ''
+ jsonId: 13
+ kind: 2
+ packageJsonFolderPath: node_modules/.pnpm/uri-js@4.4.1/node_modules/uri-js
+ rawEntryId: uri-js@4.4.1
+ referrerJsonIds:
+ - 4
+ transitivePeerDependencies: []
+workspace:
+ pnpmLockfileFolder: ''
+ pnpmLockfilePath: pnpm-lock.yaml
+ pnpmfilePath: .pnpmfile.cjs
+ workspaceRootFullPath: /repo
+"
+`;
diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap
index 58b8bf4cb78..804e1219938 100644
--- a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap
+++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap
@@ -3,12 +3,13 @@
exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
"entries:
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/d
name: '@rushstack/d'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 3
- version: link:../d
+ versionPath: link:../d
displayText: 'Project: a'
entryId: project:projects/a
entryPackageName: a
@@ -21,18 +22,20 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/d
name: '@rushstack/d'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 3
- version: link:../d
- - dependencyType: regular
+ versionPath: link:../d
+ - dependencyKind: regular
entryId: /@rushstack/n/2.0.0
name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 11
- version: 2.0.0
+ versionPath: 2.0.0
displayText: 'Project: b'
entryId: project:projects/b
entryPackageName: b
@@ -45,24 +48,27 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/e
name: '@rushstack/e'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 4
- version: link:../e
- - dependencyType: regular
+ versionPath: link:../e
+ - dependencyKind: regular
entryId: /@rushstack/k/1.0.0_@rushstack+m@1.0.0
name: '@rushstack/k'
+ originalSpecifier: ^1.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 6
- version: 1.0.0_@rushstack+m@1.0.0
- - dependencyType: regular
+ versionPath: 1.0.0_@rushstack+m@1.0.0
+ - dependencyKind: regular
entryId: /@rushstack/m/1.0.0
name: '@rushstack/m'
+ originalSpecifier: ~1.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 10
- version: 1.0.0
+ versionPath: 1.0.0
displayText: 'Project: c'
entryId: project:projects/c
entryPackageName: c
@@ -75,24 +81,27 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/e
name: '@rushstack/e'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 4
- version: link:../e
- - dependencyType: regular
+ versionPath: link:../e
+ - dependencyKind: regular
entryId: /@rushstack/j/1.0.0_@rushstack+n@2.0.0
name: '@rushstack/j'
+ originalSpecifier: ^1.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 5
- version: 1.0.0_@rushstack+n@2.0.0
- - dependencyType: regular
+ versionPath: 1.0.0_@rushstack+n@2.0.0
+ - dependencyKind: regular
entryId: /@rushstack/n/2.0.0
name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 11
- version: 2.0.0
+ versionPath: 2.0.0
displayText: 'Project: d'
entryId: project:projects/d
entryPackageName: d
@@ -107,12 +116,13 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
- 1
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /@rushstack/n/3.0.0
name: '@rushstack/n'
+ originalSpecifier: ^3.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 12
- version: 3.0.0
+ versionPath: 3.0.0
displayText: 'Project: e'
entryId: project:projects/e
entryPackageName: e
@@ -127,20 +137,22 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
- 3
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu
name: '@rushstack/k'
+ originalSpecifier: ''
peerDependencyMeta: {}
resolvedEntryJsonId: 7
- version: 1.0.0_wxpgugna4ivthu7yyu4fmciltu
- - dependencyType: regular
+ versionPath: 1.0.0_wxpgugna4ivthu7yyu4fmciltu
+ - dependencyKind: regular
entryId: /@rushstack/m/1.0.0
name: '@rushstack/m'
+ originalSpecifier: ''
peerDependencyMeta: {}
resolvedEntryJsonId: 10
- version: 1.0.0
+ versionPath: 1.0.0
displayText: '@rushstack/j 1.0.0 (@rushstack+n@2.0.0)'
- entryId: ''
+ entryId: /@rushstack/j/1.0.0_@rushstack+n@2.0.0
entryPackageName: '@rushstack/j'
entryPackageVersion: 1.0.0
entrySuffix: '@rushstack+n@2.0.0'
@@ -153,14 +165,15 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
transitivePeerDependencies:
- '@rushstack/n'
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /@rushstack/l/1.0.0_@rushstack+m@1.0.0
name: '@rushstack/l'
+ originalSpecifier: ''
peerDependencyMeta: {}
resolvedEntryJsonId: 8
- version: 1.0.0_@rushstack+m@1.0.0
+ versionPath: 1.0.0_@rushstack+m@1.0.0
displayText: '@rushstack/k 1.0.0 (@rushstack+m@1.0.0)'
- entryId: ''
+ entryId: /@rushstack/k/1.0.0_@rushstack+m@1.0.0
entryPackageName: '@rushstack/k'
entryPackageVersion: 1.0.0
entrySuffix: '@rushstack+m@1.0.0'
@@ -174,14 +187,15 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
- '@rushstack/m'
- '@rushstack/n'
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu
name: '@rushstack/l'
+ originalSpecifier: ''
peerDependencyMeta: {}
resolvedEntryJsonId: 9
- version: 1.0.0_wxpgugna4ivthu7yyu4fmciltu
+ versionPath: 1.0.0_wxpgugna4ivthu7yyu4fmciltu
displayText: '@rushstack/k 1.0.0 (wxpgugna4ivthu7yyu4fmciltu)'
- entryId: ''
+ entryId: /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu
entryPackageName: '@rushstack/k'
entryPackageVersion: 1.0.0
entrySuffix: wxpgugna4ivthu7yyu4fmciltu
@@ -195,30 +209,17 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
- '@rushstack/m'
- '@rushstack/n'
- dependencies:
- - dependencyType: regular
+ - dependencyKind: peer
entryId: /@rushstack/m/1.0.0
name: '@rushstack/m'
- peerDependencyMeta: {}
- resolvedEntryJsonId: 10
- version: 1.0.0
- - dependencyType: peer
- entryId: 'Peer: @rushstack/m'
- name: '@rushstack/m'
+ originalSpecifier: ^1.0.0
peerDependencyMeta:
name: '@rushstack/m'
optional: false
- version: ^1.0.0
- version: ^1.0.0
- - dependencyType: peer
- entryId: 'Peer: @rushstack/n'
- name: '@rushstack/n'
- peerDependencyMeta:
- name: '@rushstack/n'
- optional: true
- version: ^2.0.0
- version: ^2.0.0
+ version: 1.0.0
+ versionPath: 1.0.0
displayText: '@rushstack/l 1.0.0 (@rushstack+m@1.0.0)'
- entryId: ''
+ entryId: /@rushstack/l/1.0.0_@rushstack+m@1.0.0
entryPackageName: '@rushstack/l'
entryPackageVersion: 1.0.0
entrySuffix: '@rushstack+m@1.0.0'
@@ -230,36 +231,26 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
- 6
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: peer
entryId: /@rushstack/m/1.0.0
name: '@rushstack/m'
- peerDependencyMeta: {}
- resolvedEntryJsonId: 10
- version: 1.0.0
- - dependencyType: regular
- entryId: /@rushstack/n/2.0.0
- name: '@rushstack/n'
- peerDependencyMeta: {}
- resolvedEntryJsonId: 11
- version: 2.0.0
- - dependencyType: peer
- entryId: 'Peer: @rushstack/m'
- name: '@rushstack/m'
+ originalSpecifier: ^1.0.0
peerDependencyMeta:
name: '@rushstack/m'
optional: false
- version: ^1.0.0
- version: ^1.0.0
- - dependencyType: peer
- entryId: 'Peer: @rushstack/n'
+ version: 1.0.0
+ versionPath: 1.0.0
+ - dependencyKind: peer
+ entryId: /@rushstack/n/2.0.0
name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
peerDependencyMeta:
name: '@rushstack/n'
optional: true
- version: ^2.0.0
- version: ^2.0.0
+ version: 2.0.0
+ versionPath: 2.0.0
displayText: '@rushstack/l 1.0.0 (wxpgugna4ivthu7yyu4fmciltu)'
- entryId: ''
+ entryId: /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu
entryPackageName: '@rushstack/l'
entryPackageVersion: 1.0.0
entrySuffix: wxpgugna4ivthu7yyu4fmciltu
@@ -272,7 +263,7 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
transitivePeerDependencies: []
- dependencies: []
displayText: '@rushstack/m 1.0.0'
- entryId: ''
+ entryId: /@rushstack/m/1.0.0
entryPackageName: '@rushstack/m'
entryPackageVersion: 1.0.0
entrySuffix: ''
@@ -283,12 +274,10 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
referrerJsonIds:
- 2
- 5
- - 8
- - 9
transitivePeerDependencies: []
- dependencies: []
displayText: '@rushstack/n 2.0.0'
- entryId: ''
+ entryId: /@rushstack/n/2.0.0
entryPackageName: '@rushstack/n'
entryPackageVersion: 2.0.0
entrySuffix: ''
@@ -299,11 +288,10 @@ exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = `
referrerJsonIds:
- 1
- 3
- - 9
transitivePeerDependencies: []
- dependencies: []
displayText: '@rushstack/n 3.0.0'
- entryId: ''
+ entryId: /@rushstack/n/3.0.0
entryPackageName: '@rushstack/n'
entryPackageVersion: 3.0.0
entrySuffix: ''
diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap
index 64f461236c5..f53e290cbcd 100644
--- a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap
+++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap
@@ -3,12 +3,13 @@
exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
"entries:
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/d
name: '@rushstack/d'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 3
- version: link:../d
+ versionPath: link:../d
displayText: 'Project: a'
entryId: project:projects/a
entryPackageName: a
@@ -21,18 +22,20 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/d
name: '@rushstack/d'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 3
- version: link:../d
- - dependencyType: regular
+ versionPath: link:../d
+ - dependencyKind: regular
entryId: /@rushstack/n@2.0.0
name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 9
- version: 2.0.0
+ versionPath: 2.0.0
displayText: 'Project: b'
entryId: project:projects/b
entryPackageName: b
@@ -45,24 +48,27 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/e
name: '@rushstack/e'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 4
- version: link:../e
- - dependencyType: regular
+ versionPath: link:../e
+ - dependencyKind: regular
entryId: /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
name: '@rushstack/k'
+ originalSpecifier: ^1.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 6
- version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
- - dependencyType: regular
+ versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ - dependencyKind: regular
entryId: /@rushstack/m@1.0.0
name: '@rushstack/m'
+ originalSpecifier: ~1.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 8
- version: 1.0.0
+ versionPath: 1.0.0
displayText: 'Project: c'
entryId: project:projects/c
entryPackageName: c
@@ -75,24 +81,27 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
referrerJsonIds: []
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: project:projects/e
name: '@rushstack/e'
+ originalSpecifier: workspace:*
peerDependencyMeta: {}
resolvedEntryJsonId: 4
- version: link:../e
- - dependencyType: regular
+ versionPath: link:../e
+ - dependencyKind: regular
entryId: /@rushstack/j@1.0.0(@rushstack/n@2.0.0)
name: '@rushstack/j'
+ originalSpecifier: ^1.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 5
- version: 1.0.0(@rushstack/n@2.0.0)
- - dependencyType: regular
+ versionPath: 1.0.0(@rushstack/n@2.0.0)
+ - dependencyKind: regular
entryId: /@rushstack/n@2.0.0
name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 9
- version: 2.0.0
+ versionPath: 2.0.0
displayText: 'Project: d'
entryId: project:projects/d
entryPackageName: d
@@ -107,12 +116,13 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
- 1
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /@rushstack/n@3.0.0
name: '@rushstack/n'
+ originalSpecifier: ^3.0.0
peerDependencyMeta: {}
resolvedEntryJsonId: 10
- version: 3.0.0
+ versionPath: 3.0.0
displayText: 'Project: e'
entryId: project:projects/e
entryPackageName: e
@@ -127,20 +137,22 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
- 3
transitivePeerDependencies: []
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
name: '@rushstack/k'
+ originalSpecifier: ''
peerDependencyMeta: {}
resolvedEntryJsonId: 6
- version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
- - dependencyType: regular
+ versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ - dependencyKind: regular
entryId: /@rushstack/m@1.0.0
name: '@rushstack/m'
+ originalSpecifier: ''
peerDependencyMeta: {}
resolvedEntryJsonId: 8
- version: 1.0.0
+ versionPath: 1.0.0
displayText: '@rushstack/j 1.0.0 [@rushstack/n@2.0.0]'
- entryId: ''
+ entryId: /@rushstack/j@1.0.0(@rushstack/n@2.0.0)
entryPackageName: '@rushstack/j'
entryPackageVersion: 1.0.0
entrySuffix: '@rushstack/n@2.0.0'
@@ -153,14 +165,15 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
transitivePeerDependencies:
- '@rushstack/n'
- dependencies:
- - dependencyType: regular
+ - dependencyKind: regular
entryId: /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
name: '@rushstack/l'
+ originalSpecifier: ''
peerDependencyMeta: {}
resolvedEntryJsonId: 7
- version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
displayText: '@rushstack/k 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]'
- entryId: ''
+ entryId: /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
entryPackageName: '@rushstack/k'
entryPackageVersion: 1.0.0
entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0'
@@ -176,36 +189,26 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
- '@rushstack/m'
- '@rushstack/n'
- dependencies:
- - dependencyType: regular
+ - dependencyKind: peer
entryId: /@rushstack/m@1.0.0
name: '@rushstack/m'
- peerDependencyMeta: {}
- resolvedEntryJsonId: 8
- version: 1.0.0
- - dependencyType: regular
- entryId: /@rushstack/n@2.0.0
- name: '@rushstack/n'
- peerDependencyMeta: {}
- resolvedEntryJsonId: 9
- version: 2.0.0
- - dependencyType: peer
- entryId: 'Peer: @rushstack/m'
- name: '@rushstack/m'
+ originalSpecifier: ^1.0.0
peerDependencyMeta:
name: '@rushstack/m'
optional: false
- version: ^1.0.0
- version: ^1.0.0
- - dependencyType: peer
- entryId: 'Peer: @rushstack/n'
+ version: 1.0.0
+ versionPath: 1.0.0
+ - dependencyKind: peer
+ entryId: /@rushstack/n@2.0.0
name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
peerDependencyMeta:
name: '@rushstack/n'
optional: true
- version: ^2.0.0
- version: ^2.0.0
+ version: 2.0.0
+ versionPath: 2.0.0
displayText: '@rushstack/l 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]'
- entryId: ''
+ entryId: /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
entryPackageName: '@rushstack/l'
entryPackageVersion: 1.0.0
entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0'
@@ -219,7 +222,7 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
transitivePeerDependencies: []
- dependencies: []
displayText: '@rushstack/m 1.0.0'
- entryId: ''
+ entryId: /@rushstack/m@1.0.0
entryPackageName: '@rushstack/m'
entryPackageVersion: 1.0.0
entrySuffix: ''
@@ -230,11 +233,10 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
referrerJsonIds:
- 2
- 5
- - 7
transitivePeerDependencies: []
- dependencies: []
displayText: '@rushstack/n 2.0.0'
- entryId: ''
+ entryId: /@rushstack/n@2.0.0
entryPackageName: '@rushstack/n'
entryPackageVersion: 2.0.0
entrySuffix: ''
@@ -245,11 +247,10 @@ exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = `
referrerJsonIds:
- 1
- 3
- - 7
transitivePeerDependencies: []
- dependencies: []
displayText: '@rushstack/n 3.0.0'
- entryId: ''
+ entryId: /@rushstack/n@3.0.0
entryPackageName: '@rushstack/n'
entryPackageVersion: 3.0.0
entrySuffix: ''
diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v9.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v9.0.test.ts.snap
new file mode 100644
index 00000000000..852a55ba2d2
--- /dev/null
+++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v9.0.test.ts.snap
@@ -0,0 +1,274 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`lfxGraph-website-sample-1-v9.0 loads a workspace 1`] = `
+"entries:
+ - dependencies:
+ - dependencyKind: regular
+ entryId: project:projects/d
+ name: '@rushstack/d'
+ originalSpecifier: workspace:*
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 3
+ versionPath: link:../d
+ displayText: 'Project: a'
+ entryId: project:projects/a
+ entryPackageName: a
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 0
+ kind: 1
+ packageJsonFolderPath: projects/a
+ rawEntryId: ../../projects/a
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: project:projects/d
+ name: '@rushstack/d'
+ originalSpecifier: workspace:*
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 3
+ versionPath: link:../d
+ - dependencyKind: regular
+ entryId: '@rushstack/n@2.0.0'
+ name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 9
+ versionPath: 2.0.0
+ displayText: 'Project: b'
+ entryId: project:projects/b
+ entryPackageName: b
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 1
+ kind: 1
+ packageJsonFolderPath: projects/b
+ rawEntryId: ../../projects/b
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: project:projects/e
+ name: '@rushstack/e'
+ originalSpecifier: workspace:*
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 4
+ versionPath: link:../e
+ - dependencyKind: regular
+ entryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)'
+ name: '@rushstack/k'
+ originalSpecifier: ^1.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 6
+ versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ - dependencyKind: regular
+ entryId: '@rushstack/m@1.0.0'
+ name: '@rushstack/m'
+ originalSpecifier: ~1.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 1.0.0
+ displayText: 'Project: c'
+ entryId: project:projects/c
+ entryPackageName: c
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 2
+ kind: 1
+ packageJsonFolderPath: projects/c
+ rawEntryId: ../../projects/c
+ referrerJsonIds: []
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: project:projects/e
+ name: '@rushstack/e'
+ originalSpecifier: workspace:*
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 4
+ versionPath: link:../e
+ - dependencyKind: regular
+ entryId: '@rushstack/j@1.0.0(@rushstack/n@2.0.0)'
+ name: '@rushstack/j'
+ originalSpecifier: ^1.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 5
+ versionPath: 1.0.0(@rushstack/n@2.0.0)
+ - dependencyKind: regular
+ entryId: '@rushstack/n@2.0.0'
+ name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 9
+ versionPath: 2.0.0
+ displayText: 'Project: d'
+ entryId: project:projects/d
+ entryPackageName: d
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 3
+ kind: 1
+ packageJsonFolderPath: projects/d
+ rawEntryId: ../../projects/d
+ referrerJsonIds:
+ - 0
+ - 1
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: '@rushstack/n@3.0.0'
+ name: '@rushstack/n'
+ originalSpecifier: ^3.0.0
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 10
+ versionPath: 3.0.0
+ displayText: 'Project: e'
+ entryId: project:projects/e
+ entryPackageName: e
+ entryPackageVersion: ''
+ entrySuffix: ''
+ jsonId: 4
+ kind: 1
+ packageJsonFolderPath: projects/e
+ rawEntryId: ../../projects/e
+ referrerJsonIds:
+ - 2
+ - 3
+ transitivePeerDependencies: []
+ - dependencies:
+ - dependencyKind: regular
+ entryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)'
+ name: '@rushstack/k'
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 6
+ versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ - dependencyKind: regular
+ entryId: '@rushstack/m@1.0.0'
+ name: '@rushstack/m'
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 8
+ versionPath: 1.0.0
+ displayText: '@rushstack/j 1.0.0 [@rushstack/n@2.0.0]'
+ entryId: '@rushstack/j@1.0.0(@rushstack/n@2.0.0)'
+ entryPackageName: '@rushstack/j'
+ entryPackageVersion: 1.0.0
+ entrySuffix: '@rushstack/n@2.0.0'
+ jsonId: 5
+ kind: 2
+ packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+j@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/j
+ rawEntryId: '@rushstack/j@1.0.0(@rushstack/n@2.0.0)'
+ referrerJsonIds:
+ - 3
+ transitivePeerDependencies:
+ - '@rushstack/n'
+ - dependencies:
+ - dependencyKind: regular
+ entryId: '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)'
+ name: '@rushstack/l'
+ originalSpecifier: ''
+ peerDependencyMeta: {}
+ resolvedEntryJsonId: 7
+ versionPath: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)
+ displayText: '@rushstack/k 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]'
+ entryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)'
+ entryPackageName: '@rushstack/k'
+ entryPackageVersion: 1.0.0
+ entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0'
+ jsonId: 6
+ kind: 2
+ packageJsonFolderPath: >-
+ common/temp/node_modules/.pnpm/@rushstack+k@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/k
+ rawEntryId: '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)'
+ referrerJsonIds:
+ - 2
+ - 5
+ transitivePeerDependencies:
+ - '@rushstack/m'
+ - '@rushstack/n'
+ - dependencies:
+ - dependencyKind: peer
+ entryId: '@rushstack/m@1.0.0'
+ name: '@rushstack/m'
+ originalSpecifier: ^1.0.0
+ peerDependencyMeta:
+ name: '@rushstack/m'
+ optional: false
+ version: 1.0.0
+ versionPath: 1.0.0
+ - dependencyKind: peer
+ entryId: '@rushstack/n@2.0.0'
+ name: '@rushstack/n'
+ originalSpecifier: ^2.0.0
+ peerDependencyMeta:
+ name: '@rushstack/n'
+ optional: true
+ version: 2.0.0
+ versionPath: 2.0.0
+ displayText: '@rushstack/l 1.0.0 [@rushstack/m@1.0.0; @rushstack/n@2.0.0]'
+ entryId: '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)'
+ entryPackageName: '@rushstack/l'
+ entryPackageVersion: 1.0.0
+ entrySuffix: '@rushstack/m@1.0.0; @rushstack/n@2.0.0'
+ jsonId: 7
+ kind: 2
+ packageJsonFolderPath: >-
+ common/temp/node_modules/.pnpm/@rushstack+l@1.0.0_@rushstack+m@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/l
+ rawEntryId: '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)'
+ referrerJsonIds:
+ - 6
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: '@rushstack/m 1.0.0'
+ entryId: '@rushstack/m@1.0.0'
+ entryPackageName: '@rushstack/m'
+ entryPackageVersion: 1.0.0
+ entrySuffix: ''
+ jsonId: 8
+ kind: 2
+ packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+m@1.0.0/node_modules/@rushstack/m
+ rawEntryId: '@rushstack/m@1.0.0'
+ referrerJsonIds:
+ - 2
+ - 5
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: '@rushstack/n 2.0.0'
+ entryId: '@rushstack/n@2.0.0'
+ entryPackageName: '@rushstack/n'
+ entryPackageVersion: 2.0.0
+ entrySuffix: ''
+ jsonId: 9
+ kind: 2
+ packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@2.0.0/node_modules/@rushstack/n
+ rawEntryId: '@rushstack/n@2.0.0'
+ referrerJsonIds:
+ - 1
+ - 3
+ transitivePeerDependencies: []
+ - dependencies: []
+ displayText: '@rushstack/n 3.0.0'
+ entryId: '@rushstack/n@3.0.0'
+ entryPackageName: '@rushstack/n'
+ entryPackageVersion: 3.0.0
+ entrySuffix: ''
+ jsonId: 10
+ kind: 2
+ packageJsonFolderPath: common/temp/node_modules/.pnpm/@rushstack+n@3.0.0/node_modules/@rushstack/n
+ rawEntryId: '@rushstack/n@3.0.0'
+ referrerJsonIds:
+ - 4
+ transitivePeerDependencies: []
+workspace:
+ pnpmLockfileFolder: common/temp
+ pnpmLockfilePath: common/temp/pnpm-lock.yaml
+ pnpmfilePath: common/temp/.pnpmfile.cjs
+ rushConfig:
+ rushPnpmfilePath: common/config/.pnpmcfile.cjs
+ rushVersion: 5.158.1
+ subspaceName: ''
+ workspaceRootFullPath: /repo
+"
+`;
diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/website-sample-1.md b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/edge-cases.md
similarity index 57%
rename from apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/website-sample-1.md
rename to apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/edge-cases.md
index ff328176fab..6e71f8e1492 100644
--- a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/website-sample-1.md
+++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/edge-cases.md
@@ -2,3 +2,6 @@
This test fixture is a PNPM workspace crafted to reproduce interesting edge cases in the `lfxGraphLoader` algorithm.
+The lockfiles were built from this repistory:
+
+https://github.com/octogonz/lockfile-explorer-edge-cases
diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v5.4.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v5.4.yaml
index 4bf1414f29b..73c960a6c85 100644
--- a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v5.4.yaml
+++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v5.4.yaml
@@ -1,27 +1,52 @@
lockfileVersion: 5.4
importers:
- duplicate-1/duplicate:
+ packages/dev-dependencies:
+ specifiers:
+ color-string: ^2.1.2
+ mime-db: ^1.52.0
+ optionalDependencies:
+ mime-db: 1.54.0
+ devDependencies:
+ color-string: 2.1.2
+
+ packages/duplicate-1/duplicate:
specifiers:
color: ^5.0.2
dependencies:
color: 5.0.2
- duplicate-2/duplicate:
+ packages/duplicate-2/duplicate:
specifiers:
color-string: ^2.1.2
dependencies:
color-string: 2.1.2
- link-specifier/linker:
+ packages/link-specifier/linker:
specifiers:
has-symbols: 1.0.2
- target-folder: link:../target-folder
+ target-folder: link:packages/link-specifier/target-folder
dependencies:
has-symbols: 1.0.2
- target-folder: link:../target-folder
+ target-folder: link:packages/link-specifier/target-folder
+
+ packages/pnpmfile-transforms:
+ specifiers:
+ address: ^1.0.0
+ uri-js: ^4.0.0
+ dependencies:
+ address: 1.2.2
+ uri-js: 4.4.1
packages:
+ /address/1.2.2:
+ resolution:
+ {
+ integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==
+ }
+ engines: { node: '>= 10.0.0' }
+ dev: false
+
/color-convert/3.1.2:
resolution:
{
@@ -38,7 +63,6 @@ packages:
integrity: sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A==
}
engines: { node: '>=12.20' }
- dev: false
/color-string/2.1.2:
resolution:
@@ -48,7 +72,6 @@ packages:
engines: { node: '>=18' }
dependencies:
color-name: 2.0.2
- dev: false
/color/5.0.2:
resolution:
@@ -70,3 +93,30 @@ packages:
dependencies:
target-folder: link:link-specifier/target-folder
dev: false
+
+ /mime-db/1.54.0:
+ resolution:
+ {
+ integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+ }
+ engines: { node: '>= 0.6' }
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /punycode/2.3.1:
+ resolution:
+ {
+ integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+ }
+ engines: { node: '>=6' }
+ dev: false
+
+ /uri-js/4.4.1:
+ resolution:
+ {
+ integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ }
+ dependencies:
+ punycode: 2.3.1
+ dev: false
diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v6.0.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v6.0.yaml
index 47d4bd09ffe..97159b9ae54 100644
--- a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v6.0.yaml
+++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v6.0.yaml
@@ -5,28 +5,55 @@ settings:
excludeLinksFromLockfile: false
importers:
- duplicate-1/duplicate:
+ packages/dev-dependencies:
+ optionalDependencies:
+ mime-db:
+ specifier: ^1.52.0
+ version: 1.54.0
+ devDependencies:
+ color-string:
+ specifier: ^2.1.2
+ version: 2.1.2
+
+ packages/duplicate-1/duplicate:
dependencies:
color:
specifier: ^5.0.2
version: 5.0.2
- duplicate-2/duplicate:
+ packages/duplicate-2/duplicate:
dependencies:
color-string:
specifier: ^2.1.2
version: 2.1.2
- link-specifier/linker:
+ packages/link-specifier/linker:
dependencies:
has-symbols:
specifier: 1.0.2
version: 1.0.2
target-folder:
- specifier: link:../target-folder
- version: link:../target-folder
+ specifier: link:packages/link-specifier/target-folder
+ version: link:packages/link-specifier/target-folder
+
+ packages/pnpmfile-transforms:
+ dependencies:
+ address:
+ specifier: ^1.0.0
+ version: 1.2.2
+ uri-js:
+ specifier: ^4.0.0
+ version: 4.4.1
packages:
+ /address@1.2.2:
+ resolution:
+ {
+ integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==
+ }
+ engines: { node: '>= 10.0.0' }
+ dev: false
+
/color-convert@3.1.2:
resolution:
{
@@ -43,7 +70,6 @@ packages:
integrity: sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A==
}
engines: { node: '>=12.20' }
- dev: false
/color-string@2.1.2:
resolution:
@@ -53,7 +79,6 @@ packages:
engines: { node: '>=18' }
dependencies:
color-name: 2.0.2
- dev: false
/color@5.0.2:
resolution:
@@ -75,3 +100,30 @@ packages:
dependencies:
target-folder: link:link-specifier/target-folder
dev: false
+
+ /mime-db@1.54.0:
+ resolution:
+ {
+ integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+ }
+ engines: { node: '>= 0.6' }
+ requiresBuild: true
+ dev: false
+ optional: true
+
+ /punycode@2.3.1:
+ resolution:
+ {
+ integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+ }
+ engines: { node: '>=6' }
+ dev: false
+
+ /uri-js@4.4.1:
+ resolution:
+ {
+ integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ }
+ dependencies:
+ punycode: 2.3.1
+ dev: false
diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v9.0.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v9.0.yaml
new file mode 100644
index 00000000000..291e25e638d
--- /dev/null
+++ b/apps/lockfile-explorer/src/graph/test/fixtures/edge-cases/pnpm-lock-v9.0.yaml
@@ -0,0 +1,142 @@
+lockfileVersion: '9.0'
+
+settings:
+ autoInstallPeers: true
+ excludeLinksFromLockfile: false
+
+pnpmfileChecksum: sha256-tednqUPPat9y98NmpwR8320vxu2TlSor2aoYTxiNCdU=
+
+importers:
+ packages/dev-dependencies:
+ devDependencies:
+ color-string:
+ specifier: ^2.1.2
+ version: 2.1.2
+ optionalDependencies:
+ mime-db:
+ specifier: ^1.52.0
+ version: 1.54.0
+
+ packages/duplicate-1/duplicate:
+ dependencies:
+ color:
+ specifier: ^5.0.2
+ version: 5.0.2
+
+ packages/duplicate-2/duplicate:
+ dependencies:
+ color-string:
+ specifier: ^2.1.2
+ version: 2.1.2
+
+ packages/link-specifier/linker:
+ dependencies:
+ has-symbols:
+ specifier: 1.0.2
+ version: 1.0.2
+ target-folder:
+ specifier: link:packages/link-specifier/target-folder
+ version: link:packages/link-specifier/target-folder
+
+ packages/pnpmfile-transforms:
+ dependencies:
+ address:
+ specifier: ^1.0.0
+ version: 1.2.2
+ uri-js:
+ specifier: ^4.0.0
+ version: 4.4.1
+
+packages:
+ address@1.2.2:
+ resolution:
+ {
+ integrity: sha512-4B/qKCfeE/ODUaAUpSwfzazo5x29WD4r3vXiWsB7I2mSDAihwEqKO+g8GELZUQSSAo5e1XTYh3ZVfLyxBc12nA==
+ }
+ engines: { node: '>= 10.0.0' }
+
+ color-convert@3.1.2:
+ resolution:
+ {
+ integrity: sha512-UNqkvCDXstVck3kdowtOTWROIJQwafjOfXSmddoDrXo4cewMKmusCeF22Q24zvjR8nwWib/3S/dfyzPItPEiJg==
+ }
+ engines: { node: '>=14.6' }
+
+ color-name@2.0.2:
+ resolution:
+ {
+ integrity: sha512-9vEt7gE16EW7Eu7pvZnR0abW9z6ufzhXxGXZEVU9IqPdlsUiMwJeJfRtq0zePUmnbHGT9zajca7mX8zgoayo4A==
+ }
+ engines: { node: '>=12.20' }
+
+ color-string@2.1.2:
+ resolution:
+ {
+ integrity: sha512-RxmjYxbWemV9gKu4zPgiZagUxbH3RQpEIO77XoSSX0ivgABDZ+h8Zuash/EMFLTI4N9QgFPOJ6JQpPZKFxa+dA==
+ }
+ engines: { node: '>=18' }
+
+ color@5.0.2:
+ resolution:
+ {
+ integrity: sha512-e2hz5BzbUPcYlIRHo8ieAhYgoajrJr+hWoceg6E345TPsATMUKqDgzt8fSXZJJbxfpiPzkWyphz8yn8At7q3fA==
+ }
+ engines: { node: '>=18' }
+
+ has-symbols@1.0.2:
+ resolution:
+ {
+ integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
+ }
+ engines: { node: '>= 0.4' }
+
+ mime-db@1.54.0:
+ resolution:
+ {
+ integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==
+ }
+ engines: { node: '>= 0.6' }
+
+ punycode@2.3.1:
+ resolution:
+ {
+ integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==
+ }
+ engines: { node: '>=6' }
+
+ uri-js@4.4.1:
+ resolution:
+ {
+ integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
+ }
+
+snapshots:
+ address@1.2.2: {}
+
+ color-convert@3.1.2:
+ dependencies:
+ color-name: 2.0.2
+
+ color-name@2.0.2: {}
+
+ color-string@2.1.2:
+ dependencies:
+ color-name: 2.0.2
+
+ color@5.0.2:
+ dependencies:
+ color-convert: 3.1.2
+ color-string: 2.1.2
+
+ has-symbols@1.0.2:
+ dependencies:
+ target-folder: link:link-specifier/target-folder
+
+ mime-db@1.54.0:
+ optional: true
+
+ punycode@2.3.1: {}
+
+ uri-js@4.4.1:
+ dependencies:
+ punycode: 2.3.1
diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-pnpm.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-rush.yaml
similarity index 93%
rename from apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-pnpm.yaml
rename to apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-rush.yaml
index 60de289e509..3318a2a7837 100644
--- a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-pnpm.yaml
+++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-rush.yaml
@@ -1,19 +1,21 @@
lockfileVersion: '9.0'
settings:
- autoInstallPeers: true
+ autoInstallPeers: false
excludeLinksFromLockfile: false
-pnpmfileChecksum: sha256-6Cq2BFB3826lbTciEnsPowoZ1qvFZeM4wkoGwobxneY=
+pnpmfileChecksum: sha256-La8sfCMI7irxJPTW6u4mJb4vNiyLrXeEbKaXv5G3dL0=
importers:
- projects/a:
+ .: {}
+
+ ../../projects/a:
dependencies:
'@rushstack/d':
specifier: workspace:*
version: link:../d
- projects/b:
+ ../../projects/b:
dependencies:
'@rushstack/d':
specifier: workspace:*
@@ -22,7 +24,7 @@ importers:
specifier: ^2.0.0
version: 2.0.0
- projects/c:
+ ../../projects/c:
dependencies:
'@rushstack/e':
specifier: workspace:*
@@ -34,7 +36,7 @@ importers:
specifier: ~1.0.0
version: 1.0.0
- projects/d:
+ ../../projects/d:
dependencies:
'@rushstack/e':
specifier: workspace:*
@@ -46,7 +48,7 @@ importers:
specifier: ^2.0.0
version: 2.0.0
- projects/e:
+ ../../projects/e:
dependencies:
'@rushstack/n':
specifier: ^3.0.0
diff --git a/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts b/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts
index 74d99eb35de..b96b140669c 100644
--- a/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts
+++ b/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts
@@ -15,7 +15,7 @@ import * as lfxGraphLoader from '../lfxGraphLoader';
const FIXTURES_FOLDER: string = path.resolve(__dirname, '../../../src/graph/test/fixtures/');
-export async function loadAndSerializeLFxGraphAsync(options: {
+export async function loadAndSerializeLfxGraphAsync(options: {
workspace: IJsonLfxWorkspace;
lockfilePathUnderFixtures: string;
}): Promise {
diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v5.4.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v5.4.test.ts
index 2aa4a13c230..be8ce686c4a 100644
--- a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v5.4.test.ts
+++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v5.4.test.ts
@@ -15,7 +15,7 @@ export const workspace: IJsonLfxWorkspace = {
describe('lfxGraph-edge-cases-v5.4', () => {
it('loads a workspace', async () => {
- const serializedYaml: string = await graphTestHelpers.loadAndSerializeLFxGraphAsync({
+ const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({
lockfilePathUnderFixtures: '/edge-cases/pnpm-lock-v5.4.yaml',
workspace: workspace
});
diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v6.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v6.0.test.ts
index 2aa4a13c230..06ed7a48b0a 100644
--- a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v6.0.test.ts
+++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v6.0.test.ts
@@ -13,10 +13,10 @@ export const workspace: IJsonLfxWorkspace = {
rushConfig: undefined
};
-describe('lfxGraph-edge-cases-v5.4', () => {
+describe('lfxGraph-edge-cases-v6.0', () => {
it('loads a workspace', async () => {
- const serializedYaml: string = await graphTestHelpers.loadAndSerializeLFxGraphAsync({
- lockfilePathUnderFixtures: '/edge-cases/pnpm-lock-v5.4.yaml',
+ const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({
+ lockfilePathUnderFixtures: '/edge-cases/pnpm-lock-v6.0.yaml',
workspace: workspace
});
expect(serializedYaml).toMatchSnapshot();
diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v9.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v9.0.test.ts
new file mode 100644
index 00000000000..2e27262e8c9
--- /dev/null
+++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-edge-cases-v9.0.test.ts
@@ -0,0 +1,24 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+
+import type { IJsonLfxWorkspace } from '../../../build/lfx-shared';
+
+import * as graphTestHelpers from './graphTestHelpers';
+
+export const workspace: IJsonLfxWorkspace = {
+ workspaceRootFullPath: '/repo',
+ pnpmLockfilePath: 'pnpm-lock.yaml',
+ pnpmLockfileFolder: '',
+ pnpmfilePath: '.pnpmfile.cjs',
+ rushConfig: undefined
+};
+
+describe('lfxGraph-edge-cases-v9.0', () => {
+ it('loads a workspace', async () => {
+ const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({
+ lockfilePathUnderFixtures: '/edge-cases/pnpm-lock-v9.0.yaml',
+ workspace: workspace
+ });
+ expect(serializedYaml).toMatchSnapshot();
+ });
+});
diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts
index 7c74129e631..874661d6d19 100644
--- a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts
+++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts
@@ -19,7 +19,7 @@ export const workspace: IJsonLfxWorkspace = {
describe('lfxGraph-website-sample-1-v5.4', () => {
it('loads a workspace', async () => {
- const serializedYaml: string = await graphTestHelpers.loadAndSerializeLFxGraphAsync({
+ const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({
lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v5.4-rush.yaml',
workspace: workspace
});
diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts
index 0cf7e0c2c25..12503e64921 100644
--- a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts
+++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts
@@ -19,7 +19,7 @@ export const workspace: IJsonLfxWorkspace = {
describe('lfxGraph-website-sample-1-v6.0', () => {
it('loads a workspace', async () => {
- const serializedYaml: string = await graphTestHelpers.loadAndSerializeLFxGraphAsync({
+ const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({
lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v6.0-rush.yaml',
workspace: workspace
});
diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v9.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v9.0.test.ts
new file mode 100644
index 00000000000..70986c66c8e
--- /dev/null
+++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v9.0.test.ts
@@ -0,0 +1,30 @@
+// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
+// See LICENSE in the project root for license information.
+
+import type { IJsonLfxWorkspace } from '../../../build/lfx-shared';
+
+import * as graphTestHelpers from './graphTestHelpers';
+
+export const workspace: IJsonLfxWorkspace = {
+ workspaceRootFullPath: '/repo',
+ pnpmLockfilePath: 'common/temp/pnpm-lock.yaml',
+ pnpmLockfileFolder: 'common/temp',
+ pnpmfilePath: 'common/temp/.pnpmfile.cjs',
+ rushConfig: {
+ rushVersion: '5.158.1',
+ subspaceName: '',
+ rushPnpmfilePath: 'common/config/.pnpmcfile.cjs'
+ }
+};
+
+describe('lfxGraph-website-sample-1-v9.0', () => {
+ it('loads a workspace', async () => {
+ const serializedYaml: string = await graphTestHelpers.loadAndSerializeLfxGraphAsync({
+ // NOTE: Rush does not yet support v9.0; this file was generated by invoking the PNPM CLI manually
+ // under the common/temp folder.
+ lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v9.0-rush.yaml',
+ workspace: workspace
+ });
+ expect(serializedYaml).toMatchSnapshot();
+ });
+});
diff --git a/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts b/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts
index d05769f2e81..a6be195f847 100644
--- a/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts
+++ b/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts
@@ -16,28 +16,30 @@ Object {
Object {
"dependencies": Array [
Object {
- "dependencyType": "regular",
+ "dependencyKind": "regular",
"entryId": "/@testPackage/core/1.7.1",
"name": "@testPackage/core",
+ "originalSpecifier": "1.7.1",
"peerDependencyMeta": Object {
"name": undefined,
"optional": undefined,
"version": undefined,
},
"resolvedEntryJsonId": 1,
- "version": "1.7.1",
+ "versionPath": "1.7.1",
},
Object {
- "dependencyType": "regular",
+ "dependencyKind": "regular",
"entryId": "/@testPackage2/core/1.7.1",
"name": "@testPackage2/core",
+ "originalSpecifier": "1.7.1",
"peerDependencyMeta": Object {
"name": undefined,
"optional": undefined,
"version": undefined,
},
"resolvedEntryJsonId": 2,
- "version": "1.7.1",
+ "versionPath": "1.7.1",
},
],
"displayText": "Project: testApp1",
@@ -55,7 +57,7 @@ Object {
Object {
"dependencies": Array [],
"displayText": "@testPackage/core 1.7.1",
- "entryId": "",
+ "entryId": "/@testPackage/core/1.7.1",
"entryPackageName": "@testPackage/core",
"entryPackageVersion": "1.7.1",
"entrySuffix": "",
@@ -71,7 +73,7 @@ Object {
Object {
"dependencies": Array [],
"displayText": "@testPackage2/core 1.7.1",
- "entryId": "",
+ "entryId": "/@testPackage2/core/1.7.1",
"entryPackageName": "@testPackage2/core",
"entryPackageVersion": "1.7.1",
"entrySuffix": "",
diff --git a/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-pnpm-10_2025-10-03-05-47.json b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-pnpm-10_2025-10-03-05-47.json
new file mode 100644
index 00000000000..6f4e68f2202
--- /dev/null
+++ b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-pnpm-10_2025-10-03-05-47.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@rushstack/lockfile-explorer",
+ "comment": "Add support for PNPM 10 lockfile format",
+ "type": "major"
+ }
+ ],
+ "packageName": "@rushstack/lockfile-explorer"
+}
\ No newline at end of file
diff --git a/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-pnpm-10_2025-10-03-05-48.json b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-pnpm-10_2025-10-03-05-48.json
new file mode 100644
index 00000000000..793df66a889
--- /dev/null
+++ b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-pnpm-10_2025-10-03-05-48.json
@@ -0,0 +1,10 @@
+{
+ "changes": [
+ {
+ "packageName": "@rushstack/lockfile-explorer",
+ "comment": "Numerous improvements to the lockfile parser",
+ "type": "patch"
+ }
+ ],
+ "packageName": "@rushstack/lockfile-explorer"
+}
\ No newline at end of file