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');
module.exports = {
AstBuilder,
astNode,
Syntax
};

View File

@ -2,7 +2,7 @@ const _ = require('lodash');
const babelParser = require('@babel/parser');
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 = {
allowAwaitOutsideFunction: true,
allowImportExportEverywhere: true,
@ -58,10 +58,8 @@ function parse(source, filename, sourceType) {
// TODO: docs
class AstBuilder {
// TODO: docs
/* eslint-disable class-methods-use-this */
build(source, filename, sourceType) {
static build(source, filename, sourceType) {
return parse(source, filename, sourceType);
}
/* eslint-enable class-methods-use-this */
}
exports.AstBuilder = AstBuilder;

View File

@ -1,9 +1,9 @@
// TODO: docs
/** @module jsdoc/src/astnode */
/** @module @jsdoc/parse.astNode */
const _ = require('lodash');
const { cast } = require('@jsdoc/util');
const { SCOPE } = require('@jsdoc/core').name;
const { Syntax } = require('@jsdoc/parse');
const { Syntax } = require('./syntax');
// Counter for generating unique node IDs.
let uid = 100000000;
@ -11,7 +11,7 @@ let uid = 100000000;
/**
* 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.
* @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.
*
* @alias module:jsdoc/src/astnode.isScope
* @alias module:@jsdoc/parse.astNode.isScope
* @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.
*/

View File

@ -5,6 +5,22 @@ describe('@jsdoc/parse', () => {
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', () => {
it('is lib/syntax.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', () => {
const astBuilder = require('jsdoc/src/astbuilder');
const astNode = require('jsdoc/src/astnode');
describe('@jsdoc/parse/lib/ast-node', () => {
const astNode = require('../../../lib/ast-node');
const babelParser = require('@babel/parser');
const { Syntax } = require('@jsdoc/parse');
const { parserOptions } = require('../../../lib/ast-builder');
const { Syntax } = require('../../../lib/syntax');
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
@ -526,8 +526,8 @@ describe('jsdoc/src/astNode', () => {
// 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;
// see `module:jsdoc/src/astnode.nodeToValue` and the comment on `Syntax.MethodDefinition`
// for details
// see `module:@jsdoc/parse.astNode.nodeToValue` and the comment on
// `Syntax.MethodDefinition` for details
xit('should return `<anonymous>` for method definitions inside classes that were ' +
'returned by an arrow function expression', () => {
expect( astNode.nodeToValue(methodDefinition2) ).toBe('<anonymous>');

View File

@ -3,7 +3,7 @@
*/
const _ = require('lodash');
let dictionary = require('jsdoc/tag/dictionary');
const { isFunction } = require('jsdoc/src/astnode');
const { isFunction } = require('@jsdoc/parse').astNode;
const {
applyNamespace,
hasLeadingScope,
@ -31,7 +31,7 @@ function fakeMeta(node) {
}
// 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) {
let kind = 'member';
const node = code.node;

View File

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

View File

@ -2,7 +2,7 @@
* @module jsdoc/src/visitor
*/
// 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 { getBasename, LONGNAMES } = require('@jsdoc/core').name;
const { Syntax } = require('@jsdoc/parse');

View File

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

View File

@ -8,7 +8,7 @@ const commonPathPrefix = require('common-path-prefix');
const env = require('jsdoc/env');
const { isInlineTag } = require('jsdoc/tag/inline');
const { log } = require('@jsdoc/util');
const { nodeToValue } = require('jsdoc/src/astnode');
const { nodeToValue } = require('@jsdoc/parse').astNode;
const path = require('path');
const { Syntax } = require('@jsdoc/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
// `module:jsdoc/src/astnode.nodeToValue` and the comment on `case Syntax.MethodDefinition` for
// details
// `module:@jsdoc/parse.astNode.nodeToValue` and the comment on `case Syntax.MethodDefinition`
// for details
xit('should use the correct longname for members of a class returned by an arrow function',
() => {
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();
it('should have an "astBuilder" property', () => {
expect(parser.astBuilder).toBeObject();
});
it('should have a "visitor" property', () => {
expect(parser.visitor).toBeObject();
});
@ -61,22 +57,6 @@ describe('jsdoc/src/parser', () => {
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', () => {
expect(parser.parse).toBeFunction();
});
@ -93,14 +73,6 @@ describe('jsdoc/src/parser', () => {
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', () => {
it('should contain an appropriate visitor by default', () => {
const { Visitor } = require('jsdoc/src/visitor');