js-build-tools 6.3.0 → 6.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,36 +1,36 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
require("core-js/modules/esnext.weak-map.delete-all.js");
|
|
4
|
-
Object.defineProperty(exports, "__esModule", {
|
|
5
|
-
value: true
|
|
6
|
-
});
|
|
7
|
-
exports.resolveJsdocTheme = exports.resolveJsdocBin = exports.jsdocDocsFor = void 0;
|
|
8
|
-
require("core-js/modules/es.json.stringify.js");
|
|
9
|
-
require("core-js/modules/esnext.iterator.constructor.js");
|
|
10
|
-
require("core-js/modules/esnext.iterator.find.js");
|
|
11
|
-
require("core-js/modules/esnext.iterator.map.js");
|
|
12
|
-
var _nodeFs = _interopRequireDefault(require("node:fs"));
|
|
13
|
-
var _nodeOs = _interopRequireDefault(require("node:os"));
|
|
14
|
-
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
15
|
-
var _nodeModule = require("node:module");
|
|
16
|
-
var _nodeChild_process = require("node:child_process");
|
|
17
|
-
var _nodeUtil = require("node:util");
|
|
18
|
-
var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
|
|
19
|
-
var _removeDirectory = require("./removeDirectory.js");
|
|
20
|
-
var _jsdocBase = _interopRequireDefault(require("../../jsdoc.base.js"));
|
|
21
|
-
var cache;
|
|
22
|
-
function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
|
|
23
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
24
|
-
// jsdoc.base.js is CommonJS (it's also required directly by consuming projects' own .jsdoc.conf.js) - Node's ESM
|
|
25
|
-
// loader imports a CJS module's module.exports as the default export directly, no createRequire/import.meta needed
|
|
26
|
-
// (import.meta.url tripped up this project's own Babel CJS transform, which Jest relies on to run .mjs test files -
|
|
27
|
-
// confirmed by removing it and nothing else changing).
|
|
28
|
-
|
|
29
|
-
const execFileAsync = (0, _nodeUtil.promisify)(_nodeChild_process.execFile);
|
|
30
|
-
const escapeHtml = text => String(text).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
31
|
-
const jsdocInstallHint = 'Install it in your project with: npm install --save-dev jsdoc';
|
|
32
|
-
const themeInstallHint = name => `Install it in your project with: npm install --save-dev ${name}`;
|
|
33
|
-
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
require("core-js/modules/esnext.weak-map.delete-all.js");
|
|
4
|
+
Object.defineProperty(exports, "__esModule", {
|
|
5
|
+
value: true
|
|
6
|
+
});
|
|
7
|
+
exports.resolveJsdocTheme = exports.resolveJsdocBin = exports.jsdocDocsFor = void 0;
|
|
8
|
+
require("core-js/modules/es.json.stringify.js");
|
|
9
|
+
require("core-js/modules/esnext.iterator.constructor.js");
|
|
10
|
+
require("core-js/modules/esnext.iterator.find.js");
|
|
11
|
+
require("core-js/modules/esnext.iterator.map.js");
|
|
12
|
+
var _nodeFs = _interopRequireDefault(require("node:fs"));
|
|
13
|
+
var _nodeOs = _interopRequireDefault(require("node:os"));
|
|
14
|
+
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
15
|
+
var _nodeModule = require("node:module");
|
|
16
|
+
var _nodeChild_process = require("node:child_process");
|
|
17
|
+
var _nodeUtil = require("node:util");
|
|
18
|
+
var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
|
|
19
|
+
var _removeDirectory = require("./removeDirectory.js");
|
|
20
|
+
var _jsdocBase = _interopRequireDefault(require("../../jsdoc.base.js"));
|
|
21
|
+
var cache;
|
|
22
|
+
function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
|
|
23
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
24
|
+
// jsdoc.base.js is CommonJS (it's also required directly by consuming projects' own .jsdoc.conf.js) - Node's ESM
|
|
25
|
+
// loader imports a CJS module's module.exports as the default export directly, no createRequire/import.meta needed
|
|
26
|
+
// (import.meta.url tripped up this project's own Babel CJS transform, which Jest relies on to run .mjs test files -
|
|
27
|
+
// confirmed by removing it and nothing else changing).
|
|
28
|
+
|
|
29
|
+
const execFileAsync = (0, _nodeUtil.promisify)(_nodeChild_process.execFile);
|
|
30
|
+
const escapeHtml = text => String(text).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
31
|
+
const jsdocInstallHint = 'Install it in your project with: npm install --save-dev jsdoc';
|
|
32
|
+
const themeInstallHint = name => `Install it in your project with: npm install --save-dev ${name}`;
|
|
33
|
+
|
|
34
34
|
/**
|
|
35
35
|
* Resolve the installed directory of an optional peer dependency, from the project being built rather than from
|
|
36
36
|
* this package. Deliberately not requirePeer/importPeer's own `require(name + '/package.json')` approach - that
|
|
@@ -48,20 +48,20 @@ const themeInstallHint = name => `Install it in your project with: npm install -
|
|
|
48
48
|
* @param {string} [options.projectPath=process.cwd()]
|
|
49
49
|
* @returns {string}
|
|
50
50
|
* @throws {Error} With install instructions when the package is not installed.
|
|
51
|
-
*/
|
|
52
|
-
const resolvePeerDir = (name, {
|
|
53
|
-
task,
|
|
54
|
-
installHint,
|
|
55
|
-
projectPath = process.cwd()
|
|
56
|
-
}) => {
|
|
57
|
-
const req = (0, _nodeModule.createRequire)(_nodePath.default.join(projectPath, 'package.json'));
|
|
58
|
-
const found = (req.resolve.paths(name) || []).map(dir => _nodePath.default.join(dir, name)).find(dir => _nodeFs.default.existsSync(_nodePath.default.join(dir, 'package.json')));
|
|
59
|
-
if (!found) {
|
|
60
|
-
throw new Error(`The ${task} task needs the optional peer dependency ${name}, which is not installed. ${installHint}`);
|
|
61
|
-
}
|
|
62
|
-
return found;
|
|
63
|
-
};
|
|
64
|
-
|
|
51
|
+
*/
|
|
52
|
+
const resolvePeerDir = (name, {
|
|
53
|
+
task,
|
|
54
|
+
installHint,
|
|
55
|
+
projectPath = process.cwd()
|
|
56
|
+
}) => {
|
|
57
|
+
const req = (0, _nodeModule.createRequire)(_nodePath.default.join(projectPath, 'package.json'));
|
|
58
|
+
const found = (req.resolve.paths(name) || []).map(dir => _nodePath.default.join(dir, name)).find(dir => _nodeFs.default.existsSync(_nodePath.default.join(dir, 'package.json')));
|
|
59
|
+
if (!found) {
|
|
60
|
+
throw new Error(`The ${task} task needs the optional peer dependency ${name}, which is not installed. ${installHint}`);
|
|
61
|
+
}
|
|
62
|
+
return found;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
65
|
/**
|
|
66
66
|
* Resolve jsdoc's own CLI entry point. jsdoc has no stable programmatic Node API for generating HTML docs (unlike
|
|
67
67
|
* TypeDoc's Application.bootstrap()/convert()/generateDocs()) - gulp-jsdoc3, the established gulp wrapper, is
|
|
@@ -71,13 +71,13 @@ const resolvePeerDir = (name, {
|
|
|
71
71
|
* @memberOf module:partials
|
|
72
72
|
* @param {string} [projectPath=process.cwd()]
|
|
73
73
|
* @returns {string}
|
|
74
|
-
*/
|
|
75
|
-
const resolveJsdocBin = (projectPath = process.cwd()) => _nodePath.default.join(resolvePeerDir('jsdoc', {
|
|
76
|
-
task: 'docs',
|
|
77
|
-
installHint: jsdocInstallHint,
|
|
78
|
-
projectPath
|
|
79
|
-
}), 'jsdoc.js');
|
|
80
|
-
|
|
74
|
+
*/
|
|
75
|
+
const resolveJsdocBin = (projectPath = process.cwd()) => _nodePath.default.join(resolvePeerDir('jsdoc', {
|
|
76
|
+
task: 'docs',
|
|
77
|
+
installHint: jsdocInstallHint,
|
|
78
|
+
projectPath
|
|
79
|
+
}), 'jsdoc.js');
|
|
80
|
+
|
|
81
81
|
/**
|
|
82
82
|
* Resolve a jsdoc theme package's own template directory, for jsdoc's own opts.template config key: the folder
|
|
83
83
|
* holding its publish.js. That is the package root for a classic jsdoc template (clean-jsdoc-theme 4.x included),
|
|
@@ -86,18 +86,18 @@ const resolveJsdocBin = (projectPath = process.cwd()) => _nodePath.default.join(
|
|
|
86
86
|
* @param {string} name
|
|
87
87
|
* @param {string} [projectPath=process.cwd()]
|
|
88
88
|
* @returns {string}
|
|
89
|
-
*/
|
|
90
|
-
exports.resolveJsdocBin = resolveJsdocBin;
|
|
91
|
-
const resolveJsdocTheme = (name, projectPath = process.cwd()) => {
|
|
92
|
-
const packageDir = resolvePeerDir(name, {
|
|
93
|
-
task: 'docs',
|
|
94
|
-
installHint: themeInstallHint(name),
|
|
95
|
-
projectPath
|
|
96
|
-
});
|
|
97
|
-
const distDir = _nodePath.default.join(packageDir, 'dist');
|
|
98
|
-
return _nodeFs.default.existsSync(_nodePath.default.join(distDir, 'publish.js')) ? distDir : packageDir;
|
|
99
|
-
};
|
|
100
|
-
|
|
89
|
+
*/
|
|
90
|
+
exports.resolveJsdocBin = resolveJsdocBin;
|
|
91
|
+
const resolveJsdocTheme = (name, projectPath = process.cwd()) => {
|
|
92
|
+
const packageDir = resolvePeerDir(name, {
|
|
93
|
+
task: 'docs',
|
|
94
|
+
installHint: themeInstallHint(name),
|
|
95
|
+
projectPath
|
|
96
|
+
});
|
|
97
|
+
const distDir = _nodePath.default.join(packageDir, 'dist');
|
|
98
|
+
return _nodeFs.default.existsSync(_nodePath.default.join(distDir, 'publish.js')) ? distDir : packageDir;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
101
|
/**
|
|
102
102
|
* Generate the HTML documentation of a plain-JavaScript project with jsdoc, using jsdoc.base.js's own shared
|
|
103
103
|
* config (plugins, includePattern/excludePattern) as the starting point rather than a parallel one - the same
|
|
@@ -110,64 +110,66 @@ const resolveJsdocTheme = (name, projectPath = process.cwd()) => {
|
|
|
110
110
|
* @param {string} [outPath=gulpConfig.get('docs.to')] - The directory the documentation is generated into (cleared first).
|
|
111
111
|
* @param {function(string, Array<string>): Promise<Object>} [runJsdoc] - Runs the jsdoc CLI, tests can inject a stand-in.
|
|
112
112
|
* @returns {Function} A gulp task, it accepts an optional callback and returns a promise.
|
|
113
|
-
*/
|
|
114
|
-
exports.resolveJsdocTheme = resolveJsdocTheme;
|
|
115
|
-
const jsdocDocsFor = (srcPath = gulpConfig.get('docs.from'), outPath = gulpConfig.get('docs.to'), runJsdoc = (bin, args) => execFileAsync(process.execPath, [bin, ...args])) => {
|
|
116
|
-
if (gulpConfig.get('docs.enabled') === false) {
|
|
117
|
-
return () => {};
|
|
118
|
-
}
|
|
119
|
-
return done => {
|
|
120
|
-
const generate = async () => {
|
|
121
|
-
const theme = gulpConfig.get('docs.theme') || 'clean-jsdoc-theme';
|
|
122
|
-
const themeDir = resolveJsdocTheme(theme);
|
|
123
|
-
const indexFile = gulpConfig.get('docs.index');
|
|
124
|
-
const title = gulpConfig.get('docs.title');
|
|
125
|
-
await (0, _removeDirectory.removeDirectory)(outPath);
|
|
126
|
-
const config = {
|
|
127
|
-
..._jsdocBase.default,
|
|
128
|
-
source: {
|
|
129
|
-
..._jsdocBase.default.source,
|
|
130
|
-
include: [].concat(srcPath).map(includePath => _nodePath.default.resolve(includePath))
|
|
131
|
-
},
|
|
132
|
-
opts: {
|
|
133
|
-
destination: _nodePath.default.resolve(outPath),
|
|
134
|
-
// jsdoc does not recurse into source.include's own subdirectories by default - without this, only
|
|
135
|
-
// the top level of docs.from would ever be scanned. Confirmed from clean-jsdoc-theme's own README
|
|
136
|
-
// quick-start example, which sets this explicitly, not assumed from jsdoc's own classic defaults.
|
|
137
|
-
recurse: true,
|
|
138
|
-
template: themeDir,
|
|
139
|
-
// clean-jsdoc-theme's own
|
|
140
|
-
// site root ("/"), while every page is in one
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
113
|
+
*/
|
|
114
|
+
exports.resolveJsdocTheme = resolveJsdocTheme;
|
|
115
|
+
const jsdocDocsFor = (srcPath = gulpConfig.get('docs.from'), outPath = gulpConfig.get('docs.to'), runJsdoc = (bin, args) => execFileAsync(process.execPath, [bin, ...args])) => {
|
|
116
|
+
if (gulpConfig.get('docs.enabled') === false) {
|
|
117
|
+
return () => {};
|
|
118
|
+
}
|
|
119
|
+
return done => {
|
|
120
|
+
const generate = async () => {
|
|
121
|
+
const theme = gulpConfig.get('docs.theme') || 'clean-jsdoc-theme';
|
|
122
|
+
const themeDir = resolveJsdocTheme(theme);
|
|
123
|
+
const indexFile = gulpConfig.get('docs.index');
|
|
124
|
+
const title = gulpConfig.get('docs.title');
|
|
125
|
+
await (0, _removeDirectory.removeDirectory)(outPath);
|
|
126
|
+
const config = {
|
|
127
|
+
..._jsdocBase.default,
|
|
128
|
+
source: {
|
|
129
|
+
..._jsdocBase.default.source,
|
|
130
|
+
include: [].concat(srcPath).map(includePath => _nodePath.default.resolve(includePath))
|
|
131
|
+
},
|
|
132
|
+
opts: {
|
|
133
|
+
destination: _nodePath.default.resolve(outPath),
|
|
134
|
+
// jsdoc does not recurse into source.include's own subdirectories by default - without this, only
|
|
135
|
+
// the top level of docs.from would ever be scanned. Confirmed from clean-jsdoc-theme's own README
|
|
136
|
+
// quick-start example, which sets this explicitly, not assumed from jsdoc's own classic defaults.
|
|
137
|
+
recurse: true,
|
|
138
|
+
template: themeDir,
|
|
139
|
+
// clean-jsdoc-theme's own options for the name in its header and the home page's <title> (otherwise "Home").
|
|
140
|
+
// The header is given as a link: a plain-text title links to the site root ("/"), while every page is in one
|
|
141
|
+
// folder, so index.html is the home page wherever they are served. Both are printed unescaped by the theme.
|
|
142
|
+
...(title ? {
|
|
143
|
+
theme_opts: {
|
|
144
|
+
title: `<a href="index.html" class="sidebar-title sidebar-title-anchor">${escapeHtml(title)}</a>`,
|
|
145
|
+
homepageTitle: escapeHtml(title)
|
|
146
|
+
}
|
|
147
|
+
} : {}),
|
|
148
|
+
...(indexFile && _nodeFs.default.existsSync(indexFile) ? {
|
|
149
|
+
readme: _nodePath.default.resolve(indexFile)
|
|
150
|
+
} : {})
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
const workDir = _nodeFs.default.mkdtempSync(_nodePath.default.join(_nodeOs.default.tmpdir(), 'jsdocdocs-'));
|
|
154
|
+
try {
|
|
155
|
+
const configPath = _nodePath.default.join(workDir, 'jsdoc.conf.json');
|
|
156
|
+
_nodeFs.default.writeFileSync(configPath, JSON.stringify(config));
|
|
157
|
+
const bin = resolveJsdocBin();
|
|
158
|
+
// Pass on what jsdoc and the theme report (warnings such as a page which failed to render), which would
|
|
159
|
+
// otherwise be lost with the captured output
|
|
160
|
+
const {
|
|
161
|
+
stdout = '',
|
|
162
|
+
stderr = ''
|
|
163
|
+
} = (await runJsdoc(bin, ['-c', configPath])) || {};
|
|
164
|
+
const report = `${stdout}${stderr}`.trim();
|
|
165
|
+
if (report) {
|
|
166
|
+
console.warn(report);
|
|
167
|
+
}
|
|
168
|
+
} finally {
|
|
169
|
+
await (0, _removeDirectory.removeDirectory)(workDir);
|
|
170
|
+
}
|
|
171
|
+
};
|
|
172
|
+
return typeof done === 'function' ? generate().then(() => done(), done) : generate();
|
|
173
|
+
};
|
|
174
|
+
};
|
|
173
175
|
exports.jsdocDocsFor = jsdocDocsFor;
|
|
@@ -117,9 +117,17 @@ export const jsdocDocsFor = (
|
|
|
117
117
|
// quick-start example, which sets this explicitly, not assumed from jsdoc's own classic defaults.
|
|
118
118
|
recurse: true,
|
|
119
119
|
template: themeDir,
|
|
120
|
-
// clean-jsdoc-theme's own
|
|
121
|
-
// site root ("/"), while every page is in one
|
|
122
|
-
|
|
120
|
+
// clean-jsdoc-theme's own options for the name in its header and the home page's <title> (otherwise "Home").
|
|
121
|
+
// The header is given as a link: a plain-text title links to the site root ("/"), while every page is in one
|
|
122
|
+
// folder, so index.html is the home page wherever they are served. Both are printed unescaped by the theme.
|
|
123
|
+
...(title
|
|
124
|
+
? {
|
|
125
|
+
theme_opts: {
|
|
126
|
+
title: `<a href="index.html" class="sidebar-title sidebar-title-anchor">${escapeHtml(title)}</a>`,
|
|
127
|
+
homepageTitle: escapeHtml(title)
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
: {}),
|
|
123
131
|
...(indexFile && fs.existsSync(indexFile) ? { readme: path.resolve(indexFile) } : {})
|
|
124
132
|
}
|
|
125
133
|
}
|
|
@@ -92,14 +92,15 @@ describe('jsdocDocsFor', () => {
|
|
|
92
92
|
expect(['a.test.mjs', 'a.min.js', 'a.min.mjs', 'dir/_private.mjs', 'a.ts'].filter(documented)).toEqual([])
|
|
93
93
|
})
|
|
94
94
|
|
|
95
|
-
test('passes docs.title to the theme as a link to the home page of the docs, and leaves it out when unset', async () => {
|
|
95
|
+
test('passes docs.title to the theme as a link to the home page of the docs and as its page title, and leaves it out when unset', async () => {
|
|
96
96
|
gulpConfig.set('docs.enabled', true)
|
|
97
97
|
const srcPath = gulpConfig.get('srcPath')
|
|
98
98
|
const calls = {}
|
|
99
99
|
gulpConfig.set('docs.title', 'Tom & Jerry <Tools>')
|
|
100
100
|
await jsdocDocsFor(srcPath, `${srcPath}/../docs`, fakeRunJsdoc(calls))()
|
|
101
101
|
expect(calls.config.opts.theme_opts).toEqual({
|
|
102
|
-
title: '<a href="index.html" class="sidebar-title sidebar-title-anchor">Tom & Jerry <Tools></a>'
|
|
102
|
+
title: '<a href="index.html" class="sidebar-title sidebar-title-anchor">Tom & Jerry <Tools></a>',
|
|
103
|
+
homepageTitle: 'Tom & Jerry <Tools>'
|
|
103
104
|
})
|
|
104
105
|
|
|
105
106
|
gulpConfig.set('docs.title', '')
|
|
@@ -139,11 +140,13 @@ describe('jsdocDocsFor', () => {
|
|
|
139
140
|
describe('jsdocDocsFor, end to end with the real jsdoc CLI and clean-jsdoc-theme', () => {
|
|
140
141
|
test('produces a real browsable HTML page from real JSDoc comments', async () => {
|
|
141
142
|
gulpConfig.set('docs.enabled', true)
|
|
143
|
+
gulpConfig.set('docs.title', 'Tom & Jerry')
|
|
142
144
|
const outPath = `${gulpConfig.get('srcPath')}/../docs`
|
|
143
145
|
await jsdocDocsFor(gulpConfig.get('srcPath'), outPath)()
|
|
144
146
|
// clean-jsdoc-theme nests its real output under its own route folders (global/, source/...), not flat at
|
|
145
147
|
// outPath's own root - confirmed by actually running it, not assumed from the classic jsdoc template shape.
|
|
146
148
|
const files = fs.readdirSync(outPath, { recursive: true })
|
|
147
149
|
expect(files.some(file => file.endsWith('.html'))).toBe(true)
|
|
150
|
+
expect(fs.readFileSync(`${outPath}/index.html`, 'utf8')).toMatch(/<title>\s*Tom & Jerry\s*<\/title>/)
|
|
148
151
|
}, 30000)
|
|
149
152
|
})
|