Wie ich die Dinge in einem Projekt in Ordnung bringe, in dem es einen Wald direkter Hände gibt (tslint, hübscher usw. Einstellungen)

Hallo nochmal. In Kontakt Omelnitsky Sergey . Heute werde ich Ihnen eines meiner Probleme mitteilen, nämlich was zu tun ist, wenn viele mehrstufige Programmierer ein Projekt am Beispiel einer Winkelanwendung schreiben.



So kam es, dass ich lange Zeit nur mit meinem Team zusammengearbeitet hatte, in dem wir uns lange auf die Regeln für Formatierung, Kommentar, Einrückung usw. geeinigt hatten. Ich habe mich an sie gewöhnt und glücklich zusammen gelebt. Zum Feiern habe ich sogar einen Artikel über Habr über unseren Codestil veröffentlicht . Aus diesem Grund haben wir aus magischen Gründen nur tslint für das Pre-Commit verwendet.


Und dann sind wir gewachsen. Ein neues Projekt mit einem geerbten Code erschien, und dazu, zusätzlich zu neuen Entwicklern, in Höhe von 4 guten Stipendiaten. Und auch hier lief es nicht nach Plan.



Ich denke, viele Leute wissen, dass die Arbeit mit Legacy-Code nicht hoch ist. In meiner Erinnerung erhielt ich nur ein Projekt, von dem ich begeistert war, und den Rest ... Also, wovon spreche ich?) Oh ja.


Ehrlich gesagt ließ die Architektur des Projekts zu wünschen übrig, und wir träumten nur davon, zu kommentieren und zu tippen. Irgendwann war ich traurig darüber, dass unser Dokument nicht gemäß den Entwurfsregeln funktioniert hat, keine Kommentare geschrieben wurden, Typ - was ist das?). Hier war es notwendig, etwas damit zu tun.


Für diejenigen, die es kaum erwarten können, alle Schritte auf einmal herauszufinden:
  • Wir haben tslint in weiche Regeln (für Pre-Commit) und harte Regeln (für ide) unterteilt, damit es uns daran erinnert, was die Entwickler vergessen haben.


  • Warten Sie, bis die automatische Fixierung möglicher Regeln von hard tslint vor dem Festschreiben abgeschlossen ist


  • Schrieb Regeln für hübscher


  • Mit einem Tamburin getanzt, um Fusseln mit Fusseln zu spielen



Erster Schritt - Teilen und Erobern


Als ich auf die Idee kam, die Regeln des Linter zu verschärfen, dachte ich, wir würden uns aufhängen. Der Code wird vererbt. Sie müssen es verstehen, und in einem solchen Volumen können Sie graben. Es wurde beschlossen, einen zweiten Linter für ide zu erstellen, der ein Dorn im Auge und eine Kraft sein würde, jsdoc für Methoden und sv-c, Schreibschnittstellen oder unglückliche onPush usw. zu schreiben.


Also haben wir im Root angefangen, 2 tslin-Dateien zu legen:


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": " cloneDeep (lodash)   " } ], "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 } } 

In der src/tslint wir den Standard-tslint durch ide ersetzt


src / tslint.json
 { "extends": "../tslint.ide_only.json", "rules": { "directive-selector": [ true, "attribute", "app", "camelCase" ], "component-selector": [ true, "element", "app", "kebab-case" ] } } 

Und den Start unseres Linter in den Skripten von package.json behoben


 ng lint --tslint-config ./tslint.json --fix` 

Danach hingen wir an den unterstrichenen Dingen, die korrigiert werden müssen.


Schritt zwei - fixieren Sie ein paar Punkte



Tslint hat Regeln mit has fixer . Also lass es uns benutzen.


 tslint --project tslint.ide_only.json --fix --force 

Hier führen wir die Regeln des Hardliners mit automatischer Fixierung der verfügbaren Parameter aus und sagen, dass dieser Befehl keine Fehler zurückgibt (hier ist unser Ziel immer noch die automatische Korrektur).


Schritt drei - schön schreiben


Wenn jeder auf seine Weise schreibt, wird es letztendlich müde. Der Code muss so geschrieben sein, dass dies anscheinend von einer Person durchgeführt wird. Dafür habe ich hübscher geschraubt, mit folgenden Einstellungen:


.prettierr.yaml
 printWidth: 200 #  -    tabWidth: 2 #    singleQuote: true #    trailingComma: all #     arrowParens: always #  -  (x) => x overrides: - files: "*.ts" #   *.ts options: parser: typescript #    *.ts 

Und er fügte den Befehl hinzu: prettier --write --config .prettierr.yaml


Schritt vier - Und wie befiehlst du alles zum Laufen?


Schauen wir uns nun genauer an, wie Sie das alles beginnen können. Damit dies funktioniert, müssen wir Folgendes herunterladen:


 npm i -D prettier lint-staged husky 

Mit Husky werden wir den Start unserer Befehle an einen Git-Hook hängen - Pre-Commit. lint-staged führt abhängig von den geänderten Dateien Befehle für uns aus (ersetzen Sie diese Dateien auch durch Befehle).


Ich möchte auch sofort das Problem skizzieren, auf das ich gestoßen bin. In unserem Projekt verwenden wir ng Flusen. Wenn wir es in Verbindung mit fusselförmigen, verwendeten, werden unserem Befehl geänderte Dateien hinzugefügt. Ng lint hat den Schlüssel --files dafür, aber so wie ich es verstehe, werden keine Dateien --files , und dieser Schlüssel muss jeder Datei hinzugefügt werden. Dazu musste ich eine Datei erstellen:


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 $DESTINATIONS 

Um diese Datei auszuführen, müssen wir den Namen des Projekts übergeben. Es befindet sich in der Datei angular.json in der Projekteigenschaft. In meinem Fall ist dies partner-account und partner-account-e2e . Ich brauche einen 1 ..


Zurück zum Setup. Unsere package.json sieht jetzt so aus:


  "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" ] }, 

lint-staged --relative . --relative Parameter --relative . Wenn wir uns jetzt verpflichten, wird die lint-staged gestartet. Er wählt seinerseits Dateien aus und startet eine Liste von Befehlen, die von diesen abhängen.


Leider wird die Codeüberprüfung dadurch nicht abgebrochen, aber es ist viel sauberer geworden. Ich stelle fest, dass ich Entwickler seltener an Zugriffsmodifikatoren, eine Beschreibung der Methoden und des SV erinnerte, und dass ihre Arbeit im gleichen Stil geschrieben wurde (na ja, fast: D).


PS - Danke für die Bilder an unsere PM.

Source: https://habr.com/ru/post/de464383/


All Articles