Tslint: Предложение: конфигурация условного линта

Созданный на 3 нояб. 2017  ·  42Комментарии  ·  Источник: palantir/tslint

Есть некоторые ситуации, когда мы хотели бы условно принудительно применить проверку линта в зависимости от того, является ли линтируемый код тестовым или нет. Например, мы хотели бы запретить «любой» из производственного кода, поскольку это небезопасно. Но в тестах «любой» может быть полезен для предоставления фальшивых или фиктивных реализаций сервисов или для прохождения через них, чтобы вы могли вызывать частные методы. Или мы можем захотеть запретить другой набор методов, например, в тестах и ​​в производственном коде.

Я предлагаю способ условно включить проверку линта на основе совпадения регулярного выражения в имени файла. Это также может быть полезно для отключения проверки линта для определенных каталогов (например, содержащих "устаревший" код) или для файлов .tsx или .d.ts и т. Д.

Вот несколько идей соломенного синтаксиса; Я тоже открыт для предложений.

Объект "Разделы"

{
  "rules": {
    "no-any": {"other": true},
    "no-console":
        {
          "test": [true, "warn", "error"], 
          "other": [true, "log", "warn", "error"]
        }
  },
  "sections": {
    "test": ".*\\.spec\\.ts$"
  }
}

«Другое» - это вещи, которые не соответствуют ни одному из регулярных выражений. Это довольно лаконично, но я думаю, что читабельность раздела правил немного страдает.

Правила "переопределения"

{
  "rules": {
    "no-any": true,
    "no-console": [true, "log", "warn", "error"]
  },
  "override": {
    "match": ".*\\.spec\\.ts$",
    "rules": {
      "no-any": false,
      "no-console": [true, "warn", "error"]
    }
  }
}

(возможно, это должен быть массив, чтобы учесть несколько переопределений).

Declined Enhancement

Самый полезный комментарий

Вложенность не решает обсуждаемых здесь проблем. Многие люди хотят , чтобы их испытания в той же структуре каталогов в качестве кода он проверяет, и просто нет хороший способ сделать это с tslint прямо сейчас.

Все 42 Комментарий

Если вы поместите свои тесты и производственный код в отдельные каталоги, вам не понадобится такая функция. Если вы не предоставили файл конфигурации в качестве аргумента CLI, TSLint использует ближайший tslint.json . Поэтому у вас могут быть разные настройки для разных папок. Используя "extends" вы можете использовать ту же базовую конфигурацию и переопределить только определенные правила.

Я понимаю, что многие проекты Angular и React помещают тесты в тот же каталог, что и соответствующий производственный код. Лично я считаю, что это плохая практика. Я видел достаточно людей (случайно), импортирующих символы из тестов в производственный код.

IMO предлагаемая функция добавляет много сложности. Реализация может быть не такой уж и сложной, но это затрудняет чтение и понимание файла конфигурации.
Если мы собираемся реализовать это, я бы предпочел второе предложение.

Нам также нужно будет обсудить, как это работает при расширении конфигураций. В каком порядке применяются переопределения?

Правда, можно было бы просто разделить код, но это вредит эргономике. Либо у вас есть

src/
  tslint.json
  a/
    b/
      c/
test/
  tslint.json (extends ../src)
  a/
    b/
      c/

и c/foo.spec.ts должен import {symbol} from '../../../a/b/c/foo';

Этот путь становится некрасивым в нашем монорепозитории, где файлы часто находятся очень глубоко в дереве.

или у вас есть

  a/
    src/
      tslint.json
    test/
      tslint.json (extends ../src)
    b/
      src/
        tslint.json
      test/
        tslint.json (extends ../src)
      c/
        src/
           tslint.json
        test/
          tslint.json (extends ../src)

что слишком много файлов tslint.json

По теме переопределений: я бы сказал, что переопределения применяются в том же порядке, в котором применяются правила. Я не знаю, что это такое, и мне не удалось найти документацию, но интуитивно я подумал, что это будет примерно так:

// a.json
{"rules": {"foo": [true, 1]}}

// b.json
{"rules": {"foo": [true, 2]}}

// c.json
{
  "extends": ["a.json", "b.json"],
  "rules": {"foo": [true, 3]}
}

приведет к тому, что правило «foo» будет иметь аргумент 3. Если этого правила не было в c.json , тогда «foo» должно иметь значение 2 из-за порядка массива «extends».

Что касается переопределений, я бы ожидал, что будет применен тот же порядок. Для меня имеет смысл использовать последнее переопределение, которое соответствует предоставленному регулярному выражению, с учетом порядка, в котором рассматриваются правила «расширений». Пример одного файла:

{
  "rules": {"a": [true, 1]},
  "override": [
    {"match": "test|spec", "rules": {"a": [true, 2]}},
    {"match": "test", "rules": {"a": [true, 3]}}
  ]
}

будет иметь значение 2 для правила «foo», если путь к файлу содержит «spec», 3, если он содержит «test», и 1 в противном случае. (очевидно, не очень полезный набор переопределений, так как "test" с таким же успехом можно было бы опустить с первого раза, но идею вы поняли)

Имеет ли это смысл и отвечает на ваш вопрос?

@calebegg Есть и другие крайние случаи, которые следует учитывать:

// a.json
{
  "rules": {"foo": [true, 1]},
  "override": {"match": "test|spec", "rules": {"foo": [true, 2]}}
}

// b.json
{
  "extends": "./a.json"
  "rules": {"foo": false}
}

Каков ожидаемый результат?

  • 2 потому что заказ равен a.json/rules -> b.json/rules -> a.json/override
  • false потому что заказ a.json/rules -> a.json/override -> b.json/rules

То же самое, каков ожидаемый результат:

// c.json
{
  "rules": {"foo": [true, 1]},
  "override": {"match": "test|spec", "rules": {"foo": false}}
}

// d.json
{
  "extends": "./a.json"
  "rules": {"foo": {"options": 2}},
  "override": {"match": "test|spec", "rules": {"foo": {"options": 3}}}
}

Просто случайная мысль: почему бы просто не сопоставить шаблоны по порядку и (частично) переопределить предыдущее совпадение:

{
  "rules": { // same as "*"
    "rule-one": true,
    "rule-two": true
  },
  "*.js?(x)": { // we could get rid of "jsRules" with this
    "rule-two": false
  },
  "*.{t,j}sx": {
    "jsx-rule": true
  },
  "*.spec.*" {
    "rule-one": false
  }
}

Некоторые примеры:

  • foo.ts : правило первое, правило второе
  • foo.tsx : правило первое, правило два, правило jsx
  • foo.js : правило первое
  • foo.jsx : правило первое, правило jsx
  • foo.spec.tsx : правило два, правило jsx
  • foo.spec.js : нет

Я просто не знаю, где это поместить в конфиг. Тот же уровень, что и "rules" упрощает написание, но может запутать пользователей, потому что он находится на том же уровне, что и "extends" , "rulesDirectory" , ...

Еще одна проблема - расширение конфигов. Если мы применим все переопределения из базовой конфигурации, а затем переопределения из текущей конфигурации, это будет довольно сложно понять.

Это также усложняет код. На данный момент конфиги при парсинге сливаются. С этим предложением окончательная конфигурация известна только тогда, когда у нас есть имя файла.

Привет,

Эта функция будет отличной. Я думаю, что Eslint поддерживает эту функцию: https://eslint.org/docs/user-guide/configuring#configuration -based-on-glob-patterns. Итак, синтаксис и семантика могут быть одинаковыми, чтобы избежать путаницы.

@minomikula Большое спасибо. Раньше я искал документы ESLint, но не нашел этого раздела.

Их подход имеет смысл. Обобщить:

  • "overrides" раздел в конфиге содержит массив переопределений
  • переопределение может указывать несколько шаблонов глобусов ( "files" ). если один из них совпадает, применяется конфигурация
  • вы можете исключить файлы по шаблону глобуса: "excludedFiles"
  • шаблоны glob относятся к конфигурационному файлу, в котором они указаны
  • шаблоны glob всегда должны соответствовать всему пути, а не только базовому имени
  • переопределения обрабатываются по порядку, переопределяя предыдущее
  • при расширении файла конфигурации базовая конфигурация полностью оценивается перед переходом к расширенной конфигурации

    • base.json / правила

    • base.json / переопределяет

    • расширение.json / правила

    • расширение.json / переопределения

При переносе этого поведения в TSLint необходимо учитывать несколько моментов:

  • мы обязательно должны отключить extends и linterOptions в переопределениях
  • мы, вероятно, также хотим запретить rulesDirectory
  • хотим ли мы разрешить rules и jsRules в переопределениях, или мы отказываемся от jsRules в пользу переопределения **/*.js?(x) ?

Мысли или комментарии @adidahiya @calebegg @alexeagle @minomikula?

О, да, такой подход кажется мне разумным. Я должен был также поискать известный уровень техники.

Это было бы отличным дополнением! Подход eslint отлично работает при условном отключении некоторых правил в тестовых файлах.

@calebegg , вы все еще планируете продвигать это вперед, когда найдете время?

Да, я определенно хотел бы поработать над этим. @ajafff Вы в целом довольны тем, что начинаете с подхода ESLint и повторяете PR? Или вы думаете, что есть вопросы дизайна, о которых мы должны поговорить в первую очередь?

хотим ли мы разрешить правила и jsRules в переопределениях или мы отказываемся от jsRules в пользу переопределения * / .js? (x)?

Для меня имеет смысл осуждать, но я не очень сильно чувствую себя в любом случае.

@calebegg Меня устраивает подход ESLint. Я реализовал очень похожую концепцию в моей среде выполнения POC-линтера https://github.com/fimbullinter/wotan/tree/master/packages/wotan#overrides

Интеграция в текущий API TSLint может быть сложной, потому что в настоящее время он объединяет все конфигурации во время синтаксического анализа. Это нужно отложить до тех пор, пока не станет известно имя файла, и это нужно сделать для каждого файла.

Это, безусловно, критическое изменение API.

@calebegg @mitchlloyd @ajafff @alexeagle Я вижу небольшую выгоду в этой функции по сравнению с простым вложением файлов tslint.json для переопределения внешних конфигураций. эта функция уже работает сегодня и не требует каких-либо сложных разрывов API. Вы бы обиделись, если бы мы отклонили этот запрос?

Вложенность не решает обсуждаемых здесь проблем. Многие люди хотят , чтобы их испытания в той же структуре каталогов в качестве кода он проверяет, и просто нет хороший способ сделать это с tslint прямо сейчас.

Есть множество проектов, помещающих файлы спецификаций в тот же каталог, что и исходные коды. Это стало лучшей практикой во многих средах, Angular CLI генерирует подобную структуру проекта и т. Д. Я не думаю, что реалистичное вложение файлов конфигурации tslint будет работать для всех этих людей.

Я согласен с тем, что структура моего проекта не должна зависеть от инструмента линтинга. Вместо этого инструмент для линтинга должен поддерживать общие существующие шаблоны. Распространение тестов и исходных файлов является обычным делом.

@giladgray Запрошенное изменение поддерживает сценарий, в котором пользователи рабочие файлы рядом друг с другом следующим образом:

some-dir/
  my-component.ts
  my-component.test.ts

Как "вложение tslint.json files" решит этот вариант использования, если нам нужны разные правила для my-component.ts и my-component.test.ts ?

Руководства @giladgray angular рекомендуют размещать тесты вместе с файлами. Так делают 99% проектов angular. Из-за того, что tslint был обратным, в каждом угловом проекте, над которым я работал, были проблемы. Ваш последний комментарий сбивает с толку и близорук. Если вы не можете / не хотите принять это невероятно полезное предложение, то я думаю, что вы слишком консервативны, чтобы принимать за нас решения по такому важному проекту. Эта проблема годами усложняла работу над нашим угловым проектом.

@ohjames Давай

Имеет смысл хотеть переопределения для файлов, которые не вписываются во вложенную структуру, как упомянуто выше. Мне кажется, что комментарий @giladgray был предназначен для того, чтобы определить, есть ли по-прежнему значительный интерес сообщества к этому изменению, учитывая, что не было никакой активности по этому вопросу более 6 месяцев. Об этом, в частности, свидетельствует его комментарий к открытому пиару (# 3708):

Если вы действительно хотите продолжить, обновите эту ветку, чтобы мы могли ее просмотреть, или закройте ее, если она больше не актуальна. мы закроем это, если мы не получим известие от вас в течение двух недель.

@ohjames Я бы посоветовал вам пересмотреть свой комментарий - как упомянул @DanielSchaffer , личные атаки не помогут вам ни здесь, ни где-либо в программном обеспечении с открытым исходным кодом. Все стараются изо всех сил создавать хорошее, надежное и многофункциональное программное обеспечение, и нападения на людей никоим образом этому не способствуют.

Есть ли обновления по этой теме?
Идея, предложенная @ajafff в его комментарии, кажется разумной и удовлетворяет все многообразие потребностей. Использование той же семантики, что и eslint, - хороший путь вперед.

Как я прокомментировал к связанному с ним # 1063, мой вариант использования будет заключаться в том, что использование tslint-microsoft-contrib в настоящее время подрывает однофайловые компоненты Vue для некоторых правил. Это может быть либо проблема Vue, либо проблема TSLint, и эти команды могут или не могут найти способ исправить конкретную проблему - отключение нарушающих правил до тех пор, пока это не произойдет, кажется простым обходным путем, который не является слишком громоздким. По сравнению с необходимостью добавления одной и той же директивы disable в каждый отдельный файл .vue и обновления его во всех этих местах по мере изменения поддержки правил. Также не имеет смысла разбивать проект на файлы .vue и .ts, это была бы очень неудобная структура.

Я за то, чтобы эта функция появилась. Может быть, мы также сможем чисто решить с ее помощью запрос tslintignore в # 73, позволив некоторым переопределениям полностью отключить все правила?

{
    "files": "./src/test-data/*.ts",
    "reset": true // Resets tslint.json to {}
}

tslint-microsoft-contrib в настоящее время взрывает однофайловые компоненты Vue для некоторых правил

О 😕 @millimoose могли бы вы подать вопрос о tslint-майкрософт-вно?

@JoshuaKGoldberg - Я уже сделал подробный отчет об этой ошибке в @ vuejs / vue-cli, который мне показался наиболее подходящим. (Он помечен как «ожидает воспроизведения», так что я предполагаю, что это не так уж и неуместно.) Я просто упомянул это как мотиватор для участия здесь. Это то, что может и будет происходить в развивающейся экосистеме, что должно быть аргументом в пользу того, чтобы инструменты были достаточно гибкими, чтобы обходить препятствия, фактически не создавая хаки для чужих ошибок.

Есть новости по этой проблеме?

Эта проблема в настоящее время помечена как «Требуется предложение», но я думаю, что мы уже сделали предложение в https://github.com/palantir/tslint/issues/3447#issuecomment -344020834?

В предложении @RoystonS @ajafff упоминается несколько

При переносе этого поведения в TSLint необходимо учитывать несколько моментов:

  • мы обязательно должны отключить extends и linterOptions в переопределениях
  • мы, вероятно, также хотим запретить rulesDirectory
  • хотим ли мы разрешить rules и jsRules в переопределениях или мы отказываемся от jsRules в пользу переопределения **/*.js?(x) ?

Перед тем, как двигаться дальше, должны прийти к согласию люди из организации palantirtech, поскольку это довольно существенная особенность.

Просто наткнулся на это сам и просто хочу выразить свой интерес к такой функции.

Мы закончили тем, что ослабили некоторые правила линтинга, которые влияют на производственный код, и посмотрим, как это пойдет. ):

Я бы хотел увидеть эту функцию

подписка - тоже нужно это.

Мне это так нужно :(

То же самое! Мы используем машинописный текст с Vuejs, и наши файлы модульных тестов находятся не вместе в каталоге тестов, а повсюду в исходном коде компонентов.

Хотелось бы увидеть эту функцию, в настоящее время мы используем немного неудобную настройку, которая приводит к тому, что vscode выделяет ошибки линтинга, отличные от тех, что выделяет наша командная строка, чтобы обойти эту проблему.

Я очень сомневаюсь, что эта функция когда-либо будет реализована, tslint, похоже, в целом активно не поддерживается. Я предлагаю перейти на @typescript-eslint , он получил полную поддержку проектов eslint и ts, а миграция стала проще, чем когда-либо, с помощью @ typescript-eslint / eslint-plugin-tslint . И есть таблица совместимости с tslint и соответствующими правилами eslint / другими доступными альтернативами. Настройка Eslint отличается широкими возможностями настройки, поэтому я не вижу смысла придерживаться tslint.

Предлагаю применить концепцию, которую репозиторий git использует для файлов в .gitIgnore ... к правилам tsLint. Использование вашей текущей иерархической позиции в качестве контекста для линтера вместе с файлом переопределения при линтинге определенного подкаталога. Затем вы можете включить или исключить, настроить любую конфигурацию на любом уровне каталога, который хотите.

например
Конфигурация tslint помещается в корень, и на любом конкретном уровне в структуре исходного кода вам нужно другое поведение, просто переопределите его с помощью файла tslint расширения в корне этого подкаталога.

@redevill Это действительно помогает людям писать тесты в папке test . Но ни одного теста записи как something.test.ts в той же папке компонента / службы.

Согласовано, но с небольшими изменениями: (что можно автоматизировать с помощью генератора шаблонов (стиль CLI)
MyComponentDir
--- MyComponentTestsDir
------ tslint.test.json
------ something.test.ts
--- mycomponent.component.css
--- mycomponent.component.html
--- mycomponent.component.ts

Идея все еще могла работать.

Большой поклонник этого предложения. ДА, ПОЖАЛУЙСТА! Я бы предпочел концепцию Overrides.

Кстати, учитывая объявление о прекращении поддержки tslint, я не могу реально представить, что на этом этапе будет сделано такое большое изменение, и моя команда переходит на eslint, который уже имеет средства переопределения для каждого правила + для каждого файла.

Вышеупомянутое объявление: https://medium.com/palantir/tslint-in-2019-1a144c2317a9

@RoystonS в основном прав, такая большая функция не будет добавлена ​​в tslint на данном этапе. см. # 4534

Мы используем проект Angular. Нам нужна концепция переопределения. Иначе будет больно управлять

Была ли эта страница полезной?
0 / 5 - 0 рейтинги