Merge pull request #55 from documentationjs/infer-kind-from-ast

More intense kind inference
This commit is contained in:
Tom MacWright 2015-04-13 17:59:54 -07:00
commit 2245016d60
10 changed files with 1760 additions and 25 deletions

View File

@ -1,6 +1,10 @@
'use strict';
var through = require('through');
var through = require('through'),
types = require('ast-types');
var kindShorthands = ['class', 'constant', 'event', 'external', 'file',
'function', 'member', 'mixin', 'module', 'namespace', 'typedef'];
/**
* Create a transform stream that attempts to infer a `kind` tag from other
@ -18,17 +22,45 @@ module.exports = function () {
}
if (!hasTag('kind')) {
['class', 'constant', 'event', 'external', 'file',
'function', 'member', 'mixin', 'module', 'namespace', 'typedef'].forEach(function (kind) {
if (hasTag(kind)) {
comment.tags.push({
title: 'kind',
kind: kind
});
}
});
}
for (var i = 0; i < kindShorthands.length; i++) {
var kind = kindShorthands[i];
if (hasTag(kind)) {
comment.tags.push({
title: 'kind',
kind: kind
});
// only allow a comment to have one kind
this.push(comment);
return;
}
}
types.visit(comment.context.ast, {
setKind: function (kind) {
comment.tags.push({
title: 'kind',
kind: kind
});
this.abort();
},
visitFunction: function (path) {
if (path.value && path.value.id && path.value.id.name && !!/^[A-Z]/.exec(path.value.id.name)) {
this.setKind('class');
} else {
this.setKind('function');
}
},
visitVariableDeclaration: function (path) {
if (path.value.kind === 'const') {
this.setKind('constant');
} else {
this.traverse(path);
}
}
});
}
this.push(comment);
});
};

View File

@ -216,7 +216,7 @@ module.exports = function (opts) {
this.push(new File({
path: 'index.json',
contents: new Buffer(JSON.stringify(comments), 'utf8')
contents: new Buffer(JSON.stringify(comments, null, 2), 'utf8')
}));
this.push(new File({

View File

@ -14,6 +14,10 @@
"title": "name",
"name": "exports"
},
{
"title": "kind",
"kind": "function"
},
{
"title": "memberof",
"description": "module"
@ -47,6 +51,7 @@
}
],
"name": "exports",
"kind": "function",
"memberof": "module",
"scope": "static"
},
@ -77,6 +82,10 @@
{
"title": "name",
"name": "returnTwo"
},
{
"title": "kind",
"kind": "function"
}
],
"context": {
@ -117,6 +126,7 @@
"examples": [
"var result = returnTwo(4);\n// result is 6"
],
"name": "returnTwo"
"name": "returnTwo",
"kind": "function"
}
]

View File

@ -13,6 +13,10 @@
{
"title": "name",
"name": "multiply"
},
{
"title": "kind",
"kind": "function"
}
],
"context": {
@ -39,6 +43,7 @@
}
}
],
"name": "multiply"
"name": "multiply",
"kind": "function"
}
]

File diff suppressed because it is too large Load Diff

View File

@ -14,6 +14,10 @@
"title": "name",
"name": "exports"
},
{
"title": "kind",
"kind": "function"
},
{
"title": "memberof",
"description": "module"
@ -47,6 +51,7 @@
}
],
"name": "exports",
"kind": "function",
"memberof": "module",
"scope": "static"
}

View File

@ -26,6 +26,10 @@
{
"title": "name",
"name": "returnTwo"
},
{
"title": "kind",
"kind": "function"
}
],
"context": {
@ -66,6 +70,7 @@
"examples": [
"var result = returnTwo(4);\n// result is 6"
],
"name": "returnTwo"
"name": "returnTwo",
"kind": "function"
}
]

View File

@ -14,6 +14,10 @@
"title": "name",
"name": "exports"
},
{
"title": "kind",
"kind": "function"
},
{
"title": "memberof",
"description": "module"
@ -47,6 +51,7 @@
}
],
"name": "exports",
"kind": "function",
"memberof": "module",
"scope": "static"
}

View File

@ -1,5 +1,5 @@
'use strict';
/*eslint-disable no-unused-vars*/
var test = require('prova'),
concat = require('concat-stream'),
parse = require('../../streams/parse'),
@ -20,6 +20,20 @@ function evaluate(fn, callback) {
});
}
function evaluateString(string, callback) {
var stream = parse();
stream
.pipe(inferKind())
.pipe(flatten())
.pipe(concat(callback));
stream.end({
file: __filename,
source: string
});
}
test('inferKind - explicit', function (t) {
evaluate(function () {
/** @kind class */
@ -149,3 +163,67 @@ test('inferKind - typedef', function (t) {
t.end();
});
});
test('inferKind - context: function', function (t) {
evaluate(function () {
/**
* @returns {number} two
*/
function foo() {
}
foo();
}, function (result) {
t.equal(result[0].kind, 'function');
t.end();
});
});
test('inferKind - context: var function', function (t) {
evaluate(function () {
/**
* @returns {number} two
*/
var foo = function () {
};
}, function (result) {
t.equal(result[0].kind, 'function');
t.end();
});
});
test('inferKind - context: class (uppercase function)', function (t) {
evaluate(function () {
/**
* @returns {number} two
*/
function Foo() {
}
}, function (result) {
t.equal(result[0].kind, 'class');
t.end();
});
});
test('inferKind - context: const', function (t) {
evaluateString(
'/**' +
' * This is a constant called foo' +
' */' +
'const foo = "bar";', function (result) {
t.equal(result[0].kind, 'constant');
t.end();
});
});
test('inferKind - no hint or ast', function (t) {
evaluate(function () {
/**
* @returns {number two
*/
return 0;
}, function (result) {
t.equal(result[0].kind, undefined);
t.end();
});
});

View File

@ -16,6 +16,7 @@ function normalize(result) {
result.forEach(function (item) {
item.context.file = path.relative(__dirname, item.context.file);
});
return result;
}
test('parse', function (tt) {
@ -59,8 +60,12 @@ test('html', function (tt) {
documentation([file])
.pipe(outputHtml())
.pipe(concat(function (result) {
var clean = result.map(function (r) {
return r.inspect();
var clean = result.sort(function (a, b) {
return a.path > b.path;
}).filter(function (r) {
return (!r.path.match(/json$/));
}).map(function (r) {
return r.contents;
}).join('\n');
var outputfile = file.replace('.input.js', '.output.files');
if (UPDATE) fs.writeFileSync(outputfile, clean, 'utf8');