From ca7a33f68bee0e4b675922ca48c9abe241b726b6 Mon Sep 17 00:00:00 2001 From: Jeff Williams Date: Sun, 1 Dec 2019 18:52:09 -0800 Subject: [PATCH] refactor(jsdoc): change template/plugin loading JSDoc now discovers templates, plugins, and other resources by using the same mechanism as `require()`. It does not search additional paths for these resources. BREAKING CHANGE: Config files must specify different paths to resources. `jsdoc/path.getResourcePath` is removed. --- packages/jsdoc/cli.js | 36 +------- packages/jsdoc/lib/jsdoc/path.js | 88 ------------------- packages/jsdoc/lib/jsdoc/util/markdown.js | 28 +++--- packages/jsdoc/templates/default/publish.js | 3 +- .../test/fixtures/markdown/highlighter.js | 2 +- packages/jsdoc/test/specs/jsdoc/path.js | 87 ------------------ .../jsdoc/test/specs/jsdoc/util/markdown.js | 13 ++- 7 files changed, 26 insertions(+), 231 deletions(-) diff --git a/packages/jsdoc/cli.js b/packages/jsdoc/cli.js index 0c6c961a..6f5644f0 100644 --- a/packages/jsdoc/cli.js +++ b/packages/jsdoc/cli.js @@ -291,28 +291,6 @@ module.exports = (() => { return cli; }; - function resolvePluginPaths(paths) { - const path = require('jsdoc/path'); - - const pluginPaths = []; - - paths.forEach(plugin => { - const basename = path.basename(plugin); - const dirname = path.dirname(plugin); - const pluginPath = path.getResourcePath(dirname, basename); - - if (!pluginPath) { - logger.error('Unable to find the plugin "%s"', plugin); - - return; - } - - pluginPaths.push( pluginPath ); - }); - - return pluginPaths; - } - cli.createParser = () => { const handlers = require('jsdoc/src/handlers'); const parser = require('jsdoc/src/parser'); @@ -321,7 +299,6 @@ module.exports = (() => { props.parser = parser.createParser(env.conf.parser); if (env.conf.plugins) { - env.conf.plugins = resolvePluginPaths(env.conf.plugins); plugins.installPlugins(env.conf.plugins, props.parser); } @@ -388,22 +365,17 @@ module.exports = (() => { cli.generateDocs = () => { let message; - const path = require('jsdoc/path'); + const path = require('path'); const resolver = require('jsdoc/tutorial/resolver'); const taffy = require('taffydb').taffy; let template; - env.opts.template = (() => { - const publish = env.opts.template || 'templates/default'; - const templatePath = path.getResourcePath(publish); - - // if we didn't find the template, keep the user-specified value so the error message is - // useful - return templatePath || env.opts.template; - })(); + env.opts.template = env.opts.template || path.join(__dirname, 'templates', 'default'); try { + // TODO: Just look for a `publish` function in the specified module, not a `publish.js` + // file _and_ a `publish` function. template = require(`${env.opts.template}/publish`); } catch (e) { diff --git a/packages/jsdoc/lib/jsdoc/path.js b/packages/jsdoc/lib/jsdoc/path.js index e4116d9e..4495ec86 100644 --- a/packages/jsdoc/lib/jsdoc/path.js +++ b/packages/jsdoc/lib/jsdoc/path.js @@ -3,7 +3,6 @@ * @module jsdoc/path */ const env = require('jsdoc/env'); -const fs = require('fs'); const path = require('path'); function prefixReducer(previousPath, current) { @@ -77,93 +76,6 @@ exports.commonPrefix = (paths = []) => { return prefix; }; -/** - * Retrieve the fully qualified path to the requested resource. - * - * If the resource path is specified as a relative path, JSDoc searches for the resource in the - * following locations, in this order: - * - * 1. The current working directory - * 2. The directory where the JSDoc configuration file is located - * 3. The JSDoc directory - * 4. Anyplace where `require()` can find the resource (for example, in your project's - * `node_modules` directory) - * - * If the resource path is specified as a fully qualified path, JSDoc searches for the resource in - * the following locations, in this order: - * - * 1. The resource path - * 2. Anyplace where `require()` can find the resource (for example, in your project's - * `node_modules` directory) - * - * @param {string} filepath - The path to the requested resource. May be an absolute path; a path - * relative to the JSDoc directory; or a path relative to the current working directory. - * @param {string} [filename] - The filename of the requested resource. - * @return {string} The fully qualified path to the requested resource. Includes the filename if one - * was provided. - */ -exports.getResourcePath = (filepath, filename) => { - let result = null; - const searchDirs = [env.pwd, path.dirname(env.opts.configure || ''), env.dirname]; - - function exists(p) { - try { - fs.statSync(p); - - return true; - } - catch (e) { - return false; - } - } - - function resolve(p) { - try { - return require.resolve(p); - } - catch (e) { - return null; - } - } - - function find(p) { - // does the requested path exist? - if ( exists(p) ) { - result = p; - } - else { - // can `require()` find the requested path? - result = resolve(p); - } - - return Boolean(result); - } - - filepath = path.join(filepath, filename || ''); - - // is the filepath absolute? if so, just use it - if ( path.isAbsolute(filepath) ) { - find(filepath); - } - else { - searchDirs.some(searchDir => { - if (searchDir) { - return find( path.resolve(path.join(searchDir, filepath)) ); - } - else { - return false; - } - }); - } - - // if we still haven't found the resource, maybe it's an installed module - if (!result) { - result = resolve(filepath); - } - - return result; -}; - Object.keys(path).forEach(member => { exports[member] = path[member]; }); diff --git a/packages/jsdoc/lib/jsdoc/util/markdown.js b/packages/jsdoc/lib/jsdoc/util/markdown.js index 94a0404b..85b1441e 100644 --- a/packages/jsdoc/lib/jsdoc/util/markdown.js +++ b/packages/jsdoc/lib/jsdoc/util/markdown.js @@ -7,7 +7,6 @@ const logger = require('jsdoc/util/logger'); const MarkdownIt = require('markdown-it'); const marked = require('marked'); const mda = require('markdown-it-anchor'); -const path = require('jsdoc/path'); /** * Enumeration of Markdown parsers that are available. @@ -138,25 +137,18 @@ function unencodeQuotes(source) { */ function getHighlighter(conf) { let highlighter; - let highlighterPath; switch (typeof conf.highlight) { case 'string': - highlighterPath = path.getResourcePath(conf.highlight); - - if (highlighterPath) { - highlighter = require(highlighterPath).highlight; - - if (typeof highlighter !== 'function') { - logger.error('The syntax highlighting module "%s" does not assign a method ' + - 'to exports.highlight. Using the default syntax highlighter.', - conf.highlight); - highlighter = highlight; - } + try { + highlighter = require(conf.highlight).highlight; + } catch (e) { + logger.error(e); } - else { - logger.error('Unable to find the syntax highlighting module "%s". Using the ' + - 'default syntax highlighter.', conf.highlight); + + if (typeof highlighter !== 'function') { + logger.error(`The syntax highlighting module ${conf.highlight} does not assign a ` + + 'method to `exports.highlight`. Using the default syntax highlighter.'); highlighter = highlight; } @@ -257,8 +249,8 @@ function getParseFunction(parserName, conf) { return parserFunction; default: - logger.error('Unrecognized Markdown parser "%s". Markdown support is disabled.', - parserName); + logger.error(`Unrecognized Markdown parser "${parserName}". Markdown support is ` + + 'disabled.'); return undefined; } diff --git a/packages/jsdoc/templates/default/publish.js b/packages/jsdoc/templates/default/publish.js index 892b6c3c..e1d26ad5 100644 --- a/packages/jsdoc/templates/default/publish.js +++ b/packages/jsdoc/templates/default/publish.js @@ -453,8 +453,7 @@ exports.publish = (taffyData, opts, tutorials) => { // set up templating view.layout = conf.default.layoutFile ? - path.getResourcePath(path.dirname(conf.default.layoutFile), - path.basename(conf.default.layoutFile) ) : + path.resolve(conf.default.layoutFile) : 'layout.tmpl'; // set up tutorials for helper diff --git a/packages/jsdoc/test/fixtures/markdown/highlighter.js b/packages/jsdoc/test/fixtures/markdown/highlighter.js index 637361c5..71c5f091 100644 --- a/packages/jsdoc/test/fixtures/markdown/highlighter.js +++ b/packages/jsdoc/test/fixtures/markdown/highlighter.js @@ -1,5 +1,5 @@ 'use strict'; exports.highlight = function(code, language) { - return '
' + code + ' in this language: ' + language + '
'; + return `
${code} in this language: ${language}
`; }; diff --git a/packages/jsdoc/test/specs/jsdoc/path.js b/packages/jsdoc/test/specs/jsdoc/path.js index fb8145f5..c47bc381 100644 --- a/packages/jsdoc/test/specs/jsdoc/path.js +++ b/packages/jsdoc/test/specs/jsdoc/path.js @@ -22,10 +22,6 @@ describe('jsdoc/path', () => { expect(path.commonPrefix).toBeFunction(); }); - it('should export a "getResourcePath" function', () => { - expect(path.getResourcePath).toBeFunction(); - }); - describe('commonPrefix', () => { let oldPwd; let cwd; @@ -124,87 +120,4 @@ describe('jsdoc/path', () => { }); } }); - - describe('getResourcePath', () => { - let oldConf; - let oldPwd; - - beforeEach(() => { - oldConf = env.opts.configure; - oldPwd = env.pwd; - - env.opts.configure = path.join(env.dirname, 'lib', 'conf.json'); - env.pwd = __dirname; - }); - - afterEach(() => { - env.opts.configure = oldConf; - env.pwd = oldPwd; - }); - - it('resolves pwd-relative path that exists', () => { - const resolved = path.getResourcePath('doclet'); - - expect(resolved).toBe( path.join(__dirname, 'doclet.js') ); - }); - - it('resolves relative to ./ path that exists', () => { - // `path.join` discards the `.`, so we join with `path.sep` instead - const p = ['.', 'util'].join(path.sep); - const resolved = path.getResourcePath(p); - - expect(resolved).toBe( path.join(__dirname, 'util') ); - }); - - it('resolves relative to ../ path that exists', () => { - const p = path.join('..', 'jsdoc', 'util'); - const resolved = path.getResourcePath(p); - - expect(resolved).toBe( path.join(__dirname, 'util') ); - }); - - it('resolves path using node_modules/', () => { - const resolved = path.getResourcePath('node_modules', 'catharsis'); - - expect(resolved).toBe( path.join(env.dirname, 'node_modules', 'catharsis') ); - }); - - it('resolves paths relative to the configuration file\'s path', () => { - const resolved = path.getResourcePath('jsdoc'); - - expect(resolved).toBe( path.join(env.dirname, 'lib', 'jsdoc') ); - }); - - it('resolves paths relative to the JSDoc path', () => { - const resolved = path.getResourcePath( path.join('lib', 'jsdoc') ); - - expect(resolved).toBe( path.join(env.dirname, 'lib', 'jsdoc') ); - }); - - it('resolves installed module', () => { - const resolved = path.getResourcePath('catharsis'); - - expect(resolved).toBe( path.join(env.dirname, 'node_modules', 'catharsis', - 'catharsis.js') ); - }); - - it('fails to find a relative path that does not exist', () => { - const resolved = path.getResourcePath('foo'); - - expect(resolved).toBeNull(); - }); - - it('finds an absolute path that does exist', () => { - const p = path.join(env.dirname, 'lib'); - const resolved = path.getResourcePath(p); - - expect(resolved).toBe(p); - }); - - it('fails to find an absolute path that does not exist', () => { - const resolved = path.getResourcePath( path.join(env.dirname, 'foo') ); - - expect(resolved).toBeNull(); - }); - }); }); diff --git a/packages/jsdoc/test/specs/jsdoc/util/markdown.js b/packages/jsdoc/test/specs/jsdoc/util/markdown.js index 9a298ecd..821bb40e 100644 --- a/packages/jsdoc/test/specs/jsdoc/util/markdown.js +++ b/packages/jsdoc/test/specs/jsdoc/util/markdown.js @@ -2,6 +2,7 @@ describe('jsdoc/util/markdown', () => { const env = require('jsdoc/env'); const logger = require('jsdoc/util/logger'); const markdown = require('jsdoc/util/markdown'); + const path = require('path'); it('should exist', () => { expect(markdown).toBeObject(); @@ -152,7 +153,9 @@ describe('jsdoc/util/markdown', () => { it('should support `highlight` as the path to a highlighter module', () => { let parser; - setMarkdownConf({ highlight: 'test/fixtures/markdown/highlighter' }); + setMarkdownConf({ + highlight: path.join(env.dirname, 'test/fixtures/markdown/highlighter') + }); parser = markdown.getParser(); expect(parser('```js\nhello\n```')).toBe( @@ -163,7 +166,9 @@ describe('jsdoc/util/markdown', () => { it('should log an error if the `highlight` module cannot be found', () => { spyOn(logger, 'error'); - setMarkdownConf({ highlight: 'foo/bar/baz' }); + setMarkdownConf({ + highlight: 'foo/bar/baz' + }); markdown.getParser(); expect(logger.error).toHaveBeenCalled(); @@ -173,7 +178,9 @@ describe('jsdoc/util/markdown', () => { '`exports.highlight`', () => { spyOn(logger, 'error'); - setMarkdownConf({ highlight: 'test/fixtures/markdown/badhighlighter' }); + setMarkdownConf({ + highlight: path.join(env.dirname, 'test/fixtures/markdown/badhighlighter') + }); markdown.getParser(); expect(logger.error).toHaveBeenCalled();