2019-04-25 08:13:33 -07:00

1259 lines
22 KiB
JavaScript

const parse = require('../../src/parsers/javascript');
const remark = require('remark');
const visit = require('unist-util-visit');
function pick(obj, props) {
if (Array.isArray(props)) {
return props.reduce(function(memo, prop) {
if (obj[prop] !== undefined) {
memo[prop] = obj[prop];
}
return memo;
}, {});
}
return obj[props];
}
function evaluate(fn, filename) {
return parse(
{
file: filename || 'test.js',
source: fn instanceof Function ? '(' + fn.toString() + ')' : fn
},
{}
);
}
function addJSDocTag(tree) {
visit(tree, 'link', function(node) {
node.jsdoc = true;
});
return tree;
}
function removePosition(tree) {
visit(tree, function(node) {
delete node.position;
});
return tree;
}
test('parse - @abstract', function() {
expect(
evaluate(function() {
/** @abstract */
})[0].abstract
).toBe(true);
});
test('parse - @access', function() {
expect(
evaluate(function() {
/** @access public */
})[0].access
).toBe('public');
expect(
evaluate(function() {
/** @access protected */
})[0].access
).toBe('protected');
expect(
evaluate(function() {
/** @access private */
})[0].access
).toBe('private');
});
test('parse - @alias', function() {});
test('parse - @arg', function() {});
test('parse - @argument', function() {});
test('parse - @async', function() {
expect(
evaluate(function() {
/** @async */
})[0].async
).toBe(true);
});
test('parse - @augments', function() {
expect(
evaluate(function() {
/** @augments Foo */
})[0].augments[0].name
).toBe('Foo');
});
test('parse - @description', function() {
expect(
evaluate(function() {
/**
* This is a free-form description
* @description This tagged description wins, and [is markdown](http://markdown.com).
*/
})[0].description
).toEqual(
remark().parse(
'This tagged description wins, and [is markdown](http://markdown.com).'
)
);
});
/*
* Dossier-style augments tag
* https://github.com/google/closure-library/issues/746
*/
test('parse - @augments in dossier style', function() {
expect(
evaluate(function() {
/** @augments {Foo} */
})[0].augments[0].name
).toBe('Foo');
});
test('parse - @augments of complex passes through', function() {
expect(
evaluate(function() {
/** @augments {function()} */
})[0].augments
).toEqual([]);
});
test('parse - @author', function() {});
test('parse - @borrows', function() {});
test('parse - @callback', function() {
expect(
pick(
evaluate(function() {
/** @callback name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
name: 'name',
kind: 'typedef',
type: {
type: 'NameExpression',
name: 'Function'
}
});
});
test('parse - @class', function() {
expect(
pick(
evaluate(function() {
/** @class */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'class'
});
expect(
pick(
evaluate(function() {
/** @class name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
name: 'name',
kind: 'class'
});
expect(
pick(
evaluate(function() {
/** @class {Object} name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
name: 'name',
kind: 'class',
type: {
type: 'NameExpression',
name: 'Object'
}
});
});
test('parse - @classdesc', function() {
expect(
evaluate(function() {
/** @classdesc test */
})[0].classdesc
).toEqual(remark().parse('test'));
});
test('parse - @const', function() {});
test('parse - @constant', function() {
expect(
pick(
evaluate(function() {
/** @constant */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'constant'
});
expect(
pick(
evaluate(function() {
/** @constant name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'constant',
name: 'name'
});
expect(
pick(
evaluate(function() {
/** @constant {Object} */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'constant',
type: {
type: 'NameExpression',
name: 'Object'
}
});
expect(
pick(
evaluate(function() {
/** @constant {Object} name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'constant',
name: 'name',
type: {
type: 'NameExpression',
name: 'Object'
}
});
});
test('parse - @constructor', function() {});
test('parse - @constructs', function() {});
test('parse - @copyright', function() {
expect(
evaluate(function() {
/** @copyright test */
})[0].copyright
).toEqual(remark().parse('test'));
});
test('parse - @default', function() {});
test('parse - @defaultvalue', function() {});
test('parse - @deprecated', function() {
expect(
evaluate(function() {
/** @deprecated test */
})[0].deprecated
).toEqual(remark().parse('test'));
});
test('parse - @desc', function() {
expect(
evaluate(function() {
/** @desc test */
})[0].description
).toEqual(remark().parse('test'));
});
test('parse - @description', function() {
expect(
evaluate(function() {
/** @description test */
})[0].description
).toEqual(remark().parse('test'));
});
test('parse - description', function() {
expect(
evaluate(function() {
/** test */
})[0].description
).toEqual(remark().parse('test'));
});
test('parse - @emits', function() {});
test('parse - @enum', function() {
expect(
pick(
evaluate(function() {
/** @enum {string} */
})[0],
['kind', 'type']
)
).toEqual({
kind: 'enum',
type: {
type: 'NameExpression',
name: 'string'
}
});
});
test('parse - @event', function() {
expect(
pick(
evaluate(function() {
/** @event name */
})[0],
['kind', 'name']
)
).toEqual({
kind: 'event',
name: 'name'
});
});
test('parse - @example', function() {
expect(
evaluate(function() {
/** @example test */
})[0].examples[0]
).toEqual({
description: 'test'
});
expect(
evaluate(function() {
/**
* @example
* a
* b
*/
})[0].examples[0]
).toEqual({
description: 'a\nb'
});
expect(
evaluate(function() {
/**
* @example <caption>caption</caption>
* a
* b
*/
})[0].examples[0]
).toEqual({
description: 'a\nb',
caption: remark().parse('caption')
});
expect(
evaluate(function() {
/** @example */
})[0].errors[0]
).toEqual({
message: '@example without code',
commentLineNumber: 0
});
});
test('parse - @exception', function() {});
test('parse - @exports', function() {});
test('parse - @extends', function() {
expect(
evaluate(function() {
/** @extends Foo */
})[0].augments[0].name
).toEqual('Foo');
});
test('parse - @external', function() {
expect(
pick(
evaluate(function() {
/** @external name */
})[0],
['kind', 'name']
)
).toEqual({
kind: 'external',
name: 'name'
});
});
test('parse - @file', function() {
expect(
pick(
evaluate(function() {
/** @file */
})[0],
['kind']
)
).toEqual({
kind: 'file'
});
expect(
pick(
evaluate(function() {
/** @file desc */
})[0],
['kind', 'description']
)
).toEqual({
kind: 'file',
description: remark().parse('desc')
});
});
test('parse - @fileoverview', function() {});
test('parse - @fires', function() {});
test('parse - @func', function() {});
test('parse - @function', function() {
expect(
pick(
evaluate(function() {
/** @function */
})[0],
['kind', 'name']
)
).toEqual({
kind: 'function'
});
expect(
pick(
evaluate(function() {
/** @function name */
})[0],
['kind', 'name']
)
).toEqual({
kind: 'function',
name: 'name'
});
// When @function takes a name, it is acting as a shorthand for @name and
// should detach from code the same way @name does.
expect(
evaluate(function() {
/** @function */
function foo() {}
})[0].context.ast
).toBeDefined();
expect(
evaluate(function() {
/** @function name */
function foo() {}
})[0].context.ast
).toBeUndefined();
});
test('parse - @generator', function() {
expect(
evaluate(function() {
/** @generator */
})[0].generator
).toBe(true);
});
test('parse - @global', function() {
expect(
evaluate(function() {
/** @global */
})[0].scope
).toBe('global');
});
test('parse - @hideconstructor', function() {
expect(
evaluate(function() {
/** @hideconstructor */
})[0].hideconstructor
).toBe(true);
});
test('parse - @host', function() {});
test('parse - @ignore', function() {
expect(
evaluate(function() {
/** @ignore */
})[0].ignore
).toBe(true);
});
test('parse - @implements', function() {
expect(
evaluate(function() {
/** @implements {Foo} */
})[0].implements[0].name
).toEqual('Foo');
});
test('parse - @inheritdoc', function() {});
test('parse - @inner', function() {
expect(
evaluate(function() {
/** @inner*/
})[0].scope
).toBe('inner');
});
test('parse - @instance', function() {
expect(
evaluate(function() {
/** @instance*/
})[0].scope
).toBe('instance');
});
test('parse - @interface', function() {
expect(
evaluate(function() {
/** @interface */
})[0].kind
).toEqual('interface');
expect(
evaluate(function() {
/** @interface Foo */
})[0].name
).toEqual('Foo');
});
test('parse - @kind', function() {
expect(
evaluate(function() {
/** @kind class */
})[0].kind
).toBe('class');
});
test('parse - @license', function() {});
test('parse - @listens', function() {});
test('parse - @member', function() {
expect(
pick(
evaluate(function() {
/** @member */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'member'
});
expect(
pick(
evaluate(function() {
/** @member name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'member',
name: 'name'
});
expect(
pick(
evaluate(function() {
/** @member {Object} */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'member',
type: {
type: 'NameExpression',
name: 'Object'
}
});
expect(
pick(
evaluate(function() {
/** @member {Object} name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'member',
name: 'name',
type: {
type: 'NameExpression',
name: 'Object'
}
});
});
test('parse - @memberof', function() {
expect(
evaluate(function() {
/** @memberof test */
})[0].memberof
).toBe('test');
});
test('parse - @method', function() {});
test('parse - @mixes', function() {});
test('parse - @mixin', function() {
expect(
pick(
evaluate(function() {
/** @mixin */
})[0],
['kind', 'name']
)
).toEqual({
kind: 'mixin'
});
expect(
pick(
evaluate(function() {
/** @mixin name */
})[0],
['kind', 'name']
)
).toEqual({
kind: 'mixin',
name: 'name'
});
});
test('parse - @module', function() {
expect(
pick(
evaluate(function() {
/** @module */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'module'
});
expect(
pick(
evaluate(function() {
/** @module name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'module',
name: 'name'
});
expect(
pick(
evaluate(function() {
/** @module {Object} name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'module',
name: 'name',
type: {
type: 'NameExpression',
name: 'Object'
}
});
});
test('parse - @name', function() {
expect(
evaluate(function() {
/** @name test */
})[0].name
).toBe('test');
expect(
evaluate(function() {
/** @name foo */
const bar = 0;
})[0].context.ast
).toBeUndefined();
});
test('parse - @namespace', function() {
expect(
pick(
evaluate(function() {
/** @namespace */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'namespace'
});
expect(
pick(
evaluate(function() {
/** @namespace name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'namespace',
name: 'name'
});
expect(
pick(
evaluate(function() {
/** @namespace {Object} name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'namespace',
name: 'name',
type: {
type: 'NameExpression',
name: 'Object'
}
});
});
test('parse - @override', function() {
expect(
evaluate(function() {
/** @override */
})[0].override
).toBe(true);
});
test('parse - @overview', function() {});
test('parse - @param', function() {
expect(
evaluate(function() {
/** @param test */
})[0].params[0]
).toEqual({
name: 'test',
title: 'param',
lineNumber: 0
});
expect(
evaluate(function() {
/** @param {number} test */
})[0].params[0]
).toEqual({
name: 'test',
title: 'param',
type: {
name: 'number',
type: 'NameExpression'
},
lineNumber: 0
});
expect(
evaluate(function() {
/** @param {number} test - desc */
})[0].params[0]
).toEqual({
name: 'test',
title: 'param',
type: {
name: 'number',
type: 'NameExpression'
},
description: remark().parse('desc'),
lineNumber: 0
});
});
test('parse - @private', function() {
expect(
evaluate(function() {
/** @private */
})[0].access
).toBe('private');
});
test('parse - @prop', function() {
expect(
evaluate(function() {
/** @prop {number} test */
})[0].properties[0]
).toEqual({
name: 'test',
title: 'property',
type: {
name: 'number',
type: 'NameExpression'
},
lineNumber: 0
});
expect(
evaluate(function() {
/** @prop {number} test - desc */
})[0].properties[0]
).toEqual({
name: 'test',
title: 'property',
type: {
name: 'number',
type: 'NameExpression'
},
description: remark().parse('desc'),
lineNumber: 0
});
});
test('parse - @property', function() {
expect(
evaluate(function() {
/** @property {number} test */
})[0].properties[0]
).toEqual({
name: 'test',
title: 'property',
type: {
name: 'number',
type: 'NameExpression'
},
lineNumber: 0
});
expect(
evaluate(function() {
/** @property {number} test - desc */
})[0].properties[0]
).toEqual({
name: 'test',
title: 'property',
type: {
name: 'number',
type: 'NameExpression'
},
description: remark().parse('desc'),
lineNumber: 0
});
});
test('parse - @protected', function() {
expect(
evaluate(function() {
/** @protected */
})[0].access
).toBe('protected');
});
test('parse - @public', function() {});
test('parse - @readonly', function() {
expect(
evaluate(function() {
/** @readonly */
})[0].readonly
).toBe(true);
});
test('parse - @requires', function() {});
test('parse - @return', function() {
expect(
evaluate(function() {
/** @return test */
})[0].returns[0]
).toEqual({
title: 'returns',
description: remark().parse('test')
});
expect(
evaluate(function() {
/** @return {number} test */
})[0].returns[0]
).toEqual({
description: remark().parse('test'),
title: 'returns',
type: {
name: 'number',
type: 'NameExpression'
}
});
});
test('parse - @returns', function() {
expect(
evaluate(function() {
/** @returns test */
})[0].returns[0]
).toEqual({
title: 'returns',
description: remark().parse('test')
});
expect(
evaluate(function() {
/** @returns {number} test */
})[0].returns[0]
).toEqual({
description: remark().parse('test'),
title: 'returns',
type: {
name: 'number',
type: 'NameExpression'
}
});
});
test('parse - @see', function() {
expect(
evaluate(function() {
/** @see test */
})[0].sees
).toEqual([remark().parse('test')]);
expect(
evaluate(function() {
/**
* @see a
* @see b
*/
})[0].sees
).toEqual([remark().parse('a'), remark().parse('b')]);
});
test('parse - @since', function() {});
test('parse - @static', function() {
expect(
evaluate(function() {
/** @static */
})[0].scope
).toBe('static');
});
test('parse - @summary', function() {
expect(
evaluate(function() {
/** @summary test */
})[0].summary
).toEqual(remark().parse('test'));
});
test('parse - @this', function() {});
test('parse - @throws', function() {
expect(
evaluate(function() {
/** @throws desc */
})[0].throws[0]
).toEqual({
description: remark().parse('desc')
});
expect(
evaluate(function() {
/** @throws {Error} */
})[0].throws[0]
).toEqual({
type: {
name: 'Error',
type: 'NameExpression'
}
});
expect(
evaluate(function() {
/** @throws {Error} desc */
})[0].throws[0]
).toEqual({
type: {
name: 'Error',
type: 'NameExpression'
},
description: remark().parse('desc')
});
expect(
evaluate(function() {
/**
* @throws a
* @throws b
*/
})[0].throws
).toEqual([
{
description: remark().parse('a')
},
{
description: remark().parse('b')
}
]);
});
test('parse - @todo', function() {
expect(
evaluate(function() {
/** @todo test */
})[0].todos
).toEqual([remark().parse('test')]);
expect(
evaluate(function() {
/**
* @todo a
* @todo b
*/
})[0].todos
).toEqual([remark().parse('a'), remark().parse('b')]);
});
test('parse - @tutorial', function() {});
test('parse - @type', function() {});
test('parse - @typedef', function() {
expect(
pick(
evaluate(function() {
/** @typedef {Object} name */
})[0],
['kind', 'name', 'type']
)
).toEqual({
kind: 'typedef',
name: 'name',
type: {
type: 'NameExpression',
name: 'Object'
}
});
});
test('parse - @var', function() {});
test('parse - @variation', function() {
expect(
evaluate(function() {
/** @variation 1 */
})[0].variation
).toBe(1);
});
test('parse - @version', function() {});
test('parse - @virtual', function() {});
test('parse - @yield', function() {
expect(
evaluate(function() {
/** @yield test */
})[0].yields[0]
).toEqual({
title: 'yields',
description: remark().parse('test')
});
expect(
evaluate(function() {
/** @yield {number} test */
})[0].yields[0]
).toEqual({
description: remark().parse('test'),
title: 'yields',
type: {
name: 'number',
type: 'NameExpression'
}
});
});
test('parse - @yields', function() {
expect(
evaluate(function() {
/** @yields test */
})[0].yields[0]
).toEqual({
title: 'yields',
description: remark().parse('test')
});
expect(
evaluate(function() {
/** @yields {number} test */
})[0].yields[0]
).toEqual({
description: remark().parse('test'),
title: 'yields',
type: {
name: 'number',
type: 'NameExpression'
}
});
});
test('parse - unknown tag', function() {
expect(
evaluate(function() {
/** @unknown */
})[0].errors[0]
).toEqual({
message: 'unknown tag @unknown',
commentLineNumber: 0
});
});
test('parse - {@link}', function() {
expect(
removePosition(
evaluate(function() {
/** {@link Foo} */
})[0].description
)
).toEqual(addJSDocTag(removePosition(remark().parse('[Foo](Foo)'))));
expect(
removePosition(
evaluate(function() {
/** {@link Foo|text} */
})[0].description
)
).toEqual(addJSDocTag(removePosition(remark().parse('[text](Foo)'))));
expect(
removePosition(
evaluate(function() {
/** {@link Foo text} */
})[0].description
)
).toEqual(addJSDocTag(removePosition(remark().parse('[text](Foo)'))));
});
test('parse - {@linkcode}', function() {});
test('parse - {@linkplain}', function() {});
test('parse - {@tutorial}', function() {
expect(
removePosition(
evaluate(function() {
/** {@tutorial id} */
})[0].description
)
).toEqual({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{
type: 'tutorial',
url: 'id',
jsdoc: true,
title: null,
children: [
{
type: 'text',
value: 'id'
}
]
}
]
}
]
});
expect(
removePosition(
evaluate(function() {
/** {@tutorial id|text} */
})[0].description
)
).toEqual({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{
type: 'tutorial',
url: 'id',
jsdoc: true,
title: null,
children: [
{
type: 'text',
value: 'text'
}
]
}
]
}
]
});
expect(
removePosition(
evaluate(function() {
/** {@tutorial id text} */
})[0].description
)
).toEqual({
type: 'root',
children: [
{
type: 'paragraph',
children: [
{
type: 'tutorial',
url: 'id',
jsdoc: true,
title: null,
children: [
{
type: 'text',
value: 'text'
}
]
}
]
}
]
});
});