mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
refactor: provide logging functions in dependencies; stop using EventBus
These changes enable templates to use the logging functions even if they're not installed in the same `node_modules` directory as JSDoc. Includes API changes to various modules and functions that didn't have access to the dependency object. Most notably, you now call a function to retrieve tag definitions, rather than just using an exported object as-is.
This commit is contained in:
parent
4bcf76c830
commit
89f2c72da4
@ -13,8 +13,8 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import babelParser from '@babel/parser';
|
||||
import { log } from '@jsdoc/util';
|
||||
import _ from 'lodash';
|
||||
|
||||
// Exported so we can use them in tests.
|
||||
@ -62,23 +62,24 @@ export const parserOptions = {
|
||||
ranges: true,
|
||||
};
|
||||
|
||||
function parse(source, filename, sourceType) {
|
||||
let ast;
|
||||
const options = _.defaults({}, parserOptions, { sourceType });
|
||||
|
||||
try {
|
||||
ast = babelParser.parse(source, options);
|
||||
} catch (e) {
|
||||
log.error(`Unable to parse ${filename}: ${e.message}`);
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
|
||||
// TODO: docs
|
||||
export class AstBuilder {
|
||||
// TODO: docs
|
||||
static build(source, filename, sourceType) {
|
||||
return parse(source, filename, sourceType);
|
||||
#log;
|
||||
|
||||
constructor(deps) {
|
||||
this.#log = deps.get('log');
|
||||
}
|
||||
|
||||
build(source, filename, sourceType) {
|
||||
let ast;
|
||||
const options = _.defaults({}, parserOptions, { sourceType });
|
||||
|
||||
try {
|
||||
ast = babelParser.parse(source, options);
|
||||
} catch (e) {
|
||||
this.#log.error(`Unable to parse ${filename}: ${e.message}`);
|
||||
}
|
||||
|
||||
return ast;
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,10 +13,10 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Traversal utilities for ASTs that are compatible with the ESTree API.
|
||||
*/
|
||||
import { log } from '@jsdoc/util';
|
||||
|
||||
import * as astNode from './ast-node.js';
|
||||
import { Syntax } from './syntax.js';
|
||||
@ -645,7 +645,8 @@ walkers[Syntax.YieldExpression] = (node, parent, state, cb) => {
|
||||
*/
|
||||
export class Walker {
|
||||
// TODO: docs
|
||||
constructor(walkerFuncs = walkers) {
|
||||
constructor(deps, walkerFuncs = walkers) {
|
||||
this._log = deps.get('log');
|
||||
this._walkers = walkerFuncs;
|
||||
}
|
||||
|
||||
@ -659,7 +660,7 @@ export class Walker {
|
||||
};
|
||||
|
||||
function logUnknownNodeType({ type }) {
|
||||
log.debug(
|
||||
self._log.debug(
|
||||
`Found a node with unrecognized type ${type}. Ignoring the node and its descendants.`
|
||||
);
|
||||
}
|
||||
|
||||
@ -13,8 +13,13 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/* global jsdoc */
|
||||
|
||||
import * as astBuilder from '../../../lib/ast-builder.js';
|
||||
|
||||
const { AstBuilder } = astBuilder;
|
||||
|
||||
describe('@jsdoc/ast/lib/ast-builder', () => {
|
||||
it('is an object', () => {
|
||||
expect(astBuilder).toBeObject();
|
||||
@ -29,23 +34,26 @@ describe('@jsdoc/ast/lib/ast-builder', () => {
|
||||
});
|
||||
|
||||
describe('AstBuilder', () => {
|
||||
const { AstBuilder } = astBuilder;
|
||||
let instance;
|
||||
|
||||
beforeEach(() => {
|
||||
instance = new AstBuilder(jsdoc.deps);
|
||||
});
|
||||
|
||||
// TODO: more tests
|
||||
it('has a "build" static method', () => {
|
||||
expect(AstBuilder.build).toBeFunction();
|
||||
it('has a `build` method', () => {
|
||||
expect(instance.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');
|
||||
instance.build('qwerty!!!!!', 'bad.js');
|
||||
}
|
||||
|
||||
expect(parse).not.toThrow();
|
||||
// TODO: figure out why this stopped working
|
||||
// expect(jsdoc.didLog(parse, 'error')).toBeTrue();
|
||||
expect(jsdoc.didLog(parse, 'error')).toBeTrue();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@ -13,7 +13,10 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { EventBus } from '@jsdoc/util';
|
||||
|
||||
import EventEmitter from 'node:events';
|
||||
|
||||
import { getLogFunctions } from '@jsdoc/util';
|
||||
import _ from 'lodash';
|
||||
import ow from 'ow';
|
||||
import yargs from 'yargs-parser';
|
||||
@ -116,14 +119,13 @@ export default class Engine {
|
||||
ow(opts.revision, ow.optional.date);
|
||||
ow(opts.version, ow.optional.string);
|
||||
|
||||
this._bus = new EventBus('jsdoc', {
|
||||
cache: _.isBoolean(opts._cacheEventBus) ? opts._cacheEventBus : true,
|
||||
});
|
||||
this.emitter = new EventEmitter();
|
||||
this.flags = [];
|
||||
this._logger = new Logger({
|
||||
emitter: this._bus,
|
||||
emitter: this.emitter,
|
||||
level: opts.logLevel,
|
||||
});
|
||||
this.flags = [];
|
||||
this.log = getLogFunctions(this.emitter);
|
||||
this.revision = opts.revision;
|
||||
this.version = opts.version;
|
||||
}
|
||||
|
||||
@ -13,22 +13,12 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import RealEngine from '../../../lib/engine.js';
|
||||
import Engine from '../../../lib/engine.js';
|
||||
import flags from '../../../lib/flags.js';
|
||||
import { LEVELS } from '../../../lib/logger.js';
|
||||
|
||||
const TYPE_ERROR = 'TypeError';
|
||||
|
||||
// Wrapper to prevent reuse of the event bus, which leads to `MaxListenersExceededWarning` messages.
|
||||
class Engine extends RealEngine {
|
||||
constructor(opts) {
|
||||
opts = opts || {};
|
||||
opts._cacheEventBus = false;
|
||||
|
||||
super(opts);
|
||||
}
|
||||
}
|
||||
|
||||
describe('@jsdoc/cli/lib/engine', () => {
|
||||
it('exists', () => {
|
||||
expect(Engine).toBeFunction();
|
||||
|
||||
@ -13,7 +13,8 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { EventBus } from '@jsdoc/util';
|
||||
|
||||
import EventEmitter from 'node:events';
|
||||
|
||||
import { LEVELS, Logger } from '../../../lib/logger.js';
|
||||
|
||||
@ -22,21 +23,18 @@ const TYPE_ERROR = 'TypeError';
|
||||
|
||||
describe('@jsdoc/cli/lib/logger', () => {
|
||||
describe('Logger', () => {
|
||||
let bus;
|
||||
let emitter;
|
||||
let logger;
|
||||
|
||||
beforeEach(() => {
|
||||
bus = new EventBus('loggerTest', {
|
||||
_console: console,
|
||||
cache: false,
|
||||
});
|
||||
logger = new Logger({ emitter: bus });
|
||||
emitter = new EventEmitter();
|
||||
logger = new Logger({ emitter });
|
||||
|
||||
['debug', 'error', 'info', 'warn'].forEach((func) => spyOn(console, func));
|
||||
});
|
||||
|
||||
it('exports a Logger constructor', () => {
|
||||
expect(() => new Logger({ emitter: bus })).not.toThrow();
|
||||
expect(() => new Logger({ emitter })).not.toThrow();
|
||||
});
|
||||
|
||||
it('exports a LEVELS enum', () => {
|
||||
@ -49,7 +47,7 @@ describe('@jsdoc/cli/lib/logger', () => {
|
||||
});
|
||||
|
||||
it('accepts a valid emitter', () => {
|
||||
expect(() => new Logger({ emitter: bus })).not.toThrow();
|
||||
expect(() => new Logger({ emitter })).not.toThrow();
|
||||
});
|
||||
|
||||
it('throws on an invalid emitter', () => {
|
||||
@ -60,7 +58,7 @@ describe('@jsdoc/cli/lib/logger', () => {
|
||||
expect(
|
||||
() =>
|
||||
new Logger({
|
||||
emitter: bus,
|
||||
emitter,
|
||||
level: LEVELS.VERBOSE,
|
||||
})
|
||||
).not.toThrow();
|
||||
@ -70,7 +68,7 @@ describe('@jsdoc/cli/lib/logger', () => {
|
||||
expect(
|
||||
() =>
|
||||
new Logger({
|
||||
emitter: bus,
|
||||
emitter,
|
||||
level: LEVELS.VERBOSE + 1,
|
||||
})
|
||||
).toThrowErrorOfType(TYPE_ERROR);
|
||||
@ -83,85 +81,85 @@ describe('@jsdoc/cli/lib/logger', () => {
|
||||
const eventType = 'logger:info';
|
||||
|
||||
logger.level = LEVELS.VERBOSE;
|
||||
bus.emit(eventType, ...args);
|
||||
emitter.emit(eventType, ...args);
|
||||
|
||||
expect(console.info).toHaveBeenCalledWith(...args);
|
||||
});
|
||||
|
||||
it('logs logger:fatal events by default', () => {
|
||||
bus.emit('logger:fatal');
|
||||
emitter.emit('logger:fatal');
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not log logger:fatal events when level is SILENT', () => {
|
||||
logger.level = LEVELS.SILENT;
|
||||
bus.emit('logger:fatal');
|
||||
emitter.emit('logger:fatal');
|
||||
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('logs logger:error events by default', () => {
|
||||
bus.emit('logger:error');
|
||||
emitter.emit('logger:error');
|
||||
|
||||
expect(console.error).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not log logger:error events when level is FATAL', () => {
|
||||
logger.level = LEVELS.FATAL;
|
||||
bus.emit('logger:error');
|
||||
emitter.emit('logger:error');
|
||||
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('logs logger:warn events by default', () => {
|
||||
bus.emit('logger:warn');
|
||||
emitter.emit('logger:warn');
|
||||
|
||||
expect(console.warn).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not log logger:warn events when level is ERROR', () => {
|
||||
logger.level = LEVELS.ERROR;
|
||||
bus.emit('logger:warn');
|
||||
emitter.emit('logger:warn');
|
||||
|
||||
expect(console.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not log logger:info events by default', () => {
|
||||
bus.emit('logger:info');
|
||||
emitter.emit('logger:info');
|
||||
|
||||
expect(console.info).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('logs logger:info events when level is INFO', () => {
|
||||
logger.level = LEVELS.INFO;
|
||||
bus.emit('logger:info');
|
||||
emitter.emit('logger:info');
|
||||
|
||||
expect(console.info).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not log logger:debug events by default', () => {
|
||||
bus.emit('logger:debug');
|
||||
emitter.emit('logger:debug');
|
||||
|
||||
expect(console.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('logs logger:debug events when level is DEBUG', () => {
|
||||
logger.level = LEVELS.DEBUG;
|
||||
bus.emit('logger:debug');
|
||||
emitter.emit('logger:debug');
|
||||
|
||||
expect(console.debug).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('does not log logger:verbose events by default', () => {
|
||||
bus.emit('logger:verbose');
|
||||
emitter.emit('logger:verbose');
|
||||
|
||||
expect(console.debug).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('logs logger:verbose events when level is VERBOSE', () => {
|
||||
logger.level = LEVELS.VERBOSE;
|
||||
bus.emit('logger:verbose');
|
||||
emitter.emit('logger:verbose');
|
||||
|
||||
expect(console.debug).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -55,7 +55,7 @@ function removeFromSet(targetMap, key, value) {
|
||||
export class DocletStore {
|
||||
#commonPathPrefix;
|
||||
#docletChangedHandler;
|
||||
#eventBus;
|
||||
#emitter;
|
||||
#isListening;
|
||||
#newDocletHandler;
|
||||
#sourcePaths;
|
||||
@ -76,7 +76,7 @@ export class DocletStore {
|
||||
|
||||
constructor(dependencies) {
|
||||
this.#commonPathPrefix = null;
|
||||
this.#eventBus = dependencies.get('eventBus');
|
||||
this.#emitter = dependencies.get('emitter');
|
||||
this.#isListening = false;
|
||||
this.#sourcePaths = new Map();
|
||||
|
||||
@ -357,8 +357,8 @@ export class DocletStore {
|
||||
|
||||
startListening() {
|
||||
if (!this.#isListening) {
|
||||
this.#eventBus.on('docletChanged', this.#docletChangedHandler);
|
||||
this.#eventBus.on('newDoclet', this.#newDocletHandler);
|
||||
this.#emitter.on('docletChanged', this.#docletChangedHandler);
|
||||
this.#emitter.on('newDoclet', this.#newDocletHandler);
|
||||
|
||||
this.#isListening = true;
|
||||
}
|
||||
@ -366,8 +366,8 @@ export class DocletStore {
|
||||
|
||||
stopListening() {
|
||||
if (this.#isListening) {
|
||||
this.#eventBus.removeListener('docletChanged', this.#docletChangedHandler);
|
||||
this.#eventBus.removeListener('newDoclet', this.#newDocletHandler);
|
||||
this.#emitter.removeListener('docletChanged', this.#docletChangedHandler);
|
||||
this.#emitter.removeListener('newDoclet', this.#newDocletHandler);
|
||||
|
||||
this.#isListening = false;
|
||||
}
|
||||
|
||||
@ -327,8 +327,8 @@ function getFilepath(doclet) {
|
||||
return path.join(doclet.meta.path || '', doclet.meta.filename);
|
||||
}
|
||||
|
||||
function emitDocletChanged(eventBus, doclet, property, oldValue, newValue) {
|
||||
eventBus.emit('docletChanged', { doclet, property, oldValue, newValue });
|
||||
function emitDocletChanged(emitter, doclet, property, oldValue, newValue) {
|
||||
emitter.emit('docletChanged', { doclet, property, oldValue, newValue });
|
||||
}
|
||||
|
||||
function clone(source, target, properties) {
|
||||
@ -453,9 +453,9 @@ Doclet = class {
|
||||
*/
|
||||
constructor(docletSrc, meta, dependencies) {
|
||||
const accessConfig = dependencies.get('config')?.opts?.access?.slice() ?? [];
|
||||
const eventBus = dependencies.get('eventBus');
|
||||
const emitter = dependencies.get('emitter');
|
||||
const boundDefineWatchableProp = defineWatchableProp.bind(null, this);
|
||||
const boundEmitDocletChanged = emitDocletChanged.bind(null, eventBus, this);
|
||||
const boundEmitDocletChanged = emitDocletChanged.bind(null, emitter, this);
|
||||
let newTags = [];
|
||||
|
||||
this.#dictionary = dependencies.get('tags');
|
||||
|
||||
@ -13,7 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { log } from '@jsdoc/util';
|
||||
|
||||
import stripBom from 'strip-bom';
|
||||
|
||||
/**
|
||||
@ -79,8 +79,10 @@ function getLicenses(packageInfo) {
|
||||
export class Package {
|
||||
/**
|
||||
* @param {string} json - The contents of the `package.json` file.
|
||||
* @param {Object} deps - The JSDoc dependencies.
|
||||
*/
|
||||
constructor(json) {
|
||||
constructor(json, deps) {
|
||||
const log = deps.get('log');
|
||||
let packageInfo;
|
||||
|
||||
/**
|
||||
|
||||
@ -29,7 +29,7 @@ function makeDoclet(comment, meta, deps) {
|
||||
deps ??= jsdoc.deps;
|
||||
doclet = new Doclet(`/**\n${comment.join('\n')}\n*/`, meta, deps);
|
||||
if (meta?._emitEvent !== false) {
|
||||
deps.get('eventBus').emit('newDoclet', { doclet });
|
||||
deps.get('emitter').emit('newDoclet', { doclet });
|
||||
}
|
||||
|
||||
return doclet;
|
||||
|
||||
@ -357,7 +357,7 @@ describe('@jsdoc/doclet/lib/doclet', () => {
|
||||
config.opts.access = access.slice();
|
||||
}
|
||||
map.set('config', config);
|
||||
map.set('eventBus', jsdoc.deps.get('eventBus'));
|
||||
map.set('emitter', jsdoc.deps.get('emitter'));
|
||||
map.set('tags', jsdoc.deps.get('tags'));
|
||||
|
||||
return map;
|
||||
@ -501,7 +501,7 @@ describe('@jsdoc/doclet/lib/doclet', () => {
|
||||
});
|
||||
|
||||
describe('watchable properties', () => {
|
||||
const eventBus = jsdoc.deps.get('eventBus');
|
||||
const emitter = jsdoc.deps.get('emitter');
|
||||
let events;
|
||||
|
||||
function listener(e) {
|
||||
@ -509,12 +509,12 @@ describe('@jsdoc/doclet/lib/doclet', () => {
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
eventBus.on('docletChanged', listener);
|
||||
emitter.on('docletChanged', listener);
|
||||
events = [];
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
eventBus.removeListener('docletChanged', listener);
|
||||
emitter.removeListener('docletChanged', listener);
|
||||
});
|
||||
|
||||
it('sends events to the event bus when watchable properties change', () => {
|
||||
|
||||
@ -13,7 +13,9 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/* global jsdoc */
|
||||
|
||||
import * as jsdocPackage from '../../../lib/package.js';
|
||||
|
||||
const { Package } = jsdocPackage;
|
||||
@ -26,7 +28,7 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
const obj = {};
|
||||
|
||||
obj[name] = value;
|
||||
myPackage = new Package(JSON.stringify(obj));
|
||||
myPackage = new Package(JSON.stringify(obj), jsdoc.deps);
|
||||
// Add the package object to the cached parse results, so we can validate it against the
|
||||
// doclet schema.
|
||||
jsdoc.addParseResults(`package-property-${name}.js`, [myPackage]);
|
||||
@ -44,12 +46,12 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
|
||||
describe('Package', () => {
|
||||
beforeEach(() => {
|
||||
emptyPackage = new Package();
|
||||
emptyPackage = new Package(null, jsdoc.deps);
|
||||
});
|
||||
|
||||
it('accepts a JSON-format string', () => {
|
||||
function newPackage() {
|
||||
return new Package('{"foo": "bar"}');
|
||||
return new Package('{"foo": "bar"}', jsdoc.deps);
|
||||
}
|
||||
|
||||
expect(newPackage).not.toThrow();
|
||||
@ -57,15 +59,7 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
|
||||
it('accepts a JSON-format string with a leading BOM', () => {
|
||||
function newPackage() {
|
||||
return new Package('\uFEFF{}');
|
||||
}
|
||||
|
||||
expect(newPackage).not.toThrow();
|
||||
});
|
||||
|
||||
it('works with no arguments', () => {
|
||||
function newPackage() {
|
||||
return new Package();
|
||||
return new Package('\uFEFF{}', jsdoc.deps);
|
||||
}
|
||||
|
||||
expect(newPackage).not.toThrow();
|
||||
@ -73,7 +67,7 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
|
||||
it('logs an error when called with bad input', () => {
|
||||
function newPackage() {
|
||||
return new Package('abcdefg');
|
||||
return new Package('abcdefg', jsdoc.deps);
|
||||
}
|
||||
|
||||
expect(newPackage).not.toThrow();
|
||||
@ -164,7 +158,7 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
});
|
||||
|
||||
it('ignores the value from the package file', () => {
|
||||
const myPackage = new Package('{"files": ["foo", "bar"]}');
|
||||
const myPackage = new Package('{"files": ["foo", "bar"]}', jsdoc.deps);
|
||||
|
||||
expect(myPackage.files).toBeEmptyArray();
|
||||
});
|
||||
@ -205,7 +199,7 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
});
|
||||
|
||||
it('contains the value of `license` from the package file', () => {
|
||||
const myPackage = new Package('{"license": "My-OSS-License"}');
|
||||
const myPackage = new Package('{"license": "My-OSS-License"}', jsdoc.deps);
|
||||
|
||||
expect(myPackage.license).toBeUndefined();
|
||||
expect(myPackage.licenses).toBeArrayOfSize(1);
|
||||
@ -222,7 +216,7 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
},
|
||||
],
|
||||
};
|
||||
const myPackage = new Package(JSON.stringify(packageInfo));
|
||||
const myPackage = new Package(JSON.stringify(packageInfo), jsdoc.deps);
|
||||
|
||||
expect(myPackage.licenses).toBeArrayOfSize(2);
|
||||
});
|
||||
@ -234,7 +228,7 @@ describe('@jsdoc/doclet/lib/package', () => {
|
||||
});
|
||||
|
||||
it('reflects the value of the `name` property', () => {
|
||||
const myPackage = new Package('{"name": "foo"}');
|
||||
const myPackage = new Package('{"name": "foo"}', jsdoc.deps);
|
||||
|
||||
expect(myPackage.longname).toBe('package:foo');
|
||||
});
|
||||
|
||||
@ -16,7 +16,6 @@
|
||||
import { Syntax } from '@jsdoc/ast';
|
||||
import { name } from '@jsdoc/core';
|
||||
import { Doclet } from '@jsdoc/doclet';
|
||||
import { log } from '@jsdoc/util';
|
||||
import escape from 'escape-string-regexp';
|
||||
|
||||
const PROTOTYPE_OWNER_REGEXP = /^(.+?)(\.prototype|#)$/;
|
||||
@ -43,6 +42,7 @@ function filterByLongname({ longname }) {
|
||||
function createDoclet(comment, e, deps) {
|
||||
let doclet;
|
||||
let flatComment;
|
||||
let log;
|
||||
let msg;
|
||||
|
||||
try {
|
||||
@ -50,6 +50,7 @@ function createDoclet(comment, e, deps) {
|
||||
} catch (error) {
|
||||
flatComment = comment.replace(/[\r\n]/g, '');
|
||||
msg = `cannot create a doclet for the comment "${flatComment}": ${error.message}`;
|
||||
log = deps.get('log');
|
||||
log.error(msg);
|
||||
doclet = new Doclet('', e, deps);
|
||||
}
|
||||
|
||||
@ -19,7 +19,6 @@ import fs from 'node:fs';
|
||||
import { AstBuilder, astNode, Syntax, Walker } from '@jsdoc/ast';
|
||||
import { name } from '@jsdoc/core';
|
||||
import { Doclet, DocletStore } from '@jsdoc/doclet';
|
||||
import { log } from '@jsdoc/util';
|
||||
import _ from 'lodash';
|
||||
|
||||
import { Visitor } from './visitor.js';
|
||||
@ -73,9 +72,10 @@ export class Parser extends EventEmitter {
|
||||
this._conf = dependencies.get('config');
|
||||
this._dependencies = dependencies;
|
||||
this._docletStore = new DocletStore(dependencies);
|
||||
this._eventBus = dependencies.get('eventBus');
|
||||
this._emitter = dependencies.get('emitter');
|
||||
this._log = dependencies.get('log');
|
||||
this._visitor = new Visitor();
|
||||
this._walker = new Walker();
|
||||
this._walker = new Walker(dependencies);
|
||||
|
||||
this._visitor.setParser(this);
|
||||
|
||||
@ -107,10 +107,10 @@ export class Parser extends EventEmitter {
|
||||
this._docletStore.stopListening();
|
||||
}
|
||||
|
||||
// TODO: Always emit events from the event bus, never from the parser.
|
||||
// TODO: Always emit events from the dependencies' emitter, never from the parser.
|
||||
emit(eventName, event, ...args) {
|
||||
super.emit(eventName, event, ...args);
|
||||
this._eventBus.emit(eventName, event, ...args);
|
||||
this._emitter.emit(eventName, event, ...args);
|
||||
}
|
||||
|
||||
// TODO: update docs
|
||||
@ -145,7 +145,7 @@ export class Parser extends EventEmitter {
|
||||
}
|
||||
|
||||
e.sourcefiles = sourceFiles;
|
||||
log.debug('Parsing source files: %j', sourceFiles);
|
||||
this._log.debug('Parsing source files: %j', sourceFiles);
|
||||
|
||||
this.emit('parseBegin', e);
|
||||
|
||||
@ -161,7 +161,7 @@ export class Parser extends EventEmitter {
|
||||
try {
|
||||
sourceCode = fs.readFileSync(filename, encoding);
|
||||
} catch (err) {
|
||||
log.error(`Unable to read and parse the source file ${filename}: ${err}`);
|
||||
this._log.error(`Unable to read and parse the source file ${filename}: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
@ -177,7 +177,7 @@ export class Parser extends EventEmitter {
|
||||
doclets: this.results(),
|
||||
});
|
||||
}
|
||||
log.debug('Finished parsing source files.');
|
||||
this._log.debug('Finished parsing source files.');
|
||||
|
||||
return this._docletStore;
|
||||
}
|
||||
@ -209,13 +209,14 @@ export class Parser extends EventEmitter {
|
||||
/** @private */
|
||||
_parseSourceCode(sourceCode, sourceName) {
|
||||
let ast;
|
||||
const builder = new AstBuilder(this._dependencies);
|
||||
let e = {
|
||||
filename: sourceName,
|
||||
};
|
||||
let sourceType;
|
||||
|
||||
this.emit('fileBegin', e);
|
||||
log.info(`Parsing ${sourceName} ...`);
|
||||
this._log.info(`Parsing ${sourceName} ...`);
|
||||
|
||||
if (!e.defaultPrevented) {
|
||||
e = {
|
||||
@ -229,7 +230,7 @@ export class Parser extends EventEmitter {
|
||||
sourceCode = pretreat(e.source);
|
||||
sourceType = this._conf.source ? this._conf.source.type : undefined;
|
||||
|
||||
ast = AstBuilder.build(sourceCode, sourceName, sourceType);
|
||||
ast = builder.build(sourceCode, sourceName, sourceType);
|
||||
if (ast) {
|
||||
this._walkAst(ast, this._visitor, sourceName);
|
||||
}
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { log } from '@jsdoc/util';
|
||||
|
||||
export const handlers = {
|
||||
/**
|
||||
@ -46,12 +45,10 @@ export const handlers = {
|
||||
try {
|
||||
value = JSON.parse(tag.value);
|
||||
} catch (ex) {
|
||||
log.error(
|
||||
throw new Error(
|
||||
'@source tag expects a valid JSON value, like ' +
|
||||
'{ "filename": "myfile.js", "lineno": 123 }.'
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
doclet.meta = doclet.meta || {};
|
||||
|
||||
@ -15,7 +15,7 @@
|
||||
*/
|
||||
// Tag dictionary for Google Closure Compiler.
|
||||
|
||||
import { tags as core } from './core.js';
|
||||
import { getTags as getCoreTags } from './core.js';
|
||||
import * as util from './util.js';
|
||||
|
||||
const NOOP_TAG = {
|
||||
@ -24,139 +24,143 @@ const NOOP_TAG = {
|
||||
},
|
||||
};
|
||||
|
||||
export const tags = {
|
||||
const: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.kind = 'constant';
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
export const getTags = (deps) => {
|
||||
const coreTags = getCoreTags(deps);
|
||||
|
||||
return {
|
||||
const: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.kind = 'constant';
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
},
|
||||
// Closure Compiler only
|
||||
synonyms: ['define'],
|
||||
},
|
||||
constructor: util.cloneTagDef(coreTags.class),
|
||||
deprecated: util.cloneTagDef(coreTags.deprecated),
|
||||
// Closure Compiler only
|
||||
dict: NOOP_TAG,
|
||||
enum: util.cloneTagDef(coreTags.enum),
|
||||
// Closure Compiler only
|
||||
export: NOOP_TAG,
|
||||
extends: util.cloneTagDef(coreTags.augments),
|
||||
// Closure Compiler only
|
||||
externs: NOOP_TAG,
|
||||
fileoverview: {
|
||||
onTagged(doclet, tag) {
|
||||
util.setNameToFile(doclet);
|
||||
doclet.kind = 'file';
|
||||
util.setDocletDescriptionToValue(doclet, tag);
|
||||
|
||||
doclet.preserveName = true;
|
||||
},
|
||||
},
|
||||
final: util.cloneTagDef(coreTags.readonly),
|
||||
implements: util.cloneTagDef(coreTags.implements),
|
||||
// Closure Compiler only
|
||||
implicitcast: NOOP_TAG,
|
||||
inheritdoc: util.cloneTagDef(coreTags.inheritdoc),
|
||||
interface: util.cloneTagDef(coreTags.interface, {
|
||||
canHaveName: false,
|
||||
mustNotHaveValue: true,
|
||||
// Closure Compiler only
|
||||
synonyms: ['record'],
|
||||
}),
|
||||
lends: util.cloneTagDef(coreTags.lends),
|
||||
license: util.cloneTagDef(coreTags.license),
|
||||
modifies: util.cloneTagDef(coreTags.modifies),
|
||||
// Closure Compiler only
|
||||
noalias: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
nocollapse: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
nocompile: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
nosideeffects: {
|
||||
onTagged(doclet) {
|
||||
doclet.modifies = [];
|
||||
},
|
||||
},
|
||||
// Closure Compiler only
|
||||
synonyms: ['define'],
|
||||
},
|
||||
constructor: util.cloneTagDef(core.class),
|
||||
deprecated: util.cloneTagDef(core.deprecated),
|
||||
// Closure Compiler only
|
||||
dict: NOOP_TAG,
|
||||
enum: util.cloneTagDef(core.enum),
|
||||
// Closure Compiler only
|
||||
export: NOOP_TAG,
|
||||
extends: util.cloneTagDef(core.augments),
|
||||
// Closure Compiler only
|
||||
externs: NOOP_TAG,
|
||||
fileoverview: {
|
||||
onTagged(doclet, tag) {
|
||||
util.setNameToFile(doclet);
|
||||
doclet.kind = 'file';
|
||||
util.setDocletDescriptionToValue(doclet, tag);
|
||||
|
||||
doclet.preserveName = true;
|
||||
override: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged(doclet) {
|
||||
doclet.override = true;
|
||||
},
|
||||
},
|
||||
},
|
||||
final: util.cloneTagDef(core.readonly),
|
||||
implements: util.cloneTagDef(core.implements),
|
||||
// Closure Compiler only
|
||||
implicitcast: NOOP_TAG,
|
||||
inheritdoc: util.cloneTagDef(core.inheritdoc),
|
||||
interface: util.cloneTagDef(core.interface, {
|
||||
canHaveName: false,
|
||||
mustNotHaveValue: true,
|
||||
package: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'package';
|
||||
|
||||
if (tag.value && tag.value.type) {
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
},
|
||||
param: util.cloneTagDef(coreTags.param),
|
||||
// Closure Compiler only
|
||||
synonyms: ['record'],
|
||||
}),
|
||||
lends: util.cloneTagDef(core.lends),
|
||||
license: util.cloneTagDef(core.license),
|
||||
modifies: util.cloneTagDef(core.modifies),
|
||||
// Closure Compiler only
|
||||
noalias: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
nocollapse: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
nocompile: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
nosideeffects: {
|
||||
onTagged(doclet) {
|
||||
doclet.modifies = [];
|
||||
},
|
||||
},
|
||||
// Closure Compiler only
|
||||
override: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged(doclet) {
|
||||
doclet.override = true;
|
||||
},
|
||||
},
|
||||
package: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'package';
|
||||
polymer: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
polymerBehavior: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
preserve: util.cloneTagDef(coreTags.license),
|
||||
private: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'private';
|
||||
|
||||
if (tag.value && tag.value.type) {
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
if (tag.value && tag.value.type) {
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
param: util.cloneTagDef(core.param),
|
||||
// Closure Compiler only
|
||||
polymer: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
polymerBehavior: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
preserve: util.cloneTagDef(core.license),
|
||||
private: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'private';
|
||||
protected: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'protected';
|
||||
|
||||
if (tag.value && tag.value.type) {
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
if (tag.value && tag.value.type) {
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
protected: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'protected';
|
||||
public: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'public';
|
||||
|
||||
if (tag.value && tag.value.type) {
|
||||
if (tag.value && tag.value.type) {
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
},
|
||||
return: util.cloneTagDef(coreTags.returns),
|
||||
// Closure Compiler only
|
||||
struct: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
suppress: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
template: NOOP_TAG,
|
||||
this: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.this = util.combineTypes(tag);
|
||||
},
|
||||
},
|
||||
throws: util.cloneTagDef(coreTags.throws),
|
||||
type: util.cloneTagDef(coreTags.type, {
|
||||
mustNotHaveDescription: false,
|
||||
}),
|
||||
typedef: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
util.setDocletKindToTitle(doclet, tag);
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
public: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.access = 'public';
|
||||
|
||||
if (tag.value && tag.value.type) {
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
}
|
||||
},
|
||||
},
|
||||
return: util.cloneTagDef(core.returns),
|
||||
// Closure Compiler only
|
||||
struct: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
suppress: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
template: NOOP_TAG,
|
||||
this: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
doclet.this = util.combineTypes(tag);
|
||||
},
|
||||
},
|
||||
throws: util.cloneTagDef(core.throws),
|
||||
type: util.cloneTagDef(core.type, {
|
||||
mustNotHaveDescription: false,
|
||||
}),
|
||||
typedef: {
|
||||
canHaveType: true,
|
||||
onTagged(doclet, tag) {
|
||||
util.setDocletKindToTitle(doclet, tag);
|
||||
util.setDocletTypeToValueType(doclet, tag);
|
||||
},
|
||||
},
|
||||
// Closure Compiler only
|
||||
unrestricted: NOOP_TAG,
|
||||
// Closure Compiler only
|
||||
unrestricted: NOOP_TAG,
|
||||
};
|
||||
};
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -13,10 +13,10 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { tags as closure } from './closure.js';
|
||||
import { tags as core } from './core.js';
|
||||
import { tags as internal } from './internal.js';
|
||||
import { tags as jsdoc } from './jsdoc.js';
|
||||
import { getTags as getClosureTags } from './closure.js';
|
||||
import { getTags as getCoreTags } from './core.js';
|
||||
import { getTags as getInternalTags } from './internal.js';
|
||||
import { getTags as getJsdocTags } from './jsdoc.js';
|
||||
|
||||
export { closure, core, internal, jsdoc };
|
||||
export default { closure, core, internal, jsdoc };
|
||||
export { getClosureTags, getCoreTags, getInternalTags, getJsdocTags };
|
||||
export default { getClosureTags, getCoreTags, getInternalTags, getJsdocTags };
|
||||
|
||||
@ -13,48 +13,51 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
// Tags that JSDoc uses internally, and that must always be defined.
|
||||
export const tags = {
|
||||
// Special separator tag indicating that multiple doclets should be generated for the same
|
||||
// comment. Used internally (and by some JSDoc users, although it's not officially supported).
|
||||
//
|
||||
// In the following example, the parser will replace `//**` with an `@also` tag:
|
||||
// /**
|
||||
// * Foo.
|
||||
// *//**
|
||||
// * Foo with a param.
|
||||
// * @param {string} bar
|
||||
// */
|
||||
// function foo(bar) {}
|
||||
also: {
|
||||
onTagged() {
|
||||
// Let the parser handle it. We define the tag here to avoid "not a known tag" errors.
|
||||
export const getTags = () => {
|
||||
return {
|
||||
// Special separator tag indicating that multiple doclets should be generated for the same
|
||||
// comment. Used internally (and by some JSDoc users, although it's not officially supported).
|
||||
//
|
||||
// In the following example, the parser will replace `//**` with an `@also` tag:
|
||||
// /**
|
||||
// * Foo.
|
||||
// *//**
|
||||
// * Foo with a param.
|
||||
// * @param {string} bar
|
||||
// */
|
||||
// function foo(bar) {}
|
||||
also: {
|
||||
onTagged() {
|
||||
// Let the parser handle it. We define the tag here to avoid "not a known tag" errors.
|
||||
},
|
||||
},
|
||||
},
|
||||
description: {
|
||||
mustHaveValue: true,
|
||||
onTagged: (doclet, { value }) => {
|
||||
doclet.description = value;
|
||||
description: {
|
||||
mustHaveValue: true,
|
||||
onTagged: (doclet, { value }) => {
|
||||
doclet.description = value;
|
||||
},
|
||||
synonyms: ['desc'],
|
||||
},
|
||||
synonyms: ['desc'],
|
||||
},
|
||||
kind: {
|
||||
mustHaveValue: true,
|
||||
onTagged: (doclet, { value }) => {
|
||||
doclet.kind = value;
|
||||
kind: {
|
||||
mustHaveValue: true,
|
||||
onTagged: (doclet, { value }) => {
|
||||
doclet.kind = value;
|
||||
},
|
||||
},
|
||||
},
|
||||
name: {
|
||||
mustHaveValue: true,
|
||||
onTagged: (doclet, { value }) => {
|
||||
doclet.name = value;
|
||||
name: {
|
||||
mustHaveValue: true,
|
||||
onTagged: (doclet, { value }) => {
|
||||
doclet.name = value;
|
||||
},
|
||||
},
|
||||
},
|
||||
undocumented: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged(doclet) {
|
||||
doclet.undocumented = true;
|
||||
doclet.comment = '';
|
||||
undocumented: {
|
||||
mustNotHaveValue: true,
|
||||
onTagged(doclet) {
|
||||
doclet.undocumented = true;
|
||||
doclet.comment = '';
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -13,4 +13,4 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
export { tags } from './core.js';
|
||||
export { getTags } from './core.js';
|
||||
|
||||
@ -13,10 +13,10 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import path from 'node:path';
|
||||
|
||||
import { name } from '@jsdoc/core';
|
||||
import { log } from '@jsdoc/util';
|
||||
import commonPathPrefix from 'common-path-prefix';
|
||||
import _ from 'lodash';
|
||||
|
||||
@ -74,10 +74,13 @@ export function setDocletKindToTitle(doclet, { title }) {
|
||||
doclet.addTag('kind', title);
|
||||
}
|
||||
|
||||
export function setDocletScopeToTitle(doclet, { title }) {
|
||||
export function setDocletScopeToTitle(doclet, { title }, deps) {
|
||||
let log;
|
||||
|
||||
try {
|
||||
doclet.setScope(title);
|
||||
} catch (e) {
|
||||
log = deps.get('log');
|
||||
log.error(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,14 +13,14 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/** @module @jsdoc/tag/lib/dictionary */
|
||||
import { log } from '@jsdoc/util';
|
||||
|
||||
import definitions from './definitions/index.js';
|
||||
|
||||
const DEFINITIONS = {
|
||||
closure: 'closure',
|
||||
jsdoc: 'jsdoc',
|
||||
closure: 'getClosureTags',
|
||||
jsdoc: 'getJsdocTags',
|
||||
};
|
||||
|
||||
/** @private */
|
||||
@ -103,9 +103,12 @@ export class Dictionary {
|
||||
this._tagSynonyms[synonym.toLowerCase()] = this.normalize(title);
|
||||
}
|
||||
|
||||
static fromConfig(env) {
|
||||
let dictionaries = env.conf.tags.dictionaries;
|
||||
static fromConfig(deps) {
|
||||
const dict = new Dictionary();
|
||||
const env = deps.get('env');
|
||||
const log = deps.get('log');
|
||||
let dictionaries = env.conf.tags.dictionaries;
|
||||
let tagDefs;
|
||||
|
||||
if (!dictionaries) {
|
||||
log.error(
|
||||
@ -117,9 +120,9 @@ export class Dictionary {
|
||||
.slice()
|
||||
.reverse()
|
||||
.forEach((dictName) => {
|
||||
const tagDefs = definitions[DEFINITIONS[dictName]];
|
||||
|
||||
if (!tagDefs) {
|
||||
try {
|
||||
tagDefs = definitions[DEFINITIONS[dictName]](deps);
|
||||
} catch (e) {
|
||||
log.error(
|
||||
'The configuration setting "tags.dictionaries" contains ' +
|
||||
`the unknown dictionary name ${dictName}. Ignoring the dictionary.`
|
||||
@ -131,7 +134,7 @@ export class Dictionary {
|
||||
dict.defineTags(tagDefs);
|
||||
});
|
||||
|
||||
dict.defineTags(definitions.internal);
|
||||
dict.defineTags(definitions.getInternalTags(deps));
|
||||
}
|
||||
|
||||
return dict;
|
||||
|
||||
@ -13,12 +13,13 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Functionality related to JSDoc tags.
|
||||
*/
|
||||
|
||||
import path from 'node:path';
|
||||
|
||||
import { log } from '@jsdoc/util';
|
||||
import _ from 'lodash';
|
||||
|
||||
import * as type from './type.js';
|
||||
@ -66,10 +67,13 @@ function addHiddenProperty(obj, propName, propValue, dependencies) {
|
||||
});
|
||||
}
|
||||
|
||||
function parseType({ text, originalTitle }, { canHaveName, canHaveType }, meta) {
|
||||
function parseType({ dependencies, text, originalTitle }, { canHaveName, canHaveType }, meta) {
|
||||
let log;
|
||||
|
||||
try {
|
||||
return type.parse(text, canHaveName, canHaveType);
|
||||
} catch (e) {
|
||||
log = dependencies.get('log');
|
||||
log.error(
|
||||
'Unable to parse a tag\'s type expression%s with tag title "%s" and text "%s": %s',
|
||||
meta.path && meta.filename
|
||||
|
||||
@ -13,7 +13,6 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { log } from '@jsdoc/util';
|
||||
|
||||
function buildMessage(tagName, { filename, lineno, comment }, desc) {
|
||||
let result = `The @${tagName} tag ${desc}. File: ${filename}, line: ${lineno}`;
|
||||
@ -30,6 +29,7 @@ function buildMessage(tagName, { filename, lineno, comment }, desc) {
|
||||
*/
|
||||
export function validate({ dependencies, title, text, value }, tagDef, meta) {
|
||||
const config = dependencies.get('config');
|
||||
const log = dependencies.get('log');
|
||||
const allowUnknownTags = config.tags.allowUnknownTags;
|
||||
|
||||
// handle cases where the tag definition does not exist
|
||||
|
||||
@ -16,20 +16,20 @@
|
||||
import * as definitions from '../../../../lib/definitions/index.js';
|
||||
|
||||
describe('@jsdoc/tag/lib/definitions', () => {
|
||||
it('has a `closure` object', () => {
|
||||
expect(definitions.closure).toBeObject();
|
||||
it('has a `getClosureTags` function', () => {
|
||||
expect(definitions.getClosureTags).toBeFunction();
|
||||
});
|
||||
|
||||
it('has a `core` object', () => {
|
||||
expect(definitions.core).toBeObject();
|
||||
it('has a `getCoreTags` function', () => {
|
||||
expect(definitions.getCoreTags).toBeFunction();
|
||||
});
|
||||
|
||||
it('has an `internal` object', () => {
|
||||
expect(definitions.internal).toBeObject();
|
||||
it('has a `getInternalTags` function', () => {
|
||||
expect(definitions.getInternalTags).toBeFunction();
|
||||
});
|
||||
|
||||
it('has a `jsdoc` object', () => {
|
||||
expect(definitions.jsdoc).toBeObject();
|
||||
it('has a `getJsdocTags` function', () => {
|
||||
expect(definitions.getJsdocTags).toBeFunction();
|
||||
});
|
||||
|
||||
// For additional tests, see packages/jsdoc/test/specs/tags/.
|
||||
|
||||
@ -119,16 +119,19 @@ describe('@jsdoc/tag/lib/dictionary', () => {
|
||||
|
||||
beforeEach(() => {
|
||||
env.conf.tags.dictionaries = [];
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
env.conf.tags.dictionaries = dictionaryConfig.slice();
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
});
|
||||
|
||||
it('logs an error if `env.conf.tags.dictionaries` is undefined', () => {
|
||||
function defineTags() {
|
||||
env.conf.tags.dictionaries = undefined;
|
||||
Dictionary.fromConfig(env);
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
Dictionary.fromConfig(jsdoc.deps);
|
||||
}
|
||||
|
||||
expect(jsdoc.didLog(defineTags, 'error')).toBeTrue();
|
||||
@ -137,7 +140,8 @@ describe('@jsdoc/tag/lib/dictionary', () => {
|
||||
it('logs an error if an unknown dictionary is requested', () => {
|
||||
function defineTags() {
|
||||
env.conf.tags.dictionaries = ['jsmarmoset'];
|
||||
Dictionary.fromConfig(env);
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
Dictionary.fromConfig(jsdoc.deps);
|
||||
}
|
||||
|
||||
expect(jsdoc.didLog(defineTags, 'error')).toBeTrue();
|
||||
@ -145,7 +149,8 @@ describe('@jsdoc/tag/lib/dictionary', () => {
|
||||
|
||||
it('adds both JSDoc and Closure tags by default', () => {
|
||||
env.conf.tags.dictionaries = dictionaryConfig.slice();
|
||||
testDictionary = Dictionary.fromConfig(env);
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
testDictionary = Dictionary.fromConfig(jsdoc.deps);
|
||||
|
||||
expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject();
|
||||
expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject();
|
||||
@ -153,7 +158,8 @@ describe('@jsdoc/tag/lib/dictionary', () => {
|
||||
|
||||
it('adds only the JSDoc tags if requested', () => {
|
||||
env.conf.tags.dictionaries = ['jsdoc'];
|
||||
testDictionary = Dictionary.fromConfig(env);
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
testDictionary = Dictionary.fromConfig(jsdoc.deps);
|
||||
|
||||
expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeObject();
|
||||
expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeFalse();
|
||||
@ -161,7 +167,8 @@ describe('@jsdoc/tag/lib/dictionary', () => {
|
||||
|
||||
it('adds only the Closure tags if requested', () => {
|
||||
env.conf.tags.dictionaries = ['closure'];
|
||||
testDictionary = Dictionary.fromConfig(env);
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
testDictionary = Dictionary.fromConfig(jsdoc.deps);
|
||||
|
||||
expect(testDictionary.lookup(JSDOC_TAGNAME)).toBeFalse();
|
||||
expect(testDictionary.lookup(CLOSURE_TAGNAME)).toBeObject();
|
||||
@ -169,14 +176,16 @@ describe('@jsdoc/tag/lib/dictionary', () => {
|
||||
|
||||
it('prefers tagdefs from the first dictionary on the list', () => {
|
||||
env.conf.tags.dictionaries = ['closure', 'jsdoc'];
|
||||
testDictionary = Dictionary.fromConfig(env);
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
testDictionary = Dictionary.fromConfig(jsdoc.deps);
|
||||
|
||||
expect(testDictionary.lookup('deprecated').synonyms).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('adds tag synonyms', () => {
|
||||
env.conf.tags.dictionaries = ['jsdoc'];
|
||||
testDictionary = Dictionary.fromConfig(env);
|
||||
jsdoc.deps.registerValue('env', env);
|
||||
testDictionary = Dictionary.fromConfig(jsdoc.deps);
|
||||
|
||||
expect(testDictionary.lookup('extends')).toBeObject();
|
||||
expect(testDictionary.normalize('extends')).toBe('augments');
|
||||
|
||||
@ -13,8 +13,8 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/* global jsdoc */
|
||||
import { EventBus } from '@jsdoc/util';
|
||||
|
||||
import { Tag } from '../../../lib/tag.js';
|
||||
import * as validator from '../../../lib/validator.js';
|
||||
@ -129,10 +129,10 @@ describe('@jsdoc/tag/lib/validator', () => {
|
||||
});
|
||||
|
||||
it('logs the offending comment for validation errors', () => {
|
||||
const bus = new EventBus('jsdoc');
|
||||
const emitter = jsdoc.deps.get('emitter');
|
||||
const events = [];
|
||||
|
||||
bus.once('logger:error', (e) => events.push(e));
|
||||
emitter.once('logger:error', (e) => events.push(e));
|
||||
config.tags.allowUnknownTags = false;
|
||||
validateTag(badTag);
|
||||
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
*/
|
||||
import { name } from '@jsdoc/core';
|
||||
import { inline } from '@jsdoc/tag';
|
||||
import { log } from '@jsdoc/util';
|
||||
import catharsis from 'catharsis';
|
||||
|
||||
const { longnamesToTree, SCOPE, SCOPE_TO_PUNC, toParts } = name;
|
||||
@ -249,7 +248,7 @@ function parseType(longname) {
|
||||
return catharsis.parse(longname, { jsdoc: true });
|
||||
} catch (e) {
|
||||
err = new Error(`unable to parse ${longname}: ${e.message}`);
|
||||
log.error(err);
|
||||
console.error(err);
|
||||
|
||||
return longname;
|
||||
}
|
||||
|
||||
@ -13,7 +13,9 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/* global jsdoc */
|
||||
|
||||
import { Dependencies } from '@jsdoc/core';
|
||||
import { Doclet } from '@jsdoc/doclet';
|
||||
import salty from '@jsdoc/salty';
|
||||
@ -398,11 +400,19 @@ describe('@jsdoc/template-legacy/lib/templateHelper', () => {
|
||||
});
|
||||
|
||||
it('does not try to parse a longname starting with <anonymous> as a type application', () => {
|
||||
function linkto() {
|
||||
helper.linkto('<anonymous>~foo');
|
||||
const emitter = jsdoc.deps.get('emitter');
|
||||
const events = [];
|
||||
|
||||
function storeEvent(e) {
|
||||
events.push(e);
|
||||
}
|
||||
|
||||
expect(jsdoc.didLog(linkto, 'error')).toBeFalse();
|
||||
emitter.on('logger:error', storeEvent);
|
||||
helper.linkto('<anonymous>~foo');
|
||||
|
||||
expect(events).toBeEmptyArray();
|
||||
|
||||
emitter.off('logger:error', storeEvent);
|
||||
});
|
||||
|
||||
it('does not treat a longname with a variation as a type application', () => {
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Utility modules for JSDoc.
|
||||
*
|
||||
@ -20,7 +21,7 @@
|
||||
*/
|
||||
import EventBus from './lib/bus.js';
|
||||
import cast from './lib/cast.js';
|
||||
import log from './lib/log.js';
|
||||
import getLogFunctions from './lib/log.js';
|
||||
|
||||
export { cast, EventBus, log };
|
||||
export default { cast, EventBus, log };
|
||||
export { cast, EventBus, getLogFunctions };
|
||||
export default { cast, EventBus, getLogFunctions };
|
||||
|
||||
@ -13,13 +13,15 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import EventBus from './bus.js';
|
||||
|
||||
const bus = new EventBus('jsdoc');
|
||||
const loggerFuncs = {};
|
||||
export const LOG_TYPES = ['debug', 'error', 'info', 'fatal', 'verbose', 'warn'];
|
||||
|
||||
['debug', 'error', 'info', 'fatal', 'verbose', 'warn'].forEach((fn) => {
|
||||
loggerFuncs[fn] = (...args) => bus.emit(`logger:${fn}`, ...args);
|
||||
});
|
||||
export default function getLogFunctions(emitter) {
|
||||
const logFunctions = {};
|
||||
|
||||
export default loggerFuncs;
|
||||
LOG_TYPES.forEach((type) => {
|
||||
logFunctions[type] = (...args) => emitter.emit(`logger:${type}`, ...args);
|
||||
});
|
||||
|
||||
return logFunctions;
|
||||
}
|
||||
|
||||
@ -13,14 +13,23 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import EventBus from '../../../lib/bus.js';
|
||||
import log from '../../../lib/log.js';
|
||||
|
||||
/* global jsdoc */
|
||||
|
||||
import getLogFunctions from '../../../lib/log.js';
|
||||
|
||||
describe('@jsdoc/util/lib/log', () => {
|
||||
let emitter;
|
||||
const fns = ['debug', 'error', 'info', 'fatal', 'verbose', 'warn'];
|
||||
let log;
|
||||
|
||||
it('is an object', () => {
|
||||
expect(log).toBeObject();
|
||||
beforeEach(() => {
|
||||
emitter = jsdoc.deps.get('emitter');
|
||||
log = getLogFunctions(emitter);
|
||||
});
|
||||
|
||||
it('is a function', () => {
|
||||
expect(getLogFunctions).toBeFunction();
|
||||
});
|
||||
|
||||
it('provides the expected functions', () => {
|
||||
@ -30,13 +39,11 @@ describe('@jsdoc/util/lib/log', () => {
|
||||
});
|
||||
|
||||
describe('functions', () => {
|
||||
const bus = new EventBus('jsdoc');
|
||||
|
||||
it('sends events to the event bus', () => {
|
||||
it('sends events to the emitter', () => {
|
||||
fns.forEach((fn) => {
|
||||
let event;
|
||||
|
||||
bus.once(`logger:${fn}`, (e) => {
|
||||
emitter.once(`logger:${fn}`, (e) => {
|
||||
event = e;
|
||||
});
|
||||
log[fn]('testing');
|
||||
|
||||
@ -23,7 +23,6 @@ import { config, Dependencies, plugins } from '@jsdoc/core';
|
||||
import { augment, Package, resolveBorrows } from '@jsdoc/doclet';
|
||||
import { createParser, handlers } from '@jsdoc/parse';
|
||||
import { Dictionary } from '@jsdoc/tag';
|
||||
import { EventBus, log } from '@jsdoc/util';
|
||||
import fastGlob from 'fast-glob';
|
||||
import _ from 'lodash';
|
||||
import stripBom from 'strip-bom';
|
||||
@ -47,14 +46,18 @@ export default (() => {
|
||||
tmpdir: null,
|
||||
};
|
||||
|
||||
const bus = new EventBus('jsdoc');
|
||||
const cli = {};
|
||||
const dependencies = new Dependencies();
|
||||
const engine = new Engine();
|
||||
const emitter = engine.emitter;
|
||||
const log = engine.log;
|
||||
const FATAL_ERROR_MESSAGE =
|
||||
'Exiting JSDoc because an error occurred. See the previous log messages for details.';
|
||||
const LOG_LEVELS = Engine.LOG_LEVELS;
|
||||
|
||||
dependencies.registerValue('emitter', emitter);
|
||||
dependencies.registerValue('log', engine.log);
|
||||
|
||||
cli.setEnv = (env) => {
|
||||
dependencies.registerValue('env', env);
|
||||
|
||||
@ -107,9 +110,7 @@ export default (() => {
|
||||
// Now that we're done loading and merging things, register dependencies.
|
||||
dependencies.registerValue('config', env.conf);
|
||||
dependencies.registerValue('options', env.opts);
|
||||
dependencies.registerSingletonFactory('tags', () =>
|
||||
Dictionary.fromConfig(dependencies.get('env'))
|
||||
);
|
||||
dependencies.registerSingletonFactory('tags', () => Dictionary.fromConfig(dependencies));
|
||||
|
||||
return cli;
|
||||
};
|
||||
@ -136,13 +137,13 @@ export default (() => {
|
||||
}
|
||||
|
||||
if (options.pedantic) {
|
||||
bus.once('logger:warn', recoverableError);
|
||||
bus.once('logger:error', fatalError);
|
||||
emitter.once('logger:warn', recoverableError);
|
||||
emitter.once('logger:error', fatalError);
|
||||
} else {
|
||||
bus.once('logger:error', recoverableError);
|
||||
emitter.once('logger:error', recoverableError);
|
||||
}
|
||||
|
||||
bus.once('logger:fatal', fatalError);
|
||||
emitter.once('logger:fatal', fatalError);
|
||||
}
|
||||
|
||||
return cli;
|
||||
@ -177,8 +178,6 @@ export default (() => {
|
||||
let cmd;
|
||||
const options = dependencies.get('options');
|
||||
|
||||
dependencies.registerValue('eventBus', bus);
|
||||
|
||||
// If we already need to exit with an error, don't do any more work.
|
||||
if (props.shouldExitWithError) {
|
||||
cmd = () => Promise.resolve(0);
|
||||
@ -321,7 +320,7 @@ export default (() => {
|
||||
docletStore = props.parser.parse(env.sourceFiles, options.encoding);
|
||||
|
||||
// If there is no package.json, just create an empty package
|
||||
packageDocs = new Package(props.packageJson);
|
||||
packageDocs = new Package(props.packageJson, dependencies);
|
||||
packageDocs.files = env.sourceFiles || [];
|
||||
docletStore.add(packageDocs);
|
||||
|
||||
|
||||
@ -19,10 +19,8 @@ import { fileURLToPath } from 'node:url';
|
||||
|
||||
import { augment } from '@jsdoc/doclet';
|
||||
import { createParser, handlers } from '@jsdoc/parse';
|
||||
import { EventBus } from '@jsdoc/util';
|
||||
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const bus = new EventBus('jsdoc');
|
||||
const originalDictionaries = ['jsdoc', 'closure'];
|
||||
const packagePath = path.resolve(__dirname, '../..');
|
||||
const parseResults = [];
|
||||
@ -36,15 +34,16 @@ const helpers = {
|
||||
},
|
||||
createParser: () => createParser(jsdoc.deps),
|
||||
didLog: (fn, level) => {
|
||||
const emitter = jsdoc.deps.get('emitter');
|
||||
const events = [];
|
||||
|
||||
function listener(e) {
|
||||
events.push(e);
|
||||
}
|
||||
|
||||
bus.on(`logger:${level}`, listener);
|
||||
emitter.on(`logger:${level}`, listener);
|
||||
fn();
|
||||
bus.off(`logger:${level}`, listener);
|
||||
emitter.off(`logger:${level}`, listener);
|
||||
|
||||
return events.length !== 0;
|
||||
},
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user