1
- import type { BuilderContext , BuilderOutput } from '@angular-devkit/architect' ;
2
- import { createBuilder } from '@angular-devkit/architect ' ;
1
+ import type { BuilderOutput } from '@angular-devkit/architect' ;
2
+ import { convertNxExecutor } from '@nx/devkit ' ;
3
3
import type { ESLint } from 'eslint' ;
4
- import { writeFileSync } from 'fs' ;
4
+ import { mkdirSync , writeFileSync } from 'fs' ;
5
5
import { dirname , join , resolve } from 'path' ;
6
6
import type { Schema } from './schema' ;
7
- import { createDirectory } from './utils/create-directory' ;
8
7
import { lint , loadESLint } from './utils/eslint-utils' ;
9
8
10
- export default createBuilder (
11
- async ( options : Schema , context : BuilderContext ) : Promise < BuilderOutput > => {
12
- const workspaceRoot = context . workspaceRoot ;
13
- process . chdir ( workspaceRoot ) ;
9
+ export default convertNxExecutor (
10
+ async ( options : Schema , context ) : Promise < BuilderOutput > => {
11
+ const systemRoot = context . root ;
14
12
15
- const projectName = context . target ?. project || '<???>' ;
13
+ // eslint resolves files relative to the current working directory.
14
+ // We want these paths to always be resolved relative to the workspace
15
+ // root to be able to run the lint executor from any subfolder.
16
+ process . chdir ( systemRoot ) ;
17
+
18
+ const projectName = context . projectName || '<???>' ;
16
19
const printInfo = options . format && ! options . silent ;
17
- const reportOnlyErrors = options . quiet ;
18
- const maxWarnings = options . maxWarnings ;
19
20
20
21
if ( printInfo ) {
21
22
console . info ( `\nLinting ${ JSON . stringify ( projectName ) } ...` ) ;
22
23
}
23
24
24
- const projectESLint = await loadESLint ( ) ;
25
+ const projectESLint : { ESLint : typeof ESLint } = await loadESLint ( ) ;
25
26
const version = projectESLint . ESLint ?. version ?. split ( '.' ) ;
26
27
if (
27
28
! version ||
@@ -36,16 +37,20 @@ export default createBuilder(
36
37
37
38
/**
38
39
* We want users to have the option of not specifying the config path, and let
39
- * eslint automatically resolve the `.eslintrc` files in each folder.
40
+ * eslint automatically resolve the `.eslintrc.json ` files in each folder.
40
41
*/
41
42
const eslintConfigPath = options . eslintConfig
42
- ? resolve ( workspaceRoot , options . eslintConfig )
43
+ ? resolve ( systemRoot , options . eslintConfig )
43
44
: undefined ;
44
45
46
+ options . cacheLocation = options . cacheLocation
47
+ ? join ( options . cacheLocation , projectName )
48
+ : null ;
49
+
45
50
let lintResults : ESLint . LintResult [ ] = [ ] ;
46
51
47
52
try {
48
- lintResults = await lint ( workspaceRoot , eslintConfigPath , options ) ;
53
+ lintResults = await lint ( eslintConfigPath , options ) ;
49
54
} catch ( err ) {
50
55
if (
51
56
err instanceof Error &&
@@ -54,19 +59,18 @@ export default createBuilder(
54
59
)
55
60
) {
56
61
let eslintConfigPathForError = `for ${ projectName } ` ;
57
-
58
- const projectMetadata = await context . getProjectMetadata ( projectName ) ;
59
- if ( projectMetadata ) {
60
- eslintConfigPathForError = `\`${ projectMetadata . root } /.eslintrc.json\`` ;
62
+ if ( context . projectsConfigurations ?. projects ?. [ projectName ] ?. root ) {
63
+ const { root } = context . projectsConfigurations . projects [ projectName ] ;
64
+ eslintConfigPathForError = `\`${ root } /.eslintrc.json\`` ;
61
65
}
62
66
63
67
console . error ( `
64
- Error: You have attempted to use a lint rule which requires the full TypeScript type-checker to be available, but you do not have \`parserOptions.project\` configured to point at your project tsconfig.json files in the relevant TypeScript file "overrides" block of your ESLint config ${
65
- eslintConfigPath || eslintConfigPathForError
66
- }
67
-
68
- For full guidance on how to resolve this issue, please see https://github.com/angular-eslint/angular-eslint/blob/main/docs/RULES_REQUIRING_TYPE_INFORMATION.md
69
- `) ;
68
+ Error: You have attempted to use a lint rule which requires the full TypeScript type-checker to be available, but you do not have \`parserOptions.project\` configured to point at your project tsconfig.json files in the relevant TypeScript file "overrides" block of your project ESLint config ${
69
+ eslintConfigPath || eslintConfigPathForError
70
+ }
71
+
72
+ For full guidance on how to resolve this issue, please see https://github.com/angular-eslint/angular-eslint/blob/main/docs/RULES_REQUIRING_TYPE_INFORMATION.md
73
+ ` ) ;
70
74
71
75
return {
72
76
success : false ,
@@ -77,16 +81,37 @@ export default createBuilder(
77
81
}
78
82
79
83
if ( lintResults . length === 0 ) {
80
- throw new Error ( 'Invalid lint configuration. Nothing to lint.' ) ;
84
+ const ignoredPatterns = (
85
+ await Promise . all (
86
+ options . lintFilePatterns . map ( async ( pattern ) =>
87
+ ( await eslint . isPathIgnored ( pattern ) ) ? pattern : null ,
88
+ ) ,
89
+ )
90
+ )
91
+ . filter ( ( pattern ) => ! ! pattern )
92
+ . map ( ( pattern ) => `- '${ pattern } '` ) ;
93
+ if ( ignoredPatterns . length ) {
94
+ throw new Error (
95
+ `All files matching the following patterns are ignored:\n${ ignoredPatterns . join (
96
+ '\n' ,
97
+ ) } \n\nPlease check your '.eslintignore' file.`,
98
+ ) ;
99
+ }
100
+ throw new Error (
101
+ 'Invalid lint configuration. Nothing to lint. Please check your lint target pattern(s).' ,
102
+ ) ;
81
103
}
82
104
105
+ // output fixes to disk, if applicable based on the options
106
+ await projectESLint . ESLint . outputFixes ( lintResults ) ;
107
+
83
108
const formatter = await eslint . loadFormatter ( options . format ) ;
84
109
85
110
let totalErrors = 0 ;
86
111
let totalWarnings = 0 ;
87
112
88
- // output fixes to disk, if applicable based on the options
89
- await projectESLint . ESLint . outputFixes ( lintResults ) ;
113
+ const reportOnlyErrors = options . quiet ;
114
+ const maxWarnings = options . maxWarnings ;
90
115
91
116
/**
92
117
* Depending on user configuration we may not want to report on all the
@@ -128,8 +153,8 @@ export default createBuilder(
128
153
const formattedResults = await formatter . format ( finalLintResults ) ;
129
154
130
155
if ( options . outputFile ) {
131
- const pathToOutputFile = join ( context . workspaceRoot , options . outputFile ) ;
132
- createDirectory ( dirname ( pathToOutputFile ) ) ;
156
+ const pathToOutputFile = join ( context . root , options . outputFile ) ;
157
+ mkdirSync ( dirname ( pathToOutputFile ) , { recursive : true } ) ;
133
158
writeFileSync ( pathToOutputFile , formattedResults ) ;
134
159
} else {
135
160
console . info ( formattedResults ) ;
0 commit comments