refactor: move ast-builder and ast-node to @jsdoc/parse

BREAKING CHANGE: Modules no longer exist in jsdoc package.
This commit is contained in:
Jeff Williams 2020-12-24 16:05:58 -08:00
parent 86d18ff44a
commit 65e6db3ba4
14 changed files with 91 additions and 101 deletions

View File

@ -1,5 +1,9 @@
const { AstBuilder } = require('./lib/ast-builder');
const astNode = require('./lib/ast-node');
const { Syntax } = require('./lib/syntax'); const { Syntax } = require('./lib/syntax');
module.exports = { module.exports = {
AstBuilder,
astNode,
Syntax Syntax
}; };

View File

@ -2,7 +2,7 @@ const _ = require('lodash');
const babelParser = require('@babel/parser'); const babelParser = require('@babel/parser');
const { log } = require('@jsdoc/util'); const { log } = require('@jsdoc/util');
// exported so we can use them in tests // Exported so we can use them in tests.
const parserOptions = exports.parserOptions = { const parserOptions = exports.parserOptions = {
allowAwaitOutsideFunction: true, allowAwaitOutsideFunction: true,
allowImportExportEverywhere: true, allowImportExportEverywhere: true,
@ -58,10 +58,8 @@ function parse(source, filename, sourceType) {
// TODO: docs // TODO: docs
class AstBuilder { class AstBuilder {
// TODO: docs // TODO: docs
/* eslint-disable class-methods-use-this */ static build(source, filename, sourceType) {
build(source, filename, sourceType) {
return parse(source, filename, sourceType); return parse(source, filename, sourceType);
} }
/* eslint-enable class-methods-use-this */
} }
exports.AstBuilder = AstBuilder; exports.AstBuilder = AstBuilder;

View File

@ -1,9 +1,9 @@
// TODO: docs // TODO: docs
/** @module jsdoc/src/astnode */ /** @module @jsdoc/parse.astNode */
const _ = require('lodash'); const _ = require('lodash');
const { cast } = require('@jsdoc/util'); const { cast } = require('@jsdoc/util');
const { SCOPE } = require('@jsdoc/core').name; const { SCOPE } = require('@jsdoc/core').name;
const { Syntax } = require('@jsdoc/parse'); const { Syntax } = require('./syntax');
// Counter for generating unique node IDs. // Counter for generating unique node IDs.
let uid = 100000000; let uid = 100000000;
@ -11,7 +11,7 @@ let uid = 100000000;
/** /**
* Check whether an AST node represents a function. * Check whether an AST node represents a function.
* *
* @alias module:jsdoc/src/astnode.isFunction * @alias module:@jsdoc/parse.astNode.isFunction
* @param {(Object|string)} node - The AST node to check, or the `type` property of a node. * @param {(Object|string)} node - The AST node to check, or the `type` property of a node.
* @return {boolean} Set to `true` if the node is a function or `false` in all other cases. * @return {boolean} Set to `true` if the node is a function or `false` in all other cases.
*/ */
@ -36,7 +36,7 @@ const isFunction = exports.isFunction = node => {
/** /**
* Check whether an AST node creates a new scope. * Check whether an AST node creates a new scope.
* *
* @alias module:jsdoc/src/astnode.isScope * @alias module:@jsdoc/parse.astNode.isScope
* @param {Object} node - The AST node to check. * @param {Object} node - The AST node to check.
* @return {Boolean} Set to `true` if the node creates a new scope, or `false` in all other cases. * @return {Boolean} Set to `true` if the node creates a new scope, or `false` in all other cases.
*/ */

View File

@ -5,6 +5,22 @@ describe('@jsdoc/parse', () => {
expect(parse).toBeObject(); expect(parse).toBeObject();
}); });
describe('AstBuilder', () => {
it('is lib/ast-builder.AstBuilder', () => {
const { AstBuilder } = require('../../lib/ast-builder');
expect(parse.AstBuilder).toBe(AstBuilder);
});
});
describe('astNode', () => {
it('is lib/ast-node', () => {
const astNode = require('../../lib/ast-node');
expect(parse.astNode).toBe(astNode);
});
});
describe('Syntax', () => { describe('Syntax', () => {
it('is lib/syntax.Syntax', () => { it('is lib/syntax.Syntax', () => {
const { Syntax } = require('../../lib/syntax'); const { Syntax } = require('../../lib/syntax');

View File

@ -0,0 +1,41 @@
/* global jsdoc */
describe('@jsdoc/parse/lib/ast-builder', () => {
const astBuilder = require('../../../lib/ast-builder');
it('is an object', () => {
expect(astBuilder).toBeObject();
});
it('exports an AstBuilder class', () => {
expect(astBuilder.AstBuilder).toBeFunction();
});
it('exports a parserOptions object', () => {
expect(astBuilder.parserOptions).toBeObject();
});
describe('AstBuilder', () => {
const { AstBuilder } = astBuilder;
// TODO: more tests
it('has a "build" static method', () => {
expect(AstBuilder.build).toBeFunction();
});
describe('build', () => {
// TODO: more tests
it('logs (not throws) an error when a file cannot be parsed', () => {
function parse() {
AstBuilder.build('qwerty!!!!!', 'bad.js');
}
expect(parse).not.toThrow();
expect(jsdoc.didLog(parse, 'error')).toBeTrue();
});
});
});
describe('parserOptions', () => {
// TODO: tests
});
});

View File

@ -1,11 +1,11 @@
describe('jsdoc/src/astNode', () => { describe('@jsdoc/parse/lib/ast-node', () => {
const astBuilder = require('jsdoc/src/astbuilder'); const astNode = require('../../../lib/ast-node');
const astNode = require('jsdoc/src/astnode');
const babelParser = require('@babel/parser'); const babelParser = require('@babel/parser');
const { Syntax } = require('@jsdoc/parse'); const { parserOptions } = require('../../../lib/ast-builder');
const { Syntax } = require('../../../lib/syntax');
function parse(str) { function parse(str) {
return babelParser.parse(str, astBuilder.parserOptions).program.body[0]; return babelParser.parse(str, parserOptions).program.body[0];
} }
// create the AST nodes we'll be testing // create the AST nodes we'll be testing
@ -526,8 +526,8 @@ describe('jsdoc/src/astNode', () => {
// TODO: we can't test this here because JSDoc, not Babylon, adds the `parent` property to // TODO: we can't test this here because JSDoc, not Babylon, adds the `parent` property to
// nodes. also, we currently return an empty string instead of `<anonymous>` in this case; // nodes. also, we currently return an empty string instead of `<anonymous>` in this case;
// see `module:jsdoc/src/astnode.nodeToValue` and the comment on `Syntax.MethodDefinition` // see `module:@jsdoc/parse.astNode.nodeToValue` and the comment on
// for details // `Syntax.MethodDefinition` for details
xit('should return `<anonymous>` for method definitions inside classes that were ' + xit('should return `<anonymous>` for method definitions inside classes that were ' +
'returned by an arrow function expression', () => { 'returned by an arrow function expression', () => {
expect( astNode.nodeToValue(methodDefinition2) ).toBe('<anonymous>'); expect( astNode.nodeToValue(methodDefinition2) ).toBe('<anonymous>');

View File

@ -3,7 +3,7 @@
*/ */
const _ = require('lodash'); const _ = require('lodash');
let dictionary = require('jsdoc/tag/dictionary'); let dictionary = require('jsdoc/tag/dictionary');
const { isFunction } = require('jsdoc/src/astnode'); const { isFunction } = require('@jsdoc/parse').astNode;
const { const {
applyNamespace, applyNamespace,
hasLeadingScope, hasLeadingScope,
@ -31,7 +31,7 @@ function fakeMeta(node) {
} }
// use the meta info about the source code to guess what the doclet kind should be // use the meta info about the source code to guess what the doclet kind should be
// TODO: set this elsewhere (maybe jsdoc/src/astnode.getInfo) // TODO: set this elsewhere (maybe @jsdoc/parse.astNode.getInfo)
function codeToKind(code) { function codeToKind(code) {
let kind = 'member'; let kind = 'member';
const node = code.node; const node = code.node;

View File

@ -2,12 +2,13 @@
* @module jsdoc/src/parser * @module jsdoc/src/parser
*/ */
const _ = require('lodash'); const _ = require('lodash');
const astNode = require('jsdoc/src/astnode'); const { AstBuilder, astNode, Syntax } = require('@jsdoc/parse');
const { EventEmitter } = require('events'); const { EventEmitter } = require('events');
const fs = require('fs'); const fs = require('fs');
const { log } = require('@jsdoc/util'); const { log } = require('@jsdoc/util');
const { getBasename, LONGNAMES, SCOPE, toParts } = require('@jsdoc/core').name; const { getBasename, LONGNAMES, SCOPE, toParts } = require('@jsdoc/core').name;
const { Syntax } = require('@jsdoc/parse'); const { Visitor } = require('jsdoc/src/visitor');
const { Walker } = require('jsdoc/src/walker');
const hasOwnProp = Object.prototype.hasOwnProperty; const hasOwnProp = Object.prototype.hasOwnProperty;
@ -61,7 +62,7 @@ exports.createParser = (type, conf) => {
return null; return null;
} }
return new (require(modulePath).Parser)(null, null, null, conf); return new (require(modulePath).Parser)(conf);
}; };
// TODO: docs // TODO: docs
@ -89,24 +90,18 @@ function definedInScope(doclet, basename) {
*/ */
class Parser extends EventEmitter { class Parser extends EventEmitter {
// TODO: docs // TODO: docs
constructor(builderInstance, visitorInstance, walkerInstance, conf) { constructor(conf) {
super(); super();
this.clear(); this.clear();
this._astBuilder = builderInstance || new (require('jsdoc/src/astbuilder').AstBuilder)();
this._conf = conf || {}; this._conf = conf || {};
this._visitor = visitorInstance || new (require('jsdoc/src/visitor').Visitor)(); this._visitor = new Visitor();
this._walker = walkerInstance || new (require('jsdoc/src/walker').Walker)(); this._walker = new Walker();
this._visitor.setParser(this); this._visitor.setParser(this);
Object.defineProperties(this, { Object.defineProperties(this, {
astBuilder: {
get() {
return this._astBuilder;
}
},
visitor: { visitor: {
get() { get() {
return this._visitor; return this._visitor;
@ -285,7 +280,7 @@ class Parser extends EventEmitter {
sourceCode = pretreat(e.source); sourceCode = pretreat(e.source);
sourceType = this._conf.source ? this._conf.source.type : undefined; sourceType = this._conf.source ? this._conf.source.type : undefined;
ast = this._astBuilder.build(sourceCode, sourceName, sourceType); ast = AstBuilder.build(sourceCode, sourceName, sourceType);
if (ast) { if (ast) {
this._walkAst(ast, this._visitor, sourceName); this._walkAst(ast, this._visitor, sourceName);
} }

View File

@ -2,7 +2,7 @@
* @module jsdoc/src/visitor * @module jsdoc/src/visitor
*/ */
// TODO: consider exporting more stuff so users can override it // TODO: consider exporting more stuff so users can override it
const astNode = require('jsdoc/src/astnode'); const { astNode } = require('@jsdoc/parse');
const combineDoclets = require('jsdoc/doclet').combine; const combineDoclets = require('jsdoc/doclet').combine;
const { getBasename, LONGNAMES } = require('@jsdoc/core').name; const { getBasename, LONGNAMES } = require('@jsdoc/core').name;
const { Syntax } = require('@jsdoc/parse'); const { Syntax } = require('@jsdoc/parse');

View File

@ -3,7 +3,7 @@
* *
* @module jsdoc/src/walker * @module jsdoc/src/walker
*/ */
const astnode = require('jsdoc/src/astnode'); const { astNode } = require('@jsdoc/parse');
const { log } = require('@jsdoc/util'); const { log } = require('@jsdoc/util');
const { Syntax } = require('@jsdoc/parse'); const { Syntax } = require('@jsdoc/parse');
@ -655,9 +655,9 @@ class Walker {
function cb(node, parent, cbState) { function cb(node, parent, cbState) {
let currentScope; let currentScope;
const isScope = astnode.isScope(node); const isScope = astNode.isScope(node);
astnode.addNodeProperties(node); astNode.addNodeProperties(node);
node.parent = parent || null; node.parent = parent || null;
currentScope = getCurrentScope(cbState.scopes); currentScope = getCurrentScope(cbState.scopes);

View File

@ -8,7 +8,7 @@ const commonPathPrefix = require('common-path-prefix');
const env = require('jsdoc/env'); const env = require('jsdoc/env');
const { isInlineTag } = require('jsdoc/tag/inline'); const { isInlineTag } = require('jsdoc/tag/inline');
const { log } = require('@jsdoc/util'); const { log } = require('@jsdoc/util');
const { nodeToValue } = require('jsdoc/src/astnode'); const { nodeToValue } = require('@jsdoc/parse').astNode;
const path = require('path'); const path = require('path');
const { Syntax } = require('@jsdoc/parse'); const { Syntax } = require('@jsdoc/parse');
const parseTagType = require('jsdoc/tag/type').parse; const parseTagType = require('jsdoc/tag/type').parse;

View File

@ -20,8 +20,8 @@ describe('arrow functions', () => {
}); });
// TODO: we currently use the wrong longname in this case; see // TODO: we currently use the wrong longname in this case; see
// `module:jsdoc/src/astnode.nodeToValue` and the comment on `case Syntax.MethodDefinition` for // `module:@jsdoc/parse.astNode.nodeToValue` and the comment on `case Syntax.MethodDefinition`
// details // for details
xit('should use the correct longname for members of a class returned by an arrow function', xit('should use the correct longname for members of a class returned by an arrow function',
() => { () => {
expect(name).toBeArrayOfSize(2); expect(name).toBeArrayOfSize(2);

View File

@ -1,36 +0,0 @@
describe('jsdoc/src/astbuilder', () => {
const astbuilder = require('jsdoc/src/astbuilder');
it('should exist', () => {
expect(astbuilder).toBeObject();
});
it('should export an AstBuilder class', () => {
expect(astbuilder.AstBuilder).toBeFunction();
});
describe('AstBuilder', () => {
// TODO: more tests
let builder;
beforeEach(() => {
builder = new astbuilder.AstBuilder();
});
it('should provide a "build" method', () => {
expect(builder.build).toBeFunction();
});
describe('build', () => {
// TODO: more tests
it('should log (not throw) an error when a file cannot be parsed', () => {
function parse() {
builder.build('qwerty!!!!!', 'bad.js');
}
expect(parse).not.toThrow();
expect(jsdoc.didLog(parse, 'error')).toBeTrue();
});
});
});
});

View File

@ -49,10 +49,6 @@ describe('jsdoc/src/parser', () => {
newParser(); newParser();
it('should have an "astBuilder" property', () => {
expect(parser.astBuilder).toBeObject();
});
it('should have a "visitor" property', () => { it('should have a "visitor" property', () => {
expect(parser.visitor).toBeObject(); expect(parser.visitor).toBeObject();
}); });
@ -61,22 +57,6 @@ describe('jsdoc/src/parser', () => {
expect(parser.walker).toBeObject(); expect(parser.walker).toBeObject();
}); });
it('should accept an astBuilder, visitor, and walker as arguments', () => {
const astBuilder = {};
const visitor = {
/* eslint-disable no-empty-function */
setParser() {}
/* eslint-enable no-empty-function */
};
const walker = {};
const myParser = new jsdocParser.Parser(astBuilder, visitor, walker);
expect(myParser.astBuilder).toBe(astBuilder);
expect(myParser.visitor).toBe(visitor);
expect(myParser.walker).toBe(walker);
});
it('should have a "parse" method', () => { it('should have a "parse" method', () => {
expect(parser.parse).toBeFunction(); expect(parser.parse).toBeFunction();
}); });
@ -93,14 +73,6 @@ describe('jsdoc/src/parser', () => {
expect(parser.getAstNodeVisitors).toBeFunction(); expect(parser.getAstNodeVisitors).toBeFunction();
}); });
describe('astBuilder', () => {
it('should contain an appropriate astBuilder by default', () => {
const { AstBuilder } = require('jsdoc/src/astbuilder');
expect(parser.astBuilder instanceof AstBuilder).toBeTrue();
});
});
describe('visitor', () => { describe('visitor', () => {
it('should contain an appropriate visitor by default', () => { it('should contain an appropriate visitor by default', () => {
const { Visitor } = require('jsdoc/src/visitor'); const { Visitor } = require('jsdoc/src/visitor');