Tslint: 建议:有条件的 lint 配置

创建于 2017-11-03  ·  42评论  ·  资料来源: palantir/tslint

在某些情况下,我们希望根据被 lint 的代码是否是测试代码有条件地强制执行 lint 检查。 例如,我们想禁止生产代码中的“any”,因为它不安全。 但是在测试中,'any' 可用于提供服务的虚假或模拟实现,或通过它进行转换以便您可以调用私有方法。 或者,例如,我们可能希望在测试和生产代码中禁止一组不同的方法。

我提出的是一种基于文件名上的正则表达式匹配有条件地启用 lint 检查的方法。 这对于关闭某些目录(例如包含“遗留”代码)或 .tsx 或 .d.ts 文件等的 lint 检查也很有用。

这里有一些语法稻草人的想法; 我也愿意接受建议。

部分对象

{
  "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';

这条路径在我们的 monorepo 中变得丑陋,其中文件通常位于树的深处。

或者你有

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

当文件路径包含“spec”时,规则“foo”的值为 2,如果包含“test”则为 3,否则为 1。 (显然,这不是一组非常有用的覆盖,因为“测试”也可以从第一个中省略,但您明白了)

这是否有意义并回答您的问题?

@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" )。 如果其中之一匹配,则配置适用
  • 您可以通过 glob 模式排除文件: "excludedFiles"
  • glob 模式与它们在其中指定的配置文件相关
  • glob 模式总是需要匹配整个路径,而不仅仅是基本名称
  • 覆盖按顺序处理,覆盖前一个
  • 扩展配置文件时,在继续扩展配置之前完全评估基本配置

    • base.json/规则

    • base.json/覆盖

    • 扩展.json/规则

    • 扩展.json/覆盖

将此行为移植到 TSLint 时需要考虑一些事项:

  • 我们绝对应该在覆盖中禁用extendslinterOptions
  • 我们可能还想禁止rulesDirectory
  • 我们是要允许rulesjsRules覆盖还是弃用jsRules以支持**/*.js?(x)覆盖?

想法或评论@adidahiya @calebegg @alexeagle @minomikula?

哦,哇,是的,这种方法对我来说似乎是合理的。 我也应该寻找现有技术。

这将是一个很棒的补充! eslint 方法在有条件地禁用测试文件中的某些规则时效果很好。

@calebegg你还打算在有时间的时候推动这个吗?

是的,我绝对想从事这方面的工作。 @ajafff您是否对从 ESLint 方法开始并在 PR 中迭代感到满意? 或者您认为我们应该首先讨论哪些设计问题?

我们是要允许规则和 jsRules 覆盖,还是弃用 jsRules 以支持*/ .js?(x) 覆盖?

弃用对我来说是有道理的,但无论如何我都没有强烈的感觉。

@calebegg我对 ESLint 方法没问题。 我在我的 POC linter 运行时实现了一个非常相似的概念https://github.com/fimbullinter/wotan/tree/master/packages/wotan#overrides

在当前的 TSLint API 中集成可能很困难,因为当前它在解析时合并所有配置。 这需要推迟到文件名已知并且需要为每个文件完成。

这无疑是一个突破性的 API 更改。

@calebegg @mitchlloyd @ajafff @alexeagle我认为这个功能比简单地嵌套tslint.json文件来覆盖外部配置没什么好处。 该功能今天已经可以使用,并且不需要任何复杂的 API 中断。 如果我们拒绝了这个请求,你会生气吗?

嵌套不能解决这里讨论的问题。 许多人确实希望他们的测试与它测试的代码在相同的目录结构中,而现在用 tslint 根本没有好的方法来做到这一点。

有大量项目将规范文件与源文件放在同一目录中。 这已成为许多环境中的最佳实践,Angular CLI 生成类似的项目结构等。我认为嵌套 tslint 配置文件对所有这些人都不起作用是现实的。

我同意我的项目结构不应该由 linting 工具决定。 相反,linting 工具应该支持常见的现有模式。 并置测试和源文件是一种常见的模式。

@giladgray请求的更改支持这样一种场景:用户将他们的测试和生产文件放在一起,如下所示:

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

当我们希望my-component.tsmy-component.test.ts不同的规则时,“嵌套tslint.json文件”如何解决这个用例?

@giladgray角度指南建议您将测试与文件放在一起。 所以 99% 的 Angular 项目都是这样做的。 由于 tslint 向后,我参与的每个 Angular 项目都有问题。 你最后的评论令人困惑和短视。 如果你不能/不想接受这个非常有用的建议,那么我认为你太保守了,不能为我们这样一个重要的项目做决定。 多年来,这个问题一直使我们的 angular 项目难以工作。

@ohjames让我们继续讨论话题,避免转向人身攻击,好吗? 建议某人不适合维护自己的项目并不是影响 OSS 的方式,当然也不会帮助我们在这里争论的内容。

需要覆盖不适合上述嵌套结构的文件是有意义的。 在我看来, @giladgray的评论是为了确定社区是否仍然对此更改有重大兴趣,因为已经超过 6 个月没有关于此问题的活动了。 他对公开 PR (#3708) 的评论特别证明了这一点:

如果您确实想继续这样做,请更新此分支,以便我们对其进行审核,如果不再相关,则将其关闭。 如果我们在两周内没有收到您的来信,我们将关闭它。

@ohjames我建议你重新考虑你的评论——正如@DanielSchaffer提到的,人身攻击在这里或开源软件的任何地方都不会帮助你。 每个人都在尽最大努力创造优秀、可靠且功能丰富的软件,而攻击他人对这没有任何帮助。

是否有关于此主题的更新?
@ajafff在他的总结性评论中提出的想法似乎是合理的,可以满足各种需求。 使用与 eslint 相同的语义是一个很好的前进方向。

正如我在相关的 #1063 上评论的那样,我的用例是使用 tslint-microsoft-contrib 目前会针对某些规则对 Vue 单文件组件进行轰炸。 这可能是 Vue 问题,也可能是 TSLint 问题,这些团队可能会或可能不会解决特定问题 - 在发生这种情况之前禁用违规规则似乎是一个不太麻烦的简单解决方法。 与必须向每个 .vue 文件添加相同的禁用指令,并在规则支持更改时在所有这些位置更新它相比。 将项目拆分为 .vue 和 .ts 文件也没有意义,这将是一个非常尴尬的结构。

我赞成这个特性的出现。也许我们还可以通过允许一些覆盖完全禁用所有规则来干净地解决 #73 中的 tslintignore 请求?

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

tslint-microsoft-contrib 目前针对某些规则轰炸 Vue 单文件组件

哦😕 @millimoose你能在 tslint-microsoft-contrib 上提出问题吗?

@JoshuaKGoldberg - 我已经在 @vuejs/vue-cli 中详细报告了该错误,这似乎是最合适的。 (它被标记为“等待复制”,所以我猜它并没有完全不合适。)我刚刚提到它是作为在这里插话的动力。 这是一种可以而且将会在不断发展的生态系统中产生的东西,这应该是一个论据,即工具足够灵活,可以绕过障碍,而无需实际编写针对他人错误的黑客攻击。

关于这个问题的任何更新?

这个问题目前被标记为“需要提案”,但我认为我们已经在https://github.com/palantir/tslint/issues/3447#issuecomment -344020834 中提出了一个提案?

@RoystonS @ajafff的提案提到了一些应该解决的松散问题:

将此行为移植到 TSLint 时需要考虑一些事项:

  • 我们绝对应该在覆盖中禁用extendslinterOptions
  • 我们可能还想禁止rulesDirectory
  • 我们是要允许rulesjsRules覆盖,还是弃用jsRules以支持**/*.js?(x)覆盖?

在继续之前,palantirtech 组织中的人们也应该就此达成共识,因为这是一个非常重要的功能。

我自己偶然发现了这个,只是想表达我对这种功能的兴趣。

我们最终放宽了一些影响生产代码的 linting 规则,让我们看看它是如何进行的。 ):

我很想看到这个功能

订阅 - 也需要这个。

我非常需要这个:(

同样在这里! 我们在 Vuejs 中使用 typescript,我们的单元测试文件不在测试目录中,而是在组件源代码中随处可见。

很想看到这个功能,我们目前正在使用一个稍微不稳定的设置,导致 vscode 突出显示不同的 linting 错误,而不是我们的命令行 lint 突出显示来解决这个问题。

我非常怀疑这个功能是否会被实现,tslint 似乎没有得到积极维护。 我建议切换到@typescript-eslint ,它得到了 eslint 和 ts 项目的全面支持,并且使用@typescript-eslint/eslint-plugin-tslint迁移比以往任何时候都容易。 并且有一个带有 tslint 和相应 eslint 规则/其他可用替代方案的兼容表。 Eslint 设置是高度可定制的,所以我认为坚持使用 tslint 没有任何意义。

我建议将 git 存储库用于 .gitIgnore... 中的文件的概念应用于 tsLint 规则。 在对特定子目录进行 linting 时,将当前的层次位置用作 linter 的上下文以及覆盖文件。 然后您可以包含或排除,在您想要的任何目录级别设置任何配置。

例如
tslint 配置放置在根目录中,并且在源代码结构中的任何特定级别,您想要不同的行为,只需在该子目录的根目录中使用扩展 tslint 文件覆盖它即可。

@redevill它确实帮助人们在test文件夹中编写测试。 但不是在组件/服务的同一文件夹中将测试编写为something.test.ts

同意 - 但有细微的变化:(可以使用模板生成器(CLI 样式)自动化)
我的组件目录
---MyComponentTestsDir
------tslint.test.json
------something.test.ts
---mycomponent.component.css
---mycomponent.component.html
---mycomponent.component.ts

这个想法仍然可行。

这个提议的忠实拥护者。 是的,请! 我的偏好是 Overrides 概念。

顺便说一句,鉴于 tslint 的弃用公告,我无法_真的_想象在这个阶段会发生如此大的变化,而我的团队正在转向 eslint,它已经具有按规则 + 按文件覆盖的设施。

上述公告: https :

@RoystonS基本是对的,这么大的功能此时不会加入tslint。 见#4534

我们使用 Angular 项目。 我们需要覆盖概念。 否则管理起来很痛苦

此页面是否有帮助?
0 / 5 - 0 等级