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