fix(linter): skip verifying deps of deps by default in package.json (#18058)
This commit is contained in:
parent
da2674ded6
commit
ae773d547e
@ -452,6 +452,12 @@ describe('Linter', () => {
|
||||
];
|
||||
return json;
|
||||
});
|
||||
// Set this to false for now until the `@nx/js:lib` generator is updated to include ts/swc helpers by default.
|
||||
// TODO(jack): Remove this once the above is addressed in another PR.
|
||||
updateJson(`libs/${mylib}/tsconfig.lib.json`, (json) => {
|
||||
json.compilerOptions.importHelpers = false;
|
||||
return json;
|
||||
});
|
||||
updateJson(`libs/${mylib}/project.json`, (json) => {
|
||||
json.targets.lint.options.lintFilePatterns = [
|
||||
`libs/${mylib}/**/*.ts`,
|
||||
@ -465,8 +471,7 @@ describe('Linter', () => {
|
||||
it('should report dependency check issues', () => {
|
||||
const rootPackageJson = readJson('package.json');
|
||||
const nxVersion = rootPackageJson.devDependencies.nx;
|
||||
const swcCoreVersion = rootPackageJson.devDependencies['@swc/core'];
|
||||
const swcHelpersVersion = rootPackageJson.dependencies['@swc/helpers'];
|
||||
const tslibVersion = rootPackageJson.devDependencies['tslib'];
|
||||
|
||||
let out = runCLI(`lint ${mylib}`, { silenceError: true });
|
||||
expect(out).toContain('All files pass linting');
|
||||
@ -495,9 +500,6 @@ describe('Linter', () => {
|
||||
{
|
||||
"dependencies": {
|
||||
"@nx/devkit": "${nxVersion}",
|
||||
"@swc/core": "${swcCoreVersion}",
|
||||
"@swc/helpers": "${swcHelpersVersion}",
|
||||
"nx": "${nxVersion}",
|
||||
},
|
||||
"name": "@proj/${mylib}",
|
||||
"type": "commonjs",
|
||||
|
||||
@ -104,7 +104,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -134,6 +134,74 @@ describe('Dependency checks (eslint)', () => {
|
||||
expect(failures.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should exclude files not matching input of the build target', () => {
|
||||
const packageJson = {
|
||||
name: '@mycompany/liba',
|
||||
dependencies: {},
|
||||
};
|
||||
|
||||
const fileSys = {
|
||||
'./libs/liba/package.json': JSON.stringify(packageJson, null, 2),
|
||||
'./libs/liba/src/index.ts': '',
|
||||
'./libs/liba/project.json': JSON.stringify(
|
||||
{
|
||||
name: 'liba',
|
||||
targets: {
|
||||
build: {
|
||||
command: 'tsc -p tsconfig.lib.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
null,
|
||||
2
|
||||
),
|
||||
'./nx.json': JSON.stringify({
|
||||
targetDefaults: {
|
||||
build: {
|
||||
inputs: [
|
||||
'{projectRoot}/**/*',
|
||||
'!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)',
|
||||
],
|
||||
},
|
||||
},
|
||||
}),
|
||||
'./package.json': JSON.stringify(rootPackageJson, null, 2),
|
||||
};
|
||||
vol.fromJSON(fileSys, '/root');
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
liba: {
|
||||
name: 'liba',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/liba',
|
||||
targets: {
|
||||
build: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
externalNodes,
|
||||
dependencies: {
|
||||
liba: [{ source: 'liba', target: 'npm:external1', type: 'static' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
liba: [
|
||||
createFile(`libs/liba/src/main.ts`, []),
|
||||
createFile(`libs/liba/src/main.spec.ts`, ['npm:external1']),
|
||||
createFile(`libs/liba/package.json`, []),
|
||||
],
|
||||
}
|
||||
);
|
||||
expect(failures.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('should report missing dependencies section and fix it', () => {
|
||||
const packageJson = {
|
||||
name: '@mycompany/liba',
|
||||
@ -148,7 +216,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -191,7 +259,6 @@ describe('Dependency checks (eslint)', () => {
|
||||
"{
|
||||
"name": "@mycompany/liba",
|
||||
"dependencies": {
|
||||
"external1": "~16.1.2"
|
||||
}
|
||||
}"
|
||||
`);
|
||||
@ -211,7 +278,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ ignoredDependencies: ['external1'] },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -255,7 +322,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ ignoredDependencies: ['external1'] },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -299,7 +366,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ ignoredDependencies: ['external1'] },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -344,7 +411,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -416,7 +483,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -473,7 +540,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -534,7 +601,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ buildTargets: ['notbuild'] },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -590,7 +657,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ checkMissingDependencies: false },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -646,7 +713,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ ignoredDependencies: ['external2'] },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -706,7 +773,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -778,7 +845,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -857,7 +924,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -936,7 +1003,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1015,7 +1082,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ checkObsoleteDependencies: false },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1068,7 +1135,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ ignoredDependencies: ['unneeded'] },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1119,7 +1186,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1204,7 +1271,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ checkVersionMismatches: false },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1261,7 +1328,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
|
||||
const failures = runRule(
|
||||
{ ignoredDependencies: ['external1'] },
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1330,7 +1397,7 @@ describe('Dependency checks (eslint)', () => {
|
||||
include: ['**/*.ts'],
|
||||
};
|
||||
|
||||
const tsConfiogBaseJson = {
|
||||
const tsConfigBaseJson = {
|
||||
compilerOptions: {
|
||||
target: 'es2015',
|
||||
importHelpers: true,
|
||||
@ -1353,15 +1420,15 @@ describe('Dependency checks (eslint)', () => {
|
||||
const fileSys = {
|
||||
'./libs/liba/package.json': JSON.stringify(packageJson, null, 2),
|
||||
'./libs/liba/src/index.ts': '',
|
||||
'./libs/libb/tsconfig.json': JSON.stringify(tsConfigJson, null, 2),
|
||||
'./libs/liba/tsconfig.json': JSON.stringify(tsConfigJson, null, 2),
|
||||
'./package.json': JSON.stringify(rootPackageJson, null, 2),
|
||||
'./tsconfig.base.json': JSON.stringify(tsConfiogBaseJson, null, 2),
|
||||
'./tsconfig.base.json': JSON.stringify(tsConfigBaseJson, null, 2),
|
||||
};
|
||||
vol.fromJSON(fileSys, '/root');
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1370,21 +1437,11 @@ describe('Dependency checks (eslint)', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/liba',
|
||||
targets: {
|
||||
build: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
libb: {
|
||||
name: 'libb',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/libb',
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/js:tsc',
|
||||
options: {
|
||||
tsConfig: 'libs/libb/tsconfig.json',
|
||||
tsConfig: 'libs/liba/tsconfig.json',
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1393,26 +1450,20 @@ describe('Dependency checks (eslint)', () => {
|
||||
},
|
||||
externalNodes,
|
||||
dependencies: {
|
||||
liba: [
|
||||
{ source: 'liba', target: 'npm:external1', type: 'static' },
|
||||
{ source: 'liba', target: 'libb', type: 'static' },
|
||||
],
|
||||
libb: [{ source: 'libb', target: 'npm:external2', type: 'static' }],
|
||||
liba: [{ source: 'liba', target: 'npm:external1', type: 'static' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
liba: [
|
||||
createFile(`libs/liba/src/main.ts`, ['npm:external1']),
|
||||
createFile(`libs/liba/package.json`, ['npm:external1']),
|
||||
createFile(`libs/libb/src/main.ts`, ['npm:external2']),
|
||||
],
|
||||
}
|
||||
);
|
||||
expect(failures.length).toEqual(1);
|
||||
expect(failures[0].message).toMatchInlineSnapshot(`
|
||||
"The "liba" uses the following packages, but they are missing from the "dependencies":
|
||||
- tslib
|
||||
- external2"
|
||||
- tslib"
|
||||
`);
|
||||
expect(failures[0].line).toEqual(3);
|
||||
});
|
||||
@ -1435,14 +1486,14 @@ it('should require swc if @nx/js:swc executor', () => {
|
||||
const fileSys = {
|
||||
'./libs/liba/package.json': JSON.stringify(packageJson, null, 2),
|
||||
'./libs/liba/src/index.ts': '',
|
||||
'./libs/libb/.swcrc': JSON.stringify(swcrc, null, 2),
|
||||
'./libs/liba/.swcrc': JSON.stringify(swcrc, null, 2),
|
||||
'./package.json': JSON.stringify(rootPackageJson, null, 2),
|
||||
};
|
||||
vol.fromJSON(fileSys, '/root');
|
||||
|
||||
const failures = runRule(
|
||||
{},
|
||||
`${process.cwd()}/proj/libs/liba/package.json`,
|
||||
`/root/libs/liba/package.json`,
|
||||
JSON.stringify(packageJson, null, 2),
|
||||
{
|
||||
nodes: {
|
||||
@ -1451,22 +1502,10 @@ it('should require swc if @nx/js:swc executor', () => {
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/liba',
|
||||
targets: {
|
||||
build: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
libb: {
|
||||
name: 'libb',
|
||||
type: 'lib',
|
||||
data: {
|
||||
root: 'libs/libb',
|
||||
targets: {
|
||||
build: {
|
||||
executor: '@nx/js:swc',
|
||||
options: {
|
||||
tsConfig: 'libs/libb/tsconfig.json',
|
||||
},
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
@ -1474,26 +1513,21 @@ it('should require swc if @nx/js:swc executor', () => {
|
||||
},
|
||||
externalNodes,
|
||||
dependencies: {
|
||||
liba: [
|
||||
{ source: 'liba', target: 'npm:external1', type: 'static' },
|
||||
{ source: 'liba', target: 'libb', type: 'static' },
|
||||
],
|
||||
libb: [],
|
||||
liba: [{ source: 'liba', target: 'npm:external1', type: 'static' }],
|
||||
},
|
||||
},
|
||||
{
|
||||
liba: [
|
||||
createFile(`libs/liba/src/main.ts`, ['npm:external1']),
|
||||
createFile(`libs/liba/package.json`, ['npm:external1']),
|
||||
createFile(`libs/libb/src/main.ts`),
|
||||
],
|
||||
}
|
||||
);
|
||||
expect(failures.length).toEqual(1);
|
||||
expect(failures[0].message).toMatchInlineSnapshot(`
|
||||
"The "liba" uses the following packages, but they are missing from the "dependencies":
|
||||
- @swc/helpers"
|
||||
`);
|
||||
"The "liba" uses the following packages, but they are missing from the "dependencies":
|
||||
- @swc/helpers"
|
||||
`);
|
||||
expect(failures[0].line).toEqual(3);
|
||||
});
|
||||
|
||||
@ -1518,7 +1552,6 @@ function runRule(
|
||||
projectGraph: ProjectGraph,
|
||||
projectFileMap: ProjectFileMap
|
||||
): Linter.LintMessage[] {
|
||||
globalThis.projectPath = `${process.cwd()}/proj`;
|
||||
globalThis.projectGraph = projectGraph;
|
||||
globalThis.projectFileMap = projectFileMap;
|
||||
globalThis.projectRootMappings = createProjectRootMappings(
|
||||
|
||||
@ -1,18 +1,22 @@
|
||||
import { join } from 'path';
|
||||
import { satisfies } from 'semver';
|
||||
import { AST } from 'jsonc-eslint-parser';
|
||||
import { normalizePath, workspaceRoot } from '@nx/devkit';
|
||||
import { type JSONLiteral } from 'jsonc-eslint-parser/lib/parser/ast';
|
||||
import {
|
||||
normalizePath,
|
||||
ProjectGraphProjectNode,
|
||||
FileData,
|
||||
workspaceRoot,
|
||||
} from '@nx/devkit';
|
||||
import { findNpmDependencies } from '@nx/js/src/utils/find-npm-dependencies';
|
||||
|
||||
import { createESLintRule } from '../utils/create-eslint-rule';
|
||||
import { readProjectGraph } from '../utils/project-graph-utils';
|
||||
import { findProject, getSourceFilePath } from '../utils/runtime-lint-utils';
|
||||
import { join } from 'path';
|
||||
import { findProjectsNpmDependencies } from '@nx/js/src/internal';
|
||||
import { satisfies } from 'semver';
|
||||
import { getHelperDependenciesFromProjectGraph } from '@nx/js';
|
||||
import {
|
||||
getAllDependencies,
|
||||
getPackageJson,
|
||||
removePackageJsonFromFileMap,
|
||||
} from '../utils/package-json-utils';
|
||||
import { JSONLiteral } from 'jsonc-eslint-parser/lib/parser/ast';
|
||||
|
||||
export type Options = [
|
||||
{
|
||||
@ -22,6 +26,7 @@ export type Options = [
|
||||
checkVersionMismatches?: boolean;
|
||||
checkMissingPackageJson?: boolean;
|
||||
ignoredDependencies?: string[];
|
||||
includeTransitiveDependencies?: boolean;
|
||||
}
|
||||
];
|
||||
|
||||
@ -51,6 +56,7 @@ export default createESLintRule<Options, MessageIds>({
|
||||
checkMissingDependencies: { type: 'boolean' },
|
||||
checkObsoleteDependencies: { type: 'boolean' },
|
||||
checkVersionMismatches: { type: 'boolean' },
|
||||
includeTransitiveDependencies: { type: 'boolean' },
|
||||
},
|
||||
additionalProperties: false,
|
||||
},
|
||||
@ -69,6 +75,7 @@ export default createESLintRule<Options, MessageIds>({
|
||||
checkObsoleteDependencies: true,
|
||||
checkVersionMismatches: true,
|
||||
ignoredDependencies: [],
|
||||
includeTransitiveDependencies: false,
|
||||
},
|
||||
],
|
||||
create(
|
||||
@ -80,6 +87,7 @@ export default createESLintRule<Options, MessageIds>({
|
||||
checkMissingDependencies,
|
||||
checkObsoleteDependencies,
|
||||
checkVersionMismatches,
|
||||
includeTransitiveDependencies,
|
||||
},
|
||||
]
|
||||
) {
|
||||
@ -92,8 +100,7 @@ export default createESLintRule<Options, MessageIds>({
|
||||
return {};
|
||||
}
|
||||
|
||||
const projectPath = normalizePath(globalThis.projectPath || workspaceRoot);
|
||||
const sourceFilePath = getSourceFilePath(fileName, projectPath);
|
||||
const sourceFilePath = getSourceFilePath(fileName, workspaceRoot);
|
||||
const { projectGraph, projectRootMappings, projectFileMap } =
|
||||
readProjectGraph(RULE_NAME);
|
||||
|
||||
@ -120,32 +127,19 @@ export default createESLintRule<Options, MessageIds>({
|
||||
return {};
|
||||
}
|
||||
|
||||
// gather helper dependencies for @nx/js executors
|
||||
const helperDependencies = getHelperDependenciesFromProjectGraph(
|
||||
workspaceRoot,
|
||||
sourceProject.name,
|
||||
projectGraph
|
||||
);
|
||||
|
||||
const rootPackageJson = getPackageJson(join(workspaceRoot, 'package.json'));
|
||||
|
||||
// find all dependencies for the project
|
||||
const npmDeps = findProjectsNpmDependencies(
|
||||
const npmDependencies = findNpmDependencies(
|
||||
workspaceRoot,
|
||||
sourceProject,
|
||||
projectGraph,
|
||||
buildTarget,
|
||||
rootPackageJson,
|
||||
projectFileMap,
|
||||
buildTarget, // TODO: What if child library has a build target different from the parent?
|
||||
{
|
||||
helperDependencies: helperDependencies.map((dep) => dep.target),
|
||||
isProduction: true,
|
||||
},
|
||||
removePackageJsonFromFileMap(projectFileMap)
|
||||
includeTransitiveDependencies,
|
||||
}
|
||||
);
|
||||
const projDependencies = {
|
||||
...npmDeps.dependencies,
|
||||
...npmDeps.peerDependencies,
|
||||
};
|
||||
const expectedDependencyNames = Object.keys(projDependencies);
|
||||
const expectedDependencyNames = Object.keys(npmDependencies);
|
||||
|
||||
const projPackageJsonPath = join(
|
||||
workspaceRoot,
|
||||
@ -180,7 +174,7 @@ export default createESLintRule<Options, MessageIds>({
|
||||
fix(fixer) {
|
||||
missingDeps.forEach((d) => {
|
||||
projPackageJsonDeps[d] =
|
||||
rootPackageJsonDeps[d] || projDependencies[d];
|
||||
rootPackageJsonDeps[d] || npmDependencies[d];
|
||||
});
|
||||
|
||||
const deps = (node.value as AST.JSONObjectExpression).properties;
|
||||
@ -213,8 +207,9 @@ export default createESLintRule<Options, MessageIds>({
|
||||
return;
|
||||
}
|
||||
if (
|
||||
projDependencies[packageName] === '*' ||
|
||||
satisfies(projDependencies[packageName], packageRange)
|
||||
npmDependencies[packageName] === '*' ||
|
||||
packageRange === '*' ||
|
||||
satisfies(npmDependencies[packageName], packageRange)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@ -224,13 +219,13 @@ export default createESLintRule<Options, MessageIds>({
|
||||
messageId: 'versionMismatch',
|
||||
data: {
|
||||
packageName: packageName,
|
||||
version: projDependencies[packageName],
|
||||
version: npmDependencies[packageName],
|
||||
},
|
||||
fix: (fixer) =>
|
||||
fixer.replaceText(
|
||||
node as any,
|
||||
`"${packageName}": "${
|
||||
rootPackageJsonDeps[packageName] || projDependencies[packageName]
|
||||
rootPackageJsonDeps[packageName] || npmDependencies[packageName]
|
||||
}"`
|
||||
),
|
||||
});
|
||||
@ -308,15 +303,15 @@ export default createESLintRule<Options, MessageIds>({
|
||||
.join(),
|
||||
},
|
||||
fix: (fixer) => {
|
||||
expectedDependencyNames.sort().reduce((acc, d) => {
|
||||
acc[d] = rootPackageJsonDeps[d] || projDependencies[d];
|
||||
return acc;
|
||||
}, projPackageJsonDeps);
|
||||
|
||||
const dependencies = Object.keys(projPackageJsonDeps)
|
||||
.map((d) => `\n "${d}": "${projPackageJsonDeps[d]}"`)
|
||||
.join(',');
|
||||
|
||||
expectedDependencyNames.sort().reduce((acc, d) => {
|
||||
acc[d] = rootPackageJsonDeps[d] || dependencies[d];
|
||||
return acc;
|
||||
}, projPackageJsonDeps);
|
||||
|
||||
if (!node.properties.length) {
|
||||
return fixer.replaceText(
|
||||
node as any,
|
||||
@ -337,7 +332,7 @@ export default createESLintRule<Options, MessageIds>({
|
||||
['JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=/^(dev|peer|optional)?dependencies$/i]'](
|
||||
node: AST.JSONProperty
|
||||
) {
|
||||
return validateMissingDependencies(node);
|
||||
validateMissingDependencies(node);
|
||||
},
|
||||
['JSONExpressionStatement > JSONObjectExpression > JSONProperty[key.value=/^(dev|peer|optional)?dependencies$/i] > JSONObjectExpression > JSONProperty'](
|
||||
node: AST.JSONProperty
|
||||
@ -350,19 +345,15 @@ export default createESLintRule<Options, MessageIds>({
|
||||
}
|
||||
|
||||
if (expectedDependencyNames.includes(packageName)) {
|
||||
return validateVersionMatchesInstalled(
|
||||
node,
|
||||
packageName,
|
||||
packageRange
|
||||
);
|
||||
validateVersionMatchesInstalled(node, packageName, packageRange);
|
||||
} else {
|
||||
return reportObsoleteDependency(node, packageName);
|
||||
reportObsoleteDependency(node, packageName);
|
||||
}
|
||||
},
|
||||
['JSONExpressionStatement > JSONObjectExpression'](
|
||||
node: AST.JSONObjectExpression
|
||||
) {
|
||||
return validateDependenciesSectionExistance(node);
|
||||
validateDependenciesSectionExistance(node);
|
||||
},
|
||||
};
|
||||
},
|
||||
|
||||
@ -9,6 +9,7 @@ export function getAllDependencies(
|
||||
...packageJson.dependencies,
|
||||
...packageJson.devDependencies,
|
||||
...packageJson.peerDependencies,
|
||||
...packageJson.optionalDependencies,
|
||||
};
|
||||
}
|
||||
|
||||
@ -18,15 +19,3 @@ export function getPackageJson(path: string): PackageJson {
|
||||
}
|
||||
return {} as PackageJson;
|
||||
}
|
||||
|
||||
export function removePackageJsonFromFileMap(
|
||||
projectFileMap: ProjectFileMap
|
||||
): ProjectFileMap {
|
||||
const newFileMap = {};
|
||||
Object.keys(projectFileMap).forEach((key) => {
|
||||
newFileMap[key] = projectFileMap[key].filter(
|
||||
(f) => !f.file.endsWith('/package.json')
|
||||
);
|
||||
});
|
||||
return newFileMap;
|
||||
}
|
||||
|
||||
400
packages/js/src/utils/find-npm-dependencies.spec.ts
Normal file
400
packages/js/src/utils/find-npm-dependencies.spec.ts
Normal file
@ -0,0 +1,400 @@
|
||||
import 'nx/src/utils/testing/mock-fs';
|
||||
import { vol } from 'memfs';
|
||||
import { findNpmDependencies } from './find-npm-dependencies';
|
||||
|
||||
jest.mock('@nx/devkit', () => ({
|
||||
...jest.requireActual<any>('@nx/devkit'),
|
||||
workspaceRoot: '/root',
|
||||
}));
|
||||
|
||||
jest.mock('nx/src/utils/workspace-root', () => ({
|
||||
workspaceRoot: '/root',
|
||||
}));
|
||||
|
||||
describe('findNpmDependencies', () => {
|
||||
const nxJson = {
|
||||
targetDefaults: {
|
||||
build: {
|
||||
inputs: [
|
||||
'{projectRoot}/**/*',
|
||||
'!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)',
|
||||
],
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
afterEach(() => {
|
||||
vol.reset();
|
||||
});
|
||||
|
||||
it('should pick up external npm dependencies and their versions', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./nx.json': JSON.stringify(nxJson),
|
||||
},
|
||||
'/root'
|
||||
);
|
||||
const libWithExternalDeps = {
|
||||
name: 'my-lib',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/my-lib',
|
||||
targets: { build: {} },
|
||||
},
|
||||
};
|
||||
const projectGraph = {
|
||||
nodes: {
|
||||
'my-lib': libWithExternalDeps,
|
||||
},
|
||||
externalNodes: {
|
||||
'npm:foo': {
|
||||
name: 'npm:foo' as const,
|
||||
type: 'npm' as const,
|
||||
data: {
|
||||
packageName: 'foo',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
dependencies: {},
|
||||
};
|
||||
const projectFileMap = {
|
||||
'my-lib': [
|
||||
{
|
||||
file: 'libs/my-lib/index.ts',
|
||||
hash: '123',
|
||||
deps: ['npm:foo'],
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const results = findNpmDependencies(
|
||||
'/root',
|
||||
libWithExternalDeps,
|
||||
projectGraph,
|
||||
projectFileMap,
|
||||
'build'
|
||||
);
|
||||
|
||||
expect(results).toEqual({
|
||||
foo: '1.0.0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should pick up helper npm dependencies if required', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./nx.json': JSON.stringify(nxJson),
|
||||
'./libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
compilerOptions: {
|
||||
importHelpers: true,
|
||||
},
|
||||
}),
|
||||
'./libs/my-lib/.swcrc': JSON.stringify({
|
||||
jsc: {
|
||||
externalHelpers: true,
|
||||
},
|
||||
}),
|
||||
},
|
||||
'/root'
|
||||
);
|
||||
const libWithHelpers = {
|
||||
name: 'my-lib',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/my-lib',
|
||||
targets: {
|
||||
build1: {
|
||||
executor: '@nx/js:tsc',
|
||||
options: {
|
||||
tsConfig: 'libs/my-lib/tsconfig.json',
|
||||
},
|
||||
},
|
||||
build2: {
|
||||
executor: '@nx/js:swc',
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const projectGraph = {
|
||||
nodes: {
|
||||
'my-lib': libWithHelpers,
|
||||
},
|
||||
externalNodes: {
|
||||
'npm:tslib': {
|
||||
name: 'npm:tslib' as const,
|
||||
type: 'npm' as const,
|
||||
data: {
|
||||
packageName: 'tslib',
|
||||
version: '2.6.0',
|
||||
},
|
||||
},
|
||||
'npm:@swc/helpers': {
|
||||
name: 'npm:@swc/helpers' as const,
|
||||
type: 'npm' as const,
|
||||
data: {
|
||||
packageName: '@swc/helpers',
|
||||
version: '0.5.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
dependencies: {},
|
||||
};
|
||||
const projectFileMap = {
|
||||
'my-lib': [],
|
||||
};
|
||||
|
||||
expect(
|
||||
findNpmDependencies(
|
||||
'/root',
|
||||
libWithHelpers,
|
||||
projectGraph,
|
||||
projectFileMap,
|
||||
'build1'
|
||||
)
|
||||
).toEqual({
|
||||
tslib: '2.6.0',
|
||||
});
|
||||
expect(
|
||||
findNpmDependencies(
|
||||
'/root',
|
||||
libWithHelpers,
|
||||
projectGraph,
|
||||
projectFileMap,
|
||||
'build2'
|
||||
)
|
||||
).toEqual({
|
||||
'@swc/helpers': '0.5.0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should not pick up helper npm dependencies if not required', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./libs/my-lib/tsconfig.json': JSON.stringify({
|
||||
compilerOptions: {
|
||||
importHelpers: false,
|
||||
},
|
||||
}),
|
||||
'./libs/my-lib/.swcrc': JSON.stringify({
|
||||
jsc: {
|
||||
externalHelpers: false,
|
||||
},
|
||||
}),
|
||||
},
|
||||
'/root'
|
||||
);
|
||||
const libWithInlinedHelpers = {
|
||||
name: 'my-lib',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/my-lib',
|
||||
targets: {
|
||||
build1: {
|
||||
executor: '@nx/js:tsc',
|
||||
options: {
|
||||
tsConfig: 'libs/my-lib/tsconfig.json',
|
||||
},
|
||||
},
|
||||
build2: {
|
||||
executor: '@nx/js:swc',
|
||||
options: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const projectGraph = {
|
||||
nodes: {
|
||||
'my-lib': libWithInlinedHelpers,
|
||||
},
|
||||
externalNodes: {
|
||||
'npm:tslib': {
|
||||
name: 'npm:tslib' as const,
|
||||
type: 'npm' as const,
|
||||
data: {
|
||||
packageName: 'tslib',
|
||||
version: '2.6.0',
|
||||
},
|
||||
},
|
||||
'npm:@swc/helpers': {
|
||||
name: 'npm:@swc/helpers' as const,
|
||||
type: 'npm' as const,
|
||||
data: {
|
||||
packageName: '@swc/helpers',
|
||||
version: '0.5.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
dependencies: {},
|
||||
};
|
||||
const projectFileMap = {
|
||||
'my-lib': [],
|
||||
};
|
||||
|
||||
const results = findNpmDependencies(
|
||||
'/root',
|
||||
libWithInlinedHelpers,
|
||||
projectGraph,
|
||||
projectFileMap,
|
||||
'build'
|
||||
);
|
||||
|
||||
expect(results).toEqual({});
|
||||
});
|
||||
|
||||
it('should support recursive collection of dependencies', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./nx.json': JSON.stringify(nxJson),
|
||||
},
|
||||
'/root'
|
||||
);
|
||||
const parentLib = {
|
||||
name: 'parent',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/parent',
|
||||
targets: { build: {} },
|
||||
},
|
||||
};
|
||||
const projectGraph = {
|
||||
nodes: {
|
||||
parent: parentLib,
|
||||
child1: {
|
||||
name: 'child1',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/child1',
|
||||
targets: { build: {} },
|
||||
},
|
||||
},
|
||||
child2: {
|
||||
name: 'child2',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/child2',
|
||||
targets: { build: {} },
|
||||
},
|
||||
},
|
||||
},
|
||||
externalNodes: {
|
||||
'npm:foo': {
|
||||
name: 'npm:foo' as const,
|
||||
type: 'npm' as const,
|
||||
data: {
|
||||
packageName: 'foo',
|
||||
version: '1.0.0',
|
||||
},
|
||||
},
|
||||
},
|
||||
dependencies: {
|
||||
parent: [
|
||||
{
|
||||
type: 'static',
|
||||
source: 'parent',
|
||||
target: 'child1',
|
||||
},
|
||||
],
|
||||
child1: [
|
||||
{
|
||||
type: 'static',
|
||||
source: 'child1',
|
||||
target: 'child2',
|
||||
},
|
||||
],
|
||||
child2: [
|
||||
{
|
||||
type: 'static',
|
||||
source: 'child2',
|
||||
target: 'npm:foo',
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
const projectFileMap = {
|
||||
parent: [{ file: 'libs/parent/index.ts', hash: '123', deps: ['child1'] }],
|
||||
child1: [{ file: 'libs/child1/index.ts', hash: '123', deps: ['child2'] }],
|
||||
child2: [
|
||||
{ file: 'libs/child2/index.ts', hash: '123', deps: ['npm:foo'] },
|
||||
],
|
||||
};
|
||||
|
||||
const results = findNpmDependencies(
|
||||
'/root',
|
||||
parentLib,
|
||||
projectGraph,
|
||||
projectFileMap,
|
||||
'build',
|
||||
{
|
||||
includeTransitiveDependencies: true,
|
||||
}
|
||||
);
|
||||
|
||||
expect(results).toEqual({
|
||||
foo: '1.0.0',
|
||||
});
|
||||
});
|
||||
|
||||
it('should find workspace dependencies', () => {
|
||||
vol.fromJSON(
|
||||
{
|
||||
'./libs/lib3/package.json': JSON.stringify({
|
||||
name: '@acme/lib3',
|
||||
version: '0.0.1',
|
||||
}),
|
||||
'./nx.json': JSON.stringify(nxJson),
|
||||
},
|
||||
'/root'
|
||||
);
|
||||
const lib1 = {
|
||||
name: 'lib1',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/lib1',
|
||||
targets: { build: {} },
|
||||
},
|
||||
};
|
||||
const lib2 = {
|
||||
name: 'lib2',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/lib2',
|
||||
targets: { build: {} },
|
||||
},
|
||||
};
|
||||
const lib3 = {
|
||||
name: 'lib3',
|
||||
type: 'lib' as const,
|
||||
data: {
|
||||
root: 'libs/lib3',
|
||||
targets: { build: {} },
|
||||
},
|
||||
};
|
||||
const projectGraph = {
|
||||
nodes: {
|
||||
lib1: lib1,
|
||||
lib2: lib2,
|
||||
lib3: lib3,
|
||||
},
|
||||
externalNodes: {},
|
||||
dependencies: {},
|
||||
};
|
||||
const projectFileMap = {
|
||||
lib1: [{ file: 'libs/lib1/index.ts', hash: '123', deps: ['lib3'] }],
|
||||
lib2: [{ file: 'libs/lib1/index.ts', hash: '123', deps: ['lib3'] }],
|
||||
lib3: [],
|
||||
};
|
||||
|
||||
expect(
|
||||
findNpmDependencies('/root', lib1, projectGraph, projectFileMap, 'build')
|
||||
).toEqual({
|
||||
'@acme/lib3': '*',
|
||||
});
|
||||
expect(
|
||||
findNpmDependencies('/root', lib2, projectGraph, projectFileMap, 'build')
|
||||
).toEqual({
|
||||
'@acme/lib3': '*',
|
||||
});
|
||||
});
|
||||
});
|
||||
191
packages/js/src/utils/find-npm-dependencies.ts
Normal file
191
packages/js/src/utils/find-npm-dependencies.ts
Normal file
@ -0,0 +1,191 @@
|
||||
import { join } from 'path';
|
||||
import { readNxJson } from 'nx/src/project-graph/file-utils';
|
||||
import {
|
||||
getTargetInputs,
|
||||
filterUsingGlobPatterns,
|
||||
} from 'nx/src/hasher/task-hasher';
|
||||
import {
|
||||
type ProjectGraph,
|
||||
type ProjectGraphProjectNode,
|
||||
type ProjectFileMap,
|
||||
readJsonFile,
|
||||
FileData,
|
||||
joinPathFragments,
|
||||
} from '@nx/devkit';
|
||||
import { fileExists } from 'nx/src/utils/fileutils';
|
||||
import { fileDataDepTarget } from 'nx/src/config/project-graph';
|
||||
import { readTsConfig } from './typescript/ts-config';
|
||||
|
||||
/**
|
||||
* Finds all npm dependencies and their expected versions for a given project.
|
||||
*/
|
||||
export function findNpmDependencies(
|
||||
workspaceRoot: string,
|
||||
sourceProject: ProjectGraphProjectNode,
|
||||
projectGraph: ProjectGraph,
|
||||
projectFileMap: ProjectFileMap,
|
||||
buildTarget: string,
|
||||
options: {
|
||||
includeTransitiveDependencies?: boolean;
|
||||
} = {}
|
||||
): Record<string, string> {
|
||||
let seen: null | Set<string> = null;
|
||||
if (options.includeTransitiveDependencies) {
|
||||
seen = new Set<string>();
|
||||
}
|
||||
|
||||
const results: Record<string, string> = {};
|
||||
|
||||
function collectAll(
|
||||
currentProject: ProjectGraphProjectNode,
|
||||
collectedDeps: Record<string, string>
|
||||
): void {
|
||||
if (seen?.has(currentProject.name)) return;
|
||||
|
||||
collectDependenciesFromFileMap(
|
||||
workspaceRoot,
|
||||
currentProject,
|
||||
projectGraph,
|
||||
projectFileMap,
|
||||
buildTarget,
|
||||
collectedDeps
|
||||
);
|
||||
|
||||
collectHelperDependencies(
|
||||
workspaceRoot,
|
||||
currentProject,
|
||||
projectGraph,
|
||||
buildTarget,
|
||||
collectedDeps
|
||||
);
|
||||
|
||||
if (options.includeTransitiveDependencies) {
|
||||
const projectDeps = projectGraph.dependencies[currentProject.name];
|
||||
for (const dep of projectDeps) {
|
||||
const projectDep = projectGraph.nodes[dep.target];
|
||||
if (projectDep) collectAll(projectDep, collectedDeps);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
collectAll(sourceProject, results);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
// Keep track of workspace libs we already read package.json for so we don't read from disk again.
|
||||
const seenWorkspaceDeps: Record<string, { name: string; version: string }> = {};
|
||||
|
||||
function collectDependenciesFromFileMap(
|
||||
workspaceRoot: string,
|
||||
sourceProject: ProjectGraphProjectNode,
|
||||
projectGraph: ProjectGraph,
|
||||
projectFileMap: ProjectFileMap,
|
||||
buildTarget: string,
|
||||
npmDeps: Record<string, string>
|
||||
): void {
|
||||
const rawFiles = projectFileMap[sourceProject.name];
|
||||
if (!rawFiles) return;
|
||||
|
||||
// Cannot read inputs if the target does not exist on the project.
|
||||
if (!sourceProject.data.targets[buildTarget]) return;
|
||||
|
||||
const inputs = getTargetInputs(
|
||||
readNxJson(),
|
||||
sourceProject,
|
||||
buildTarget
|
||||
).selfInputs;
|
||||
const files = filterUsingGlobPatterns(
|
||||
sourceProject.data.root,
|
||||
projectFileMap[sourceProject.name] || [],
|
||||
inputs
|
||||
);
|
||||
|
||||
for (const fileData of files) {
|
||||
if (
|
||||
!fileData.deps ||
|
||||
fileData.file ===
|
||||
joinPathFragments(sourceProject.data.root, 'package.json')
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const dep of fileData.deps) {
|
||||
const target = fileDataDepTarget(dep);
|
||||
|
||||
// If the node is external, then read package info from `data`.
|
||||
const externalDep = projectGraph.externalNodes[target];
|
||||
if (externalDep?.type === 'npm') {
|
||||
npmDeps[externalDep.data.packageName] = externalDep.data.version;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If node is internal, then try reading package info from `package.json` (which must exist for this to work).
|
||||
const workspaceDep = projectGraph.nodes[target];
|
||||
if (!workspaceDep) continue;
|
||||
const cached = seenWorkspaceDeps[workspaceDep.name];
|
||||
if (cached) {
|
||||
npmDeps[cached.name] = cached.version;
|
||||
} else {
|
||||
const packageJson = readPackageJson(workspaceDep, workspaceRoot);
|
||||
if (packageJson) {
|
||||
// This is a workspace lib so we can't reliably read in a specific version since it depends on how the workspace is set up.
|
||||
// ASSUMPTION: Most users will use '*' for workspace lib versions. Otherwise, they can manually update it.
|
||||
npmDeps[packageJson.name] = '*';
|
||||
seenWorkspaceDeps[workspaceDep.name] = {
|
||||
name: packageJson.name,
|
||||
version: '*',
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function readPackageJson(
|
||||
project: ProjectGraphProjectNode,
|
||||
workspaceRoot: string
|
||||
): null | {
|
||||
name: string;
|
||||
dependencies?: Record<string, string>;
|
||||
optionalDependencies?: Record<string, string>;
|
||||
peerDependencies?: Record<string, string>;
|
||||
} {
|
||||
const packageJsonPath = join(
|
||||
workspaceRoot,
|
||||
project.data.root,
|
||||
'package.json'
|
||||
);
|
||||
if (fileExists(packageJsonPath)) return readJsonFile(packageJsonPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
function collectHelperDependencies(
|
||||
workspaceRoot: string,
|
||||
sourceProject: ProjectGraphProjectNode,
|
||||
projectGraph: ProjectGraph,
|
||||
buildTarget: string,
|
||||
npmDeps: Record<string, string>
|
||||
): void {
|
||||
const target = sourceProject.data.targets[buildTarget];
|
||||
if (!target) return;
|
||||
|
||||
if (target.executor === '@nx/js:tsc' && target.options?.tsConfig) {
|
||||
const tsConfig = readTsConfig(join(workspaceRoot, target.options.tsConfig));
|
||||
if (tsConfig?.options['importHelpers']) {
|
||||
npmDeps['tslib'] = projectGraph.externalNodes['npm:tslib']?.data.version;
|
||||
}
|
||||
}
|
||||
if (target.executor === '@nx/js:swc') {
|
||||
const swcConfigPath = target.options.swcrc
|
||||
? join(workspaceRoot, target.options.swcrc)
|
||||
: join(workspaceRoot, sourceProject.data.root, '.swcrc');
|
||||
const swcConfig = fileExists(swcConfigPath)
|
||||
? readJsonFile(swcConfigPath)
|
||||
: {};
|
||||
if (swcConfig?.jsc?.externalHelpers) {
|
||||
npmDeps['@swc/helpers'] =
|
||||
projectGraph.externalNodes['npm:@swc/helpers']?.data.version;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user