documentation/lib/parsers/javascript.js
Tom MacWright 0a122b51c2 Walk trailing comments. Fixes #93
cc @jfirebaugh for the review
2015-10-04 11:39:55 -04:00

140 lines
4.0 KiB
JavaScript

'use strict';
var espree = require('espree'),
types = require('ast-types'),
extend = require('extend'),
isJSDocComment = require('../../lib/is_jsdoc_comment'),
parse = require('../../lib/parse');
/**
* Comment-out a shebang line that may sit at the top of a file,
* making it executable on linux-like systems.
* @param {string} code the source code in full
* @return {string} code
* @example
* var foo = commentShebang('#!/usr/bin/env/node');
* foo === '//#!/usr/bin/env/node';
*/
function commentShebang(code) {
return (code[0] === '#' && code[1] === '!') ? '//' + code : code;
}
var espreeConfig = {
loc: true,
attachComment: true,
// specify parsing features (default only has blockBindings: true)
ecmaFeatures: {
// enable parsing of arrow functions
arrowFunctions: true,
// enable parsing of let/const
blockBindings: true,
// enable parsing of destructured arrays and objects
destructuring: true,
// enable parsing of regular expression y flag
regexYFlag: true,
// enable parsing of regular expression u flag
regexUFlag: true,
// enable parsing of template strings
templateStrings: true,
// enable parsing of binary literals
binaryLiterals: true,
// enable parsing of ES6 octal literals
octalLiterals: true,
// enable parsing unicode code point escape sequences
unicodeCodePointEscapes: true,
// enable parsing of default parameters
defaultParams: true,
// enable parsing of rest parameters
restParams: true,
// enable parsing of for-of statement
forOf: true,
// enable parsing computed object literal properties
objectLiteralComputedProperties: true,
// enable parsing of shorthand object literal methods
objectLiteralShorthandMethods: true,
// enable parsing of shorthand object literal properties
objectLiteralShorthandProperties: true,
// Allow duplicate object literal properties (except '__proto__')
objectLiteralDuplicateProperties: true,
// enable parsing of generators/yield
generators: true,
// enable parsing spread operator
spread: true,
// enable parsing classes
classes: true,
// enable parsing of modules
modules: true,
// enable React JSX parsing
jsx: true,
// enable return in global scope
globalReturn: true
}
};
/**
* Receives a module-dep item,
* reads the file, parses the JavaScript, and parses the JSDoc.
*
* @name parse
* @param {Object} data a chunk of data provided by module-deps
* @return {Array<Object>} an array of parsed comments
*/
module.exports = function (data) {
var results = [];
var code = commentShebang(data.source),
ast = espree.parse(code, espreeConfig);
var visited = {};
function walkComments(ast, type) {
types.visit(ast, {
visitNode: function (path) {
/**
* Parse a comment with doctrine and decorate the result with file position and code context.
*
* @param {Object} comment the current state of the parsed JSDoc comment
* @return {undefined} this emits data
*/
function parseComment(comment) {
var context = {
loc: extend({}, path.value.loc),
file: data.file
};
var key = JSON.stringify(comment.loc);
if (visited[key]) {
return;
}
visited[key] = true;
// This is non-enumerable so that it doesn't get stringified in output; e.g. by the
// documentation binary.
Object.defineProperty(context, 'ast', {
enumerable: false,
value: path
});
if (path.parent && path.parent.node) {
context.code = code.substring
.apply(code, path.parent.node.range);
}
results.push(parse(comment.value, comment.loc, context));
}
(path.value[type] || [])
.filter(isJSDocComment)
.forEach(parseComment);
this.traverse(path);
}
});
}
walkComments(ast, 'leadingComments');
walkComments(ast, 'trailingComments');
return results;
};