DEV Community

Discussion on: The ultimate migration guide to angular-eslint, ESLint and Nx 11

Collapse
kylecannon profile image
Kyle Cannon

I took this a step further and I think I have successfully bashified it..

#!/bin/bash
#set -euxo pipefail
set -o pipefail
echo "Installing json globally for the time being";
npm i -g json

mv tsconfig.base.json tsconfig.json

yarn nx add @angular-eslint/schematics
yarn add eslint@7.10.0 -D

for project in $(cat angular.json | jq -c '.projects | to_entries | map_values(.key) | .[]' | xargs echo); do
    nx generate @angular-eslint/schematics:convert-tslint-to-eslint $project;
done

mv tsconfig.json tsconfig.base.json
yarn remove @angular-eslint/builder @angular-eslint/schematics
yarn add --dev @nrwl/eslint-plugin-nx eslint-config-prettier eslint-plugin-cypress

# Ignore all files not matched in overrides
npx json -I -f .eslintrc.json -e "this.ignorePatterns = ['**/*'];"

# Support ESLint plugins from `@nrwl/eslint-plugin-nx`
npx json -I -f .eslintrc.json -e "this.plugins = ['@nrwl/nx'];"

# Include tsx files
# Can be left out from an Angular-only workspace
npx json -I -f .eslintrc.json -e "this.overrides[0].files = ['*.ts', '*.tsx'];"

# Match all TypeScript project configuration files
npx json -I -f .eslintrc.json -e "this.overrides[0].parserOptions.project = './tsconfig.*?.json';"

# This setting is not used by the Nrwl Linter
npx json -I -f .eslintrc.json -e "delete this.overrides[0].parserOptions.createDefaultProgram;"

# Replace angular-eslint plugins with the Nx TypeScript ESLint plugin as it uses them internally
npx json -I -f .eslintrc.json -e "this.overrides[0].extends = ['plugin:@nrwl/nx/typescript'];"

# Remove component template rule as this is defined in project-specific ESLint configurations
npx json -I -f .eslintrc.json -e "this.overrides = this.overrides.slice(0, 1);"

# Use Nx JavaScript ESLint plugin for js and jsx files
# Can be left out from an Angular-only workspace
npx json -I -f .eslintrc.json -e "this.overrides = [...this.overrides, { files: ['*.js', '*.jsx'], extends: ['plugin:@nrwl/nx/javascript'], rules: {} }];"

# Remove angular-eslint rules that are added to project-specific ESLint configurations
npx json -I -f .eslintrc.json -e "delete this.overrides[0].rules['@angular-eslint/component-selector'];"
npx json -I -f .eslintrc.json -e "delete this.overrides[0].rules['@angular-eslint/directive-selector'];"
npx json -I -f .eslintrc.json -e "this.overrides = [{ files: ['*.ts', '*.tsx', '*.js', '*.jsx'], rules: { '@nrwl/nx/enforce-module-boundaries': ['error', { enforceBuildableLibDependency: true, allow: [], depConstraints: [{ sourceTag: '*', onlyDependOnLibsWithTags: ['*'] }] }] } }, ...this.overrides];"

# For non e2e projects
for row in $(cat angular.json | jq -c '.projects | to_entries | .[] | select(.value.architect.e2e == null) | @base64' | xargs echo); do
    _jq() {
     echo ${row} | base64 --decode | jq -r ${1}
    }

   PROJECT_KEY=$(_jq '.key');
   PROJECT_ROOT=$(_jq '.value.root')
   PROJECT_DEPTH=$(echo ${PROJECT_ROOT} | tr -cd '/' | wc -c)
   PROJECT_TYPE=$(_jq '.value.projectType')
   echo "Migrating project ${PROJECT_KEY}";
   ESLINT_ROOT_PATH=".eslintrc.json"
    for i in `seq 0 ${PROJECT_DEPTH}`; do
        ESLINT_ROOT_PATH="../${ESLINT_ROOT_PATH}"
    done

    # Correct path to root ESLint configuration
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.extends = '${ESLINT_ROOT_PATH}'"

    # Add Nx Angular ESLint plugin and the ESLint inline component template processor
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.overrides[0].extends = ['plugin:@nrwl/nx/angular', 'plugin:@angular-eslint/template/process-inline-templates'];";

    # Match all TypeScript project configuration files
    if [ $PROJECT_TYPE  == "application" ]; then
        npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.overrides[0].parserOptions.project = [this.overrides[0].parserOptions.project[0].replace('/tsconfig.app.json', '/tsconfig.*?.json')];";
    fi

    if [ $PROJECT_TYPE  == "library" ]; then
        npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.overrides[0].parserOptions.project = [this.overrides[0].parserOptions.project[0].replace('/tsconfig.lib.json', '/tsconfig.*?.json')];";
    fi

    # This setting is not used by the Nrwl Linter
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "delete this.overrides[0].parserOptions.createDefaultProgram;";
    # Use the ESLint component template processor and recommended component template rules from angular-eslint
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.overrides[1].extends = ['plugin:@nrwl/nx/angular-template', 'plugin:@angular-eslint/template/recommended'];";

    npx json -I -f angular.json -e "this.projects['${PROJECT_KEY}'].architect.lint.builder = '@nrwl/linter:eslint';"
done

# For e2e projects
for row in $(cat angular.json | jq -c '.projects | to_entries | .[] | select(.value.architect.e2e != null) | @base64' | xargs echo); do
    _jq() {
     echo ${row} | base64 --decode | jq -r ${1}
    }

   PROJECT_KEY=$(_jq '.key');
   PROJECT_ROOT=$(_jq '.value.root')
   PROJECT_DEPTH=$(echo ${PROJECT_ROOT} | tr -cd '/' | wc -c)
   echo "Migrating project ${PROJECT_KEY}";

    # Use rules recommended by Cypress
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.extends = ['plugin:cypress/recommended', this.extends];"

    # Delete rule for component templates
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.overrides = this.overrides.slice(0, 1);"

    # Add rules specifically for the Cypress plugin loader
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.overrides = [{ files: ['src/plugins/index.js'], rules: { '@typescript-eslint/no-var-requires': 'off', 'no-undef': 'off' } }, ...this.overrides];"

    # Match all TypeScript project configuration files
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "this.overrides[1].parserOptions.project = [this.overrides[1].parserOptions.project[0].replace('/tsconfig.app.json', '/tsconfig.*?.json')];"

    # This setting is not used by the Nrwl Linter
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "delete this.overrides[1].parserOptions.createDefaultProgram;"

    # Remove Angular declarable rules
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "delete this.overrides[1].rules['@angular-eslint/component-selector'];"
    npx json -I -f ${PROJECT_ROOT}/.eslintrc.json -e "delete this.overrides[1].rules['@angular-eslint/directive-selector'];"


    npx json -I -f angular.json -e "this.projects['${PROJECT_KEY}'].architect.lint.builder = '@nrwl/linter:eslint';"

    # Only lint js and ts files in the end-to-end test project
    npx json -I -f angular.json -e "this.projects['${PROJECT_KEY}'].architect.lint.options.lintFilePatterns = [this.projects['${PROJECT_KEY}'].architect.lint.options.lintFilePatterns[0].replace('*.ts', '*.{js,ts}')];"
done
yarn remove codelyzer tslint
rm tslint.json

echo "Uninstalling json globally since we're done";
npm uninstall -g json

Enter fullscreen mode Exit fullscreen mode
Collapse
layzee profile image
Lars Gyrup Brink Nielsen Author

That's great 😊 I just realized that we might need to treat non-Angular projects differently, somewhat similar to the e2e project, but without the Cypress rules. Maybe we should filter on builders or something like that.

Collapse
kylecannon profile image
Kyle Cannon

Ah yeah.. you're right. Totally doable though.

Collapse
petterhoel profile image
Petter

Thank you so much for this guide 😊 the json package stopped supporting lookups in v10 (github.com/trentm/json/blob/master...). Any ideas as to how to migrate all those json editing commands?

Collapse
layzee profile image
Lars Gyrup Brink Nielsen Author

Hi,

I'm using json version 10.0. It complains sometimes. I have it installed globally which usually works. Sometimes you have to install it as a development dependency in the project and use npx or pnpx to run it. If everything fails, installing it as a development dependency and running it through a package.json script usually works.

Thread Thread
petterhoel profile image
Petter

Ah!

I was skimming the json changelog and assumed it was the version, as I have successfully done this in the past. But that was on a different machine/environment, so it was probably something else.

Global install and omitting npx solved it for me. Thanks ☺️

Collapse
warrendugan profile image
Warren Dugan

You're a legend! Thank you so much for this.

Note: if anyone is struggling to get this work due to zsh errors, you'll want to fix the conditionals by escaping the square brackets since zsh tries to do it's own own thing with those

Collapse
cogoo profile image
Colin Ogoo

THANK YOU! Caps intended .. this was so so useful