Skip to content

Refactored converters to have names match intent #714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
Sep 20, 2020
  •  
  •  
  •  
68 changes: 0 additions & 68 deletions docs/Architecture.md

This file was deleted.

22 changes: 22 additions & 0 deletions docs/Architecture/Comments.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Comments

Comment conversions in `src/converters/comments/convertComments.ts` are the last root-level converter to be run.
The `ruleEquivalents` map it receives is filled out with the rule equivalents from earlier converters, i.e. lint rule converters.

In general, its flow is:

1. If no comments are requested to be converted, immediately report it out and mark this as passed.
2. Create the list of include and possibly exclude globs to search on.
3. Search for files matching those globs to have their comments converted.
4. Convert comments in the contents of each file, storing equivalents in a cache.
5. Report out the results of converting the unique globbed file paths.

## File Manipulations

Source files are parsed into TypeScript files by `src/comments/parseFileComments.ts`, which then extracts their comment nodes.
Those comments are parsed for TSLint rule disable or enable comments.

Comments that match will be rewritten in their their file to their new ESLint rule equivalent in `src/comments/replaceFileComments.ts`, as determined by:

1. First, if the `ruleEquivalents` cache received from configuration convertion has the TSLint rule's ESLint equivalents listed, those are used.
2. Failing that, a comment-specific `ruleCommentsCache` is populated with rules converted ad-hoc with no arguments.
13 changes: 13 additions & 0 deletions docs/Architecture/Editors.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Editors

Editor lint configurations are converted by `src/converters/editorConfigs/convertEditorConfig.ts`.
Any setting that matches a known built-in TSLint setting will be replaced with the ESLint equivalent.

For now, only VS Code editor settings are accounted for.
Eventually this will be refactored to allow other editors such as Atom.

1. An existing editor configuration is read from disk.
2. If the existing configuration is not found or errored, nothing else needs to be done.
3. Configuration settings are converted to their ESLint equivalents.
4. Those ESLint equivalents are written to the configuration file.
5. Results from converting are reported to the user.
57 changes: 57 additions & 0 deletions docs/Architecture/Linters.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
# Linters

TSLint-to-ESLint linter configuration conversion is the first root-level converter run.
Within `src/converters/lintConfigs/convertLintConfig.ts`, the following steps occur:

1. Raw TSLint rules are mapped to their ESLint equivalents.
2. Those ESLint equivalents are deduplicated and relevant preset(s) detected.
3. Those deduplicated rules and metadata are written to the output configuration file.
4. A summary of conversion results is printed, along with any now-missing packages.

## Rule Conversion

The parts of linter configurations most users focus on are the rule converters.
Those are run by `src/converters/lintConfigs/rules/convertRules.ts`, which takes the following steps on each original TSLint rule:

1. The raw TSLint rule is converted to a standardized format.
2. The appropriate converter is run for the rule.
3. If the rule is missing or the conversion failed, this is marked.
4. For each output rule equivalent given by the conversion:
* The output rule name is added to the TSLint rule's equivalency set.
* The TSLint rule's config severity is mapped to its ESLint equivalent.
* If this is the first time the output ESLint rule is seen, it's directly marked as converted.
* If not, a rule merger is run to combine it with its existing output settings.

### Rule Converters

Each TSLint rule should output at least one ESLint rule as the equivalent.
"Converters" for TSLint rules are located in `src/rules/converters/`, and keyed under their names by the map in `src/rules/converters.ts`.

Each converter for a TSLint rule takes an arguments object for the rule, and returns an array of objects containing:

- `rules`: At least one equivalent ESLint rule and options
- `notices`: Any extra info that should be printed after conversion
- `plugins`: Any plugins that should now be installed if not already

The `rules` output is an array of objects containing:

- `ruleName`: Equivalent ESLint rule name that should be enabled
- `ruleArguments`: Any arguments for that ESLint rule

Multiple objects must be supported because some general-use TSLint rules can only be represented by two or more ESLint rules.
For example, TSLint's `no-banned-terms` is represented by ESLint's `no-caller` and `no-eval`.

### Rule Mergers

It's possible that one ESLint rule will be output by multiple converters.
"Mergers" for those ESLint rules should take in two configurations to the same rule and output the equivalent single configuration.
These are located in `src/rules/mergers/`, and keyed under their names by the map in `src/rules/mergers.ts`.

For example, `@typescript-eslint/ban-types` spreads both arguments' `types` members into one large `types` object.

## Package Summaries

ESLint configurations are summarized based on extended ESLint and TSLint presets.

- If no output rules conflict with `eslint-config-prettier`, it's added in.
- Any ESLint rules that are configured the same as an extended preset are trimmed.
26 changes: 26 additions & 0 deletions docs/Architecture/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Architecture

tslint-to-eslint-config is a heavily tested CLI app with application flow starting in `bin/tslint-to-eslint-config`:

1. `src/cli/main.ts`'s `main` is called with `process.argv` as the program arguments.
* This file sets up all function dependencies and bound functions that call to each other.
2. `src/cli/runCli.ts`'s `runCli` is called with those bound dependencies and raw arguments.

> See [Dependencies.md](./Dependencies.md) for more info on functions and their dependencies are bound together.

## CLI Runner

Within `runCli`:

1. CLI options are parsed from the raw arguments into a commands object.
2. If the version should be printed, we do that and stop execution.
3. Any existing linter and TypeScript configurations are read from disk.
4. Each converter is run, halting execution if it fails.

### Converters

Within that flow, there are three "root-level" converters directly called by `runCli`, in order:

1. **[Linters.md](./Linters.md)**: Converting from an original TSLint configuration to the equivalent TSLint configuration.
2. **[Editors.md](./Editors.md)**: Creating new IDE settings for ESLint equivalent to any existing TSLint settings.
3. **[Comments.md](./Comments.md)**: Converting inline `tslint:disable` lint disable comments to their `eslint-disable` equivalents.
5 changes: 5 additions & 0 deletions docs/Dependencies.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,3 +62,8 @@ Suppose your method `myMethod`, should take in a `fileSystem`, a `string`, and a
myMethod: SansDependencies<typeof myMethod>;
};
```

### Adapters

Global Node constructs as `console` are never written to directly by functions; instead, "adapter" wrappers are set up in `src/adapters/*.ts` and provided as dependencies to functions.
This enables native calls to be directly tested in tests without stubbing out their global equivalents.
2 changes: 1 addition & 1 deletion docs/Development.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@ Compile with `npm run tsc` and run tests with `npm run test`.

## Further Reading

- [Architecture](./Architecture.md): How the general app structure operates
- [Architecture](./Architecture/README.md): How the general app structure operates
- [Dependencies](./Dependencies.md): How functions pass and receive static dependencies
- [Testing](./Testing.md): Unit tests
6 changes: 3 additions & 3 deletions jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ module.exports = {
"!./src/**/*.d.ts",
"!./src/**/*.stubs.ts",
"!./src/adapters/*.ts",
"!./src/rules/rulesConverters.ts",
"!./src/editorSettings/editorSettingsConverters.ts",
"!./src/rules/mergers.ts",
"!./src/cli/main.ts",
"!./src/converters/editorConfigs/editorSettingsConverters.ts",
"!./src/converters/lintConfigs/rules/ruleConverters.ts",
"!./src/converters/lintConfigs/rules/ruleMergers.ts",
],
coverageThreshold: {
global: {
Expand Down
Loading