diff --git a/scripts/monorepo/src/getDependencies.d.ts b/scripts/monorepo/src/getDependencies.d.ts index 710fff0fdd16cc..443defe0a1fb57 100644 --- a/scripts/monorepo/src/getDependencies.d.ts +++ b/scripts/monorepo/src/getDependencies.d.ts @@ -2,16 +2,19 @@ // - modules(projects) written in TS not having enabled `checkJS:true` wont infer types from .js files, thus the API will have `any` type. // This errors in strict ts check mode. -/// export declare function getDependencies(packageName: string): Promise<{ dependencies: Dependency[]; devDependencies: Dependency[]; all: Dependency[]; - projectGraph: import('lerna/utils').ProjectGraphWithPackages; + projectGraph: import('@nx/devkit').ProjectGraph; + getProjectPackageJsonInfo: ( + project: string, + projectGraph: import('@nx/devkit').ProjectGraph, + ) => import('./types').PackageJson & { absoluteRootPath: string }; }>; type Dependency = { name: string; isTopLevel: boolean; - dependencyType: import('lerna/utils').ProjectGraphWorkspacePackageDependency['dependencyCollection']; + dependencyType: 'dependencies' | 'devDependencies' | 'optionalDependencies' | null; }; diff --git a/scripts/monorepo/src/getDependencies.js b/scripts/monorepo/src/getDependencies.js index 75d44dab5b1f34..3bdaa9a4abc98e 100644 --- a/scripts/monorepo/src/getDependencies.js +++ b/scripts/monorepo/src/getDependencies.js @@ -1,17 +1,96 @@ -const lernaUtils = require('lerna/utils'); +const fs = require('node:fs'); + +const { createProjectGraphAsync, joinPathFragments, workspaceRoot } = require('@nx/devkit'); /** * @typedef {{ name: string, isTopLevel: boolean, - dependencyType: lernaUtils.ProjectGraphWorkspacePackageDependency['dependencyCollection'], + dependencyType: 'dependencies' | 'devDependencies' | 'optionalDependencies' | null, }} Dependency */ +/** @typedef {import('./types').PackageJson & {absoluteRootPath:string}} PackageJsonInfoData */ + +/** + * @type {Record} + */ +const packageJsonInfo = {}; + /** * * @param {string} project - * @param {lernaUtils.ProjectGraphWithPackages} projectGraph + * @param {import('@nx/devkit').ProjectGraph} projectGraph + */ +function getProjectPackageJsonInfo(project, projectGraph) { + const cachedInfo = packageJsonInfo[project]; + if (cachedInfo) { + return cachedInfo; + } + + const metadata = projectGraph.nodes[project]; + const absoluteRootPath = joinPathFragments(workspaceRoot, metadata.data.root); + const pkgJsonContent = fs.readFileSync(joinPathFragments(workspaceRoot, metadata.data.root, 'package.json'), 'utf-8'); + + /** @type {PackageJsonInfoData} */ + const pkgJson = JSON.parse(pkgJsonContent); + pkgJson.absoluteRootPath = absoluteRootPath; + + // store in cache + packageJsonInfo[project] = pkgJson; + + return pkgJson; +} + +/** + * Returns local dependencies of provided project. Local means dependency from within workspace + * @param {string} project + * @param {import('@nx/devkit').ProjectGraph} projectGraph + */ +function getLocalDeps(project, projectGraph) { + const deps = projectGraph.dependencies[project]; + const pkgJson = getProjectPackageJsonInfo(project, projectGraph); + + /** + * @type {Array<{target:string;dependencyType:ReturnType}>} + */ + const localDeps = []; + for (const dep of deps) { + if (!dep.target.startsWith('npm:')) { + const dependencyType = getDepType(dep.target, pkgJson); + localDeps.push({ target: dep.target, dependencyType }); + } + } + + if (localDeps.length > 0) { + return localDeps; + } + + return null; +} +/** + * + * @param {string} pkgName + * @param {import('./types').PackageJson} json + * @returns + */ +function getDepType(pkgName, json) { + if (json.dependencies?.[pkgName]) { + return 'dependencies'; + } + if (json.devDependencies?.[pkgName]) { + return 'devDependencies'; + } + if (json.optionalDependencies?.[pkgName]) { + return 'optionalDependencies'; + } + return null; +} + +/** + * + * @param {string} project + * @param {import('@nx/devkit').ProjectGraph} projectGraph * @param {*} options * @param {Dependency[]} _acc * @param {boolean} _areTopLevelDeps @@ -27,28 +106,26 @@ function collectDependencies( _acc = [], _areTopLevelDeps = true, ) { - if (!projectGraph.localPackageDependencies[project]) { + const localDeps = getLocalDeps(project, projectGraph); + + if (!localDeps) { return _acc; } - projectGraph.localPackageDependencies[project].forEach(dependency => { + localDeps.forEach(dependency => { const isDependencyAlreadyCollected = _acc.some(dep => dep.name === dependency.target); if (isDependencyAlreadyCollected) { return; } - if ( - options.dependenciesOnly && - dependency.dependencyCollection && - dependency.dependencyCollection !== 'dependencies' - ) { + if (options.dependenciesOnly && dependency.dependencyType && dependency.dependencyType !== 'dependencies') { return; } _acc.push({ name: dependency.target, - dependencyType: dependency.dependencyCollection, + dependencyType: dependency.dependencyType, isTopLevel: _areTopLevelDeps, }); @@ -65,7 +142,7 @@ function collectDependencies( * @param {string} packageName - including `@fluentui/` prefix */ async function getDependencies(packageName) { - const { projectGraph } = await lernaUtils.detectProjects(); + const projectGraph = await createProjectGraphAsync(); const allDepsGraph = collectDependencies(packageName, projectGraph, { shallow: false, dependenciesOnly: false }); const depsGraph = collectDependencies(packageName, projectGraph, { shallow: false, dependenciesOnly: true }); @@ -76,6 +153,7 @@ async function getDependencies(packageName) { devDependencies: devDepsGraph, all: allDepsGraph, projectGraph, + getProjectPackageJsonInfo, }; } diff --git a/scripts/monorepo/src/getDependencies.spec.js b/scripts/monorepo/src/getDependencies.spec.js index 4fc69c2f41ff26..5f6d84263c5828 100644 --- a/scripts/monorepo/src/getDependencies.spec.js +++ b/scripts/monorepo/src/getDependencies.spec.js @@ -96,13 +96,13 @@ describe(`#getDependencies`, () => { `); }); - it(`should provide similar api like 'new Project(root).getPackages()'`, async () => { - const { projectGraph } = await getDependencies(packageName); - const packageInfo = projectGraph.nodes[packageName].package; + it(`should provide access to package.json`, async () => { + const { projectGraph, getProjectPackageJsonInfo } = await getDependencies(packageName); + const packageInfo = getProjectPackageJsonInfo(packageName, projectGraph); - expect(packageInfo?.location).toEqual(expect.stringContaining('packages/react-components/react-text')); + expect(packageInfo.absoluteRootPath).toEqual(expect.stringContaining('packages/react-components/react-text')); expect(packageInfo?.dependencies).toEqual(expect.any(Object)); - expect(packageInfo?.get('main')).toEqual('lib-commonjs/index.js'); - expect(packageInfo?.get('module')).toEqual('lib/index.js'); + expect(packageInfo?.main).toEqual('lib-commonjs/index.js'); + expect(packageInfo?.module).toEqual('lib/index.js'); }); }); diff --git a/scripts/projects-test/src/packPackages.ts b/scripts/projects-test/src/packPackages.ts index 30176ff5ccb58e..40e94665e0cec7 100644 --- a/scripts/projects-test/src/packPackages.ts +++ b/scripts/projects-test/src/packPackages.ts @@ -32,7 +32,7 @@ export async function packProjectPackages(logger: Function, project: string): Pr packedPackages = {}; - const { dependencies: projectDependencies, projectGraph } = await getDependencies(project); + const { dependencies: projectDependencies, projectGraph, getProjectPackageJsonInfo } = await getDependencies(project); // add provided package to be packaged projectDependencies.unshift({ name: project, @@ -51,13 +51,13 @@ export async function packProjectPackages(logger: Function, project: string): Pr await Promise.all( projectDependencies.map(async projectConfig => { const packageName = projectConfig.name; - const packageInfo = projectGraph.nodes[packageName].package; + const packageInfo = getProjectPackageJsonInfo(packageName, projectGraph); if (!packageInfo) { throw new Error(`Package ${packageName} doesn't exist`); } - const packagePath = packageInfo.location; - const packageMain = packageInfo.get('main') as string | undefined; + const packagePath = packageInfo.absoluteRootPath; + const packageMain = packageInfo.main; const entryPointPath = packageMain ? path.join(packagePath, packageMain) : ''; if (!fs.existsSync(entryPointPath)) { throw new Error( diff --git a/typings/lerna/index.d.ts b/typings/lerna/index.d.ts deleted file mode 100644 index 791c6ee22eb007..00000000000000 --- a/typings/lerna/index.d.ts +++ /dev/null @@ -1,75 +0,0 @@ -// Type definitions for lerna 7.0.0 - -// NOTE: types taken from @see https://github.com/lerna/lerna/blob/main/libs/core/src/lib/project-graph-with-packages.ts -// ISSUE: https://github.com/lerna/lerna/issues/3851 - -declare module 'lerna/utils' { - import type { ProjectFileMap, ProjectGraph, ProjectGraphDependency, ProjectGraphProjectNode } from '@nx/devkit'; - - interface RawManifest { - name: string; - version: string; - description?: string; - private?: boolean; - bin?: Record | string; - scripts?: Record; - dependencies?: Record; - devDependencies?: Record; - optionalDependencies?: Record; - peerDependencies?: Record; - publishConfig?: Record<'directory' | 'registry' | 'tag', string>; - workspaces?: string[]; - nx?: Record; - gitHead?: string; - lerna?: RawManifestLernaConfig; - } - - interface RawManifestLernaConfig { - command?: { - publish?: { - directory?: string; - assets?: AssetDefinition[]; - }; - }; - } - type AssetDefinition = string | { from: string; to: string }; - - interface Package extends Omit { - /** - * Map-like retrieval of arbitrary values from package.json - */ - get(key: string): unknown; - binLocation: string; - - resolved: Record; - /** - * path to package.json - */ - manifestLocation: string; - location: string; - lernaConfig: RawManifest['lerna'] | undefined; - } - - type ExtendedNpaResult = { - workspaceSpec?: string; - workspaceAlias?: string; - }; - - interface ProjectGraphProjectNodeWithPackage extends ProjectGraphProjectNode { - package: Package | null; - } - interface ProjectGraphWorkspacePackageDependency extends ProjectGraphDependency { - targetVersionMatchesDependencyRequirement: boolean; - targetResolvedNpaResult: ExtendedNpaResult; - dependencyCollection: 'dependencies' | 'devDependencies' | 'optionalDependencies'; // lerna doesn't manage peer dependencies - } - export interface ProjectGraphWithPackages extends ProjectGraph { - nodes: Record; - localPackageDependencies: Record; - } - - export function detectProjects(): Promise<{ - projectGraph: ProjectGraphWithPackages; - projectFileMap: ProjectFileMap; - }>; -} diff --git a/typings/lerna/tsconfig.json b/typings/lerna/tsconfig.json deleted file mode 100644 index c6f8b0a935c4c2..00000000000000 --- a/typings/lerna/tsconfig.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": "../tsconfig.json", - "compilerOptions": {}, - "include": ["*.d.ts"] -} diff --git a/typings/tsconfig.json b/typings/tsconfig.json index 66aabec9b543cb..d2324f1f1c570d 100644 --- a/typings/tsconfig.json +++ b/typings/tsconfig.json @@ -30,9 +30,6 @@ }, { "path": "./find-free-port/tsconfig.json" - }, - { - "path": "./lerna/tsconfig.json" } ] }