Lintest CLI

Copyright 2024. mornya. All rights reserved.
About
Integrated lint and test environment project.
Features
- TypeScript and ES6+ support.
- Linting TypeScript / JavaScript codes with ESLint.
- Testing codes with Jest.
- Availabled for Node.js / React.js (Next.js) / Vue.js (Nuxt.js) applications.
Installation
ν΄λΉ λΌμ΄λΈλ¬λ¦¬λ κΈλ‘λ² μμμ μ€μΉνλ€.
npm λμ yarn μ¬μ©μ, νλ‘μ νΈ λ£¨νΈ κ²½λ‘μ package-lock.json νμΌμ΄ μ‘΄μ¬νλ©΄ μ κ±°νκ³ yarn.lock νμΌλ§ μ°Έμ‘°λλλ‘ νλ€.
$ npm install -g @lintest/cli
or
$ yarn global add @lintest/cli
Execution
Commands
$ lintest <action> [option]
μ¬μ©κ°λ₯ν actionμ μλμ κ°λ€.
install: λ¦°νΈ λ£°μ
ν¨ν€μ§ μ€μΉ λ° lintest μ 보 μμ±, λͺ¨λ μ
κ·Έλ μ΄λ λ± μν
uninstall: μμ±λ μ 보 λ° λ³΅μ¬λ νμΌ λ± install/export μνμ λ°λ₯Έ κ΄λ ¨ νμΌ μ κ±°
export: λ¦°νΈ λ° ν
μ€νΈ νκ²½μ€μ λ΄μ©μ JSON νμΌλ‘ μΆλ ₯νμ¬ IDEμμ μ€μ μ΄ μ°Έμ‘°λλλ‘ ν¨
check: TypeScript μ»΄νμΌλ¬λ₯Ό μ€νμμΌ νλ‘μ νΈ λ΄ μ½λ μ€λ₯ κ²μ¬ μν
clean: κΈ°λ³Έμ μΌλ‘ dist λ° node_modules/.cache λλ ν 리μ λ΄μ©μ λΉμ°μ§λ§, νλΌλ―Έν°λ‘ μΈμ
λ λλ ν 리(λ€)μ΄ μ‘΄μ¬μ ν΄λΉ λλ ν 리μ λ΄μ©μ λΉμ
lint: νλ‘μ νΈ λ΄ μ½λμ λν λ¦°νΈ μν
test: νλ‘μ νΈ λ΄ ν
μ€νΈ μ½λμ λν ν
μ€νΈμΌμ΄μ€ μν
list: κΈ°λ³Έ ESLint νλ¬κ·ΈμΈκ³Ό μΆκ°μ μΌλ‘ μ€μΉλ νλ¬κ·ΈμΈ λͺ©λ‘μ νμ
help: κ° μ‘μ
μ λν λμλ§ νμ
μ΅μ
μ λν λμλ§μ μλμ κ°μ΄ 컀맨λλ₯Ό μ
λ ₯νμ¬ νμΈνλ€.
$ lintest --help
$ lintest help [lint|test|...]
CLI
lintest νκ²½μ€μ μ νλ‘μ νΈ λ£¨νΈ κ²½λ‘μ lintest.config.js νΉμ lintest.config.json λ±μ νμΌλ‘ μμ±νλ©΄ λλ€.
lintest μ€νμ νλ‘μ νΈμ ν΄λΉ μ€μ νμΌμ΄ μ‘΄μ¬νλ©΄ lintest install λͺ
λ Ήμ μνν λ providerνλͺ©μΌλ‘ μ§μ λ λ£°μ
ν¨ν€μ§κ° NPM κΈλ‘λ² μμμ μ€μΉ(μ
λ°μ΄νΈ) λλ©°, λ¦°νΈ λ£°μ
μ ν΄λΉ ν¨ν€μ§ λ΄ μ€μ μ λ°λ₯΄κ² λλ€.
module.exports = {
provider: 'sample',
framework: 'next',
exportConfig: {
lint: 'eslint.config.json',
test: 'jest.config.json',
prettier: '.prettierrc',
},
cacheLocation: {
lint: '.eslintcache',
test: '.jestcache',
},
installPlugins: [
'eslint-plugin-something@latest',
'eslint-plugin-simple-import-sort',
],
installEnvironments: [
'jest-environment-selenium',
],
overrides: {
lintRules: { ... },
eslint: [
{
files: '*.vue',
plugins: ['eslint-plugin-simple-import-sort'],
rules: {
'simple-import-sort/imports': 'error',
'simple-import-sort/exports': 'error',
},
},
],
jest: {
bail: false,
testEnvironmentOptions: {
url: 'https://localhost:8443'
},
...
},
}
}
μμ κ°μ΄ μ€μ νλ©΄ lintest install λͺ
λ Ή μ€νμ @lintest/rules-sample ν¨ν€μ§κ° κΈλ‘λ² μμμ μ€μΉκ° λλ©° νλ‘μ νΈμ λ¦°νΈ λ£°μ
μ ν΄λΉ ν¨ν€μ§μ μ μΈλ μ€μ μ λ°λ₯Έλ€.
κ·Έλ¦¬κ³ lintest export λͺ
λ Ή μ€νμ exportConfigμ μ μΈλ νμΌλ€λ‘ ESLint λ£°μ
κ³Ό Jest, Prettier μ€μ μ΄ μΆλ ₯λλ€.
rules λνλμ μμ±μ μλμμ λ€λ£¬λ€.
λ¦°νΈ λ° ν
μ€νΈ μνμ CLIλ‘ μ€ννλ©°, 컀맨λλΌμΈμμ μλμ κ°μ΄ μ€ν ν μ μλ€.
$ lintest lint [--fix][--debug][--no-cache][...]
$ lintest test [--coverage][--watch][--debug][--no-cache][...]
λ¦°νΈ λ° ν
μ€νΈ νκ²½μ€μ λ΄μ©μ΄ νμν κ²½μ° export λͺ
λ Ήμ μ¬μ©νμ¬ νκ²½μ€μ μ μ°Έκ³ ν μ μλ€.
μνκ²°κ³Όλ νλ‘μ νΈ λ£¨νΈ κ²½λ‘μ ESLint νκ²½μ€μ νμΌ λ° Jest νκ²½μ€μ νμΌμ΄ μΆλ ₯λλ€ (lintest.config νμΌμμ μ§μ ν νμΌκ²½λ‘λ‘ λ³κ²½ κ°λ₯).
λ§μ½ μ μμ μΈ μΆλ ₯μ΄ λμ§ μλλ€λ©΄ debug νλΌλ―Έν°λ‘ νμΈνλ€.
$ lintest export [--debug]
NPM
NPM νλ‘μ νΈμμλ npm run λͺ
λ ΉμΌλ‘ μ€νλλλ‘ μλμ κ°μ΄ package.json νμΌ λ΄μ μ€μ νλ€.
{
"scripts": {
"check": "lintest check",
"clean": "lintest clean",
"lint": "lintest lint",
"lint:fix": "lintest lint --fix",
"lint:debug": "lintest lint --debug --no-cache",
"test": "lintest test",
"test:watch": "lintest test --watch",
"test:coverage": "lintest test --coverage --no-cache"
}
}
νλ‘μ νΈμμ npm install λͺ
λ Ήμ΄ μ€νλ νμ lintest μ
λ°μ΄νΈ λ° λ£° μ
λ°μ΄νΈλ₯Ό μλμΌλ‘ μνν΄ μ€ μ μλλ‘ μλμ κ°μ΄ μ€μ ν μλ μλ€.
exit 0μ lintestκ° μ€μΉλμ΄ μμ§ μμ κ²½μ°, μ€λ₯λ‘ μΈν΄ λ€μ νλ‘μΈμ€κ° λμνμ§ μλ κ²μ λ°©μ§νκΈ° μν΄ μ μμ’
λ£λ‘ μ²λ¦¬νλλ‘ ν΄μ€λ€.
- λ‘컬 κ°λ°νκ²½μ΄ μλ ν
μ€νΈ/μ΄μνκ²½μμ lintest λ―Έμ€μΉλ‘ μΈν΄ μ€λ₯κ° λ°μνμ§ μλλ‘ μ£Όμ.
{
"scripts": {
"postinstall": "lintest install || exit 0",
"postuninstall": "lintest install || exit 0",
"prepare": "lintest export || exit 0"
}
}
Testing
ν
μ€νΈμΌμ΄μ€λ₯Ό μννκΈ° μν΄ CLIμ λνλμλ‘ μ€μΉλ jest λ°μ΄λλ¦¬κ° μ€νλλ€.
ν
μ€νΈ νμΌμ νλ‘μ νΈ λ΄ μ‘΄μ¬νλ *.{test,spec}.{ts,tsx,js,jsx} νμΌλ€μ΄ ν
μ€νΈ λμμ΄ λλ€.
Setup files
κ° λ¨μ ν
μ€νΈλ₯Ό μννκΈ° μ mocking methodλ μ΄κΈ° μ€μ μ ν μ μλλ‘ μ
μ
νμΌμ μΆκ° ν μ μλ€.
μ μ©λ ν
μ€νΈ μ
μ
νμΌμ μλ λͺ©λ‘μμ μ‘΄μ¬νλ νμΌμ λͺ¨λ μ°Ύμ μ¬μ©νκ² λλ€.
μμΈν λ΄μ©μ Jest κ΄λ ¨ λ¬Έμλ₯Ό μ°Έκ³ .
<rootDir>/src/test/@setup.ts (or .js|cjs|cts|mjs|mts)
<rootDir>/src/tests/@setup.ts
<rootDir>/test/@setup.ts
<rootDir>/tests/@setup.ts
<rootDir>/test-setup.ts
Test Coverage
μλ λͺ
λ ΉμΌλ‘ ν
μ€νΈ 컀λ²λ¦¬μ§ λ°μ΄ν°λ₯Ό νλ‘μ νΈ λ΄ /coverage λλ ν 리μ μμ±ν μ μλ€.
$ lintest test --coverage
Lint rules package
Naming
ν¨ν€μ§λͺ
μ @lintest/rules-{νλ‘λ°μ΄λλͺ
}μΌλ‘ μ μνκ³ NPM @lintest μ‘°μ§μ μΉμΈμ λ°μ λ°°ν¬ν¨μΌλ‘μ¨ CLIμμ ν΄λΉ ν¨ν€μ§λ₯Ό λ°μ λ¦°νΈ λ£°μ μ μ© ν μ μκ² λλ€.
Package defination
package.jsonμ "main"μΌλ‘ μ€μ λ νμΌ(index.js)μ μλμ κ°μ λ¨μΌ ννμ μ μ νμΌμ΄ κΈ°λ³Έμ μΌλ‘ νμνλ€.
μ€μ κ°λ₯ νλͺ©μ prettier, lintRules, disableLintIgnore, enableCompatibility λ±μ΄ μλ€.
prettier
prettier νλͺ©μ prettier μ¬μ©μ΄ νμν λλ§ λͺ
μνλ©΄ λλ€.
lintRules
μλ μνμ²λΌ μ€μ ν΄μ£Όλ©΄ lintestμμ μ€μ μ λ°λΌ μ¬λ¬ νλ¬κ·ΈμΈμ μ‘°ν©νμ¬ μ΅μ’
λ¦°νΈ λ£°μ
μ λ§λ€μ΄λΈλ€.
lintRules νμ νλͺ©μ λ£°μ λν μ μΈμ νλ¬κ·ΈμΈλ³ prefixλ₯Ό λΆμ΄μ§ μμλ λλ©°, λΆνμμ λͺ
μνμ§ μμλ λλ€.
μλ₯Ό λ€μ΄, typescript νλͺ©μ '@typescript-eslint/indent' λ£°μ μ μν λ '@typescript-eslint/'λ κ΅³μ΄ λΆμ¬μ£Όμ§ μμλ 'typescript' νλͺ© νμμ 'indent'λ§μΌλ‘ μ μΈν΄λ μ΅μ’
λ£°μ '@typescript-eslint/indent'λ‘ λ³νλλ€.
lintRules νμ νλͺ© μ€ vue νΉμ react λ£°μ΄ λͺ
μλλ©΄ κ΄λ ¨ λ£°μ
μ΄ ν¨κ» μ μ©λλ€.
vueλ "eslint-plugin-vue", "@vue/standard", "@vue/typescript" λ± μ μ©.
reactλ "eslint-plugin-jsx-a11y", "eslint-plugin-react", "eslint-plugin-react-hooks" λ± μ μ©.
- μ¬μ©νμ§ μμ λ£°μ ν΄λΉ νλͺ©μ μ£Όμμ²λ¦¬ ν΄λκ±°λ μμ νλ©΄ λλ€.
ex)
// prettier: 'unused',
lintRules: {
Β Β // import: {},
},
Sample
module.exports = {
prettier: {
tabWidth: 2,
useTabs: false,
},
lintRules: {
general: {
'comma-dangle': 'off',
'no-console': 'off',
'no-debugger': 'off',
},
typescript: {
'@typescript-eslint/indent': ['error', 2],
},
react: {
'react/jsx-boolean-value': 'off',
'jsx-wrap-multilines': 'off',
},
reactHooks: {
'rules-of-hooks': 'error',
'exhaustive-deps': 'warn',
},
next: {
'no-img-element': 'off',
},
vue: {
'attribute-hyphenation': 'off',
'vue/html-closing-bracket-spacing': 'off',
'vue/html-indent': ['error', 2],
'html-self-closing': 'off',
},
nuxt: {
'nuxt/no-cjs-in-config': 'off',
},
unicorn: {
'escape-case': 'error',
},
promise: {
'promise/valid-params': 'off',
},
import: {},
jest: {},
lintest: {
report: [1, 'all', 10, 300],
},
node: {},
},
disableLintIgnore: false,
enableCompatibility: false,
}
Etcs
λ¦°νΈ νΌν¬λ¨Όμ€ ν₯μμ μν΄ μλμ κ°μ΄ performance reportλ₯Ό μ½μλ‘ μΆλ ₯ν μ μλ€.
λ¦°νΈμ μνμκ°μ 체ν¬ν΄λ³΄λ©΄μ μκ°μ΄ λ§μ΄ 걸리λ λ£°μ λν΄ λΉνμ±ννλ©΄ μνμλ ν₯μμ λμμ΄ λλ€.
$ export TIMING=1
$ npm run lint
Change Log
νλ‘μ νΈ λ³κ²½μ¬νμ CHANGELOG.md νμΌ μ°Έμ‘°.
License
νλ‘μ νΈ λΌμ΄μΌμ€λ LICENSE μ°Έμ‘°.