diff --git a/.gitignore b/.gitignore index a7871370954..18091f23d4e 100644 --- a/.gitignore +++ b/.gitignore @@ -107,6 +107,7 @@ common/autoinstallers/*/.npmrc *.lock # Common toolchain intermediate files +build/ temp/ lib/ lib-amd/ diff --git a/apps/api-documenter/package.json b/apps/api-documenter/package.json index 0e2e59990da..dedd7522377 100644 --- a/apps/api-documenter/package.json +++ b/apps/api-documenter/package.json @@ -25,12 +25,12 @@ "@rushstack/node-core-library": "workspace:*", "@rushstack/terminal": "workspace:*", "@rushstack/ts-command-line": "workspace:*", - "js-yaml": "~3.13.1", + "js-yaml": "~4.1.0", "resolve": "~1.22.1" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/js-yaml": "3.12.1", + "@types/js-yaml": "4.0.9", "@types/resolve": "1.20.2", "eslint": "~9.25.1", "local-node-rig": "workspace:*" diff --git a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts index 0050b7147ce..a080458ddb6 100644 --- a/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/OfficeYamlDocumenter.ts @@ -48,8 +48,8 @@ export class OfficeYamlDocumenter extends YamlDocumenter { console.log('Loading snippets from ' + snippetsFilePath); const snippetsContent: string = FileSystem.readFile(snippetsFilePath); - this._snippets = yaml.load(snippetsContent, { filename: snippetsFilePath }); - this._snippetsAll = yaml.load(snippetsContent, { filename: snippetsFilePath }); + this._snippets = yaml.load(snippetsContent, { filename: snippetsFilePath }) as ISnippetsFile; + this._snippetsAll = yaml.load(snippetsContent, { filename: snippetsFilePath }) as ISnippetsFile; } /** @override */ diff --git a/apps/api-documenter/src/documenters/YamlDocumenter.ts b/apps/api-documenter/src/documenters/YamlDocumenter.ts index b165622ce84..0d51be689f6 100644 --- a/apps/api-documenter/src/documenters/YamlDocumenter.ts +++ b/apps/api-documenter/src/documenters/YamlDocumenter.ts @@ -756,7 +756,7 @@ export class YamlDocumenter { ): void { JsonFile.validateNoUndefinedMembers(dataObject); - let stringified: string = yaml.safeDump(dataObject, { + let stringified: string = yaml.dump(dataObject, { lineWidth: 120 }); diff --git a/apps/api-documenter/src/utils/ToSdpConvertHelper.ts b/apps/api-documenter/src/utils/ToSdpConvertHelper.ts index 2de3530d9fc..73815485793 100644 --- a/apps/api-documenter/src/utils/ToSdpConvertHelper.ts +++ b/apps/api-documenter/src/utils/ToSdpConvertHelper.ts @@ -49,10 +49,10 @@ function convert(inputPath: string, outputPath: string): void { console.log(`convert file ${fpath} from udp to sdp`); - const file: IYamlApiFile = yaml.safeLoad(yamlContent) as IYamlApiFile; + const file: IYamlApiFile = yaml.load(yamlContent) as IYamlApiFile; const result: { model: CommonYamlModel; type: string } | undefined = convertToSDP(file); if (result && result.model) { - const stringified: string = `### YamlMime:TS${result.type}\n${yaml.safeDump(result.model, { + const stringified: string = `### YamlMime:TS${result.type}\n${yaml.dump(result.model, { lineWidth: 120 })}`; FileSystem.writeFile(`${outputPath}/${name}`, stringified, { diff --git a/apps/lockfile-explorer-web/eslint.config.js b/apps/lockfile-explorer-web/eslint.config.js index 4664e2044d7..9765c392aa3 100644 --- a/apps/lockfile-explorer-web/eslint.config.js +++ b/apps/lockfile-explorer-web/eslint.config.js @@ -3,10 +3,12 @@ const webAppProfile = require('local-web-rig/profiles/app/includes/eslint/flat/profile/web-app'); const reactMixin = require('local-web-rig/profiles/app/includes/eslint/flat/mixins/react'); +const packletsMixin = require('local-web-rig/profiles/app/includes/eslint/flat/mixins/packlets'); module.exports = [ ...webAppProfile, ...reactMixin, + packletsMixin, { files: ['**/*.ts', '**/*.tsx'], languageOptions: { diff --git a/apps/lockfile-explorer-web/package.json b/apps/lockfile-explorer-web/package.json index c6445b31fb0..59923434733 100644 --- a/apps/lockfile-explorer-web/package.json +++ b/apps/lockfile-explorer-web/package.json @@ -12,7 +12,6 @@ "_phase:test": "heft run --only test -- --clean" }, "dependencies": { - "@lifaon/path": "~2.1.0", "@reduxjs/toolkit": "~1.8.6", "@rushstack/rush-themed-ui": "workspace:*", "react-dom": "~17.0.2", diff --git a/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx b/apps/lockfile-explorer-web/src/containers/BookmarksSidebar/index.tsx index 3603d4dd56c..c15fd3772ed 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/LfxGraph'; +import type { LfxGraphEntry } from '../../packlets/lfx-shared'; import { clearStackAndPush, removeBookmark } from '../../store/slices/entrySlice'; import { Button, ScrollArea, Text } from '@rushstack/rush-themed-ui'; @@ -14,13 +14,13 @@ export const BookmarksSidebar = (): JSX.Element => { const dispatch = useAppDispatch(); const clear = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(clearStackAndPush(entry)); }, [dispatch] ); const deleteEntry = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(removeBookmark(entry)); }, [dispatch] diff --git a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx index 8e9b9b83b81..8b0fb3769e1 100644 --- a/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/LockfileEntryDetailsView/index.tsx @@ -3,14 +3,15 @@ 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 { DependencyKind, type LockfileDependency } from '../../parsing/LfxGraph'; + +import { LfxDependencyKind, type LfxGraphDependency, type LfxGraphEntry } from '../../packlets/lfx-shared'; 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/LfxGraph'; import { logDiagnosticInfo } from '../../helpers/logDiagnosticInfo'; import { displaySpecChanges } from '../../helpers/displaySpecChanges'; import type { IPackageJson } from '../../types/IPackageJson'; @@ -27,7 +28,7 @@ enum DependencyKey { } interface IInfluencerType { - entry: LockfileEntry; + entry: LfxGraphEntry; type: DependencyType; } @@ -36,14 +37,14 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { const specChanges = useAppSelector((state) => state.workspace.specChanges); const dispatch = useAppDispatch(); - const [inspectDependency, setInspectDependency] = useState(null); + const [inspectDependency, setInspectDependency] = useState(null); const [influencers, setInfluencers] = useState([]); const [directRefsPackageJSON, setDirectRefsPackageJSON] = useState>( new Map() ); useEffect(() => { - async function loadPackageJson(referrers: LockfileEntry[]): Promise { + async function loadPackageJson(referrers: LfxGraphEntry[]): Promise { const referrersJsonMap = new Map(); await Promise.all( referrers.map(async (ref) => { @@ -80,15 +81,15 @@ 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 !== DependencyKind.PEER_DEPENDENCY) { + if (dependencyToTrace.dependencyType !== LfxDependencyKind.Peer) { return; } // calculate influencers const stack = [selectedEntry]; - const determinants = new Set(); - const transitiveReferrers = new Set(); - const visitedNodes = new Set(); + const determinants = new Set(); + const transitiveReferrers = new Set(); + const visitedNodes = new Set(); visitedNodes.add(selectedEntry); while (stack.length) { const currEntry = stack.pop(); @@ -179,7 +180,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => { package.json spec:{' '} - {inspectDependency.dependencyType === DependencyKind.PEER_DEPENDENCY + {inspectDependency.dependencyType === LfxDependencyKind.Peer ? `"${inspectDependency.peerDependencyMeta.version}" ${ inspectDependency.peerDependencyMeta.optional ? 'Optional' : 'Required' } Peer` @@ -203,9 +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 === DependencyKind.PEER_DEPENDENCY - ); + const peerDeps = selectedEntry.dependencies.filter((d) => d.dependencyType === LfxDependencyKind.Peer); if (!peerDeps.length) { return (
@@ -213,7 +212,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
); } - if (!inspectDependency || inspectDependency.dependencyType !== DependencyKind.PEER_DEPENDENCY) { + if (!inspectDependency || inspectDependency.dependencyType !== LfxDependencyKind.Peer) { return (
Select a peer dependency to view its influencers @@ -301,7 +300,7 @@ export const LockfileEntryDetailsView = (): JSX.Element | ReactNull => {
- {selectedEntry.referrers?.map((referrer: LockfileEntry) => ( + {selectedEntry.referrers?.map((referrer: LfxGraphEntry) => (
{
- {selectedEntry.dependencies?.map((dependency: LockfileDependency) => ( + {selectedEntry.dependencies?.map((dependency: LfxGraphDependency) => (
{ > Name: {dependency.name}{' '} - {dependency.dependencyType === DependencyKind.PEER_DEPENDENCY + {dependency.dependencyType === LfxDependencyKind.Peer ? `${ 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 17176f29f48..bd90300589e 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/LfxGraph'; +import { type LfxGraphEntry, LfxGraphEntryKind } from '../../packlets/lfx-shared'; import { ReactNull } from '../../types/ReactNull'; import { useAppDispatch, useAppSelector } from '../../store/hooks'; import { @@ -17,7 +17,7 @@ import { Tabs, Checkbox, ScrollArea, Input, Text } from '@rushstack/rush-themed- interface ILockfileEntryGroup { entryName: string; - versions: LockfileEntry[]; + versions: LfxGraphEntry[]; } const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element => { @@ -26,7 +26,7 @@ const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element const dispatch = useAppDispatch(); const fieldRef = useRef() as React.MutableRefObject; const clear = useCallback( - (entry: LockfileEntry) => () => { + (entry: LfxGraphEntry) => () => { dispatch(pushToStack(entry)); }, [dispatch] @@ -40,7 +40,7 @@ const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element } }, [selectedEntry, group]); - if (activeFilters[LockfileEntryFilter.Project]) { + if (activeFilters[LfxGraphEntryKind.Project]) { return (
{group.versions.map((entry) => ( @@ -80,7 +80,7 @@ const LockfileEntryLi = ({ group }: { group: ILockfileEntryGroup }): JSX.Element ); }; -const multipleVersions = (entries: LockfileEntry[]): boolean => { +const multipleVersions = (entries: LfxGraphEntry[]): boolean => { const set = new Set(); for (const entry of entries) { if (set.has(entry.entryPackageVersion)) return true; @@ -96,8 +96,8 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { const entries = useAppSelector(selectFilteredEntries); const activeFilters = useAppSelector((state) => state.entry.filters); const updateFilter = useCallback( - (type: LockfileEntryFilter) => (e: React.ChangeEvent) => { - if (type === LockfileEntryFilter.Project) { + (type: LfxGraphEntryKind) => (e: React.ChangeEvent) => { + if (type === LfxGraphEntryKind.Project) { setProjectFilter(e.target.value); } else { setPackageFilter(e.target.value); @@ -108,19 +108,19 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { ); useEffect(() => { - setProjectFilter(getFilterFromLocalStorage(LockfileEntryFilter.Project)); - setPackageFilter(getFilterFromLocalStorage(LockfileEntryFilter.Package)); + setProjectFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Project)); + setPackageFilter(getFilterFromLocalStorage(LfxGraphEntryKind.Package)); }, []); const getEntriesToShow = (): ILockfileEntryGroup[] => { - let filteredEntries: LockfileEntry[] = entries; - if (projectFilter && activeFilters[LockfileEntryFilter.Project]) { + let filteredEntries: LfxGraphEntry[] = entries; + if (projectFilter && activeFilters[LfxGraphEntryKind.Project]) { filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(projectFilter) !== -1); - } else if (packageFilter && activeFilters[LockfileEntryFilter.Package]) { + } else if (packageFilter && activeFilters[LfxGraphEntryKind.Package]) { filteredEntries = entries.filter((entry) => entry.entryPackageName.indexOf(packageFilter) !== -1); } - const reducedEntries = filteredEntries.reduce((groups: { [key: string]: LockfileEntry[] }, item) => { + const reducedEntries = filteredEntries.reduce((groups: { [key: string]: LfxGraphEntry[] }, item) => { const group = groups[item.entryPackageName] || []; group.push(item); groups[item.entryPackageName] = group; @@ -134,14 +134,14 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { }); } - if (activeFilters[LockfileEntryFilter.SideBySide]) { + if (activeFilters[LfxGraphEntryKind.SideBySide]) { groupedEntries = groupedEntries.filter((entry) => entry.versions.length > 1); } - if (activeFilters[LockfileEntryFilter.Doppelganger]) { + if (activeFilters[LfxGraphEntryKind.Doppelganger]) { groupedEntries = groupedEntries.filter((entry) => multipleVersions(entry.versions)); } - if (activeFilters[LockfileEntryFilter.Project]) { + if (activeFilters[LfxGraphEntryKind.Project]) { groupedEntries = groupedEntries.sort((a, b) => a.entryName > b.entryName ? 1 : b.entryName > a.entryName ? -1 : 0 ); @@ -151,7 +151,7 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { }; const changeFilter = useCallback( - (filter: LockfileEntryFilter, enabled: boolean) => (): void => { + (filter: LfxGraphEntryKind, enabled: boolean) => (): void => { dispatch(selectFilter({ filter, state: enabled })); }, [dispatch] @@ -160,11 +160,11 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { const togglePackageView = useCallback( (selected: string) => { if (selected === 'Projects') { - dispatch(selectFilter({ filter: LockfileEntryFilter.Project, state: true })); - dispatch(selectFilter({ filter: LockfileEntryFilter.Package, state: false })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: false })); } else { - dispatch(selectFilter({ filter: LockfileEntryFilter.Package, state: true })); - dispatch(selectFilter({ filter: LockfileEntryFilter.Project, state: false })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Package, state: true })); + dispatch(selectFilter({ filter: LfxGraphEntryKind.Project, state: false })); } }, // eslint-disable-next-line react-hooks/exhaustive-deps @@ -186,17 +186,15 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { header: 'Packages' } ]} - value={activeFilters[LockfileEntryFilter.Project] ? 'Projects' : 'Packages'} + value={activeFilters[LfxGraphEntryKind.Project] ? 'Projects' : 'Packages'} onChange={togglePackageView} /> @@ -204,25 +202,25 @@ export const LockfileViewer = (): JSX.Element | ReactNull => { ))} - {activeFilters[LockfileEntryFilter.Package] ? ( + {activeFilters[LfxGraphEntryKind.Package] ? (
Filters
diff --git a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx index 071a3f20a8d..b7588f360a7 100644 --- a/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx +++ b/apps/lockfile-explorer-web/src/containers/PackageJsonViewer/index.tsx @@ -12,7 +12,7 @@ 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/LfxGraph'; +import { LfxGraphEntryKind } from '../../packlets/lfx-shared'; const PackageView: { [key: string]: string } = { PACKAGE_JSON: 'PACKAGE_JSON', @@ -186,7 +186,7 @@ export const PackageJsonViewer = (): JSX.Element => { Package Name: - {selectedEntry?.kind === LockfileEntryFilter.Project + {selectedEntry?.kind === LfxGraphEntryKind.Project ? parsedPackageJSON.name : selectedEntry?.displayText} diff --git a/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts b/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts index 53cdff9e4c4..9750281021a 100644 --- a/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts +++ b/apps/lockfile-explorer-web/src/helpers/isEntryModified.ts @@ -2,10 +2,10 @@ // See LICENSE in the project root for license information. import type { ISpecChange } from '../parsing/compareSpec'; -import type { LockfileEntry } from '../parsing/LfxGraph'; +import type { LfxGraphEntry } from '../packlets/lfx-shared'; export const isEntryModified = ( - entry: LockfileEntry | undefined, + entry: LfxGraphEntry | undefined, specChanges: Map ): boolean => { if (!entry) return false; diff --git a/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts b/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts index 14d694c9785..9cc6f469556 100644 --- a/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts +++ b/apps/lockfile-explorer-web/src/helpers/lfxApiClient.ts @@ -2,7 +2,7 @@ // See LICENSE in the project root for license information. import type { IPackageJson } from '../types/IPackageJson'; -import type { ILfxWorkspace } from '../types/lfxProtocol'; +import type { IJsonLfxWorkspace } from '../packlets/lfx-shared'; const SERVICE_URL: string = window.appContext.serviceUrl; @@ -19,7 +19,7 @@ export async function checkAliveAsync(): Promise { * 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 { +export async function readWorkspaceConfigAsync(): Promise { let response: Response; try { @@ -39,7 +39,7 @@ export async function readWorkspaceConfigAsync(): Promise { throw new Error('Network error: ' + (e.message || 'An unknown error occurred')); } - const responseJson: ILfxWorkspace = await response.json(); + const responseJson: IJsonLfxWorkspace = await response.json(); return responseJson; } diff --git a/apps/lockfile-explorer-web/src/helpers/localStorage.ts b/apps/lockfile-explorer-web/src/helpers/localStorage.ts index 77d703d859f..5242b4e368b 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/LfxGraph'; +import { type LfxGraphEntry, LfxGraphEntryKind } from '../packlets/lfx-shared'; const BOOKMARK_KEY: string = 'LOCKFILE_EXPLORER_BOOKMARKS'; @@ -14,14 +14,14 @@ export const getBookmarksFromStorage = (): Set => { return bookmarkSet; }; -export const saveBookmarkToLocalStorage = (entry: LockfileEntry): void => { +export const saveBookmarkToLocalStorage = (entry: LfxGraphEntry): void => { const key = entry.rawEntryId; const currBookmarks = JSON.parse(localStorage.getItem(BOOKMARK_KEY) || '{}'); currBookmarks[key] = true; localStorage.setItem(BOOKMARK_KEY, JSON.stringify(currBookmarks)); }; -export const removeBookmarkFromLocalStorage = (entry: LockfileEntry): void => { +export const removeBookmarkFromLocalStorage = (entry: LfxGraphEntry): void => { const key = entry.rawEntryId; const currBookmarks = JSON.parse(localStorage.getItem(BOOKMARK_KEY) || '{}'); delete currBookmarks[key]; @@ -30,16 +30,16 @@ export const removeBookmarkFromLocalStorage = (entry: LockfileEntry): void => { const PROJECT_FILTER_KEY: string = 'LOCKFILE_EXPLORER_PROJECT_FILTER'; const PACKAGE_FILTER_KEY: string = 'LOCKFILE_EXPLORER_PACKAGE_FILTER'; -export const saveFilterToLocalStorage = (filter: string, type: LockfileEntryFilter): void => { - if (type === LockfileEntryFilter.Project) { +export const saveFilterToLocalStorage = (filter: string, type: LfxGraphEntryKind): void => { + if (type === LfxGraphEntryKind.Project) { localStorage.setItem(PROJECT_FILTER_KEY, filter); } else { localStorage.setItem(PACKAGE_FILTER_KEY, filter); } }; -export const getFilterFromLocalStorage = (type: LockfileEntryFilter): string => { - if (type === LockfileEntryFilter.Project) { +export const getFilterFromLocalStorage = (type: LfxGraphEntryKind): string => { + if (type === LfxGraphEntryKind.Project) { return localStorage.getItem(PROJECT_FILTER_KEY) || ''; } else { return localStorage.getItem(PACKAGE_FILTER_KEY) || ''; diff --git a/apps/lockfile-explorer-web/src/types/IAppContext.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IAppContext.ts similarity index 100% rename from apps/lockfile-explorer-web/src/types/IAppContext.ts rename to apps/lockfile-explorer-web/src/packlets/lfx-shared/IAppContext.ts diff --git a/apps/lockfile-explorer-web/src/parsing/JsonLfxGraph.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts similarity index 75% rename from apps/lockfile-explorer-web/src/parsing/JsonLfxGraph.ts rename to apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts index 4bb82873b36..7632e332f8f 100644 --- a/apps/lockfile-explorer-web/src/parsing/JsonLfxGraph.ts +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxGraph.ts @@ -1,7 +1,14 @@ // 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'; +import type { IJsonLfxWorkspace } from './IJsonLfxWorkspace'; + +export enum LfxGraphEntryKind { + Project = 1, + Package = 2, + SideBySide = 3, + Doppelganger = 4 +} export interface IJsonPeerDependencyMeta { name?: string; @@ -13,13 +20,19 @@ export interface IJsonLfxDependency { name: string; version: string; entryId: string; - dependencyType: DependencyKind; + dependencyType: LfxDependencyKind; resolvedEntryJsonId?: number; peerDependencyMeta: IJsonPeerDependencyMeta; } +export enum LfxDependencyKind { + Regular = 'regular', + Dev = 'dev', + Peer = 'peer' +} + export interface IJsonLfxEntry { /** * A unique ID used when serializing graph links. @@ -30,7 +43,7 @@ export interface IJsonLfxEntry { */ jsonId: number; - kind: LockfileEntryFilter; + kind: LfxGraphEntryKind; entryId: string; rawEntryId: string; packageJsonFolderPath: string; @@ -46,5 +59,6 @@ export interface IJsonLfxEntry { } export interface IJsonLfxGraph { + workspace: IJsonLfxWorkspace; entries: IJsonLfxEntry[]; } diff --git a/apps/lockfile-explorer-web/src/types/lfxProtocol.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxWorkspace.ts similarity index 69% rename from apps/lockfile-explorer-web/src/types/lfxProtocol.ts rename to apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxWorkspace.ts index 04a1d793964..31c081d1c91 100644 --- a/apps/lockfile-explorer-web/src/types/lfxProtocol.ts +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/IJsonLfxWorkspace.ts @@ -1,34 +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 { +export interface IJsonLfxWorkspaceRushConfig { /** * The rushVersion from rush.json. */ - rushVersion: string; + readonly 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; + readonly subspaceName: string; } -export interface ILfxWorkspace { +export interface IJsonLfxWorkspace { /** * Absolute path to the workspace folder that is opened by the app. * Relative paths are generally relative to this path. */ - workspaceRootFolder: string; + readonly workspaceRootFolder: string; /** * The path to the pnpm-lock.yaml file. */ - pnpmLockfilePath: string; + readonly pnpmLockfilePath: string; /** * If this is a Rush workspace (versus a plain PNPM workspace), then * this section will be defined. */ - rushConfig: ILfxWorkspaceRushConfig | undefined; + readonly rushConfig: IJsonLfxWorkspaceRushConfig | undefined; } diff --git a/apps/lockfile-explorer-web/src/parsing/LfxGraph.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts similarity index 76% rename from apps/lockfile-explorer-web/src/parsing/LfxGraph.ts rename to apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts index 8cbfd4ee7ea..11ce9f58c98 100644 --- a/apps/lockfile-explorer-web/src/parsing/LfxGraph.ts +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/LfxGraph.ts @@ -1,19 +1,14 @@ // 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'; +import type { LfxDependencyKind, IJsonPeerDependencyMeta, LfxGraphEntryKind } from './IJsonLfxGraph'; +import type { IJsonLfxWorkspace } from './IJsonLfxWorkspace'; -export enum DependencyKind { - DEPENDENCY = 'regular', - DEV_DEPENDENCY = 'dev', - PEER_DEPENDENCY = 'peer' -} - -export interface ILockfileDependencyOptions { +export interface ILfxGraphDependencyOptions { name: string; version: string; - dependencyType: DependencyKind; - containingEntry: LockfileEntry; + dependencyType: LfxDependencyKind; + containingEntry: LfxGraphEntry; peerDependencyMeta: IJsonPeerDependencyMeta; entryId: string; } @@ -27,17 +22,17 @@ export interface ILockfileDependencyOptions { * 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 { +export class LfxGraphDependency { public readonly name: string; public readonly version: string; - public readonly dependencyType: DependencyKind; - public readonly containingEntry: LockfileEntry; + public readonly dependencyType: LfxDependencyKind; + public readonly containingEntry: LfxGraphEntry; public readonly entryId: string; public readonly peerDependencyMeta: IJsonPeerDependencyMeta; - public resolvedEntry: LockfileEntry | undefined = undefined; + public resolvedEntry: LfxGraphEntry | undefined = undefined; - public constructor(options: ILockfileDependencyOptions) { + public constructor(options: ILfxGraphDependencyOptions) { this.name = options.name; this.version = options.version; this.dependencyType = options.dependencyType; @@ -47,15 +42,8 @@ export class LockfileDependency { } } -export enum LockfileEntryFilter { - Project = 1, - Package = 2, - SideBySide = 3, - Doppelganger = 4 -} - -export interface ILockfileEntryOptions { - kind: LockfileEntryFilter; +export interface ILfxGraphEntryOptions { + kind: LfxGraphEntryKind; entryId: string; rawEntryId: string; packageJsonFolderPath: string; @@ -72,11 +60,11 @@ export interface ILockfileEntryOptions { * 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 { +export class LfxGraphEntry { /** * Whether this entry is a project or a package (specified by importers or packages in the lockfile). */ - public readonly kind: LockfileEntryFilter; + public readonly kind: LfxGraphEntryKind; /** * A unique (human-readable) identifier for this lockfile entry. For projects, this is just @@ -112,7 +100,7 @@ export class LockfileEntry { * 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[] = []; + public readonly dependencies: LfxGraphDependency[] = []; /** * A list of dependencies that are listed under the "transitivePeerDependencies" in the pnpm lockfile. @@ -122,9 +110,9 @@ export class LockfileEntry { /** * A list of entries that specify this entry as a dependency. */ - public readonly referrers: LockfileEntry[] = []; + public readonly referrers: LfxGraphEntry[] = []; - public constructor(options: ILockfileEntryOptions) { + public constructor(options: ILfxGraphEntryOptions) { this.kind = options.kind; this.entryId = options.entryId; this.rawEntryId = options.rawEntryId; @@ -137,5 +125,10 @@ export class LockfileEntry { } export class LfxGraph { - public readonly entries: LockfileEntry[] = []; + public readonly workspace: IJsonLfxWorkspace; + public readonly entries: LfxGraphEntry[] = []; + + public constructor(workspace: IJsonLfxWorkspace) { + this.workspace = { ...workspace }; + } } diff --git a/apps/lockfile-explorer-web/src/packlets/lfx-shared/index.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/index.ts new file mode 100644 index 00000000000..c060ea5e6b6 --- /dev/null +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/index.ts @@ -0,0 +1,8 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +export * from './IAppContext'; +export * from './IJsonLfxGraph'; +export * from './IJsonLfxWorkspace'; +export * from './LfxGraph'; +export * as lfxGraphSerializer from './lfxGraphSerializer'; diff --git a/apps/lockfile-explorer-web/src/parsing/lfxGraphSerializer.ts b/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts similarity index 84% rename from apps/lockfile-explorer-web/src/parsing/lfxGraphSerializer.ts rename to apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts index 30a0e19fa53..b175dbd2080 100644 --- a/apps/lockfile-explorer-web/src/parsing/lfxGraphSerializer.ts +++ b/apps/lockfile-explorer-web/src/packlets/lfx-shared/lfxGraphSerializer.ts @@ -1,15 +1,15 @@ // 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'; +import type { IJsonLfxDependency, IJsonLfxEntry, IJsonLfxGraph } from './IJsonLfxGraph'; +import { type ILfxGraphEntryOptions, LfxGraph, LfxGraphDependency, LfxGraphEntry } from './LfxGraph'; export function serializeToJson(graph: LfxGraph): IJsonLfxGraph { const jsonLfxEntries: IJsonLfxEntry[] = []; - const jsonIdByEntry: Map = new Map(); + const jsonIdByEntry: Map = new Map(); - function toJsonId(entry: LockfileEntry): number { + function toJsonId(entry: LfxGraphEntry): number { const result: number | undefined = jsonIdByEntry.get(entry); if (result === undefined) { throw new Error('Attempt to serialize disconnected object'); @@ -46,7 +46,7 @@ export function serializeToJson(graph: LfxGraph): IJsonLfxGraph { // 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]; + const entry: LfxGraphEntry = graph.entries[i]; for (const dependency of entry.dependencies) { const jsonLfxDependency: IJsonLfxDependency = { @@ -70,16 +70,16 @@ export function serializeToJson(graph: LfxGraph): IJsonLfxGraph { jsonLfxEntry.referrerJsonIds = entry.referrers.map((x) => toJsonId(x)); } - return { entries: jsonLfxEntries }; + return { workspace: graph.workspace, entries: jsonLfxEntries }; } export function deserializeFromJson(jsonLfxGraph: IJsonLfxGraph): LfxGraph { - const graph: LfxGraph = new LfxGraph(); + const graph: LfxGraph = new LfxGraph(jsonLfxGraph.workspace); - const entries: LockfileEntry[] = graph.entries; + const entries: LfxGraphEntry[] = graph.entries; - function fromJsonId(jsonId: number): LockfileEntry { - const result: LockfileEntry | undefined = entries[jsonId]; + function fromJsonId(jsonId: number): LfxGraphEntry { + const result: LfxGraphEntry | undefined = entries[jsonId]; if (result === undefined) { throw new Error('Invalid jsonId'); } @@ -90,7 +90,7 @@ export function deserializeFromJson(jsonLfxGraph: IJsonLfxGraph): LfxGraph { // First create the jsonId mapping for (const jsonLfxEntry of jsonLfxEntries) { - const options: ILockfileEntryOptions = { + const options: ILfxGraphEntryOptions = { kind: jsonLfxEntry.kind, entryId: jsonLfxEntry.entryId, rawEntryId: jsonLfxEntry.rawEntryId, @@ -100,16 +100,16 @@ export function deserializeFromJson(jsonLfxGraph: IJsonLfxGraph): LfxGraph { entryPackageVersion: jsonLfxEntry.entryPackageVersion, entrySuffix: jsonLfxEntry.entrySuffix }; - entries.push(new LockfileEntry(options)); + entries.push(new LfxGraphEntry(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]; + const entry: LfxGraphEntry = graph.entries[i]; for (const jsonLfxDependency of jsonLfxEntry.dependencies) { - const dependency: LockfileDependency = new LockfileDependency({ + const dependency: LfxGraphDependency = new LfxGraphDependency({ name: jsonLfxDependency.name, version: jsonLfxDependency.version, dependencyType: jsonLfxDependency.dependencyType, diff --git a/apps/lockfile-explorer-web/src/parsing/readLockfile.ts b/apps/lockfile-explorer-web/src/parsing/readLockfile.ts index c68b9bb26d8..5c44f0887c6 100644 --- a/apps/lockfile-explorer-web/src/parsing/readLockfile.ts +++ b/apps/lockfile-explorer-web/src/parsing/readLockfile.ts @@ -1,14 +1,21 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -import type { LockfileEntry } from './LfxGraph'; -import * as lfxGraphLoader from './lfxGraphLoader'; +import { + type LfxGraph, + lfxGraphSerializer, + type IJsonLfxGraph, + type LfxGraphEntry +} from '../packlets/lfx-shared'; const serviceUrl: string = window.appContext.serviceUrl; -export async function readLockfileAsync(): Promise { - const response = await fetch(`${serviceUrl}/api/lockfile`); - const lockfile: { doc: lfxGraphLoader.ILockfilePackageType; subspaceName: string } = await response.json(); +export async function readLockfileAsync(): Promise { + // eslint-disable-next-line no-console + console.log('Loading graph'); - return lfxGraphLoader.generateLockfileGraph(lockfile.doc, lockfile.subspaceName).entries; + const response = await fetch(`${serviceUrl}/api/graph`); + const jsonGraph: IJsonLfxGraph = await response.json(); + const graph: LfxGraph = lfxGraphSerializer.deserializeFromJson(jsonGraph); + return graph.entries; } diff --git a/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts b/apps/lockfile-explorer-web/src/store/slices/entrySlice.ts index 8c6bd99c0fc..6c3f4c8de50 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/LfxGraph'; +import { type LfxGraphEntry, LfxGraphEntryKind } from '../../packlets/lfx-shared'; import type { RootState } from '../index'; import { getBookmarksFromStorage, @@ -12,22 +12,22 @@ import { // eslint-disable-next-line @typescript-eslint/consistent-type-definitions type EntryState = { - allEntries: LockfileEntry[]; + allEntries: LfxGraphEntry[]; filters: { - [key in LockfileEntryFilter]: boolean; + [key in LfxGraphEntryKind]: boolean; }; - selectedEntryStack: LockfileEntry[]; - selectedEntryForwardStack: LockfileEntry[]; - bookmarkedEntries: LockfileEntry[]; + selectedEntryStack: LfxGraphEntry[]; + selectedEntryForwardStack: LfxGraphEntry[]; + bookmarkedEntries: LfxGraphEntry[]; }; const initialState: EntryState = { allEntries: [], filters: { - [LockfileEntryFilter.Project]: false, - [LockfileEntryFilter.Package]: true, - [LockfileEntryFilter.SideBySide]: false, - [LockfileEntryFilter.Doppelganger]: false + [LfxGraphEntryKind.Project]: false, + [LfxGraphEntryKind.Package]: true, + [LfxGraphEntryKind.SideBySide]: false, + [LfxGraphEntryKind.Doppelganger]: false }, selectedEntryStack: [], selectedEntryForwardStack: [], @@ -39,7 +39,7 @@ const entrySlice = createSlice({ name: 'entry', initialState, reducers: { - loadEntries: (state, payload: PayloadAction) => { + loadEntries: (state, payload: PayloadAction) => { state.allEntries = payload.payload; // Hydrate the bookmarks state const bookmarkSet = getBookmarksFromStorage(); @@ -49,70 +49,70 @@ const entrySlice = createSlice({ } } }, - setFilter: (state, payload: PayloadAction<{ filter: LockfileEntryFilter; state: boolean }>) => { + setFilter: (state, payload: PayloadAction<{ filter: LfxGraphEntryKind; state: boolean }>) => { state.filters[payload.payload.filter] = payload.payload.state; }, - clearStackAndPush: (state, payload: PayloadAction) => { + clearStackAndPush: (state, payload: PayloadAction) => { state.selectedEntryStack = [payload.payload]; state.selectedEntryForwardStack = []; }, - pushToStack: (state, payload: PayloadAction) => { + pushToStack: (state, payload: PayloadAction) => { state.selectedEntryStack.push(payload.payload); state.selectedEntryForwardStack = []; - if (payload.payload.kind === LockfileEntryFilter.Package) { - state.filters[LockfileEntryFilter.Project] = false; - state.filters[LockfileEntryFilter.Package] = true; + if (payload.payload.kind === LfxGraphEntryKind.Package) { + state.filters[LfxGraphEntryKind.Project] = false; + state.filters[LfxGraphEntryKind.Package] = true; } else { - state.filters[LockfileEntryFilter.Project] = true; - state.filters[LockfileEntryFilter.Package] = false; + state.filters[LfxGraphEntryKind.Project] = true; + state.filters[LfxGraphEntryKind.Package] = false; } }, popStack: (state) => { if (state.selectedEntryStack.length > 1) { - const poppedEntry = state.selectedEntryStack.pop() as LockfileEntry; + const poppedEntry = state.selectedEntryStack.pop() as LfxGraphEntry; state.selectedEntryForwardStack.push(poppedEntry); if (state.selectedEntryStack.length >= 1) { const currEntry = state.selectedEntryStack[state.selectedEntryStack.length - 1]; - if (currEntry.kind === LockfileEntryFilter.Package) { - state.filters[LockfileEntryFilter.Project] = false; - state.filters[LockfileEntryFilter.Package] = true; + if (currEntry.kind === LfxGraphEntryKind.Package) { + state.filters[LfxGraphEntryKind.Project] = false; + state.filters[LfxGraphEntryKind.Package] = true; } else { - state.filters[LockfileEntryFilter.Project] = true; - state.filters[LockfileEntryFilter.Package] = false; + state.filters[LfxGraphEntryKind.Project] = true; + state.filters[LfxGraphEntryKind.Package] = false; } } } }, forwardStack: (state) => { if (state.selectedEntryForwardStack.length > 0) { - const poppedEntry = state.selectedEntryForwardStack.pop() as LockfileEntry; + const poppedEntry = state.selectedEntryForwardStack.pop() as LfxGraphEntry; state.selectedEntryStack.push(poppedEntry); - if (poppedEntry.kind === LockfileEntryFilter.Package) { - state.filters[LockfileEntryFilter.Project] = false; - state.filters[LockfileEntryFilter.Package] = true; + if (poppedEntry.kind === LfxGraphEntryKind.Package) { + state.filters[LfxGraphEntryKind.Project] = false; + state.filters[LfxGraphEntryKind.Package] = true; } else { - state.filters[LockfileEntryFilter.Project] = true; - state.filters[LockfileEntryFilter.Package] = false; + state.filters[LfxGraphEntryKind.Project] = true; + state.filters[LfxGraphEntryKind.Package] = false; } } }, - addBookmark: (state, payload: PayloadAction) => { + addBookmark: (state, payload: PayloadAction) => { if (!state.bookmarkedEntries.includes(payload.payload)) { state.bookmarkedEntries.push(payload.payload); saveBookmarkToLocalStorage(payload.payload); } }, - removeBookmark: (state, payload: PayloadAction) => { + removeBookmark: (state, payload: PayloadAction) => { state.bookmarkedEntries = state.bookmarkedEntries.filter( - (entry: LockfileEntry) => entry.rawEntryId !== payload.payload.rawEntryId + (entry: LfxGraphEntry) => entry.rawEntryId !== payload.payload.rawEntryId ); removeBookmarkFromLocalStorage(payload.payload); } } }); -export const selectCurrentEntry = (state: RootState): LockfileEntry | undefined => { +export const selectCurrentEntry = (state: RootState): LfxGraphEntry | undefined => { if (state.entry.selectedEntryStack.length) { return state.entry.selectedEntryStack[state.entry.selectedEntryStack.length - 1]; } else { @@ -120,15 +120,15 @@ export const selectCurrentEntry = (state: RootState): LockfileEntry | undefined } }; -export const selectFilteredEntries = (state: RootState): LockfileEntry[] => { - const filteredEntries: LockfileEntry[] = []; - if (state.entry.filters[LockfileEntryFilter.Package]) { +export const selectFilteredEntries = (state: RootState): LfxGraphEntry[] => { + const filteredEntries: LfxGraphEntry[] = []; + if (state.entry.filters[LfxGraphEntryKind.Package]) { filteredEntries.push( - ...state.entry.allEntries.filter((entry) => entry.kind === LockfileEntryFilter.Package) + ...state.entry.allEntries.filter((entry) => entry.kind === LfxGraphEntryKind.Package) ); - } else if (state.entry.filters[LockfileEntryFilter.Project]) { + } else if (state.entry.filters[LfxGraphEntryKind.Project]) { filteredEntries.push( - ...state.entry.allEntries.filter((entry) => entry.kind === LockfileEntryFilter.Project) + ...state.entry.allEntries.filter((entry) => entry.kind === LfxGraphEntryKind.Project) ); } return filteredEntries; diff --git a/apps/lockfile-explorer-web/src/types/AppContext.ts b/apps/lockfile-explorer-web/src/types/AppContext.ts index 28e788cf31f..5bd79089f4c 100644 --- a/apps/lockfile-explorer-web/src/types/AppContext.ts +++ b/apps/lockfile-explorer-web/src/types/AppContext.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 { IAppContext } from './IAppContext'; +import type { IAppContext } from '../packlets/lfx-shared'; declare global { // eslint-disable-next-line @typescript-eslint/naming-convention diff --git a/apps/lockfile-explorer/.npmignore b/apps/lockfile-explorer/.npmignore index bc349f9a4be..538016c27d7 100644 --- a/apps/lockfile-explorer/.npmignore +++ b/apps/lockfile-explorer/.npmignore @@ -30,3 +30,6 @@ # --------------------------------------------------------------------------- # DO NOT MODIFY ABOVE THIS LINE! Add any project-specific overrides below. # --------------------------------------------------------------------------- + +# heft.json copies this folder from lockfile-explorer-web: +!/build/lfx-shared/** diff --git a/apps/lockfile-explorer/.vscode/launch.json b/apps/lockfile-explorer/.vscode/launch.json index f1cdf885db1..9cc2fd9f58d 100644 --- a/apps/lockfile-explorer/.vscode/launch.json +++ b/apps/lockfile-explorer/.vscode/launch.json @@ -7,20 +7,30 @@ { "type": "node", "request": "launch", - "name": "Debug Jest tests", + "name": "All 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": "Single Jest test", + "program": "${workspaceFolder}/node_modules/@rushstack/heft/lib/start.js", + "cwd": "${workspaceFolder}", + "args": ["--debug", "test", "--clean", "-u", "--test-path-pattern", "lfxGraphLoader60"], + "console": "integratedTerminal", + "sourceMaps": true }, { "type": "node", "request": "launch", - "name": "Run in specified folder", + "name": "Run LAST BUILD in specified folder", "program": "${workspaceFolder}/lib/start-explorer.js", - //"cwd": "C:\\Git\\lockfile-explorer-demos", "cwd": "(your project path)", + //"cwd": "C:\\Git\\lockfile-explorer-demos", "args": ["--debug"], "sourceMaps": true } diff --git a/apps/lockfile-explorer/config/heft.json b/apps/lockfile-explorer/config/heft.json index 425aa0a60d9..6664d95480c 100644 --- a/apps/lockfile-explorer/config/heft.json +++ b/apps/lockfile-explorer/config/heft.json @@ -14,6 +14,8 @@ "phasesByName": { "build": { + "cleanFiles": [{ "includeGlobs": ["build"] }], + "tasksByName": { "copy-app-bundle": { "taskPlugin": { @@ -34,6 +36,31 @@ ] } } + }, + + "pre-compile-copy": { + "taskPlugin": { + "pluginPackage": "@rushstack/heft", + "pluginName": "copy-files-plugin", + "options": { + "copyOperations": [ + { + "sourcePath": "node_modules/@rushstack/lockfile-explorer-web/lib/packlets/lfx-shared", + "destinationFolders": ["build/lfx-shared"], + "includeGlobs": ["*.d.ts"] + }, + { + "sourcePath": "node_modules/@rushstack/lockfile-explorer-web/lib-commonjs/packlets/lfx-shared", + "destinationFolders": ["build/lfx-shared"], + "includeGlobs": ["*.js", "*.map"] + } + ] + } + } + }, + "typescript": { + // The "typescript" task should not run until after "pre-compile-copy" completes. + "taskDependencies": ["pre-compile-copy"] } } } diff --git a/apps/lockfile-explorer/eslint.config.js b/apps/lockfile-explorer/eslint.config.js index 0c26ce1ce48..ceb5a1bee40 100644 --- a/apps/lockfile-explorer/eslint.config.js +++ b/apps/lockfile-explorer/eslint.config.js @@ -1,10 +1,12 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. -const nodeProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node'); +const nodeTrustedToolProfile = require('local-node-rig/profiles/default/includes/eslint/flat/profile/node-trusted-tool'); +const friendlyLocalsMixin = require('local-node-rig/profiles/default/includes/eslint/flat/mixins/friendly-locals'); module.exports = [ - ...nodeProfile, + ...nodeTrustedToolProfile, + ...friendlyLocalsMixin, { files: ['**/*.ts', '**/*.tsx'], languageOptions: { diff --git a/apps/lockfile-explorer/package.json b/apps/lockfile-explorer/package.json index 0110d91bd00..4e175cb7851 100644 --- a/apps/lockfile-explorer/package.json +++ b/apps/lockfile-explorer/package.json @@ -51,7 +51,7 @@ "@rushstack/lockfile-explorer-web": "workspace:*", "@types/cors": "~2.8.12", "@types/express": "4.17.21", - "@types/js-yaml": "3.12.1", + "@types/js-yaml": "4.0.9", "@types/update-notifier": "~6.0.1", "eslint": "~9.25.1", "local-node-rig": "workspace:*", @@ -59,17 +59,19 @@ "@types/semver": "7.5.0" }, "dependencies": { + "tslib": "~2.8.1", + "@lifaon/path": "~2.1.0", "@microsoft/rush-lib": "workspace:*", + "@pnpm/dependency-path-lockfile-pre-v9": "npm:@pnpm/dependency-path@~2.1.2", "@rushstack/node-core-library": "workspace:*", + "@rushstack/rush-sdk": "workspace:*", "@rushstack/terminal": "workspace:*", + "@rushstack/ts-command-line": "workspace:*", "cors": "~2.8.5", "express": "4.20.0", - "js-yaml": "~3.13.1", + "js-yaml": "~4.1.0", "open": "~8.4.0", - "update-notifier": "~5.1.0", - "@pnpm/dependency-path-lockfile-pre-v9": "npm:@pnpm/dependency-path@~2.1.2", "semver": "~7.5.4", - "@rushstack/rush-sdk": "workspace:*", - "@rushstack/ts-command-line": "workspace:*" + "update-notifier": "~5.1.0" } } diff --git a/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts index 4f9d3efb2f7..cc40653e354 100644 --- a/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts +++ b/apps/lockfile-explorer/src/cli/explorer/ExplorerCommandLineParser.ts @@ -15,12 +15,17 @@ import { CommandLineParser, type IRequiredCommandLineStringParameter } from '@rushstack/ts-command-line'; -import type { IAppContext } from '@rushstack/lockfile-explorer-web/lib/types/IAppContext'; import type { Lockfile } from '@pnpm/lockfile-types'; +import { + type LfxGraph, + lfxGraphSerializer, + type IAppContext, + type IJsonLfxGraph +} from '../../../build/lfx-shared'; import type { IAppState } from '../../state'; import { init } from '../../utils/init'; -import { convertLockfileV6DepPathToV5DepPath, getShrinkwrapFileMajorVersion } from '../../utils/shrinkwrap'; +import * as lfxGraphLoader from '../../graph/lfxGraphLoader'; const EXPLORER_TOOL_FILENAME: 'lockfile-explorer' = 'lockfile-explorer'; @@ -135,27 +140,6 @@ export class ExplorerCommandLineParser extends CommandLineParser { app.use('/favicon.ico', express.static(distFolderPath, { index: 'favicon.ico' })); - app.get('/api/lockfile', async (req: express.Request, res: express.Response) => { - const pnpmLockfileText: string = await FileSystem.readFileAsync(appState.pnpmLockfileLocation); - const doc = yaml.load(pnpmLockfileText) as Lockfile; - const { packages, lockfileVersion } = doc; - - const shrinkwrapFileMajorVersion: number = getShrinkwrapFileMajorVersion(lockfileVersion); - - if (packages && shrinkwrapFileMajorVersion === 6) { - const updatedPackages: Lockfile['packages'] = {}; - for (const [dependencyPath, dependency] of Object.entries(packages)) { - updatedPackages[convertLockfileV6DepPathToV5DepPath(dependencyPath)] = dependency; - } - doc.packages = updatedPackages; - } - - res.send({ - doc, - subspaceName: this._subspaceParameter.value - }); - }); - app.get('/api/health', (req: express.Request, res: express.Response) => { awaitingFirstConnect = false; isClientConnected = true; @@ -166,15 +150,25 @@ 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.get('/api/graph', async (req: express.Request, res: express.Response) => { + const pnpmLockfileText: string = await FileSystem.readFileAsync(appState.pnpmLockfileLocation); + const lockfile: Lockfile = yaml.load(pnpmLockfileText) as Lockfile; + + const graph: LfxGraph = lfxGraphLoader.generateLockfileGraph( + appState.lfxWorkspace, + lockfile as lfxGraphLoader.ILockfilePackageType, + appState.lfxWorkspace.rushConfig?.subspaceName ?? '' + ); + + const jsonGraph: IJsonLfxGraph = lfxGraphSerializer.serializeToJson(graph); + res.type('application/json').send(jsonGraph); }); app.post( '/api/package-json', async (req: express.Request<{}, {}, { projectPath: string }, {}>, res: express.Response) => { const { projectPath } = req.body; - const fileLocation = `${appState.projectRoot}/${projectPath}/package.json`; + const fileLocation: string = `${appState.projectRoot}/${projectPath}/package.json`; let packageJsonText: string; try { packageJsonText = await FileSystem.readFileAsync(fileLocation); @@ -215,7 +209,7 @@ export class ExplorerCommandLineParser extends CommandLineParser { '/api/package-spec', async (req: express.Request<{}, {}, { projectPath: string }, {}>, res: express.Response) => { const { projectPath } = req.body; - const fileLocation = `${appState.projectRoot}/${projectPath}/package.json`; + const fileLocation: string = `${appState.projectRoot}/${projectPath}/package.json`; let packageJson: IPackageJson; try { packageJson = await JsonFile.loadAsync(fileLocation); @@ -232,7 +226,7 @@ export class ExplorerCommandLineParser extends CommandLineParser { const { hooks: { readPackage } } = require(appState.pnpmfileLocation); - const parsedPackage = readPackage(packageJson, {}); + const parsedPackage: {} = readPackage(packageJson, {}); res.send(parsedPackage); } ); diff --git a/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts b/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts index 2903d0e8575..389bb27001b 100644 --- a/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts +++ b/apps/lockfile-explorer/src/cli/lint/actions/CheckAction.ts @@ -118,9 +118,9 @@ export class CheckAction extends CommandLineAction { await Promise.all( Object.entries(importers).map(async ([relativePath, { dependencies }]) => { if (path.resolve(projectFolder, relativePath) === projectFolder) { - const dependenciesEntries = Object.entries(dependencies ?? {}); + const dependenciesEntries: [string, unknown][] = Object.entries(dependencies ?? {}); for (const [dependencyName, dependencyValue] of dependenciesEntries) { - const fullDependencyPath = splicePackageWithVersion( + const fullDependencyPath: string = splicePackageWithVersion( shrinkwrapFileMajorVersion, dependencyName, typeof dependencyValue === 'string' diff --git a/apps/lockfile-explorer-web/src/parsing/lfxGraphLoader.ts b/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts similarity index 73% rename from apps/lockfile-explorer-web/src/parsing/lfxGraphLoader.ts rename to apps/lockfile-explorer/src/graph/lfxGraphLoader.ts index e9b02ec4e47..64ed34f997a 100644 --- a/apps/lockfile-explorer-web/src/parsing/lfxGraphLoader.ts +++ b/apps/lockfile-explorer/src/graph/lfxGraphLoader.ts @@ -1,15 +1,20 @@ // 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 ILockfileDependencyOptions, - type ILockfileEntryOptions, + type ILfxGraphDependencyOptions, + type ILfxGraphEntryOptions, LfxGraph, - LockfileEntry, - LockfileEntryFilter -} from './LfxGraph'; -import { DependencyKind, LockfileDependency } from './LfxGraph'; -import { Path } from '@lifaon/path'; + LfxGraphEntry, + LfxGraphEntryKind, + LfxDependencyKind, + LfxGraphDependency, + type IJsonLfxWorkspace +} from '../../build/lfx-shared'; + +import { convertLockfileV6DepPathToV5DepPath } from '../utils/shrinkwrap'; enum PnpmLockfileVersion { V6, @@ -75,11 +80,11 @@ const packageEntryIdRegex: RegExp = new RegExp('/(.*)/([^/]+)$'); function createLockfileDependency( name: string, version: string, - dependencyType: DependencyKind, - containingEntry: LockfileEntry, + dependencyType: LfxDependencyKind, + containingEntry: LfxGraphEntry, node?: ILockfileNode -): LockfileDependency { - const result: ILockfileDependencyOptions = { +): LfxGraphDependency { + const result: ILfxGraphDependencyOptions = { name, version, dependencyType, @@ -89,19 +94,18 @@ function createLockfileDependency( }; if (version.startsWith('link:')) { - const relativePath = version.substring('link:'.length); - const rootRelativePath = new Path('.').relative( + const relativePath: string = version.substring('link:'.length); + const rootRelativePath: Path | null = 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); + return new LfxGraphDependency(result); } result.entryId = 'project:' + rootRelativePath.toString(); } else if (result.version.startsWith('/')) { result.entryId = version; - } else if (result.dependencyType === DependencyKind.PEER_DEPENDENCY) { + } else if (result.dependencyType === LfxDependencyKind.Peer) { if (node?.peerDependencies) { result.peerDependencyMeta = { name: result.name, @@ -113,39 +117,36 @@ function createLockfileDependency( }; 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); + return new LfxGraphDependency(result); } // node is the yaml entry that we are trying to parse function parseDependencies( - dependencies: LockfileDependency[], - lockfileEntry: LockfileEntry, + dependencies: LfxGraphDependency[], + lockfileEntry: LfxGraphEntry, node: ILockfileNode ): void { if (node.dependencies) { for (const [pkgName, pkgVersion] of Object.entries(node.dependencies)) { dependencies.push( - createLockfileDependency(pkgName, pkgVersion, DependencyKind.DEPENDENCY, lockfileEntry) + createLockfileDependency(pkgName, pkgVersion, LfxDependencyKind.Regular, lockfileEntry) ); } } if (node.devDependencies) { for (const [pkgName, pkgVersion] of Object.entries(node.devDependencies)) { - dependencies.push( - createLockfileDependency(pkgName, pkgVersion, DependencyKind.DEV_DEPENDENCY, lockfileEntry) - ); + dependencies.push(createLockfileDependency(pkgName, pkgVersion, LfxDependencyKind.Dev, lockfileEntry)); } } if (node.peerDependencies) { for (const [pkgName, pkgVersion] of Object.entries(node.peerDependencies)) { dependencies.push( - createLockfileDependency(pkgName, pkgVersion, DependencyKind.PEER_DEPENDENCY, lockfileEntry, node) + createLockfileDependency(pkgName, pkgVersion, LfxDependencyKind.Peer, lockfileEntry, node) ); } } @@ -158,14 +159,14 @@ function parseDependencies( function createLockfileEntry(options: { rawEntryId: string; - kind: LockfileEntryFilter; + kind: LfxGraphEntryKind; rawYamlData: ILockfileNode; duplicates?: Set; subspaceName?: string; -}): LockfileEntry { +}): LfxGraphEntry { const { rawEntryId, kind, rawYamlData, duplicates, subspaceName } = options; - const result: ILockfileEntryOptions = { + const result: ILfxGraphEntryOptions = { kind, entryId: '', rawEntryId: '', @@ -180,27 +181,27 @@ function createLockfileEntry(options: { if (rawEntryId === '.') { // Project Root - return new LockfileEntry(result); + return new LfxGraphEntry(result); } - if (kind === LockfileEntryFilter.Project) { - const rootPackageJsonFolderPath = new Path(`common/temp/${subspaceName}/package.json`).dirname() || ''; - const packageJsonFolderPath = new Path('.').relative( + if (kind === LfxGraphEntryKind.Project) { + const rootPackageJsonFolderPath: '' | Path = + new Path(`common/temp/${subspaceName}/package.json`).dirname() || ''; + const packageJsonFolderPath: Path | null = new Path('.').relative( new Path(rootPackageJsonFolderPath).concat(rawEntryId) ); - const packageName = new Path(rawEntryId).basename(); + const packageName: string | null = 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); + return new LfxGraphEntry(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); + const fullPath: string = new Path(rawEntryId).makeAbsolute('/').toString().substring(1); result.displayText = `Project: ${result.entryPackageName} (${fullPath})`; result.entryPackageName = `${result.entryPackageName} (${fullPath})`; } else { @@ -209,16 +210,16 @@ function createLockfileEntry(options: { } else { result.displayText = rawEntryId; - const match = packageEntryIdRegex.exec(rawEntryId); + const match: RegExpExecArray | null = packageEntryIdRegex.exec(rawEntryId); if (match) { const [, packageName, versionPart] = match; result.entryPackageName = packageName; - const underscoreIndex = versionPart.indexOf('_'); + const underscoreIndex: number = versionPart.indexOf('_'); if (underscoreIndex >= 0) { - const version = versionPart.substring(0, underscoreIndex); - const suffix = versionPart.substring(underscoreIndex + 1); + const version: string = versionPart.substring(0, underscoreIndex); + const suffix: string = versionPart.substring(underscoreIndex + 1); result.entryPackageVersion = version; result.entrySuffix = suffix; @@ -249,7 +250,7 @@ function createLockfileEntry(options: { result.entryPackageName; } - const lockfileEntry = new LockfileEntry(result); + const lockfileEntry: LfxGraphEntry = new LfxGraphEntry(result); parseDependencies(lockfileEntry.dependencies, lockfileEntry, rawYamlData); return lockfileEntry; } @@ -265,7 +266,7 @@ function getImporterValue( pnpmLockfileVersion: PnpmLockfileVersion ): ILockfileImporterV5 { if (pnpmLockfileVersion === PnpmLockfileVersion.V6) { - const v6ImporterValue = importerValue as ILockfileImporterV6; + const v6ImporterValue: ILockfileImporterV6 = importerValue as ILockfileImporterV6; const v5ImporterValue: ILockfileImporterV5 = { specifiers: {}, dependencies: {}, @@ -291,22 +292,35 @@ function getImporterValue( * * @returns A list of all the LockfileEntries in the lockfile. */ -export function generateLockfileGraph(lockfile: ILockfilePackageType, subspaceName?: string): LfxGraph { +export function generateLockfileGraph( + workspace: IJsonLfxWorkspace, + 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.packages && pnpmLockfileVersion === PnpmLockfileVersion.V6) { + const updatedPackages: ILockfilePackageType['packages'] = {}; + for (const [dependencyPath, dependency] of Object.entries(lockfile.packages)) { + updatedPackages[convertLockfileV6DepPathToV5DepPath(dependencyPath)] = dependency; + } + lockfile.packages = updatedPackages; + } + + const lfxGraph: LfxGraph = new LfxGraph(workspace); + const allEntries: LfxGraphEntry[] = lfxGraph.entries; + const allEntriesById: { [key: string]: LfxGraphEntry } = {}; + + const allImporters: LfxGraphEntry[] = []; if (lockfile.importers) { // Find duplicate importer names - const baseNames = new Set(); - const duplicates = new Set(); + const baseNames: Set = new Set(); + const duplicates: Set = new Set(); for (const importerKey of Object.keys(lockfile.importers)) { - const baseName = new Path(importerKey).basename(); + const baseName: string | null = new Path(importerKey).basename(); if (baseName) { if (baseNames.has(baseName)) { duplicates.add(baseName); @@ -319,10 +333,10 @@ export function generateLockfileGraph(lockfile: ILockfilePackageType, subspaceNa // console.log('normalized importer key: ', new Path(importerKey).makeAbsolute('/').toString()); // const normalizedPath = new Path(importerKey).makeAbsolute('/').toString(); - const importer: LockfileEntry = createLockfileEntry({ + const importer: LfxGraphEntry = createLockfileEntry({ // entryId: normalizedPath, rawEntryId: importerKey, - kind: LockfileEntryFilter.Project, + kind: LfxGraphEntryKind.Project, rawYamlData: getImporterValue(importerValue, pnpmLockfileVersion), duplicates, subspaceName @@ -333,15 +347,15 @@ export function generateLockfileGraph(lockfile: ILockfilePackageType, subspaceNa } } - const allPackages = []; + const allPackages: LfxGraphEntry[] = []; if (lockfile.packages) { for (const [dependencyKey, dependencyValue] of Object.entries(lockfile.packages)) { // const normalizedPath = new Path(dependencyKey).makeAbsolute('/').toString(); - const currEntry: LockfileEntry = createLockfileEntry({ + const currEntry: LfxGraphEntry = createLockfileEntry({ // entryId: normalizedPath, rawEntryId: dependencyKey, - kind: LockfileEntryFilter.Package, + kind: LfxGraphEntryKind.Package, rawYamlData: dependencyValue, subspaceName }); @@ -356,11 +370,11 @@ export function generateLockfileGraph(lockfile: ILockfilePackageType, subspaceNa 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) { + if (dependency.dependencyType === LfxDependencyKind.Peer) { continue; } - const matchedEntry = allEntriesById[dependency.entryId]; + const matchedEntry: LfxGraphEntry = allEntriesById[dependency.entryId]; if (matchedEntry) { // Create a two-way link between the dependency and the entry dependency.resolvedEntry = matchedEntry; @@ -368,7 +382,6 @@ export function generateLockfileGraph(lockfile: ILockfilePackageType, subspaceNa } else { if (dependency.entryId.startsWith('/')) { // Local package - // eslint-disable-next-line no-console console.error('Could not resolve dependency entryId: ', dependency.entryId, dependency); } } diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap new file mode 100644 index 00000000000..f37d9721956 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v5.4.test.ts.snap @@ -0,0 +1,338 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-website-sample-1-v5.4 loads a workspace 1`] = ` +"entries: + - dependencies: [] + displayText: '' + entryId: '' + entryPackageName: '' + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: '' + rawEntryId: . + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/d + name: '@rushstack/d' + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + version: link:../d + displayText: 'Project: a' + entryId: project:./common/projects/a + entryPackageName: a + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: ./common/projects/a + rawEntryId: ../../projects/a + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/d + name: '@rushstack/d' + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + version: link:../d + - dependencyType: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 12 + version: 2.0.0 + displayText: 'Project: b' + entryId: project:./common/projects/b + entryPackageName: b + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: ./common/projects/b + rawEntryId: ../../projects/b + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/e + name: '@rushstack/e' + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + version: link:../e + - dependencyType: regular + entryId: /@rushstack/k/1.0.0_@rushstack+m@1.0.0 + name: '@rushstack/k' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + version: 1.0.0_@rushstack+m@1.0.0 + - dependencyType: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + version: 1.0.0 + displayText: 'Project: c' + entryId: project:./common/projects/c + entryPackageName: c + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: ./common/projects/c + rawEntryId: ../../projects/c + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/e + name: '@rushstack/e' + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + version: link:../e + - dependencyType: regular + entryId: /@rushstack/j/1.0.0_@rushstack+n@2.0.0 + name: '@rushstack/j' + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + version: 1.0.0_@rushstack+n@2.0.0 + - dependencyType: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 12 + version: 2.0.0 + displayText: 'Project: d' + entryId: project:./common/projects/d + entryPackageName: d + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: ./common/projects/d + rawEntryId: ../../projects/d + referrerJsonIds: + - 1 + - 2 + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: /@rushstack/n/3.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 13 + version: 3.0.0 + displayText: 'Project: e' + entryId: project:./common/projects/e + entryPackageName: e + entryPackageVersion: '' + entrySuffix: '' + jsonId: 5 + kind: 1 + packageJsonFolderPath: ./common/projects/e + rawEntryId: ../../projects/e + referrerJsonIds: + - 3 + - 4 + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu + name: '@rushstack/k' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + version: 1.0.0_wxpgugna4ivthu7yyu4fmciltu + - dependencyType: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + version: 1.0.0 + displayText: '@rushstack/j 1.0.0 (@rushstack+n@2.0.0)' + entryId: '' + entryPackageName: '@rushstack/j' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack+n@2.0.0' + jsonId: 6 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+j@1.0.0_@rushstack+n@2.0.0/node_modules/@rushstack/j + rawEntryId: /@rushstack/j/1.0.0_@rushstack+n@2.0.0 + referrerJsonIds: + - 4 + transitivePeerDependencies: + - '@rushstack/n' + - dependencies: + - dependencyType: regular + entryId: /@rushstack/l/1.0.0_@rushstack+m@1.0.0 + name: '@rushstack/l' + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + version: 1.0.0_@rushstack+m@1.0.0 + displayText: '@rushstack/k 1.0.0 (@rushstack+m@1.0.0)' + entryId: '' + entryPackageName: '@rushstack/k' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack+m@1.0.0' + jsonId: 7 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+k@1.0.0_@rushstack+m@1.0.0/node_modules/@rushstack/k + rawEntryId: /@rushstack/k/1.0.0_@rushstack+m@1.0.0 + referrerJsonIds: + - 3 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + - dependencies: + - dependencyType: regular + entryId: /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu + name: '@rushstack/l' + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + version: 1.0.0_wxpgugna4ivthu7yyu4fmciltu + displayText: '@rushstack/k 1.0.0 (wxpgugna4ivthu7yyu4fmciltu)' + entryId: '' + entryPackageName: '@rushstack/k' + entryPackageVersion: 1.0.0 + entrySuffix: wxpgugna4ivthu7yyu4fmciltu + jsonId: 8 + kind: 2 + packageJsonFolderPath: >- + common/temp/undefined/node_modules/.pnpm/@rushstack+k@1.0.0_wxpgugna4ivthu7yyu4fmciltu/node_modules/@rushstack/k + rawEntryId: /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu + referrerJsonIds: + - 6 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + - dependencies: + - dependencyType: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + version: 1.0.0 + - dependencyType: peer + entryId: 'Peer: @rushstack/m' + name: '@rushstack/m' + peerDependencyMeta: + name: '@rushstack/m' + optional: false + version: ^1.0.0 + version: ^1.0.0 + - dependencyType: peer + entryId: 'Peer: @rushstack/n' + name: '@rushstack/n' + peerDependencyMeta: + name: '@rushstack/n' + optional: true + version: ^2.0.0 + version: ^2.0.0 + displayText: '@rushstack/l 1.0.0 (@rushstack+m@1.0.0)' + entryId: '' + entryPackageName: '@rushstack/l' + entryPackageVersion: 1.0.0 + entrySuffix: '@rushstack+m@1.0.0' + jsonId: 9 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+l@1.0.0_@rushstack+m@1.0.0/node_modules/@rushstack/l + rawEntryId: /@rushstack/l/1.0.0_@rushstack+m@1.0.0 + referrerJsonIds: + - 7 + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + version: 1.0.0 + - dependencyType: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 12 + version: 2.0.0 + - dependencyType: peer + entryId: 'Peer: @rushstack/m' + name: '@rushstack/m' + peerDependencyMeta: + name: '@rushstack/m' + optional: false + version: ^1.0.0 + version: ^1.0.0 + - dependencyType: peer + entryId: 'Peer: @rushstack/n' + name: '@rushstack/n' + peerDependencyMeta: + name: '@rushstack/n' + optional: true + version: ^2.0.0 + version: ^2.0.0 + displayText: '@rushstack/l 1.0.0 (wxpgugna4ivthu7yyu4fmciltu)' + entryId: '' + entryPackageName: '@rushstack/l' + entryPackageVersion: 1.0.0 + entrySuffix: wxpgugna4ivthu7yyu4fmciltu + jsonId: 10 + kind: 2 + packageJsonFolderPath: >- + common/temp/undefined/node_modules/.pnpm/@rushstack+l@1.0.0_wxpgugna4ivthu7yyu4fmciltu/node_modules/@rushstack/l + rawEntryId: /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu + referrerJsonIds: + - 8 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/m 1.0.0' + entryId: '' + entryPackageName: '@rushstack/m' + entryPackageVersion: 1.0.0 + entrySuffix: '' + jsonId: 11 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+m@1.0.0/node_modules/@rushstack/m + rawEntryId: /@rushstack/m/1.0.0 + referrerJsonIds: + - 3 + - 6 + - 9 + - 10 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 2.0.0' + entryId: '' + entryPackageName: '@rushstack/n' + entryPackageVersion: 2.0.0 + entrySuffix: '' + jsonId: 12 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+n@2.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n/2.0.0 + referrerJsonIds: + - 2 + - 4 + - 10 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 3.0.0' + entryId: '' + entryPackageName: '@rushstack/n' + entryPackageVersion: 3.0.0 + entrySuffix: '' + jsonId: 13 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+n@3.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n/3.0.0 + referrerJsonIds: + - 5 + transitivePeerDependencies: [] +workspace: + pnpmLockfilePath: common/temp/pnpm-lock.yaml + rushConfig: + rushVersion: 5.83.3 + subspaceName: '' + workspaceRootFolder: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap new file mode 100644 index 00000000000..a24bbbb326c --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/__snapshots__/lfxGraph-website-sample-1-v6.0.test.ts.snap @@ -0,0 +1,283 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`lfxGraph-website-sample-1-v6.0 loads a workspace 1`] = ` +"entries: + - dependencies: [] + displayText: '' + entryId: '' + entryPackageName: '' + entryPackageVersion: '' + entrySuffix: '' + jsonId: 0 + kind: 1 + packageJsonFolderPath: '' + rawEntryId: . + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/d + name: '@rushstack/d' + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + version: link:../d + displayText: 'Project: a' + entryId: project:./common/projects/a + entryPackageName: a + entryPackageVersion: '' + entrySuffix: '' + jsonId: 1 + kind: 1 + packageJsonFolderPath: ./common/projects/a + rawEntryId: ../../projects/a + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/d + name: '@rushstack/d' + peerDependencyMeta: {} + resolvedEntryJsonId: 4 + version: link:../d + - dependencyType: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + version: 2.0.0 + displayText: 'Project: b' + entryId: project:./common/projects/b + entryPackageName: b + entryPackageVersion: '' + entrySuffix: '' + jsonId: 2 + kind: 1 + packageJsonFolderPath: ./common/projects/b + rawEntryId: ../../projects/b + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/e + name: '@rushstack/e' + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + version: link:../e + - dependencyType: regular + entryId: /@rushstack/k/1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + name: '@rushstack/k' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + - dependencyType: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + version: 1.0.0 + displayText: 'Project: c' + entryId: project:./common/projects/c + entryPackageName: c + entryPackageVersion: '' + entrySuffix: '' + jsonId: 3 + kind: 1 + packageJsonFolderPath: ./common/projects/c + rawEntryId: ../../projects/c + referrerJsonIds: [] + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: project:./common/projects/e + name: '@rushstack/e' + peerDependencyMeta: {} + resolvedEntryJsonId: 5 + version: link:../e + - dependencyType: regular + entryId: /@rushstack/j/1.0.0(@rushstack/n@2.0.0) + name: '@rushstack/j' + peerDependencyMeta: {} + resolvedEntryJsonId: 6 + version: 1.0.0(@rushstack/n@2.0.0) + - dependencyType: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + version: 2.0.0 + displayText: 'Project: d' + entryId: project:./common/projects/d + entryPackageName: d + entryPackageVersion: '' + entrySuffix: '' + jsonId: 4 + kind: 1 + packageJsonFolderPath: ./common/projects/d + rawEntryId: ../../projects/d + referrerJsonIds: + - 1 + - 2 + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: /@rushstack/n/3.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 11 + version: 3.0.0 + displayText: 'Project: e' + entryId: project:./common/projects/e + entryPackageName: e + entryPackageVersion: '' + entrySuffix: '' + jsonId: 5 + kind: 1 + packageJsonFolderPath: ./common/projects/e + rawEntryId: ../../projects/e + referrerJsonIds: + - 3 + - 4 + transitivePeerDependencies: [] + - dependencies: + - dependencyType: regular + entryId: /@rushstack/k/1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + name: '@rushstack/k' + peerDependencyMeta: {} + resolvedEntryJsonId: 7 + version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + - dependencyType: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + version: 1.0.0 + displayText: '@rushstack/j/1.0.0(@rushstack n@2.0.0)' + entryId: '' + entryPackageName: '@rushstack/j/1.0.0(@rushstack' + entryPackageVersion: n@2.0.0) + entrySuffix: '' + jsonId: 6 + kind: 2 + packageJsonFolderPath: >- + common/temp/undefined/node_modules/.pnpm/@rushstack+j/1.0.0(@rushstack@n@2.0.0)/node_modules/@rushstack/j/1.0.0(@rushstack + rawEntryId: /@rushstack/j/1.0.0(@rushstack/n@2.0.0) + referrerJsonIds: + - 4 + transitivePeerDependencies: + - '@rushstack/n' + - dependencies: + - dependencyType: regular + entryId: /@rushstack/l/1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + name: '@rushstack/l' + peerDependencyMeta: {} + resolvedEntryJsonId: 8 + version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + displayText: '@rushstack/k/1.0.0(@rushstack/m@1.0.0)(@rushstack n@2.0.0)' + entryId: '' + entryPackageName: '@rushstack/k/1.0.0(@rushstack/m@1.0.0)(@rushstack' + entryPackageVersion: n@2.0.0) + entrySuffix: '' + jsonId: 7 + kind: 2 + packageJsonFolderPath: >- + common/temp/undefined/node_modules/.pnpm/@rushstack+k/1.0.0(@rushstack/m@1.0.0)(@rushstack@n@2.0.0)/node_modules/@rushstack/k/1.0.0(@rushstack/m@1.0.0)(@rushstack + rawEntryId: /@rushstack/k/1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + referrerJsonIds: + - 3 + - 6 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + - dependencies: + - dependencyType: regular + entryId: /@rushstack/m/1.0.0 + name: '@rushstack/m' + peerDependencyMeta: {} + resolvedEntryJsonId: 9 + version: 1.0.0 + - dependencyType: regular + entryId: /@rushstack/n/2.0.0 + name: '@rushstack/n' + peerDependencyMeta: {} + resolvedEntryJsonId: 10 + version: 2.0.0 + - dependencyType: peer + entryId: 'Peer: @rushstack/m' + name: '@rushstack/m' + peerDependencyMeta: + name: '@rushstack/m' + optional: false + version: ^1.0.0 + version: ^1.0.0 + - dependencyType: peer + entryId: 'Peer: @rushstack/n' + name: '@rushstack/n' + peerDependencyMeta: + name: '@rushstack/n' + optional: true + version: ^2.0.0 + version: ^2.0.0 + displayText: '@rushstack/l/1.0.0(@rushstack/m@1.0.0)(@rushstack n@2.0.0)' + entryId: '' + entryPackageName: '@rushstack/l/1.0.0(@rushstack/m@1.0.0)(@rushstack' + entryPackageVersion: n@2.0.0) + entrySuffix: '' + jsonId: 8 + kind: 2 + packageJsonFolderPath: >- + common/temp/undefined/node_modules/.pnpm/@rushstack+l/1.0.0(@rushstack/m@1.0.0)(@rushstack@n@2.0.0)/node_modules/@rushstack/l/1.0.0(@rushstack/m@1.0.0)(@rushstack + rawEntryId: /@rushstack/l/1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + referrerJsonIds: + - 7 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/m 1.0.0' + entryId: '' + entryPackageName: '@rushstack/m' + entryPackageVersion: 1.0.0 + entrySuffix: '' + jsonId: 9 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+m@1.0.0/node_modules/@rushstack/m + rawEntryId: /@rushstack/m/1.0.0 + referrerJsonIds: + - 3 + - 6 + - 8 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 2.0.0' + entryId: '' + entryPackageName: '@rushstack/n' + entryPackageVersion: 2.0.0 + entrySuffix: '' + jsonId: 10 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+n@2.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n/2.0.0 + referrerJsonIds: + - 2 + - 4 + - 8 + transitivePeerDependencies: [] + - dependencies: [] + displayText: '@rushstack/n 3.0.0' + entryId: '' + entryPackageName: '@rushstack/n' + entryPackageVersion: 3.0.0 + entrySuffix: '' + jsonId: 11 + kind: 2 + packageJsonFolderPath: common/temp/undefined/node_modules/.pnpm/@rushstack+n@3.0.0/node_modules/@rushstack/n + rawEntryId: /@rushstack/n/3.0.0 + referrerJsonIds: + - 5 + transitivePeerDependencies: [] +workspace: + pnpmLockfilePath: common/temp/pnpm-lock.yaml + rushConfig: + rushVersion: 5.158.1 + subspaceName: '' + workspaceRootFolder: /repo +" +`; diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v5.4-rush.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v5.4-rush.yaml new file mode 100644 index 00000000000..f1fb1554c57 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v5.4-rush.yaml @@ -0,0 +1,134 @@ +lockfileVersion: 5.4 + +importers: + .: + specifiers: {} + + ../../projects/a: + specifiers: + '@rushstack/d': workspace:* + dependencies: + '@rushstack/d': link:../d + + ../../projects/b: + specifiers: + '@rushstack/d': workspace:* + '@rushstack/n': ^2.0.0 + dependencies: + '@rushstack/d': link:../d + '@rushstack/n': 2.0.0 + + ../../projects/c: + specifiers: + '@rushstack/e': workspace:* + '@rushstack/k': ^1.0.0 + '@rushstack/m': ~1.0.0 + dependencies: + '@rushstack/e': link:../e + '@rushstack/k': 1.0.0_@rushstack+m@1.0.0 + '@rushstack/m': 1.0.0 + + ../../projects/d: + specifiers: + '@rushstack/e': workspace:* + '@rushstack/j': ^1.0.0 + '@rushstack/n': ^2.0.0 + dependencies: + '@rushstack/e': link:../e + '@rushstack/j': 1.0.0_@rushstack+n@2.0.0 + '@rushstack/n': 2.0.0 + + ../../projects/e: + specifiers: + '@rushstack/n': ^3.0.0 + dependencies: + '@rushstack/n': 3.0.0 + +packages: + /@rushstack/j/1.0.0_@rushstack+n@2.0.0: + resolution: + { + integrity: sha512-D799Tv8advqKGl9u/j1x1cTG1pef6uY9CE7ETPqz9RHSNTRBL4Ftw98M95EK/dWS41OFlJ+eNGVwzWn3PjL85g== + } + dependencies: + '@rushstack/k': 1.0.0_wxpgugna4ivthu7yyu4fmciltu + '@rushstack/m': 1.0.0 + transitivePeerDependencies: + - '@rushstack/n' + dev: false + + /@rushstack/k/1.0.0_@rushstack+m@1.0.0: + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + dependencies: + '@rushstack/l': 1.0.0_@rushstack+m@1.0.0 + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + dev: false + + /@rushstack/k/1.0.0_wxpgugna4ivthu7yyu4fmciltu: + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + dependencies: + '@rushstack/l': 1.0.0_wxpgugna4ivthu7yyu4fmciltu + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + dev: false + + /@rushstack/l/1.0.0_@rushstack+m@1.0.0: + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + dependencies: + '@rushstack/m': 1.0.0 + dev: false + + /@rushstack/l/1.0.0_wxpgugna4ivthu7yyu4fmciltu: + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + dependencies: + '@rushstack/m': 1.0.0 + '@rushstack/n': 2.0.0 + dev: false + + /@rushstack/m/1.0.0: + resolution: + { + integrity: sha512-iZtUynf07U6UNf4QeYFdCNq7t+VTB3YyRb66v2U0uc3yP486dbXFO4LCCyqPpCsRlkwt4y/hKJH7lsODB+ISMA== + } + dev: false + + /@rushstack/n/2.0.0: + resolution: + { + integrity: sha512-cOGhNwbSaZv6hcfuUtut43vENNyGAPlhNU7r2kixj7dKKeyiQ1XlyhABxvFya2qEyFDRjbFW7/gSMrFmtLAxRg== + } + dev: false + + /@rushstack/n/3.0.0: + resolution: + { + integrity: sha512-GyiYvYT2KHlVlsiQ1Z+Lgt7lB5SR6axKASYKaj9qM+ycvpHTs8MoHJGp/Mbt+Iqrjfjlk3t4cXzLvftqFbPWuw== + } + dev: false diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v6.0-rush.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v6.0-rush.yaml new file mode 100644 index 00000000000..8a8bc8077ac --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v6.0-rush.yaml @@ -0,0 +1,115 @@ +lockfileVersion: '6.0' + +settings: + autoInstallPeers: false + excludeLinksFromLockfile: false + +importers: + .: {} + + ../../projects/a: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + + ../../projects/b: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + ../../projects/c: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/k': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': + specifier: ~1.0.0 + version: 1.0.0 + + ../../projects/d: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/j': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/n@2.0.0) + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + ../../projects/e: + dependencies: + '@rushstack/n': + specifier: ^3.0.0 + version: 3.0.0 + +packages: + /@rushstack/j@1.0.0(@rushstack/n@2.0.0): + resolution: + { + integrity: sha512-D799Tv8advqKGl9u/j1x1cTG1pef6uY9CE7ETPqz9RHSNTRBL4Ftw98M95EK/dWS41OFlJ+eNGVwzWn3PjL85g== + } + dependencies: + '@rushstack/k': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': 1.0.0 + transitivePeerDependencies: + - '@rushstack/n' + dev: false + + /@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0): + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + dependencies: + '@rushstack/l': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + dev: false + + /@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0): + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + dependencies: + '@rushstack/m': 1.0.0 + '@rushstack/n': 2.0.0 + dev: false + + /@rushstack/m@1.0.0: + resolution: + { + integrity: sha512-iZtUynf07U6UNf4QeYFdCNq7t+VTB3YyRb66v2U0uc3yP486dbXFO4LCCyqPpCsRlkwt4y/hKJH7lsODB+ISMA== + } + dev: false + + /@rushstack/n@2.0.0: + resolution: + { + integrity: sha512-cOGhNwbSaZv6hcfuUtut43vENNyGAPlhNU7r2kixj7dKKeyiQ1XlyhABxvFya2qEyFDRjbFW7/gSMrFmtLAxRg== + } + dev: false + + /@rushstack/n@3.0.0: + resolution: + { + integrity: sha512-GyiYvYT2KHlVlsiQ1Z+Lgt7lB5SR6axKASYKaj9qM+ycvpHTs8MoHJGp/Mbt+Iqrjfjlk3t4cXzLvftqFbPWuw== + } + dev: false diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-pnpm.yaml b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-pnpm.yaml new file mode 100644 index 00000000000..60de289e509 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/pnpm-lock-v9.0-pnpm.yaml @@ -0,0 +1,123 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +pnpmfileChecksum: sha256-6Cq2BFB3826lbTciEnsPowoZ1qvFZeM4wkoGwobxneY= + +importers: + projects/a: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + + projects/b: + dependencies: + '@rushstack/d': + specifier: workspace:* + version: link:../d + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + projects/c: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/k': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': + specifier: ~1.0.0 + version: 1.0.0 + + projects/d: + dependencies: + '@rushstack/e': + specifier: workspace:* + version: link:../e + '@rushstack/j': + specifier: ^1.0.0 + version: 1.0.0(@rushstack/n@2.0.0) + '@rushstack/n': + specifier: ^2.0.0 + version: 2.0.0 + + projects/e: + dependencies: + '@rushstack/n': + specifier: ^3.0.0 + version: 3.0.0 + +packages: + '@rushstack/j@1.0.0': + resolution: + { + integrity: sha512-D799Tv8advqKGl9u/j1x1cTG1pef6uY9CE7ETPqz9RHSNTRBL4Ftw98M95EK/dWS41OFlJ+eNGVwzWn3PjL85g== + } + + '@rushstack/k@1.0.0': + resolution: + { + integrity: sha512-HIap/n3FPoZMx+J6GbzziJTaVd8Q0FpHXUgYU1EHSM7Sy6suMbCxx6KSRuuM0Iv2BB3rht5jn6yv2l7pGBpXAA== + } + + '@rushstack/l@1.0.0': + resolution: + { + integrity: sha512-qJvPD0WLK6P+4KmczcuKA0f/6oUpZXYWYPIvMNJfasFy3DGMoUHg+3TSpisqQQb7OuWzf1mHQCG/suYiIeXQaQ== + } + peerDependencies: + '@rushstack/m': ^1.0.0 + '@rushstack/n': ^2.0.0 + peerDependenciesMeta: + '@rushstack/n': + optional: true + + '@rushstack/m@1.0.0': + resolution: + { + integrity: sha512-iZtUynf07U6UNf4QeYFdCNq7t+VTB3YyRb66v2U0uc3yP486dbXFO4LCCyqPpCsRlkwt4y/hKJH7lsODB+ISMA== + } + + '@rushstack/n@2.0.0': + resolution: + { + integrity: sha512-cOGhNwbSaZv6hcfuUtut43vENNyGAPlhNU7r2kixj7dKKeyiQ1XlyhABxvFya2qEyFDRjbFW7/gSMrFmtLAxRg== + } + + '@rushstack/n@3.0.0': + resolution: + { + integrity: sha512-GyiYvYT2KHlVlsiQ1Z+Lgt7lB5SR6axKASYKaj9qM+ycvpHTs8MoHJGp/Mbt+Iqrjfjlk3t4cXzLvftqFbPWuw== + } + +snapshots: + '@rushstack/j@1.0.0(@rushstack/n@2.0.0)': + dependencies: + '@rushstack/k': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + '@rushstack/m': 1.0.0 + transitivePeerDependencies: + - '@rushstack/n' + + '@rushstack/k@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)': + dependencies: + '@rushstack/l': 1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0) + transitivePeerDependencies: + - '@rushstack/m' + - '@rushstack/n' + + '@rushstack/l@1.0.0(@rushstack/m@1.0.0)(@rushstack/n@2.0.0)': + dependencies: + '@rushstack/m': 1.0.0 + optionalDependencies: + '@rushstack/n': 2.0.0 + + '@rushstack/m@1.0.0': {} + + '@rushstack/n@2.0.0': {} + + '@rushstack/n@3.0.0': {} diff --git a/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/website-sample-1.md b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/website-sample-1.md new file mode 100644 index 00000000000..62e16149c48 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/fixtures/website-sample-1/website-sample-1.md @@ -0,0 +1,12 @@ +# fixtures/website-sample-1 + +This test fixture uses the `demos/sample-1` branch from the Lockfile Explorer website demos repistory: + +https://github.com/microsoft/lockfile-explorer-demos/tree/demo/sample-1 + +There are three versions of the lockfile: + + +- `pnpm-lock-v5.4-rush.yaml`: The old 5.4 YAML format generated using PNPM 7.16.1 and Rush 5.83.3 from [`ee8a06e`](https://github.com/microsoft/lockfile-explorer-demos/commit/ee8a06e71b63feb806f240de01e57d42854d02af). +- `pnpm-lock-v6.0-rush.yaml`: The 6.0 YAML format generated using PNPM 8.15.9 and Rush 5.158.1 from [`8c3ad3c`](https://github.com/microsoft/lockfile-explorer-demos/commit/8c3ad3cad68a921baa4eb6d264d293e928a962f5) +- `pnpm-lock-v9.0-pnpm.yaml`: For comparison, a lockfile generated using a PNPM 9.15.9 with a plain PNPM workspace (without Rush). Rush doesn't support this format yet. diff --git a/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts b/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts new file mode 100644 index 00000000000..52583dec6c2 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/graphTestHelpers.ts @@ -0,0 +1,36 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import * as path from 'path'; +import yaml from 'js-yaml'; +import { FileSystem, NewlineKind } from '@rushstack/node-core-library'; +import { + type IJsonLfxGraph, + type IJsonLfxWorkspace, + lfxGraphSerializer, + type LfxGraph +} from '../../../build/lfx-shared'; + +import * as lfxGraphLoader from '../lfxGraphLoader'; + +const FIXTURES_FOLDER: string = path.resolve(__dirname, '../../../src/graph/test/fixtures/'); + +export async function loadAndSerializeLFxGraphAsync(options: { + workspace: IJsonLfxWorkspace; + lockfilePathUnderFixtures: string; +}): Promise { + const lockfileYaml: string = await FileSystem.readFileAsync( + FIXTURES_FOLDER + options.lockfilePathUnderFixtures, + { convertLineEndings: NewlineKind.Lf } + ); + const lockfileObject = yaml.load(lockfileYaml) as lfxGraphLoader.ILockfilePackageType; + const graph: LfxGraph = lfxGraphLoader.generateLockfileGraph(options.workspace, lockfileObject); + const serializedObject: IJsonLfxGraph = lfxGraphSerializer.serializeToJson(graph); + const serializedYaml: string = yaml.dump(serializedObject, { + noRefs: true, + sortKeys: true, + noCompatMode: true, + lineWidth: 110 + }); + return serializedYaml; +} diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts new file mode 100644 index 00000000000..3ca5deda4b8 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v5.4.test.ts @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFolder: '/repo', + pnpmLockfilePath: 'common/temp/pnpm-lock.yaml', + rushConfig: { + rushVersion: '5.83.3', + subspaceName: '' + } +}; + +describe('lfxGraph-website-sample-1-v5.4', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLFxGraphAsync({ + lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v5.4-rush.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts new file mode 100644 index 00000000000..dd381d93a96 --- /dev/null +++ b/apps/lockfile-explorer/src/graph/test/lfxGraph-website-sample-1-v6.0.test.ts @@ -0,0 +1,25 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +import type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +import * as graphTestHelpers from './graphTestHelpers'; + +export const workspace: IJsonLfxWorkspace = { + workspaceRootFolder: '/repo', + pnpmLockfilePath: 'common/temp/pnpm-lock.yaml', + rushConfig: { + rushVersion: '5.158.1', + subspaceName: '' + } +}; + +describe('lfxGraph-website-sample-1-v6.0', () => { + it('loads a workspace', async () => { + const serializedYaml: string = await graphTestHelpers.loadAndSerializeLFxGraphAsync({ + lockfilePathUnderFixtures: '/website-sample-1/pnpm-lock-v6.0-rush.yaml', + workspace: workspace + }); + expect(serializedYaml).toMatchSnapshot(); + }); +}); diff --git a/apps/lockfile-explorer-web/src/parsing/test/lockfile.test.ts b/apps/lockfile-explorer/src/graph/test/lockfile.test.ts similarity index 87% rename from apps/lockfile-explorer-web/src/parsing/test/lockfile.test.ts rename to apps/lockfile-explorer/src/graph/test/lockfile.test.ts index d6cbc0626dc..8b89f8de00d 100644 --- a/apps/lockfile-explorer-web/src/parsing/test/lockfile.test.ts +++ b/apps/lockfile-explorer/src/graph/test/lockfile.test.ts @@ -1,16 +1,17 @@ // 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 type { LfxGraphEntry } from '../../../build/lfx-shared'; + +import { TEST_WORKSPACE, TEST_LOCKFILE } from './testLockfile'; import * as lfxGraphLoader from '../lfxGraphLoader'; -import type { LockfileEntry } from '../LfxGraph'; describe('LockfileGeneration', () => { it('creates a valid bi-directional graph', () => { - const resolvedPackages = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE).entries; + const resolvedPackages = lfxGraphLoader.generateLockfileGraph(TEST_WORKSPACE, TEST_LOCKFILE).entries; // Mapping of all the lockfile entries created by the lockfile - const resolvedPackagesMap: { [key: string]: LockfileEntry } = {}; + const resolvedPackagesMap: { [key: string]: LfxGraphEntry } = {}; 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/src/graph/test/serializeToJson.test.ts similarity index 90% rename from apps/lockfile-explorer-web/src/parsing/test/serializeToJson.test.ts rename to apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts index 2fe9915fbe8..977cae423be 100644 --- a/apps/lockfile-explorer-web/src/parsing/test/serializeToJson.test.ts +++ b/apps/lockfile-explorer/src/graph/test/serializeToJson.test.ts @@ -1,14 +1,14 @@ // 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 { lfxGraphSerializer, type LfxGraph } from '../../../build/lfx-shared'; + import * as lfxGraphLoader from '../lfxGraphLoader'; -import * as lfxGraphSerializer from '../lfxGraphSerializer'; -import type { LfxGraph } from '../LfxGraph'; +import { TEST_WORKSPACE, TEST_LOCKFILE } from './testLockfile'; describe('serializeToJson', () => { it('serializes a simple graph', () => { - const graph = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE); + const graph = lfxGraphLoader.generateLockfileGraph(TEST_WORKSPACE, TEST_LOCKFILE); expect(lfxGraphSerializer.serializeToJson(graph)).toMatchInlineSnapshot(` Object { @@ -99,12 +99,17 @@ Object { "transitivePeerDependencies": Array [], }, ], + "workspace": Object { + "pnpmLockfilePath": "/test/pnpm-lock.yaml", + "rushConfig": undefined, + "workspaceRootFolder": "/test", + }, } `); }); it('deserializes a simple graph', () => { - const originalGraph = lfxGraphLoader.generateLockfileGraph(TEST_LOCKFILE); + const originalGraph = lfxGraphLoader.generateLockfileGraph(TEST_WORKSPACE, TEST_LOCKFILE); const serialized: string = JSON.stringify( lfxGraphSerializer.serializeToJson(originalGraph), diff --git a/apps/lockfile-explorer-web/src/parsing/test/testLockfile.ts b/apps/lockfile-explorer/src/graph/test/testLockfile.ts similarity index 82% rename from apps/lockfile-explorer-web/src/parsing/test/testLockfile.ts rename to apps/lockfile-explorer/src/graph/test/testLockfile.ts index cd364697874..0ba13018fbc 100644 --- a/apps/lockfile-explorer-web/src/parsing/test/testLockfile.ts +++ b/apps/lockfile-explorer/src/graph/test/testLockfile.ts @@ -1,6 +1,14 @@ // Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. // See LICENSE in the project root for license information. +import type { IJsonLfxWorkspace } from '../../../build/lfx-shared'; + +export const TEST_WORKSPACE: IJsonLfxWorkspace = { + workspaceRootFolder: '/test', + pnpmLockfilePath: '/test/pnpm-lock.yaml', + rushConfig: undefined +}; + export const TEST_LOCKFILE = { lockfileVersion: 5.3, importers: { diff --git a/apps/lockfile-explorer/src/state/index.ts b/apps/lockfile-explorer/src/state/index.ts index d718311e17f..481d2812655 100644 --- a/apps/lockfile-explorer/src/state/index.ts +++ b/apps/lockfile-explorer/src/state/index.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 { ILfxWorkspace } from '@rushstack/lockfile-explorer-web/lib/types/lfxProtocol'; +import type { IJsonLfxWorkspace } from '../../build/lfx-shared'; export interface IAppState { lockfileExplorerProjectRoot: string; @@ -11,5 +11,5 @@ export interface IAppState { pnpmfileLocation: string; appVersion: string; debugMode: boolean; - lfxWorkspace: ILfxWorkspace; + lfxWorkspace: IJsonLfxWorkspace; } diff --git a/apps/lockfile-explorer/src/utils/init.ts b/apps/lockfile-explorer/src/utils/init.ts index 7cf20374902..73856ea7943 100644 --- a/apps/lockfile-explorer/src/utils/init.ts +++ b/apps/lockfile-explorer/src/utils/init.ts @@ -16,7 +16,7 @@ export const init = (options: { appVersion: string; debugMode: boolean; subspaceName: string; -}): IAppState => { +}): Omit => { const { lockfileExplorerProjectRoot, appVersion, debugMode, subspaceName } = options; const currentWorkingDirectory: string = path.resolve(process.cwd()); diff --git a/apps/lockfile-explorer/src/utils/shrinkwrap.ts b/apps/lockfile-explorer/src/utils/shrinkwrap.ts index 8cb289fc1e6..12792e3cebd 100644 --- a/apps/lockfile-explorer/src/utils/shrinkwrap.ts +++ b/apps/lockfile-explorer/src/utils/shrinkwrap.ts @@ -11,8 +11,9 @@ interface IPackageInfo { export function convertLockfileV6DepPathToV5DepPath(newDepPath: string): string { if (!newDepPath.includes('@', 2) || newDepPath.startsWith('file:')) return newDepPath; - const index = newDepPath.indexOf('@', newDepPath.indexOf('/@') + 2); - if (newDepPath.includes('(') && index > dependencyPathLockfilePreV9.indexOfPeersSuffix(newDepPath)) return newDepPath; + const index: number = newDepPath.indexOf('@', newDepPath.indexOf('/@') + 2); + if (newDepPath.includes('(') && index > dependencyPathLockfilePreV9.indexOfPeersSuffix(newDepPath)) + return newDepPath; return `${newDepPath.substring(0, index)}/${newDepPath.substring(index + 1)}`; } @@ -21,7 +22,8 @@ export function parseDependencyPath(shrinkwrapFileMajorVersion: number, newDepPa if (shrinkwrapFileMajorVersion === 6) { dependencyPath = convertLockfileV6DepPathToV5DepPath(newDepPath); } - const packageInfo = dependencyPathLockfilePreV9.parse(dependencyPath); + const packageInfo: ReturnType = + dependencyPathLockfilePreV9.parse(dependencyPath); return { name: packageInfo.name as string, peersSuffix: packageInfo.peersSuffix, @@ -55,5 +57,7 @@ export function splicePackageWithVersion( dependencyPackageName: string, dependencyPackageVersion: string ): string { - return `/${dependencyPackageName}${shrinkwrapFileMajorVersion === 6 ? '@' : '/'}${dependencyPackageVersion}`; + return `/${dependencyPackageName}${ + shrinkwrapFileMajorVersion === 6 ? '@' : '/' + }${dependencyPackageVersion}`; } diff --git a/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap b/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap index 06d73c0c646..fabda2846fd 100644 --- a/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap +++ b/build-tests/api-documenter-test/src/test/__snapshots__/snapshot.test.ts.snap @@ -11,36 +11,36 @@ summary: |- This project tests various documentation generation scenarios and doc comment syntaxes. classes: - - 'api-documenter-test!AbstractClass:class' - - 'api-documenter-test!DecoratorExample:class' - - 'api-documenter-test!DocBaseClass:class' - - 'api-documenter-test!DocClass1:class' - - 'api-documenter-test!DocClassInterfaceMerge:class' - - 'api-documenter-test!Generic:class' - - 'api-documenter-test!SystemEvent:class' + - api-documenter-test!AbstractClass:class + - api-documenter-test!DecoratorExample:class + - api-documenter-test!DocBaseClass:class + - api-documenter-test!DocClass1:class + - api-documenter-test!DocClassInterfaceMerge:class + - api-documenter-test!Generic:class + - api-documenter-test!SystemEvent:class interfaces: - - 'api-documenter-test!Constraint:interface' - - 'api-documenter-test!DefaultType:interface' - - 'api-documenter-test!DocClassInterfaceMerge:interface' - - 'api-documenter-test!IDocInterface1:interface' - - 'api-documenter-test!IDocInterface2:interface' - - 'api-documenter-test!IDocInterface3:interface' - - 'api-documenter-test!IDocInterface4:interface' - - 'api-documenter-test!IDocInterface5:interface' - - 'api-documenter-test!IDocInterface6:interface' - - 'api-documenter-test!IDocInterface7:interface' + - api-documenter-test!Constraint:interface + - api-documenter-test!DefaultType:interface + - api-documenter-test!DocClassInterfaceMerge:interface + - api-documenter-test!IDocInterface1:interface + - api-documenter-test!IDocInterface2:interface + - api-documenter-test!IDocInterface3:interface + - api-documenter-test!IDocInterface4:interface + - api-documenter-test!IDocInterface5:interface + - api-documenter-test!IDocInterface6:interface + - api-documenter-test!IDocInterface7:interface enums: - - 'api-documenter-test!DocEnum:enum' - - 'api-documenter-test!DocEnumNamespaceMerge:enum' + - api-documenter-test!DocEnum:enum + - api-documenter-test!DocEnumNamespaceMerge:enum typeAliases: - - 'api-documenter-test!ExampleDuplicateTypeAlias:type' - - 'api-documenter-test!ExampleTypeAlias:type' - - 'api-documenter-test!ExampleUnionTypeAlias:type' - - 'api-documenter-test!GenericTypeAlias:type' - - 'api-documenter-test!TypeAlias:type' + - api-documenter-test!ExampleDuplicateTypeAlias:type + - api-documenter-test!ExampleTypeAlias:type + - api-documenter-test!ExampleUnionTypeAlias:type + - api-documenter-test!GenericTypeAlias:type + - api-documenter-test!TypeAlias:type functions: - - name: 'exampleFunction(x, y)' - uid: 'api-documenter-test!exampleFunction:function(1)' + - name: exampleFunction(x, y) + uid: api-documenter-test!exampleFunction:function(1) package: api-documenter-test! summary: An exported function with hyperlinked parameters and return value. remarks: '' @@ -52,15 +52,15 @@ functions: parameters: - id: x description: an API item that should get hyperlinked - type: '' + type: - id: 'y' description: a system type that should NOT get hyperlinked type: number return: - type: '' + type: description: an interface that should get hyperlinked - name: yamlReferenceUniquenessTest() - uid: 'api-documenter-test!yamlReferenceUniquenessTest:function(1)' + uid: api-documenter-test!yamlReferenceUniquenessTest:function(1) package: api-documenter-test! summary: '' remarks: '' @@ -70,12 +70,12 @@ functions: syntax: content: 'export declare function yamlReferenceUniquenessTest(): IDocInterface1;' return: - type: '' + type: description: '' ", "/api-documenter-test/abstractclass.yml": "### YamlMime:TSType name: AbstractClass -uid: 'api-documenter-test!AbstractClass:class' +uid: api-documenter-test!AbstractClass:class package: api-documenter-test! fullName: AbstractClass summary: Some abstract class with abstract members. @@ -86,7 +86,7 @@ isDeprecated: false type: class properties: - name: property - uid: 'api-documenter-test!AbstractClass#property:member' + uid: api-documenter-test!AbstractClass#property:member package: api-documenter-test! fullName: property summary: Some abstract property. @@ -100,7 +100,7 @@ properties: type: number methods: - name: method() - uid: 'api-documenter-test!AbstractClass#method:member(1)' + uid: api-documenter-test!AbstractClass#method:member(1) package: api-documenter-test! fullName: method() summary: Some abstract method. @@ -116,7 +116,7 @@ methods: ", "/api-documenter-test/constraint.yml": "### YamlMime:TSType name: Constraint -uid: 'api-documenter-test!Constraint:interface' +uid: api-documenter-test!Constraint:interface package: api-documenter-test! fullName: Constraint summary: Type parameter constraint used by test case below. @@ -128,7 +128,7 @@ type: interface ", "/api-documenter-test/decoratorexample.yml": "### YamlMime:TSType name: DecoratorExample -uid: 'api-documenter-test!DecoratorExample:class' +uid: api-documenter-test!DecoratorExample:class package: api-documenter-test! fullName: DecoratorExample summary: '' @@ -139,7 +139,7 @@ isDeprecated: false type: class properties: - name: creationDate - uid: 'api-documenter-test!DecoratorExample#creationDate:member' + uid: api-documenter-test!DecoratorExample#creationDate:member package: api-documenter-test! fullName: creationDate summary: The date when the record was created. @@ -154,7 +154,7 @@ properties: ", "/api-documenter-test/defaulttype.yml": "### YamlMime:TSType name: DefaultType -uid: 'api-documenter-test!DefaultType:interface' +uid: api-documenter-test!DefaultType:interface package: api-documenter-test! fullName: DefaultType summary: Type parameter default type used by test case below. @@ -166,7 +166,7 @@ type: interface ", "/api-documenter-test/docbaseclass.yml": "### YamlMime:TSType name: DocBaseClass -uid: 'api-documenter-test!DocBaseClass:class' +uid: api-documenter-test!DocBaseClass:class package: api-documenter-test! fullName: DocBaseClass summary: Example base class @@ -177,7 +177,7 @@ isDeprecated: false type: class constructors: - name: (constructor)() - uid: 'api-documenter-test!DocBaseClass:constructor(1)' + uid: api-documenter-test!DocBaseClass:constructor(1) package: api-documenter-test! fullName: (constructor)() summary: The simple constructor for \`DocBaseClass\` @@ -188,7 +188,7 @@ constructors: syntax: content: constructor(); - name: (constructor)(x) - uid: 'api-documenter-test!DocBaseClass:constructor(2)' + uid: api-documenter-test!DocBaseClass:constructor(2) package: api-documenter-test! fullName: (constructor)(x) summary: The overloaded constructor for \`DocBaseClass\` @@ -205,7 +205,7 @@ constructors: ", "/api-documenter-test/docclass1.yml": "### YamlMime:TSType name: DocClass1 -uid: 'api-documenter-test!DocClass1:class' +uid: api-documenter-test!DocClass1:class package: api-documenter-test! fullName: DocClass1 summary: This is an example class. @@ -225,7 +225,7 @@ isDeprecated: false type: class properties: - name: multipleModifiersProperty - uid: 'api-documenter-test!DocClass1.multipleModifiersProperty:member' + uid: api-documenter-test!DocClass1.multipleModifiersProperty:member package: api-documenter-test! fullName: multipleModifiersProperty summary: Some property with multiple modifiers. @@ -238,7 +238,7 @@ properties: return: type: boolean - name: protectedProperty - uid: 'api-documenter-test!DocClass1#protectedProperty:member' + uid: api-documenter-test!DocClass1#protectedProperty:member package: api-documenter-test! fullName: protectedProperty summary: Some protected property. @@ -251,7 +251,7 @@ properties: return: type: string - name: readonlyProperty - uid: 'api-documenter-test!DocClass1#readonlyProperty:member' + uid: api-documenter-test!DocClass1#readonlyProperty:member package: api-documenter-test! fullName: readonlyProperty summary: '' @@ -264,7 +264,7 @@ properties: return: type: string - name: regularProperty - uid: 'api-documenter-test!DocClass1#regularProperty:member' + uid: api-documenter-test!DocClass1#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: This is a regular property that happens to use the SystemEvent type. @@ -275,9 +275,9 @@ properties: syntax: content: 'regularProperty: SystemEvent;' return: - type: '' + type: - name: writeableProperty - uid: 'api-documenter-test!DocClass1#writeableProperty:member' + uid: api-documenter-test!DocClass1#writeableProperty:member package: api-documenter-test! fullName: writeableProperty summary: '' @@ -293,7 +293,7 @@ properties: return: type: string - name: writeonlyProperty - uid: 'api-documenter-test!DocClass1#writeonlyProperty:member' + uid: api-documenter-test!DocClass1#writeonlyProperty:member package: api-documenter-test! fullName: writeonlyProperty summary: API Extractor will surface an \`ae-missing-getter\` finding for this property. @@ -307,7 +307,7 @@ properties: type: string methods: - name: deprecatedExample() - uid: 'api-documenter-test!DocClass1#deprecatedExample:member(1)' + uid: api-documenter-test!DocClass1#deprecatedExample:member(1) package: api-documenter-test! fullName: deprecatedExample() summary: '' @@ -321,10 +321,10 @@ methods: return: type: void description: '' - - name: 'exampleFunction(a, b)' - uid: 'api-documenter-test!DocClass1#exampleFunction:member(1)' + - name: exampleFunction(a, b) + uid: api-documenter-test!DocClass1#exampleFunction:member(1) package: api-documenter-test! - fullName: 'exampleFunction(a, b)' + fullName: exampleFunction(a, b) summary: This is an overloaded function. remarks: '' example: [] @@ -343,7 +343,7 @@ methods: type: string description: '' - name: exampleFunction(x) - uid: 'api-documenter-test!DocClass1#exampleFunction:member(2)' + uid: api-documenter-test!DocClass1#exampleFunction:member(2) package: api-documenter-test! fullName: exampleFunction(x) summary: This is also an overloaded function. @@ -361,7 +361,7 @@ methods: type: number description: '' - name: genericWithConstraintAndDefault(x) - uid: 'api-documenter-test!DocClass1#genericWithConstraintAndDefault:member(1)' + uid: api-documenter-test!DocClass1#genericWithConstraintAndDefault:member(1) package: api-documenter-test! fullName: genericWithConstraintAndDefault(x) summary: This is a method with a complex type parameter. @@ -379,7 +379,7 @@ methods: type: void description: '' - name: interestingEdgeCases() - uid: 'api-documenter-test!DocClass1#interestingEdgeCases:member(1)' + uid: api-documenter-test!DocClass1#interestingEdgeCases:member(1) package: api-documenter-test! fullName: interestingEdgeCases() summary: |- @@ -396,7 +396,7 @@ methods: type: void description: '' - name: optionalParamFunction(x) - uid: 'api-documenter-test!DocClass1#optionalParamFunction:member(1)' + uid: api-documenter-test!DocClass1#optionalParamFunction:member(1) package: api-documenter-test! fullName: optionalParamFunction(x) summary: This is a function with an optional parameter. @@ -413,10 +413,10 @@ methods: return: type: void description: '' - - name: 'sumWithExample(x, y)' - uid: 'api-documenter-test!DocClass1.sumWithExample:member(1)' + - name: sumWithExample(x, y) + uid: api-documenter-test!DocClass1.sumWithExample:member(1) package: api-documenter-test! - fullName: 'sumWithExample(x, y)' + fullName: sumWithExample(x, y) summary: Returns the sum of two numbers. remarks: This illustrates usage of the \`@example\` block tag. example: @@ -449,7 +449,7 @@ methods: type: number description: the sum of the two numbers - name: tableExample() - uid: 'api-documenter-test!DocClass1#tableExample:member(1)' + uid: api-documenter-test!DocClass1#tableExample:member(1) package: api-documenter-test! fullName: tableExample() summary: 'An example with tables:' @@ -464,7 +464,7 @@ methods: description: '' events: - name: malformedEvent - uid: 'api-documenter-test!DocClass1#malformedEvent:member' + uid: api-documenter-test!DocClass1#malformedEvent:member package: api-documenter-test! fullName: malformedEvent summary: This event should have been marked as readonly. @@ -475,9 +475,9 @@ events: syntax: content: 'malformedEvent: SystemEvent;' return: - type: '' + type: - name: modifiedEvent - uid: 'api-documenter-test!DocClass1#modifiedEvent:member' + uid: api-documenter-test!DocClass1#modifiedEvent:member package: api-documenter-test! fullName: modifiedEvent summary: This event is fired whenever the object is modified. @@ -488,12 +488,12 @@ events: syntax: content: 'readonly modifiedEvent: SystemEvent;' return: - type: '' -extends: '' + type: +extends: ", "/api-documenter-test/docclassinterfacemerge-class.yml": "### YamlMime:TSType name: DocClassInterfaceMerge -uid: 'api-documenter-test!DocClassInterfaceMerge:class' +uid: api-documenter-test!DocClassInterfaceMerge:class package: api-documenter-test! fullName: DocClassInterfaceMerge summary: Class that merges with interface @@ -508,7 +508,7 @@ type: class ", "/api-documenter-test/docclassinterfacemerge-interface.yml": "### YamlMime:TSType name: DocClassInterfaceMerge -uid: 'api-documenter-test!DocClassInterfaceMerge:interface' +uid: api-documenter-test!DocClassInterfaceMerge:interface package: api-documenter-test! fullName: DocClassInterfaceMerge summary: Interface that merges with class @@ -520,7 +520,7 @@ type: interface ", "/api-documenter-test/docenum.yml": "### YamlMime:TSEnum name: DocEnum -uid: 'api-documenter-test!DocEnum:enum' +uid: api-documenter-test!DocEnum:enum package: api-documenter-test! fullName: DocEnum summary: Docs for DocEnum @@ -530,12 +530,12 @@ isPreview: false isDeprecated: false fields: - name: One - uid: 'api-documenter-test!DocEnum.One:member' + uid: api-documenter-test!DocEnum.One:member package: api-documenter-test! summary: These are some docs for One value: '1' - name: Two - uid: 'api-documenter-test!DocEnum.Two:member' + uid: api-documenter-test!DocEnum.Two:member package: api-documenter-test! summary: |- These are some docs for Two. @@ -543,14 +543,14 @@ fields: [DocEnum.One](xref:api-documenter-test!DocEnum.One:member) is a direct link to another enum member. value: '2' - name: Zero - uid: 'api-documenter-test!DocEnum.Zero:member' + uid: api-documenter-test!DocEnum.Zero:member package: api-documenter-test! summary: These are some docs for Zero value: '0' ", "/api-documenter-test/docenumnamespacemerge-enum.yml": "### YamlMime:TSEnum name: DocEnumNamespaceMerge -uid: 'api-documenter-test!DocEnumNamespaceMerge:enum' +uid: api-documenter-test!DocEnumNamespaceMerge:enum package: api-documenter-test! fullName: DocEnumNamespaceMerge summary: Enum that merges with namespace @@ -565,19 +565,19 @@ isPreview: false isDeprecated: false fields: - name: Left - uid: 'api-documenter-test!DocEnumNamespaceMerge.Left:member' + uid: api-documenter-test!DocEnumNamespaceMerge.Left:member package: api-documenter-test! summary: These are some docs for Left value: '0' - name: Right - uid: 'api-documenter-test!DocEnumNamespaceMerge.Right:member' + uid: api-documenter-test!DocEnumNamespaceMerge.Right:member package: api-documenter-test! summary: These are some docs for Right value: '1' ", "/api-documenter-test/docenumnamespacemerge-namespace.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!DocEnumNamespaceMerge:namespace' + - uid: api-documenter-test!DocEnumNamespaceMerge:namespace summary: Namespace that merges with enum name: DocEnumNamespaceMerge fullName: DocEnumNamespaceMerge @@ -586,14 +586,14 @@ items: type: namespace package: api-documenter-test! children: - - 'api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1)' - - uid: 'api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1)' + - api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1) + - uid: api-documenter-test!DocEnumNamespaceMerge.exampleFunction:function(1) summary: This is a function inside of a namespace that merges with an enum. name: exampleFunction() fullName: DocEnumNamespaceMerge.exampleFunction() langs: - typeScript - namespace: 'api-documenter-test!DocEnumNamespaceMerge:namespace' + namespace: api-documenter-test!DocEnumNamespaceMerge:namespace type: function syntax: content: 'function exampleFunction(): void;' @@ -604,7 +604,7 @@ items: ", "/api-documenter-test/ecmasymbols.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!EcmaSymbols:namespace' + - uid: api-documenter-test!EcmaSymbols:namespace summary: A namespace containing an ECMAScript symbol name: EcmaSymbols fullName: EcmaSymbols @@ -613,14 +613,14 @@ items: type: namespace package: api-documenter-test! children: - - 'api-documenter-test!EcmaSymbols.example:var' - - uid: 'api-documenter-test!EcmaSymbols.example:var' + - api-documenter-test!EcmaSymbols.example:var + - uid: api-documenter-test!EcmaSymbols.example:var summary: An ECMAScript symbol name: example fullName: EcmaSymbols.example langs: - typeScript - namespace: 'api-documenter-test!EcmaSymbols:namespace' + namespace: api-documenter-test!EcmaSymbols:namespace type: variable syntax: content: 'example: unique symbol' @@ -630,7 +630,7 @@ items: ", "/api-documenter-test/exampleduplicatetypealias.yml": "### YamlMime:TSTypeAlias name: ExampleDuplicateTypeAlias -uid: 'api-documenter-test!ExampleDuplicateTypeAlias:type' +uid: api-documenter-test!ExampleDuplicateTypeAlias:type package: api-documenter-test! fullName: ExampleDuplicateTypeAlias summary: A type alias that has duplicate references. @@ -642,7 +642,7 @@ syntax: export type ExampleDuplicateTypeAlias = SystemEvent | typeof SystemEvent ", "/api-documenter-test/exampletypealias.yml": "### YamlMime:TSTypeAlias name: ExampleTypeAlias -uid: 'api-documenter-test!ExampleTypeAlias:type' +uid: api-documenter-test!ExampleTypeAlias:type package: api-documenter-test! fullName: ExampleTypeAlias summary: A type alias @@ -654,7 +654,7 @@ syntax: export type ExampleTypeAlias = Promise; ", "/api-documenter-test/exampleuniontypealias.yml": "### YamlMime:TSTypeAlias name: ExampleUnionTypeAlias -uid: 'api-documenter-test!ExampleUnionTypeAlias:type' +uid: api-documenter-test!ExampleUnionTypeAlias:type package: api-documenter-test! fullName: ExampleUnionTypeAlias summary: A type alias that references multiple other types. @@ -666,7 +666,7 @@ syntax: export type ExampleUnionTypeAlias = IDocInterface1 | IDocInterface3; ", "/api-documenter-test/generic.yml": "### YamlMime:TSType name: Generic -uid: 'api-documenter-test!Generic:class' +uid: api-documenter-test!Generic:class package: api-documenter-test! fullName: Generic summary: Generic class. @@ -678,7 +678,7 @@ type: class ", "/api-documenter-test/generictypealias.yml": "### YamlMime:TSTypeAlias name: GenericTypeAlias -uid: 'api-documenter-test!GenericTypeAlias:type' +uid: api-documenter-test!GenericTypeAlias:type package: api-documenter-test! fullName: GenericTypeAlias summary: '' @@ -686,11 +686,11 @@ remarks: '' example: [] isPreview: false isDeprecated: false -syntax: 'export type GenericTypeAlias = T[];' +syntax: export type GenericTypeAlias = T[]; ", "/api-documenter-test/idocinterface1.yml": "### YamlMime:TSType name: IDocInterface1 -uid: 'api-documenter-test!IDocInterface1:interface' +uid: api-documenter-test!IDocInterface1:interface package: api-documenter-test! fullName: IDocInterface1 summary: '' @@ -701,7 +701,7 @@ isDeprecated: false type: interface properties: - name: regularProperty - uid: 'api-documenter-test!IDocInterface1#regularProperty:member' + uid: api-documenter-test!IDocInterface1#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: Does something @@ -712,11 +712,11 @@ properties: syntax: content: 'regularProperty: SystemEvent;' return: - type: '' + type: ", "/api-documenter-test/idocinterface2.yml": "### YamlMime:TSType name: IDocInterface2 -uid: 'api-documenter-test!IDocInterface2:interface' +uid: api-documenter-test!IDocInterface2:interface package: api-documenter-test! fullName: IDocInterface2 summary: '' @@ -727,7 +727,7 @@ isDeprecated: false type: interface methods: - name: deprecatedExample() - uid: 'api-documenter-test!IDocInterface2#deprecatedExample:member(1)' + uid: api-documenter-test!IDocInterface2#deprecatedExample:member(1) package: api-documenter-test! fullName: deprecatedExample() summary: '' @@ -741,11 +741,11 @@ methods: return: type: void description: '' -extends: '' +extends: ", "/api-documenter-test/idocinterface3.yml": "### YamlMime:TSType name: IDocInterface3 -uid: 'api-documenter-test!IDocInterface3:interface' +uid: api-documenter-test!IDocInterface3:interface package: api-documenter-test! fullName: IDocInterface3 summary: Some less common TypeScript declaration kinds. @@ -756,7 +756,7 @@ isDeprecated: false type: interface properties: - name: '\\"[not.a.symbol]\\"' - uid: 'api-documenter-test!IDocInterface3#\\"[not.a.symbol]\\":member' + uid: api-documenter-test!IDocInterface3#\\"[not.a.symbol]\\":member package: api-documenter-test! fullName: '\\"[not.a.symbol]\\"' summary: An identifier that does need quotes. It misleadingly looks like an ECMAScript symbol. @@ -769,7 +769,7 @@ properties: return: type: string - name: '[EcmaSymbols.example]' - uid: 'api-documenter-test!IDocInterface3#[EcmaSymbols.example]:member' + uid: api-documenter-test!IDocInterface3#[EcmaSymbols.example]:member package: api-documenter-test! fullName: '[EcmaSymbols.example]' summary: ECMAScript symbol @@ -782,7 +782,7 @@ properties: return: type: string - name: redundantQuotes - uid: 'api-documenter-test!IDocInterface3#redundantQuotes:member' + uid: api-documenter-test!IDocInterface3#redundantQuotes:member package: api-documenter-test! fullName: redundantQuotes summary: A quoted identifier with redundant quotes. @@ -797,7 +797,7 @@ properties: ", "/api-documenter-test/idocinterface4.yml": "### YamlMime:TSType name: IDocInterface4 -uid: 'api-documenter-test!IDocInterface4:interface' +uid: api-documenter-test!IDocInterface4:interface package: api-documenter-test! fullName: IDocInterface4 summary: Type union in an interface. @@ -808,7 +808,7 @@ isDeprecated: false type: interface properties: - name: Context - uid: 'api-documenter-test!IDocInterface4#Context:member' + uid: api-documenter-test!IDocInterface4#Context:member package: api-documenter-test! fullName: Context summary: Test newline rendering when code blocks are used in tables @@ -827,7 +827,7 @@ properties: children: string; }) => boolean - name: generic - uid: 'api-documenter-test!IDocInterface4#generic:member' + uid: api-documenter-test!IDocInterface4#generic:member package: api-documenter-test! fullName: generic summary: make sure html entities are escaped in tables. @@ -838,9 +838,9 @@ properties: syntax: content: 'generic: Generic;' return: - type: '<number>' + type: <number> - name: numberOrFunction - uid: 'api-documenter-test!IDocInterface4#numberOrFunction:member' + uid: api-documenter-test!IDocInterface4#numberOrFunction:member package: api-documenter-test! fullName: numberOrFunction summary: a union type with a function @@ -853,7 +853,7 @@ properties: return: type: number | (() => number) - name: stringOrNumber - uid: 'api-documenter-test!IDocInterface4#stringOrNumber:member' + uid: api-documenter-test!IDocInterface4#stringOrNumber:member package: api-documenter-test! fullName: stringOrNumber summary: a union type @@ -868,7 +868,7 @@ properties: ", "/api-documenter-test/idocinterface5.yml": "### YamlMime:TSType name: IDocInterface5 -uid: 'api-documenter-test!IDocInterface5:interface' +uid: api-documenter-test!IDocInterface5:interface package: api-documenter-test! fullName: IDocInterface5 summary: Interface without inline tag to test custom TOC @@ -879,7 +879,7 @@ isDeprecated: false type: interface properties: - name: regularProperty - uid: 'api-documenter-test!IDocInterface5#regularProperty:member' + uid: api-documenter-test!IDocInterface5#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: Property of type string that does something @@ -894,7 +894,7 @@ properties: ", "/api-documenter-test/idocinterface6.yml": "### YamlMime:TSType name: IDocInterface6 -uid: 'api-documenter-test!IDocInterface6:interface' +uid: api-documenter-test!IDocInterface6:interface package: api-documenter-test! fullName: IDocInterface6 summary: Interface without inline tag to test custom TOC with injection @@ -905,7 +905,7 @@ isDeprecated: false type: interface properties: - name: arrayProperty - uid: 'api-documenter-test!IDocInterface6#arrayProperty:member' + uid: api-documenter-test!IDocInterface6#arrayProperty:member package: api-documenter-test! fullName: arrayProperty summary: '' @@ -916,9 +916,9 @@ properties: syntax: content: 'arrayProperty: IDocInterface1[];' return: - type: '[]' + type: [] - name: intersectionProperty - uid: 'api-documenter-test!IDocInterface6#intersectionProperty:member' + uid: api-documenter-test!IDocInterface6#intersectionProperty:member package: api-documenter-test! fullName: intersectionProperty summary: '' @@ -933,7 +933,7 @@ properties: & - name: regularProperty - uid: 'api-documenter-test!IDocInterface6#regularProperty:member' + uid: api-documenter-test!IDocInterface6#regularProperty:member package: api-documenter-test! fullName: regularProperty summary: Property of type number that does something @@ -946,7 +946,7 @@ properties: return: type: number - name: tupleProperty - uid: 'api-documenter-test!IDocInterface6#tupleProperty:member' + uid: api-documenter-test!IDocInterface6#tupleProperty:member package: api-documenter-test! fullName: tupleProperty summary: '' @@ -961,7 +961,7 @@ properties: [, ] - name: typeReferenceProperty - uid: 'api-documenter-test!IDocInterface6#typeReferenceProperty:member' + uid: api-documenter-test!IDocInterface6#typeReferenceProperty:member package: api-documenter-test! fullName: typeReferenceProperty summary: '' @@ -976,7 +976,7 @@ properties: <> - name: unionProperty - uid: 'api-documenter-test!IDocInterface6#unionProperty:member' + uid: api-documenter-test!IDocInterface6#unionProperty:member package: api-documenter-test! fullName: unionProperty summary: '' @@ -992,7 +992,7 @@ properties: uid=\\"api-documenter-test!IDocInterface2:interface\\" /> methods: - name: genericReferenceMethod(x) - uid: 'api-documenter-test!IDocInterface6#genericReferenceMethod:member(1)' + uid: api-documenter-test!IDocInterface6#genericReferenceMethod:member(1) package: api-documenter-test! fullName: genericReferenceMethod(x) summary: '' @@ -1012,7 +1012,7 @@ methods: ", "/api-documenter-test/idocinterface7.yml": "### YamlMime:TSType name: IDocInterface7 -uid: 'api-documenter-test!IDocInterface7:interface' +uid: api-documenter-test!IDocInterface7:interface package: api-documenter-test! fullName: IDocInterface7 summary: Interface for testing optional properties @@ -1023,7 +1023,7 @@ isDeprecated: false type: interface properties: - name: optionalField - uid: 'api-documenter-test!IDocInterface7#optionalField:member' + uid: api-documenter-test!IDocInterface7#optionalField:member package: api-documenter-test! fullName: optionalField summary: Description of optionalField @@ -1036,7 +1036,7 @@ properties: return: type: boolean - name: optionalReadonlyField - uid: 'api-documenter-test!IDocInterface7#optionalReadonlyField:member' + uid: api-documenter-test!IDocInterface7#optionalReadonlyField:member package: api-documenter-test! fullName: optionalReadonlyField summary: Description of optionalReadonlyField @@ -1049,7 +1049,7 @@ properties: return: type: boolean - name: optionalUndocumentedField - uid: 'api-documenter-test!IDocInterface7#optionalUndocumentedField:member' + uid: api-documenter-test!IDocInterface7#optionalUndocumentedField:member package: api-documenter-test! fullName: optionalUndocumentedField summary: '' @@ -1063,7 +1063,7 @@ properties: type: boolean methods: - name: optionalMember() - uid: 'api-documenter-test!IDocInterface7#optionalMember:member(1)' + uid: api-documenter-test!IDocInterface7#optionalMember:member(1) package: api-documenter-test! fullName: optionalMember() summary: Description of optionalMember @@ -1079,7 +1079,7 @@ methods: ", "/api-documenter-test/outernamespace.innernamespace.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + - uid: api-documenter-test!OuterNamespace.InnerNamespace:namespace summary: A nested namespace name: OuterNamespace.InnerNamespace fullName: OuterNamespace.InnerNamespace @@ -1088,14 +1088,14 @@ items: type: namespace package: api-documenter-test! children: - - 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' - - uid: 'api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1)' + - api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1) + - uid: api-documenter-test!OuterNamespace.InnerNamespace.nestedFunction:function(1) summary: A function inside a namespace name: nestedFunction(x) fullName: OuterNamespace.InnerNamespace.nestedFunction(x) langs: - typeScript - namespace: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + namespace: api-documenter-test!OuterNamespace.InnerNamespace:namespace type: function syntax: content: 'function nestedFunction(x: number): number;' @@ -1112,7 +1112,7 @@ items: ", "/api-documenter-test/outernamespace.yml": "### YamlMime:UniversalReference items: - - uid: 'api-documenter-test!OuterNamespace:namespace' + - uid: api-documenter-test!OuterNamespace:namespace summary: A top-level namespace name: OuterNamespace fullName: OuterNamespace @@ -1121,14 +1121,14 @@ items: type: namespace package: api-documenter-test! children: - - 'api-documenter-test!OuterNamespace.nestedVariable:var' - - uid: 'api-documenter-test!OuterNamespace.nestedVariable:var' + - api-documenter-test!OuterNamespace.nestedVariable:var + - uid: api-documenter-test!OuterNamespace.nestedVariable:var summary: A variable exported from within a namespace. name: nestedVariable fullName: OuterNamespace.nestedVariable langs: - typeScript - namespace: 'api-documenter-test!OuterNamespace:namespace' + namespace: api-documenter-test!OuterNamespace:namespace type: variable syntax: content: 'nestedVariable: boolean' @@ -1138,7 +1138,7 @@ items: ", "/api-documenter-test/systemevent.yml": "### YamlMime:TSType name: SystemEvent -uid: 'api-documenter-test!SystemEvent:class' +uid: api-documenter-test!SystemEvent:class package: api-documenter-test! fullName: SystemEvent summary: A class used to exposed events. @@ -1149,7 +1149,7 @@ isDeprecated: false type: class methods: - name: addHandler(handler) - uid: 'api-documenter-test!SystemEvent#addHandler:member(1)' + uid: api-documenter-test!SystemEvent#addHandler:member(1) package: api-documenter-test! fullName: addHandler(handler) summary: Adds an handler for the event. @@ -1169,7 +1169,7 @@ methods: ", "/api-documenter-test/typealias.yml": "### YamlMime:TSTypeAlias name: TypeAlias -uid: 'api-documenter-test!TypeAlias:type' +uid: api-documenter-test!TypeAlias:type package: api-documenter-test! fullName: TypeAlias summary: '' @@ -1191,75 +1191,75 @@ syntax: export type TypeAlias = number; - name: DocBaseClass items: - name: DocBaseClass - uid: 'api-documenter-test!DocBaseClass:class' + uid: api-documenter-test!DocBaseClass:class - name: IDocInterface1 - uid: 'api-documenter-test!IDocInterface1:interface' + uid: api-documenter-test!IDocInterface1:interface - name: IDocInterface2 - uid: 'api-documenter-test!IDocInterface2:interface' + uid: api-documenter-test!IDocInterface2:interface - name: DocClass1 items: - name: DocClass1 - uid: 'api-documenter-test!DocClass1:class' + uid: api-documenter-test!DocClass1:class - name: IDocInterface3 - uid: 'api-documenter-test!IDocInterface3:interface' + uid: api-documenter-test!IDocInterface3:interface - name: IDocInterface4 - uid: 'api-documenter-test!IDocInterface4:interface' + uid: api-documenter-test!IDocInterface4:interface - name: Interfaces items: - name: Interface5 items: - name: IDocInterface5 - uid: 'api-documenter-test!IDocInterface5:interface' + uid: api-documenter-test!IDocInterface5:interface - name: Interface6 items: - name: InjectedCustomInterface uid: customUid - name: IDocInterface6 - uid: 'api-documenter-test!IDocInterface6:interface' + uid: api-documenter-test!IDocInterface6:interface - name: References items: - name: InjectedCustomItem uid: customUrl - name: AbstractClass - uid: 'api-documenter-test!AbstractClass:class' + uid: api-documenter-test!AbstractClass:class - name: Constraint - uid: 'api-documenter-test!Constraint:interface' + uid: api-documenter-test!Constraint:interface - name: DecoratorExample - uid: 'api-documenter-test!DecoratorExample:class' + uid: api-documenter-test!DecoratorExample:class - name: DefaultType - uid: 'api-documenter-test!DefaultType:interface' + uid: api-documenter-test!DefaultType:interface - name: DocClassInterfaceMerge (Class) - uid: 'api-documenter-test!DocClassInterfaceMerge:class' + uid: api-documenter-test!DocClassInterfaceMerge:class - name: DocClassInterfaceMerge (Interface) - uid: 'api-documenter-test!DocClassInterfaceMerge:interface' + uid: api-documenter-test!DocClassInterfaceMerge:interface - name: DocEnum - uid: 'api-documenter-test!DocEnum:enum' + uid: api-documenter-test!DocEnum:enum - name: DocEnumNamespaceMerge (Enum) - uid: 'api-documenter-test!DocEnumNamespaceMerge:enum' + uid: api-documenter-test!DocEnumNamespaceMerge:enum - name: DocEnumNamespaceMerge (Namespace) - uid: 'api-documenter-test!DocEnumNamespaceMerge:namespace' + uid: api-documenter-test!DocEnumNamespaceMerge:namespace - name: EcmaSymbols - uid: 'api-documenter-test!EcmaSymbols:namespace' + uid: api-documenter-test!EcmaSymbols:namespace - name: ExampleDuplicateTypeAlias - uid: 'api-documenter-test!ExampleDuplicateTypeAlias:type' + uid: api-documenter-test!ExampleDuplicateTypeAlias:type - name: ExampleTypeAlias - uid: 'api-documenter-test!ExampleTypeAlias:type' + uid: api-documenter-test!ExampleTypeAlias:type - name: ExampleUnionTypeAlias - uid: 'api-documenter-test!ExampleUnionTypeAlias:type' + uid: api-documenter-test!ExampleUnionTypeAlias:type - name: Generic - uid: 'api-documenter-test!Generic:class' + uid: api-documenter-test!Generic:class - name: GenericTypeAlias - uid: 'api-documenter-test!GenericTypeAlias:type' + uid: api-documenter-test!GenericTypeAlias:type - name: IDocInterface7 - uid: 'api-documenter-test!IDocInterface7:interface' + uid: api-documenter-test!IDocInterface7:interface - name: OuterNamespace - uid: 'api-documenter-test!OuterNamespace:namespace' + uid: api-documenter-test!OuterNamespace:namespace - name: OuterNamespace.InnerNamespace - uid: 'api-documenter-test!OuterNamespace.InnerNamespace:namespace' + uid: api-documenter-test!OuterNamespace.InnerNamespace:namespace - name: SystemEvent - uid: 'api-documenter-test!SystemEvent:class' + uid: api-documenter-test!SystemEvent:class - name: TypeAlias - uid: 'api-documenter-test!TypeAlias:type' + uid: api-documenter-test!TypeAlias:type ", } `; diff --git a/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json b/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json index 5b39d9101b7..d95757eac5e 100644 --- a/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json +++ b/build-tests/api-extractor-test-05/dist/tsdoc-metadata.json @@ -5,7 +5,7 @@ "toolPackages": [ { "packageName": "@microsoft/api-extractor", - "packageVersion": "7.52.11" + "packageVersion": "7.52.13" } ] } diff --git a/common/changes/@microsoft/api-documenter/octogonz-js-yaml-upgrade_2025-09-14-20-16.json b/common/changes/@microsoft/api-documenter/octogonz-js-yaml-upgrade_2025-09-14-20-16.json new file mode 100644 index 00000000000..a26c6b3afd1 --- /dev/null +++ b/common/changes/@microsoft/api-documenter/octogonz-js-yaml-upgrade_2025-09-14-20-16.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Upgraded `js-yaml` dependency", + "type": "patch", + "packageName": "@microsoft/api-documenter" + } + ], + "packageName": "@microsoft/api-documenter", + "email": "4673363+octogonz@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@microsoft/rush/octogonz-js-yaml-upgrade_2025-09-14-20-16.json b/common/changes/@microsoft/rush/octogonz-js-yaml-upgrade_2025-09-14-20-16.json new file mode 100644 index 00000000000..bf925b6cda8 --- /dev/null +++ b/common/changes/@microsoft/rush/octogonz-js-yaml-upgrade_2025-09-14-20-16.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Upgraded `js-yaml` dependency", + "type": "none", + "packageName": "@microsoft/rush" + } + ], + "packageName": "@microsoft/rush", + "email": "4673363+octogonz@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/lockfile-explorer/octogonz-js-yaml-upgrade_2025-09-14-20-16.json b/common/changes/@rushstack/lockfile-explorer/octogonz-js-yaml-upgrade_2025-09-14-20-16.json new file mode 100644 index 00000000000..8675acd12cd --- /dev/null +++ b/common/changes/@rushstack/lockfile-explorer/octogonz-js-yaml-upgrade_2025-09-14-20-16.json @@ -0,0 +1,11 @@ +{ + "changes": [ + { + "comment": "Upgraded `js-yaml` dependency", + "type": "patch", + "packageName": "@rushstack/lockfile-explorer" + } + ], + "packageName": "@rushstack/lockfile-explorer", + "email": "4673363+octogonz@users.noreply.github.com" +} \ No newline at end of file diff --git a/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-fixes2_2025-09-14-05-29.json b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-fixes2_2025-09-14-05-29.json new file mode 100644 index 00000000000..22d17643a68 --- /dev/null +++ b/common/changes/@rushstack/lockfile-explorer/octogonz-lfx-fixes2_2025-09-14-05-29.json @@ -0,0 +1,10 @@ +{ + "changes": [ + { + "packageName": "@rushstack/lockfile-explorer", + "comment": "", + "type": "none" + } + ], + "packageName": "@rushstack/lockfile-explorer" +} \ No newline at end of file diff --git a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml index 31209c4ff7f..7c125ac9f67 100644 --- a/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml +++ b/common/config/subspaces/build-tests-subspace/pnpm-lock.yaml @@ -105,10 +105,10 @@ importers: version: file:../../../apps/heft(@types/node@20.17.19) '@rushstack/heft-lint-plugin': specifier: file:../../heft-plugins/heft-lint-plugin - version: file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19) + version: file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19) '@rushstack/heft-typescript-plugin': specifier: file:../../heft-plugins/heft-typescript-plugin - version: file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19) + version: file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19) eslint: specifier: ~9.25.1 version: 9.25.1 @@ -4516,13 +4516,6 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - /js-yaml@3.13.1: - resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true @@ -6902,7 +6895,7 @@ packages: - supports-color dev: true - file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19): + file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19): resolution: {directory: ../../../heft-plugins/heft-api-extractor-plugin, type: directory} id: file:../../../heft-plugins/heft-api-extractor-plugin name: '@rushstack/heft-api-extractor-plugin' @@ -6916,7 +6909,7 @@ packages: - '@types/node' dev: true - file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19)(jest-environment-node@29.5.0): + file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19)(jest-environment-node@29.5.0): resolution: {directory: ../../../heft-plugins/heft-jest-plugin, type: directory} id: file:../../../heft-plugins/heft-jest-plugin name: '@rushstack/heft-jest-plugin' @@ -6951,7 +6944,7 @@ packages: - ts-node dev: true - file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19): + file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19): resolution: {directory: ../../../heft-plugins/heft-lint-plugin, type: directory} id: file:../../../heft-plugins/heft-lint-plugin name: '@rushstack/heft-lint-plugin' @@ -6966,7 +6959,7 @@ packages: - '@types/node' dev: true - file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19): + file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19): resolution: {directory: ../../../heft-plugins/heft-typescript-plugin, type: directory} id: file:../../../heft-plugins/heft-typescript-plugin name: '@rushstack/heft-typescript-plugin' @@ -7120,7 +7113,7 @@ packages: https-proxy-agent: 5.0.1 ignore: 5.1.9 inquirer: 8.2.7(@types/node@20.17.19) - js-yaml: 3.13.1 + js-yaml: 4.1.0 npm-check: 6.0.1 npm-package-arg: 6.1.1 pnpm-sync-lib: 0.3.2 @@ -7193,7 +7186,7 @@ packages: transitivePeerDependencies: - '@types/node' - file:../../../rigs/heft-node-rig(@rushstack/heft@0.74.3)(@types/node@20.17.19): + file:../../../rigs/heft-node-rig(@rushstack/heft@0.74.5)(@types/node@20.17.19): resolution: {directory: ../../../rigs/heft-node-rig, type: directory} id: file:../../../rigs/heft-node-rig name: '@rushstack/heft-node-rig' @@ -7203,10 +7196,10 @@ packages: '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@20.17.19) '@rushstack/eslint-config': file:../../../eslint/eslint-config(eslint@9.25.1)(typescript@5.8.2) '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) - '@rushstack/heft-api-extractor-plugin': file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19) - '@rushstack/heft-jest-plugin': file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19)(jest-environment-node@29.5.0) - '@rushstack/heft-lint-plugin': file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19) - '@rushstack/heft-typescript-plugin': file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.74.3)(@types/node@20.17.19) + '@rushstack/heft-api-extractor-plugin': file:../../../heft-plugins/heft-api-extractor-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19) + '@rushstack/heft-jest-plugin': file:../../../heft-plugins/heft-jest-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19)(jest-environment-node@29.5.0) + '@rushstack/heft-lint-plugin': file:../../../heft-plugins/heft-lint-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19) + '@rushstack/heft-typescript-plugin': file:../../../heft-plugins/heft-typescript-plugin(@rushstack/heft@0.74.5)(@types/node@20.17.19) '@types/heft-jest': 1.0.1 eslint: 9.25.1 jest-environment-node: 29.5.0 @@ -7228,7 +7221,7 @@ packages: '@microsoft/api-extractor': file:../../../apps/api-extractor(@types/node@20.17.19) '@rushstack/eslint-patch': file:../../../eslint/eslint-patch '@rushstack/heft': file:../../../apps/heft(@types/node@20.17.19) - '@rushstack/heft-node-rig': file:../../../rigs/heft-node-rig(@rushstack/heft@0.74.3)(@types/node@20.17.19) + '@rushstack/heft-node-rig': file:../../../rigs/heft-node-rig(@rushstack/heft@0.74.5)(@types/node@20.17.19) '@types/heft-jest': 1.0.1 '@types/node': 20.17.19 eslint: 9.25.1 diff --git a/common/config/subspaces/build-tests-subspace/repo-state.json b/common/config/subspaces/build-tests-subspace/repo-state.json index c8006dca5f9..df8d3168341 100644 --- a/common/config/subspaces/build-tests-subspace/repo-state.json +++ b/common/config/subspaces/build-tests-subspace/repo-state.json @@ -1,6 +1,6 @@ // DO NOT MODIFY THIS FILE MANUALLY BUT DO COMMIT IT. It is generated and used by Rush. { - "pnpmShrinkwrapHash": "79b1140f2f030775f15eb0e2a4a1fc175f8f93e4", + "pnpmShrinkwrapHash": "f89693a88037554bf0c35db4f2295ef771cd2a71", "preferredVersionsHash": "550b4cee0bef4e97db6c6aad726df5149d20e7d9", - "packageJsonInjectedDependenciesHash": "e126030136de647c674c725e365ee7321eb18f72" + "packageJsonInjectedDependenciesHash": "364e001eac655a92be31ddb4bbf0d8b291d1e9cc" } diff --git a/common/config/subspaces/default/pnpm-lock.yaml b/common/config/subspaces/default/pnpm-lock.yaml index 8331a3ef056..b19882175df 100644 --- a/common/config/subspaces/default/pnpm-lock.yaml +++ b/common/config/subspaces/default/pnpm-lock.yaml @@ -31,8 +31,8 @@ importers: specifier: workspace:* version: link:../../libraries/ts-command-line js-yaml: - specifier: ~3.13.1 - version: 3.13.1 + specifier: ~4.1.0 + version: 4.1.0 resolve: specifier: ~1.22.1 version: 1.22.8 @@ -41,8 +41,8 @@ importers: specifier: workspace:* version: link:../heft '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 '@types/resolve': specifier: 1.20.2 version: 1.20.2 @@ -193,6 +193,9 @@ importers: ../../../apps/lockfile-explorer: dependencies: + '@lifaon/path': + specifier: ~2.1.0 + version: 2.1.0 '@microsoft/rush-lib': specifier: workspace:* version: link:../../libraries/rush-lib @@ -218,14 +221,17 @@ importers: specifier: 4.20.0 version: 4.20.0 js-yaml: - specifier: ~3.13.1 - version: 3.13.1 + specifier: ~4.1.0 + version: 4.1.0 open: specifier: ~8.4.0 version: 8.4.2 semver: specifier: ~7.5.4 version: 7.5.4 + tslib: + specifier: ~2.8.1 + version: 2.8.1 update-notifier: specifier: ~5.1.0 version: 5.1.0 @@ -246,8 +252,8 @@ importers: specifier: 4.17.21 version: 4.17.21 '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 '@types/semver': specifier: 7.5.0 version: 7.5.0 @@ -263,9 +269,6 @@ importers: ../../../apps/lockfile-explorer-web: dependencies: - '@lifaon/path': - specifier: ~2.1.0 - version: 2.1.0 '@reduxjs/toolkit': specifier: ~1.8.6 version: 1.8.6(react-redux@8.0.7)(react@17.0.2) @@ -3630,8 +3633,8 @@ importers: specifier: ~8.2.7 version: 8.2.7 js-yaml: - specifier: ~3.13.1 - version: 3.13.1 + specifier: ~4.1.0 + version: 4.1.0 npm-check: specifier: ~6.0.1 version: 6.0.1 @@ -3697,8 +3700,8 @@ importers: specifier: 7.3.1 version: 7.3.1 '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 '@types/npm-package-arg': specifier: 6.1.0 version: 6.1.0 @@ -3977,15 +3980,15 @@ importers: specifier: workspace:* version: link:../../libraries/node-core-library js-yaml: - specifier: ~3.13.1 - version: 3.13.1 + specifier: ~4.1.0 + version: 4.1.0 devDependencies: '@rushstack/heft': specifier: workspace:* version: link:../../apps/heft '@types/js-yaml': - specifier: 3.12.1 - version: 3.12.1 + specifier: 4.0.9 + version: 4.0.9 eslint: specifier: ~9.25.1 version: 9.25.1(supports-color@8.1.1) @@ -8023,7 +8026,7 @@ packages: globals: 12.4.0 ignore: 4.0.6 import-fresh: 3.3.0 - js-yaml: 3.13.1 + js-yaml: 3.14.1 lodash: 4.17.21 minimatch: 3.1.2 strip-json-comments: 3.1.1 @@ -8041,7 +8044,7 @@ packages: globals: 13.24.0 ignore: 4.0.6 import-fresh: 3.3.0 - js-yaml: 3.13.1 + js-yaml: 3.14.1 minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: @@ -9699,7 +9702,7 @@ packages: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 - js-yaml: 3.13.1 + js-yaml: 3.14.1 resolve-from: 5.0.0 /@istanbuljs/schema@0.1.3: @@ -13876,8 +13879,8 @@ packages: resolution: {integrity: sha512-LFt+YA7Lv2IZROMwokZKiPNORAV5N3huMs3IKnzlE430HWhWYZ8b+78HiwJXJJP1V2IEjinyJURuRJfGoaFSIA==} dev: true - /@types/js-yaml@3.12.1: - resolution: {integrity: sha512-SGGAhXLHDx+PK4YLNcNGa6goPf9XRWQNAUUbffkwVGGXIxmDKWyGGL4inzq2sPmExu431Ekb9aEMn9BkPqEYFA==} + /@types/js-yaml@4.0.9: + resolution: {integrity: sha512-k4MGaQl5TGo/iipqb2UDG2UwjXziSWkh0uysQelTlJpX1qGlpUZYm8PnO4DxG1qBomtJUdYJ6qR6xdIah10JLg==} dev: true /@types/jsdom@20.0.1: @@ -19610,7 +19613,7 @@ packages: import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 3.13.1 + js-yaml: 3.14.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash: 4.17.21 @@ -19660,7 +19663,7 @@ packages: import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 3.13.1 + js-yaml: 3.14.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 @@ -19706,7 +19709,7 @@ packages: import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 - js-yaml: 3.13.1 + js-yaml: 3.14.1 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash: 4.17.21 @@ -23360,20 +23363,12 @@ packages: /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - /js-yaml@3.13.1: - resolution: {integrity: sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==} - hasBin: true - dependencies: - argparse: 1.0.10 - esprima: 4.0.1 - /js-yaml@3.14.1: resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} hasBin: true dependencies: argparse: 1.0.10 esprima: 4.0.1 - dev: false /js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} @@ -23802,7 +23797,7 @@ packages: engines: {node: '>=6'} dependencies: graceful-fs: 4.2.11 - js-yaml: 3.13.1 + js-yaml: 3.14.1 pify: 4.0.1 strip-bom: 3.0.0 dev: false @@ -29307,7 +29302,7 @@ packages: commander: 2.20.3 diff: 4.0.2 glob: 7.2.3 - js-yaml: 3.13.1 + js-yaml: 3.14.1 minimatch: 3.1.2 mkdirp: 0.5.6 resolve: 1.22.8 @@ -29330,7 +29325,7 @@ packages: commander: 2.20.3 diff: 4.0.2 glob: 7.2.3 - js-yaml: 3.13.1 + js-yaml: 3.14.1 minimatch: 3.1.2 mkdirp: 0.5.6 resolve: 1.22.8 @@ -29353,7 +29348,7 @@ packages: commander: 2.20.3 diff: 4.0.2 glob: 7.2.3 - js-yaml: 3.13.1 + js-yaml: 3.14.1 minimatch: 3.1.2 mkdirp: 0.5.6 resolve: 1.22.8 @@ -29376,7 +29371,7 @@ packages: commander: 2.20.3 diff: 4.0.2 glob: 7.2.3 - js-yaml: 3.13.1 + js-yaml: 3.14.1 minimatch: 3.1.2 mkdirp: 0.5.6 resolve: 1.22.8 diff --git a/common/config/subspaces/default/repo-state.json b/common/config/subspaces/default/repo-state.json index b484328badb..3c852d397ea 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": "0514179437811ed9b568114b19d8ecf0943f75dc", + "pnpmShrinkwrapHash": "43e8674ca74b9c3f20cf12f03de5ce2968017331", "preferredVersionsHash": "61cd419c533464b580f653eb5f5a7e27fe7055ca" } diff --git a/eslint/local-eslint-config/config/heft.json b/eslint/local-eslint-config/config/heft.json index d4ccbea3f42..14fee0004b8 100644 --- a/eslint/local-eslint-config/config/heft.json +++ b/eslint/local-eslint-config/config/heft.json @@ -3,7 +3,7 @@ "phasesByName": { "build": { - "cleanFiles": [{ "includeGlobs": ["mixins", "patch", "profile"] }], + "cleanFiles": [{ "includeGlobs": ["flat/**"] }], "tasksByName": { "copy-contents": { diff --git a/libraries/rush-lib/package.json b/libraries/rush-lib/package.json index 2fcae0639a1..1c5090d7350 100644 --- a/libraries/rush-lib/package.json +++ b/libraries/rush-lib/package.json @@ -54,7 +54,7 @@ "https-proxy-agent": "~5.0.0", "ignore": "~5.1.6", "inquirer": "~8.2.7", - "js-yaml": "~3.13.1", + "js-yaml": "~4.1.0", "npm-check": "~6.0.1", "npm-package-arg": "~6.1.0", "pnpm-sync-lib": "0.3.2", @@ -80,7 +80,7 @@ "@rushstack/webpack-preserve-dynamic-require-plugin": "workspace:*", "@types/cli-table": "0.3.0", "@types/inquirer": "7.3.1", - "@types/js-yaml": "3.12.1", + "@types/js-yaml": "4.0.9", "@types/npm-package-arg": "6.1.0", "@types/read-package-tree": "5.1.0", "@types/semver": "7.5.0", diff --git a/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts b/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts index ecd36bea9fd..9bfb3a888c1 100644 --- a/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts +++ b/libraries/rush-lib/src/logic/ProjectImpactGraphGenerator.ts @@ -141,7 +141,7 @@ export class ProjectImpactGraphGenerator { const projects: Record = Object.fromEntries(projectEntries); const content: IProjectImpactGraphFile = { globalExcludedGlobs, projects }; - await FileSystem.writeFileAsync(this._projectImpactGraphFilePath, yaml.safeDump(content)); + await FileSystem.writeFileAsync(this._projectImpactGraphFilePath, yaml.dump(content)); stopwatch.stop(); this._terminal.writeLine(); diff --git a/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts index ca5f40a1cf5..3846b1217ca 100644 --- a/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts +++ b/libraries/rush-lib/src/logic/installManager/WorkspaceInstallManager.ts @@ -697,7 +697,9 @@ export class WorkspaceInstallManager extends BaseInstallManager { ) { // Find the .modules.yaml file in the subspace temp/node_modules folder const modulesContent: string = await FileSystem.readFileAsync(modulesFilePath); - const yamlContent: IPnpmModules = yaml.load(modulesContent, { filename: modulesFilePath }); + const yamlContent: IPnpmModules = yaml.load(modulesContent, { + filename: modulesFilePath + }) as IPnpmModules; const { hoistedDependencies } = yamlContent; const subspaceProject: RushConfigurationProject = subspace.getProjects()[0]; const projectNodeModulesPath: string = `${subspaceProject.projectFolder}/node_modules`; diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts index f9fac5a2620..5c63d293cd9 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmShrinkwrapFile.ts @@ -399,7 +399,7 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { return cached; } - const shrinkwrapJson: IPnpmShrinkwrapYaml = yamlModule.safeLoad(shrinkwrapContent); + const shrinkwrapJson: IPnpmShrinkwrapYaml = yamlModule.load(shrinkwrapContent) as IPnpmShrinkwrapYaml; if ((shrinkwrapJson as LockfileFileV9).snapshots) { const lockfile: IPnpmShrinkwrapYaml | null = convertLockfileV9ToLockfileObject( shrinkwrapJson as LockfileFileV9 @@ -1317,6 +1317,6 @@ export class PnpmShrinkwrapFile extends BaseShrinkwrapFile { } } - return yamlModule.safeDump(shrinkwrapToSerialize, PNPM_SHRINKWRAP_YAML_FORMAT); + return yamlModule.dump(shrinkwrapToSerialize, PNPM_SHRINKWRAP_YAML_FORMAT); } } diff --git a/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts b/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts index 0615741be7c..989ad898f77 100644 --- a/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts +++ b/libraries/rush-lib/src/logic/pnpm/PnpmWorkspaceFile.ts @@ -66,6 +66,6 @@ export class PnpmWorkspaceFile extends BaseWorkspaceFile { const workspaceYaml: IPnpmWorkspaceYaml = { packages: Array.from(this._workspacePackages) }; - return yamlModule.safeDump(workspaceYaml, PNPM_SHRINKWRAP_YAML_FORMAT); + return yamlModule.dump(workspaceYaml, PNPM_SHRINKWRAP_YAML_FORMAT); } } diff --git a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts index 673bf4826ff..912bbc55b7a 100644 --- a/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts +++ b/libraries/rush-lib/src/logic/pnpm/test/PnpmShrinkwrapConverters.test.ts @@ -10,7 +10,7 @@ describe(convertLockfileV9ToLockfileObject.name, () => { const lockfileContent: string = FileSystem.readFile( `${__dirname}/yamlFiles/pnpm-lock-v9/pnpm-lock-v9.yaml` ); - const lockfileJson: LockfileFileV9 = yamlModule.safeLoad(lockfileContent); + const lockfileJson: LockfileFileV9 = yamlModule.load(lockfileContent) as LockfileFileV9; const lockfile = convertLockfileV9ToLockfileObject(lockfileJson); it('merge packages and snapshots', () => { @@ -39,7 +39,7 @@ describe(convertLockfileV9ToLockfileObject.name, () => { }); }); - it("no nullish values", () => { + it('no nullish values', () => { const importers = new Map(Object.entries(lockfile.importers || {})); const currentPackage = importers.get('.'); diff --git a/repo-scripts/doc-plugin-rush-stack/package.json b/repo-scripts/doc-plugin-rush-stack/package.json index 0ec18c28e86..aeaff892a36 100644 --- a/repo-scripts/doc-plugin-rush-stack/package.json +++ b/repo-scripts/doc-plugin-rush-stack/package.json @@ -15,11 +15,11 @@ "@microsoft/api-extractor-model": "workspace:*", "@microsoft/tsdoc": "~0.15.1", "@rushstack/node-core-library": "workspace:*", - "js-yaml": "~3.13.1" + "js-yaml": "~4.1.0" }, "devDependencies": { "@rushstack/heft": "workspace:*", - "@types/js-yaml": "3.12.1", + "@types/js-yaml": "4.0.9", "eslint": "~9.25.1", "local-node-rig": "workspace:*" } diff --git a/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.ts b/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.ts index 7de3c775426..d214295a313 100644 --- a/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.ts +++ b/repo-scripts/doc-plugin-rush-stack/src/RushStackFeature.ts @@ -55,7 +55,7 @@ export class RushStackFeature extends MarkdownDocumenterFeature { this._buildNavigation(navigationFile.api_nav, this.context.apiModel); const navFilePath: string = path.join(this.context.outputFolder, '..', 'api_nav.yaml'); - const navFileContent: string = yaml.safeDump(navigationFile, { lineWidth: 120 }); + const navFileContent: string = yaml.dump(navigationFile, { lineWidth: 120 }); FileSystem.writeFile(navFilePath, navFileContent, { ensureFolderExists: true }); } diff --git a/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js new file mode 100644 index 00000000000..61892fd848d --- /dev/null +++ b/rigs/decoupled-local-node-rig/profiles/default/includes/eslint/flat/mixins/packlets.js @@ -0,0 +1,6 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license. +// See LICENSE in the project root for license information. + +const packletsMixin = require('@rushstack/eslint-config/flat/mixins/packlets'); + +module.exports = { ...packletsMixin }; diff --git a/rigs/local-web-rig/profiles/app/includes/eslint/flat/mixins/packlets.js b/rigs/local-web-rig/profiles/app/includes/eslint/flat/mixins/packlets.js index 4291377cb4d..d33ecdd60ec 100644 --- a/rigs/local-web-rig/profiles/app/includes/eslint/flat/mixins/packlets.js +++ b/rigs/local-web-rig/profiles/app/includes/eslint/flat/mixins/packlets.js @@ -3,4 +3,4 @@ const packletsMixin = require('local-eslint-config/flat/mixins/packlets'); -module.exports = [...packletsMixin]; +module.exports = { ...packletsMixin };