Skip to content

Commit 8130a3f

Browse files
committed
feat(parser): switch a parser to babylon
#293 this is breaking change.
1 parent 52f8ce3 commit 8130a3f

File tree

14 files changed

+144
-236
lines changed

14 files changed

+144
-236
lines changed

npm-shrinkwrap.json

Lines changed: 57 additions & 156 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,17 @@
2222
"color-logger": "0.0.3",
2323
"core-js": "2.4.1",
2424
"escape-html": "1.0.3",
25-
"escodegen": "1.8.1",
26-
"espree": "2.2.0",
27-
"estraverse": "4.2.0",
25+
"babylon": "6.8.4",
26+
"babel-generator": "6.11.4",
27+
"babel-traverse": "6.12.0",
2828
"fs-extra": "0.30.0",
2929
"ice-cap": "0.0.4",
3030
"marked": "0.3.6",
3131
"minimist": "1.2.0",
3232
"taffydb": "2.7.2"
3333
},
3434
"devDependencies": {
35+
"espree": "2.2.0",
3536
"babel-register": "6.11.6",
3637
"babel-cli": "6.11.4",
3738
"babel-plugin-transform-es2015-modules-commonjs": "6.11.5",

script/ast.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
2-
require('babel/register');
3-
var ESParser = require('../src/Parser/ESParser.js');
2+
require('babel-register');
3+
var ESParser = require('../src/Parser/ESParser.js').default;
44
var Plugin = require('../src/Plugin/Plugin.js').default;
55

66
Plugin.init([]);

src/Doc/AbstractDoc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,7 @@ export default class AbstractDoc {
633633
*/
634634
_findClassLongname(className) {
635635
// find in same file.
636-
for (let node of this._ast.body) {
636+
for (let node of this._ast.program.body) {
637637
if (!['ExportDefaultDeclaration', 'ExportNamedDeclaration'].includes(node.type)) continue;
638638
if (node.declaration && node.declaration.type === 'ClassDeclaration' && node.declaration.id.name === className) {
639639
return `${this._pathResolver.filePath}~${className}`;

src/Doc/MemberDoc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ export default class MemberDoc extends AbstractDoc {
3636

3737
let parent = this._node.parent;
3838
while (parent) {
39-
if (parent.type === 'MethodDefinition') {
39+
if (parent.type === 'ClassMethod') {
4040
this._value.static = parent.static;
4141
break;
4242
}

src/Doc/MethodDoc.js

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import escodegen from 'escodegen';
21
import AbstractDoc from './AbstractDoc.js';
32
import ParamParser from '../Parser/ParamParser.js';
3+
import babelGenerator from 'babel-generator';
44

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

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

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

69-
this._value.params = ParamParser.guessParams(this._node.value.params);
65+
this._value.params = ParamParser.guessParams(this._node.params);
7066
}
7167

7268
/** 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 {
7975
this._value.type = ParamParser.guessType(this._node.right);
8076
break;
8177
case 'get':
82-
let result = ParamParser.guessReturnParam(this._node.value.body);
78+
let result = ParamParser.guessReturnParam(this._node.body);
8379
if (result) this._value.type = result;
8480
break;
8581
}
@@ -92,7 +88,7 @@ export default class MethodDoc extends AbstractDoc {
9288

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

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

106-
this._value.generator = this._node.value.generator;
102+
this._value.generator = this._node.generator;
107103
}
108104
}

src/Factory/DocFactory.js

Lines changed: 13 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ export default class DocFactory {
4949
this._results.push(doc.value);
5050

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

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

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

162-
this._ast.body.push(...pseudoExportNodes);
162+
this._ast.program.body.push(...pseudoExportNodes);
163163
}
164164

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

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

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

264-
this._ast.body.push(...pseudoExportNodes);
264+
this._ast.program.body.push(...pseudoExportNodes);
265265
}
266266

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

318-
// hack: leadingComment of MethodDefinition with Literal is not valid by espree(v2.0.2)
319-
//if (node.type === 'MethodDefinition' && node.key.type === 'Literal') {
320-
// todo: switch espree to acorn
321-
if (node.type === 'MethodDefinition' && (node.computed || !node.key.name)) {
322-
let line = node.loc.start.line - 1;
323-
for (let comment of this._ast.comments || []) {
324-
if (comment.loc.end.line === line) {
325-
comments = [comment];
326-
break;
327-
}
328-
}
329-
}
330-
331318
if (comments && comments.length) {
332319
let temp = [];
333320
for (let comment of comments) {
@@ -339,7 +326,7 @@ export default class DocFactory {
339326
}
340327

341328
if (comments.length === 0) {
342-
comments = [{type: 'Block', value: '* @_undocument'}];
329+
comments = [{type: 'CommentBlock', value: '* @_undocument'}];
343330
}
344331

345332
let results = [];
@@ -427,7 +414,7 @@ export default class DocFactory {
427414
switch (node.type) {
428415
case 'ClassDeclaration':
429416
return this._decideClassDeclarationType(node);
430-
case 'MethodDefinition':
417+
case 'ClassMethod': // for babylon
431418
return this._decideMethodDefinitionType(node);
432419
case 'ExpressionStatement':
433420
return this._decideExpressionStatementType(node);
@@ -449,7 +436,7 @@ export default class DocFactory {
449436
* @private
450437
*/
451438
_decideClassDeclarationType(node) {
452-
if (!this._isTopDepthInBody(node, this._ast.body)) return {type: null, node: null};
439+
if (!this._isTopDepthInBody(node, this._ast.program.body)) return {type: null, node: null};
453440

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

482469
return {type: 'Function', node: node};
483470
}
@@ -489,7 +476,7 @@ export default class DocFactory {
489476
* @private
490477
*/
491478
_decideExpressionStatementType(node) {
492-
let isTop = this._isTopDepthInBody(node, this._ast.body);
479+
let isTop = this._isTopDepthInBody(node, this._ast.program.body);
493480
Object.defineProperty(node.expression, 'parent', {value: node});
494481
node = node.expression;
495482
node[already] = true;
@@ -542,7 +529,7 @@ export default class DocFactory {
542529
* @private
543530
*/
544531
_decideVariableType(node) {
545-
if (!this._isTopDepthInBody(node, this._ast.body)) return {type: null, node: null};
532+
if (!this._isTopDepthInBody(node, this._ast.program.body)) return {type: null, node: null};
546533

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

580567
let innerType;
581568
let innerNode;

src/Parser/CommentParser.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ export default class CommentParser {
1212
* parse comment to tags.
1313
* @param {ASTNode} commentNode - comment node.
1414
* @param {string} commentNode.value - comment body.
15-
* @param {string} commentNode.type - Block or Line.
15+
* @param {string} commentNode.type - CommentBlock or CommentLine.
1616
* @returns {Tag[]} parsed comment.
1717
*/
1818
static parse(commentNode) {
@@ -59,7 +59,7 @@ export default class CommentParser {
5959
* @returns {boolean} if true, this comment node is doc comment.
6060
*/
6161
static isESDoc(commentNode) {
62-
if (commentNode.type !== 'Block') return false;
62+
if (commentNode.type !== 'CommentBlock') return false;
6363
return commentNode.value.charAt(0) === '*';
6464
}
6565
}

src/Parser/ESParser.js

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import fs from 'fs-extra';
2-
import path from 'path';
32
import espree from 'espree';
43
import Plugin from '../Plugin/Plugin.js';
4+
import * as babylon from 'babylon';
55

66
/**
77
* ECMAScript Parser class.
@@ -16,6 +16,11 @@ export default class ESParser {
1616
* @returns {AST} AST of source code.
1717
*/
1818
static parse(filePath) {
19+
return this.parseWithBabylon(filePath);
20+
// return this.parseWithEspree(filePath);
21+
}
22+
23+
static parseWithEspree(filePath) {
1924
let code = fs.readFileSync(filePath, {encode: 'utf8'}).toString();
2025

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

6772
return ast;
6873
}
74+
75+
static parseWithBabylon(filePath) {
76+
let code = fs.readFileSync(filePath, {encode: 'utf8'}).toString();
77+
code = Plugin.onHandleCode(code, filePath);
78+
if (code.charAt(0) === '#') code = code.replace(/^#!/, '//');
79+
80+
const option = {
81+
sourceType: 'module',
82+
plugins: ['jsx']
83+
};
84+
85+
let parser = (code) => {
86+
return babylon.parse(code, option);
87+
};
88+
89+
parser = Plugin.onHandleCodeParser(parser, option, filePath, code);
90+
91+
let ast = parser(code);
92+
93+
ast = Plugin.onHandleAST(ast, filePath, code);
94+
95+
return ast;
96+
}
6997
}

src/Parser/ParamParser.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ export default class ParamParser {
117117
else {
118118
result.types = [''];
119119
}
120-
120+
121121
if (result.types.some(t => !t)) {
122122
throw new Error(`Empty Type found name=${paramName} desc=${paramDesc}`);
123123
}
@@ -185,7 +185,7 @@ export default class ParamParser {
185185

186186
result.optional = true;
187187

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

275275
if (!node.argument) return;
276276

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

309310
if (value === null || value === undefined) {
310311
return {types: ['*']};

0 commit comments

Comments
 (0)