js-build-tools 6.2.2 → 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.
Files changed (52) hide show
  1. package/README.md +180 -9
  2. package/dist/build.js +66 -66
  3. package/dist/bundle.js +1 -1
  4. package/dist/docs.js +11 -11
  5. package/dist/partials/jsdocDocsFor.js +133 -113
  6. package/dist/partials/loadPlaywright.js +34 -0
  7. package/dist/partials/neostandardLint.js +5 -3
  8. package/dist/partials/resolveDocsMethod.js +12 -12
  9. package/dist/partials/serveStatic.js +57 -0
  10. package/dist/partials/tsFor.js +2 -2
  11. package/dist/partials/typeDocsFor.js +28 -22
  12. package/dist/partials.js +169 -149
  13. package/dist/partials.min.js +1 -1
  14. package/dist/test-helpers/setUp.js +6 -0
  15. package/dist/utilities/convertMjsFilesForDocs.js +1 -0
  16. package/dist/utilities/dotGet.js +1 -0
  17. package/dist/utilities/dotNotate.js +5 -0
  18. package/dist/utilities/dotSet.js +1 -0
  19. package/dist/utilities/esmNamedExportsToCjs.js +1 -0
  20. package/dist/utilities/getBundleConfigs.js +1 -0
  21. package/dist/utilities/isObject.js +1 -0
  22. package/dist/utilities/strAfter.js +1 -0
  23. package/dist/utilities/strBefore.js +1 -0
  24. package/functions/bundle.mjs +1 -1
  25. package/functions/jsdocEsmExports.test.mjs +24 -0
  26. package/functions/partials/jsdocDocsFor.mjs +33 -13
  27. package/functions/partials/jsdocDocsFor.test.mjs +51 -0
  28. package/functions/partials/loadPlaywright.mjs +23 -0
  29. package/functions/partials/loadPlaywright.test.mjs +71 -0
  30. package/functions/partials/neostandardLint.mjs +5 -3
  31. package/functions/partials/serveStatic.mjs +47 -0
  32. package/functions/partials/serveStatic.test.mjs +71 -0
  33. package/functions/partials/tsFor.mjs +2 -2
  34. package/functions/partials/typeDocsFor.mjs +24 -20
  35. package/functions/partials/typeDocsFor.test.mjs +23 -0
  36. package/functions/partials.mjs +2 -0
  37. package/functions/partials.test.mjs +1 -1
  38. package/functions/test-helpers/setUp.mjs +6 -0
  39. package/functions/utilities/convertMjsFilesForDocs.mjs +1 -0
  40. package/functions/utilities/dotGet.mjs +1 -0
  41. package/functions/utilities/dotNotate.mjs +5 -0
  42. package/functions/utilities/dotSet.mjs +1 -0
  43. package/functions/utilities/esmNamedExportsToCjs.mjs +1 -0
  44. package/functions/utilities/getBundleConfigs.mjs +1 -0
  45. package/functions/utilities/isObject.mjs +1 -0
  46. package/functions/utilities/strAfter.mjs +1 -0
  47. package/functions/utilities/strBefore.mjs +1 -0
  48. package/gulp.config.mjs +2 -2
  49. package/gulpfile.base.mjs +1 -3
  50. package/jsdoc.base.js +9 -3
  51. package/jsdoc.esmExports.js +17 -0
  52. package/package.json +16 -10
@@ -1,35 +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, and by this
25
- // project's own legacy htmldocs script) - Node's ESM loader imports a CJS module's module.exports as the default
26
- // export directly, no createRequire/import.meta needed (import.meta.url tripped up this project's own Babel CJS
27
- // transform, which Jest relies on to run .mjs test files - confirmed by removing it and nothing else changing).
28
-
29
- const execFileAsync = (0, _nodeUtil.promisify)(_nodeChild_process.execFile);
30
- const jsdocInstallHint = 'Install it in your project with: npm install --save-dev jsdoc';
31
- const themeInstallHint = name => `Install it in your project with: npm install --save-dev ${name}`;
32
-
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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;');
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
+
33
34
  /**
34
35
  * Resolve the installed directory of an optional peer dependency, from the project being built rather than from
35
36
  * this package. Deliberately not requirePeer/importPeer's own `require(name + '/package.json')` approach - that
@@ -47,20 +48,20 @@ const themeInstallHint = name => `Install it in your project with: npm install -
47
48
  * @param {string} [options.projectPath=process.cwd()]
48
49
  * @returns {string}
49
50
  * @throws {Error} With install instructions when the package is not installed.
50
- */
51
- const resolvePeerDir = (name, {
52
- task,
53
- installHint,
54
- projectPath = process.cwd()
55
- }) => {
56
- const req = (0, _nodeModule.createRequire)(_nodePath.default.join(projectPath, 'package.json'));
57
- const found = (req.resolve.paths(name) || []).map(dir => _nodePath.default.join(dir, name)).find(dir => _nodeFs.default.existsSync(_nodePath.default.join(dir, 'package.json')));
58
- if (!found) {
59
- throw new Error(`The ${task} task needs the optional peer dependency ${name}, which is not installed. ${installHint}`);
60
- }
61
- return found;
62
- };
63
-
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
+
64
65
  /**
65
66
  * Resolve jsdoc's own CLI entry point. jsdoc has no stable programmatic Node API for generating HTML docs (unlike
66
67
  * TypeDoc's Application.bootstrap()/convert()/generateDocs()) - gulp-jsdoc3, the established gulp wrapper, is
@@ -70,34 +71,33 @@ const resolvePeerDir = (name, {
70
71
  * @memberOf module:partials
71
72
  * @param {string} [projectPath=process.cwd()]
72
73
  * @returns {string}
73
- */
74
- const resolveJsdocBin = (projectPath = process.cwd()) => _nodePath.default.join(resolvePeerDir('jsdoc', {
75
- task: 'docs',
76
- installHint: jsdocInstallHint,
77
- projectPath
78
- }), 'jsdoc.js');
79
-
74
+ */
75
+ const resolveJsdocBin = (projectPath = process.cwd()) => _nodePath.default.join(resolvePeerDir('jsdoc', {
76
+ task: 'docs',
77
+ installHint: jsdocInstallHint,
78
+ projectPath
79
+ }), 'jsdoc.js');
80
+
80
81
  /**
81
- * Resolve a jsdoc theme package's own template directory, for jsdoc's own opts.template config key. Not
82
- * necessarily the package's own root - clean-jsdoc-theme's own docs say to point opts.template at its `dist`
83
- * subdirectory specifically, confirmed by reading its real README rather than assuming every theme follows the
84
- * classic jsdoc template layout (a bare package root with its own tmpl/static folders) - clean-jsdoc-theme does
85
- * not (it is a modern, self-contained, server-rendered theme with no such folders at its package root at all).
82
+ * Resolve a jsdoc theme package's own template directory, for jsdoc's own opts.template config key: the folder
83
+ * holding its publish.js. That is the package root for a classic jsdoc template (clean-jsdoc-theme 4.x included),
84
+ * but `dist` for a bundled one (clean-jsdoc-theme 5.x).
86
85
  * @memberOf module:partials
87
86
  * @param {string} name
88
87
  * @param {string} [projectPath=process.cwd()]
89
88
  * @returns {string}
90
- */
91
- exports.resolveJsdocBin = resolveJsdocBin;
92
- const resolveJsdocTheme = (name, projectPath = process.cwd()) => {
93
- const packageDir = resolvePeerDir(name, {
94
- task: 'docs',
95
- installHint: themeInstallHint(name),
96
- projectPath
97
- });
98
- return name === 'clean-jsdoc-theme' ? _nodePath.default.join(packageDir, 'dist') : 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
@@ -105,51 +105,71 @@ const resolveJsdocTheme = (name, projectPath = process.cwd()) => {
105
105
  * options generated here instead of hand-maintained per project. Configure this with 'docs.from', 'docs.to',
106
106
  * 'docs.index', 'docs.theme' and 'docs.title'.
107
107
  * @memberOf module:partials
108
- * @param {string} [srcPath=gulpConfig.get('docs.from')] - The directory (or glob) holding the JS source.
108
+ * @param {string|Array<string>} [srcPath=gulpConfig.get('docs.from')] - The directory (or directories and files) holding
109
+ * the JS source.
109
110
  * @param {string} [outPath=gulpConfig.get('docs.to')] - The directory the documentation is generated into (cleared first).
110
111
  * @param {function(string, Array<string>): Promise<Object>} [runJsdoc] - Runs the jsdoc CLI, tests can inject a stand-in.
111
112
  * @returns {Function} A gulp task, it accepts an optional callback and returns a promise.
112
- */
113
- exports.resolveJsdocTheme = resolveJsdocTheme;
114
- const jsdocDocsFor = (srcPath = gulpConfig.get('docs.from'), outPath = gulpConfig.get('docs.to'), runJsdoc = (bin, args) => execFileAsync(process.execPath, [bin, ...args])) => {
115
- if (gulpConfig.get('docs.enabled') === false) {
116
- return () => {};
117
- }
118
- return done => {
119
- const generate = async () => {
120
- const theme = gulpConfig.get('docs.theme') || 'clean-jsdoc-theme';
121
- const themeDir = resolveJsdocTheme(theme);
122
- const indexFile = gulpConfig.get('docs.index');
123
- await (0, _removeDirectory.removeDirectory)(outPath);
124
- const config = {
125
- ..._jsdocBase.default,
126
- source: {
127
- ..._jsdocBase.default.source,
128
- include: [_nodePath.default.resolve(srcPath)]
129
- },
130
- opts: {
131
- destination: _nodePath.default.resolve(outPath),
132
- // jsdoc does not recurse into source.include's own subdirectories by default - without this, only
133
- // the top level of docs.from would ever be scanned. Confirmed from clean-jsdoc-theme's own README
134
- // quick-start example, which sets this explicitly, not assumed from jsdoc's own classic defaults.
135
- recurse: true,
136
- template: themeDir,
137
- ...(indexFile && _nodeFs.default.existsSync(indexFile) ? {
138
- readme: _nodePath.default.resolve(indexFile)
139
- } : {})
140
- }
141
- };
142
- const workDir = _nodeFs.default.mkdtempSync(_nodePath.default.join(_nodeOs.default.tmpdir(), 'jsdocdocs-'));
143
- try {
144
- const configPath = _nodePath.default.join(workDir, 'jsdoc.conf.json');
145
- _nodeFs.default.writeFileSync(configPath, JSON.stringify(config));
146
- const bin = resolveJsdocBin();
147
- await runJsdoc(bin, ['-c', configPath]);
148
- } finally {
149
- await (0, _removeDirectory.removeDirectory)(workDir);
150
- }
151
- };
152
- return typeof done === 'function' ? generate().then(() => done(), done) : generate();
153
- };
154
- };
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
+ };
155
175
  exports.jsdocDocsFor = jsdocDocsFor;
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.loadPlaywright = exports.launchBrowser = void 0;
7
+ var _loadPeer = require("./loadPeer.js");
8
+ const installHint = 'Install it in your project with: npm install --save-dev playwright';
9
+
10
+ /**
11
+ * Find Playwright (headless-browser automation) of the project being built, an optional peer dependency only
12
+ * needed by whatever actually drives a real browser - projects which never do never need it installed.
13
+ * @memberOf module:partials
14
+ * @param {string} [projectPath=process.cwd()] The folder of the project (which has the package.json) being built.
15
+ * @returns {Object} The Playwright module.
16
+ * @throws {Error} With install instructions when playwright is not installed.
17
+ */
18
+ const loadPlaywright = (projectPath = process.cwd()) => (0, _loadPeer.requirePeer)('playwright', {
19
+ task: 'browser automation',
20
+ installHint,
21
+ projectPath
22
+ });
23
+
24
+ /**
25
+ * Launch a real headless Chromium browser via Playwright. See {@link loadPlaywright}.
26
+ * @memberOf module:partials
27
+ * @param {Function} [load=loadPlaywright] Which Playwright to launch - swappable in tests.
28
+ * @param {string} [projectPath=process.cwd()] The folder of the project (which has the package.json) being built.
29
+ * @returns {Promise<Browser>} The running Playwright browser - close it yourself (browser.close()) once done with it.
30
+ * @throws {Error} With install instructions when playwright is not installed.
31
+ */
32
+ exports.loadPlaywright = loadPlaywright;
33
+ const launchBrowser = (load = loadPlaywright, projectPath = process.cwd()) => load(projectPath).chromium.launch();
34
+ exports.launchBrowser = launchBrowser;
@@ -21,6 +21,7 @@ const importNeostandard = () => (0, _loadPeer.importModule)('neostandard');
21
21
  * migrating from `standard` keeps its globals (jest, browser, ...) without touching package.json.
22
22
  * @param {string} cwd
23
23
  * @returns {Array<string>}
24
+ * @private
24
25
  */
25
26
  const readEnv = cwd => {
26
27
  try {
@@ -42,7 +43,8 @@ const readEnv = cwd => {
42
43
  * @param {boolean} options.ts
43
44
  * @param {boolean} options.fix
44
45
  * @param {Object<string, *>} [options.rules={}]
45
- * @returns {Promise<import('eslint').ESLint>}
46
+ * @returns {Promise<ESLint>} eslint's ESLint instance
47
+ * @private
46
48
  */
47
49
  const buildEslint = async ({
48
50
  cwd,
@@ -75,7 +77,7 @@ const buildEslint = async ({
75
77
  /**
76
78
  * Print a file's lint messages, if it has any.
77
79
  * @memberOf module:partials
78
- * @param {import('vinyl')} file
80
+ * @param {Vinyl} file
79
81
  * @param {{messages: Array<{line: number, column: number, message: string}>, errorCount: number, warningCount: number}} result
80
82
  * @returns {undefined}
81
83
  */
@@ -108,7 +110,7 @@ const printFileReport = (file, result) => {
108
110
  * @param {function(Object): Promise<{lintText: Function}>} [loadEslint] - Resolves an ESLint-shaped linter. Real
109
111
  * callers should never need to pass this - it exists so tests can supply a stand-in, since this project's
110
112
  * CommonJS-transform-based Jest setup cannot execute a real dynamic import() of neostandard (ESM-only).
111
- * @returns {import('stream').Transform}
113
+ * @returns {stream.Transform}
112
114
  */
113
115
  const neostandardLint = ({
114
116
  fix = true,
@@ -1,19 +1,19 @@
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.resolveDocsMethod = void 0;
8
- var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
9
- var cache;
10
- 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; }
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.resolveDocsMethod = void 0;
8
+ var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
9
+ var cache;
10
+ 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; }
11
11
  /**
12
12
  * Pick which engine generates the HTML documentation: docs.method picks it explicitly; left unset (false, the
13
13
  * default), it's inferred from typescript.enabled - every existing TypeScript project's config, which never
14
14
  * sets method, keeps producing TypeDoc output exactly as it always has.
15
15
  * @memberOf module:partials
16
16
  * @returns {'typedoc'|'jsdoc'}
17
- */
18
- const resolveDocsMethod = () => gulpConfig.get('docs.method') || (gulpConfig.get('typescript.enabled') ? 'typedoc' : 'jsdoc');
17
+ */
18
+ const resolveDocsMethod = () => gulpConfig.get('docs.method') || (gulpConfig.get('typescript.enabled') ? 'typedoc' : 'jsdoc');
19
19
  exports.resolveDocsMethod = resolveDocsMethod;
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.serveStatic = void 0;
7
+ var _nodeFs = _interopRequireDefault(require("node:fs"));
8
+ var _nodeHttp = _interopRequireDefault(require("node:http"));
9
+ var _nodePath = _interopRequireDefault(require("node:path"));
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ // A real, previously-undiscovered bug fixed here: without a Content-Type header, a browser enforces strict MIME
12
+ // checking on <script type="module"> and refuses to load it at all - exactly the case this partial exists for.
13
+ const contentTypes = {
14
+ '.css': 'text/css',
15
+ '.gif': 'image/gif',
16
+ '.html': 'text/html',
17
+ '.ico': 'image/x-icon',
18
+ '.jpeg': 'image/jpeg',
19
+ '.jpg': 'image/jpeg',
20
+ '.js': 'text/javascript',
21
+ '.json': 'application/json',
22
+ '.mjs': 'text/javascript',
23
+ '.png': 'image/png',
24
+ '.svg': 'image/svg+xml',
25
+ '.woff': 'font/woff',
26
+ '.woff2': 'font/woff2'
27
+ };
28
+
29
+ /**
30
+ * Serve a directory's real files over plain HTTP, for anything that needs a page loaded from a real URL rather
31
+ * than a bare file:// path - most commonly, a page using root-relative asset paths (/browser/...), which a
32
+ * file:// load resolves against the filesystem root instead of the page's own directory.
33
+ * @memberOf module:partials
34
+ * @param {string} rootDir - The directory to serve.
35
+ * @param {number} [port=0] - The port to listen on; 0 picks any free port.
36
+ * @returns {Promise<{server: http.Server, url: string}>} The running server, and its base URL - close the
37
+ * server yourself (server.close()) once done with it.
38
+ */
39
+ const serveStatic = (rootDir, port = 0) => new Promise((resolve, reject) => {
40
+ const server = _nodeHttp.default.createServer((req, res) => {
41
+ const filePath = _nodePath.default.join(rootDir, decodeURIComponent(req.url.split('?')[0]));
42
+ _nodeFs.default.readFile(filePath, (error, data) => {
43
+ if (error) {
44
+ res.statusCode = 404;
45
+ return res.end(`Not found: ${req.url}`);
46
+ }
47
+ res.setHeader('Content-Type', contentTypes[_nodePath.default.extname(filePath)] || 'application/octet-stream');
48
+ res.end(data);
49
+ });
50
+ });
51
+ server.once('error', reject);
52
+ server.listen(port, '127.0.0.1', () => resolve({
53
+ server,
54
+ url: `http://127.0.0.1:${server.address().port}`
55
+ }));
56
+ });
57
+ exports.serveStatic = serveStatic;
@@ -18,7 +18,7 @@ const importGulpTsCompile = () => (0, _loadPeer.importModule)('gulp-ts-compile')
18
18
  /**
19
19
  * Wrap a stream in a promise that resolves once it finishes writing.
20
20
  * @memberOf module:partials
21
- * @param {import('node:stream').Stream} stream
21
+ * @param {stream.Stream} stream
22
22
  * @returns {Promise<void>}
23
23
  */
24
24
  const installHint = 'Install it in your project with: npm install --save-dev typescript';
@@ -49,7 +49,7 @@ const streamToPromise = stream => new Promise((resolve, reject) => {
49
49
  * gulp-typescript when a removed API call started throwing under TypeScript 7.
50
50
  * @memberOf module:partials
51
51
  * @param {string} configPath - Path to a tsconfig.json file.
52
- * @returns {import('typescript').CompilerOptions}
52
+ * @returns {ts.CompilerOptions} TypeScript's compiler options
53
53
  */
54
54
  const readCompilerOptions = (ts, configPath) => {
55
55
  const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
@@ -5,6 +5,7 @@ Object.defineProperty(exports, "__esModule", {
5
5
  value: true
6
6
  });
7
7
  exports.writeDocEntries = exports.typeDocsFor = exports.loadTypeDoc = exports.describeFolder = exports.describeFile = exports.describeExports = void 0;
8
+ require("core-js/modules/es.array.includes.js");
8
9
  require("core-js/modules/es.json.stringify.js");
9
10
  require("core-js/modules/esnext.iterator.constructor.js");
10
11
  require("core-js/modules/esnext.iterator.filter.js");
@@ -42,12 +43,19 @@ exports.loadTypeDoc = loadTypeDoc;
42
43
  const isSource = fileName => /\.(ts|tsx|mts|cts)$/.test(fileName) && !/\.d\.[cm]?ts$/.test(fileName) && !/\.(test|spec)\./.test(fileName);
43
44
  const listSources = dirPath => _nodeFs.default.readdirSync(dirPath, {
44
45
  withFileTypes: true
45
- }).flatMap(entry => {
46
- const entryPath = _nodePath.default.join(dirPath, entry.name);
47
- if (entry.isDirectory()) {
48
- return entry.name === 'node_modules' ? [] : listSources(entryPath);
49
- }
50
- return isSource(entry.name) ? [entryPath] : [];
46
+ }).filter(entry => entry.isFile() && isSource(entry.name)).map(entry => _nodePath.default.join(dirPath, entry.name));
47
+
48
+ // Every folder below dirPath (at any depth), named by its path from dirPath, with the source files directly in it
49
+ const listFolders = (dirPath, prefix = '') => _nodeFs.default.readdirSync(dirPath, {
50
+ withFileTypes: true
51
+ }).filter(entry => entry.isDirectory() && entry.name !== 'node_modules').flatMap(entry => {
52
+ const folderPath = _nodePath.default.join(dirPath, entry.name);
53
+ const name = `${prefix}${entry.name}`;
54
+ return [{
55
+ name,
56
+ path: folderPath,
57
+ files: listSources(folderPath)
58
+ }, ...listFolders(folderPath, `${name}/`)];
51
59
  });
52
60
  const toIdentifier = fileName => fileName.replace(/[^\w$]+(\w)?/g, (match, letter) => (letter || '').toUpperCase()).replace(/^(\d)/, '_$1');
53
61
  const toModulePath = filePath => filePath.replace(/\.[cm]?tsx?$/, '').split(_nodePath.default.sep).join('/');
@@ -127,11 +135,12 @@ const describeFile = filePath => {
127
135
 
128
136
  /**
129
137
  * Write one entry file per folder of the source directory into the entry directory. TypeDoc makes a module of every
130
- * entry file, so the modules of the documentation mirror the folders. The default export of each source file is
138
+ * entry file, so the modules of the documentation mirror the folders. Nested folders are modules of their own, named
139
+ * by their path (utilities/parsers), and a folder's module holds only the files directly in it. The default export of each source file is
131
140
  * re-exported under the name of the file (the source files hold one function each), and anything else a file exports
132
141
  * is re-exported as it is (that is where the types.ts files go). Index files (the barrels), tests and declaration
133
142
  * files are left out, but the first doc comment of a folder's index file becomes the description of its module.
134
- * A file which sits beside the folders (not an index or main file) is a module of its own, described by its header
143
+ * A file which sits beside the folders (not an index, main or browser file) is a module of its own, described by its header
135
144
  * comment. A source directory with no folders gets a single entry called index.
136
145
  * @memberOf module:partials
137
146
  * @param {Object} ts - The TypeScript compiler API.
@@ -145,18 +154,10 @@ const writeDocEntries = (ts, srcDir, entryDir) => {
145
154
  _nodeFs.default.mkdirSync(entryDir, {
146
155
  recursive: true
147
156
  });
148
- const folders = _nodeFs.default.readdirSync(absoluteSrc, {
149
- withFileTypes: true
150
- }).filter(entry => entry.isDirectory() && entry.name !== 'node_modules').map(entry => ({
151
- name: entry.name,
152
- path: _nodePath.default.join(absoluteSrc, entry.name),
153
- files: listSources(_nodePath.default.join(absoluteSrc, entry.name))
154
- })).filter(folder => folder.files.length);
155
- const rootFiles = _nodeFs.default.readdirSync(absoluteSrc, {
156
- withFileTypes: true
157
- }).filter(entry => entry.isFile() && isSource(entry.name) && !/^(index|main)\./.test(entry.name)).map(entry => _nodePath.default.join(absoluteSrc, entry.name));
158
- // Folders make modules, and so do the files which sit beside them (except the barrel: index and main). A source
159
- // directory with no folders gets a single module called index which holds its files.
157
+ const folders = listFolders(absoluteSrc).filter(folder => folder.files.some(file => !/^index\./.test(_nodePath.default.basename(file))));
158
+ const rootFiles = listSources(absoluteSrc).filter(file => !/^(index|main|browser)\./.test(_nodePath.default.basename(file)));
159
+ // Folders make modules, and so do the files which sit beside them (except the barrels: index, main and browser, the
160
+ // browser bundle's entry). A source directory with no folders gets a single module called index which holds its files.
160
161
  const groups = folders.length ? [...folders, ...rootFiles.map(file => ({
161
162
  name: toIdentifier(_nodePath.default.basename(file).replace(/\.[cm]?tsx?$/, '')),
162
163
  files: [file],
@@ -178,8 +179,13 @@ const writeDocEntries = (ts, srcDir, entryDir) => {
178
179
  });
179
180
  const description = group.description ?? (group.path ? describeFolder(group.path) : '');
180
181
  // TypeDoc takes the first comment of an entry file which has the @module tag as the description of the module
181
- const moduleComment = description ? `/**\n${description.split('\n').map(line => ` * ${line}`.trimEnd()).join('\n')}\n * @module\n */\n\n` : '';
182
+ // A nested folder's module is named by its path (utilities/parsers), so it is not mistaken for its parent's
183
+ const moduleName = group.name.includes('/') ? ` ${group.name}` : '';
184
+ const moduleComment = description || moduleName ? `/**\n${description ? description.split('\n').map(line => ` * ${line}`.trimEnd()).join('\n') + '\n' : ''} * @module${moduleName}\n */\n\n` : '';
182
185
  const entryPath = _nodePath.default.join(entryDir, `${group.name}.ts`);
186
+ _nodeFs.default.mkdirSync(_nodePath.default.dirname(entryPath), {
187
+ recursive: true
188
+ });
183
189
  _nodeFs.default.writeFileSync(entryPath, moduleComment + lines.join('\n') + '\n');
184
190
  return entryPath;
185
191
  });
@@ -225,7 +231,7 @@ const typeDocsFor = (srcPath = gulpConfig.get('docs.from'), outPath = gulpConfig
225
231
  ...(projectConfig ? {
226
232
  extends: _nodePath.default.resolve(projectConfig)
227
233
  } : {}),
228
- include: [_nodePath.default.join(workDir, 'entries', '*.ts').split(_nodePath.default.sep).join('/'), _nodePath.default.resolve(srcPath).split(_nodePath.default.sep).join('/') + '/**/*.ts'],
234
+ include: [_nodePath.default.join(workDir, 'entries', '**', '*.ts').split(_nodePath.default.sep).join('/'), _nodePath.default.resolve(srcPath).split(_nodePath.default.sep).join('/') + '/**/*.ts'],
229
235
  exclude: [_nodePath.default.resolve(srcPath).split(_nodePath.default.sep).join('/') + '/**/*.test.*']
230
236
  }));
231
237
  const indexFile = gulpConfig.get('docs.index');