From 65e6db3ba45c358c06d2da712408f69b98ed1ce8 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Thu, 24 Dec 2020 16:05:58 -0800 Subject: [PATCH] refactor: move ast-builder and ast-node to @jsdoc/parse BREAKING CHANGE: Modules no longer exist in jsdoc package. --- packages/jsdoc-parse/index.js | 4 ++ .../lib/ast-builder.js} | 6 +-- .../lib/ast-node.js} | 8 ++-- packages/jsdoc-parse/test/specs/index.js | 16 ++++++++ .../jsdoc-parse/test/specs/lib/ast-builder.js | 41 +++++++++++++++++++ .../test/specs/lib/ast-node.js} | 14 +++---- packages/jsdoc/lib/jsdoc/doclet.js | 4 +- packages/jsdoc/lib/jsdoc/src/parser.js | 21 ++++------ packages/jsdoc/lib/jsdoc/src/visitor.js | 2 +- packages/jsdoc/lib/jsdoc/src/walker.js | 6 +-- .../lib/jsdoc/tag/dictionary/definitions.js | 2 +- .../test/specs/documentation/arrowfunction.js | 4 +- .../jsdoc/test/specs/jsdoc/src/astbuilder.js | 36 ---------------- packages/jsdoc/test/specs/jsdoc/src/parser.js | 28 ------------- 14 files changed, 91 insertions(+), 101 deletions(-) rename packages/{jsdoc/lib/jsdoc/src/astbuilder.js => jsdoc-parse/lib/ast-builder.js} (89%) rename packages/{jsdoc/lib/jsdoc/src/astnode.js => jsdoc-parse/lib/ast-node.js} (99%) create mode 100644 packages/jsdoc-parse/test/specs/lib/ast-builder.js rename packages/{jsdoc/test/specs/jsdoc/src/astnode.js => jsdoc-parse/test/specs/lib/ast-node.js} (98%) delete mode 100644 packages/jsdoc/test/specs/jsdoc/src/astbuilder.js diff --git a/packages/jsdoc-parse/index.js b/packages/jsdoc-parse/index.js index da5b4e95..0ba0cb06 100644 --- a/packages/jsdoc-parse/index.js +++ b/packages/jsdoc-parse/index.js @@ -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 }; diff --git a/packages/jsdoc/lib/jsdoc/src/astbuilder.js b/packages/jsdoc-parse/lib/ast-builder.js similarity index 89% rename from packages/jsdoc/lib/jsdoc/src/astbuilder.js rename to packages/jsdoc-parse/lib/ast-builder.js index a4320e3b..8845cf6d 100644 --- a/packages/jsdoc/lib/jsdoc/src/astbuilder.js +++ b/packages/jsdoc-parse/lib/ast-builder.js @@ -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; diff --git a/packages/jsdoc/lib/jsdoc/src/astnode.js b/packages/jsdoc-parse/lib/ast-node.js similarity index 99% rename from packages/jsdoc/lib/jsdoc/src/astnode.js rename to packages/jsdoc-parse/lib/ast-node.js index 6935eccf..f3d48ce2 100644 --- a/packages/jsdoc/lib/jsdoc/src/astnode.js +++ b/packages/jsdoc-parse/lib/ast-node.js @@ -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. */ diff --git a/packages/jsdoc-parse/test/specs/index.js b/packages/jsdoc-parse/test/specs/index.js index 5c810a8f..c7878e17 100644 --- a/packages/jsdoc-parse/test/specs/index.js +++ b/packages/jsdoc-parse/test/specs/index.js @@ -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'); diff --git a/packages/jsdoc-parse/test/specs/lib/ast-builder.js b/packages/jsdoc-parse/test/specs/lib/ast-builder.js new file mode 100644 index 00000000..44f6f459 --- /dev/null +++ b/packages/jsdoc-parse/test/specs/lib/ast-builder.js @@ -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 + }); +}); diff --git a/packages/jsdoc/test/specs/jsdoc/src/astnode.js b/packages/jsdoc-parse/test/specs/lib/ast-node.js similarity index 98% rename from packages/jsdoc/test/specs/jsdoc/src/astnode.js rename to packages/jsdoc-parse/test/specs/lib/ast-node.js index 58a49e0f..f427a9f7 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/astnode.js +++ b/packages/jsdoc-parse/test/specs/lib/ast-node.js @@ -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 `` 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 `` for method definitions inside classes that were ' + 'returned by an arrow function expression', () => { expect( astNode.nodeToValue(methodDefinition2) ).toBe(''); diff --git a/packages/jsdoc/lib/jsdoc/doclet.js b/packages/jsdoc/lib/jsdoc/doclet.js index 0be0546f..c7b7fcf8 100644 --- a/packages/jsdoc/lib/jsdoc/doclet.js +++ b/packages/jsdoc/lib/jsdoc/doclet.js @@ -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; diff --git a/packages/jsdoc/lib/jsdoc/src/parser.js b/packages/jsdoc/lib/jsdoc/src/parser.js index 7b24ea1c..f3c0bea2 100644 --- a/packages/jsdoc/lib/jsdoc/src/parser.js +++ b/packages/jsdoc/lib/jsdoc/src/parser.js @@ -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); } diff --git a/packages/jsdoc/lib/jsdoc/src/visitor.js b/packages/jsdoc/lib/jsdoc/src/visitor.js index 6ab0bef2..2d0f81d2 100644 --- a/packages/jsdoc/lib/jsdoc/src/visitor.js +++ b/packages/jsdoc/lib/jsdoc/src/visitor.js @@ -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'); diff --git a/packages/jsdoc/lib/jsdoc/src/walker.js b/packages/jsdoc/lib/jsdoc/src/walker.js index 3f82043d..7414940e 100644 --- a/packages/jsdoc/lib/jsdoc/src/walker.js +++ b/packages/jsdoc/lib/jsdoc/src/walker.js @@ -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); diff --git a/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js b/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js index e83531e6..b06c43fb 100644 --- a/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js +++ b/packages/jsdoc/lib/jsdoc/tag/dictionary/definitions.js @@ -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; diff --git a/packages/jsdoc/test/specs/documentation/arrowfunction.js b/packages/jsdoc/test/specs/documentation/arrowfunction.js index 0d4a0779..9e5c34b3 100644 --- a/packages/jsdoc/test/specs/documentation/arrowfunction.js +++ b/packages/jsdoc/test/specs/documentation/arrowfunction.js @@ -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); diff --git a/packages/jsdoc/test/specs/jsdoc/src/astbuilder.js b/packages/jsdoc/test/specs/jsdoc/src/astbuilder.js deleted file mode 100644 index 5dd5fb34..00000000 --- a/packages/jsdoc/test/specs/jsdoc/src/astbuilder.js +++ /dev/null @@ -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(); - }); - }); - }); -}); diff --git a/packages/jsdoc/test/specs/jsdoc/src/parser.js b/packages/jsdoc/test/specs/jsdoc/src/parser.js index 5147d30e..bc6850ba 100644 --- a/packages/jsdoc/test/specs/jsdoc/src/parser.js +++ b/packages/jsdoc/test/specs/jsdoc/src/parser.js @@ -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');