/flow-jsdoc

Use JSDoc to represent Flow annotations

Primary LanguageJavaScriptApache License 2.0Apache-2.0

flow-jsdoc

Build Status

This is a CLI tool to convert JSDoc annotations into standard Flow type annotations. This means:

  • You only need to document your types once: in JSDoc.
  • You can get the benefits of Flow without having to go through a transpiler, and without having to use ugly looking comment syntax.
  • You can do tiny in-line type comments for those functions which don't have JSDoc but you still want types.
// Converts this:

/**
 * @param {Foobar[]} bar A foobar array
 * @param {Function} baz
 * @return {number}
 */
function foo(bar, baz) {
    return 42;
}

// Into this:

/**
 * @param {Foobar[]} bar A foobar array
 * @param {Function} baz
 * @return {number}
 */
function foo(bar: Array<Foobar>, baz: Function) : number {
    return 42;
}

Furthermore, a short in-line style is also supported:

// Converts this:

//: (string, number) : Object
function foo(a, b) {
  return {};
}

// Into this:

function foo(a: string, b: number) : Object {
  return {};
}

// NB: The ":" at the start of the comment is REQUIRED.
// NBB: The in-line comment is REMOVED in the output to avoid Flow re-interpreting it..

The goal of this project is to make type checking as easy as running a linter, so you can take any project and run the following to get type errors:

 $ flow-jsdoc -d ./lib -o ./annotated
 $ flow check --all ./annotated

Usage

This tool will NOT apply /* @flow */ to the file. You still need to do that!

CLI

 $ npm install -g flow-jsdoc
 $ flow-jsdoc -f path/to/file.js
# annotated file prints to stdout

 $ flow-jsdoc -d path/to/lib -o path/to/output
# every file in path/to/lib is processed and output to path/to/output (directory structure preserved)

JS

 var flowJsdoc = require("flow-jsdoc");
 var fileContents = // extract your file contents e.g. via 'fs' - this should be a string
 var opts = {
 // no options yet!
 };
 var annotatedContents = flowJsdoc(fileContents, opts);
 // write out annotated contents to file

What this does

Currently, this tool will only work on functions and ES6 classes. It will handle functions represented in the following ways:

  • function foo(bar) {}
  • var foo = function(bar) {}
  • var obj = { foo: function(bar) {} }
  • ObjClass.prototype.foo = function(bar) {} - ES5 Classes
  • class ObjClass { foo(bar) {} } - ES6 Classes
  • (foo, bar) => { } - ES6 "fat arrow" functions

For each recognised function, the JSDoc tags @param and @return will be mapped to Flow annotations. This will currently do the following mappings from JSDoc to Flow:

  • {AnyThingHere} => : AnyThingHere (Name expressions)
  • {String[]} => : Array<String> (Type applications)
  • {*} => : any (Any type)
  • {Object|String} => : Object | String (Type unions)
  • {string=} => : ?string (Optional params)
  • {?string} => : ?string (Nullable types)

ES6 classes will include field declarations via the @prop and @property tags like so:

// Converts this ES6 Class:

class Foo {
  /**
   * Construct a Foo.
   * @property {string} bar
   * @prop {number} baz
   */
  constructor(bar, baz) {
    this.bar = bar;
    this.baz = baz;
  }
}

// Into this:

class Foo {
  bar: string;
  baz: number;

  /**
   * Construct a Foo.
   * @property {string} bar
   * @prop {number} baz
   */
  constructor(bar, baz) {
    this.bar = bar;
    this.baz = baz;
  }
}

This tool will then produce the whole file again with flow annotations included (JSDoc preserved).

Additions

There are plans for this tool to (roughly in priority order):

  • Handle record types {{a: number, b: string, c}}
  • Auto-require()ing types you reference in other files if you don't import them yourself. When you start type-annotating, sometimes you'll declare a type that is defined in another file but you won't need to require() it manually (e.g. because it's just passed as a function argument). Flow needs to know where the type is declared, so you need to import it somehow even if it's a no-op in the code. This tool should be able to automatically do this.
  • Handle type definitions @typedef
  • Handle callback type resolution (mapping @callback sensibly)