Skip to content

Commit 90ca436

Browse files
authored
feat(linter): add option to ignore files based on pattern (#18863)
1 parent 29850b0 commit 90ca436

File tree

6 files changed

+282
-15
lines changed

6 files changed

+282
-15
lines changed

packages/eslint-plugin/src/rules/dependency-checks.spec.ts

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,75 @@ describe('Dependency checks (eslint)', () => {
202202
expect(failures.length).toEqual(0);
203203
});
204204

205+
it('should exclude files that are ignored', () => {
206+
const packageJson = {
207+
name: '@mycompany/liba',
208+
dependencies: {},
209+
};
210+
211+
const fileSys = {
212+
'./libs/liba/package.json': JSON.stringify(packageJson, null, 2),
213+
'./libs/liba/vite.config.ts': '',
214+
'./libs/liba/project.json': JSON.stringify(
215+
{
216+
name: 'liba',
217+
targets: {
218+
build: {
219+
command: 'tsc -p tsconfig.lib.json',
220+
},
221+
},
222+
},
223+
null,
224+
2
225+
),
226+
'./nx.json': JSON.stringify({
227+
targetDefaults: {
228+
build: {
229+
inputs: [
230+
'{projectRoot}/**/*',
231+
'!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)',
232+
],
233+
},
234+
},
235+
}),
236+
'./package.json': JSON.stringify(rootPackageJson, null, 2),
237+
};
238+
vol.fromJSON(fileSys, '/root');
239+
240+
const failures = runRule(
241+
{
242+
ignoredFiles: ['{projectRoot}/vite.config.ts'],
243+
},
244+
`/root/libs/liba/package.json`,
245+
JSON.stringify(packageJson, null, 2),
246+
{
247+
nodes: {
248+
liba: {
249+
name: 'liba',
250+
type: 'lib',
251+
data: {
252+
root: 'libs/liba',
253+
targets: {
254+
build: {},
255+
},
256+
},
257+
},
258+
},
259+
externalNodes,
260+
dependencies: {
261+
liba: [{ source: 'liba', target: 'npm:external1', type: 'static' }],
262+
},
263+
},
264+
{
265+
liba: [
266+
createFile(`libs/liba/vite.config.ts`, ['npm:external1']),
267+
createFile(`libs/liba/package.json`, []),
268+
],
269+
}
270+
);
271+
expect(failures.length).toEqual(0);
272+
});
273+
205274
it('should report missing dependencies section and fix it', () => {
206275
const packageJson = {
207276
name: '@mycompany/liba',

packages/eslint-plugin/src/rules/dependency-checks.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export type Options = [
2222
checkVersionMismatches?: boolean;
2323
checkMissingPackageJson?: boolean;
2424
ignoredDependencies?: string[];
25+
ignoredFiles?: string[];
2526
includeTransitiveDependencies?: boolean;
2627
}
2728
];
@@ -49,6 +50,7 @@ export default createESLintRule<Options, MessageIds>({
4950
properties: {
5051
buildTargets: [{ type: 'string' }],
5152
ignoredDependencies: [{ type: 'string' }],
53+
ignoredFiles: [{ type: 'string' }],
5254
checkMissingDependencies: { type: 'boolean' },
5355
checkObsoleteDependencies: { type: 'boolean' },
5456
checkVersionMismatches: { type: 'boolean' },
@@ -71,6 +73,7 @@ export default createESLintRule<Options, MessageIds>({
7173
checkObsoleteDependencies: true,
7274
checkVersionMismatches: true,
7375
ignoredDependencies: [],
76+
ignoredFiles: [],
7477
includeTransitiveDependencies: false,
7578
},
7679
],
@@ -80,6 +83,7 @@ export default createESLintRule<Options, MessageIds>({
8083
{
8184
buildTargets,
8285
ignoredDependencies,
86+
ignoredFiles,
8387
checkMissingDependencies,
8488
checkObsoleteDependencies,
8589
checkVersionMismatches,
@@ -133,6 +137,7 @@ export default createESLintRule<Options, MessageIds>({
133137
buildTarget, // TODO: What if child library has a build target different from the parent?
134138
{
135139
includeTransitiveDependencies,
140+
ignoredFiles,
136141
}
137142
);
138143
const expectedDependencyNames = Object.keys(npmDependencies);

packages/js/src/generators/library/library.spec.ts

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,20 @@ describe('lib', () => {
11371137
executor: '@nx/vite:test',
11381138
});
11391139
expect(tree.exists('libs/my-lib/vite.config.ts')).toBeTruthy();
1140+
expect(
1141+
readJson(tree, 'libs/my-lib/.eslintrc.json').overrides
1142+
).toContainEqual({
1143+
files: ['*.json'],
1144+
parser: 'jsonc-eslint-parser',
1145+
rules: {
1146+
'@nx/dependency-checks': [
1147+
'error',
1148+
{
1149+
ignoredFiles: ['{projectRoot}/vite.config.{js,ts,mjs,mts}'],
1150+
},
1151+
],
1152+
},
1153+
});
11401154
});
11411155

11421156
it.each`
@@ -1159,6 +1173,66 @@ describe('lib', () => {
11591173
);
11601174
});
11611175

1176+
describe('--bundler=esbuild', () => {
1177+
it('should add build with esbuild', async () => {
1178+
await libraryGenerator(tree, {
1179+
...defaultOptions,
1180+
name: 'myLib',
1181+
bundler: 'esbuild',
1182+
unitTestRunner: 'none',
1183+
});
1184+
1185+
const project = readProjectConfiguration(tree, 'my-lib');
1186+
expect(project.targets.build).toMatchObject({
1187+
executor: '@nx/esbuild:esbuild',
1188+
});
1189+
expect(
1190+
readJson(tree, 'libs/my-lib/.eslintrc.json').overrides
1191+
).toContainEqual({
1192+
files: ['*.json'],
1193+
parser: 'jsonc-eslint-parser',
1194+
rules: {
1195+
'@nx/dependency-checks': [
1196+
'error',
1197+
{
1198+
ignoredFiles: ['{projectRoot}/esbuild.config.{js,ts,mjs,mts}'],
1199+
},
1200+
],
1201+
},
1202+
});
1203+
});
1204+
});
1205+
1206+
describe('--bundler=rollup', () => {
1207+
it('should add build with rollup', async () => {
1208+
await libraryGenerator(tree, {
1209+
...defaultOptions,
1210+
name: 'myLib',
1211+
bundler: 'rollup',
1212+
unitTestRunner: 'none',
1213+
});
1214+
1215+
const project = readProjectConfiguration(tree, 'my-lib');
1216+
expect(project.targets.build).toMatchObject({
1217+
executor: '@nx/rollup:rollup',
1218+
});
1219+
expect(
1220+
readJson(tree, 'libs/my-lib/.eslintrc.json').overrides
1221+
).toContainEqual({
1222+
files: ['*.json'],
1223+
parser: 'jsonc-eslint-parser',
1224+
rules: {
1225+
'@nx/dependency-checks': [
1226+
'error',
1227+
{
1228+
ignoredFiles: ['{projectRoot}/rollup.config.{js,ts,mjs,mts}'],
1229+
},
1230+
],
1231+
},
1232+
});
1233+
});
1234+
});
1235+
11621236
describe('--minimal', () => {
11631237
it('should generate a README.md when minimal is set to false', async () => {
11641238
await libraryGenerator(tree, {

packages/js/src/generators/library/library.ts

Lines changed: 61 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
names,
1111
offsetFromRoot,
1212
ProjectConfiguration,
13+
readProjectConfiguration,
1314
runTasksInSerial,
1415
toJS,
1516
Tree,
@@ -236,12 +237,14 @@ export type AddLintOptions = Pick<
236237
| 'js'
237238
| 'setParserOptionsProject'
238239
| 'rootProject'
240+
| 'bundler'
239241
>;
240242
export async function addLint(
241243
tree: Tree,
242244
options: AddLintOptions
243245
): Promise<GeneratorCallback> {
244246
const { lintProjectGenerator } = ensurePackage('@nx/linter', nxVersion);
247+
const projectConfiguration = readProjectConfiguration(tree, options.name);
245248
const task = lintProjectGenerator(tree, {
246249
project: options.name,
247250
linter: options.linter,
@@ -256,15 +259,17 @@ export async function addLint(
256259
setParserOptionsProject: options.setParserOptionsProject,
257260
rootProject: options.rootProject,
258261
});
262+
const {
263+
addOverrideToLintConfig,
264+
lintConfigHasOverride,
265+
isEslintConfigSupported,
266+
updateOverrideInLintConfig,
267+
// nx-ignore-next-line
268+
} = require('@nx/linter/src/generators/utils/eslint-file');
269+
259270
// Also update the root ESLint config. The lintProjectGenerator will not generate it for root projects.
260271
// But we need to set the package.json checks.
261272
if (options.rootProject) {
262-
const {
263-
addOverrideToLintConfig,
264-
isEslintConfigSupported,
265-
// nx-ignore-next-line
266-
} = require('@nx/linter/src/generators/utils/eslint-file');
267-
268273
if (isEslintConfigSupported(tree)) {
269274
addOverrideToLintConfig(tree, '', {
270275
files: ['*.json'],
@@ -275,6 +280,56 @@ export async function addLint(
275280
});
276281
}
277282
}
283+
284+
// If project lints package.json with @nx/dependency-checks, then add ignore files for
285+
// build configuration files such as vite.config.ts. These config files need to be
286+
// ignored, otherwise we will errors on missing dependencies that are for dev only.
287+
if (
288+
lintConfigHasOverride(
289+
tree,
290+
projectConfiguration.root,
291+
(o) =>
292+
Array.isArray(o.files)
293+
? o.files.some((f) => f.match(/\.json$/))
294+
: !!o.files?.match(/\.json$/),
295+
true
296+
)
297+
) {
298+
updateOverrideInLintConfig(
299+
tree,
300+
projectConfiguration.root,
301+
(o) => o.rules?.['@nx/dependency-checks'],
302+
(o) => {
303+
const value = o.rules['@nx/dependency-checks'];
304+
let ruleSeverity: string;
305+
let ruleOptions: any;
306+
if (Array.isArray(value)) {
307+
ruleSeverity = value[0];
308+
ruleOptions = value[1];
309+
} else {
310+
ruleSeverity = value;
311+
ruleOptions = {};
312+
}
313+
if (options.bundler === 'vite' || options.unitTestRunner === 'vitest') {
314+
ruleOptions.ignoredFiles = [
315+
'{projectRoot}/vite.config.{js,ts,mjs,mts}',
316+
];
317+
o.rules['@nx/dependency-checks'] = [ruleSeverity, ruleOptions];
318+
} else if (options.bundler === 'rollup') {
319+
ruleOptions.ignoredFiles = [
320+
'{projectRoot}/rollup.config.{js,ts,mjs,mts}',
321+
];
322+
o.rules['@nx/dependency-checks'] = [ruleSeverity, ruleOptions];
323+
} else if (options.bundler === 'esbuild') {
324+
ruleOptions.ignoredFiles = [
325+
'{projectRoot}/esbuild.config.{js,ts,mjs,mts}',
326+
];
327+
o.rules['@nx/dependency-checks'] = [ruleSeverity, ruleOptions];
328+
}
329+
return o;
330+
}
331+
);
332+
}
278333
return task;
279334
}
280335

packages/js/src/utils/find-npm-dependencies.spec.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -397,4 +397,57 @@ describe('findNpmDependencies', () => {
397397
'@acme/lib3': '*',
398398
});
399399
});
400+
401+
it('should support ignoring extra file patterns in addition to task input', () => {
402+
vol.fromJSON(
403+
{
404+
'./nx.json': JSON.stringify(nxJson),
405+
},
406+
'/root'
407+
);
408+
const lib = {
409+
name: 'my-lib',
410+
type: 'lib' as const,
411+
data: {
412+
root: 'libs/my-lib',
413+
targets: { build: {} },
414+
},
415+
};
416+
const projectGraph = {
417+
nodes: {
418+
'my-lib': lib,
419+
},
420+
externalNodes: {
421+
'npm:foo': {
422+
name: 'npm:foo' as const,
423+
type: 'npm' as const,
424+
data: {
425+
packageName: 'foo',
426+
version: '1.0.0',
427+
},
428+
},
429+
},
430+
dependencies: {},
431+
};
432+
const projectFileMap = {
433+
'my-lib': [
434+
{
435+
file: 'libs/my-lib/vite.config.ts',
436+
hash: '123',
437+
deps: ['npm:foo'],
438+
},
439+
],
440+
};
441+
442+
const results = findNpmDependencies(
443+
'/root',
444+
lib,
445+
projectGraph,
446+
projectFileMap,
447+
'build',
448+
{ ignoredFiles: ['{projectRoot}/vite.config.ts'] }
449+
);
450+
451+
expect(results).toEqual({});
452+
});
400453
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy