Pershendetje përsëri. Jam në kontakt . Sot do të ndaj me ju një nga dhimbjet e mia të kokës, dmth - çfarë të bëni kur një projekt shkruhet nga shumë programues me nivele të ndryshme, për shembull në një aplikacion angular.

Kështu ndodhi, që unë kam punuar për një kohë të gjatë vetëm me ekipin tim, ku ne kishim rregulluar prej kohësh rregullat e formatimit, komentimit, hapësirave dhe të tjera. Ne e kthyem në një zakon dhe jetuam në harmoni dhe lumturi. Kënaqësinë e madhe e ndaja edhe një artikull në Habr për . Prandaj, nga ndonjë magji ne përdorëm vetëm tslint në pre-commit.
Dhe këtu u zgjeruam. Pati një projekt të ri me kod të trashëguar, dhe përveç kësaj, shumë zhvillues të rinj, katër burra të mirë. Dhe gjërat nuk shkuan sipas planit.

Mendoj se shumë e dinë që punën me kodin e trashëguar nuk është e lehtë. Në memorien time kam marrë vetëm një projekt nga i cili isha i ngazëllyer, ndërsa të tjerat... Çfarë përmenda? Ah, po.
Të flas sinqerisht, arkitektura e projektit la për të dëshiruar, ndërsa komentet dhe tipizimi ishin diçka që mund të ëndërroshim. Në një moment, u zhgënjeva nga fakti që dokumentacioni ynë për rregullat e formatimit nuk funksionon, komentet nuk shkruhen, tipi - çfarë është kjo?). Kjo duhet të trajtohej.
Për ata që nuk mund të presin të dinë të gjitha hapat menjëherë:
Ne e ndamë tslint në rregulla të buta (për pre-commit) dhe rregulla të forta (për ide, që të kujtonte se zhvilluesit harrojnë të bëjnë)
Kemi vendosur auto-fiksimin e mundshëm të rregullave nga tslint i fortë në pre-commit
Kemi shkruar rregulla për prettier
Dançuam me tambur që të fillonim ng lint me lint-staged
Hapi i parë - ndaje dhe sundo
Kur më erdhi ideja për të ashpërsuar rregullat e linters, mendoja se do të vdisnim. Kodi është i trashëguar. Duhet të merremi me të, dhe në një masë të tillë mund të humbasim. U mor vendimi për të krijuar një linters të dytë për ide, që do të na godiste sy më sy dhe do të na detyronte të shkruanim jsdoc për metodat dhe vetit, të shkruanim ndërfaqet ose të njohurën onPush dhe kështu me radhë.
Pra, në rrënjë fillestare kishim 2 skedarë tslin:
tsconfig.json
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
200
],
"member-access": false,
"member-ordering": [
true,
{
"order": [
"static-field",
"instance-field",
"static-method",
"instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": [
true,
"debug",
"info",
"time",
"timeEnd",
"trace"
],
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-eval": true,
"no-inferrable-types": [
false,
"ignore-params"
],
"no-duplicate-imports": true,
"no-misused-new": true,
"no-non-null-assertion": true,
"no-redundant-jsdoc": true,
"no-shadowed-variable": false,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": [
true,
"ignore-comments",
"ignore-jsdoc"
],
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-use-before-declare": false,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": false,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": false,
"no-inputs-metadata-property": true,
"no-outputs-metadata-property": true,
"no-host-metadata-property": true,
"no-input-rename": false,
"no-output-rename": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"no-consecutive-blank-lines": true
}
}tslint.ide_only.json
{
"rulesDirectory": [
"node_modules/codelyzer"
],
"rules": {
"completed-docs": [
true,
{
"properties": true,
"methods": true
}
],
"no-angle-bracket-type-assertion": true,
"no-any": true,
"prefer-output-readonly": true,
"prefer-on-push-component-change-detection": true,
"array-type": [
true,
"array"
],
"typedef": [
true,
"call-signature",
"arrow-call-signature"
],
"arrow-return-shorthand": true,
"callable-types": true,
"class-name": true,
"comment-format": [
true,
"check-space"
],
"curly": true,
"deprecation": {
"severity": "warn"
},
"eofline": true,
"forin": true,
"import-blacklist": [
true,
"rxjs/Rx"
],
"import-spacing": true,
"indent": [
true,
"spaces"
],
"interface-over-type-literal": true,
"label-position": true,
"max-line-length": [
true,
200
],
"member-access": [
true,
"check-parameter-property",
"check-accessor"
],
"member-ordering": [
true,
{
"order": [
"public-static-field",
"protected-static-field",
"private-static-field",
"public-instance-field",
"protected-instance-field",
"private-instance-field",
"constructor",
"public-static-method",
"protected-static-method",
"private-static-method",
"public-instance-method",
"protected-instance-method",
"private-instance-method"
]
}
],
"no-arg": true,
"no-bitwise": true,
"no-console": true,
"no-construct": true,
"no-debugger": true,
"no-duplicate-super": true,
"no-empty": false,
"no-empty-interface": true,
"no-duplicate-switch-case": true,
"no-eval": true,
"no-inferrable-types": [
false,
"ignore-params"
],
"no-duplicate-imports": true,
"one-variable-per-declaration": true,
"no-misused-new": true,
"no-non-null-assertion": true,
"prefer-template": [
true,
"allow-single-concat"
],
"ordered-imports": true,
"no-redundant-jsdoc": true,
"no-shadowed-variable": false,
"no-string-literal": false,
"no-string-throw": true,
"no-switch-case-fall-through": true,
"no-trailing-whitespace": [
true,
"ignore-comments",
"ignore-jsdoc"
],
"ban": [
true,
{
"name": [
"Object",
"assign"
],
"message": "Përdorni cloneDeep (lodash) për të kopjuar objektin"
}
],
"max-classes-per-file": [
true,
1
],
"cyclomatic-complexity": [
true,
6
],
"static-this": true,
"no-unnecessary-initializer": true,
"no-unused-expression": true,
"no-var-keyword": true,
"object-literal-sort-keys": false,
"one-line": [
true,
"check-open-brace",
"check-catch",
"check-else",
"check-whitespace"
],
"prefer-const": true,
"quotemark": [
true,
"single"
],
"radix": false,
"semicolon": [
true,
"always"
],
"triple-equals": [
true,
"allow-null-check"
],
"typedef-whitespace": [
true,
{
"call-signature": "nospace",
"index-signature": "nospace",
"parameter": "nospace",
"property-declaration": "nospace",
"variable-declaration": "nospace"
}
],
"unified-signatures": true,
"variable-name": false,
"whitespace": [
true,
"check-branch",
"check-decl",
"check-operator",
"check-separator",
"check-type"
],
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
],
"no-output-on-prefix": false,
"no-inputs-metadata-property": true,
"no-outputs-metadata-property": true,
"no-host-metadata-property": true,
"no-input-rename": false,
"no-output-rename": true,
"use-lifecycle-interface": true,
"use-pipe-transform-interface": true,
"component-class-suffix": true,
"directive-class-suffix": true,
"no-consecutive-blank-lines": true
}
}Në skedar src/tslint ne zëvendësuam tslint standard me ide
src/tslint.json
{
"extends": "../tslint.ide_only.json",
"rules": {
"directive-selector": [
true,
"attribute",
"app",
"camelCase"
],
"component-selector": [
true,
"element",
"app",
"kebab-case"
]
}
}И поправил запуск нашего линтера в скритах package.json
ng lint --tslint-config ./tslint.json --fix`Pas kësaj, filluam të shqetësohemi për gjërat e theksuara që duhet të rregullohen.
Hapi i dytë — rregullo disa momente

Të tslint ka rregulla me ka korrigjues. Pra, le të përfitojmë.
tslint --project tslint.ide_only.json --fix --forceKëtu ne aktivizojmë rregullat e linters rigoroz me automatikë për rregullimin e parametrave të disponueshëm dhe i themi kësaj komande që të mos kthejë gabime (qëllimi ynë është të realizojmë automatikisht rregullime).
Hapi i tretë — shkruaj bukur
Kur secili shkruan në mënyrën e tij, në fund të fundit, bëhet e lodhshme. Kodi duhet të shkruhet në mënyrë që të duken se e bën një person. Për këtë, kam integruar prettier, me cilësimet e mëposhtme:
.prettierr.yaml
printWidth: 200 # Numri maksimal i simboleve në rresht
tabWidth: 2 # Hapësirat në Tab
singleQuote: true # Përdorenação e thonjzave të vetme
trailingComma: all # Përdorimi i presjeve kur është e mundur
arrowParens: always # Funksionet me shigjeta shfaqen (x) => x
overrides:
- files: "*.ts" # Kontrollimi i skedarëve *.ts
options:
parser: typescript # Gjuha në skedarët *.tsDhe shtova komandën: prettier --write --config .prettierr.yaml
Hapi i katërt — Si do të urdhërosh të gjithë këto?
Le të shqyrtojmë tani më në detaje se si ta aktivizojmë të gjithë këtë. Për të bërë që gjithçka të funksionojë, duhet të shkarkojmë bibliotekat e mëposhtme:
npm i -D prettier lint-staged huskyMe ndihmën e husky, ne do të aktivizojmë ekzekutimin e komandave tona në git hook — pre-commit. lint-staged do të ekzekutojë komandat tona në përputhje me skedarët e ndryshuar (po ashtu do të futë këta skedarë në komandat tona).
Doja gjithashtu të shpjegoja problemin me të cilin u ndesha. Ne në projektin tonë përdorim ng lint. Kur e përdorim në lidhje me lint-staged, skedarët e ndryshuar shtohen në komandën tonë. Ng lint ka një çelës për këtë --files, por, si e kuptova, ai nuk e sheh një grup skedarësh dhe i duhet të shtojë këtë çelës për çdo skedar. Për këtë, më duhet të krijoj skedarin:
lint.sh
#!/bin/bash
PROJECT=$1
shift
SOURCES=$@
DESTINATIONS=""
DELIMITER=""
for src in $SOURCES
do
DELIMITER=" --files "
DESTINATIONS="$DESTINATIONS$DELIMITER${src}"
done
ng lint $PROJECT --tslint-config ./tslint.json $DESTINATIONSPër të ekzekutuar këtë skedar, ne duhet të kalojmë emrin e projektit. Ai ndodhet në skedarin angular.json në pronën projekt. Në rastin tim është partner-account dhe partner-account-e2e. Më nevojitet i pari.
Do të kthehem tek konfigurimi. Paketimi ynë.json tani duket kështu:
"husky": {
"hooks": {
"pre-commit": "lint-staged --relative"
}
},
"lint-staged": {
"*.{ts,js}": [
"prettier --write --config .prettierr.yaml",
"tslint --project tslint.ide_only.json --fix --force",
"sh lint.sh partner-account",
"git add"
],
"*.{html,scss,css}": [
"prettier --write --config .prettierr.yaml",
"git add"
]
},Vini re lint-staged --relative. Parametri --relative është e detyrueshme. Tani, kur bëjmë commit, ater ndodh lint-staged. Ai nga ana e tij seleksionon skedarët dhe ekzekuton një listë komandash në varësi të tyre.
Fatkeqësisht, kjo nuk e anullon shqyrtimin e kodit, por ai është bërë shumë më i pastër. Dua të vënë në dukje se kam filluar të ju kujtoj më rrallë zhvilluesve për modifikatorët e qasjes, përshkrimin e metodave dhe veti, dhe krijimtaria e tyre tani shkruhet në një stil të njëjtë (në të vërtetë pothuajse 😀 ).
P.S. — Faleminderit për imazhet tonë PM.
Burimi: habr.com
