Och Äterigen, hej. HÀr Àr vi . Idag kommer jag att dela med mig av en av mina huvudvÀrkare, nÀmligen - vad man ska göra nÀr ett projekt skrivs av mÄnga programmerare pÄ olika nivÄer, med exempel pÄ en Angular-applikation.

Det har blivit sÄ, att jag under lÄng tid endast har arbetat med mitt team, dÀr vi lÀnge har enats om regler för formatering, kommentering, indrag och sÄ vidare. Vi har blivit vana vid dem och levt i harmoni och lycka. Av glÀdje publicerade jag till och med en artikel pÄ Habr om . SÄ vi anvÀnde nÄgot magiskt, bara tslint vid pre-commit.
Och hÀr vÀxte vi. En ny projektt med Àrvd kod dök upp, och till det en ny grupp utvecklare - fyra duktiga killar. Och hÀr började det gÄ snett.

Jag tror mÄnga vet att det inte Àr roligt att arbeta med Àrvd kod. Av det jag minns har jag bara fÄtt ett projekt som jag tyckte om, resten... SÄ vad pratade jag om?) à h ja.
Ărligt talat, arkitekturen i projektet lĂ€mnade mycket kvar att önska, och kommentarer och typning var nĂ€stan en dröm. Vid nĂ„got tillfĂ€lle kĂ€nde jag mig nedslagen av att vĂ„r dokumentation om formateringsreglerna inte fungerade, kommentarer skrivs inte, typ - vad Ă€r detta?). HĂ€r var det dags att göra nĂ„got.
För den som inte kan vÀnta med att fÄ veta alla steg i förvÀg:
Vi delade upp tslint i mjuka regler (för pre-commit) och strikta regler (för ide, för att pÄminna om vad utvecklarna glömde göra)
Vi lade till automatisk fixering för möjliga regler frÄn den strikta tslint vid pre-commit
Vi skrev regler för prettier
Vi dansade med trumman för att fÄ igÄng ng lint med lint-staged
Steg ett - dela och hÀrska
NÀr jag fick idén att skÀrpa linterns regler tÀnkte jag att vi skulle hÀnga oss. Koden Àr ju Àrvd. Man behöver förstÄ den, och i sÄdan omfattning kan man fastna. Beslutet fattades att skapa en andra linter för ide, som skulle irritera ögonen och fÄ folk att skriva jsdoc för metoder och egenskaper, skriva grÀnssnitt eller det olyckliga onPush, och sÄ vidare.
SÄ i roten lÄg det tvÄ tslint-filer:
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": "AnvÀnd cloneDeep (lodash) för att kopiera objekt"
}
],
"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
}
}I filen src/tslint Vi har ersatt standard tslint med 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`Efter det började vi fÄ problem med understrukna saker som behövde rÀttas.
Steg tvĂ„ â fixa ett par punkter

Tslint har regler för har fixer. SÄ lÄt oss anvÀnda det.
tslint --project tslint.ide_only.json --fix --forceHÀr kör vi hÄrda linter-regler med automatisk korrigering för tillgÀngliga parametrar och sÀger att det hÀr kommandot inte ska returnera nÄgra fel (vÄr mÄlsÀttning Àr trots allt att göra automatiska korrigeringar).
Steg tre â skriv vackert
NÀr varje person skriver pÄ sitt eget sÀtt blir det tröttande i slutÀndan. Koden bör skrivas sÄ att det verkar som om en enda person gör det. För detta har jag lagt till prettier med följande instÀllningar:
.prettierr.yaml
printWidth: 200 # Maximalt antal tecken per rad
tabWidth: 2 # mellanslag i tab
singleQuote: true # AnvÀnda enkla citattecken
trailingComma: all # AnvÀnda komman dÀr det Àr möjligt
arrowParens: always # Pilfunktioner ser ut som (x) => x
overrides:
- files: "*.ts" # Kontroll av *.ts-filer
options:
parser: typescript # SprÄk i *.ts-filerOch jag lade till kommandot: prettier --write --config .prettierr.yaml
Steg fyra â Och hur tĂ€nker du köra allt detta?
LÄt oss nu gÄ igenom hur man kör allt detta detaljerat. För att det ska fungera behöver vi ladda ner följande bibliotek:
npm i -D prettier lint-staged huskyMed husky kopplar vi körningen av vĂ„ra kommandon till git-hooks â pre-commit. lint-staged kommer att köra vĂ„ra kommandon beroende pĂ„ Ă€ndrade filer (och ocksĂ„ inkludera dessa filer i vĂ„ra kommandon).
Jag skulle ocksÄ vilja belysa ett problem som jag stötte pÄ. I vÄrt projekt anvÀnder vi ng lint. NÀr vi anvÀnder det tillsammans med lint-staged, lÀggs de Àndrade filerna till i vÄrt kommando. Ng lint har en flagga för detta --files, men som jag förstod det, ser den inte ett paket av filer och den behöver den hÀr flaggan lÀggas till för varje fil. För detta var jag tvungen att skapa en fil:
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 $DESTINATIONSFör att köra den hÀr filen mÄste vi ange projektets namn. Det finns i filen angular.json i projektattributet. I mitt fall Àr det partner-account och partner-account-e2e. Jag behöver den första.
Tillbaka till instÀllningen. VÄr package.json ser nu ut sÄ hÀr:
"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"
]
},Observera lint-staged --relative. Parametern --relative Àr obligatorisk. Nu körs lint-staged. Den plockar ut filerna och kör beroende pÄ dem en lista med kommandon.
TyvĂ€rr upphĂ€ver detta inte kodgranskningen, men den har blivit mycket renare. Jag mĂ€rker att jag numera sĂ€llan pĂ„minner utvecklarna om Ă„tkomstmodifierare, metodbeskrivningar och attribut, och deras kreativitet har skrivits i en enhetlig stil (nĂ€stan đ ).
P.S. â Tack för bilderna till vĂ„r PM.
KĂ€lla: habr.com
