Skip to content

Instantly share code, notes, and snippets.

@dimabory
Last active April 21, 2020 10:17
Show Gist options
  • Save dimabory/8c9c5a3d7b36ea88bbf0b12bf778d8ad to your computer and use it in GitHub Desktop.
Save dimabory/8c9c5a3d7b36ea88bbf0b12bf778d8ad to your computer and use it in GitHub Desktop.
This is a script to automatically install/configure ESLint into TS project.
#!/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