Skip to content

Latest commit

 

History

History
135 lines (87 loc) · 5.98 KB

Architecture.md

File metadata and controls

135 lines (87 loc) · 5.98 KB

Architecture

This document goes over how TypeStart runs and generates fixes. Before reading this, you should read:

Runtime

When the typestat command is entered into the CLI, roughly the following happens in order:

  1. bin/typestat calls to the CLI
  2. Commander.js parses the CLI's arguments
  3. Settings are loaded from the -c/--config file
  4. An Automutator provider is created for TypeStat with createTypeStatMutationsProvider.

Mutation Providers

There are three mutation providers that are run in order by createTypeStatMutationsProvider:

  1. Require renames: changes to import and require statements from files.renameExtensions
  2. Core mutations: changes to type annotations in provided files
  3. Files modified: adds annotations to the top (files.above) and/or bottom (files.below) of mutated files if enabled

Require Renames

If any require to a file including the extension is stored as a variable, and files.renameExtensions is enabled, that variable will be given a type equivalent to the extensionless equivalent. This is done as a separate mutation provider before the core mutations to ensure these mutations are applied before core mutations.

import declarations cannot be given different types, so they are ignored.

Core Mutations

Each round of mutations in the core mutation provider roughly:

  1. Records the starting time
  2. Creates a set of TypeScript language services
  3. For each file to be visited:
    1. Retrieves file mutations for that file
    2. If more than 100 mutations have been collected, or mutations have been collected and it's been more than 10 seconds since the round started, stops the round

Subsequent rounds will pick up where the previous round left off. For example, given files a.ts, b.ts, and c.ts in order, if the first round runs on a.ts and b.ts, the second will start on c.ts.

Rounds stop after those thresholds to allow Automutate to write mutations regularly. TypeStat crashing before a round is complete shouldn't lose all accumulated mutations.

Once TypeStat has visited each file, it will either:

  • Stop if no file had mutations applied
  • Restart (and reload language services) if any file had mutations applied

File Mutations

For each file it visits, findMutationsInFile will attempt to apply built-in file mutators:

Each fixer targets a general range of potential type improvements and contains a series of sub-fixers that target individual improvements. For example, fixIncompleteTypes contains a fixIncompleteParameterTypes fixer that fills in incomplete types for parameters.

Within each round of applying mutations, TypeStat will stop looking at a file after each step if any mutations are found. Adding mutations from one from can improve mutations from other forms, so reloading the file between rounds could reduce the number of later rounds.

See Fixes.md.

Directory Structure

The following directories exist under src/:

logging

Definition and default implementation of the logger for runtime. It wraps process.stderr and process.stdout and is given to the runtime mutators as a member of options.

During tests, it'll be stubbed out.

mutators

A file for each of the forms of mutation run in a round. These are stored in the above fastest-first order in the exported builtInFileMutators array.

mutations

Called by the mutators to create mutations. The mutators directory figures out which types should be modified, then mutations creates mutations to modify them.

We should note two common pieces of terminology used in this directory:

  • "Flags" refers to type nodes for primitive types, such as boolean
  • "Types" refers to rich (non-primitive) types, such as MyClass

options

Parsing logic and TypeScript types for raw and parsed options.

loadOptions will require a -c/--config file from the path provided. Options parsed from that file will be of type RawTypeStatOptions, and will be filled out into TypeStatOptions via fillOutRawOptions.

runtime

Automutate hooks that launch and run the processes described above. Think of this area as the coordinating force behind mutators.

services

Creates wrappers around the TypeScript Compiler API later used by mutators. These include the TypeScript Language Service API.

Language services are passed to mutators in the form of a LanguageServices object. They're recreated each mutations wave, as the underlying TypeScript source files generally change between wave.

shared

Miscellaneous utilities used by other sections.

Why Not jscodeshift?

When I started on TypeStat, jscodeshift didn't yet support TypeScript. Now it does. Maybe this should be converted?

See #20.