Skip to content
Permalink
Browse files

feat(parser): switch a parser to babylon

esdoc#293
this is breaking change.
  • Loading branch information...
h13i32maru committed Aug 14, 2016
1 parent 52f8ce3 commit 8130a3f42b497e81f9ec6fc4cf0ef07ed5a7fa22

Large diffs are not rendered by default.

@@ -22,16 +22,17 @@
"color-logger": "0.0.3",
"core-js": "2.4.1",
"escape-html": "1.0.3",
"escodegen": "1.8.1",
"espree": "2.2.0",
"estraverse": "4.2.0",
"babylon": "6.8.4",
"babel-generator": "6.11.4",
"babel-traverse": "6.12.0",
"fs-extra": "0.30.0",
"ice-cap": "0.0.4",
"marked": "0.3.6",
"minimist": "1.2.0",
"taffydb": "2.7.2"
},
"devDependencies": {
"espree": "2.2.0",
"babel-register": "6.11.6",
"babel-cli": "6.11.4",
"babel-plugin-transform-es2015-modules-commonjs": "6.11.5",
@@ -1,6 +1,6 @@
#!/usr/bin/env node
require('babel/register');
var ESParser = require('../src/Parser/ESParser.js');
require('babel-register');
var ESParser = require('../src/Parser/ESParser.js').default;
var Plugin = require('../src/Plugin/Plugin.js').default;

Plugin.init([]);
@@ -633,7 +633,7 @@ export default class AbstractDoc {
*/
_findClassLongname(className) {
// find in same file.
for (let node of this._ast.body) {
for (let node of this._ast.program.body) {
if (!['ExportDefaultDeclaration', 'ExportNamedDeclaration'].includes(node.type)) continue;
if (node.declaration && node.declaration.type === 'ClassDeclaration' && node.declaration.id.name === className) {
return `${this._pathResolver.filePath}~${className}`;
@@ -36,7 +36,7 @@ export default class MemberDoc extends AbstractDoc {

let parent = this._node.parent;
while (parent) {
if (parent.type === 'MethodDefinition') {
if (parent.type === 'ClassMethod') {
this._value.static = parent.static;
break;
}
@@ -1,6 +1,6 @@
import escodegen from 'escodegen';
import AbstractDoc from './AbstractDoc.js';
import ParamParser from '../Parser/ParamParser.js';
import babelGenerator from 'babel-generator';

/**
* Doc Class from Method Definition AST node.
@@ -30,12 +30,8 @@ export default class MethodDoc extends AbstractDoc {
AbstractDoc.prototype['@_name'].call(this);
if (this._value.name) return;

// todo: espree parses ``*[foo.bar](){}`` as not computed.
// so, I hacked ``!this._node.key.name`` condition.
// this condition is not needed with acorn.
// see https://github.com/esdoc/esdoc/issues/107
if (this._node.computed || !this._node.key.name) {
const expression = escodegen.generate(this._node.key);
if (this._node.computed) {
const expression = babelGenerator(this._node.key).code;
this._value.name = `[${expression}]`;
} else {
this._value.name = this._node.key.name;
@@ -66,7 +62,7 @@ export default class MethodDoc extends AbstractDoc {

if (['set', 'get'].includes(this._value.kind)) return;

this._value.params = ParamParser.guessParams(this._node.value.params);
this._value.params = ParamParser.guessParams(this._node.params);
}

/** if @type is not exists, guess type by using self node. only ``get`` and ``set`` are guess. */
@@ -79,7 +75,7 @@ export default class MethodDoc extends AbstractDoc {
this._value.type = ParamParser.guessType(this._node.right);
break;
case 'get':
let result = ParamParser.guessReturnParam(this._node.value.body);
let result = ParamParser.guessReturnParam(this._node.body);
if (result) this._value.type = result;
break;
}
@@ -92,7 +88,7 @@ export default class MethodDoc extends AbstractDoc {

if (['constructor', 'set', 'get'].includes(this._value.kind)) return;

let result = ParamParser.guessReturnParam(this._node.value.body);
let result = ParamParser.guessReturnParam(this._node.body);
if (result) {
this._value.return = result;
}
@@ -103,6 +99,6 @@ export default class MethodDoc extends AbstractDoc {
super['@_generator']();
if ('generator' in this._value) return;

this._value.generator = this._node.value.generator;
this._value.generator = this._node.generator;
}
}
@@ -49,8 +49,8 @@ export default class DocFactory {
this._results.push(doc.value);

// ast does not child, so only comment.
if (ast.body.length === 0 && ast.leadingComments) {
let results = this._traverseComments(ast, null, ast.leadingComments);
if (ast.program.body.length === 0 && ast.program.innerComments) {
let results = this._traverseComments(ast, null, ast.program.innerComments);
this._results.push(...results);
}
}
@@ -86,7 +86,7 @@ export default class DocFactory {
_inspectExportDefaultDeclaration() {
let pseudoExportNodes = [];

for (let exportNode of this._ast.body) {
for (let exportNode of this._ast.program.body) {
if (exportNode.type !== 'ExportDefaultDeclaration') continue;

let targetClassName = null;
@@ -159,7 +159,7 @@ export default class DocFactory {
}
}

this._ast.body.push(...pseudoExportNodes);
this._ast.program.body.push(...pseudoExportNodes);
}

/**
@@ -186,7 +186,7 @@ export default class DocFactory {
_inspectExportNamedDeclaration() {
let pseudoExportNodes = [];

for (let exportNode of this._ast.body) {
for (let exportNode of this._ast.program.body) {
if (exportNode.type !== 'ExportNamedDeclaration') continue;

if (exportNode.declaration && exportNode.declaration.type === 'VariableDeclaration') {
@@ -261,7 +261,7 @@ export default class DocFactory {
}
}

this._ast.body.push(...pseudoExportNodes);
this._ast.program.body.push(...pseudoExportNodes);
}

/**
@@ -315,19 +315,6 @@ export default class DocFactory {
node = virtualNode;
}

// hack: leadingComment of MethodDefinition with Literal is not valid by espree(v2.0.2)
//if (node.type === 'MethodDefinition' && node.key.type === 'Literal') {
// todo: switch espree to acorn
if (node.type === 'MethodDefinition' && (node.computed || !node.key.name)) {
let line = node.loc.start.line - 1;
for (let comment of this._ast.comments || []) {
if (comment.loc.end.line === line) {
comments = [comment];
break;
}
}
}

if (comments && comments.length) {
let temp = [];
for (let comment of comments) {
@@ -339,7 +326,7 @@ export default class DocFactory {
}

if (comments.length === 0) {
comments = [{type: 'Block', value: '* @_undocument'}];
comments = [{type: 'CommentBlock', value: '* @_undocument'}];
}

let results = [];
@@ -427,7 +414,7 @@ export default class DocFactory {
switch (node.type) {
case 'ClassDeclaration':
return this._decideClassDeclarationType(node);
case 'MethodDefinition':
case 'ClassMethod': // for babylon
return this._decideMethodDefinitionType(node);
case 'ExpressionStatement':
return this._decideExpressionStatementType(node);
@@ -449,7 +436,7 @@ export default class DocFactory {
* @private
*/
_decideClassDeclarationType(node) {
if (!this._isTopDepthInBody(node, this._ast.body)) return {type: null, node: null};
if (!this._isTopDepthInBody(node, this._ast.program.body)) return {type: null, node: null};

return {type: 'Class', node: node};
}
@@ -477,7 +464,7 @@ export default class DocFactory {
* @private
*/
_decideFunctionDeclarationType(node) {
if (!this._isTopDepthInBody(node, this._ast.body)) return {type: null, node: null};
if (!this._isTopDepthInBody(node, this._ast.program.body)) return {type: null, node: null};

return {type: 'Function', node: node};
}
@@ -489,7 +476,7 @@ export default class DocFactory {
* @private
*/
_decideExpressionStatementType(node) {
let isTop = this._isTopDepthInBody(node, this._ast.body);
let isTop = this._isTopDepthInBody(node, this._ast.program.body);
Object.defineProperty(node.expression, 'parent', {value: node});
node = node.expression;
node[already] = true;
@@ -542,7 +529,7 @@ export default class DocFactory {
* @private
*/
_decideVariableType(node) {
if (!this._isTopDepthInBody(node, this._ast.body)) return {type: null, node: null};
if (!this._isTopDepthInBody(node, this._ast.program.body)) return {type: null, node: null};

let innerType = null;
let innerNode = null;
@@ -575,7 +562,7 @@ export default class DocFactory {
* @private
*/
_decideAssignmentType(node) {
if (!this._isTopDepthInBody(node, this._ast.body)) return {type: null, node: null};
if (!this._isTopDepthInBody(node, this._ast.program.body)) return {type: null, node: null};

let innerType;
let innerNode;
@@ -12,7 +12,7 @@ export default class CommentParser {
* parse comment to tags.
* @param {ASTNode} commentNode - comment node.
* @param {string} commentNode.value - comment body.
* @param {string} commentNode.type - Block or Line.
* @param {string} commentNode.type - CommentBlock or CommentLine.
* @returns {Tag[]} parsed comment.
*/
static parse(commentNode) {
@@ -59,7 +59,7 @@ export default class CommentParser {
* @returns {boolean} if true, this comment node is doc comment.
*/
static isESDoc(commentNode) {
if (commentNode.type !== 'Block') return false;
if (commentNode.type !== 'CommentBlock') return false;
return commentNode.value.charAt(0) === '*';
}
}
@@ -1,7 +1,7 @@
import fs from 'fs-extra';
import path from 'path';
import espree from 'espree';
import Plugin from '../Plugin/Plugin.js';
import * as babylon from 'babylon';

/**
* ECMAScript Parser class.
@@ -16,6 +16,11 @@ export default class ESParser {
* @returns {AST} AST of source code.
*/
static parse(filePath) {
return this.parseWithBabylon(filePath);
// return this.parseWithEspree(filePath);
}

static parseWithEspree(filePath) {
let code = fs.readFileSync(filePath, {encode: 'utf8'}).toString();

code = Plugin.onHandleCode(code, filePath);
@@ -66,4 +71,27 @@ export default class ESParser {

return ast;
}

static parseWithBabylon(filePath) {
let code = fs.readFileSync(filePath, {encode: 'utf8'}).toString();
code = Plugin.onHandleCode(code, filePath);
if (code.charAt(0) === '#') code = code.replace(/^#!/, '//');

const option = {
sourceType: 'module',
plugins: ['jsx']
};

let parser = (code) => {
return babylon.parse(code, option);
};

parser = Plugin.onHandleCodeParser(parser, option, filePath, code);

let ast = parser(code);

ast = Plugin.onHandleAST(ast, filePath, code);

return ast;
}
}
@@ -117,7 +117,7 @@ export default class ParamParser {
else {
result.types = [''];
}

if (result.types.some(t => !t)) {
throw new Error(`Empty Type found name=${paramName} desc=${paramDesc}`);
}
@@ -185,7 +185,7 @@ export default class ParamParser {

result.optional = true;

if (param.right.type === 'Literal') {
if (param.right.type.includes('Literal')) {
// e.g. func(a = 10){}
result.types = param.right.value === null ? ['*'] : [typeof param.right.value];
result.defaultRaw = param.right.value;
@@ -274,7 +274,8 @@ export default class ParamParser {

if (!node.argument) return;

switch (node.argument.type) {
const type = node.argument.type.includes('Literal') ? 'Literal' : node.argument.type;
switch (type) {
case 'Literal':
if (node.argument.value === null) {
result.types = result.types || ['*'];
@@ -304,7 +305,7 @@ export default class ParamParser {
* @returns {ParsedParam}
*/
static guessType(right) {
let value = right && right.type === 'Literal' ? right.value : null;
let value = right && right.type.includes('Literal') ? right.value : null;

if (value === null || value === undefined) {
return {types: ['*']};
@@ -46,8 +46,8 @@ export default class LintDocBuilder extends DocBuilder {
case 'FunctionDeclaration':
params = node.params || [];
break;
case 'MethodDefinition':
params = node.value.params || [];
case 'ClassMethod':
params = node.params || [];
break;
default:
throw new Error(`unknown node type. type = ${node.type}`);

0 comments on commit 8130a3f

Please sign in to comment.
You can’t perform that action at this time.