From 6ccd0d22ec6f01e3e5ae70ca27d621a2dd157b0e Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Fri, 9 Sep 2016 19:23:49 -0700 Subject: [PATCH 1/3] Make findTarget return VariableDeclarator This is in preparation for inferring types for const/let/var. --- lib/infer/finders.js | 4 ++-- lib/infer/params.js | 6 ++++++ test/lib/infer/params.js | 16 ++++++++++++++++ 3 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/infer/finders.js b/lib/infer/finders.js index 791cb7afd..394f24ce6 100644 --- a/lib/infer/finders.js +++ b/lib/infer/finders.js @@ -22,9 +22,9 @@ function findTarget(path) { path = path.declaration; } - // var x = TARGET; + // var x = init; if (t.isVariableDeclaration(path)) { - return path.declarations[0].init; + return path.declarations[0]; } // foo.x = TARGET diff --git a/lib/infer/params.js b/lib/infer/params.js index 31278ac71..511a3a9b5 100644 --- a/lib/infer/params.js +++ b/lib/infer/params.js @@ -162,6 +162,12 @@ function inferParams() { return shouldSkipInference(function inferParams(comment) { var node = finders.findTarget(comment.context.ast); + // In case of `/** */ var x = function () {}` findTarget returns + // the declarator. + if (t.isVariableDeclarator(node)) { + node = node.init; + } + if (!t.isFunction(node)) { return comment; } diff --git a/test/lib/infer/params.js b/test/lib/infer/params.js index 4f48dae76..b318918c4 100644 --- a/test/lib/infer/params.js +++ b/test/lib/infer/params.js @@ -21,6 +21,22 @@ test('inferParams', function (t) { function f(x) {} }).params, [{lineNumber: 3, name: 'x', title: 'param'}]); + t.deepEqual(evaluate(function () { + /** Test */ + var f = function (x) {}; + }).params, [{lineNumber: 3, name: 'x', title: 'param'}]); + + t.deepEqual(evaluate('/** Test */ var f = (x) => {}').params, + [{lineNumber: 1, name: 'x', title: 'param'}]); + + t.deepEqual(evaluate(function () { + var x = 1, + g = function (y) {}, + /** Test */ + f = function (x) {}; + }).params, [{lineNumber: 5, name: 'x', title: 'param'}]); + + t.deepEqual(evaluate('/** Test */ export function f(x) {}').params, [{lineNumber: 1, name: 'x', title: 'param'}]); From 4f4877fd6851bfb74c1ff778f6e91d95c0bc78c3 Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Fri, 9 Sep 2016 19:08:17 -0700 Subject: [PATCH 2/3] Infer type for variable declarations and class properties This infers the type from Flow type annotations for variable declarations and class properties. This also moves the logic for setting the `type` for typedefs to the same type inferrer. --- index.js | 6 +-- lib/infer/type.js | 46 ++++++++++++++++++++ lib/infer/typedef_type.js | 27 ------------ test/lib/infer/{typedef_type.js => type.js} | 48 +++++++++++++++++++-- 4 files changed, 94 insertions(+), 33 deletions(-) create mode 100644 lib/infer/type.js delete mode 100644 lib/infer/typedef_type.js rename test/lib/infer/{typedef_type.js => type.js} (56%) diff --git a/index.js b/index.js index 180f3d95d..570a5a925 100644 --- a/index.js +++ b/index.js @@ -20,7 +20,7 @@ var fs = require('fs'), inferMembership = require('./lib/infer/membership'), inferReturn = require('./lib/infer/return'), inferAccess = require('./lib/infer/access'), - inferTypedefType = require('./lib/infer/typedef_type'), + inferType = require('./lib/infer/type'), formatLint = require('./lib/lint').formatLint, garbageCollect = require('./lib/garbage_collect'), lintComments = require('./lib/lint').lintComments, @@ -175,7 +175,7 @@ function buildSync(indexes, options) { inferProperties(), inferReturn(), inferMembership(), - inferTypedefType(), + inferType(), nest, options.github && github, garbageCollect); @@ -245,7 +245,7 @@ function lint(indexes, options, callback) { inferProperties(), inferReturn(), inferMembership(), - inferTypedefType(), + inferType(), nest); return expandInputs(indexes, options, function (error, inputs) { diff --git a/lib/infer/type.js b/lib/infer/type.js new file mode 100644 index 000000000..ee62ed252 --- /dev/null +++ b/lib/infer/type.js @@ -0,0 +1,46 @@ +'use strict'; + +var finders = require('./finders'), + shouldSkipInference = require('./should_skip_inference'), + flowDoctrine = require('../flow_doctrine'), + t = require('babel-types'); + +/** + * Infers type tags by using Flow type annotations + * + * @name inferType + * @param {Object} comment parsed comment + * @returns {Object} comment with type tag inferred + */ +module.exports = function () { + return shouldSkipInference(function inferType(comment) { + if (comment.type) { + return comment; + } + + var n = finders.findTarget(comment.context.ast); + if (!n) { + return comment; + } + + var type; + switch (n.type) { + case 'VariableDeclarator': + type = n.id.typeAnnotation; + break; + case 'ClassProperty': + type = n.typeAnnotation; + break; + case 'TypeAlias': + type = n.right; + break; + } + if (type) { + if (t.isTypeAnnotation(type)) { + type = type.typeAnnotation; + } + comment.type = flowDoctrine(type); + } + return comment; + }); +}; diff --git a/lib/infer/typedef_type.js b/lib/infer/typedef_type.js deleted file mode 100644 index b4cb10578..000000000 --- a/lib/infer/typedef_type.js +++ /dev/null @@ -1,27 +0,0 @@ -'use strict'; - -var shouldSkipInference = require('./should_skip_inference'), - flowDoctrine = require('../flow_doctrine'), - finders = require('./finders'); - -/** - * Infers the type of typedefs defined by Flow type aliases - * - * @name inferTypedefType - * @param {Object} comment parsed comment - * @returns {Object} comment with type tag inferred - */ -module.exports = function () { - return shouldSkipInference(function inferTypedefType(comment) { - if (comment.kind !== 'typedef') { - return comment; - } - - var flowAlias = finders.findTarget(comment.context.ast); - if (flowAlias && flowAlias.type === 'TypeAlias') { - comment.type = flowDoctrine(flowAlias.right); - } - - return comment; - }); -}; diff --git a/test/lib/infer/typedef_type.js b/test/lib/infer/type.js similarity index 56% rename from test/lib/infer/typedef_type.js rename to test/lib/infer/type.js index 070ec5ed6..451902232 100644 --- a/test/lib/infer/typedef_type.js +++ b/test/lib/infer/type.js @@ -3,7 +3,7 @@ var test = require('tap').test, parse = require('../../../lib/parsers/javascript'), inferKind = require('../../../lib/infer/kind')(), - inferTypedefType = require('../../../lib/infer/typedef_type')(); + inferType = require('../../../lib/infer/type')(); function toComment(code) { return parse({ @@ -12,10 +12,10 @@ function toComment(code) { } function evaluate(code) { - return inferTypedefType(inferKind(toComment(code))); + return inferType(inferKind(toComment(code))); } -test('inferTypedefType', function (t) { +test('inferType', function (t) { t.deepEqual(evaluate( '/** @typedef {T} V */' ).type, { @@ -64,6 +64,48 @@ test('inferTypedefType', function (t) { type: 'TypeApplication' }); + t.deepEqual(evaluate( + '/** */' + + 'var x: number' + ).type, { + name: 'number', + type: 'NameExpression' + }); + + t.deepEqual(evaluate( + '/** */' + + 'let x: number' + ).type, { + name: 'number', + type: 'NameExpression' + }); + + t.deepEqual(evaluate( + '/** */' + + 'const x: number = 42;' + ).type, { + name: 'number', + type: 'NameExpression' + }); + + t.deepEqual(evaluate( + 'let x,' + + '/** */' + + 'y: number' + ).type, { + name: 'number', + type: 'NameExpression' + }); + + t.deepEqual(evaluate( + 'class C {' + + '/** */' + + 'x: number;' + + '}' + ).type, { + name: 'number', + type: 'NameExpression' + }); t.end(); }); From 906f69d5a06c62cfca8689d5b542bddbc6a714df Mon Sep 17 00:00:00 2001 From: Erik Arvidsson Date: Sun, 11 Sep 2016 16:07:33 -0700 Subject: [PATCH 3/3] Also infer type from const initializer Infer the type for statements like: ```js const x = 42; ``` same as: ```js const x: number = 42; ``` --- lib/infer/type.js | 9 +++++++++ test/lib/infer/type.js | 24 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/lib/infer/type.js b/lib/infer/type.js index ee62ed252..d9b0004c1 100644 --- a/lib/infer/type.js +++ b/lib/infer/type.js @@ -5,6 +5,12 @@ var finders = require('./finders'), flowDoctrine = require('../flow_doctrine'), t = require('babel-types'); +var constTypeMapping = { + 'BooleanLiteral': {type: 'BooleanTypeAnnotation'}, + 'NumericLiteral': {type: 'NumberTypeAnnotation'}, + 'StringLiteral': {type: 'StringTypeAnnotation'} +}; + /** * Infers type tags by using Flow type annotations * @@ -27,6 +33,9 @@ module.exports = function () { switch (n.type) { case 'VariableDeclarator': type = n.id.typeAnnotation; + if (!type && comment.kind === 'constant') { + type = constTypeMapping[n.init.type]; + } break; case 'ClassProperty': type = n.typeAnnotation; diff --git a/test/lib/infer/type.js b/test/lib/infer/type.js index 451902232..6777d79dc 100644 --- a/test/lib/infer/type.js +++ b/test/lib/infer/type.js @@ -107,5 +107,29 @@ test('inferType', function (t) { type: 'NameExpression' }); + t.deepEqual(evaluate( + '/** */' + + 'const x = 42;' + ).type, { + name: 'number', + type: 'NameExpression' + }); + + t.deepEqual(evaluate( + '/** */' + + 'const x = "abc";' + ).type, { + name: 'string', + type: 'NameExpression' + }); + + t.deepEqual(evaluate( + '/** */' + + 'const x = true;' + ).type, { + name: 'boolean', + type: 'NameExpression' + }); + t.end(); });