-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
cleanup(angular): add @angular-eslint/builder:lint builder migrator (#…
- Loading branch information
1 parent
f12186a
commit 2a671e7
Showing
9 changed files
with
252 additions
and
330 deletions.
There are no files selected for viewing
208 changes: 208 additions & 0 deletions
208
packages/angular/src/generators/ng-add/migrators/builders/angular-eslint-lint.migrator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
import { | ||
ProjectConfiguration, | ||
TargetConfiguration, | ||
Tree, | ||
updateJson, | ||
} from '@nrwl/devkit'; | ||
import { | ||
joinPathFragments, | ||
offsetFromRoot, | ||
readJson, | ||
updateProjectConfiguration, | ||
} from '@nrwl/devkit'; | ||
import { hasRulesRequiringTypeChecking } from '@nrwl/linter'; | ||
import { dirname } from 'path'; | ||
import type { | ||
Logger, | ||
ProjectMigrationInfo, | ||
ValidationError, | ||
ValidationResult, | ||
} from '../../utilities'; | ||
import { arrayToString } from '../../utilities'; | ||
import { BuilderMigrator } from './builder.migrator'; | ||
|
||
export class AngularEslintLintMigrator extends BuilderMigrator { | ||
private oldEsLintConfigPath: string; | ||
private newEsLintConfigPath: string; | ||
|
||
constructor( | ||
tree: Tree, | ||
project: ProjectMigrationInfo, | ||
projectConfig: ProjectConfiguration, | ||
logger: Logger | ||
) { | ||
super( | ||
tree, | ||
'@angular-eslint/builder:lint', | ||
'eslint', | ||
project, | ||
projectConfig, | ||
logger | ||
); | ||
} | ||
|
||
override migrate(): void { | ||
for (const [name, target] of this.targets) { | ||
this.oldEsLintConfigPath = | ||
target.options?.eslintConfig ?? | ||
joinPathFragments(this.project.oldRoot, '.eslintrc.json'); | ||
this.newEsLintConfigPath = this.convertRootPath(this.oldEsLintConfigPath); | ||
|
||
this.moveProjectRootFile(this.oldEsLintConfigPath); | ||
this.updateTargetConfiguration(name, target); | ||
this.updateEsLintConfig(); | ||
this.updateCacheableOperations([name]); | ||
} | ||
|
||
if (!this.targets.size && this.projectConfig.root === '') { | ||
// there could still be a .eslintrc.json file in the root | ||
// so move to new location | ||
const eslintConfig = '.eslintrc.json'; | ||
if (this.tree.exists(eslintConfig)) { | ||
this.logger.info( | ||
'No "lint" target was found, but an ESLint config file was found in the project root. The file will be moved to the new location.' | ||
); | ||
this.moveProjectRootFile(eslintConfig); | ||
} | ||
} | ||
} | ||
|
||
override validate(): ValidationResult { | ||
const errors: ValidationError[] = []; | ||
// TODO(leo): keeping restriction until the full refactor is done and we start | ||
// expanding what's supported. | ||
if (this.targets.size > 1) { | ||
errors.push({ | ||
message: `There is more than one target using a builder that is used to lint the project (${arrayToString( | ||
[...this.targets.keys()] | ||
)}).`, | ||
hint: `Make sure the project only has one target with a builder that is used to lint the project.`, | ||
}); | ||
} | ||
|
||
return errors.length ? errors : null; | ||
} | ||
|
||
private async updateTargetConfiguration( | ||
targetName: string, | ||
target: TargetConfiguration | ||
): Promise<void> { | ||
target.executor = '@nrwl/linter:eslint'; | ||
|
||
if (!target.options) { | ||
this.logger.warn( | ||
`The target "${targetName}" is not specifying any options. Skipping updating the target configuration.` | ||
); | ||
return; | ||
} | ||
|
||
const existEsLintConfigPath = this.tree.exists(this.newEsLintConfigPath); | ||
if (!existEsLintConfigPath) { | ||
this.logger.warn( | ||
`The ESLint config file "${this.oldEsLintConfigPath}" could not be found. Skipping updating the file.` | ||
); | ||
} | ||
|
||
target.options.eslintConfig = | ||
target.options.eslintConfig && this.newEsLintConfigPath; | ||
target.options.lintFilePatterns = | ||
target.options.lintFilePatterns && | ||
target.options.lintFilePatterns.map((pattern) => { | ||
// replace the old source root with the new root, we want to lint all | ||
// matching files in the project, not just the ones in the source root | ||
if (pattern.startsWith(this.project.oldSourceRoot)) { | ||
return joinPathFragments( | ||
this.project.newRoot, | ||
pattern.replace(this.project.oldSourceRoot, '') | ||
); | ||
} | ||
|
||
// replace the old root with the new root | ||
if (pattern.startsWith(this.project.oldRoot)) { | ||
return joinPathFragments( | ||
this.project.newRoot, | ||
pattern.replace(this.project.oldRoot, '') | ||
); | ||
} | ||
|
||
// do nothing, warn about the pattern | ||
this.logger.warn( | ||
`The lint file pattern "${pattern}" specified in the "${targetName}" target is not contained in the project root or source root. The pattern will not be updated.` | ||
); | ||
|
||
return pattern; | ||
}); | ||
|
||
if (existEsLintConfigPath) { | ||
const eslintConfig = readJson(this.tree, this.newEsLintConfigPath); | ||
if (hasRulesRequiringTypeChecking(eslintConfig)) { | ||
target.options.hasTypeAwareRules = true; | ||
} | ||
} | ||
|
||
updateProjectConfiguration(this.tree, this.project.name, { | ||
...this.projectConfig, | ||
}); | ||
} | ||
|
||
private updateEsLintConfig(): void { | ||
if (!this.tree.exists(this.newEsLintConfigPath)) { | ||
return; | ||
} | ||
|
||
updateJson(this.tree, this.newEsLintConfigPath, (json) => { | ||
delete json.root; | ||
json.ignorePatterns = ['!**/*']; | ||
|
||
const rootEsLintConfigRelativePath = joinPathFragments( | ||
offsetFromRoot(this.projectConfig.root), | ||
'.eslintrc.json' | ||
); | ||
if (Array.isArray(json.extends)) { | ||
json.extends = json.extends.map((extend: string) => | ||
this.convertEsLintConfigExtendToNewPath( | ||
this.oldEsLintConfigPath, | ||
extend | ||
) | ||
); | ||
|
||
// it might have not been extending from the root config, make sure it does | ||
if (!json.extends.includes(rootEsLintConfigRelativePath)) { | ||
json.extends.unshift(rootEsLintConfigRelativePath); | ||
} | ||
} else { | ||
json.extends = rootEsLintConfigRelativePath; | ||
} | ||
|
||
json.overrides?.forEach((override) => { | ||
if (!override.parserOptions?.project) { | ||
return; | ||
} | ||
|
||
override.parserOptions.project = [ | ||
`${this.projectConfig.root}/tsconfig.*?.json`, | ||
]; | ||
}); | ||
|
||
return json; | ||
}); | ||
} | ||
|
||
private convertEsLintConfigExtendToNewPath( | ||
eslintConfigPath: string, | ||
extendPath: string | ||
): string { | ||
if (!extendPath.startsWith('..')) { | ||
// we only need to adjust paths that are on a different directory, files | ||
// in the same directory are moved together so their relative paths are | ||
// not changed | ||
return extendPath; | ||
} | ||
|
||
return joinPathFragments( | ||
offsetFromRoot(this.project.newRoot), | ||
dirname(eslintConfigPath), | ||
extendPath | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
1 change: 1 addition & 0 deletions
1
packages/angular/src/generators/ng-add/migrators/builders/index.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,5 @@ | ||
export * from './angular-devkit-karma.migrator'; | ||
export * from './angular-devkit-ng-packagr.migrator'; | ||
export * from './angular-eslint-lint.migrator'; | ||
export * from './builder-migrator-class.type'; | ||
export * from './builder.migrator'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.