fix(core): improve resolution of packages in package manager workspaces when constructing the project graph (#29795)
Main fixes:
- Identify dependencies from packages that only expose named exports (no
`.` export)
- Identify dependencies from exports containing wildcards (e.g.
`"./utils/*": "./src/utils/*.js`)
- Disallow identifying dependencies from restricted exports (e.g.
`"./foo": null`)
- Handle conditional exports (e.g. `"exports": { "import":
"./dist/index.js", "default": "./dist/index.js" }`
- Handle invalid `"exports": {}` (by not falling back to `main`)
- Handle projects included or not in package manager workspaces
## Current Behavior
## Expected Behavior
## Related Issue(s)
Fixes #29486
This commit is contained in:
parent
d655e667a1
commit
4235cf35e3
@ -8,7 +8,7 @@ A node describing a project in a workspace
|
|||||||
|
|
||||||
- [data](../../devkit/documents/ProjectGraphProjectNode#data): ProjectConfiguration & Object
|
- [data](../../devkit/documents/ProjectGraphProjectNode#data): ProjectConfiguration & Object
|
||||||
- [name](../../devkit/documents/ProjectGraphProjectNode#name): string
|
- [name](../../devkit/documents/ProjectGraphProjectNode#name): string
|
||||||
- [type](../../devkit/documents/ProjectGraphProjectNode#type): "lib" | "app" | "e2e"
|
- [type](../../devkit/documents/ProjectGraphProjectNode#type): "app" | "e2e" | "lib"
|
||||||
|
|
||||||
## Properties
|
## Properties
|
||||||
|
|
||||||
@ -28,4 +28,4 @@ Additional metadata about a project
|
|||||||
|
|
||||||
### type
|
### type
|
||||||
|
|
||||||
• **type**: `"lib"` \| `"app"` \| `"e2e"`
|
• **type**: `"app"` \| `"e2e"` \| `"lib"`
|
||||||
|
|||||||
343
e2e/nx/src/graph-ts-solution.test.ts
Normal file
343
e2e/nx/src/graph-ts-solution.test.ts
Normal file
@ -0,0 +1,343 @@
|
|||||||
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
|
createFile,
|
||||||
|
getPackageManagerCommand,
|
||||||
|
getSelectedPackageManager,
|
||||||
|
newProject,
|
||||||
|
readJson,
|
||||||
|
runCLI,
|
||||||
|
runCommand,
|
||||||
|
updateFile,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/e2e/utils';
|
||||||
|
import { basename } from 'node:path';
|
||||||
|
|
||||||
|
describe('Graph - TS solution setup', () => {
|
||||||
|
beforeAll(() => {
|
||||||
|
newProject({
|
||||||
|
packages: ['@nx/js'],
|
||||||
|
preset: 'ts',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
cleanupProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should detect dependencies from local packages included in the package manager workspaces', () => {
|
||||||
|
const pm = getSelectedPackageManager();
|
||||||
|
const pmc = getPackageManagerCommand({ packageManager: pm });
|
||||||
|
|
||||||
|
createPackage('pkg-parent', { sourceFilePaths: ['index.ts'] });
|
||||||
|
|
||||||
|
// invalid definition with no entry fields in package.json
|
||||||
|
createPackage('pkg1');
|
||||||
|
// only `main`
|
||||||
|
createPackage('pkg2', {
|
||||||
|
packageJsonEntryFields: { main: './dist/src/index.js' },
|
||||||
|
});
|
||||||
|
// invalid empty exports, no code is accessible
|
||||||
|
createPackage('pkg3', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
main: './dist/src/index.js',
|
||||||
|
types: './dist/src/index.d.ts',
|
||||||
|
exports: {},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// '.' entry point
|
||||||
|
createPackage('pkg4', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
types: './dist/src/index.d.ts',
|
||||||
|
default: './dist/src/index.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// conditional exports
|
||||||
|
createPackage('pkg5', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
types: './dist/src/index.d.ts',
|
||||||
|
default: './dist/src/index.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// exports set to a string
|
||||||
|
createPackage('pkg6', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: './dist/src/index.js',
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// '.' entry point set to source (non buildable library)
|
||||||
|
createPackage('pkg7', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'.': './src/index.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// matches a path alias that resolves correctly
|
||||||
|
createPackage('pkg8', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
types: './dist/src/index.d.ts',
|
||||||
|
default: './dist/src/index.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// matches a path alias that doesn't resolve correctly, should still be
|
||||||
|
// picked up by the package manager workspaces fallback resolution
|
||||||
|
createPackage('pkg9', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
types: './src/index.ts',
|
||||||
|
default: './src/index.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// only named exports, no '.' entry point
|
||||||
|
createPackage('pkg10', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'./feature1': {
|
||||||
|
types: './dist/src/index.d.ts',
|
||||||
|
default: './dist/src/index.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// wildcard exports
|
||||||
|
createPackage('pkg11', {
|
||||||
|
sourceFilePaths: ['src/utils/util1.ts'],
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'./utils/*': {
|
||||||
|
types: './dist/src/utils/*.d.ts',
|
||||||
|
default: './dist/src/utils/*.js',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// restricted exports, should not be picked up as a dependency
|
||||||
|
createPackage('pkg12', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: { './feature1': null },
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// valid package that will be imported as @proj/pkg14 due to a TS path alias
|
||||||
|
createPackage('pkg13', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
types: './src/index.ts',
|
||||||
|
default: './src/index.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// valid package that we'll be foreshadowed by a TS path alias pointing to
|
||||||
|
// pkg13, so should not be picked up as a dependency
|
||||||
|
createPackage('pkg14', {
|
||||||
|
packageJsonEntryFields: {
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
types: './src/index.ts',
|
||||||
|
default: './src/index.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// project outside of the package manager workspaces
|
||||||
|
createPackage('lib1', { root: 'libs/lib1' });
|
||||||
|
|
||||||
|
if (pm === 'pnpm') {
|
||||||
|
// for pnpm we need to add the local packages as dependencies to each consumer package.json
|
||||||
|
// we keep out the ones we want to validate won't be picked up as dependencies, otherwise
|
||||||
|
// they would be included because the package.json depends on them
|
||||||
|
updateJson('packages/pkg-parent/package.json', (json) => {
|
||||||
|
json.dependencies ??= {};
|
||||||
|
json.dependencies['@proj/pkg2'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg4'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg5'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg6'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg7'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg8'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg9'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg10'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg11'] = 'workspace:*';
|
||||||
|
json.dependencies['@proj/pkg13'] = 'workspace:*';
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
runCommand(pmc.install);
|
||||||
|
|
||||||
|
updateJson('tsconfig.base.json', (json) => {
|
||||||
|
json.compilerOptions.baseUrl = '.';
|
||||||
|
json.compilerOptions.paths = {
|
||||||
|
'@proj/pkg8': ['packages/pkg8/src/index.ts'],
|
||||||
|
'@proj/pkg9': ['dist/packages/pkg9'],
|
||||||
|
'@proj/pkg14': ['packages/pkg13/src/index.ts'],
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
// add TS project references to all packages, including the invalid ones
|
||||||
|
// so they are all built ahead of pkg-parent and we can assert the test
|
||||||
|
// correctly sets them up as invalid imports
|
||||||
|
updateJson('packages/pkg-parent/tsconfig.json', (json) => {
|
||||||
|
json.references = [
|
||||||
|
{ path: '../pkg1' },
|
||||||
|
{ path: '../pkg2' },
|
||||||
|
{ path: '../pkg3' },
|
||||||
|
{ path: '../pkg4' },
|
||||||
|
{ path: '../pkg5' },
|
||||||
|
{ path: '../pkg6' },
|
||||||
|
{ path: '../pkg7' },
|
||||||
|
{ path: '../pkg8' },
|
||||||
|
{ path: '../pkg9' },
|
||||||
|
{ path: '../pkg10' },
|
||||||
|
{ path: '../pkg11' },
|
||||||
|
{ path: '../pkg12' },
|
||||||
|
{ path: '../pkg13' },
|
||||||
|
{ path: '../pkg14' },
|
||||||
|
];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
updateFile(
|
||||||
|
'packages/pkg-parent/index.ts',
|
||||||
|
() => `
|
||||||
|
import { pkg1 } from '@proj/pkg1';
|
||||||
|
import { pkg2 } from '@proj/pkg2';
|
||||||
|
import { pkg3 } from '@proj/pkg3';
|
||||||
|
import { pkg4 } from '@proj/pkg4';
|
||||||
|
import { pkg5 } from '@proj/pkg5';
|
||||||
|
import { pkg6 } from '@proj/pkg6';
|
||||||
|
import { pkg7 } from '@proj/pkg7';
|
||||||
|
import { pkg8 } from '@proj/pkg8';
|
||||||
|
import { pkg9 } from '@proj/pkg9';
|
||||||
|
import { pkg10 } from '@proj/pkg10/feature1';
|
||||||
|
import { util1 } from '@proj/pkg11/utils/util1';
|
||||||
|
import { pkg12 } from '@proj/pkg12/feature1';
|
||||||
|
import { pkg13 } from '@proj/pkg14';
|
||||||
|
// this is an invalid import that doesn't match any TS path alias and
|
||||||
|
// it's not included in the package manager workspaces, it should not
|
||||||
|
// be picked up as a dependency
|
||||||
|
import { lib1 } from '@proj/lib1';
|
||||||
|
|
||||||
|
// use the correct imports, leave out the invalid ones so it's easier to remove them later
|
||||||
|
export const pkgParent = pkg2 + pkg4 + pkg5 + pkg6 + pkg7 + pkg8 + pkg9 + pkg10 + util1 + pkg13;
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCLI(`graph --file graph.json`);
|
||||||
|
|
||||||
|
const { graph } = readJson('graph.json');
|
||||||
|
// pkg1, pkg3, pkg12, pkg14, and lib1 are not detected as dependencies
|
||||||
|
expect(
|
||||||
|
graph.dependencies['@proj/pkg-parent'].map((d) => d.target)
|
||||||
|
).toStrictEqual([
|
||||||
|
'@proj/pkg2',
|
||||||
|
'@proj/pkg4',
|
||||||
|
'@proj/pkg5',
|
||||||
|
'@proj/pkg6',
|
||||||
|
'@proj/pkg7',
|
||||||
|
'@proj/pkg8',
|
||||||
|
'@proj/pkg9',
|
||||||
|
'@proj/pkg10',
|
||||||
|
'@proj/pkg11',
|
||||||
|
'@proj/pkg13',
|
||||||
|
]);
|
||||||
|
|
||||||
|
// assert build fails due to the invalid imports
|
||||||
|
const output = runCommand(`${pmc.exec} tsc -b packages/pkg-parent`);
|
||||||
|
expect(output).toContain(
|
||||||
|
`error TS2307: Cannot find module '@proj/pkg1' or its corresponding type declarations.`
|
||||||
|
);
|
||||||
|
expect(output).toContain(
|
||||||
|
`error TS2307: Cannot find module '@proj/pkg3' or its corresponding type declarations.`
|
||||||
|
);
|
||||||
|
expect(output).toContain(
|
||||||
|
`error TS2307: Cannot find module '@proj/pkg12/feature1' or its corresponding type declarations.`
|
||||||
|
);
|
||||||
|
expect(output).toContain(
|
||||||
|
`error TS2307: Cannot find module '@proj/lib1' or its corresponding type declarations.`
|
||||||
|
);
|
||||||
|
|
||||||
|
// remove the invalid imports
|
||||||
|
updateFile('packages/pkg-parent/index.ts', (content) =>
|
||||||
|
content
|
||||||
|
.replace(`import { pkg1 } from '@proj/pkg1';`, '')
|
||||||
|
.replace(`import { pkg3 } from '@proj/pkg3';`, '')
|
||||||
|
.replace(`import { pkg12 } from '@proj/pkg12/feature1';`, '')
|
||||||
|
.replace(`import { lib1 } from '@proj/lib1';`, '')
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert build succeeds, tsc outputs nothing when successful
|
||||||
|
expect(runCommand(`${pmc.exec} tsc -b packages/pkg-parent`)).toBe('');
|
||||||
|
checkFilesExist(
|
||||||
|
'packages/pkg-parent/dist/index.js',
|
||||||
|
'packages/pkg-parent/dist/index.d.ts'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
function createPackage(
|
||||||
|
name: string,
|
||||||
|
options?: {
|
||||||
|
root?: string;
|
||||||
|
sourceFilePaths?: string[];
|
||||||
|
packageJsonEntryFields?: {
|
||||||
|
main?: string;
|
||||||
|
types?: string;
|
||||||
|
exports?: string | Record<string, any>;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
): void {
|
||||||
|
const root = options?.root ?? `packages/${name}`;
|
||||||
|
|
||||||
|
createFile(
|
||||||
|
`${root}/package.json`,
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
name: `@proj/${name}`,
|
||||||
|
version: '1.0.0',
|
||||||
|
...options?.packageJsonEntryFields,
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
createFile(
|
||||||
|
`${root}/tsconfig.json`,
|
||||||
|
JSON.stringify(
|
||||||
|
{
|
||||||
|
extends: '../../tsconfig.base.json',
|
||||||
|
compilerOptions: {
|
||||||
|
outDir: './dist',
|
||||||
|
emitDeclarationOnly: false,
|
||||||
|
},
|
||||||
|
include: ['**/*.ts'],
|
||||||
|
},
|
||||||
|
null,
|
||||||
|
2
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
const sourceFilePaths = options?.sourceFilePaths ?? ['src/index.ts'];
|
||||||
|
for (const sourceFilePath of sourceFilePaths) {
|
||||||
|
const fileName = basename(sourceFilePath, '.ts');
|
||||||
|
createFile(
|
||||||
|
`${root}/${sourceFilePath}`,
|
||||||
|
`export const ${
|
||||||
|
fileName !== 'index' ? fileName : name
|
||||||
|
} = '${name} - ${fileName}';`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
@ -5,6 +5,7 @@ import {
|
|||||||
ensureCypressInstallation,
|
ensureCypressInstallation,
|
||||||
ensurePlaywrightBrowsersInstallation,
|
ensurePlaywrightBrowsersInstallation,
|
||||||
getNpmMajorVersion,
|
getNpmMajorVersion,
|
||||||
|
getPnpmVersion,
|
||||||
getPublishedVersion,
|
getPublishedVersion,
|
||||||
getStrippedEnvironmentVariables,
|
getStrippedEnvironmentVariables,
|
||||||
getYarnMajorVersion,
|
getYarnMajorVersion,
|
||||||
@ -17,6 +18,7 @@ import * as isCI from 'is-ci';
|
|||||||
import { fileExists, readJson, updateJson } from './file-utils';
|
import { fileExists, readJson, updateJson } from './file-utils';
|
||||||
import { logError, stripConsoleColors } from './log-utils';
|
import { logError, stripConsoleColors } from './log-utils';
|
||||||
import { existsSync } from 'fs-extra';
|
import { existsSync } from 'fs-extra';
|
||||||
|
import { gte } from 'semver';
|
||||||
|
|
||||||
export interface RunCmdOpts {
|
export interface RunCmdOpts {
|
||||||
silenceError?: boolean;
|
silenceError?: boolean;
|
||||||
@ -111,9 +113,11 @@ export function getPackageManagerCommand({
|
|||||||
addDev: string;
|
addDev: string;
|
||||||
list: string;
|
list: string;
|
||||||
runLerna: string;
|
runLerna: string;
|
||||||
|
exec: string;
|
||||||
} {
|
} {
|
||||||
const npmMajorVersion = getNpmMajorVersion();
|
const npmMajorVersion = getNpmMajorVersion();
|
||||||
const yarnMajorVersion = getYarnMajorVersion(path);
|
const yarnMajorVersion = getYarnMajorVersion(path);
|
||||||
|
const pnpmVersion = getPnpmVersion();
|
||||||
const publishedVersion = getPublishedVersion();
|
const publishedVersion = getPublishedVersion();
|
||||||
const isYarnWorkspace = fileExists(join(path, 'package.json'))
|
const isYarnWorkspace = fileExists(join(path, 'package.json'))
|
||||||
? readJson('package.json').workspaces
|
? readJson('package.json').workspaces
|
||||||
@ -135,6 +139,7 @@ export function getPackageManagerCommand({
|
|||||||
addDev: `npm install --legacy-peer-deps -D`,
|
addDev: `npm install --legacy-peer-deps -D`,
|
||||||
list: 'npm ls --depth 10',
|
list: 'npm ls --depth 10',
|
||||||
runLerna: `npx lerna`,
|
runLerna: `npx lerna`,
|
||||||
|
exec: 'npx',
|
||||||
},
|
},
|
||||||
yarn: {
|
yarn: {
|
||||||
createWorkspace: `npx ${
|
createWorkspace: `npx ${
|
||||||
@ -156,6 +161,7 @@ export function getPackageManagerCommand({
|
|||||||
yarnMajorVersion && +yarnMajorVersion >= 2
|
yarnMajorVersion && +yarnMajorVersion >= 2
|
||||||
? 'yarn lerna'
|
? 'yarn lerna'
|
||||||
: `yarn --silent lerna`,
|
: `yarn --silent lerna`,
|
||||||
|
exec: 'yarn',
|
||||||
},
|
},
|
||||||
// Pnpm 3.5+ adds nx to
|
// Pnpm 3.5+ adds nx to
|
||||||
pnpm: {
|
pnpm: {
|
||||||
@ -170,6 +176,7 @@ export function getPackageManagerCommand({
|
|||||||
addDev: isPnpmWorkspace ? 'pnpm add -Dw' : 'pnpm add -D',
|
addDev: isPnpmWorkspace ? 'pnpm add -Dw' : 'pnpm add -D',
|
||||||
list: 'pnpm ls --depth 10',
|
list: 'pnpm ls --depth 10',
|
||||||
runLerna: `pnpm exec lerna`,
|
runLerna: `pnpm exec lerna`,
|
||||||
|
exec: pnpmVersion && gte(pnpmVersion, '6.13.0') ? 'pnpm exec' : 'pnpx',
|
||||||
},
|
},
|
||||||
bun: {
|
bun: {
|
||||||
createWorkspace: `bunx create-nx-workspace@${publishedVersion}`,
|
createWorkspace: `bunx create-nx-workspace@${publishedVersion}`,
|
||||||
@ -183,6 +190,7 @@ export function getPackageManagerCommand({
|
|||||||
addDev: 'bun install -D',
|
addDev: 'bun install -D',
|
||||||
list: 'bun pm ls',
|
list: 'bun pm ls',
|
||||||
runLerna: `bunx lerna`,
|
runLerna: `bunx lerna`,
|
||||||
|
exec: 'bun',
|
||||||
},
|
},
|
||||||
}[packageManager.trim() as PackageManager];
|
}[packageManager.trim() as PackageManager];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -99,6 +99,17 @@ export function getYarnMajorVersion(path: string): string | undefined {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getPnpmVersion(): string | undefined {
|
||||||
|
try {
|
||||||
|
const pnpmVersion = execSync(`pnpm -v`, {
|
||||||
|
encoding: 'utf-8',
|
||||||
|
}).trim();
|
||||||
|
return pnpmVersion;
|
||||||
|
} catch {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function getLatestLernaVersion(): string {
|
export function getLatestLernaVersion(): string {
|
||||||
const lernaVersion = execSync(`npm view lerna version`, {
|
const lernaVersion = execSync(`npm view lerna version`, {
|
||||||
encoding: 'utf-8',
|
encoding: 'utf-8',
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
import { createNodesFromFiles, NxPluginV2 } from '../src/project-graph/plugins';
|
import { createNodesFromFiles, NxPluginV2 } from '../src/project-graph/plugins';
|
||||||
import { workspaceRoot } from '../src/utils/workspace-root';
|
import { workspaceRoot } from '../src/utils/workspace-root';
|
||||||
import { createNodeFromPackageJson } from '../src/plugins/package-json';
|
import {
|
||||||
|
buildPackageJsonWorkspacesMatcher,
|
||||||
|
createNodeFromPackageJson,
|
||||||
|
} from '../src/plugins/package-json';
|
||||||
import { workspaceDataDirectory } from '../src/utils/cache-directory';
|
import { workspaceDataDirectory } from '../src/utils/cache-directory';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { ProjectConfiguration } from '../src/config/workspace-json-project-json';
|
import { ProjectConfiguration } from '../src/config/workspace-json-project-json';
|
||||||
@ -31,8 +34,19 @@ const plugin: NxPluginV2 = {
|
|||||||
(configFiles, options, context) => {
|
(configFiles, options, context) => {
|
||||||
const cache = readPackageJsonConfigurationCache();
|
const cache = readPackageJsonConfigurationCache();
|
||||||
|
|
||||||
|
const isInPackageJsonWorkspaces = buildPackageJsonWorkspacesMatcher(
|
||||||
|
context.workspaceRoot,
|
||||||
|
(f) => readJsonFile(join(context.workspaceRoot, f))
|
||||||
|
);
|
||||||
|
|
||||||
const result = createNodesFromFiles(
|
const result = createNodesFromFiles(
|
||||||
(f) => createNodeFromPackageJson(f, workspaceRoot, cache),
|
(packageJsonPath) =>
|
||||||
|
createNodeFromPackageJson(
|
||||||
|
packageJsonPath,
|
||||||
|
workspaceRoot,
|
||||||
|
cache,
|
||||||
|
isInPackageJsonWorkspaces(packageJsonPath)
|
||||||
|
),
|
||||||
configFiles,
|
configFiles,
|
||||||
options,
|
options,
|
||||||
context
|
context
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { existsSync } from 'fs';
|
import { existsSync } from 'fs';
|
||||||
import { extname, join } from 'path';
|
import { extname, join } from 'path';
|
||||||
import { resolve as resolveExports } from 'resolve.exports';
|
import { resolve as resolveExports } from 'resolve.exports';
|
||||||
import { getPackageEntryPointsToProjectMap } from '../plugins/js/utils/packages';
|
import { getWorkspacePackagesMetadata } from '../plugins/js/utils/packages';
|
||||||
import { registerPluginTSTranspiler } from '../project-graph/plugins';
|
import { registerPluginTSTranspiler } from '../project-graph/plugins';
|
||||||
import { normalizePath } from '../utils/path';
|
import { normalizePath } from '../utils/path';
|
||||||
import type { ProjectConfiguration } from './workspace-json-project-json';
|
import type { ProjectConfiguration } from './workspace-json-project-json';
|
||||||
@ -119,16 +119,16 @@ export function resolveSchema(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let packageEntryPointsToProjectMap: Record<string, ProjectConfiguration>;
|
let packageToProjectMap: Record<string, ProjectConfiguration>;
|
||||||
function tryResolveFromSource(
|
function tryResolveFromSource(
|
||||||
path: string,
|
path: string,
|
||||||
directory: string,
|
directory: string,
|
||||||
packageName: string,
|
packageName: string,
|
||||||
projects: Record<string, ProjectConfiguration>
|
projects: Record<string, ProjectConfiguration>
|
||||||
): string | null {
|
): string | null {
|
||||||
packageEntryPointsToProjectMap ??=
|
packageToProjectMap ??=
|
||||||
getPackageEntryPointsToProjectMap(projects);
|
getWorkspacePackagesMetadata(projects).packageToProjectMap;
|
||||||
const localProject = packageEntryPointsToProjectMap[packageName];
|
const localProject = packageToProjectMap[packageName];
|
||||||
if (!localProject) {
|
if (!localProject) {
|
||||||
// it doesn't match any of the package names from the local projects
|
// it doesn't match any of the package names from the local projects
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@ -58,6 +58,7 @@ describe('Workspaces', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "my-package description",
|
"description": "my-package description",
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
"packageName": "my-package",
|
"packageName": "my-package",
|
||||||
},
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
|
|||||||
@ -140,6 +140,8 @@ export interface ProjectMetadata {
|
|||||||
js?: {
|
js?: {
|
||||||
packageName: string;
|
packageName: string;
|
||||||
packageExports?: PackageJson['exports'];
|
packageExports?: PackageJson['exports'];
|
||||||
|
packageMain?: string;
|
||||||
|
isInPackageManagerWorkspaces?: boolean;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -74,7 +74,11 @@ describe('explicit package json dependencies', () => {
|
|||||||
data: {
|
data: {
|
||||||
root: 'libs/proj',
|
root: 'libs/proj',
|
||||||
metadata: {
|
metadata: {
|
||||||
js: { packageName: 'proj', packageExports: undefined },
|
js: {
|
||||||
|
packageName: 'proj',
|
||||||
|
packageExports: undefined,
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -84,7 +88,11 @@ describe('explicit package json dependencies', () => {
|
|||||||
data: {
|
data: {
|
||||||
root: 'libs/proj2',
|
root: 'libs/proj2',
|
||||||
metadata: {
|
metadata: {
|
||||||
js: { packageName: 'proj2', packageExports: undefined },
|
js: {
|
||||||
|
packageName: 'proj2',
|
||||||
|
packageExports: undefined,
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -94,7 +102,11 @@ describe('explicit package json dependencies', () => {
|
|||||||
data: {
|
data: {
|
||||||
root: 'libs/proj4',
|
root: 'libs/proj4',
|
||||||
metadata: {
|
metadata: {
|
||||||
js: { packageName: 'proj3', packageExports: undefined },
|
js: {
|
||||||
|
packageName: 'proj3',
|
||||||
|
packageExports: undefined,
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@ -221,6 +221,8 @@ describe('TargetProjectLocator', () => {
|
|||||||
js: {
|
js: {
|
||||||
packageName: '@proj/child-pm-workspaces',
|
packageName: '@proj/child-pm-workspaces',
|
||||||
packageExports: undefined,
|
packageExports: undefined,
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
packageMain: 'index.ts',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@ -1011,6 +1013,197 @@ describe('TargetProjectLocator', () => {
|
|||||||
expect(result).toEqual('npm:foo@0.0.1');
|
expect(result).toEqual('npm:foo@0.0.1');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('findDependencyInWorkspaceProjects', () => {
|
||||||
|
it.each`
|
||||||
|
exports
|
||||||
|
${undefined}
|
||||||
|
${'dist/index.js'}
|
||||||
|
${{}}
|
||||||
|
${{ '.': 'dist/index.js' }}
|
||||||
|
${{ './subpath': './dist/subpath.js' }}
|
||||||
|
${{ import: './dist/index.js', default: './dist/index.js' }}
|
||||||
|
`(
|
||||||
|
'should find "@org/pkg1" package as "pkg1" project when exports="$exports"',
|
||||||
|
({ exports }) => {
|
||||||
|
let projects: Record<string, ProjectGraphProjectNode> = {
|
||||||
|
pkg1: {
|
||||||
|
name: 'pkg1',
|
||||||
|
type: 'lib' as const,
|
||||||
|
data: {
|
||||||
|
root: 'pkg1',
|
||||||
|
metadata: {
|
||||||
|
js: {
|
||||||
|
packageName: '@org/pkg1',
|
||||||
|
packageExports: exports,
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const targetProjectLocator = new TargetProjectLocator(
|
||||||
|
projects,
|
||||||
|
{},
|
||||||
|
new Map()
|
||||||
|
);
|
||||||
|
const result =
|
||||||
|
targetProjectLocator.findDependencyInWorkspaceProjects('@org/pkg1');
|
||||||
|
|
||||||
|
expect(result).toEqual('pkg1');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it('should not match "@org/pkg2" when there is no workspace project with that package name', () => {
|
||||||
|
let projects: Record<string, ProjectGraphProjectNode> = {
|
||||||
|
pkg1: {
|
||||||
|
name: 'pkg1',
|
||||||
|
type: 'lib' as const,
|
||||||
|
data: {
|
||||||
|
root: 'pkg1',
|
||||||
|
metadata: {
|
||||||
|
js: {
|
||||||
|
packageName: '@org/pkg1',
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const targetProjectLocator = new TargetProjectLocator(
|
||||||
|
projects,
|
||||||
|
{},
|
||||||
|
new Map()
|
||||||
|
);
|
||||||
|
const result =
|
||||||
|
targetProjectLocator.findDependencyInWorkspaceProjects('@org/pkg2');
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('findImportInWorkspaceProjects', () => {
|
||||||
|
it.each`
|
||||||
|
exports | importPath
|
||||||
|
${'dist/index.js'} | ${'@org/pkg1'}
|
||||||
|
${{ '.': 'dist/index.js' }} | ${'@org/pkg1'}
|
||||||
|
${{ './subpath': './dist/subpath.js' }} | ${'@org/pkg1/subpath'}
|
||||||
|
${{ './*': './dist/*.js' }} | ${'@org/pkg1/subpath'}
|
||||||
|
${{ import: './dist/index.js', default: './dist/index.js' }} | ${'@org/pkg1'}
|
||||||
|
`(
|
||||||
|
'should find "$importPath" as "pkg1" project when exports="$exports"',
|
||||||
|
({ exports, importPath }) => {
|
||||||
|
let projects: Record<string, ProjectGraphProjectNode> = {
|
||||||
|
pkg1: {
|
||||||
|
name: 'pkg1',
|
||||||
|
type: 'lib' as const,
|
||||||
|
data: {
|
||||||
|
root: 'pkg1',
|
||||||
|
metadata: {
|
||||||
|
js: {
|
||||||
|
packageName: '@org/pkg1',
|
||||||
|
packageExports: exports,
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const targetProjectLocator = new TargetProjectLocator(
|
||||||
|
projects,
|
||||||
|
{},
|
||||||
|
new Map()
|
||||||
|
);
|
||||||
|
const result =
|
||||||
|
targetProjectLocator.findImportInWorkspaceProjects(importPath);
|
||||||
|
|
||||||
|
expect(result).toEqual('pkg1');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
exports | importPath
|
||||||
|
${'dist/index.js'} | ${'@org/pkg1'}
|
||||||
|
${{ '.': 'dist/index.js' }} | ${'@org/pkg1'}
|
||||||
|
${{ './subpath': './dist/subpath.js' }} | ${'@org/pkg1/subpath'}
|
||||||
|
${{ './*': './dist/*.js' }} | ${'@org/pkg1/subpath'}
|
||||||
|
${{ import: './dist/index.js', default: './dist/index.js' }} | ${'@org/pkg1'}
|
||||||
|
`(
|
||||||
|
'should not find "$importPath" as "pkg1" project when exports="$exports" and isInPackageManagerWorkspaces is false',
|
||||||
|
({ exports, importPath }) => {
|
||||||
|
let projects: Record<string, ProjectGraphProjectNode> = {
|
||||||
|
pkg1: {
|
||||||
|
name: 'pkg1',
|
||||||
|
type: 'lib' as const,
|
||||||
|
data: {
|
||||||
|
root: 'pkg1',
|
||||||
|
metadata: {
|
||||||
|
js: {
|
||||||
|
packageName: '@org/pkg1',
|
||||||
|
packageExports: exports,
|
||||||
|
isInPackageManagerWorkspaces: false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const targetProjectLocator = new TargetProjectLocator(
|
||||||
|
projects,
|
||||||
|
{},
|
||||||
|
new Map()
|
||||||
|
);
|
||||||
|
const result =
|
||||||
|
targetProjectLocator.findImportInWorkspaceProjects(importPath);
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it.each`
|
||||||
|
exports | importPath
|
||||||
|
${undefined} | ${'@org/pkg1'}
|
||||||
|
${{}} | ${'@org/pkg1'}
|
||||||
|
${{ '.': 'dist/index.js' }} | ${'@org/pkg1/subpath'}
|
||||||
|
${{ './subpath': './dist/subpath.js' }} | ${'@org/pkg1/subpath/extra-path'}
|
||||||
|
${{ './*': './dist/*.js' }} | ${'@org/pkg1/subpath/extra-path'}
|
||||||
|
${{ './feature': null }} | ${'@org/pkg1/feature'}
|
||||||
|
${{ import: './dist/index.js', default: './dist/index.js' }} | ${'@org/pkg1/subpath'}
|
||||||
|
`(
|
||||||
|
'should not match "$importPath" when exports="$exports"',
|
||||||
|
({ exports, importPath }) => {
|
||||||
|
let projects: Record<string, ProjectGraphProjectNode> = {
|
||||||
|
pkg1: {
|
||||||
|
name: 'pkg1',
|
||||||
|
type: 'lib' as const,
|
||||||
|
data: {
|
||||||
|
root: 'pkg1',
|
||||||
|
metadata: {
|
||||||
|
js: {
|
||||||
|
packageName: '@org/pkg1',
|
||||||
|
packageExports: exports,
|
||||||
|
isInPackageManagerWorkspaces: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const targetProjectLocator = new TargetProjectLocator(
|
||||||
|
projects,
|
||||||
|
{},
|
||||||
|
new Map()
|
||||||
|
);
|
||||||
|
const result =
|
||||||
|
targetProjectLocator.findImportInWorkspaceProjects(importPath);
|
||||||
|
|
||||||
|
expect(result).toBeFalsy();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('isBuiltinModuleImport()', () => {
|
describe('isBuiltinModuleImport()', () => {
|
||||||
|
|||||||
@ -13,7 +13,10 @@ import { isRelativePath, readJsonFile } from '../../../../utils/fileutils';
|
|||||||
import { getPackageNameFromImportPath } from '../../../../utils/get-package-name-from-import-path';
|
import { getPackageNameFromImportPath } from '../../../../utils/get-package-name-from-import-path';
|
||||||
import type { PackageJson } from '../../../../utils/package-json';
|
import type { PackageJson } from '../../../../utils/package-json';
|
||||||
import { workspaceRoot } from '../../../../utils/workspace-root';
|
import { workspaceRoot } from '../../../../utils/workspace-root';
|
||||||
import { getPackageEntryPointsToProjectMap } from '../../utils/packages';
|
import {
|
||||||
|
getWorkspacePackagesMetadata,
|
||||||
|
matchImportToWildcardEntryPointsToProjectMap,
|
||||||
|
} from '../../utils/packages';
|
||||||
import { resolveRelativeToDir } from '../../utils/resolve-relative-to-dir';
|
import { resolveRelativeToDir } from '../../utils/resolve-relative-to-dir';
|
||||||
import {
|
import {
|
||||||
getRootTsConfigFileName,
|
getRootTsConfigFileName,
|
||||||
@ -45,10 +48,11 @@ export class TargetProjectLocator {
|
|||||||
private tsConfig = this.getRootTsConfig();
|
private tsConfig = this.getRootTsConfig();
|
||||||
private paths = this.tsConfig.config?.compilerOptions?.paths;
|
private paths = this.tsConfig.config?.compilerOptions?.paths;
|
||||||
private typescriptResolutionCache = new Map<string, string | null>();
|
private typescriptResolutionCache = new Map<string, string | null>();
|
||||||
private packageEntryPointsToProjectMap: Record<
|
private packagesMetadata: {
|
||||||
string,
|
entryPointsToProjectMap: Record<string, ProjectGraphProjectNode>;
|
||||||
ProjectGraphProjectNode
|
wildcardEntryPointsToProjectMap: Record<string, ProjectGraphProjectNode>;
|
||||||
>;
|
packageToProjectMap: Record<string, ProjectGraphProjectNode>;
|
||||||
|
};
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private readonly nodes: Record<string, ProjectGraphProjectNode>,
|
private readonly nodes: Record<string, ProjectGraphProjectNode>,
|
||||||
@ -142,7 +146,7 @@ export class TargetProjectLocator {
|
|||||||
|
|
||||||
// fall back to see if it's a locally linked workspace project where the
|
// fall back to see if it's a locally linked workspace project where the
|
||||||
// output might not exist yet
|
// output might not exist yet
|
||||||
const localProject = this.findDependencyInWorkspaceProjects(importExpr);
|
const localProject = this.findImportInWorkspaceProjects(importExpr);
|
||||||
if (localProject) {
|
if (localProject) {
|
||||||
return localProject;
|
return localProject;
|
||||||
}
|
}
|
||||||
@ -254,12 +258,25 @@ export class TargetProjectLocator {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
findDependencyInWorkspaceProjects(dep: string): string | null {
|
findImportInWorkspaceProjects(importPath: string): string | null {
|
||||||
this.packageEntryPointsToProjectMap ??= getPackageEntryPointsToProjectMap(
|
this.packagesMetadata ??= getWorkspacePackagesMetadata(this.nodes);
|
||||||
this.nodes
|
|
||||||
|
if (this.packagesMetadata.entryPointsToProjectMap[importPath]) {
|
||||||
|
return this.packagesMetadata.entryPointsToProjectMap[importPath].name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = matchImportToWildcardEntryPointsToProjectMap(
|
||||||
|
this.packagesMetadata.wildcardEntryPointsToProjectMap,
|
||||||
|
importPath
|
||||||
);
|
);
|
||||||
|
|
||||||
return this.packageEntryPointsToProjectMap[dep]?.name ?? null;
|
return project?.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
findDependencyInWorkspaceProjects(dep: string): string | null {
|
||||||
|
this.packagesMetadata ??= getWorkspacePackagesMetadata(this.nodes);
|
||||||
|
|
||||||
|
return this.packagesMetadata.packageToProjectMap[dep]?.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
private resolveImportWithTypescript(
|
private resolveImportWithTypescript(
|
||||||
|
|||||||
@ -1,11 +1,20 @@
|
|||||||
|
import { minimatch } from 'minimatch';
|
||||||
import { join } from 'node:path/posix';
|
import { join } from 'node:path/posix';
|
||||||
import type { ProjectGraphProjectNode } from '../../../config/project-graph';
|
import type { ProjectGraphProjectNode } from '../../../config/project-graph';
|
||||||
import type { ProjectConfiguration } from '../../../config/workspace-json-project-json';
|
import type { ProjectConfiguration } from '../../../config/workspace-json-project-json';
|
||||||
|
|
||||||
export function getPackageEntryPointsToProjectMap<
|
export function getWorkspacePackagesMetadata<
|
||||||
T extends ProjectGraphProjectNode | ProjectConfiguration
|
T extends ProjectGraphProjectNode | ProjectConfiguration
|
||||||
>(projects: Record<string, T>): Record<string, T> {
|
>(
|
||||||
const result: Record<string, T> = {};
|
projects: Record<string, T>
|
||||||
|
): {
|
||||||
|
entryPointsToProjectMap: Record<string, T>;
|
||||||
|
wildcardEntryPointsToProjectMap: Record<string, T>;
|
||||||
|
packageToProjectMap: Record<string, T>;
|
||||||
|
} {
|
||||||
|
const entryPointsToProjectMap: Record<string, T> = {};
|
||||||
|
const wildcardEntryPointsToProjectMap: Record<string, T> = {};
|
||||||
|
const packageToProjectMap: Record<string, T> = {};
|
||||||
for (const project of Object.values(projects)) {
|
for (const project of Object.values(projects)) {
|
||||||
const metadata =
|
const metadata =
|
||||||
'data' in project ? project.data.metadata : project.metadata;
|
'data' in project ? project.data.metadata : project.metadata;
|
||||||
@ -14,17 +23,75 @@ export function getPackageEntryPointsToProjectMap<
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const { packageName, packageExports } = metadata.js;
|
const {
|
||||||
if (!packageExports || typeof packageExports === 'string') {
|
packageName,
|
||||||
// no `exports` or it points to a file, which would be the equivalent of
|
packageExports,
|
||||||
// an '.' export, in which case the package name is the entry point
|
packageMain,
|
||||||
result[packageName] = project;
|
isInPackageManagerWorkspaces,
|
||||||
} else {
|
} = metadata.js;
|
||||||
for (const entryPoint of Object.keys(packageExports)) {
|
packageToProjectMap[packageName] = project;
|
||||||
result[join(packageName, entryPoint)] = project;
|
|
||||||
|
if (!isInPackageManagerWorkspaces) {
|
||||||
|
// it is not included in the package manager workspaces config, so we
|
||||||
|
// skip it since the exports information wouldn't be used by the Node.js
|
||||||
|
// resolution
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (packageExports) {
|
||||||
|
if (typeof packageExports === 'string') {
|
||||||
|
// it points to a file, which would be the equivalent of an '.' export,
|
||||||
|
// in which case the package name is the entry point
|
||||||
|
entryPointsToProjectMap[packageName] = project;
|
||||||
|
} else {
|
||||||
|
for (const entryPoint of Object.keys(packageExports)) {
|
||||||
|
if (packageExports[entryPoint] === null) {
|
||||||
|
// if the entry point is restricted, we skip it
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryPoint.startsWith('.')) {
|
||||||
|
// it is a relative subpath export
|
||||||
|
if (entryPoint.includes('*')) {
|
||||||
|
wildcardEntryPointsToProjectMap[join(packageName, entryPoint)] =
|
||||||
|
project;
|
||||||
|
} else {
|
||||||
|
entryPointsToProjectMap[join(packageName, entryPoint)] = project;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// it's a conditional export, so we use the package name as the entry point
|
||||||
|
// https://nodejs.org/api/packages.html#conditional-exports
|
||||||
|
entryPointsToProjectMap[packageName] = project;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else if (packageMain) {
|
||||||
|
// if there is no exports, but there is a main, the package name is the
|
||||||
|
// entry point
|
||||||
|
entryPointsToProjectMap[packageName] = project;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return {
|
||||||
|
entryPointsToProjectMap,
|
||||||
|
wildcardEntryPointsToProjectMap,
|
||||||
|
packageToProjectMap,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function matchImportToWildcardEntryPointsToProjectMap<
|
||||||
|
T extends ProjectGraphProjectNode | ProjectConfiguration
|
||||||
|
>(
|
||||||
|
wildcardEntryPointsToProjectMap: Record<string, T>,
|
||||||
|
importPath: string
|
||||||
|
): T | null {
|
||||||
|
if (!Object.keys(wildcardEntryPointsToProjectMap).length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchingPair = Object.entries(wildcardEntryPointsToProjectMap).find(
|
||||||
|
([key]) => minimatch(importPath, key)
|
||||||
|
);
|
||||||
|
|
||||||
|
return matchingPair?.[1];
|
||||||
}
|
}
|
||||||
|
|||||||
@ -48,7 +48,7 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
'/root'
|
'/root'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(createNodeFromPackageJson('package.json', '/root', {}))
|
expect(createNodeFromPackageJson('package.json', '/root', {}, false))
|
||||||
.toMatchInlineSnapshot(`
|
.toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
@ -56,7 +56,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": false,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "root",
|
"packageName": "root",
|
||||||
},
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
@ -95,7 +97,12 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('packages/lib-a/package.json', '/root', {})
|
createNodeFromPackageJson(
|
||||||
|
'packages/lib-a/package.json',
|
||||||
|
'/root',
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
)
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
@ -103,7 +110,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "lib-a description",
|
"description": "lib-a description",
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": false,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "lib-a",
|
"packageName": "lib-a",
|
||||||
},
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
@ -142,7 +151,12 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('packages/lib-b/package.json', '/root', {})
|
createNodeFromPackageJson(
|
||||||
|
'packages/lib-b/package.json',
|
||||||
|
'/root',
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
)
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
{
|
{
|
||||||
"projects": {
|
"projects": {
|
||||||
@ -157,7 +171,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": "lib-b description",
|
"description": "lib-b description",
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": false,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "lib-b",
|
"packageName": "lib-b",
|
||||||
},
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
@ -265,7 +281,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "vite",
|
"packageName": "vite",
|
||||||
},
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
@ -367,7 +385,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "vite",
|
"packageName": "vite",
|
||||||
},
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
@ -465,7 +485,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "vite",
|
"packageName": "vite",
|
||||||
},
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
@ -547,7 +569,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "root",
|
"packageName": "root",
|
||||||
},
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
@ -629,7 +653,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "root",
|
"packageName": "root",
|
||||||
},
|
},
|
||||||
"targetGroups": {
|
"targetGroups": {
|
||||||
@ -718,7 +744,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
"metadata": {
|
"metadata": {
|
||||||
"description": undefined,
|
"description": undefined,
|
||||||
"js": {
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
"packageExports": undefined,
|
"packageExports": undefined,
|
||||||
|
"packageMain": undefined,
|
||||||
"packageName": "root",
|
"packageName": "root",
|
||||||
},
|
},
|
||||||
"targetGroups": {},
|
"targetGroups": {},
|
||||||
@ -769,13 +797,17 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('apps/myapp/package.json', '/root', {})
|
createNodeFromPackageJson('apps/myapp/package.json', '/root', {}, false)
|
||||||
.projects['apps/myapp'].projectType
|
.projects['apps/myapp'].projectType
|
||||||
).toEqual('application');
|
).toEqual('application');
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('packages/mylib/package.json', '/root', {})
|
createNodeFromPackageJson(
|
||||||
.projects['packages/mylib'].projectType
|
'packages/mylib/package.json',
|
||||||
|
'/root',
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
).projects['packages/mylib'].projectType
|
||||||
).toEqual('library');
|
).toEqual('library');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -797,8 +829,9 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('package.json', '/root', {}).projects['.']
|
createNodeFromPackageJson('package.json', '/root', {}, false).projects[
|
||||||
.projectType
|
'.'
|
||||||
|
].projectType
|
||||||
).toEqual('library');
|
).toEqual('library');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -823,19 +856,26 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('packages/mylib/package.json', '/root', {})
|
createNodeFromPackageJson(
|
||||||
.projects['packages/mylib'].projectType
|
'packages/mylib/package.json',
|
||||||
|
'/root',
|
||||||
|
{},
|
||||||
|
false
|
||||||
|
).projects['packages/mylib'].projectType
|
||||||
).toEqual('library');
|
).toEqual('library');
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('example/package.json', '/root', {}).projects[
|
createNodeFromPackageJson('example/package.json', '/root', {}, false)
|
||||||
'example'
|
.projects['example'].projectType
|
||||||
].projectType
|
|
||||||
).toBeUndefined();
|
).toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should store package name and exports in the project metadata', () => {
|
it('should store js package metadata', async () => {
|
||||||
vol.fromJSON(
|
vol.fromJSON(
|
||||||
{
|
{
|
||||||
|
'package.json': JSON.stringify({
|
||||||
|
name: 'repo',
|
||||||
|
workspaces: ['packages/*'],
|
||||||
|
}),
|
||||||
'packages/lib-a/package.json': JSON.stringify({
|
'packages/lib-a/package.json': JSON.stringify({
|
||||||
name: 'lib-a',
|
name: 'lib-a',
|
||||||
description: 'lib-a description',
|
description: 'lib-a description',
|
||||||
@ -845,59 +885,139 @@ describe('nx package.json workspaces plugin', () => {
|
|||||||
'.': './dist/index.js',
|
'.': './dist/index.js',
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
// not in package manager workspaces
|
||||||
|
'libs/lib-b/package.json': JSON.stringify({
|
||||||
|
name: 'lib-b',
|
||||||
|
description: 'lib-b description',
|
||||||
|
scripts: { test: 'jest' },
|
||||||
|
exports: {
|
||||||
|
'./package.json': './package.json',
|
||||||
|
'.': './dist/index.js',
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
// project.json so it's identified as a project
|
||||||
|
'libs/lib-b/project.json': '{}',
|
||||||
},
|
},
|
||||||
'/root'
|
'/root'
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
createNodeFromPackageJson('packages/lib-a/package.json', '/root', {})
|
await createNodesV2[1](
|
||||||
|
[
|
||||||
|
'package.json',
|
||||||
|
'packages/lib-a/package.json',
|
||||||
|
'libs/lib-b/package.json',
|
||||||
|
'libs/lib-b/project.json',
|
||||||
|
],
|
||||||
|
|
||||||
|
undefined,
|
||||||
|
context
|
||||||
|
)
|
||||||
).toMatchInlineSnapshot(`
|
).toMatchInlineSnapshot(`
|
||||||
{
|
[
|
||||||
"projects": {
|
[
|
||||||
"packages/lib-a": {
|
"packages/lib-a/package.json",
|
||||||
"metadata": {
|
{
|
||||||
"description": "lib-a description",
|
"projects": {
|
||||||
"js": {
|
"packages/lib-a": {
|
||||||
"packageExports": {
|
|
||||||
".": "./dist/index.js",
|
|
||||||
"./package.json": "./package.json",
|
|
||||||
},
|
|
||||||
"packageName": "lib-a",
|
|
||||||
},
|
|
||||||
"targetGroups": {
|
|
||||||
"NPM Scripts": [
|
|
||||||
"test",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
"name": "lib-a",
|
|
||||||
"root": "packages/lib-a",
|
|
||||||
"sourceRoot": "packages/lib-a",
|
|
||||||
"tags": [
|
|
||||||
"npm:public",
|
|
||||||
],
|
|
||||||
"targets": {
|
|
||||||
"nx-release-publish": {
|
|
||||||
"dependsOn": [
|
|
||||||
"^nx-release-publish",
|
|
||||||
],
|
|
||||||
"executor": "@nx/js:release-publish",
|
|
||||||
"options": {},
|
|
||||||
},
|
|
||||||
"test": {
|
|
||||||
"executor": "nx:run-script",
|
|
||||||
"metadata": {
|
"metadata": {
|
||||||
"runCommand": "npm run test",
|
"description": "lib-a description",
|
||||||
"scriptContent": "jest",
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": true,
|
||||||
|
"packageExports": {
|
||||||
|
".": "./dist/index.js",
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
},
|
||||||
|
"packageMain": undefined,
|
||||||
|
"packageName": "lib-a",
|
||||||
|
},
|
||||||
|
"targetGroups": {
|
||||||
|
"NPM Scripts": [
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"options": {
|
"name": "lib-a",
|
||||||
"script": "test",
|
"root": "packages/lib-a",
|
||||||
|
"sourceRoot": "packages/lib-a",
|
||||||
|
"tags": [
|
||||||
|
"npm:public",
|
||||||
|
],
|
||||||
|
"targets": {
|
||||||
|
"nx-release-publish": {
|
||||||
|
"dependsOn": [
|
||||||
|
"^nx-release-publish",
|
||||||
|
],
|
||||||
|
"executor": "@nx/js:release-publish",
|
||||||
|
"options": {},
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "nx:run-script",
|
||||||
|
"metadata": {
|
||||||
|
"runCommand": "npm run test",
|
||||||
|
"scriptContent": "jest",
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"script": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
}
|
[
|
||||||
|
"libs/lib-b/package.json",
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"libs/lib-b": {
|
||||||
|
"metadata": {
|
||||||
|
"description": "lib-b description",
|
||||||
|
"js": {
|
||||||
|
"isInPackageManagerWorkspaces": false,
|
||||||
|
"packageExports": {
|
||||||
|
".": "./dist/index.js",
|
||||||
|
"./package.json": "./package.json",
|
||||||
|
},
|
||||||
|
"packageMain": undefined,
|
||||||
|
"packageName": "lib-b",
|
||||||
|
},
|
||||||
|
"targetGroups": {
|
||||||
|
"NPM Scripts": [
|
||||||
|
"test",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"name": "lib-b",
|
||||||
|
"root": "libs/lib-b",
|
||||||
|
"sourceRoot": "libs/lib-b",
|
||||||
|
"tags": [
|
||||||
|
"npm:public",
|
||||||
|
],
|
||||||
|
"targets": {
|
||||||
|
"nx-release-publish": {
|
||||||
|
"dependsOn": [
|
||||||
|
"^nx-release-publish",
|
||||||
|
],
|
||||||
|
"executor": "@nx/js:release-publish",
|
||||||
|
"options": {},
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"executor": "nx:run-script",
|
||||||
|
"metadata": {
|
||||||
|
"runCommand": "npm run test",
|
||||||
|
"scriptContent": "jest",
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"script": "test",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -50,8 +50,10 @@ export const createNodesV2: CreateNodesV2 = [
|
|||||||
|
|
||||||
return createNodesFromFiles(
|
return createNodesFromFiles(
|
||||||
(packageJsonPath, options, context) => {
|
(packageJsonPath, options, context) => {
|
||||||
|
const isInPackageManagerWorkspaces =
|
||||||
|
isInPackageJsonWorkspaces(packageJsonPath);
|
||||||
if (
|
if (
|
||||||
!isInPackageJsonWorkspaces(packageJsonPath) &&
|
!isInPackageManagerWorkspaces &&
|
||||||
!isNextToProjectJson(packageJsonPath)
|
!isNextToProjectJson(packageJsonPath)
|
||||||
) {
|
) {
|
||||||
// Skip if package.json is not part of the package.json workspaces and not next to a project.json.
|
// Skip if package.json is not part of the package.json workspaces and not next to a project.json.
|
||||||
@ -61,7 +63,8 @@ export const createNodesV2: CreateNodesV2 = [
|
|||||||
return createNodeFromPackageJson(
|
return createNodeFromPackageJson(
|
||||||
packageJsonPath,
|
packageJsonPath,
|
||||||
context.workspaceRoot,
|
context.workspaceRoot,
|
||||||
cache
|
cache,
|
||||||
|
isInPackageManagerWorkspaces
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
packageJsons,
|
packageJsons,
|
||||||
@ -91,7 +94,7 @@ function splitConfigFiles(configFiles: readonly string[]): {
|
|||||||
|
|
||||||
export function buildPackageJsonWorkspacesMatcher(
|
export function buildPackageJsonWorkspacesMatcher(
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
readJson: (string) => any
|
readJson: (path: string) => any
|
||||||
) {
|
) {
|
||||||
const patterns = getGlobPatternsFromPackageManagerWorkspaces(
|
const patterns = getGlobPatternsFromPackageManagerWorkspaces(
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
@ -129,7 +132,8 @@ export function buildPackageJsonWorkspacesMatcher(
|
|||||||
export function createNodeFromPackageJson(
|
export function createNodeFromPackageJson(
|
||||||
pkgJsonPath: string,
|
pkgJsonPath: string,
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
cache: PackageJsonConfigurationCache
|
cache: PackageJsonConfigurationCache,
|
||||||
|
isInPackageManagerWorkspaces: boolean
|
||||||
) {
|
) {
|
||||||
const json: PackageJson = readJsonFile(join(workspaceRoot, pkgJsonPath));
|
const json: PackageJson = readJsonFile(join(workspaceRoot, pkgJsonPath));
|
||||||
|
|
||||||
@ -138,12 +142,7 @@ export function createNodeFromPackageJson(
|
|||||||
const hash = hashObject({
|
const hash = hashObject({
|
||||||
...json,
|
...json,
|
||||||
root: projectRoot,
|
root: projectRoot,
|
||||||
/**
|
isInPackageManagerWorkspaces,
|
||||||
* Increment this number to force processing the package.json again. Do it
|
|
||||||
* when the implementation of this plugin is changed and results in different
|
|
||||||
* results for the same package.json contents.
|
|
||||||
*/
|
|
||||||
bust: 1,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const cached = cache[hash];
|
const cached = cache[hash];
|
||||||
@ -159,7 +158,8 @@ export function createNodeFromPackageJson(
|
|||||||
json,
|
json,
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
pkgJsonPath,
|
pkgJsonPath,
|
||||||
readNxJson(workspaceRoot)
|
readNxJson(workspaceRoot),
|
||||||
|
isInPackageManagerWorkspaces
|
||||||
);
|
);
|
||||||
|
|
||||||
cache[hash] = project;
|
cache[hash] = project;
|
||||||
@ -174,7 +174,8 @@ export function buildProjectConfigurationFromPackageJson(
|
|||||||
packageJson: PackageJson,
|
packageJson: PackageJson,
|
||||||
workspaceRoot: string,
|
workspaceRoot: string,
|
||||||
packageJsonPath: string,
|
packageJsonPath: string,
|
||||||
nxJson: NxJsonConfiguration
|
nxJson: NxJsonConfiguration,
|
||||||
|
isInPackageManagerWorkspaces: boolean
|
||||||
): ProjectConfiguration & { name: string } {
|
): ProjectConfiguration & { name: string } {
|
||||||
const normalizedPath = packageJsonPath.split('\\').join('/');
|
const normalizedPath = packageJsonPath.split('\\').join('/');
|
||||||
const projectRoot = dirname(normalizedPath);
|
const projectRoot = dirname(normalizedPath);
|
||||||
@ -213,7 +214,10 @@ export function buildProjectConfigurationFromPackageJson(
|
|||||||
...packageJson.nx,
|
...packageJson.nx,
|
||||||
targets: readTargetsFromPackageJson(packageJson, nxJson),
|
targets: readTargetsFromPackageJson(packageJson, nxJson),
|
||||||
tags: getTagsFromPackageJson(packageJson),
|
tags: getTagsFromPackageJson(packageJson),
|
||||||
metadata: getMetadataFromPackageJson(packageJson),
|
metadata: getMetadataFromPackageJson(
|
||||||
|
packageJson,
|
||||||
|
isInPackageManagerWorkspaces
|
||||||
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
if (
|
if (
|
||||||
|
|||||||
@ -22,6 +22,7 @@ import {
|
|||||||
readProjectConfigurationsFromRootMap,
|
readProjectConfigurationsFromRootMap,
|
||||||
} from './utils/project-configuration-utils';
|
} from './utils/project-configuration-utils';
|
||||||
import {
|
import {
|
||||||
|
buildPackageJsonWorkspacesMatcher,
|
||||||
buildProjectConfigurationFromPackageJson,
|
buildProjectConfigurationFromPackageJson,
|
||||||
getGlobPatternsFromPackageManagerWorkspaces,
|
getGlobPatternsFromPackageManagerWorkspaces,
|
||||||
} from '../plugins/package-json';
|
} from '../plugins/package-json';
|
||||||
@ -200,6 +201,11 @@ function getProjectsSync(
|
|||||||
];
|
];
|
||||||
const projectFiles = globWithWorkspaceContextSync(root, patterns);
|
const projectFiles = globWithWorkspaceContextSync(root, patterns);
|
||||||
|
|
||||||
|
const isInPackageJsonWorkspaces = buildPackageJsonWorkspacesMatcher(
|
||||||
|
root,
|
||||||
|
(f) => readJsonFile(join(root, f))
|
||||||
|
);
|
||||||
|
|
||||||
const rootMap: Record<string, ProjectConfiguration> = {};
|
const rootMap: Record<string, ProjectConfiguration> = {};
|
||||||
for (const projectFile of projectFiles) {
|
for (const projectFile of projectFiles) {
|
||||||
if (basename(projectFile) === 'project.json') {
|
if (basename(projectFile) === 'project.json') {
|
||||||
@ -218,7 +224,8 @@ function getProjectsSync(
|
|||||||
packageJson,
|
packageJson,
|
||||||
root,
|
root,
|
||||||
projectFile,
|
projectFile,
|
||||||
nxJson
|
nxJson,
|
||||||
|
isInPackageJsonWorkspaces(projectFile)
|
||||||
);
|
);
|
||||||
if (!rootMap[config.root]) {
|
if (!rootMap[config.root]) {
|
||||||
mergeProjectConfigurationIntoRootMap(
|
mergeProjectConfigurationIntoRootMap(
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
import * as path from 'node:path';
|
import * as path from 'node:path';
|
||||||
import { existsSync } from 'node:fs';
|
import { existsSync } from 'node:fs';
|
||||||
|
|
||||||
import { getPackageEntryPointsToProjectMap } from '../../plugins/js/utils/packages';
|
import {
|
||||||
|
getWorkspacePackagesMetadata,
|
||||||
|
matchImportToWildcardEntryPointsToProjectMap,
|
||||||
|
} from '../../plugins/js/utils/packages';
|
||||||
import { readJsonFile } from '../../utils/fileutils';
|
import { readJsonFile } from '../../utils/fileutils';
|
||||||
import { logger } from '../../utils/logger';
|
import { logger } from '../../utils/logger';
|
||||||
import { normalizePath } from '../../utils/path';
|
import { normalizePath } from '../../utils/path';
|
||||||
@ -119,6 +122,7 @@ function lookupLocalPlugin(
|
|||||||
}
|
}
|
||||||
|
|
||||||
let packageEntryPointsToProjectMap: Record<string, ProjectConfiguration>;
|
let packageEntryPointsToProjectMap: Record<string, ProjectConfiguration>;
|
||||||
|
let wildcardEntryPointsToProjectMap: Record<string, ProjectConfiguration>;
|
||||||
function findNxProjectForImportPath(
|
function findNxProjectForImportPath(
|
||||||
importPath: string,
|
importPath: string,
|
||||||
projects: Record<string, ProjectConfiguration>,
|
projects: Record<string, ProjectConfiguration>,
|
||||||
@ -146,12 +150,24 @@ function findNxProjectForImportPath(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
packageEntryPointsToProjectMap ??=
|
if (!packageEntryPointsToProjectMap && !wildcardEntryPointsToProjectMap) {
|
||||||
getPackageEntryPointsToProjectMap(projects);
|
({
|
||||||
|
entryPointsToProjectMap: packageEntryPointsToProjectMap,
|
||||||
|
wildcardEntryPointsToProjectMap,
|
||||||
|
} = getWorkspacePackagesMetadata(projects));
|
||||||
|
}
|
||||||
if (packageEntryPointsToProjectMap[importPath]) {
|
if (packageEntryPointsToProjectMap[importPath]) {
|
||||||
return packageEntryPointsToProjectMap[importPath];
|
return packageEntryPointsToProjectMap[importPath];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const project = matchImportToWildcardEntryPointsToProjectMap(
|
||||||
|
wildcardEntryPointsToProjectMap,
|
||||||
|
importPath
|
||||||
|
);
|
||||||
|
if (project) {
|
||||||
|
return project;
|
||||||
|
}
|
||||||
|
|
||||||
logger.verbose(
|
logger.verbose(
|
||||||
'Unable to find local plugin',
|
'Unable to find local plugin',
|
||||||
possibleTsPaths,
|
possibleTsPaths,
|
||||||
|
|||||||
@ -154,9 +154,10 @@ export function buildTargetFromScript(
|
|||||||
let packageManagerCommand: PackageManagerCommands | undefined;
|
let packageManagerCommand: PackageManagerCommands | undefined;
|
||||||
|
|
||||||
export function getMetadataFromPackageJson(
|
export function getMetadataFromPackageJson(
|
||||||
packageJson: PackageJson
|
packageJson: PackageJson,
|
||||||
|
isInPackageManagerWorkspaces: boolean
|
||||||
): ProjectMetadata {
|
): ProjectMetadata {
|
||||||
const { scripts, nx, description, name, exports } = packageJson;
|
const { scripts, nx, description, name, exports, main } = packageJson;
|
||||||
const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {});
|
const includedScripts = nx?.includedScripts || Object.keys(scripts ?? {});
|
||||||
return {
|
return {
|
||||||
targetGroups: {
|
targetGroups: {
|
||||||
@ -166,6 +167,8 @@ export function getMetadataFromPackageJson(
|
|||||||
js: {
|
js: {
|
||||||
packageName: name,
|
packageName: name,
|
||||||
packageExports: exports,
|
packageExports: exports,
|
||||||
|
packageMain: main,
|
||||||
|
isInPackageManagerWorkspaces,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user