fimbullinter / wotan

Pluggable TypeScript and JavaScript linter
Apache License 2.0
281 stars 23 forks source link

Rethink configuration #635

Open ajafff opened 5 years ago

ajafff commented 5 years ago

Use a single wotan.config.<ext> that is loaded at startup. No longer use a different config per file/directory. That can be configured via overrides. This new config is searched upwards in the directory tree starting at the current directory. <ext> can be:

TBD: how to enable the old per-directory config of TSLint (and ESLint?)-compat plugins? Is that even necessary?

Get rid of .fimbullinter.yaml. CLI defaults are now part of the new wotan.config.<ext>.

Plugins are specified in the config as code. There's no more -m CLI option. TBD: do we even need plugins at the moment?

-c can be used to explicitly use a specific config and avoid the lookup.

Maybe it could be possible to specify multiple subcommands that are run in sequence. Possible separator ---: wotan lint -p tsconfig.json --- tslint -e '**/*.d.ts' --- eslint -e '**/*.js'

Treat overrides (almost) the same as top-level config: allow extends, rulesDirectories, overrides (needs to handle arbitrary nesting), ...

extends can contain strings as module names or objects of the extended configs. That allows converting foreign configs inline.

Configurations should be responsible to load/provide rules, formatters and processors. The rule loader can optionally return a different RuleExecutor (will be used by Linter to execute all matching rules). That allows executing all ESLint rules together rather than wrapping and executing them individually.

extends: [
  'wotan:recommended',
  loadTslintConfig('tslint-consistent-codestyle', 'tcc'), // convert TSLint config with prefix 'tcc', this replaces @fimbul/heimdall
],
definitions: {
  identifier: 'foo',
  // provide rules directory
  rules: 'rules-directory',
  // or provide the implementations
  rules: {
    baz: BazRule,
  },
  // or implement a loader. TBD: is this allowed to be async?
  rules: (name: string) => require('./rules/directory/' + name),
  processors: 'processors-dir', // same as 'rules'
  formatters: 'formatters-dir', // same as 'rules'
  // aliases are moved here; they were not documented anyway
  aliases: {
    bar: 'foo/baz'
  }
},
rules: {
  'foo/bar': 'warn', // alias redirects to implementation of 'foo/baz'
  'foo/baz': 'error',
}
ajafff commented 5 years ago

To avoid too much breakage for existing configs, if there's no wotan.config.<ext>, but a .wotanrc.<ext>, use that and convert it to the new config format (and also search for .fimbullinter.yaml). Print a deprecation warning. Offer a subcommand that migrates an existing config to the new format.

ajafff commented 5 years ago

Some more thoughts:

ajafff commented 5 years ago

Regarding automatic prefixing: this is probably not the best option. The full-compat (@fimbul/valtyr) configs should not prefix anything. Instead configs should be able to provide declarations in the default namespace. If the lookup for a builtin declaration reaches a root config that has no loader for the default namespace it falls back to the builtin loader. Multiple loaders of the default namespace can coexist. They are executed in reverse order (from child to parent, latest parent first - just like everything else in the config) until the declaration is found. In order to allow full-compat configs together with builtin Wotan declarations, you can extend wotan:core which contains the loader for builtin declarations.

Executing rules of different engines and reporting all of them Wotan findings makes it difficult for users to know which line switch to use. There should be a way to mark findings of rules executed with a different engine, e.g. ERROR foo.ts:1:1 no-empty(tslint) ... LanguageService suggestions should allow provide a quick fix with the correct disable comment.

ajafff commented 5 years ago

Some more thoughts: