Si e rregulloja projektin, ku pylli ishte një kaos i plotë (konfigurimet e tslint, prettier, etj.)

PĂ«rshĂ«ndetje pĂ«rsĂ«ri. NjĂ« mĂ«ngjes i mrekullueshĂ«m pĂ«r ju Omelnytskyi Serhiy. Sot do tĂ« ndaj me ju njĂ« nga dhimbjet e mia tĂ« kokĂ«s, konkretisht — çfarĂ« tĂ« bĂ«jmĂ« kur projekti shkruhet nga shumĂ« programues tĂ« niveleve tĂ« ndryshme, duke u bazuar nĂ« njĂ« aplikacion angular.

Si e rregulloja projektin, ku pylli ishte një kaos i plotë (konfigurimet e tslint, prettier, etj.)

Isha mësuar që për një kohë të gjatë të punoja vetëm me ekipin tim, ku ne ishim pajtuar për rregullat e formatimit, komentimin, hapësirat etj. U përshtatëm me to dhe kemi jetuar të lumtur e të qetë. Në gëzimin tonë, madje publikova një artikull në Habr mbi stilistÀ tonë të kodit. Prandaj, siç njihet ndryshe, ne përdorim vetëm tslint në pre-commit.

Dhe aty, ne u zgjeruam. U shfaq një projekt i ri me kod të trashëguar, dhe për ta, një grup i ri zhvilluesish me katër djem të mirë. Dhe çfarë ndodhi, nuk shkoi sipas planit.

Si e rregulloja projektin, ku pylli ishte një kaos i plotë (konfigurimet e tslint, prettier, etj.)

Mendoj se shumĂ« e dinĂ« se puna me kod tĂ« trashĂ«guar nuk Ă«shtĂ« e kĂ«ndshme. NĂ« kujtesĂ«n time kam pasur vetĂ«m njĂ« projekt qĂ« mĂ« ka emocionuar, ndĂ«rsa tĂ« tjerat
 Po pĂ«r çfarĂ« po flas?) Ah po.

Me tĂ« vĂ«rtetĂ«, arkitektura nĂ« projekt kishte shumĂ« pĂ«r tĂ« dĂ«shmuar, dhe komentet dhe tipizimi ishin njĂ« Ă«ndĂ«rr pĂ«r ne. NĂ« njĂ« moment, fillova tĂ« mĂ«rzitem nga fakti se dokumentacioni ynĂ« mbi rregullat e formatimit nuk funksiononte, komentet nuk shkruhen, tip — çfarĂ« Ă«shtĂ« kjo?). KĂ«shtu qĂ« duhej bĂ«rĂ« diçka.

Për ata që mezi presin të dinë të gjitha hapat menjëherë:

  • Ne ndamĂ« tslint nĂ« rregulla tĂ« buta (pĂ«r pre-commit) dhe rregulla tĂ« forta (pĂ«r ide, pĂ«r t'i kujtuar zhvilluesit se kishin harruar tĂ« bĂ«nin diçka)

  • VendosĂ«m auto-fiksimin e mundshĂ«m tĂ« rregullave nga tslint i fortĂ« nĂ« pre-commit

  • Shkruam rregulla pĂ«r prettier

  • Dançim me bubullimĂ« pĂ«r tĂ« ekzekutuar ng lint me lint-staged

Hapi i parĂ« — ndaje dhe sundo

Kur më erdhi ideja për të ashpërsuar rregullat e linterit, mendoja se do të na kaplohej. Kodi është trashëguar. Duhet të kuptohet, dhe në një volum të tillë mund të mbesim të mbytur. U mor vendimi për të krijuar një linter të dytë për ide, i cili do të na shqetësonte dhe do të na bënte të shkruajmë jsdoc për metodat dhe prop, të shkruajmë interfaca ose të famshmin onPush dhe të tjera.

Kështu që në rrënjë ne filluam me 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 kopjimin e objektit"
      }
    ],
    "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ë ndiheshim ngushtë me gjërat e theksuara që nevojonin korrigjim.

Hapi i dytĂ« — korrigjo disa pika

Si e rregulloja projektin, ku pylli ishte një kaos i plotë (konfigurimet e tslint, prettier, etj.)

Tslint ka rregulla me ka ndreqës. Pra, le të përfitojmë.

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

Këtu ne ekzekutojmë rregullat e lintrit të fortë me auto-rregullimin e parametrave të disponueshëm dhe i themi asaj komande që të mos kthejë gabime (qëllimi ynë përfundimisht është të bëjmë auto-korrigjimin).

Hapi i tretĂ« — shkruaj me bukuri

Kur secili shkruan në stilin e tij, përfundimisht bëhet lodhëse. Kodi duhet të shkruhet në një mënyrë që të duket se e bën një njeri. Për këtë, unë krijova prettier me konfigurimet e mëposhtme:

.prettierr.yaml

printWidth: 200     # Numri maksimal i simboleve në linjë
tabWidth: 2         # Hapsira në tab
singleQuote: true   # Përdorimi i thonjëzave të vetme
trailingComma: all  # Përdorimi i presjeve ku është e mundur
arrowParens: always # Funksionet me arrow duken (x) => x
overrides:
  - files: "*.ts"   # Kontrolli i skedarëve *.ts
    options:
      parser: typescript  # Gjuha në skedarët *.ts

Dhe shtova komandën: prettier --write --config .prettierr.yaml

Hapi i katĂ«rt — Si do tĂ« urdhĂ«rosh tĂ« gjithĂ« kĂ«tĂ« tĂ« ekzekutohet?

Tani le të shqyrtojmë më në detaje se si ta ekzekutojmë të gjithë këtë. Për të punuar kështu, na nevojitet të shkarkojmë bibliotekat e mëposhtme:

npm i -D prettier lint-staged husky

Me husky do tĂ« lidhim ekzekutimin e komandave tona nĂ« hook-un git — pre-commit. lint-staged do tĂ« ekzekutojĂ« komandat tona nĂ« varĂ«si tĂ« skedarĂ«ve tĂ« ndryshuar ( gjithashtu do tĂ« vendosĂ« kĂ«ta skedarĂ« nĂ« komandat tona).

Doja të përshkruaja gjithashtu një problem me të cilin kam hasur. Në projektin tonë ne 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 çelësin për këtë --files, por, siç kam kuptuar, ai nuk e sheh paketën e skedarëve, dhe i nevojitet të shtohet ky çelës për secilin skedare. Për këtë, më duhej të krijoja një skedar:

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

Për të ekzekutuar këtë skedar, duhet të kalojmë emrin e projektit. Ai është në skedarin angular.json në pronën project. Në rastin tim, është partner-account dhe partner-account-e2e. Më nevojitet i pari.

Të kthehem te konfigurimi. Tani package.json ynë 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"
    ]
  },

Kujdesi për lint-staged --relative. Parametri --relative është e detyrueshme. Tani, kur bëjmë commit, fillon lint-staged. Ai përzgjedh skedarët dhe ekzekuton një listë komandash në varësi të tyre.

FatkeqĂ«sisht, kjo nuk anullon rishikimin e kodit, por ai Ă«shtĂ« bĂ«rĂ« shumĂ« mĂ« i pastĂ«r. Dua tĂ« theksoj se kam filluar tĂ« i kujtoj mĂ« rrallĂ« zhvilluesve pĂ«r modifikatorĂ«t e aksesit, pĂ«rshkrimin e metodave dhe pronave, dhe krijimtaria e tyre Ă«shtĂ« shkruar nĂ« njĂ« stil tĂ« unifikuar (pothuajse 😀 ).

P.S. — Faleminderit pĂ«r imazhet PM-sĂ« sonĂ«.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster