mirror of
https://github.com/jsdoc/jsdoc.git
synced 2025-12-08 19:46:11 +00:00
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.
This commit is contained in:
parent
3eaa696a4d
commit
ca7a33f68b
@ -291,28 +291,6 @@ module.exports = (() => {
|
|||||||
return cli;
|
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 = () => {
|
cli.createParser = () => {
|
||||||
const handlers = require('jsdoc/src/handlers');
|
const handlers = require('jsdoc/src/handlers');
|
||||||
const parser = require('jsdoc/src/parser');
|
const parser = require('jsdoc/src/parser');
|
||||||
@ -321,7 +299,6 @@ module.exports = (() => {
|
|||||||
props.parser = parser.createParser(env.conf.parser);
|
props.parser = parser.createParser(env.conf.parser);
|
||||||
|
|
||||||
if (env.conf.plugins) {
|
if (env.conf.plugins) {
|
||||||
env.conf.plugins = resolvePluginPaths(env.conf.plugins);
|
|
||||||
plugins.installPlugins(env.conf.plugins, props.parser);
|
plugins.installPlugins(env.conf.plugins, props.parser);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,22 +365,17 @@ module.exports = (() => {
|
|||||||
|
|
||||||
cli.generateDocs = () => {
|
cli.generateDocs = () => {
|
||||||
let message;
|
let message;
|
||||||
const path = require('jsdoc/path');
|
const path = require('path');
|
||||||
const resolver = require('jsdoc/tutorial/resolver');
|
const resolver = require('jsdoc/tutorial/resolver');
|
||||||
const taffy = require('taffydb').taffy;
|
const taffy = require('taffydb').taffy;
|
||||||
|
|
||||||
let template;
|
let template;
|
||||||
|
|
||||||
env.opts.template = (() => {
|
env.opts.template = env.opts.template || path.join(__dirname, 'templates', 'default');
|
||||||
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;
|
|
||||||
})();
|
|
||||||
|
|
||||||
try {
|
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`);
|
template = require(`${env.opts.template}/publish`);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
|
|||||||
@ -3,7 +3,6 @@
|
|||||||
* @module jsdoc/path
|
* @module jsdoc/path
|
||||||
*/
|
*/
|
||||||
const env = require('jsdoc/env');
|
const env = require('jsdoc/env');
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
|
|
||||||
function prefixReducer(previousPath, current) {
|
function prefixReducer(previousPath, current) {
|
||||||
@ -77,93 +76,6 @@ exports.commonPrefix = (paths = []) => {
|
|||||||
return prefix;
|
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 => {
|
Object.keys(path).forEach(member => {
|
||||||
exports[member] = path[member];
|
exports[member] = path[member];
|
||||||
});
|
});
|
||||||
|
|||||||
@ -7,7 +7,6 @@ const logger = require('jsdoc/util/logger');
|
|||||||
const MarkdownIt = require('markdown-it');
|
const MarkdownIt = require('markdown-it');
|
||||||
const marked = require('marked');
|
const marked = require('marked');
|
||||||
const mda = require('markdown-it-anchor');
|
const mda = require('markdown-it-anchor');
|
||||||
const path = require('jsdoc/path');
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enumeration of Markdown parsers that are available.
|
* Enumeration of Markdown parsers that are available.
|
||||||
@ -138,25 +137,18 @@ function unencodeQuotes(source) {
|
|||||||
*/
|
*/
|
||||||
function getHighlighter(conf) {
|
function getHighlighter(conf) {
|
||||||
let highlighter;
|
let highlighter;
|
||||||
let highlighterPath;
|
|
||||||
|
|
||||||
switch (typeof conf.highlight) {
|
switch (typeof conf.highlight) {
|
||||||
case 'string':
|
case 'string':
|
||||||
highlighterPath = path.getResourcePath(conf.highlight);
|
try {
|
||||||
|
highlighter = require(conf.highlight).highlight;
|
||||||
if (highlighterPath) {
|
} catch (e) {
|
||||||
highlighter = require(highlighterPath).highlight;
|
logger.error(e);
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof highlighter !== 'function') {
|
if (typeof highlighter !== 'function') {
|
||||||
logger.error('The syntax highlighting module "%s" does not assign a method ' +
|
logger.error(`The syntax highlighting module ${conf.highlight} does not assign a ` +
|
||||||
'to exports.highlight. Using the default syntax highlighter.',
|
'method to `exports.highlight`. Using the default syntax highlighter.');
|
||||||
conf.highlight);
|
|
||||||
highlighter = highlight;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
logger.error('Unable to find the syntax highlighting module "%s". Using the ' +
|
|
||||||
'default syntax highlighter.', conf.highlight);
|
|
||||||
highlighter = highlight;
|
highlighter = highlight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,8 +249,8 @@ function getParseFunction(parserName, conf) {
|
|||||||
return parserFunction;
|
return parserFunction;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
logger.error('Unrecognized Markdown parser "%s". Markdown support is disabled.',
|
logger.error(`Unrecognized Markdown parser "${parserName}". Markdown support is ` +
|
||||||
parserName);
|
'disabled.');
|
||||||
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -453,8 +453,7 @@ exports.publish = (taffyData, opts, tutorials) => {
|
|||||||
|
|
||||||
// set up templating
|
// set up templating
|
||||||
view.layout = conf.default.layoutFile ?
|
view.layout = conf.default.layoutFile ?
|
||||||
path.getResourcePath(path.dirname(conf.default.layoutFile),
|
path.resolve(conf.default.layoutFile) :
|
||||||
path.basename(conf.default.layoutFile) ) :
|
|
||||||
'layout.tmpl';
|
'layout.tmpl';
|
||||||
|
|
||||||
// set up tutorials for helper
|
// set up tutorials for helper
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
exports.highlight = function(code, language) {
|
exports.highlight = function(code, language) {
|
||||||
return '<pre><code>' + code + ' in this language: ' + language + '</code></pre>';
|
return `<pre><code>${code} in this language: ${language}</code></pre>`;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -22,10 +22,6 @@ describe('jsdoc/path', () => {
|
|||||||
expect(path.commonPrefix).toBeFunction();
|
expect(path.commonPrefix).toBeFunction();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should export a "getResourcePath" function', () => {
|
|
||||||
expect(path.getResourcePath).toBeFunction();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('commonPrefix', () => {
|
describe('commonPrefix', () => {
|
||||||
let oldPwd;
|
let oldPwd;
|
||||||
let cwd;
|
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();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,6 +2,7 @@ describe('jsdoc/util/markdown', () => {
|
|||||||
const env = require('jsdoc/env');
|
const env = require('jsdoc/env');
|
||||||
const logger = require('jsdoc/util/logger');
|
const logger = require('jsdoc/util/logger');
|
||||||
const markdown = require('jsdoc/util/markdown');
|
const markdown = require('jsdoc/util/markdown');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
it('should exist', () => {
|
it('should exist', () => {
|
||||||
expect(markdown).toBeObject();
|
expect(markdown).toBeObject();
|
||||||
@ -152,7 +153,9 @@ describe('jsdoc/util/markdown', () => {
|
|||||||
it('should support `highlight` as the path to a highlighter module', () => {
|
it('should support `highlight` as the path to a highlighter module', () => {
|
||||||
let parser;
|
let parser;
|
||||||
|
|
||||||
setMarkdownConf({ highlight: 'test/fixtures/markdown/highlighter' });
|
setMarkdownConf({
|
||||||
|
highlight: path.join(env.dirname, 'test/fixtures/markdown/highlighter')
|
||||||
|
});
|
||||||
parser = markdown.getParser();
|
parser = markdown.getParser();
|
||||||
|
|
||||||
expect(parser('```js\nhello\n```')).toBe(
|
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', () => {
|
it('should log an error if the `highlight` module cannot be found', () => {
|
||||||
spyOn(logger, 'error');
|
spyOn(logger, 'error');
|
||||||
|
|
||||||
setMarkdownConf({ highlight: 'foo/bar/baz' });
|
setMarkdownConf({
|
||||||
|
highlight: 'foo/bar/baz'
|
||||||
|
});
|
||||||
markdown.getParser();
|
markdown.getParser();
|
||||||
|
|
||||||
expect(logger.error).toHaveBeenCalled();
|
expect(logger.error).toHaveBeenCalled();
|
||||||
@ -173,7 +178,9 @@ describe('jsdoc/util/markdown', () => {
|
|||||||
'`exports.highlight`', () => {
|
'`exports.highlight`', () => {
|
||||||
spyOn(logger, 'error');
|
spyOn(logger, 'error');
|
||||||
|
|
||||||
setMarkdownConf({ highlight: 'test/fixtures/markdown/badhighlighter' });
|
setMarkdownConf({
|
||||||
|
highlight: path.join(env.dirname, 'test/fixtures/markdown/badhighlighter')
|
||||||
|
});
|
||||||
markdown.getParser();
|
markdown.getParser();
|
||||||
|
|
||||||
expect(logger.error).toHaveBeenCalled();
|
expect(logger.error).toHaveBeenCalled();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user