js-build-tools 5.6.0 → 5.7.0

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.
package/README.md CHANGED
@@ -40,6 +40,8 @@ provided are the defaults):
40
40
  // Module names or file paths left out of the bundle entirely (requiring one at runtime throws, unless something
41
41
  // else provides it, for example a script tag which loads it separately).
42
42
  "exclude": [],
43
+ // Additional bundles to produce alongside the primary one above (see 'Configure additional browser bundles').
44
+ "bundles": [],
43
45
  // The output directory for browser-bundled files.
44
46
  "to": "browser"
45
47
  },
@@ -100,6 +102,9 @@ provided are the defaults):
100
102
  "from": [
101
103
  "src/**/!(*.test).js"
102
104
  ],
105
+ // Additional .mjs files to document alongside 'from' (see 'Configure including ESM files in the generated
106
+ // readme'). Empty by default: a project that never sets this gets exactly the readme it always did.
107
+ "fromEsm": [],
103
108
  // The directory to output the readme file in.
104
109
  "to": "./"
105
110
  },
@@ -316,6 +321,56 @@ Two settings in `browser` handle this, both take module names or file paths (see
316
321
  }
317
322
  ```
318
323
 
324
+ ### Configure additional browser bundles (optional)
325
+
326
+ By default a project produces exactly one browser bundle, from `dist.main`/`browser.name`/`browser.ignore`/
327
+ `browser.exclude` above. `browser.bundles` adds more bundles alongside it - for example a render-only variant built
328
+ from a different entry point than the full bundle. Each entry only needs to specify what's actually different about
329
+ that bundle; anything left out falls back to the primary bundle's own value:
330
+
331
+ ```json
332
+ {
333
+ "browser": {
334
+ "bundles": [
335
+ {
336
+ // Required, and must be unique among all of a project's bundles: the name for this bundle's own output file
337
+ // and standalone export.
338
+ "name": "render-only",
339
+ // This bundle's own entry point. Falls back to dist.main when omitted.
340
+ "main": "dist/renderOnly.js",
341
+ // This bundle's own ignore list. Falls back to browser.ignore when omitted.
342
+ "ignore": [],
343
+ // This bundle's own exclude list. Falls back to browser.exclude when omitted.
344
+ "exclude": []
345
+ }
346
+ ]
347
+ }
348
+ }
349
+ ```
350
+
351
+ For the `gulpConfig` module's own `get`/`set` functions (read or override a resolved configuration value from your
352
+ own code, by the same dot-notation path a setting has in the JSON above), see the generated reference below.
353
+
354
+ ### Configure including ESM files in the generated readme (optional)
355
+
356
+ The readme generator (`jsdoc-to-markdown`) only recognizes `.js` files, even though it parses real ESM `import`/
357
+ `export` syntax just fine once it reads one - the file extension is the only thing it filters on, not the content.
358
+ `readme.fromEsm` names `.mjs` files to document anyway: each one is read, rewritten (every top-level `export const`/
359
+ `export function`/`export class` becomes a plain declaration plus a trailing `module.exports = { ... }` - the same
360
+ shape `jsdoc-to-markdown` already documents cleanly, since that rewrite is exactly what this project's own
361
+ `gulp.config.mjs` needs it for) and written to a temp `.js` file outside your project entirely, which is cleaned up
362
+ again once the readme generator has read it. Other export forms (`export default`, re-exports, `export { a, b }`
363
+ lists) are left untouched in whatever way `jsdoc-to-markdown` already handles ESM - restructure a file to use named
364
+ exports if you want it documented this cleanly:
365
+
366
+ ```json
367
+ {
368
+ "readme": {
369
+ "fromEsm": ["src/myEsmOnlyModule.mjs"]
370
+ }
371
+ }
372
+ ```
373
+
319
374
  ### Configure move fonts (optional)
320
375
 
321
376
  Be able to copy a source directory of fonts into the distribution path.
@@ -546,10 +601,12 @@ Modify these configurations to match your project specifications.
546
601
  * [~StringSetting](#module_gulpConfig..StringSetting) : <code>string</code>
547
602
  * [~Setting](#module_gulpConfig..Setting) : <code>ArrayableSetting</code> \| <code>BooleanSetting</code> \| <code>FlagsSetting</code> \| <code>StringSetting</code>
548
603
  * [~BrowserConfig](#module_gulpConfig..BrowserConfig) : <code>Object.&lt;string, Setting&gt;</code>
604
+ * [~AdditionalBundleConfig](#module_gulpConfig..AdditionalBundleConfig) : <code>Object.&lt;string, Setting&gt;</code>
549
605
  * [~DistConfig](#module_gulpConfig..DistConfig) : <code>Object.&lt;string, Setting&gt;</code>
550
606
  * [~FontConfig](#module_gulpConfig..FontConfig) : <code>Object.&lt;string, Setting&gt;</code>
551
607
  * [~ImageConfig](#module_gulpConfig..ImageConfig) : <code>Object.&lt;string, Setting&gt;</code>
552
608
  * [~ReadmeConfig](#module_gulpConfig..ReadmeConfig) : <code>Object.&lt;string, Setting&gt;</code>
609
+ * [~DocsConfig](#module_gulpConfig..DocsConfig) : <code>Object.&lt;string, Setting&gt;</code>
553
610
  * [~SassConfig](#module_gulpConfig..SassConfig) : <code>Object.&lt;string, Setting&gt;</code>
554
611
  * [~TestConfig](#module_gulpConfig..TestConfig) : <code>Object.&lt;string, Setting&gt;</code>
555
612
  * [~TsConfig](#module_gulpConfig..TsConfig) : <code>Object.&lt;string, Setting&gt;</code>
@@ -646,9 +703,27 @@ Configurations for building the browser files.
646
703
  | Name | Type | Description |
647
704
  | --- | --- | --- |
648
705
  | enabled | <code>BooleanSetting</code> | 'true' to generate browser bundled files; 'false' for node environment only |
649
- | from | <code>StringSetting</code> | The name to use for the browser-bundled output file (.js will be appended). |
650
- | name | <code>StringSetting</code> | The search pattern used for retrieving compiled distribution files. |
706
+ | from | <code>StringSetting</code> | The search pattern used for retrieving compiled distribution files. |
707
+ | name | <code>StringSetting</code> | The name to use for the browser-bundled output file (.js will be appended). |
651
708
  | to | <code>StringSetting</code> | The output directory for browser-bundled files. |
709
+ | ignore | <code>ArrayableSetting</code> | Module names or file paths which resolve to an empty object ({}) in the bundle instead of their real contents. For a dependency which is only reached because it is the default value of an option you always override (for example a selector engine's default DOM adapter, when you always pass your own), this keeps it (and anything only it requires) out of the bundle, as long as your code never actually reaches the real module by not overriding that option. See browserify's b.ignore(file). |
710
+ | exclude | <code>ArrayableSetting</code> | Module names or file paths left out of the bundle entirely; requiring one at runtime throws unless something else provides it (for example a script tag loading it separately). See browserify's b.exclude(file). |
711
+ | bundles | [<code>Array.&lt;AdditionalBundleConfig&gt;</code>](#module_gulpConfig..AdditionalBundleConfig) | Additional bundles to produce alongside the primary one (name/dist.main/ignore/exclude above) - for example a render-only variant built from a different entry point than the full bundle. Empty by default: a project that never sets this gets exactly the one bundle it always did. |
712
+
713
+ <a name="module_gulpConfig..AdditionalBundleConfig"></a>
714
+
715
+ ### gulpConfig~AdditionalBundleConfig : <code>Object.&lt;string, Setting&gt;</code>
716
+ One additional bundle - everything but `name` falls back to the primary bundle's own value when omitted, so an
717
+
718
+ **Kind**: inner typedef of [<code>gulpConfig</code>](#module_gulpConfig)
719
+ **Properties**
720
+
721
+ | Name | Type | Description |
722
+ | --- | --- | --- |
723
+ | name | <code>StringSetting</code> | The name for this bundle's output file and standalone export - must be unique among all of a project's bundles. |
724
+ | [main] | <code>StringSetting</code> | This bundle's own entry point. Falls back to dist.main when omitted. |
725
+ | [ignore] | <code>ArrayableSetting</code> | This bundle's own ignore list. Falls back to browser.ignore when omitted. |
726
+ | [exclude] | <code>ArrayableSetting</code> | This bundle's own exclude list. Falls back to browser.exclude when omitted. |
652
727
 
653
728
  <a name="module_gulpConfig..DistConfig"></a>
654
729
 
@@ -704,10 +779,29 @@ Configurations to compile and generate the Readme file.
704
779
  | --- | --- | --- |
705
780
  | file | <code>StringSetting</code> | The name of the output documentation markdown file. |
706
781
  | from | <code>StringSetting</code> | Location of files to use for compiling documentation into the readme. |
782
+ | fromEsm | <code>ArrayableSetting</code> | Additional `.mjs` files to document alongside `from`, converted on the fly since the readme generator only recognizes `.js` files - see 'Configure including ESM files in the generated readme'. Empty by default: a project that never sets this gets exactly the readme it always did. |
707
783
  | options | <code>ArrayableSetting</code> | Options for formatting the output readme. |
708
784
  | template | <code>StringSetting</code> | The file which will be pre-fixed to your README.md output. |
709
785
  | to | <code>StringSetting</code> | The directory to output the readme file in. |
710
786
 
787
+ <a name="module_gulpConfig..DocsConfig"></a>
788
+
789
+ ### gulpConfig~DocsConfig : <code>Object.&lt;string, Setting&gt;</code>
790
+ Configurations for generating the HTML documentation of a TypeScript project (with TypeDoc, from the source).
791
+
792
+ **Kind**: inner typedef of [<code>gulpConfig</code>](#module_gulpConfig)
793
+ **Properties**
794
+
795
+ | Name | Type | Description |
796
+ | --- | --- | --- |
797
+ | enabled | <code>BooleanSetting</code> | Toggle generating the documentation from the TypeScript source. When it is on the build does this instead of generating the readme from the jsdoc comments of the compiled files. |
798
+ | from | <code>StringSetting</code> | The directory holding the TypeScript source, each folder in it becomes a module. |
799
+ | index | <code>StringSetting</code> | The markdown file used as the front page of the documentation. |
800
+ | logLevel | <code>StringSetting</code> | How much TypeDoc reports: Verbose, Info, Warn, Error or None. |
801
+ | title | <code>StringSetting</code> | The name of the documentation, defaults to the name in the package.json. |
802
+ | to | <code>StringSetting</code> | The directory to generate the documentation in (it is cleared first). |
803
+ | tsconfig | <code>FlagStringSetting</code> | The tsconfig file to read the source with, defaults to the one of typescript.config. |
804
+
711
805
  <a name="module_gulpConfig..SassConfig"></a>
712
806
 
713
807
  ### gulpConfig~SassConfig : <code>Object.&lt;string, Setting&gt;</code>
@@ -765,6 +859,7 @@ A set of Configurations options defined by Settings.
765
859
  | browser | <code>BrowserConfig</code> | Browser bundling configuration group. |
766
860
  | cleanPaths | <code>ArrayableSetting</code> | The paths for directories to delete before build. |
767
861
  | dist | <code>DistConfig</code> | Distribution file generation configuration group. |
862
+ | docs | <code>DocsConfig</code> | Generate the documentation of a TypeScript project configuration group. |
768
863
  | fonts | <code>FontConfig</code> | Fonts copy configuration group. |
769
864
  | images | <code>ImageConfig</code> | Minify and copy the images configuration. |
770
865
  | readme | <code>ReadmeConfig</code> | Build readme files configuration. |
@@ -1,23 +1,34 @@
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.addToReadme = void 0;
8
- var _fs = _interopRequireDefault(require("fs"));
9
- var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
10
- var _jsdocToMarkdown = _interopRequireDefault(require("jsdoc-to-markdown"));
11
- var _glob = require("glob");
12
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
13
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
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.addToReadme = void 0;
8
+ var _fs = _interopRequireDefault(require("fs"));
9
+ var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
10
+ var _jsdocToMarkdown = _interopRequireDefault(require("jsdoc-to-markdown"));
11
+ var _glob = require("glob");
12
+ var _convertMjsFilesForDocs = require("../utilities/convertMjsFilesForDocs.js");
13
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
15
  /**
15
16
  * Appends all the jsdoc comments to the readme file. Assumes empty or templated file.
16
17
  * Configure this with 'readmeSearch', 'readmePath', 'readmeFile', and 'readmeOptions'.
18
+ *
19
+ * jsdoc-to-markdown only recognizes `.js` files, even though it parses real ESM syntax just fine once it reads
20
+ * one - `readme.fromEsm` (empty by default) names `.mjs` files to include anyway, converted on the fly (see
21
+ * {@link convertMjsFilesForDocs}) and cleaned up again once this has read them, win or lose.
17
22
  * @memberOf module:partials
18
23
  * @returns {string|Uint8Array}
19
- */
20
- const addToReadme = () => _jsdocToMarkdown.default.render({
21
- files: (0, _glob.globSync)(gulpConfig.get('readme.from'))
22
- }).then(readme => _fs.default.appendFileSync(gulpConfig.get('readme.to') + gulpConfig.get('readme.file'), readme, gulpConfig.get('readmeOptions')));
24
+ */
25
+ const addToReadme = () => {
26
+ const {
27
+ filePaths: esmFilePaths,
28
+ cleanUp
29
+ } = (0, _convertMjsFilesForDocs.convertMjsFilesForDocs)((0, _glob.globSync)(gulpConfig.get('readme.fromEsm') || []));
30
+ return _jsdocToMarkdown.default.render({
31
+ files: [...(0, _glob.globSync)(gulpConfig.get('readme.from')), ...esmFilePaths]
32
+ }).finally(cleanUp).then(readme => _fs.default.appendFileSync(gulpConfig.get('readme.to') + gulpConfig.get('readme.file'), readme, gulpConfig.get('readmeOptions')));
33
+ };
23
34
  exports.addToReadme = addToReadme;
@@ -1,94 +1,99 @@
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
- Object.defineProperty(exports, "afterEach", {
8
- enumerable: true,
9
- get: function () {
10
- return _testFilesystem.afterEach;
11
- }
12
- });
13
- Object.defineProperty(exports, "beforeEach", {
14
- enumerable: true,
15
- get: function () {
16
- return _testFilesystem.beforeEach;
17
- }
18
- });
19
- Object.defineProperty(exports, "countMatches", {
20
- enumerable: true,
21
- get: function () {
22
- return _testFilesystem.countMatches;
23
- }
24
- });
25
- Object.defineProperty(exports, "createTempDir", {
26
- enumerable: true,
27
- get: function () {
28
- return _testFilesystem.createTempDir;
29
- }
30
- });
31
- Object.defineProperty(exports, "fileExists", {
32
- enumerable: true,
33
- get: function () {
34
- return _testFilesystem.fileExists;
35
- }
36
- });
37
- exports.gulpConfig = void 0;
38
- Object.defineProperty(exports, "logObject", {
39
- enumerable: true,
40
- get: function () {
41
- return _testFilesystem.logObject;
42
- }
43
- });
44
- Object.defineProperty(exports, "removeDirectory", {
45
- enumerable: true,
46
- get: function () {
47
- return _testFilesystem.removeDirectory;
48
- }
49
- });
50
- exports.setDefaults = void 0;
51
- var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
52
- exports.gulpConfig = gulpConfig;
53
- var _testFilesystem = require("test-filesystem");
54
- function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
55
- // Import the configurations and override some of them to direct to the temp directory.
56
-
57
- let tempDir = 'test-temp/';
58
- let srcPath = `${tempDir}src`;
59
-
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
+ Object.defineProperty(exports, "afterEach", {
8
+ enumerable: true,
9
+ get: function () {
10
+ return _testFilesystem.afterEach;
11
+ }
12
+ });
13
+ Object.defineProperty(exports, "beforeEach", {
14
+ enumerable: true,
15
+ get: function () {
16
+ return _testFilesystem.beforeEach;
17
+ }
18
+ });
19
+ Object.defineProperty(exports, "countMatches", {
20
+ enumerable: true,
21
+ get: function () {
22
+ return _testFilesystem.countMatches;
23
+ }
24
+ });
25
+ Object.defineProperty(exports, "createTempDir", {
26
+ enumerable: true,
27
+ get: function () {
28
+ return _testFilesystem.createTempDir;
29
+ }
30
+ });
31
+ Object.defineProperty(exports, "fileExists", {
32
+ enumerable: true,
33
+ get: function () {
34
+ return _testFilesystem.fileExists;
35
+ }
36
+ });
37
+ exports.gulpConfig = void 0;
38
+ Object.defineProperty(exports, "logObject", {
39
+ enumerable: true,
40
+ get: function () {
41
+ return _testFilesystem.logObject;
42
+ }
43
+ });
44
+ Object.defineProperty(exports, "removeDirectory", {
45
+ enumerable: true,
46
+ get: function () {
47
+ return _testFilesystem.removeDirectory;
48
+ }
49
+ });
50
+ exports.setDefaults = void 0;
51
+ var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
52
+ exports.gulpConfig = gulpConfig;
53
+ var _testFilesystem = require("test-filesystem");
54
+ function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
55
+ // Import the configurations and override some of them to direct to the temp directory.
56
+
57
+ let tempDir = 'test-temp/';
58
+ let srcPath = `${tempDir}src`;
59
+
60
60
  /**
61
61
  * Update the gulp configurations with the test data. Set the test directory where temp files will be created for testing.
62
62
  * @memberOf module:testHelpers
63
63
  * @param {string} testDir
64
- */
65
- const setDefaults = (testDir = 'test-temp') => {
66
- tempDir = `${testDir}/`;
67
- srcPath = `${tempDir}src`;
68
- _testFilesystem.setUp.setDefaults(tempDir);
69
- const distPath = `${tempDir}dist`;
70
- const browserPath = `${tempDir}browser`;
71
- const sassPath = `${tempDir}sass`;
72
- gulpConfig.set('browser.from', `${distPath}/**/*.js`);
73
- gulpConfig.set('browser.to', browserPath);
74
- gulpConfig.set('cleanPaths', [distPath, browserPath]);
75
- gulpConfig.set('dist.from', `${srcPath}/**/!(*.test).js`);
76
- gulpConfig.set('dist.main', `${distPath}/main`);
77
- gulpConfig.set('dist.to', distPath);
78
- gulpConfig.set('fonts.from', `${srcPath}/fonts/**/*`);
79
- gulpConfig.set('fonts.to', `${browserPath}/fonts`);
80
- gulpConfig.set('images.from', `${srcPath}/img/**/*.+(png|jpg|jpeg|gif|svg)`);
81
- gulpConfig.set('images.to', `${browserPath}/img`);
82
- gulpConfig.set('readme.template', `${tempDir}MAIN.md`);
83
- gulpConfig.set('readme.to', tempDir);
84
- gulpConfig.set('readme.from', `${srcPath}/**/!(*.test).js`);
85
- gulpConfig.set('rootPath', tempDir);
86
- gulpConfig.set('sass.from', `${sassPath}/**/*.+(scss|sass)`);
87
- gulpConfig.set('sass.path', sassPath);
88
- gulpConfig.set('sass.to', `${browserPath}/css`);
89
- gulpConfig.set('srcPath', srcPath);
90
- gulpConfig.set('typescript.from', `${srcPath}/**/*.ts`);
91
- gulpConfig.set('typescript.to', distPath);
92
- gulpConfig.set('test.watch', `${srcPath}/**/*.js`);
93
- };
64
+ */
65
+ const setDefaults = (testDir = 'test-temp') => {
66
+ tempDir = `${testDir}/`;
67
+ srcPath = `${tempDir}src`;
68
+ _testFilesystem.setUp.setDefaults(tempDir);
69
+ const distPath = `${tempDir}dist`;
70
+ const browserPath = `${tempDir}browser`;
71
+ const sassPath = `${tempDir}sass`;
72
+ gulpConfig.set('browser.from', `${distPath}/**/*.js`);
73
+ gulpConfig.set('browser.to', browserPath);
74
+ gulpConfig.set('cleanPaths', [distPath, browserPath]);
75
+ gulpConfig.set('dist.from', `${srcPath}/**/!(*.test).js`);
76
+ gulpConfig.set('dist.main', `${distPath}/main`);
77
+ gulpConfig.set('dist.to', distPath);
78
+ gulpConfig.set('fonts.from', `${srcPath}/fonts/**/*`);
79
+ gulpConfig.set('fonts.to', `${browserPath}/fonts`);
80
+ gulpConfig.set('images.from', `${srcPath}/img/**/*.+(png|jpg|jpeg|gif|svg)`);
81
+ gulpConfig.set('images.to', `${browserPath}/img`);
82
+ gulpConfig.set('readme.template', `${tempDir}MAIN.md`);
83
+ gulpConfig.set('readme.to', tempDir);
84
+ gulpConfig.set('readme.from', `${srcPath}/**/!(*.test).js`);
85
+ // Reset explicitly: gulpConfig is a process-wide singleton seeded once from this real project's own
86
+ // build-tools.config.json, so without this, this project's own real readme.fromEsm value (gulp.config.mjs)
87
+ // would leak into every test that exercises addToReadme/compileReadme but never sets this path itself -
88
+ // doing real file I/O and a real jsdoc-to-markdown parse of this project's own, much larger, config file.
89
+ gulpConfig.set('readme.fromEsm', []);
90
+ gulpConfig.set('rootPath', tempDir);
91
+ gulpConfig.set('sass.from', `${sassPath}/**/*.+(scss|sass)`);
92
+ gulpConfig.set('sass.path', sassPath);
93
+ gulpConfig.set('sass.to', `${browserPath}/css`);
94
+ gulpConfig.set('srcPath', srcPath);
95
+ gulpConfig.set('typescript.from', `${srcPath}/**/*.ts`);
96
+ gulpConfig.set('typescript.to', distPath);
97
+ gulpConfig.set('test.watch', `${srcPath}/**/*.js`);
98
+ };
94
99
  exports.setDefaults = setDefaults;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.convertMjsFilesForDocs = void 0;
7
+ require("core-js/modules/esnext.iterator.constructor.js");
8
+ require("core-js/modules/esnext.iterator.map.js");
9
+ var _fs = _interopRequireDefault(require("fs"));
10
+ var _os = _interopRequireDefault(require("os"));
11
+ var _path = _interopRequireDefault(require("path"));
12
+ var _esmNamedExportsToCjs = require("./esmNamedExportsToCjs.js");
13
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
14
+ /**
15
+ * Writes a rewritten (see {@link esmNamedExportsToCjs}) copy of each given `.mjs` file into a fresh, unique
16
+ * directory under the OS temp directory, with a `.js` extension - jsdoc-to-markdown only recognizes `.js` as a
17
+ * documentable file, regardless of whether its contents are actually CommonJS or ESM (it parses the real ESM
18
+ * syntax of the rest of a file fine; the extension is the only thing it filters on). Writing outside the project
19
+ * tree means there is nothing to gitignore and nothing left behind in the project - call the returned `cleanUp`
20
+ * once done (for example, right after jsdoc-to-markdown has read the files) to remove the temp directory.
21
+ * @memberOf module:utilities
22
+ * @param {Array<string>} mjsFilePaths - Real `.mjs` files to convert. An empty array is a safe, cheap no-op.
23
+ * @returns {{filePaths: Array<string>, cleanUp: function(): void}} The temp `.js` file paths to pass to
24
+ * jsdoc-to-markdown instead of the real `.mjs` ones, and a function to remove the temp directory afterward.
25
+ */
26
+ const convertMjsFilesForDocs = (mjsFilePaths = []) => {
27
+ if (mjsFilePaths.length === 0) {
28
+ return {
29
+ filePaths: [],
30
+ cleanUp: () => {}
31
+ };
32
+ }
33
+ const tempDir = _fs.default.mkdtempSync(_path.default.join(_os.default.tmpdir(), 'js-build-tools-docs-'));
34
+ const filePaths = mjsFilePaths.map(mjsFilePath => {
35
+ const tempFilePath = _path.default.join(tempDir, _path.default.basename(mjsFilePath, '.js') + '.js');
36
+ const source = _fs.default.readFileSync(mjsFilePath, 'utf8');
37
+ _fs.default.writeFileSync(tempFilePath, (0, _esmNamedExportsToCjs.esmNamedExportsToCjs)(source));
38
+ return tempFilePath;
39
+ });
40
+ return {
41
+ filePaths,
42
+ cleanUp: () => _fs.default.rmSync(tempDir, {
43
+ recursive: true,
44
+ force: true
45
+ })
46
+ };
47
+ };
48
+ exports.convertMjsFilesForDocs = convertMjsFilesForDocs;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.esmNamedExportsToCjs = void 0;
7
+ /**
8
+ * Rewrites named `export const`/`export function`/`export class` declarations to plain declarations plus a
9
+ * trailing `module.exports = { ... }` - the same shape jsdoc-to-markdown already documents cleanly (a plain
10
+ * declaration with its own `@memberOf` tag, exported all at once at the bottom), rather than the "exports.name"
11
+ * longname jsdoc-to-markdown's own ESM-compat layer produces for an inline `export const name = ...`.
12
+ *
13
+ * This is a narrow, text-level rewrite for documentation purposes only - it does not execute the module, so it
14
+ * only has to look enough like the real thing for jsdoc-to-markdown's parser. It handles the common named-export
15
+ * forms (`export const`, `export function`, `export class`) and leaves everything else (including `export
16
+ * default`, re-exports, and `export { a, b }` lists) untouched in place - a file using one of those keeps its
17
+ * own export line as-is, which jsdoc-to-markdown will document however it already does for ESM.
18
+ * @memberOf module:utilities
19
+ * @param {string} source - The raw ESM source text (never executed, just rewritten as text).
20
+ * @returns {string} The rewritten text, safe to write out with a `.js` extension for jsdoc-to-markdown to read.
21
+ */
22
+ const esmNamedExportsToCjs = source => {
23
+ const exportedNames = [];
24
+ const rewritten = source.replace(/^export (const|function|class) (\w+)/gm, (match, keyword, name) => {
25
+ exportedNames.push(name);
26
+ return `${keyword} ${name}`;
27
+ });
28
+ if (exportedNames.length === 0) {
29
+ return rewritten;
30
+ }
31
+ return `${rewritten}\n\nmodule.exports = { ${exportedNames.join(', ')} }\n`;
32
+ };
33
+ exports.esmNamedExportsToCjs = esmNamedExportsToCjs;
@@ -2,15 +2,24 @@ import fs from 'fs'
2
2
  import * as gulpConfig from '../../gulp.config.mjs'
3
3
  import jsdoc2md from 'jsdoc-to-markdown'
4
4
  import { globSync } from 'glob'
5
+ import { convertMjsFilesForDocs } from '../utilities/convertMjsFilesForDocs.mjs'
5
6
 
6
7
  /**
7
8
  * Appends all the jsdoc comments to the readme file. Assumes empty or templated file.
8
9
  * Configure this with 'readmeSearch', 'readmePath', 'readmeFile', and 'readmeOptions'.
10
+ *
11
+ * jsdoc-to-markdown only recognizes `.js` files, even though it parses real ESM syntax just fine once it reads
12
+ * one - `readme.fromEsm` (empty by default) names `.mjs` files to include anyway, converted on the fly (see
13
+ * {@link convertMjsFilesForDocs}) and cleaned up again once this has read them, win or lose.
9
14
  * @memberOf module:partials
10
15
  * @returns {string|Uint8Array}
11
16
  */
12
- export const addToReadme = () => jsdoc2md
13
- .render({ files: globSync(gulpConfig.get('readme.from')) })
14
- .then(
15
- readme => fs.appendFileSync(gulpConfig.get('readme.to') + gulpConfig.get('readme.file'), readme, gulpConfig.get('readmeOptions'))
16
- )
17
+ export const addToReadme = () => {
18
+ const { filePaths: esmFilePaths, cleanUp } = convertMjsFilesForDocs(globSync(gulpConfig.get('readme.fromEsm') || []))
19
+ return jsdoc2md
20
+ .render({ files: [...globSync(gulpConfig.get('readme.from')), ...esmFilePaths] })
21
+ .finally(cleanUp)
22
+ .then(
23
+ readme => fs.appendFileSync(gulpConfig.get('readme.to') + gulpConfig.get('readme.file'), readme, gulpConfig.get('readmeOptions'))
24
+ )
25
+ }
@@ -30,6 +30,11 @@ export const setDefaults = (testDir = 'test-temp') => {
30
30
  gulpConfig.set('readme.template', `${tempDir}MAIN.md`)
31
31
  gulpConfig.set('readme.to', tempDir)
32
32
  gulpConfig.set('readme.from', `${srcPath}/**/!(*.test).js`)
33
+ // Reset explicitly: gulpConfig is a process-wide singleton seeded once from this real project's own
34
+ // build-tools.config.json, so without this, this project's own real readme.fromEsm value (gulp.config.mjs)
35
+ // would leak into every test that exercises addToReadme/compileReadme but never sets this path itself -
36
+ // doing real file I/O and a real jsdoc-to-markdown parse of this project's own, much larger, config file.
37
+ gulpConfig.set('readme.fromEsm', [])
33
38
  gulpConfig.set('rootPath', tempDir)
34
39
  gulpConfig.set('sass.from', `${sassPath}/**/*.+(scss|sass)`)
35
40
  gulpConfig.set('sass.path', sassPath)
@@ -0,0 +1,33 @@
1
+ import fs from 'fs'
2
+ import os from 'os'
3
+ import path from 'path'
4
+ import { esmNamedExportsToCjs } from './esmNamedExportsToCjs.mjs'
5
+
6
+ /**
7
+ * Writes a rewritten (see {@link esmNamedExportsToCjs}) copy of each given `.mjs` file into a fresh, unique
8
+ * directory under the OS temp directory, with a `.js` extension - jsdoc-to-markdown only recognizes `.js` as a
9
+ * documentable file, regardless of whether its contents are actually CommonJS or ESM (it parses the real ESM
10
+ * syntax of the rest of a file fine; the extension is the only thing it filters on). Writing outside the project
11
+ * tree means there is nothing to gitignore and nothing left behind in the project - call the returned `cleanUp`
12
+ * once done (for example, right after jsdoc-to-markdown has read the files) to remove the temp directory.
13
+ * @memberOf module:utilities
14
+ * @param {Array<string>} mjsFilePaths - Real `.mjs` files to convert. An empty array is a safe, cheap no-op.
15
+ * @returns {{filePaths: Array<string>, cleanUp: function(): void}} The temp `.js` file paths to pass to
16
+ * jsdoc-to-markdown instead of the real `.mjs` ones, and a function to remove the temp directory afterward.
17
+ */
18
+ export const convertMjsFilesForDocs = (mjsFilePaths = []) => {
19
+ if (mjsFilePaths.length === 0) {
20
+ return { filePaths: [], cleanUp: () => {} }
21
+ }
22
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'js-build-tools-docs-'))
23
+ const filePaths = mjsFilePaths.map((mjsFilePath) => {
24
+ const tempFilePath = path.join(tempDir, path.basename(mjsFilePath, '.mjs') + '.js')
25
+ const source = fs.readFileSync(mjsFilePath, 'utf8')
26
+ fs.writeFileSync(tempFilePath, esmNamedExportsToCjs(source))
27
+ return tempFilePath
28
+ })
29
+ return {
30
+ filePaths,
31
+ cleanUp: () => fs.rmSync(tempDir, { recursive: true, force: true })
32
+ }
33
+ }
@@ -0,0 +1,57 @@
1
+ import fs from 'fs'
2
+ import * as setUp from '../test-helpers/setUp.mjs'
3
+ import { convertMjsFilesForDocs } from './convertMjsFilesForDocs.mjs'
4
+
5
+ setUp.setDefaults('test-temp-convert-mjs-for-docs')
6
+ const gulpConfig = setUp.gulpConfig
7
+
8
+ const rawContents = '/**\n' +
9
+ ' * Say hello with a given name.\n' +
10
+ ' * @memberOf module:greet\n' +
11
+ ' * @param {string} name\n' +
12
+ ' * @returns {string}\n' +
13
+ ' */\n' +
14
+ 'export const sayHello = name => `Hello from ${name}`\n'
15
+
16
+ beforeEach(() => setUp.beforeEach()
17
+ .then(() => fs.writeFileSync(gulpConfig.get('srcPath') + '/greet.mjs', rawContents)))
18
+
19
+ afterEach(setUp.afterEach)
20
+
21
+ describe('convertMjsFilesForDocs', () => {
22
+ test('returns an empty result, with a safe no-op cleanUp, for an empty list', () => {
23
+ const { filePaths, cleanUp } = convertMjsFilesForDocs([])
24
+ expect(filePaths).toEqual([])
25
+ expect(() => cleanUp()).not.toThrow()
26
+ })
27
+
28
+ test('writes a rewritten, doc-parseable .js copy outside the project tree', () => {
29
+ const mjsFilePath = gulpConfig.get('srcPath') + '/greet.mjs'
30
+ const { filePaths, cleanUp } = convertMjsFilesForDocs([mjsFilePath])
31
+
32
+ expect(filePaths).toHaveLength(1)
33
+ expect(filePaths[0]).toMatch(/greet\.js$/)
34
+ expect(filePaths[0]).not.toContain(process.cwd())
35
+
36
+ const converted = fs.readFileSync(filePaths[0], 'utf8')
37
+ expect(converted).toContain('const sayHello = name => `Hello from ${name}`')
38
+ expect(converted).toContain('module.exports = { sayHello }')
39
+
40
+ cleanUp()
41
+ expect(fs.existsSync(filePaths[0])).toBe(false)
42
+ })
43
+
44
+ test('converts several files into the same temp directory', () => {
45
+ fs.writeFileSync(gulpConfig.get('srcPath') + '/greetAgain.mjs', rawContents.replace('sayHello', 'sayHelloAgain'))
46
+ const { filePaths, cleanUp } = convertMjsFilesForDocs([
47
+ gulpConfig.get('srcPath') + '/greet.mjs',
48
+ gulpConfig.get('srcPath') + '/greetAgain.mjs'
49
+ ])
50
+
51
+ expect(filePaths).toHaveLength(2)
52
+ filePaths.forEach(filePath => expect(fs.existsSync(filePath)).toBe(true))
53
+
54
+ cleanUp()
55
+ filePaths.forEach(filePath => expect(fs.existsSync(filePath)).toBe(false))
56
+ })
57
+ })
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Rewrites named `export const`/`export function`/`export class` declarations to plain declarations plus a
3
+ * trailing `module.exports = { ... }` - the same shape jsdoc-to-markdown already documents cleanly (a plain
4
+ * declaration with its own `@memberOf` tag, exported all at once at the bottom), rather than the "exports.name"
5
+ * longname jsdoc-to-markdown's own ESM-compat layer produces for an inline `export const name = ...`.
6
+ *
7
+ * This is a narrow, text-level rewrite for documentation purposes only - it does not execute the module, so it
8
+ * only has to look enough like the real thing for jsdoc-to-markdown's parser. It handles the common named-export
9
+ * forms (`export const`, `export function`, `export class`) and leaves everything else (including `export
10
+ * default`, re-exports, and `export { a, b }` lists) untouched in place - a file using one of those keeps its
11
+ * own export line as-is, which jsdoc-to-markdown will document however it already does for ESM.
12
+ * @memberOf module:utilities
13
+ * @param {string} source - The raw ESM source text (never executed, just rewritten as text).
14
+ * @returns {string} The rewritten text, safe to write out with a `.js` extension for jsdoc-to-markdown to read.
15
+ */
16
+ export const esmNamedExportsToCjs = (source) => {
17
+ const exportedNames = []
18
+ const rewritten = source.replace(
19
+ /^export (const|function|class) (\w+)/gm,
20
+ (match, keyword, name) => {
21
+ exportedNames.push(name)
22
+ return `${keyword} ${name}`
23
+ }
24
+ )
25
+ if (exportedNames.length === 0) {
26
+ return rewritten
27
+ }
28
+ return `${rewritten}\n\nmodule.exports = { ${exportedNames.join(', ')} }\n`
29
+ }
@@ -0,0 +1,47 @@
1
+ import { esmNamedExportsToCjs } from './esmNamedExportsToCjs.mjs'
2
+
3
+ describe('esmNamedExportsToCjs', () => {
4
+ test('rewrites a single export const to a plain declaration plus a trailing module.exports', () => {
5
+ const source = 'export const get = (path) => path\n'
6
+ const result = esmNamedExportsToCjs(source)
7
+ expect(result).toContain('const get = (path) => path')
8
+ expect(result).toContain('module.exports = { get }')
9
+ expect(result).not.toContain('export const')
10
+ })
11
+
12
+ test('rewrites multiple export const declarations into one module.exports with all the names', () => {
13
+ const source = 'export const get = () => {}\nexport const set = () => {}\n'
14
+ const result = esmNamedExportsToCjs(source)
15
+ expect(result).toContain('const get = () => {}')
16
+ expect(result).toContain('const set = () => {}')
17
+ expect(result).toContain('module.exports = { get, set }')
18
+ })
19
+
20
+ test('rewrites export function and export class the same way', () => {
21
+ const source = 'export function doThing() {}\nexport class Thing {}\n'
22
+ const result = esmNamedExportsToCjs(source)
23
+ expect(result).toContain('function doThing() {}')
24
+ expect(result).toContain('class Thing {}')
25
+ expect(result).toContain('module.exports = { doThing, Thing }')
26
+ })
27
+
28
+ test('leaves non-export lines and JSDoc comments untouched', () => {
29
+ const source = '/**\n * A function.\n * @memberOf module:gulpConfig\n */\nexport const get = () => {}\n'
30
+ const result = esmNamedExportsToCjs(source)
31
+ expect(result).toContain('/**\n * A function.\n * @memberOf module:gulpConfig\n */\nconst get = () => {}')
32
+ })
33
+
34
+ test('does not add a module.exports block when there is nothing to export', () => {
35
+ const source = 'import { thing } from \'./thing.mjs\'\nconst local = 1\n'
36
+ const result = esmNamedExportsToCjs(source)
37
+ expect(result).toBe(source)
38
+ expect(result).not.toContain('module.exports')
39
+ })
40
+
41
+ test('leaves export default and other export forms untouched', () => {
42
+ const source = 'const value = 1\nexport default value\n'
43
+ const result = esmNamedExportsToCjs(source)
44
+ expect(result).toContain('export default value')
45
+ expect(result).not.toContain('module.exports')
46
+ })
47
+ })
package/gulp.config.mjs CHANGED
@@ -101,6 +101,9 @@ import { fileExists } from 'test-filesystem'
101
101
  * @typedef {Object<string, Setting>} module:gulpConfig~ReadmeConfig
102
102
  * @property {StringSetting} file - The name of the output documentation markdown file.
103
103
  * @property {StringSetting} from - Location of files to use for compiling documentation into the readme.
104
+ * @property {ArrayableSetting} fromEsm - Additional `.mjs` files to document alongside `from`, converted on the
105
+ * fly since the readme generator only recognizes `.js` files - see 'Configure including ESM files in the
106
+ * generated readme'. Empty by default: a project that never sets this gets exactly the readme it always did.
104
107
  * @property {ArrayableSetting} options - Options for formatting the output readme.
105
108
  * @property {StringSetting} template - The file which will be pre-fixed to your README.md output.
106
109
  * @property {StringSetting} to - The directory to output the readme file in.
@@ -200,6 +203,7 @@ const setDefaults = {
200
203
  readme: {
201
204
  file: 'README.md',
202
205
  from: 'src/**/!(*.test).js',
206
+ fromEsm: [],
203
207
  options: 'utf8',
204
208
  template: 'MAIN.md',
205
209
  to: './'
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "js-build-tools",
3
- "version": "5.6.0",
3
+ "version": "5.7.0",
4
4
  "description": "Standardised build process with gulp.",
5
5
  "main": "gulpfile.base.js",
6
6
  "exports": {