diff --git a/apps/lockfile-explorer-web/package.json b/apps/lockfile-explorer-web/package.json index d9c76c4bca2..c6445b31fb0 100644 --- a/apps/lockfile-explorer-web/package.json +++ b/apps/lockfile-explorer-web/package.json @@ -12,19 +12,21 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "react": "~17.0.2", - "react-dom": "~17.0.2", "@lifaon/path": "~2.1.0", "@reduxjs/toolkit": "~1.8.6", + "@rushstack/rush-themed-ui": "workspace:*", + "react-dom": "~17.0.2", "react-redux": "~8.0.4", + "react": "~17.0.2", "redux": "~4.2.0", - "@rushstack/rush-themed-ui": "workspace:*" + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", "@types/react": "17.0.74", "@types/react-dom": "17.0.25", "eslint": "~9.25.1", - "local-web-rig": "workspace:*" + "local-web-rig": "workspace:*", + "typescript": "5.8.2" } } diff --git a/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx index d7e1d963bdf..9a29a13d849 100644 --- a/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx +++ b/apps/lockfile-explorer-web/src/components/ConnectionModal/index.tsx @@ -5,7 +5,7 @@ import React, { useCallback, useEffect, useState } from 'react'; import { Button, Text } from '@rushstack/rush-themed-ui'; import styles from './styles.scss'; import appStyles from '../../App.scss'; -import { checkAliveAsync } from '../../parsing/getPackageFiles'; +import { checkAliveAsync } from '../../helpers/lfxApiClient'; import type { ReactNull } from '../../types/ReactNull'; export const ConnectionModal = (): JSX.Element | ReactNull => { diff --git a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx index 28a2ac8eaff..3603d4dd56c 100644 --- a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx @@ -5,7 +5,7 @@ import React, { useCallback } from 'react'; import appStyles from '../../App.scss'; import styles from './styles.scss'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; -import type { LockfileEntry } from '../../parsing/LockfileEntry'; +import type { LockfileEntry } from '../../parsing/LfxGraph'; import { clearStackAndPush, removeBookmark } from '../../store/slices/entrySlice'; import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; diff --git a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx index 277edde9e61..8e9b9b83b81 100644 --- a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx @@ -5,12 +5,12 @@ import React, { useCallback, useEffect, useState } from 'react'; import { ScrollArea, Text } from '@rushstack/rush-themed-ui'; import styles from './styles.scss'; import appStyles from '../../App.scss'; -import { IDependencyType, type LockfileDependency } from '../../parsing/LockfileDependency'; -import { readPackageJsonAsync } from '../../parsing/getPackageFiles'; +import { DependencyKind, type LockfileDependency } from '../../parsing/LfxGraph'; +import { readPackageJsonAsync } from '../../helpers/lfxApiClient'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { pushToStack, selectCurrentEntry } from '../../store/slices/entrySlice'; import { ReactNull } from '../../types/ReactNull'; -import type { LockfileEntry } from '../../parsing/LockfileEntry'; +import type { LockfileEntry } from '../../parsing/LfxGraph'; import { logDiagnosticInfo } from '../../helpers/logDiagnosticInfo'; import { displaySpecChanges } from '../../helpers/displaySpecChanges'; import type { IPackageJson } from '../../types/IPackageJson'; @@ -80,7 +80,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { // Check if we need to calculate influencers. // If the current dependencyToTrace is a peer dependency then we do - if (dependencyToTrace.dependencyType !== IDependencyType.PEER_DEPENDENCY) { + if (dependencyToTrace.dependencyType !== DependencyKind.PEER_DEPENDENCY) { return; } @@ -179,7 +179,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { package.json spec:{' '} - {inspectDependency.dependencyType === IDependencyType.PEER_DEPENDENCY + {inspectDependency.dependencyType === DependencyKind.PEER_DEPENDENCY ? `"${inspectDependency.peerDependencyMeta.version}" ${ inspectDependency.peerDependencyMeta.optional ? 'Optional' : 'Required' } Peer` @@ -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 === IDependencyType.PEER_DEPENDENCY + (d) => d.dependencyType === DependencyKind.PEER_DEPENDENCY ); if (!peerDeps.length) { return ( @@ -213,7 +213,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { ); } - if (!inspectDependency || inspectDependency.dependencyType !== IDependencyType.PEER_DEPENDENCY) { + if (!inspectDependency || inspectDependency.dependencyType !== DependencyKind.PEER_DEPENDENCY) { return (
Select a peer dependency to view its influencers @@ -338,7 +338,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { > Name: {dependency.name}{' '} - {dependency.dependencyType === IDependencyType.PEER_DEPENDENCY + {dependency.dependencyType === DependencyKind.PEER_DEPENDENCY ? `${ dependency.peerDependencyMeta.optional ? '(Optional)' : '(Non-optional)' } Peer Dependency` diff --git a/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx index 05bc7b2ce8d..17176f29f48 100644 --- a/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LockfileViewer/index.tsx @@ -3,7 +3,7 @@ import React, { useCallback, useEffect, useRef, useState } from 'react'; import styles from './styles.scss'; -import { type LockfileEntry, LockfileEntryFilter } from '../../parsing/LockfileEntry'; +import { type LockfileEntry, LockfileEntryFilter } from '../../parsing/LfxGraph'; import { ReactNull } from '../../types/ReactNull'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { @@ -120,7 +120,7 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(packageFilter) !== -1); } - const reducedEntries = filteredEntries.reduce((groups: { [key in string]: LockfileEntry[] }, item) => { + const reducedEntries = filteredEntries.reduce((groups: { [key: string]: LockfileEntry[] }, item) => { const group = groups[item.entryPackageName] || []; group.push(item); groups[item.entryPackageName] = group; diff --git a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx index d7bdd1ad267..071a3f20a8d 100644 --- a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import React, { useCallback, useEffect, useState } from 'react'; -import { readPnpmfileAsync, readPackageSpecAsync, readPackageJsonAsync } from '../../parsing/getPackageFiles'; +import { readPnpmfileAsync, readPackageSpecAsync, readPackageJsonAsync } from '../../helpers/lfxApiClient'; import styles from './styles.scss'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { selectCurrentEntry } from '../../store/slices/entrySlice'; @@ -12,9 +12,9 @@ import { loadSpecChanges } from '../../store/slices/workspaceSlice'; import { displaySpecChanges } from '../../helpers/displaySpecChanges'; import { isEntryModified } from '../../helpers/isEntryModified'; import { ScrollArea, Tabs, Text } from '@rushstack/rush-themed-ui'; -import { LockfileEntryFilter } from '../../parsing/LockfileEntry'; +import { LockfileEntryFilter } from '../../parsing/LfxGraph'; -const PackageView: { [key in string]: string } = { +const PackageView: { [key: string]: string } = { PACKAGE_JSON: 'PACKAGE_JSON', PACKAGE_SPEC: 'PACKAGE_SPEC', PARSED_PACKAGE_JSON: 'PARSED_PACKAGE_JSON' diff --git a/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts b/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts index 30c38e0830a..53cdff9e4c4 100644 --- a/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts +++ b/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import type { ISpecChange } from '../parsing/compareSpec'; -import type { LockfileEntry } from '../parsing/LockfileEntry'; +import type { LockfileEntry } from '../parsing/LfxGraph'; export const isEntryModified = ( entry: LockfileEntry | undefined, diff --git a/apps/lockfile-explorer-web/src/parsing/getPackageFiles.ts b/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts similarity index 55% rename from apps/lockfile-explorer-web/src/parsing/getPackageFiles.ts rename to apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts index 81283b33548..14d694c9785 100644 --- a/apps/lockfile-explorer-web/src/parsing/getPackageFiles.ts +++ b/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts @@ -2,18 +2,47 @@ // See LICENSE in the project root for license information. import type { IPackageJson } from '../types/IPackageJson'; +import type { ILfxWorkspace } from '../types/lfxProtocol'; -const apiPath: string = `${window.appContext.serviceUrl}/api`; +const SERVICE_URL: string = window.appContext.serviceUrl; export async function checkAliveAsync(): Promise { try { - await fetch(`${apiPath}/health`); + await fetch(`${SERVICE_URL}/api/health`); return true; } catch (e) { return false; } } +/** + * Read the contents of a text file under the workspace directory. + * @param relativePath - a file path that is relative to the working directory. + */ +export async function readWorkspaceConfigAsync(): Promise { + let response: Response; + + try { + response = await fetch(`${SERVICE_URL}/api/workspace`); + if (!response.ok) { + const responseText: string = await response.text(); + const error = new Error( + 'The operation failed: ' + (responseText.trim() || 'An unknown error occurred') + ); + // eslint-disable-next-line no-console + console.error('readWorkspaceConfigAsync() failed: ', error); + throw error; + } + } catch (e) { + // eslint-disable-next-line no-console + console.error('Network error in readWorkspaceConfigAsync(): ', e); + throw new Error('Network error: ' + (e.message || 'An unknown error occurred')); + } + + const responseJson: ILfxWorkspace = await response.json(); + return responseJson; +} + /** * Fetches a projects configuration files from the local file system * @@ -21,7 +50,7 @@ export async function checkAliveAsync(): Promise { */ export async function readPnpmfileAsync(): Promise { try { - const response = await fetch(`${apiPath}/pnpmfile`); + const response = await fetch(`${SERVICE_URL}/api/pnpmfile`); return await response.text(); } catch (e) { // eslint-disable-next-line no-console @@ -32,7 +61,7 @@ export async function readPnpmfileAsync(): Promise { export async function readPackageJsonAsync(projectPath: string): Promise { try { - const response = await fetch(`${apiPath}/package-json`, { + const response = await fetch(`${SERVICE_URL}/api/package-json`, { method: 'POST', headers: { 'Content-Type': 'application/json' @@ -51,7 +80,7 @@ export async function readPackageJsonAsync(projectPath: string): Promise { try { - const response = await fetch(`${apiPath}/package-spec`, { + const response = await fetch(`${SERVICE_URL}/api/package-spec`, { method: 'POST', headers: { 'Content-Type': 'application/json' diff --git a/apps/lockfile-explorer-web/src/helpers/localStorage.ts b/apps/lockfile-explorer-web/src/helpers/localStorage.ts index dadcc500ef8..77d703d859f 100644 --- a/apps/lockfile-explorer-web/src/helpers/localStorage.ts +++ b/apps/lockfile-explorer-web/src/helpers/localStorage.ts @@ -1,7 +1,7 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { type LockfileEntry, LockfileEntryFilter } from '../parsing/LockfileEntry'; +import { type LockfileEntry, LockfileEntryFilter } from '../parsing/LfxGraph'; const BOOKMARK_KEY: string = 'LOCKFILE_EXPLORER_BOOKMARKS'; diff --git a/apps/lockfile-explorer-web/src/parsing/JsonLfxGraph.ts b/apps/lockfile-explorer-web/src/parsing/JsonLfxGraph.ts new file mode 100644 index 00000000000..4bb82873b36 --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/JsonLfxGraph.ts @@ -0,0 +1,50 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { DependencyKind, LockfileEntryFilter } from './LfxGraph'; + +export interface IJsonPeerDependencyMeta { + name?: string; + version?: string; + optional?: boolean; +} + +export interface IJsonLfxDependency { + name: string; + version: string; + entryId: string; + dependencyType: DependencyKind; + + resolvedEntryJsonId?: number; + + peerDependencyMeta: IJsonPeerDependencyMeta; +} + +export interface IJsonLfxEntry { + /** + * A unique ID used when serializing graph links. + * + * @remarks + * This is just the `IJsonLfxGraph.entries` array index, but debugging is easier if we include + * it in the serialized representation. + */ + jsonId: number; + + kind: LockfileEntryFilter; + entryId: string; + rawEntryId: string; + packageJsonFolderPath: string; + entryPackageName: string; + displayText: string; + entryPackageVersion: string; + entrySuffix: string; + + // Lists + dependencies: IJsonLfxDependency[]; + transitivePeerDependencies: string[]; + referrerJsonIds: number[]; +} + +export interface IJsonLfxGraph { + entries: IJsonLfxEntry[]; +} diff --git a/apps/lockfile-explorer-web/src/parsing/LfxGraph.ts b/apps/lockfile-explorer-web/src/parsing/LfxGraph.ts new file mode 100644 index 00000000000..8cbfd4ee7ea --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/LfxGraph.ts @@ -0,0 +1,141 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IJsonPeerDependencyMeta } from './JsonLfxGraph'; + +export enum DependencyKind { + DEPENDENCY = 'regular', + DEV_DEPENDENCY = 'dev', + PEER_DEPENDENCY = 'peer' +} + +export interface ILockfileDependencyOptions { + name: string; + version: string; + dependencyType: DependencyKind; + containingEntry: LockfileEntry; + peerDependencyMeta: IJsonPeerDependencyMeta; + entryId: string; +} + +/** + * 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. + */ +export class LockfileDependency { + public readonly name: string; + public readonly version: string; + public readonly dependencyType: DependencyKind; + public readonly containingEntry: LockfileEntry; + public readonly entryId: string; + public readonly peerDependencyMeta: IJsonPeerDependencyMeta; + + public resolvedEntry: LockfileEntry | undefined = undefined; + + public constructor(options: ILockfileDependencyOptions) { + this.name = options.name; + this.version = options.version; + this.dependencyType = options.dependencyType; + this.containingEntry = options.containingEntry; + this.entryId = options.entryId; + this.peerDependencyMeta = options.peerDependencyMeta; + } +} + +export enum LockfileEntryFilter { + Project = 1, + Package = 2, + SideBySide = 3, + Doppelganger = 4 +} + +export interface ILockfileEntryOptions { + kind: LockfileEntryFilter; + entryId: string; + rawEntryId: string; + packageJsonFolderPath: string; + entryPackageName: string; + displayText: string; + entryPackageVersion: string; + entrySuffix: string; +} + +/** + * Represents a project or package listed in the pnpm lockfile. + * + * @remarks + * Each project or package will have its own LockfileEntry, which is created when the lockfile is first parsed. + * The fields for the LockfileEntry are outlined below: + */ +export class LockfileEntry { + /** + * Whether this entry is a project or a package (specified by importers or packages in the lockfile). + */ + public readonly kind: LockfileEntryFilter; + + /** + * A unique (human-readable) identifier for this lockfile entry. For projects, this is just + * `Project:` + the package json path for this project. + */ + public readonly entryId: string; + + /** + * The unique identifier assigned to this project/package in the lockfile. + * e.g. `/@emotion/core/10.3.1_qjwx5m6wssz3lnb35xwkc3pz6q:` + */ + public readonly rawEntryId: string; + + /** + * Where the package.json is for this project or package. + */ + public readonly packageJsonFolderPath: string; + + /** + * Just the name of the package with no specifiers. + */ + public readonly entryPackageName: string; + + /** + * A human friendly name for the project or package. + */ + public readonly displayText: string; + + public readonly entryPackageVersion: string; + public readonly entrySuffix: string; + + /** + * A list of all the dependencies for this entry. + * Note that dependencies, dev dependencies, as well as peer dependencies are all included. + */ + public readonly dependencies: LockfileDependency[] = []; + + /** + * A list of dependencies that are listed under the "transitivePeerDependencies" in the pnpm lockfile. + */ + public readonly transitivePeerDependencies: Set = new Set(); + + /** + * A list of entries that specify this entry as a dependency. + */ + public readonly referrers: LockfileEntry[] = []; + + public constructor(options: ILockfileEntryOptions) { + this.kind = options.kind; + this.entryId = options.entryId; + this.rawEntryId = options.rawEntryId; + this.packageJsonFolderPath = options.packageJsonFolderPath; + this.entryPackageName = options.entryPackageName; + this.displayText = options.displayText; + this.entryPackageVersion = options.entryPackageVersion; + this.entrySuffix = options.entrySuffix; + } +} + +export class LfxGraph { + public readonly entries: LockfileEntry[] = []; +} diff --git a/apps/lockfile-explorer-web/src/parsing/LockfileDependency.ts b/apps/lockfile-explorer-web/src/parsing/LockfileDependency.ts deleted file mode 100644 index 4ece5b79c49..00000000000 --- a/apps/lockfile-explorer-web/src/parsing/LockfileDependency.ts +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { Path } from '@lifaon/path'; -import type { LockfileEntry } from './LockfileEntry'; - -export interface ILockfileNode { - dependencies?: { - [key in string]: string; - }; - devDependencies?: { - [key in string]: string; - }; - peerDependencies?: { - [key in string]: string; - }; - peerDependenciesMeta?: { - [key in string]: { - optional: boolean; - }; - }; - transitivePeerDependencies?: string[]; -} - -export enum IDependencyType { - DEPENDENCY, - DEV_DEPENDENCY, - PEER_DEPENDENCY -} - -/** - * 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. - * - */ -export class LockfileDependency { - public name: string; - public version: string; - public entryId: string = ''; - public dependencyType: IDependencyType; - public containingEntry: LockfileEntry; - public resolvedEntry: LockfileEntry | undefined; - - public peerDependencyMeta: { - name?: string; - version?: string; - optional?: boolean; - }; - - public constructor( - name: string, - version: string, - dependencyType: IDependencyType, - containingEntry: LockfileEntry, - node?: ILockfileNode - ) { - this.name = name; - this.version = version; - this.dependencyType = dependencyType; - this.containingEntry = containingEntry; - this.peerDependencyMeta = {}; - - if (this.version.startsWith('link:')) { - const relativePath = this.version.substring('link:'.length); - const rootRelativePath = new Path('.').relative( - new Path(containingEntry.packageJsonFolderPath).concat(relativePath) - ); - if (!rootRelativePath) { - // eslint-disable-next-line no-console - console.error('No root relative path for dependency!', name); - return; - } - this.entryId = 'project:' + rootRelativePath.toString(); - } else if (this.version.startsWith('/')) { - this.entryId = this.version; - } else if (this.dependencyType === IDependencyType.PEER_DEPENDENCY) { - if (node?.peerDependencies) { - this.peerDependencyMeta = { - name: this.name, - version: node.peerDependencies[this.name], - optional: - node.peerDependenciesMeta && node.peerDependenciesMeta[this.name] - ? node.peerDependenciesMeta[this.name].optional - : false - }; - this.entryId = 'Peer: ' + this.name; - } else { - // eslint-disable-next-line no-console - console.error('Peer dependencies info missing!', node); - } - } else { - this.entryId = '/' + this.name + '/' + this.version; - } - } - - // node is the yaml entry that we are trying to parse - public static parseDependencies( - dependencies: LockfileDependency[], - lockfileEntry: LockfileEntry, - node: ILockfileNode - ): void { - if (node.dependencies) { - for (const [pkgName, pkgVersion] of Object.entries(node.dependencies)) { - dependencies.push( - new LockfileDependency(pkgName, pkgVersion, IDependencyType.DEPENDENCY, lockfileEntry) - ); - } - } - if (node.devDependencies) { - for (const [pkgName, pkgVersion] of Object.entries(node.devDependencies)) { - dependencies.push( - new LockfileDependency(pkgName, pkgVersion, IDependencyType.DEV_DEPENDENCY, lockfileEntry) - ); - } - } - if (node.peerDependencies) { - for (const [pkgName, pkgVersion] of Object.entries(node.peerDependencies)) { - dependencies.push( - new LockfileDependency(pkgName, pkgVersion, IDependencyType.PEER_DEPENDENCY, lockfileEntry, node) - ); - } - } - if (node.transitivePeerDependencies) { - for (const dep of node.transitivePeerDependencies) { - lockfileEntry.transitivePeerDependencies.add(dep); - } - } - } -} diff --git a/apps/lockfile-explorer-web/src/parsing/LockfileEntry.ts b/apps/lockfile-explorer-web/src/parsing/LockfileEntry.ts deleted file mode 100644 index f8712e4e785..00000000000 --- a/apps/lockfile-explorer-web/src/parsing/LockfileEntry.ts +++ /dev/null @@ -1,141 +0,0 @@ -// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. -// See LICENSE in the project root for license information. - -import { Path } from '@lifaon/path'; -import { type ILockfileNode, LockfileDependency } from './LockfileDependency'; - -export enum LockfileEntryFilter { - Project, - Package, - SideBySide, - Doppelganger -} - -interface IProps { - rawEntryId: string; - kind: LockfileEntryFilter; - rawYamlData: ILockfileNode; - duplicates?: Set; - subspaceName?: string; -} - -/** - * Represents a project or package listed in the pnpm lockfile. - * - * @remarks - * Each project or package will have its own LockfileEntry, which is created when the lockfile is first parsed. - * The fields for the LockfileEntry are outlined below: - * - * @class LockfileEntry - * @property entryId {string} a unique (human-readable) identifier for this lockfile entry. For projects, this is just - * "Project:" + the package json path for this project. - * @property rawEntryId {string} the unique identifier assigned to this project/package in the lockfile. - * e.g. /@emotion/core/10.3.1_qjwx5m6wssz3lnb35xwkc3pz6q: - * @property kind {LockfileEntryFilter} Whether this entry is a project or a package (specified by importers or packages in the lockfile). - * @property packageJsonFolderPath {string} Where the package.json is for this project or package. - * @property entryPackageName {string} Just the name of the package with no specifiers. - * @property displayText {string} A human friendly name for the project or package. - * @property dependencies {LockfileDependency[]} A list of all the dependencies for this entry. - * Note that dependencies, dev dependencies, as well as peer dependencies are all included. - * @property transitivePeerDependencies {Set} A list of dependencies that are listed under the - * "transitivePeerDependencies" in the pnpm lockfile. - * @property referrers {LockfileEntry[]} a list of entries that specify this entry as a dependency. - * - */ -export class LockfileEntry { - public entryId: string = ''; - public kind: LockfileEntryFilter; - public rawEntryId: string; - public packageJsonFolderPath: string = ''; - - public entryPackageName: string = ''; - public displayText: string = ''; - - public dependencies: LockfileDependency[] = []; - public transitivePeerDependencies: Set = new Set(); - public referrers: LockfileEntry[] = []; - - private static _packageEntryIdRegex: RegExp = new RegExp('/(.*)/([^/]+)$'); - - public entryPackageVersion: string = ''; - public entrySuffix: string = ''; - - public constructor(data: IProps) { - const { rawEntryId, kind, rawYamlData, duplicates, subspaceName } = data; - this.rawEntryId = rawEntryId; - this.kind = kind; - - if (rawEntryId === '.') { - // Project Root - return; - } - - if (kind === LockfileEntryFilter.Project) { - const rootPackageJsonFolderPath = new Path(`common/temp/${subspaceName}/package.json`).dirname() || ''; - const packageJsonFolderPath = new Path('.').relative( - new Path(rootPackageJsonFolderPath).concat(rawEntryId) - ); - const packageName = new Path(rawEntryId).basename(); - - if (!packageJsonFolderPath || !packageName) { - // eslint-disable-next-line no-console - console.error('Could not construct path for entry: ', rawEntryId); - return; - } - - this.packageJsonFolderPath = packageJsonFolderPath.toString(); - this.entryId = 'project:' + this.packageJsonFolderPath; - this.entryPackageName = packageName.toString(); - if (duplicates?.has(this.entryPackageName)) { - const fullPath = new Path(rawEntryId).makeAbsolute('/').toString().substring(1); - this.displayText = `Project: ${this.entryPackageName} (${fullPath})`; - this.entryPackageName = `${this.entryPackageName} (${fullPath})`; - } else { - this.displayText = 'Project: ' + this.entryPackageName; - } - } else { - this.displayText = rawEntryId; - - const match = LockfileEntry._packageEntryIdRegex.exec(rawEntryId); - - if (match) { - const [, packageName, versionPart] = match; - this.entryPackageName = packageName; - - const underscoreIndex = versionPart.indexOf('_'); - if (underscoreIndex >= 0) { - const version = versionPart.substring(0, underscoreIndex); - const suffix = versionPart.substring(underscoreIndex + 1); - - this.entryPackageVersion = version; - this.entrySuffix = suffix; - - // /@rushstack/eslint-config/3.0.1_eslint@8.21.0+typescript@4.7.4 - // --> @rushstack/eslint-config 3.0.1 (eslint@8.21.0+typescript@4.7.4) - this.displayText = packageName + ' ' + version + ' (' + suffix + ')'; - } else { - this.entryPackageVersion = versionPart; - - // /@rushstack/eslint-config/3.0.1 - // --> @rushstack/eslint-config 3.0.1 - this.displayText = packageName + ' ' + versionPart; - } - } - - // Example: - // common/temp/default/node_modules/.pnpm - // /@babel+register@7.17.7_@babel+core@7.17.12 - // /node_modules/@babel/register - this.packageJsonFolderPath = - `common/temp/${subspaceName}/node_modules/.pnpm/` + - this.entryPackageName.replace('/', '+') + - '@' + - this.entryPackageVersion + - (this.entrySuffix ? `_${this.entrySuffix}` : '') + - '/node_modules/' + - this.entryPackageName; - } - - LockfileDependency.parseDependencies(this.dependencies, this, rawYamlData); - } -} diff --git a/apps/lockfile-explorer-web/src/parsing/lfxGraphLoader.ts b/apps/lockfile-explorer-web/src/parsing/lfxGraphLoader.ts new file mode 100644 index 00000000000..e9b02ec4e47 --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/lfxGraphLoader.ts @@ -0,0 +1,379 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { + type ILockfileDependencyOptions, + type ILockfileEntryOptions, + LfxGraph, + LockfileEntry, + LockfileEntryFilter +} from './LfxGraph'; +import { DependencyKind, LockfileDependency } from './LfxGraph'; +import { Path } from '@lifaon/path'; + +enum PnpmLockfileVersion { + V6, + V5 +} + +export interface ILockfileImporterV6 { + dependencies?: { + [key: string]: { + specifier: string; + version: string; + }; + }; + devDependencies?: { + [key: string]: { + specifier: string; + version: string; + }; + }; +} +export interface ILockfileImporterV5 { + specifiers?: Record; + dependencies?: Record; + devDependencies?: Record; +} +export interface ILockfilePackageType { + lockfileVersion: number | string; + importers?: { + [key: string]: ILockfileImporterV5 | ILockfileImporterV6; + }; + packages?: { + [key: string]: { + resolution: { + integrity: string; + }; + dependencies?: Record; + peerDependencies?: Record; + dev: boolean; + }; + }; +} + +export interface ILockfileNode { + dependencies?: { + [key: string]: string; + }; + devDependencies?: { + [key: string]: string; + }; + peerDependencies?: { + [key: string]: string; + }; + peerDependenciesMeta?: { + [key: string]: { + optional: boolean; + }; + }; + transitivePeerDependencies?: string[]; +} + +const packageEntryIdRegex: RegExp = new RegExp('/(.*)/([^/]+)$'); + +function createLockfileDependency( + name: string, + version: string, + dependencyType: DependencyKind, + containingEntry: LockfileEntry, + node?: ILockfileNode +): LockfileDependency { + const result: ILockfileDependencyOptions = { + name, + version, + dependencyType, + containingEntry, + entryId: '', + peerDependencyMeta: {} + }; + + if (version.startsWith('link:')) { + const relativePath = version.substring('link:'.length); + const rootRelativePath = new Path('.').relative( + new Path(containingEntry.packageJsonFolderPath).concat(relativePath) + ); + if (!rootRelativePath) { + // eslint-disable-next-line no-console + console.error('No root relative path for dependency!', name); + return new LockfileDependency(result); + } + result.entryId = 'project:' + rootRelativePath.toString(); + } else if (result.version.startsWith('/')) { + result.entryId = version; + } else if (result.dependencyType === DependencyKind.PEER_DEPENDENCY) { + if (node?.peerDependencies) { + result.peerDependencyMeta = { + name: result.name, + version: node.peerDependencies[result.name], + optional: + node.peerDependenciesMeta && node.peerDependenciesMeta[result.name] + ? node.peerDependenciesMeta[result.name].optional + : false + }; + result.entryId = 'Peer: ' + result.name; + } else { + // eslint-disable-next-line no-console + console.error('Peer dependencies info missing!', node); + } + } else { + result.entryId = '/' + result.name + '/' + result.version; + } + return new LockfileDependency(result); +} + +// node is the yaml entry that we are trying to parse +function parseDependencies( + dependencies: LockfileDependency[], + lockfileEntry: LockfileEntry, + node: ILockfileNode +): void { + if (node.dependencies) { + for (const [pkgName, pkgVersion] of Object.entries(node.dependencies)) { + dependencies.push( + createLockfileDependency(pkgName, pkgVersion, DependencyKind.DEPENDENCY, lockfileEntry) + ); + } + } + if (node.devDependencies) { + for (const [pkgName, pkgVersion] of Object.entries(node.devDependencies)) { + dependencies.push( + createLockfileDependency(pkgName, pkgVersion, DependencyKind.DEV_DEPENDENCY, lockfileEntry) + ); + } + } + if (node.peerDependencies) { + for (const [pkgName, pkgVersion] of Object.entries(node.peerDependencies)) { + dependencies.push( + createLockfileDependency(pkgName, pkgVersion, DependencyKind.PEER_DEPENDENCY, lockfileEntry, node) + ); + } + } + if (node.transitivePeerDependencies) { + for (const dep of node.transitivePeerDependencies) { + lockfileEntry.transitivePeerDependencies.add(dep); + } + } +} + +function createLockfileEntry(options: { + rawEntryId: string; + kind: LockfileEntryFilter; + rawYamlData: ILockfileNode; + duplicates?: Set; + subspaceName?: string; +}): LockfileEntry { + const { rawEntryId, kind, rawYamlData, duplicates, subspaceName } = options; + + const result: ILockfileEntryOptions = { + kind, + entryId: '', + rawEntryId: '', + packageJsonFolderPath: '', + entryPackageName: '', + displayText: '', + entryPackageVersion: '', + entrySuffix: '' + }; + + result.rawEntryId = rawEntryId; + + if (rawEntryId === '.') { + // Project Root + return new LockfileEntry(result); + } + + if (kind === LockfileEntryFilter.Project) { + const rootPackageJsonFolderPath = new Path(`common/temp/${subspaceName}/package.json`).dirname() || ''; + const packageJsonFolderPath = new Path('.').relative( + new Path(rootPackageJsonFolderPath).concat(rawEntryId) + ); + const packageName = new Path(rawEntryId).basename(); + + if (!packageJsonFolderPath || !packageName) { + // eslint-disable-next-line no-console + console.error('Could not construct path for entry: ', rawEntryId); + return new LockfileEntry(result); + } + + result.packageJsonFolderPath = packageJsonFolderPath.toString(); + result.entryId = 'project:' + result.packageJsonFolderPath; + result.entryPackageName = packageName.toString(); + if (duplicates?.has(result.entryPackageName)) { + const fullPath = new Path(rawEntryId).makeAbsolute('/').toString().substring(1); + result.displayText = `Project: ${result.entryPackageName} (${fullPath})`; + result.entryPackageName = `${result.entryPackageName} (${fullPath})`; + } else { + result.displayText = 'Project: ' + result.entryPackageName; + } + } else { + result.displayText = rawEntryId; + + const match = packageEntryIdRegex.exec(rawEntryId); + + if (match) { + const [, packageName, versionPart] = match; + result.entryPackageName = packageName; + + const underscoreIndex = versionPart.indexOf('_'); + if (underscoreIndex >= 0) { + const version = versionPart.substring(0, underscoreIndex); + const suffix = versionPart.substring(underscoreIndex + 1); + + result.entryPackageVersion = version; + result.entrySuffix = suffix; + + // /@rushstack/eslint-config/3.0.1_eslint@8.21.0+typescript@4.7.4 + // --> @rushstack/eslint-config 3.0.1 (eslint@8.21.0+typescript@4.7.4) + result.displayText = packageName + ' ' + version + ' (' + suffix + ')'; + } else { + result.entryPackageVersion = versionPart; + + // /@rushstack/eslint-config/3.0.1 + // --> @rushstack/eslint-config 3.0.1 + result.displayText = packageName + ' ' + versionPart; + } + } + + // Example: + // common/temp/default/node_modules/.pnpm + // /@babel+register@7.17.7_@babel+core@7.17.12 + // /node_modules/@babel/register + result.packageJsonFolderPath = + `common/temp/${subspaceName}/node_modules/.pnpm/` + + result.entryPackageName.replace('/', '+') + + '@' + + result.entryPackageVersion + + (result.entrySuffix ? `_${result.entrySuffix}` : '') + + '/node_modules/' + + result.entryPackageName; + } + + const lockfileEntry = new LockfileEntry(result); + parseDependencies(lockfileEntry.dependencies, lockfileEntry, rawYamlData); + return lockfileEntry; +} + +/** + * Transform any newer lockfile formats to the following format: + * [packageName]: + * specifier: ... + * version: ... + */ +function getImporterValue( + importerValue: ILockfileImporterV5 | ILockfileImporterV6, + pnpmLockfileVersion: PnpmLockfileVersion +): ILockfileImporterV5 { + if (pnpmLockfileVersion === PnpmLockfileVersion.V6) { + const v6ImporterValue = importerValue as ILockfileImporterV6; + const v5ImporterValue: ILockfileImporterV5 = { + specifiers: {}, + dependencies: {}, + devDependencies: {} + }; + for (const [depName, depDetails] of Object.entries(v6ImporterValue.dependencies ?? {})) { + v5ImporterValue.specifiers![depName] = depDetails.specifier; + v5ImporterValue.dependencies![depName] = depDetails.version; + } + for (const [depName, depDetails] of Object.entries(v6ImporterValue.devDependencies ?? {})) { + v5ImporterValue.specifiers![depName] = depDetails.specifier; + v5ImporterValue.devDependencies![depName] = depDetails.version; + } + return v5ImporterValue; + } else { + return importerValue as ILockfileImporterV5; + } +} + +/** + * Parse through the lockfile and create all the corresponding LockfileEntries and LockfileDependencies + * to construct the lockfile graph. + * + * @returns A list of all the LockfileEntries in the lockfile. + */ +export function generateLockfileGraph(lockfile: ILockfilePackageType, subspaceName?: string): LfxGraph { + let pnpmLockfileVersion: PnpmLockfileVersion = PnpmLockfileVersion.V5; + if (parseInt(lockfile.lockfileVersion.toString(), 10) === 6) { + pnpmLockfileVersion = PnpmLockfileVersion.V6; + } + const lfxGraph: LfxGraph = new LfxGraph(); + const allEntries: LockfileEntry[] = lfxGraph.entries; + const allEntriesById: { [key: string]: LockfileEntry } = {}; + + const allImporters = []; + if (lockfile.importers) { + // Find duplicate importer names + const baseNames = new Set(); + const duplicates = new Set(); + for (const importerKey of Object.keys(lockfile.importers)) { + const baseName = new Path(importerKey).basename(); + if (baseName) { + if (baseNames.has(baseName)) { + duplicates.add(baseName); + } + baseNames.add(baseName); + } + } + + for (const [importerKey, importerValue] of Object.entries(lockfile.importers)) { + // console.log('normalized importer key: ', new Path(importerKey).makeAbsolute('/').toString()); + + // const normalizedPath = new Path(importerKey).makeAbsolute('/').toString(); + const importer: LockfileEntry = createLockfileEntry({ + // entryId: normalizedPath, + rawEntryId: importerKey, + kind: LockfileEntryFilter.Project, + rawYamlData: getImporterValue(importerValue, pnpmLockfileVersion), + duplicates, + subspaceName + }); + allImporters.push(importer); + allEntries.push(importer); + allEntriesById[importer.entryId] = importer; + } + } + + const allPackages = []; + if (lockfile.packages) { + for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages)) { + // const normalizedPath = new Path(dependencyKey).makeAbsolute('/').toString(); + + const currEntry: LockfileEntry = createLockfileEntry({ + // entryId: normalizedPath, + rawEntryId: dependencyKey, + kind: LockfileEntryFilter.Package, + rawYamlData: dependencyValue, + subspaceName + }); + + allPackages.push(currEntry); + allEntries.push(currEntry); + allEntriesById[dependencyKey] = currEntry; + } + } + + // Construct the graph + for (const entry of allEntries) { + for (const dependency of entry.dependencies) { + // Peer dependencies do not have a matching entry + if (dependency.dependencyType === DependencyKind.PEER_DEPENDENCY) { + continue; + } + + const matchedEntry = allEntriesById[dependency.entryId]; + if (matchedEntry) { + // Create a two-way link between the dependency and the entry + dependency.resolvedEntry = matchedEntry; + matchedEntry.referrers.push(entry); + } else { + if (dependency.entryId.startsWith('/')) { + // Local package + // eslint-disable-next-line no-console + console.error('Could not resolve dependency entryId: ', dependency.entryId, dependency); + } + } + } + } + + return lfxGraph; +} diff --git a/apps/lockfile-explorer-web/src/parsing/lfxGraphSerializer.ts b/apps/lockfile-explorer-web/src/parsing/lfxGraphSerializer.ts new file mode 100644 index 00000000000..30a0e19fa53 --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/lfxGraphSerializer.ts @@ -0,0 +1,142 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IJsonLfxDependency, IJsonLfxEntry, IJsonLfxGraph } from './JsonLfxGraph'; +import { type ILockfileEntryOptions, LfxGraph, LockfileDependency, LockfileEntry } from './LfxGraph'; + +export function serializeToJson(graph: LfxGraph): IJsonLfxGraph { + const jsonLfxEntries: IJsonLfxEntry[] = []; + + const jsonIdByEntry: Map = new Map(); + + function toJsonId(entry: LockfileEntry): number { + const result: number | undefined = jsonIdByEntry.get(entry); + if (result === undefined) { + throw new Error('Attempt to serialize disconnected object'); + } + return result; + } + + // First create the jsonId mapping + for (const entry of graph.entries) { + const nextIndex: number = jsonLfxEntries.length; + + const jsonLfxEntry: IJsonLfxEntry = { + jsonId: nextIndex, + + kind: entry.kind, + entryId: entry.entryId, + rawEntryId: entry.rawEntryId, + packageJsonFolderPath: entry.packageJsonFolderPath, + entryPackageName: entry.entryPackageName, + displayText: entry.displayText, + entryPackageVersion: entry.entryPackageVersion, + entrySuffix: entry.entrySuffix, + + // Lists will be added in the second loop + dependencies: [], + transitivePeerDependencies: [], + referrerJsonIds: [] + }; + + jsonLfxEntries.push(jsonLfxEntry); + jsonIdByEntry.set(entry, jsonLfxEntry.jsonId); + } + + // Use the jsonId mapping to serialize the lists + for (let i: number = 0; i < jsonLfxEntries.length; ++i) { + const jsonLfxEntry: IJsonLfxEntry = jsonLfxEntries[i]; + const entry: LockfileEntry = graph.entries[i]; + + for (const dependency of entry.dependencies) { + const jsonLfxDependency: IJsonLfxDependency = { + name: dependency.name, + version: dependency.version, + entryId: dependency.entryId, + dependencyType: dependency.dependencyType, + peerDependencyMeta: { + name: dependency.peerDependencyMeta.name, + version: dependency.peerDependencyMeta.version, + optional: dependency.peerDependencyMeta.optional + } + }; + if (dependency.resolvedEntry) { + jsonLfxDependency.resolvedEntryJsonId = toJsonId(dependency.resolvedEntry); + } + + jsonLfxEntry.dependencies.push(jsonLfxDependency); + } + jsonLfxEntry.transitivePeerDependencies = Array.from(entry.transitivePeerDependencies); + jsonLfxEntry.referrerJsonIds = entry.referrers.map((x) => toJsonId(x)); + } + + return { entries: jsonLfxEntries }; +} + +export function deserializeFromJson(jsonLfxGraph: IJsonLfxGraph): LfxGraph { + const graph: LfxGraph = new LfxGraph(); + + const entries: LockfileEntry[] = graph.entries; + + function fromJsonId(jsonId: number): LockfileEntry { + const result: LockfileEntry | undefined = entries[jsonId]; + if (result === undefined) { + throw new Error('Invalid jsonId'); + } + return result; + } + + const jsonLfxEntries: IJsonLfxEntry[] = jsonLfxGraph.entries; + + // First create the jsonId mapping + for (const jsonLfxEntry of jsonLfxEntries) { + const options: ILockfileEntryOptions = { + kind: jsonLfxEntry.kind, + entryId: jsonLfxEntry.entryId, + rawEntryId: jsonLfxEntry.rawEntryId, + packageJsonFolderPath: jsonLfxEntry.packageJsonFolderPath, + entryPackageName: jsonLfxEntry.entryPackageName, + displayText: jsonLfxEntry.displayText, + entryPackageVersion: jsonLfxEntry.entryPackageVersion, + entrySuffix: jsonLfxEntry.entrySuffix + }; + entries.push(new LockfileEntry(options)); + } + + // Use the jsonId mapping to deserialize the lists + for (let i: number = 0; i < jsonLfxEntries.length; ++i) { + const jsonLfxEntry: IJsonLfxEntry = jsonLfxEntries[i]; + const entry: LockfileEntry = graph.entries[i]; + + for (const jsonLfxDependency of jsonLfxEntry.dependencies) { + const dependency: LockfileDependency = new LockfileDependency({ + name: jsonLfxDependency.name, + version: jsonLfxDependency.version, + dependencyType: jsonLfxDependency.dependencyType, + containingEntry: entry, + entryId: jsonLfxDependency.entryId, + peerDependencyMeta: { + name: jsonLfxDependency.peerDependencyMeta.name, + version: jsonLfxDependency.peerDependencyMeta.version, + optional: jsonLfxDependency.peerDependencyMeta.optional + } + }); + + if (jsonLfxDependency.resolvedEntryJsonId) { + dependency.resolvedEntry = fromJsonId(jsonLfxDependency.resolvedEntryJsonId); + } + + entry.dependencies.push(dependency); + } + + for (const item of jsonLfxEntry.transitivePeerDependencies) { + entry.transitivePeerDependencies.add(item); + } + + for (const referrerJsonId of jsonLfxEntry.referrerJsonIds) { + entry.referrers.push(fromJsonId(referrerJsonId)); + } + } + + return graph; +} diff --git a/apps/lockfile-explorer-web/src/parsing/readLockfile.ts b/apps/lockfile-explorer-web/src/parsing/readLockfile.ts index ce78139f673..c68b9bb26d8 100644 --- a/apps/lockfile-explorer-web/src/parsing/readLockfile.ts +++ b/apps/lockfile-explorer-web/src/parsing/readLockfile.ts @@ -1,187 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import { LockfileEntry, LockfileEntryFilter } from './LockfileEntry'; -import { IDependencyType } from './LockfileDependency'; -import { Path } from '@lifaon/path'; +import type { LockfileEntry } from './LfxGraph'; +import * as lfxGraphLoader from './lfxGraphLoader'; const serviceUrl: string = window.appContext.serviceUrl; -export enum PnpmLockfileVersion { - V6, - V5 -} - -export interface IPackageJsonType { - name: string; - dependencies: Record; - devDependencies: Record; -} -export interface ILockfileImporterV6 { - dependencies?: { - [key in string]: { - specifier: string; - version: string; - }; - }; - devDependencies?: { - [key in string]: { - specifier: string; - version: string; - }; - }; -} -export interface ILockfileImporterV5 { - specifiers?: Record; - dependencies?: Record; - devDependencies?: Record; -} -export interface ILockfilePackageType { - lockfileVersion: number | string; - importers?: { - [key in string]: ILockfileImporterV5 | ILockfileImporterV6; - }; - packages?: { - [key in string]: { - resolution: { - integrity: string; - }; - dependencies?: Record; - peerDependencies?: Record; - dev: boolean; - }; - }; -} - -/** - * Transform any newer lockfile formats to the following format: - * [packageName]: - * specifier: ... - * version: ... - */ -function getImporterValue( - importerValue: ILockfileImporterV5 | ILockfileImporterV6, - pnpmLockfileVersion: PnpmLockfileVersion -): ILockfileImporterV5 { - if (pnpmLockfileVersion === PnpmLockfileVersion.V6) { - const v6ImporterValue = importerValue as ILockfileImporterV6; - const v5ImporterValue: ILockfileImporterV5 = { - specifiers: {}, - dependencies: {}, - devDependencies: {} - }; - for (const [depName, depDetails] of Object.entries(v6ImporterValue.dependencies || {})) { - v5ImporterValue.specifiers![depName] = depDetails.specifier; - v5ImporterValue.dependencies![depName] = depDetails.version; - } - for (const [depName, depDetails] of Object.entries(v6ImporterValue.devDependencies || {})) { - v5ImporterValue.specifiers![depName] = depDetails.specifier; - v5ImporterValue.devDependencies![depName] = depDetails.version; - } - return v5ImporterValue; - } else { - return importerValue as ILockfileImporterV5; - } -} - -/** - * Parse through the lockfile and create all the corresponding LockfileEntries and LockfileDependencies - * to construct the lockfile graph. - * - * @returns A list of all the LockfileEntries in the lockfile. - */ -export function generateLockfileGraph( - lockfile: ILockfilePackageType, - subspaceName?: string -): LockfileEntry[] { - let pnpmLockfileVersion: PnpmLockfileVersion = PnpmLockfileVersion.V5; - if (`${lockfile.lockfileVersion}`.startsWith('6')) { - pnpmLockfileVersion = PnpmLockfileVersion.V6; - } - const allEntries: LockfileEntry[] = []; - const allEntriesById: { [key in string]: LockfileEntry } = {}; - - const allImporters = []; - if (lockfile.importers) { - // Find duplicate importer names - const baseNames = new Set(); - const duplicates = new Set(); - for (const importerKey of Object.keys(lockfile.importers)) { - const baseName = new Path(importerKey).basename(); - if (baseName) { - if (baseNames.has(baseName)) { - duplicates.add(baseName); - } - baseNames.add(baseName); - } - } - - for (const [importerKey, importerValue] of Object.entries(lockfile.importers)) { - // console.log('normalized importer key: ', new Path(importerKey).makeAbsolute('/').toString()); - - // const normalizedPath = new Path(importerKey).makeAbsolute('/').toString(); - const importer = new LockfileEntry({ - // entryId: normalizedPath, - rawEntryId: importerKey, - kind: LockfileEntryFilter.Project, - rawYamlData: getImporterValue(importerValue, pnpmLockfileVersion), - duplicates, - subspaceName - }); - allImporters.push(importer); - allEntries.push(importer); - allEntriesById[importer.entryId] = importer; - } - } - - const allPackages = []; - if (lockfile.packages) { - for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages)) { - // const normalizedPath = new Path(dependencyKey).makeAbsolute('/').toString(); - - const currEntry = new LockfileEntry({ - // entryId: normalizedPath, - rawEntryId: dependencyKey, - kind: LockfileEntryFilter.Package, - rawYamlData: dependencyValue, - subspaceName - }); - - allPackages.push(currEntry); - allEntries.push(currEntry); - allEntriesById[dependencyKey] = currEntry; - } - } - - // Construct the graph - for (const entry of allEntries) { - for (const dependency of entry.dependencies) { - // Peer dependencies do not have a matching entry - if (dependency.dependencyType === IDependencyType.PEER_DEPENDENCY) { - continue; - } - - const matchedEntry = allEntriesById[dependency.entryId]; - if (matchedEntry) { - // Create a two-way link between the dependency and the entry - dependency.resolvedEntry = matchedEntry; - matchedEntry.referrers.push(entry); - } else { - if (dependency.entryId.startsWith('/')) { - // Local package - // eslint-disable-next-line no-console - console.error('Could not resolve dependency entryId: ', dependency.entryId, dependency); - } - } - } - } - - return allEntries; -} - export async function readLockfileAsync(): Promise { const response = await fetch(`${serviceUrl}/api/lockfile`); - const lockfile: { doc: ILockfilePackageType; subspaceName: string } = await response.json(); + const lockfile: { doc: lfxGraphLoader.ILockfilePackageType; subspaceName: string } = await response.json(); - return generateLockfileGraph(lockfile.doc, lockfile.subspaceName); + return lfxGraphLoader.generateLockfileGraph(lockfile.doc, lockfile.subspaceName).entries; } diff --git a/apps/lockfile-explorer-web/src/parsing/test/lockfile.test.ts b/apps/lockfile-explorer-web/src/parsing/test/lockfile.test.ts index b2dbce9f2c7..d6cbc0626dc 100644 --- a/apps/lockfile-explorer-web/src/parsing/test/lockfile.test.ts +++ b/apps/lockfile-explorer-web/src/parsing/test/lockfile.test.ts @@ -2,15 +2,15 @@ // See LICENSE in the project root for license information. import { TEST_LOCKFILE } from './testLockfile'; -import { generateLockfileGraph } from '../readLockfile'; -import type { LockfileEntry } from '../LockfileEntry'; +import * as lfxGraphLoader from '../lfxGraphLoader'; +import type { LockfileEntry } from '../LfxGraph'; describe('LockfileGeneration', () => { it('creates a valid bi-directional graph', () => { - const resolvedPackages = generateLockfileGraph(TEST_LOCKFILE); + const resolvedPackages = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE).entries; // Mapping of all the lockfile entries created by the lockfile - const resolvedPackagesMap: { [key in string]: LockfileEntry } = {}; + const resolvedPackagesMap: { [key: string]: LockfileEntry } = {}; for (const resolvedPackage of resolvedPackages) { resolvedPackagesMap[resolvedPackage.entryPackageName] = resolvedPackage; } diff --git a/apps/lockfile-explorer-web/src/parsing/test/serializeToJson.test.ts b/apps/lockfile-explorer-web/src/parsing/test/serializeToJson.test.ts new file mode 100644 index 00000000000..2fe9915fbe8 --- /dev/null +++ b/apps/lockfile-explorer-web/src/parsing/test/serializeToJson.test.ts @@ -0,0 +1,127 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import { TEST_LOCKFILE } from './testLockfile'; +import * as lfxGraphLoader from '../lfxGraphLoader'; +import * as lfxGraphSerializer from '../lfxGraphSerializer'; +import type { LfxGraph } from '../LfxGraph'; + +describe('serializeToJson', () => { + it('serializes a simple graph', () => { + const graph = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE); + + expect(lfxGraphSerializer.serializeToJson(graph)).toMatchInlineSnapshot(` +Object { + "entries": Array [ + Object { + "dependencies": Array [], + "displayText": "", + "entryId": "", + "entryPackageName": "", + "entryPackageVersion": "", + "entrySuffix": "", + "jsonId": 0, + "kind": 1, + "packageJsonFolderPath": "", + "rawEntryId": ".", + "referrerJsonIds": Array [], + "transitivePeerDependencies": Array [], + }, + Object { + "dependencies": Array [ + Object { + "dependencyType": "regular", + "entryId": "/@testPackage/core/1.7.1", + "name": "@testPackage/core", + "peerDependencyMeta": Object { + "name": undefined, + "optional": undefined, + "version": undefined, + }, + "resolvedEntryJsonId": 2, + "version": "1.7.1", + }, + Object { + "dependencyType": "regular", + "entryId": "/@testPackage2/core/1.7.1", + "name": "@testPackage2/core", + "peerDependencyMeta": Object { + "name": undefined, + "optional": undefined, + "version": undefined, + }, + "resolvedEntryJsonId": 3, + "version": "1.7.1", + }, + ], + "displayText": "Project: testApp1", + "entryId": "project:./apps/testApp1", + "entryPackageName": "testApp1", + "entryPackageVersion": "", + "entrySuffix": "", + "jsonId": 1, + "kind": 1, + "packageJsonFolderPath": "./apps/testApp1", + "rawEntryId": "../../../apps/testApp1", + "referrerJsonIds": Array [], + "transitivePeerDependencies": Array [], + }, + Object { + "dependencies": Array [], + "displayText": "@testPackage/core 1.7.1", + "entryId": "", + "entryPackageName": "@testPackage/core", + "entryPackageVersion": "1.7.1", + "entrySuffix": "", + "jsonId": 2, + "kind": 2, + "packageJsonFolderPath": "common/temp/undefined/node_modules/.pnpm/@testPackage+core@1.7.1/node_modules/@testPackage/core", + "rawEntryId": "/@testPackage/core/1.7.1", + "referrerJsonIds": Array [ + 1, + ], + "transitivePeerDependencies": Array [], + }, + Object { + "dependencies": Array [], + "displayText": "@testPackage2/core 1.7.1", + "entryId": "", + "entryPackageName": "@testPackage2/core", + "entryPackageVersion": "1.7.1", + "entrySuffix": "", + "jsonId": 3, + "kind": 2, + "packageJsonFolderPath": "common/temp/undefined/node_modules/.pnpm/@testPackage2+core@1.7.1/node_modules/@testPackage2/core", + "rawEntryId": "/@testPackage2/core/1.7.1", + "referrerJsonIds": Array [ + 1, + ], + "transitivePeerDependencies": Array [], + }, + ], +} +`); + }); + + it('deserializes a simple graph', () => { + const originalGraph = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE); + + const serialized: string = JSON.stringify( + lfxGraphSerializer.serializeToJson(originalGraph), + undefined, + 2 + ); + + const deserialized: LfxGraph = lfxGraphSerializer.deserializeFromJson(JSON.parse(serialized)); + + expect(deserialized.entries.length === originalGraph.entries.length); + + const reserialized: string = JSON.stringify( + lfxGraphSerializer.serializeToJson(deserialized), + undefined, + 2 + ); + + expect(reserialized).toEqual(serialized); + }); +}); diff --git a/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts b/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts index 078c98cf8b6..8c6bd99c0fc 100644 --- a/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts +++ b/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import { createSlice, type PayloadAction, type Reducer } from '@reduxjs/toolkit'; -import { type LockfileEntry, LockfileEntryFilter } from '../../parsing/LockfileEntry'; +import { type LockfileEntry, LockfileEntryFilter } from '../../parsing/LfxGraph'; import type { RootState } from '../index'; import { getBookmarksFromStorage, diff --git a/apps/lockfile-explorer-web/src/types/AppContext.ts b/apps/lockfile-explorer-web/src/types/AppContext.ts new file mode 100644 index 00000000000..28e788cf31f --- /dev/null +++ b/apps/lockfile-explorer-web/src/types/AppContext.ts @@ -0,0 +1,11 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IAppContext } from './IAppContext'; + +declare global { + // eslint-disable-next-line @typescript-eslint/naming-convention + interface Window { + appContext: IAppContext; + } +} diff --git a/apps/lockfile-explorer-web/src/AppContext.ts b/apps/lockfile-explorer-web/src/types/IAppContext.ts similarity index 87% rename from apps/lockfile-explorer-web/src/AppContext.ts rename to apps/lockfile-explorer-web/src/types/IAppContext.ts index 098a8432e53..93792c57b59 100644 --- a/apps/lockfile-explorer-web/src/AppContext.ts +++ b/apps/lockfile-explorer-web/src/types/IAppContext.ts @@ -34,10 +34,3 @@ export interface IAppContext { */ debugMode: boolean; } - -declare global { - // eslint-disable-next-line @typescript-eslint/naming-convention - interface Window { - appContext: IAppContext; - } -} diff --git a/apps/lockfile-explorer-web/src/types/IPackageJson.ts b/apps/lockfile-explorer-web/src/types/IPackageJson.ts index 9ca29b24b7c..3f575a99f52 100644 --- a/apps/lockfile-explorer-web/src/types/IPackageJson.ts +++ b/apps/lockfile-explorer-web/src/types/IPackageJson.ts @@ -5,12 +5,12 @@ export interface IPackageJson { name: string; version: string; dependencies: { - [key in string]: string; + [key: string]: string; }; devDependencies: { - [key in string]: string; + [key: string]: string; }; peerDependencies: { - [key in string]: string; + [key: string]: string; }; } diff --git a/apps/lockfile-explorer-web/src/types/lfxProtocol.ts b/apps/lockfile-explorer-web/src/types/lfxProtocol.ts new file mode 100644 index 00000000000..04a1d793964 --- /dev/null +++ b/apps/lockfile-explorer-web/src/types/lfxProtocol.ts @@ -0,0 +1,34 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export interface ILfxWorkspaceRushConfig { + /** + * The rushVersion from rush.json. + */ + rushVersion: string; + + /** + * If the subspaces feature is enabled and a subspace was loaded, the name of the subspace. + * Otherwise this will be an empty string. + */ + subspaceName: string; +} + +export interface ILfxWorkspace { + /** + * Absolute path to the workspace folder that is opened by the app. + * Relative paths are generally relative to this path. + */ + workspaceRootFolder: string; + + /** + * The path to the pnpm-lock.yaml file. + */ + pnpmLockfilePath: string; + + /** + * If this is a Rush workspace (versus a plain PNPM workspace), then + * this section will be defined. + */ + rushConfig: ILfxWorkspaceRushConfig | undefined; +} diff --git a/apps/lockfile-explorer-web/webpack.config.js b/apps/lockfile-explorer-web/webpack.config.js index bd625b455a9..10ce2633322 100644 --- a/apps/lockfile-explorer-web/webpack.config.js +++ b/apps/lockfile-explorer-web/webpack.config.js @@ -25,6 +25,12 @@ module.exports = function createConfig(env, argv) { }, devServer: { port: 8096, + + open: '/', + // Disable HTTPS to simplify Fiddler configuration + server: { type: 'http' }, + //hot: false, + static: { directory: path.join(__dirname, 'dist') }, diff --git a/apps/lockfile-explorer/.vscode/launch.json b/apps/lockfile-explorer/.vscode/launch.json new file mode 100644 index 00000000000..f1cdf885db1 --- /dev/null +++ b/apps/lockfile-explorer/.vscode/launch.json @@ -0,0 +1,28 @@ +{ + // Use IntelliSense to learn about possible attributes. + // Hover to view descriptions of existing attributes. + // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Debug Jest tests", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean"], + "console": "integratedTerminal", + "sourceMaps": true + }, + { + "type": "node", + "request": "launch", + "name": "Run in specified folder", + "program": "${workspaceFolder}/lib/start-explorer.js", + //"cwd": "C:\\Git\\lockfile-explorer-demos", + "cwd": "(your project path)", + "args": ["--debug"], + "sourceMaps": true + } + ] +} diff --git a/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts index dc5fc422619..4f9d3efb2f7 100644 --- a/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts +++ b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts @@ -15,7 +15,7 @@ import { CommandLineParser, type IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; -import type { IAppContext } from '@rushstack/lockfile-explorer-web/lib/AppContext'; +import type { IAppContext } from '@rushstack/lockfile-explorer-web/lib/types/IAppContext'; import type { Lockfile } from '@pnpm/lockfile-types'; import type { IAppState } from '../../state'; @@ -166,6 +166,10 @@ export class ExplorerCommandLineParser extends CommandLineParser { res.status(200).send(); }); + app.get('/api/workspace', (req: express.Request, res: express.Response) => { + res.type('application/javascript').send(appState.lfxWorkspace); + }); + app.post( '/api/package-json', async (req: express.Request<{}, {}, { projectPath: string }, {}>, res: express.Response) => { diff --git a/apps/lockfile-explorer/src/state/index.ts b/apps/lockfile-explorer/src/state/index.ts index 43b356f6ab7..d718311e17f 100644 --- a/apps/lockfile-explorer/src/state/index.ts +++ b/apps/lockfile-explorer/src/state/index.ts @@ -1,37 +1,15 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -export enum ProjectType { - RUSH_PROJECT, - PNPM_WORKSPACE -} - -export interface IRushProjectDetails { - projectName: string; - projectFolder: string; -} +import type { ILfxWorkspace } from '@rushstack/lockfile-explorer-web/lib/types/lfxProtocol'; -export interface IAppStateBase { +export interface IAppState { lockfileExplorerProjectRoot: string; - currDir: string; + currentWorkingDirectory: string; projectRoot: string; - projectType: ProjectType; pnpmLockfileLocation: string; pnpmfileLocation: string; appVersion: string; debugMode: boolean; + lfxWorkspace: ILfxWorkspace; } - -export interface IRushAppState extends IAppStateBase { - projectType: ProjectType.RUSH_PROJECT; - rush: { - rushJsonPath: string; - projectsByProjectFolder: Map; - }; -} - -export interface IPnpmWorkspaceAppState extends IAppStateBase { - projectType: ProjectType.PNPM_WORKSPACE; -} - -export type IAppState = IRushAppState | IPnpmWorkspaceAppState; diff --git a/apps/lockfile-explorer/src/utils/init.ts b/apps/lockfile-explorer/src/utils/init.ts index 4a3192db6a8..7cf20374902 100644 --- a/apps/lockfile-explorer/src/utils/init.ts +++ b/apps/lockfile-explorer/src/utils/init.ts @@ -9,7 +9,7 @@ import { RushConfiguration } from '@microsoft/rush-lib/lib/api/RushConfiguration import type { Subspace } from '@microsoft/rush-lib/lib/api/Subspace'; import path from 'path'; -import { type IAppState, type IRushProjectDetails, ProjectType } from '../state'; +import type { IAppState } from '../state'; export const init = (options: { lockfileExplorerProjectRoot: string; @@ -18,60 +18,60 @@ export const init = (options: { subspaceName: string; }): IAppState => { const { lockfileExplorerProjectRoot, appVersion, debugMode, subspaceName } = options; - const currDir = process.cwd(); + const currentWorkingDirectory: string = path.resolve(process.cwd()); let appState: IAppState | undefined; - let currExploredDir = Path.convertToSlashes(currDir); - while (currExploredDir.includes('/')) { + let currentFolder: string = Path.convertToSlashes(currentWorkingDirectory); + while (currentFolder.includes('/')) { // Look for a rush.json [rush project] or pnpm-lock.yaml file [regular pnpm workspace] - const rushJsonPath: string = path.resolve(currExploredDir, 'rush.json'); - const pnpmLockPath: string = path.resolve(currExploredDir, 'pnpm-lock.yaml'); + const rushJsonPath: string = currentFolder + '/rush.json'; + const pnpmLockPath: string = currentFolder + '/pnpm-lock.yaml'; if (FileSystem.exists(rushJsonPath)) { console.log('Found a Rush workspace: ', rushJsonPath); - const rushConfiguration: RushConfiguration = RushConfiguration.tryLoadFromDefaultLocation()!; + const rushConfiguration: RushConfiguration = RushConfiguration.loadFromConfigurationFile(rushJsonPath); const subspace: Subspace = rushConfiguration.getSubspace(subspaceName); const workspaceFolder: string = subspace.getSubspaceTempFolderPath(); - const projectsByProjectFolder: Map = new Map(); - for (const project of rushConfiguration.projects) { - projectsByProjectFolder.set(project.projectFolder, { - projectName: project.packageName, - projectFolder: project.projectFolder - }); - } - + const pnpmLockfileLocation: string = path.resolve(workspaceFolder, 'pnpm-lock.yaml'); appState = { - currDir, + currentWorkingDirectory, appVersion, debugMode, lockfileExplorerProjectRoot, - projectType: ProjectType.RUSH_PROJECT, - pnpmLockfileLocation: path.resolve(workspaceFolder, 'pnpm-lock.yaml'), - pnpmfileLocation: path.resolve(workspaceFolder, '.pnpmfile.cjs'), - projectRoot: currExploredDir, - rush: { - rushJsonPath, - projectsByProjectFolder + pnpmLockfileLocation, + pnpmfileLocation: workspaceFolder + '/.pnpmfile.cjs', + projectRoot: currentFolder, + lfxWorkspace: { + workspaceRootFolder: currentFolder, + pnpmLockfilePath: Path.convertToSlashes(path.relative(currentFolder, pnpmLockfileLocation)), + rushConfig: { + rushVersion: rushConfiguration.rushConfigurationJson.rushVersion, + subspaceName: subspaceName ?? '' + } } }; break; } else if (FileSystem.exists(pnpmLockPath)) { appState = { - currDir, + currentWorkingDirectory, appVersion, debugMode, lockfileExplorerProjectRoot, - projectType: ProjectType.PNPM_WORKSPACE, - pnpmLockfileLocation: path.resolve(currExploredDir, 'pnpm-lock.yaml'), - pnpmfileLocation: path.resolve(currExploredDir, '.pnpmfile.cjs'), - projectRoot: currExploredDir + pnpmLockfileLocation: currentFolder + '/pnpm-lock.yaml', + pnpmfileLocation: currentFolder + '/.pnpmfile.cjs', + projectRoot: currentFolder, + lfxWorkspace: { + workspaceRootFolder: currentFolder, + pnpmLockfilePath: Path.convertToSlashes(path.relative(currentFolder, pnpmLockPath)), + rushConfig: undefined + } }; break; } - currExploredDir = currExploredDir.substring(0, currExploredDir.lastIndexOf('/')); + currentFolder = currentFolder.substring(0, currentFolder.lastIndexOf('/')); } if (!appState) { diff --git a/build-tests-samples/heft-storybook-react-tutorial/package.json b/build-tests-samples/heft-storybook-react-tutorial/package.json index b6c6f330ae7..b13e1793757 100644 --- a/build-tests-samples/heft-storybook-react-tutorial/package.json +++ b/build-tests-samples/heft-storybook-react-tutorial/package.json @@ -14,7 +14,7 @@ "dependencies": { "react-dom": "~17.0.2", "react": "~17.0.2", - "tslib": "~2.3.1" + "tslib": "~2.8.1" }, "devDependencies": { "@babel/core": "~7.20.0", diff --git a/build-tests-samples/heft-web-rig-app-tutorial/package.json b/build-tests-samples/heft-web-rig-app-tutorial/package.json index 9f89a388039..ebc46f5c98c 100644 --- a/build-tests-samples/heft-web-rig-app-tutorial/package.json +++ b/build-tests-samples/heft-web-rig-app-tutorial/package.json @@ -13,7 +13,7 @@ "heft-web-rig-library-tutorial": "workspace:*", "react": "~17.0.2", "react-dom": "~17.0.2", - "tslib": "~2.3.1" + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", diff --git a/build-tests-samples/heft-web-rig-library-tutorial/package.json b/build-tests-samples/heft-web-rig-library-tutorial/package.json index 1dffed1a3a9..9832895cac8 100644 --- a/build-tests-samples/heft-web-rig-library-tutorial/package.json +++ b/build-tests-samples/heft-web-rig-library-tutorial/package.json @@ -15,7 +15,7 @@ "dependencies": { "react": "~17.0.2", "react-dom": "~17.0.2", - "tslib": "~2.3.1" + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft-web-rig": "workspace:*", diff --git a/build-tests-samples/heft-webpack-basic-tutorial/package.json b/build-tests-samples/heft-webpack-basic-tutorial/package.json index 4594196400a..70a7260797c 100644 --- a/build-tests-samples/heft-webpack-basic-tutorial/package.json +++ b/build-tests-samples/heft-webpack-basic-tutorial/package.json @@ -12,7 +12,7 @@ "dependencies": { "react-dom": "~17.0.2", "react": "~17.0.2", - "tslib": "~2.3.1" + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft-jest-plugin": "workspace:*", diff --git a/common/changes/@microsoft/rush/octogonz-lfx-fixes_2025-09-13-23-34.json b/common/changes/@microsoft/rush/octogonz-lfx-fixes_2025-09-13-23-34.json new file mode 100644 index 00000000000..bd7ff97cb34 --- /dev/null +++ b/common/changes/@microsoft/rush/octogonz-lfx-fixes_2025-09-13-23-34.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@microsoft/rush", + "comment": "", + "type": "none" + } + ], + "packageName": "@microsoft/rush" +} \ No newline at end of file diff --git a/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-fixes_2025-09-13-23-34.json b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-fixes_2025-09-13-23-34.json new file mode 100644 index 00000000000..d1f75fa99d2 --- /dev/null +++ b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-fixes_2025-09-13-23-34.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/lockfile-explorer", + "comment": "Refactoring to support future work", + "type": "patch" + } + ], + "packageName": "@rushstack/lockfile-explorer" +} \ No newline at end of file diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index 9f808d8cd08..8331a3ef056 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -284,6 +284,9 @@ importers: redux: specifier: ~4.2.0 version: 4.2.1 + tslib: + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -300,6 +303,9 @@ importers: local-web-rig: specifier: workspace:* version: link:../../rigs/local-web-rig + typescript: + specifier: 5.8.2 + version: 5.8.2 ../../../apps/rundown: dependencies: @@ -584,8 +590,8 @@ importers: specifier: ~17.0.2 version: 17.0.2(react@17.0.2) tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@babel/core': specifier: ~7.20.0 @@ -757,8 +763,8 @@ importers: specifier: ~17.0.2 version: 17.0.2(react@17.0.2) tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -791,8 +797,8 @@ importers: specifier: ~17.0.2 version: 17.0.2(react@17.0.2) tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -825,8 +831,8 @@ importers: specifier: ~17.0.2 version: 17.0.2(react@17.0.2) tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -4634,8 +4640,8 @@ importers: specifier: workspace:* version: link:../vscode-shared tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -4683,8 +4689,8 @@ importers: specifier: 0.19.0 version: 0.19.0 tslib: - specifier: ~2.3.1 - version: 2.3.1 + specifier: ~2.8.1 + version: 2.8.1 devDependencies: '@rushstack/heft': specifier: workspace:* @@ -5353,7 +5359,7 @@ packages: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' @@ -5402,7 +5408,7 @@ packages: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sts' - aws-crt @@ -5449,7 +5455,7 @@ packages: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - aws-crt dev: true @@ -5496,7 +5502,7 @@ packages: '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -5512,7 +5518,7 @@ packages: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 fast-xml-parser: 4.2.5 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/credential-provider-env@3.567.0: @@ -5522,7 +5528,7 @@ packages: '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/credential-provider-http@3.567.0: @@ -5537,7 +5543,7 @@ packages: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/credential-provider-ini@3.567.0(@aws-sdk/client-sso-oidc@3.567.0)(@aws-sdk/client-sts@3.567.0): @@ -5556,7 +5562,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -5577,7 +5583,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - '@aws-sdk/client-sts' @@ -5592,7 +5598,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/credential-provider-sso@3.567.0(@aws-sdk/client-sso-oidc@3.567.0): @@ -5605,7 +5611,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - '@aws-sdk/client-sso-oidc' - aws-crt @@ -5621,7 +5627,7 @@ packages: '@aws-sdk/types': 3.567.0 '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/middleware-host-header@3.567.0: @@ -5631,7 +5637,7 @@ packages: '@aws-sdk/types': 3.567.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/middleware-logger@3.567.0: @@ -5640,7 +5646,7 @@ packages: dependencies: '@aws-sdk/types': 3.567.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/middleware-recursion-detection@3.567.0: @@ -5650,7 +5656,7 @@ packages: '@aws-sdk/types': 3.567.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/middleware-user-agent@3.567.0: @@ -5661,7 +5667,7 @@ packages: '@aws-sdk/util-endpoints': 3.567.0 '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/region-config-resolver@3.567.0: @@ -5673,7 +5679,7 @@ packages: '@smithy/types': 2.12.0 '@smithy/util-config-provider': 2.3.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/token-providers@3.567.0(@aws-sdk/client-sso-oidc@3.567.0): @@ -5687,7 +5693,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/types@3.567.0: @@ -5695,7 +5701,7 @@ packages: engines: {node: '>=16.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/util-endpoints@3.567.0: @@ -5705,14 +5711,14 @@ packages: '@aws-sdk/types': 3.567.0 '@smithy/types': 2.12.0 '@smithy/util-endpoints': 1.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/util-locate-window@3.567.0: resolution: {integrity: sha512-o05vqq2+IdIHVqu2L28D1aVzZRkjheyQQE0kAIB+aS0fr4hYidsO2XqkXRRnhkaOxW3VN5/K/p2gxCaKt6A1XA==} engines: {node: '>=16.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/util-user-agent-browser@3.567.0: @@ -5721,7 +5727,7 @@ packages: '@aws-sdk/types': 3.567.0 '@smithy/types': 2.12.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/util-user-agent-node@3.567.0: @@ -5736,27 +5742,27 @@ packages: '@aws-sdk/types': 3.567.0 '@smithy/node-config-provider': 2.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@aws-sdk/util-utf8-browser@3.259.0: resolution: {integrity: sha512-UvFa/vR+e19XookZF8RzFZBrw2EUkQWxiBW0yYQAhvk3C+QVGl0H3ouca8LDBlBfQKXwmW3huo/59H8rwb1wJw==} dependencies: - tslib: 2.3.1 + tslib: 2.8.1 dev: true /@azure/abort-controller@2.1.0: resolution: {integrity: sha512-SYtcG13aiV7znycu6plCClWUzD9BBtfnsbIxT89nkkRvQRB4n0kuZyJJvJ7hqdKOn7x7YoGKZ9lVStLJpLnOFw==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/abort-controller@2.1.2: resolution: {integrity: sha512-nBrLsEWm4J2u5LpAPjxADTlq3trDgVZZXHNKabeXZtpq3d3AbN/KGO82R87rdDz5/lYB024rtEf10/q0urNgsA==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-auth@1.7.0: @@ -5765,7 +5771,7 @@ packages: dependencies: '@azure/abort-controller': 2.1.2 '@azure/core-util': 1.8.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-auth@1.9.0: @@ -5774,7 +5780,7 @@ packages: dependencies: '@azure/abort-controller': 2.1.0 '@azure/core-util': 1.11.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-client@1.9.0: @@ -5787,7 +5793,7 @@ packages: '@azure/core-tracing': 1.2.0 '@azure/core-util': 1.8.0 '@azure/logger': 1.1.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -5802,7 +5808,7 @@ packages: '@azure/core-tracing': 1.1.0 '@azure/core-util': 1.11.0 '@azure/logger': 1.1.0 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -5825,14 +5831,14 @@ packages: '@azure/abort-controller': 2.1.2 '@azure/core-util': 1.8.0 '@azure/logger': 1.1.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-paging@1.6.0: resolution: {integrity: sha512-W8eRv7MVFx/jbbYfcRT5+pGnZ9St/P1UvOi+63vxPwuQ3y+xj+wqWTGxpkXUETv3szsqGu0msdxVtjszCeB4zA==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-rest-pipeline@1.15.0: @@ -5846,7 +5852,7 @@ packages: '@azure/logger': 1.1.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.4 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -5862,7 +5868,7 @@ packages: '@azure/logger': 1.1.0 http-proxy-agent: 7.0.2 https-proxy-agent: 7.0.4 - tslib: 2.6.2 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -5871,14 +5877,14 @@ packages: resolution: {integrity: sha512-MVeJvGHB4jmF7PeHhyr72vYJsBJ3ff1piHikMgRaabPAC4P3rxhf9fm42I+DixLysBunskJWhsDQD2A+O+plkQ==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-tracing@1.2.0: resolution: {integrity: sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-util@1.11.0: @@ -5886,7 +5892,7 @@ packages: engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 2.1.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-util@1.8.0: @@ -5894,7 +5900,7 @@ packages: engines: {node: '>=18.0.0'} dependencies: '@azure/abort-controller': 2.1.2 - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/core-xml@1.4.4: @@ -5902,7 +5908,7 @@ packages: engines: {node: '>=18.0.0'} dependencies: fast-xml-parser: 4.5.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/identity@4.5.0: @@ -5922,7 +5928,7 @@ packages: jws: 4.0.0 open: 8.4.2 stoppable: 1.1.0 - tslib: 2.3.1 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -5931,7 +5937,7 @@ packages: resolution: {integrity: sha512-BnfkfzVEsrgbVCtqq0RYRMePSH2lL/cgUUR5sYRF4yNN10zJZq/cODz0r89k3ykY83MqeM3twR292a3YBNgC3w==} engines: {node: '>=18.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@azure/msal-browser@3.27.0: @@ -5971,7 +5977,7 @@ packages: '@azure/core-xml': 1.4.4 '@azure/logger': 1.1.0 events: 3.3.0 - tslib: 2.3.1 + tslib: 2.8.1 transitivePeerDependencies: - supports-color dev: false @@ -8159,14 +8165,14 @@ packages: resolution: {integrity: sha512-l+mLfJ2VhdHjBpELLLPDaWgT7GMLynm2aqR7SttbEb6Jh7hc/7ck1MWm93RTb3gYVHYai8SENqimNcvIxHt/zg==} dependencies: '@fluentui/set-version': 8.2.14 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/dom-utilities@2.2.14: resolution: {integrity: sha512-+4DVm5sNfJh+l8fM+7ylpOkGNZkNr4X1z1uKQPzRJ1PRhlnvc6vLpWNNicGwpjTbgufSrVtGKXwP5sf++r81lg==} dependencies: '@fluentui/set-version': 8.2.14 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/font-icons-mdl2@8.5.33(@types/react@17.0.74)(react@17.0.2): @@ -8175,7 +8181,7 @@ packages: '@fluentui/set-version': 8.2.14 '@fluentui/style-utilities': 8.10.4(@types/react@17.0.74)(react@17.0.2) '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) - tslib: 2.3.1 + tslib: 2.8.1 transitivePeerDependencies: - '@types/react' - react @@ -8193,13 +8199,13 @@ packages: '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) '@types/react': 17.0.74 react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/keyboard-key@0.4.14: resolution: {integrity: sha512-XzZHcyFEM20H23h3i15UpkHi2AhRBriXPGAHq0Jm98TKFppXehedjjEFuUsh+CyU5JKBhDalWp8TAQ1ArpNzow==} dependencies: - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/keyboard-keys@9.0.7: @@ -8212,7 +8218,7 @@ packages: resolution: {integrity: sha512-Si54VVK/XZQMTPT6aKE/RmqsY7uy9hERreU143Fbqtg9cf+Hr4iJ7FOGC4dXCfrFIXs0KvIHXCh5mtfrEW2aRQ==} dependencies: '@fluentui/set-version': 8.2.14 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/priority-overflow@9.1.11: @@ -8632,7 +8638,7 @@ packages: '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) '@types/react': 17.0.74 react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/react-hooks@8.6.37(@types/react@17.0.74)(react@17.0.2): @@ -8646,7 +8652,7 @@ packages: '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) '@types/react': 17.0.74 react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/react-icons@2.0.232(react@17.0.2): @@ -8656,7 +8662,7 @@ packages: dependencies: '@griffel/react': 1.5.20(react@17.0.2) react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/react-image@9.1.62(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): @@ -9450,7 +9456,7 @@ packages: '@fluentui/set-version': 8.2.14 '@types/react': 17.0.74 react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/react@8.115.7(@types/react-dom@17.0.25)(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): @@ -9478,13 +9484,13 @@ packages: '@types/react-dom': 17.0.25 react: 17.0.2 react-dom: 17.0.2(react@17.0.2) - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/set-version@8.2.14: resolution: {integrity: sha512-f/QWJnSeyfAjGAqq57yjMb6a5ejPlwfzdExPmzFBuEOuupi8hHbV8Yno12XJcTW4I0KXEQGw+PUaM1aOf/j7jw==} dependencies: - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/style-utilities@8.10.4(@types/react@17.0.74)(react@17.0.2): @@ -9495,7 +9501,7 @@ packages: '@fluentui/theme': 2.6.42(@types/react@17.0.74)(react@17.0.2) '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) '@microsoft/load-themed-styles': 1.10.295 - tslib: 2.3.1 + tslib: 2.8.1 transitivePeerDependencies: - '@types/react' - react @@ -9512,7 +9518,7 @@ packages: '@fluentui/utilities': 8.14.0(@types/react@17.0.74)(react@17.0.2) '@types/react': 17.0.74 react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@fluentui/tokens@1.0.0-alpha.16: @@ -9532,7 +9538,7 @@ packages: '@fluentui/set-version': 8.2.14 '@types/react': 17.0.74 react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@gar/promisify@1.1.3: @@ -9547,7 +9553,7 @@ packages: csstype: 3.1.3 rtl-css-js: 1.16.1 stylis: 4.3.1 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@griffel/react@1.5.20(react@17.0.2): @@ -9557,7 +9563,7 @@ packages: dependencies: '@griffel/core': 1.15.2 react: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /@griffel/style-types@1.0.3: @@ -10130,33 +10136,33 @@ packages: dependencies: jsep: 1.4.0 - /@jsonjoy.com/base64@1.1.2(tslib@2.3.1): + /@jsonjoy.com/base64@1.1.2(tslib@2.8.1): resolution: {integrity: sha512-q6XAnWQDIMA3+FTiOYajoYqySkO+JSat0ytXGSuRdq9uXE7o92gzuQwQM14xaCRlBLGq3v5miDGC4vkVTn54xA==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' dependencies: - tslib: 2.3.1 + tslib: 2.8.1 - /@jsonjoy.com/json-pack@1.1.0(tslib@2.3.1): + /@jsonjoy.com/json-pack@1.1.0(tslib@2.8.1): resolution: {integrity: sha512-zlQONA+msXPPwHWZMKFVS78ewFczIll5lXiVPwFPCZUsrOKdxc2AvxU1HoNBmMRhqDZUR9HkC3UOm+6pME6Xsg==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' dependencies: - '@jsonjoy.com/base64': 1.1.2(tslib@2.3.1) - '@jsonjoy.com/util': 1.3.0(tslib@2.3.1) + '@jsonjoy.com/base64': 1.1.2(tslib@2.8.1) + '@jsonjoy.com/util': 1.3.0(tslib@2.8.1) hyperdyperid: 1.2.0 - thingies: 1.21.0(tslib@2.3.1) - tslib: 2.3.1 + thingies: 1.21.0(tslib@2.8.1) + tslib: 2.8.1 - /@jsonjoy.com/util@1.3.0(tslib@2.3.1): + /@jsonjoy.com/util@1.3.0(tslib@2.8.1): resolution: {integrity: sha512-Cebt4Vk7k1xHy87kHY7KSPLT77A7Ev7IfOblyLZhtYEhrdQ6fX4EoLq3xOQ3O/DRMEh2ok5nyC180E+ABS8Wmw==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' dependencies: - tslib: 2.3.1 + tslib: 2.8.1 /@leichtgewicht/ip-codec@2.0.4: resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} @@ -11783,7 +11789,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/config-resolver@2.2.0: @@ -11794,7 +11800,7 @@ packages: '@smithy/types': 2.12.0 '@smithy/util-config-provider': 2.3.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/core@1.4.2: @@ -11808,7 +11814,7 @@ packages: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/credential-provider-imds@2.3.0: @@ -11819,7 +11825,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/types': 2.12.0 '@smithy/url-parser': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/fetch-http-handler@2.5.0: @@ -11829,7 +11835,7 @@ packages: '@smithy/querystring-builder': 2.2.0 '@smithy/types': 2.12.0 '@smithy/util-base64': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/hash-node@2.2.0: @@ -11839,21 +11845,21 @@ packages: '@smithy/types': 2.12.0 '@smithy/util-buffer-from': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/invalid-dependency@2.2.0: resolution: {integrity: sha512-nEDASdbKFKPXN2O6lOlTgrEEOO9NHIeO+HVvZnkqc8h5U9g3BIhWsvzFo+UcUbliMHvKNPD/zVxDrkP1Sbgp8Q==} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/is-array-buffer@2.2.0: resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/middleware-content-length@2.2.0: @@ -11862,7 +11868,7 @@ packages: dependencies: '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/middleware-endpoint@2.5.1: @@ -11875,7 +11881,7 @@ packages: '@smithy/types': 2.12.0 '@smithy/url-parser': 2.2.0 '@smithy/util-middleware': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/middleware-retry@2.3.1: @@ -11889,7 +11895,7 @@ packages: '@smithy/types': 2.12.0 '@smithy/util-middleware': 2.2.0 '@smithy/util-retry': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 uuid: 9.0.1 dev: true @@ -11898,7 +11904,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/middleware-stack@2.2.0: @@ -11906,7 +11912,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/node-config-provider@2.3.0: @@ -11916,7 +11922,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/shared-ini-file-loader': 2.4.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/node-http-handler@2.5.0: @@ -11927,7 +11933,7 @@ packages: '@smithy/protocol-http': 3.3.0 '@smithy/querystring-builder': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/property-provider@2.2.0: @@ -11935,7 +11941,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/protocol-http@3.3.0: @@ -11943,7 +11949,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/querystring-builder@2.2.0: @@ -11952,7 +11958,7 @@ packages: dependencies: '@smithy/types': 2.12.0 '@smithy/util-uri-escape': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/querystring-parser@2.2.0: @@ -11960,7 +11966,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/service-error-classification@2.1.5: @@ -11975,7 +11981,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/signature-v4@2.3.0: @@ -11988,7 +11994,7 @@ packages: '@smithy/util-middleware': 2.2.0 '@smithy/util-uri-escape': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/smithy-client@2.5.1: @@ -12000,14 +12006,14 @@ packages: '@smithy/protocol-http': 3.3.0 '@smithy/types': 2.12.0 '@smithy/util-stream': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/types@2.12.0: resolution: {integrity: sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/url-parser@2.2.0: @@ -12015,7 +12021,7 @@ packages: dependencies: '@smithy/querystring-parser': 2.2.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-base64@2.3.0: @@ -12024,20 +12030,20 @@ packages: dependencies: '@smithy/util-buffer-from': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-body-length-browser@2.2.0: resolution: {integrity: sha512-dtpw9uQP7W+n3vOtx0CfBD5EWd7EPdIdsQnWTDoFf77e3VUf05uA7R7TGipIo8e4WL2kuPdnsr3hMQn9ziYj5w==} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-body-length-node@2.3.0: resolution: {integrity: sha512-ITWT1Wqjubf2CJthb0BuT9+bpzBfXeMokH/AAa5EJQgbv9aPMVfnM76iFIZVFf50hYXGbtiV71BHAthNWd6+dw==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-buffer-from@2.2.0: @@ -12045,14 +12051,14 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/is-array-buffer': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-config-provider@2.3.0: resolution: {integrity: sha512-HZkzrRcuFN1k70RLqlNK4FnPXKOpkik1+4JaBoHNJn+RnJGYqaa3c5/+XtLOXhlKzlRgNvyaLieHTW2VwGN0VQ==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-defaults-mode-browser@2.2.1: @@ -12063,7 +12069,7 @@ packages: '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 bowser: 2.11.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-defaults-mode-node@2.3.1: @@ -12076,7 +12082,7 @@ packages: '@smithy/property-provider': 2.2.0 '@smithy/smithy-client': 2.5.1 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-endpoints@1.2.0: @@ -12085,14 +12091,14 @@ packages: dependencies: '@smithy/node-config-provider': 2.3.0 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-hex-encoding@2.2.0: resolution: {integrity: sha512-7iKXR+/4TpLK194pVjKiasIyqMtTYJsgKgM242Y9uzt5dhHnUDvMNb+3xIhRJ9QhvqGii/5cRUt4fJn3dtXNHQ==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-middleware@2.2.0: @@ -12100,7 +12106,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-retry@2.2.0: @@ -12109,7 +12115,7 @@ packages: dependencies: '@smithy/service-error-classification': 2.1.5 '@smithy/types': 2.12.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-stream@2.2.0: @@ -12123,14 +12129,14 @@ packages: '@smithy/util-buffer-from': 2.2.0 '@smithy/util-hex-encoding': 2.2.0 '@smithy/util-utf8': 2.3.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-uri-escape@2.2.0: resolution: {integrity: sha512-jtmJMyt1xMD/d8OtbVJ2gFZOSKc+ueYJZPW20ULW1GOp/q/YIM0wNh+u8ZFao9UaIGz4WoPW8hC64qlWLIfoDA==} engines: {node: '>=14.0.0'} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@smithy/util-utf8@2.3.0: @@ -12138,7 +12144,7 @@ packages: engines: {node: '>=14.0.0'} dependencies: '@smithy/util-buffer-from': 2.2.0 - tslib: 2.6.2 + tslib: 2.8.1 dev: true /@storybook/addon-actions@6.4.22(@types/react@17.0.74)(react-dom@17.0.2)(react@17.0.2): @@ -13233,7 +13239,7 @@ packages: flat-cache: 3.2.0 micromatch: 4.0.5 react-docgen-typescript: 2.2.2(typescript@5.8.2) - tslib: 2.3.1 + tslib: 2.8.1 typescript: 5.8.2 webpack: 4.47.0 transitivePeerDependencies: @@ -13575,20 +13581,20 @@ packages: /@swc/helpers@0.4.14: resolution: {integrity: sha512-4C7nX/dvpzB7za4Ql9K81xK3HPxCpHMgwTZVyf+9JQ6VUbn9jjZVN7/Nkdz/Ugzs2CSjqnL/UPXroiVBVHUWUw==} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@swc/helpers@0.4.36: resolution: {integrity: sha512-5lxnyLEYFskErRPenYItLRSge5DjrJngYKdVjRSrWfza9G6KkgHEXi0vUZiyUeMU5JfXH1YnvXZzSp8ul88o2Q==} dependencies: legacy-swc-helpers: /@swc/helpers@0.4.14 - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@swc/helpers@0.5.7: resolution: {integrity: sha512-BVvNZhx362+l2tSwSuyEUV4h7+jk9raNdoTSdLfwTshXJSaGmYKluGRJznziCI3KX02Z19DdsQrdfrpXAU3Hfg==} dependencies: - tslib: 2.6.2 + tslib: 2.8.1 dev: false /@swc/types@0.1.19: @@ -15936,7 +15942,7 @@ packages: resolution: {integrity: sha512-O0yuUDnZeQDL+ncNGlJ78BiO4jnYI3bvMsD5prT0/nsgijG/LpNBIr63gTjVTNsiGkgQhiyCShTgxt8oXOrklA==} engines: {node: '>=4'} dependencies: - tslib: 2.3.1 + tslib: 2.8.1 dev: true /astral-regex@1.0.0: @@ -16877,7 +16883,7 @@ packages: resolution: {integrity: sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==} dependencies: pascal-case: 3.1.2 - tslib: 2.3.1 + tslib: 2.8.1 /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} @@ -18445,7 +18451,7 @@ packages: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: no-case: 3.0.4 - tslib: 2.3.1 + tslib: 2.8.1 /dot-prop@5.3.0: resolution: {integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==} @@ -18488,7 +18494,7 @@ packages: prop-types: 15.8.1 react: 17.0.2 react-is: 17.0.2 - tslib: 2.3.1 + tslib: 2.8.1 dev: true /dunder-proto@1.0.1: @@ -23965,7 +23971,7 @@ packages: /lower-case@2.0.2: resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} dependencies: - tslib: 2.3.1 + tslib: 2.8.1 /lowercase-keys@2.0.0: resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} @@ -24183,10 +24189,10 @@ packages: resolution: {integrity: sha512-74wDsex5tQDSClVkeK1vtxqYCAgCoXxx+K4NSHzgU/muYVYByFqa+0RnrPO9NM6naWm1+G9JmZ0p6QHhXmeYfA==} engines: {node: '>= 4.0.0'} dependencies: - '@jsonjoy.com/json-pack': 1.1.0(tslib@2.3.1) - '@jsonjoy.com/util': 1.3.0(tslib@2.3.1) - tree-dump: 1.0.2(tslib@2.3.1) - tslib: 2.3.1 + '@jsonjoy.com/json-pack': 1.1.0(tslib@2.8.1) + '@jsonjoy.com/util': 1.3.0(tslib@2.8.1) + tree-dump: 1.0.2(tslib@2.8.1) + tslib: 2.8.1 /memoizerific@1.11.3: resolution: {integrity: sha512-/EuHYwAPdLtXwAwSZkh/Gutery6pD2KYd44oQLhAvQp/50mpyduZh8Q7PYHXTCJ+wuXxt7oij2LXyIJOOYFPog==} @@ -24674,7 +24680,7 @@ packages: resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} dependencies: lower-case: 2.0.2 - tslib: 2.3.1 + tslib: 2.8.1 /node-abi@3.56.0: resolution: {integrity: sha512-fZjdhDOeRcaS+rcpve7XuwHBmktS1nS1gzgghwKUQQ8nTy2FdSDr6ZT8k6YhvlJeHmmQMYiT/IH9hfco5zeW2Q==} @@ -25330,7 +25336,7 @@ packages: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} dependencies: dot-case: 3.0.4 - tslib: 2.3.1 + tslib: 2.8.1 /parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} @@ -25414,7 +25420,7 @@ packages: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} dependencies: no-case: 3.0.4 - tslib: 2.3.1 + tslib: 2.8.1 /pascalcase@0.1.1: resolution: {integrity: sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw==} @@ -26859,7 +26865,7 @@ packages: ast-types: 0.14.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.3.1 + tslib: 2.8.1 dev: true /rechoir@0.6.2: @@ -27308,7 +27314,7 @@ packages: /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} dependencies: - tslib: 2.3.1 + tslib: 2.8.1 dev: false /safe-array-concat@1.1.2: @@ -28825,7 +28831,7 @@ packages: resolution: {integrity: sha512-wTPy2d6WVmU/YjT0ERY9jc+et1P/B8FoSQ4qhr1xi7liwTezRbRV6yA1pKx8kdPWmLdIOBA4fn07x9c0x/wnow==} dependencies: keyborg: 2.5.0 - tslib: 2.3.1 + tslib: 2.8.1 dev: false /tapable@1.1.3: @@ -29041,13 +29047,13 @@ packages: any-promise: 1.3.0 dev: false - /thingies@1.21.0(tslib@2.3.1): + /thingies@1.21.0(tslib@2.8.1): resolution: {integrity: sha512-hsqsJsFMsV+aD4s3CWKk85ep/3I9XzYV/IXaSouJMYIoDlgyi11cBhsqYe9/geRfB0YIikBQg6raRaM+nIMP9g==} engines: {node: '>=10.18'} peerDependencies: tslib: ^2 dependencies: - tslib: 2.3.1 + tslib: 2.8.1 /throat@6.0.2: resolution: {integrity: sha512-WKexMoJj3vEuK0yFEapj8y64V0A6xcuPuK9Gt1d0R+dzCSJc0lHqQytAbSB4cDAK0dWh4T0E2ETkoLE2WZ41OQ==} @@ -29182,13 +29188,13 @@ packages: resolution: {integrity: sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==} dev: true - /tree-dump@1.0.2(tslib@2.3.1): + /tree-dump@1.0.2(tslib@2.8.1): resolution: {integrity: sha512-dpev9ABuLWdEubk+cIaI9cHwRNNDjkBBLXTwI4UCUFdQ5xXKqNXoK4FEciw/vxf+NQ7Cb7sGUyeUtORvHIdRXQ==} engines: {node: '>=10.0'} peerDependencies: tslib: '2' dependencies: - tslib: 2.3.1 + tslib: 2.8.1 /trim-newlines@3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} @@ -29281,15 +29287,12 @@ packages: /tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - /tslib@2.3.1: - resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} - /tslib@2.4.0: resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} dev: true - /tslib@2.6.2: - resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} + /tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} /tslint@5.20.1(typescript@2.9.2): resolution: {integrity: sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==} diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json index eef32ca157f..b484328badb 100644 --- a/common/config/subspaces/default/repo-state.json +++ b/common/config/subspaces/default/repo-state.json @@ -1,5 +1,5 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "6eb7f8d5c5f93d8b7af7074cd5b2d499e9f06a76", + "pnpmShrinkwrapHash": "0514179437811ed9b568114b19d8ecf0943f75dc", "preferredVersionsHash": "61cd419c533464b580f653eb5f5a7e27fe7055ca" } diff --git a/libraries/rush-lib/src/api/Subspace.ts b/libraries/rush-lib/src/api/Subspace.ts index 34476e5046c..7ec49d40558 100644 --- a/libraries/rush-lib/src/api/Subspace.ts +++ b/libraries/rush-lib/src/api/Subspace.ts @@ -198,7 +198,10 @@ export class Subspace { * Returns the full path of the folder containing this subspace's variant-dependent configuration files * such as `pnpm-lock.yaml`. * - * Example: `common/config/subspaces/my-subspace` or `common/config/subspaces/my-subspace/variants/my-variant` + * Example (variants): `C:\MyRepo\common\config\rush\variants\my-variant` + * Example (variants and subspaces): `C:\MyRepo\common\config\subspaces\my-subspace\variants\my-variant` + * Example (subspaces): `C:\MyRepo\common\config\subspaces\my-subspace` + * Example (neither): `C:\MyRepo\common\config\rush` * @beta * * @remarks @@ -219,7 +222,8 @@ export class Subspace { /** * Returns the full path of the folder containing this subspace's configuration files such as `pnpm-lock.yaml`. * - * Example: `common/config/subspaces/my-subspace` + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace` + * Example (subspaces feature disabled): `C:\MyRepo\common\config\rush` * @beta */ public getSubspaceConfigFolderPath(): string { @@ -229,8 +233,8 @@ export class Subspace { /** * Returns the full path of the folder containing this subspace's configuration files such as `pnpm-lock.yaml`. * - * Example: `common/config/subspaces/my-subspace/pnpm-patches` (subspaces feature enabled) - * Example: `common/config/pnpm-patches` (subspaces feature disabled) + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace\pnpm-patches` + * Example (subspaces feature disabled): `C:\MyRepo\common\pnpm-patches` * @beta */ public getSubspacePnpmPatchesFolderPath(): string { @@ -238,9 +242,10 @@ export class Subspace { } /** - * The folder where the subspace's node_modules and other temporary files will be stored. + * The full path of the folder where the subspace's node_modules and other temporary files will be stored. * - * Example: `common/temp/subspaces/my-subspace` + * Example (subspaces feature enabled): `C:\MyRepo\common\temp\subspaces\my-subspace` + * Example (subspaces feature disabled): `C:\MyRepo\common\temp` * @beta */ public getSubspaceTempFolderPath(): string { @@ -284,9 +289,10 @@ export class Subspace { } /** - * Gets the path to the common-versions.json config file for this subspace. + * Gets the full path to the common-versions.json config file for this subspace. * - * Example: `C:\MyRepo\common\subspaces\my-subspace\common-versions.json` + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace\common-versions.json` + * Example (subspaces feature disabled): `C:\MyRepo\common\config\rush\common-versions.json` * @beta */ public getCommonVersionsFilePath(variant?: string): string { @@ -296,9 +302,10 @@ export class Subspace { } /** - * Gets the path to the pnpm-config.json config file for this subspace. + * Gets the full path to the pnpm-config.json config file for this subspace. * - * Example: `C:\MyRepo\common\subspaces\my-subspace\pnpm-config.json` + * Example (subspaces feature enabled): `C:\MyRepo\common\config\subspaces\my-subspace\pnpm-config.json` + * Example (subspaces feature disabled): `C:\MyRepo\common\config\rush\pnpm-config.json` * @beta */ public getPnpmConfigFilePath(): string { diff --git a/vscode-extensions/debug-certificate-manager-vscode-extension/package.json b/vscode-extensions/debug-certificate-manager-vscode-extension/package.json index 83f51d8d6be..ab9fd0b720d 100644 --- a/vscode-extensions/debug-certificate-manager-vscode-extension/package.json +++ b/vscode-extensions/debug-certificate-manager-vscode-extension/package.json @@ -114,7 +114,7 @@ "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", "@rushstack/vscode-shared": "workspace:*", - "tslib": "~2.3.1" + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft-vscode-extension-rig": "workspace:*", diff --git a/vscode-extensions/rush-vscode-command-webview/package.json b/vscode-extensions/rush-vscode-command-webview/package.json index c43c71bc3be..cbe5138da99 100644 --- a/vscode-extensions/rush-vscode-command-webview/package.json +++ b/vscode-extensions/rush-vscode-command-webview/package.json @@ -27,7 +27,7 @@ "react": "~17.0.2", "redux": "~4.2.0", "scheduler": "0.19.0", - "tslib": "~2.3.1" + "tslib": "~2.8.1" }, "devDependencies": { "@rushstack/heft": "workspace:*",