Last active
April 21, 2020 10:17
-
-
Save dimabory/8c9c5a3d7b36ea88bbf0b12bf778d8ad to your computer and use it in GitHub Desktop.
This is a script to automatically install/configure ESLint into TS project.
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
#!/usr/bin/env bash | |
# Script Name: eslint-migration.sh | |
# | |
# Author: Dmytro Borysovskyi ([email protected]) | |
# Date : 25.08.2019 | |
# | |
# Description: The following script tries to automatically (partially) | |
# migrate TSLint to ESLint. | |
# | |
VERSION=1.2.0 | |
# execution flow | |
COMMANDS=( | |
"Upgrading TS" | |
"Checking TS compatibility" | |
"Uninstalling TSLint" | |
"Removing tslint.json" | |
"Installing ESLint and dependencies" | |
"Creating configuration .eslintrc.json" | |
"Updating lint script to use eslint" | |
"[ONLY ZEISSLET] Updating 'npm start' script to use elsint" | |
"Creating .eslintignore" | |
"Checking ESLint" | |
) | |
# colorize console | |
GREEN='\033[0;32m' | |
YELLOW='\033[1;33m' | |
RED='\033[0;31m' | |
NC='\033[0m' | |
ESLINT_CONFIG_FILENAME=".eslintrc.json" | |
ESLINT_IGNORE_FILENAME=".eslintignore" | |
# packages to be installed | |
DEPS=( | |
eslint | |
eslint-friendly-formatter | |
@typescript-eslint/eslint-plugin | |
@typescript-eslint/parser | |
eslint-plugin-no-null | |
eslint-plugin-prettier | |
eslint-config-prettier | |
) | |
# eslint react specific plugins to be installed | |
REACT_PLUGIN_DEPS=( | |
eslint-plugin-react | |
eslint-loader | |
[email protected] | |
) | |
CWD=$0 | |
COMMAND_NAME=$(basename "$0") | |
# | |
# Usage of the script | |
# | |
COMMAND_USAGE=" | |
USAGE | |
${COMMAND_NAME} [-r] [-s] <path_to_repository> | |
DESCRIPTION | |
This is a script to automatically install/configure ESLint into TS project. | |
OPTIONS | |
-h Show this help text | |
-v Show the version | |
-r Whether remove 'tslint' or not (default = 0) | |
-s Start execution from the step (default = 0): | |
$(for i in "${!COMMANDS[@]}"; do printf '\t%s %s\n' "$i." "${COMMANDS[$i]}"; done) | |
EXAMPLES | |
${COMMAND_NAME} ./dcc.app.iqs-academy-metrology | |
${COMMAND_NAME} -r ./dcc.app.iqs-academy-metrology | |
${COMMAND_NAME} -s 2 dcc.app.iqs-academy-metrology | |
IMPLEMENTATION | |
Version ${VERSION} | |
Author Dmytro Borysovskyi ([email protected]) | |
" | |
# just a helper for echo | |
function print { | |
echo -e "$1" | |
} | |
RM_ESLINT=0 # flag whether to remove eslint or not | |
STEP=0 # flaп to start execution from specific step | |
while getopts ':hvs:r' option; do | |
case $option in | |
h) print "$COMMAND_USAGE"; exit ;; | |
v) print "$VERSION"; exit ;; | |
s) STEP=$(printf '%d\n' "$OPTARG" 2>/dev/null); ;; | |
r) RM_ESLINT=1 ;; | |
:) printf "missing argument for -%s\n" "$OPTARG" >&2 | |
print "$COMMAND_USAGE" >&2 | |
exit 1 | |
;; | |
\?) printf "illegal option: -%s\n" "$OPTARG" >&2 | |
print "$COMMAND_USAGE" >&2 | |
exit 1 | |
;; | |
esac | |
done | |
shift $((OPTIND - 1)) | |
# | |
# Validate argument (path to repo) | |
# | |
if [ ! "$1" ] | |
then | |
print "${RED}Please provide the repository path.${YELLOW} e.g.: | |
${COMMAND_NAME} ./dcc.app.iqs-academy-metrology" | |
exit 2 | |
fi | |
if [ ! -d "$1" ] | |
then | |
print "${RED}${1}: No such directory" | |
exit 2 | |
fi | |
# | |
# Check environment | |
# | |
print "node version $(node -v)" | |
print "npm version $(npm -v)" | |
git --version | |
# | |
# Proceed to the folder and set env | |
# | |
DIR=$1 | |
cd "$DIR" || exit | |
export PATH="$PATH:${PWD}/node_modules/.bin" | |
# | |
# Detect the type of project | |
# | |
print "${GREEN}" | |
print "✅ Everything is ready to start migration" | |
print "📂 ${PWD}\n" | |
IS_ZEISSLET=0 # zeisslet detected (or service) | |
if grep --quiet zeisslet "package.json"; then | |
print "💡 ${YELLOW}The script detected a ZEISSLET repository. | |
There will be installed React specific rules/packages for ESLint." | |
IS_ZEISSLET=1 | |
DEPS=("${DEPS[@]}" "${REACT_PLUGIN_DEPS[@]}") | |
else | |
print "💡 ${YELLOW}The script detected an API service repository." | |
fi | |
print "${NC}------------------------------------" | |
# prompt whether to proceed or not | |
read -e -p "Are you sure you want to continue? [Y/n] " YN </dev/tty | |
[[ $YN != "y" && $YN != "Y" && $YN != "" ]] && exit | |
# | |
# Helpers | |
# | |
function exit_with_error { | |
print "${RED}$1" >&2 | |
exit 2 | |
} | |
function run_command { | |
INFO_MSG="${YELLOW}As soon as you fix errors you can skip previous steps and \ | |
start the command again:\n${CWD} -s $1 ${DIR}" | |
ERROR_MSG="${3:-An error occured while executing command.}\n${INFO_MSG}" | |
print "$(if [ "$1" -lt "$STEP" ]; then echo "${YELLOW}[SKIP]: "; else echo "${GREEN}"; fi)$1. ${COMMANDS[$1]}${NC} |> $2" | |
if [ "$1" -lt "$STEP" ]; then return; fi | |
eval "$2" || exit_with_error "${ERROR_MSG}" | |
print "..." | |
} | |
# | |
# Migration code | |
# | |
run_command 0 "npm i -D typescript@~3.6.0 --loglevel=error --unsafe-perm=true --allow-root" | |
run_command 1 "tsc --p tsconfig.json --noEmit" "Please fix TS errors above to continue migration" | |
# skip steps related to removing eslint | |
if [[ $RM_ESLINT == 0 && $STEP -lt 4 ]]; then | |
STEP=4 | |
fi | |
run_command 2 "npm uninstall -D tslint tslint-config-prettier tslint-plugin-prettier --unsafe-perm=true --allow-root" | |
run_command 3 "$([[ $RM_ESLINT == 1 && -f "tslint.json" ]] && { rm "tslint.json"; })" | |
run_command 4 "npm i --loglevel=error --unsafe-perm=true --allow-root -D $(print "$(for i in "${DEPS[@]}"; do printf '%s' "$i "; done)")" | |
ESLINT_ZEISSLET_CONTENT='{ | |
"extends": [ | |
"eslint:recommended", | |
"plugin:@typescript-eslint/eslint-recommended", | |
"plugin:@typescript-eslint/recommended", | |
"plugin:react/recommended", | |
"plugin:prettier/recommended" | |
], | |
"parser": "@typescript-eslint/parser", | |
"plugins": [ | |
"no-null" | |
], | |
"env": { | |
"es6": true, | |
"browser": true | |
}, | |
"parserOptions": { | |
"ecmaFeatures": { | |
"jsx": true | |
}, | |
"ecmaVersion": 2015, | |
"sourceType": "module", | |
"project": "./tsconfig.json" | |
}, | |
"rules": { | |
"@typescript-eslint/no-use-before-define": [ | |
2, | |
{ | |
"classes": false, | |
"functions": false | |
} | |
], | |
"@typescript-eslint/no-unused-vars": [ | |
2, | |
{ | |
"ignoreRestSiblings": true | |
} | |
], | |
"@typescript-eslint/ban-ts-ignore": 0, | |
"@typescript-eslint/explicit-function-return-type": 0, | |
"@typescript-eslint/no-explicit-any": [ | |
2, | |
{ | |
"ignoreRestArgs": true | |
} | |
], | |
"@typescript-eslint/prefer-for-of": 2, | |
"prefer-const": 2, | |
"no-multiple-empty-lines": 2, | |
"no-eval": 2, | |
"no-console": 1, | |
"eqeqeq": 2, | |
"one-var": [ | |
2, | |
"never" | |
], | |
"quote-props": 0, | |
"radix": 2, | |
"space-before-function-paren": 0, | |
"no-null/no-null": 2, | |
"react/prop-types": 0, | |
"react/display-name": 0, | |
"prefer-arrow-callback": [ | |
2, | |
{ | |
"allowNamedFunctions": true | |
} | |
] | |
}, | |
"settings": { | |
"react": { | |
"version": "detect" | |
} | |
} | |
} | |
' | |
ESLINT_SERVICE_CONTENT='{ | |
"extends": [ | |
"eslint:recommended", | |
"plugin:@typescript-eslint/eslint-recommended", | |
"plugin:@typescript-eslint/recommended", | |
"plugin:prettier/recommended" | |
], | |
"parser": "@typescript-eslint/parser", | |
"plugins": [ | |
"no-null" | |
], | |
"env": { | |
"es6": true, | |
"node": true | |
}, | |
"parserOptions": { | |
"ecmaVersion": 2015, | |
"sourceType": "module", | |
"project": "./tsconfig.json" | |
}, | |
"rules": { | |
"@typescript-eslint/no-use-before-define": [ | |
2, | |
{ | |
"classes": false, | |
"functions": false | |
} | |
], | |
"@typescript-eslint/no-unused-vars": [ | |
2, | |
{ | |
"ignoreRestSiblings": true, | |
"argsIgnorePattern": "^_" | |
} | |
], | |
"@typescript-eslint/ban-ts-ignore": 0, | |
"@typescript-eslint/explicit-function-return-type": 0, | |
"@typescript-eslint/no-explicit-any": [ | |
2, | |
{ | |
"ignoreRestArgs": true | |
} | |
], | |
"@typescript-eslint/prefer-for-of": 2, | |
"prefer-const": 2, | |
"no-multiple-empty-lines": 2, | |
"no-eval": 2, | |
"no-console": 1, | |
"eqeqeq": 2, | |
"one-var": [ | |
2, | |
"never" | |
], | |
"quote-props": 0, | |
"radix": 2, | |
"space-before-function-paren": 0, | |
"no-null/no-null": 2, | |
"prefer-arrow-callback": [ | |
2, | |
{ | |
"allowNamedFunctions": true | |
} | |
] | |
}, | |
"settings": {} | |
} | |
' | |
[[ $IS_ZEISSLET == 0 ]] && ESLINTRC_CONTENT=$ESLINT_SERVICE_CONTENT || ESLINTRC_CONTENT=$ESLINT_ZEISSLET_CONTENT | |
run_command 5 "$([[ $STEP -le 5 ]] && { echo "${ESLINTRC_CONTENT}" > "${PWD}"/${ESLINT_CONFIG_FILENAME}; })" | |
ESLINT_FRIENDLY_FORMATTER_PATH='"node_modules/eslint-friendly-formatter"' | |
run_command 6 "$([[ $STEP -le 6 ]] && { sed -i.bak 's#tslint -c tslint.json#eslint -f \\"node_modules\/eslint-friendly-formatter\\"#g' package.json; rm package.json.bak; })" | |
# skip steps related to ZEISSlet | |
if [[ $IS_ZEISSLET == 0 && $STEP -lt 8 ]]; then | |
STEP=8 | |
fi | |
# npm start script is already changed | |
if grep -lq 'debug-zeisslet --eslint' package.json; then | |
STEP=8 | |
fi | |
run_command 7 "sed -i.bak 's#debug-zeisslet#debug-zeisslet --eslint#g' package.json; rm package.json.bak" | |
#run_command 8 "npm i -D @zeiss/portal@^0.18.0-alpha.155816 --unsafe-perm=true --allow-root" | |
ESLINTIGNORE_ZEISSLET_CONTENT='src/**/*.test.*' | |
ESLINTIGNORE_SERVICE_CONTENT='src/**/*.test.* | |
src/routes.ts | |
src/**/mock/* | |
' | |
[[ $IS_ZEISSLET == 0 ]] && ESLINTIGNORE_CONTENT=$ESLINTIGNORE_SERVICE_CONTENT || ESLINTIGNORE_CONTENT=$ESLINTIGNORE_ZEISSLET_CONTENT | |
run_command 8 "$([[ $STEP -le 8 ]] && { echo "${ESLINTIGNORE_CONTENT}" > "${PWD}"/${ESLINT_IGNORE_FILENAME}; })" | |
run_command 9 "npm run lint" | |
# no way to reach this 😂 | |
print "${GREEN}WOW 😎, ESLint has not detected any errors in your code. Looks like you're 10x engineer 💪." |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment