js-build-tools 6.2.0 → 6.3.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.
Files changed (59) hide show
  1. package/README.md +180 -9
  2. package/dist/build.js +2 -4
  3. package/dist/build.min.js +1 -1
  4. package/dist/bundle.js +1 -1
  5. package/dist/docs.js +19 -0
  6. package/dist/docs.min.js +1 -0
  7. package/dist/partials/jsdocDocsFor.js +31 -13
  8. package/dist/partials/loadPlaywright.js +34 -0
  9. package/dist/partials/neostandardLint.js +5 -3
  10. package/dist/partials/resolveDocsMethod.js +19 -0
  11. package/dist/partials/serveStatic.js +57 -0
  12. package/dist/partials/tsFor.js +2 -2
  13. package/dist/partials/typeDocsFor.js +28 -22
  14. package/dist/partials.js +34 -0
  15. package/dist/partials.min.js +1 -1
  16. package/dist/test-helpers/setUp.js +6 -0
  17. package/dist/utilities/convertMjsFilesForDocs.js +1 -0
  18. package/dist/utilities/dotGet.js +1 -0
  19. package/dist/utilities/dotNotate.js +5 -0
  20. package/dist/utilities/dotSet.js +1 -0
  21. package/dist/utilities/esmNamedExportsToCjs.js +1 -0
  22. package/dist/utilities/getBundleConfigs.js +1 -0
  23. package/dist/utilities/isObject.js +1 -0
  24. package/dist/utilities/strAfter.js +1 -0
  25. package/dist/utilities/strBefore.js +1 -0
  26. package/functions/build.mjs +2 -4
  27. package/functions/bundle.mjs +1 -1
  28. package/functions/docs.mjs +13 -0
  29. package/functions/docs.test.mjs +45 -0
  30. package/functions/jsdocEsmExports.test.mjs +24 -0
  31. package/functions/partials/jsdocDocsFor.mjs +25 -13
  32. package/functions/partials/jsdocDocsFor.test.mjs +48 -0
  33. package/functions/partials/loadPlaywright.mjs +23 -0
  34. package/functions/partials/loadPlaywright.test.mjs +71 -0
  35. package/functions/partials/neostandardLint.mjs +5 -3
  36. package/functions/partials/resolveDocsMethod.mjs +10 -0
  37. package/functions/partials/resolveDocsMethod.test.mjs +33 -0
  38. package/functions/partials/serveStatic.mjs +47 -0
  39. package/functions/partials/serveStatic.test.mjs +71 -0
  40. package/functions/partials/tsFor.mjs +2 -2
  41. package/functions/partials/typeDocsFor.mjs +24 -20
  42. package/functions/partials/typeDocsFor.test.mjs +23 -0
  43. package/functions/partials.mjs +4 -0
  44. package/functions/partials.test.mjs +1 -1
  45. package/functions/test-helpers/setUp.mjs +6 -0
  46. package/functions/utilities/convertMjsFilesForDocs.mjs +1 -0
  47. package/functions/utilities/dotGet.mjs +1 -0
  48. package/functions/utilities/dotNotate.mjs +5 -0
  49. package/functions/utilities/dotSet.mjs +1 -0
  50. package/functions/utilities/esmNamedExportsToCjs.mjs +1 -0
  51. package/functions/utilities/getBundleConfigs.mjs +1 -0
  52. package/functions/utilities/isObject.mjs +1 -0
  53. package/functions/utilities/strAfter.mjs +1 -0
  54. package/functions/utilities/strBefore.mjs +1 -0
  55. package/gulp.config.mjs +2 -2
  56. package/gulpfile.base.mjs +3 -4
  57. package/jsdoc.base.js +9 -3
  58. package/jsdoc.esmExports.js +17 -0
  59. package/package.json +19 -10
package/README.md CHANGED
@@ -546,7 +546,7 @@ documentation straight from your source, with either engine:
546
546
  are not needed. `typedoc` is an optional peer dependency (like `typescript`), install it in your project with
547
547
  `npm install --save-dev typedoc` (this needs a `typescript` version it supports).
548
548
  * **jsdoc** (for a plain JavaScript project, where TypeDoc has no real types to read) - scans your source
549
- recursively with jsdoc itself, rendered with a modern theme (`clean-jsdoc-theme` by default, used instead of
549
+ (`.js`, `.mjs` and `.cjs` files, leaving out tests and minified `.min.js` copies) recursively with jsdoc itself, rendered with a modern theme (`clean-jsdoc-theme` by default, used instead of
550
550
  jsdoc's own classic default template) instead of the manual `.jsdoc.conf.js` setup described further below.
551
551
  `jsdoc` and whichever theme you configure are optional peer dependencies, install them with
552
552
  `npm install --save-dev jsdoc clean-jsdoc-theme` (or your own chosen theme package).
@@ -558,7 +558,8 @@ Add the following to the exports in your `build-tools.config.json`:
558
558
  "docs": {
559
559
  // Generate the documentation from the source
560
560
  "enabled": true,
561
- // The directory holding the source, each folder in it becomes a module (TypeDoc) or is scanned recursively (jsdoc)
561
+ // The directory holding the source, each folder in it becomes a module (TypeDoc) or is scanned recursively (jsdoc).
562
+ // jsdoc also takes a list of directories and files, for example ["functions", "gulpfile.base.mjs"]
562
563
  "from": "src",
563
564
  // The markdown file used as the front page of the documentation (a short overview of your project)
564
565
  "index": "MAIN.md",
@@ -569,6 +570,8 @@ Add the following to the exports in your `build-tools.config.json`:
569
570
  // Only meaningful when method is (or resolves to) 'jsdoc' - the theme package to render with. TypeDoc
570
571
  // always keeps its own default regardless of this setting.
571
572
  "theme": "clean-jsdoc-theme",
573
+ // The name of the documentation (TypeDoc's title, the theme's title for jsdoc), defaults to the package name
574
+ "title": "",
572
575
  // Where the HTML is generated (the directory is cleared first)
573
576
  "to": "docs"
574
577
  }
@@ -579,6 +582,35 @@ While `docs.enabled` is on, `gulp build` generates the documentation instead of
579
582
  hand-written (a short overview which links to the documentation). If you also export `docs` from your gulpfile you can
580
583
  run it on its own with `gulp docs`, and can then add the script `"docs": "gulp docs"`.
581
584
 
585
+ ### Browser automation (optional)
586
+
587
+ Unlike the rest of this file, this isn't a `build-tools.config.json`-driven feature with its own task - it's a pair
588
+ of plain functions (`partials.loadPlaywright`/`partials.launchBrowser` and `partials.serveStatic`) for whatever your
589
+ own script needs a real browser for: verifying a page that only works correctly in a real browser (for example one
590
+ using `<script type="module">`, which no DOM-simulation library executes at all), or taking a real screenshot.
591
+
592
+ `playwright` is an optional peer dependency, install it in your project with `npm install --save-dev playwright`,
593
+ then fetch a real browser binary once per machine (not per project) with `npx playwright install chromium` - if
594
+ that fails with "Playwright does not support chromium on <your distro>", your OS is too old for the current
595
+ release; either upgrade it or pin an older `playwright` version known to still support it (confirmed: `1.48.0`
596
+ still installs and runs real headless Chromium on Ubuntu 20.04, which the current release has dropped).
597
+
598
+ ```js
599
+ const { launchBrowser, serveStatic } = require('js-build-tools').partials
600
+
601
+ const { server, url } = await serveStatic('browser') // serves ./browser/ over a real local HTTP server
602
+ const browser = await launchBrowser()
603
+ const page = await browser.newPage()
604
+ await page.goto(`${url}/index.html`)
605
+ await page.screenshot({ path: 'homepage.png' }) // a real screenshot, to actually look at
606
+ await browser.close()
607
+ server.close()
608
+ ```
609
+
610
+ `serveStatic` exists because a page loaded directly from a `file://` path resolves any root-relative asset path
611
+ (`/browser/...`) against the filesystem root instead of the page's own directory - serving it over real HTTP avoids
612
+ that entirely, and is also the right fix for the exact same problem in a jsdom-based test.
613
+
582
614
  ### Configure lint rule overrides (optional)
583
615
 
584
616
  `sourceLint` lints your real source directly (not the compiled dist/browser output) with
@@ -613,7 +645,6 @@ In your `package.json` file, add the following scripts:
613
645
  "build": "gulp build",
614
646
  "dev": "gulp",
615
647
  "docs": "gulp docs",
616
- "htmldocs": "jsdoc -R MAIN.md -c ./.jsdoc.conf.js -d docs",
617
648
  "publish:bundle": "gulp copyFiles",
618
649
  "readme": "gulp readme",
619
650
  "sass": "gulp sass",
@@ -629,8 +660,6 @@ In your `package.json` file, add the following scripts:
629
660
 
630
661
  Run any of the above commands with `gulp` or `npm run`.
631
662
 
632
- # Available functions documentation
633
-
634
663
  ## Modules
635
664
 
636
665
  <dl>
@@ -649,6 +678,146 @@ Export these functions to your own project to customize your build pipeline.
649
678
 
650
679
  **Version**: 3.0.0
651
680
  **Author**: Joshua Heagle <joshuaheagle@gmail.com>
681
+
682
+ * [js-build-tools](#module_js-build-tools)
683
+ * [.typeScript](#module_js-build-tools.typeScript) ⇒ <code>function</code>
684
+ * [.typeDocs](#module_js-build-tools.typeDocs) ⇒ <code>function</code>
685
+ * [.jsdocDocs](#module_js-build-tools.jsdocDocs) ⇒ <code>function</code>
686
+ * [.compileReadme](#module_js-build-tools.compileReadme) ⇒ <code>stream.Stream</code>
687
+ * [.watchTest()](#module_js-build-tools.watchTest) ⇒ <code>\*</code>
688
+ * [.watchFull()](#module_js-build-tools.watchFull) ⇒ <code>FSWatcher</code>
689
+ * [.testQuick()](#module_js-build-tools.testQuick) ⇒ <code>Promise.&lt;\*&gt;</code>
690
+ * [.testFull()](#module_js-build-tools.testFull) ⇒ <code>Promise.&lt;\*&gt;</code>
691
+ * [.sourceLint()](#module_js-build-tools.sourceLint) ⇒ <code>\*</code>
692
+ * [.images()](#module_js-build-tools.images) ⇒ <code>stream.Stream</code>
693
+ * [.docs([done])](#module_js-build-tools.docs) ⇒ <code>\*</code>
694
+ * [.distMinify()](#module_js-build-tools.distMinify) ⇒ <code>\*</code>
695
+ * [.dist()](#module_js-build-tools.dist) ⇒ <code>\*</code>
696
+ * [.defaultCmd([done])](#module_js-build-tools.defaultCmd) ⇒ <code>stream.Stream</code>
697
+ * [.copyFonts()](#module_js-build-tools.copyFonts) ⇒ <code>stream.Stream</code>
698
+ * [.copyFiles()](#module_js-build-tools.copyFiles) ⇒ <code>Promise.&lt;void&gt;</code>
699
+ * [.bundleMinify()](#module_js-build-tools.bundleMinify) ⇒ <code>\*</code>
700
+ * [.bundle()](#module_js-build-tools.bundle) ⇒ <code>stream.Stream</code>
701
+ * [.build()](#module_js-build-tools.build) ⇒ <code>stream.Stream</code>
702
+
703
+ <a name="module_js-build-tools.typeScript"></a>
704
+
705
+ ### js-build-tools.typeScript ⇒ <code>function</code>
706
+ Simplified typescript task using tsFor.
707
+
708
+ **Kind**: static constant of [<code>js-build-tools</code>](#module_js-build-tools)
709
+ <a name="module_js-build-tools.typeDocs"></a>
710
+
711
+ ### js-build-tools.typeDocs ⇒ <code>function</code>
712
+ Generate the HTML documentation of a TypeScript project from its source, with the modules mirroring the source
713
+
714
+ **Kind**: static constant of [<code>js-build-tools</code>](#module_js-build-tools)
715
+ <a name="module_js-build-tools.jsdocDocs"></a>
716
+
717
+ ### js-build-tools.jsdocDocs ⇒ <code>function</code>
718
+ Generate the HTML documentation of a plain-JavaScript project from its source, with a modern jsdoc theme
719
+
720
+ **Kind**: static constant of [<code>js-build-tools</code>](#module_js-build-tools)
721
+ <a name="module_js-build-tools.compileReadme"></a>
722
+
723
+ ### js-build-tools.compileReadme ⇒ <code>stream.Stream</code>
724
+ Generate the README.md file based off of the template, then append the generated documentation.
725
+
726
+ **Kind**: static constant of [<code>js-build-tools</code>](#module_js-build-tools)
727
+ <a name="module_js-build-tools.watchTest"></a>
728
+
729
+ ### js-build-tools.watchTest() ⇒ <code>\*</code>
730
+ Watch for changes and run the tests.
731
+
732
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
733
+ <a name="module_js-build-tools.watchFull"></a>
734
+
735
+ ### js-build-tools.watchFull() ⇒ <code>FSWatcher</code>
736
+ Watch for changes and run the distribution for the changed files, then bundle and test the changed files.
737
+
738
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
739
+ <a name="module_js-build-tools.testQuick"></a>
740
+
741
+ ### js-build-tools.testQuick() ⇒ <code>Promise.&lt;\*&gt;</code>
742
+ Run the Jest tests for files which have been modified (based on git status).
743
+
744
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
745
+ <a name="module_js-build-tools.testFull"></a>
746
+
747
+ ### js-build-tools.testFull() ⇒ <code>Promise.&lt;\*&gt;</code>
748
+ Run all tests with jest.
749
+
750
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
751
+ <a name="module_js-build-tools.sourceLint"></a>
752
+
753
+ ### js-build-tools.sourceLint() ⇒ <code>\*</code>
754
+ Applies neostandard linting (js-build-tools' chosen style) to the real, hand-written source - not the compiled
755
+
756
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
757
+ <a name="module_js-build-tools.images"></a>
758
+
759
+ ### js-build-tools.images() ⇒ <code>stream.Stream</code>
760
+ Move and optimize the images into the browser folder using configured settings.
761
+
762
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
763
+ <a name="module_js-build-tools.docs"></a>
764
+
765
+ ### js-build-tools.docs([done]) ⇒ <code>\*</code>
766
+ Generate the HTML documentation with whichever engine docs.method (or its typescript.enabled-based default)
767
+
768
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
769
+
770
+ | Param | Type | Default |
771
+ | --- | --- | --- |
772
+ | [done] | <code>function</code> | <code></code> |
773
+
774
+ <a name="module_js-build-tools.distMinify"></a>
775
+
776
+ ### js-build-tools.distMinify() ⇒ <code>\*</code>
777
+ Creates minified versions of the dist files.
778
+
779
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
780
+ <a name="module_js-build-tools.dist"></a>
781
+
782
+ ### js-build-tools.dist() ⇒ <code>\*</code>
783
+ Simplified distribution tasks which will use arguments from distFor.
784
+
785
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
786
+ <a name="module_js-build-tools.defaultCmd"></a>
787
+
788
+ ### js-build-tools.defaultCmd([done]) ⇒ <code>stream.Stream</code>
789
+ Recommended as the default task, runs the simple dist and bundle tasks.
790
+
791
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
792
+
793
+ | Param | Type | Default |
794
+ | --- | --- | --- |
795
+ | [done] | <code>function</code> | <code></code> |
796
+
797
+ <a name="module_js-build-tools.copyFonts"></a>
798
+
799
+ ### js-build-tools.copyFonts() ⇒ <code>stream.Stream</code>
800
+ Move the font files into the browser directory.
801
+
802
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
803
+ <a name="module_js-build-tools.copyFiles"></a>
804
+
805
+ ### js-build-tools.copyFiles() ⇒ <code>Promise.&lt;void&gt;</code>
806
+ Copy files from one place to another - any number of { from, to, base? } entries, configured via copyFiles.
807
+
808
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
809
+ <a name="module_js-build-tools.bundleMinify"></a>
810
+
811
+ ### js-build-tools.bundleMinify() ⇒ <code>\*</code>
812
+ Creates the minified file for every bundle (the primary bundle, plus any additional ones from
813
+
814
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
815
+ <a name="module_js-build-tools.bundle"></a>
816
+
817
+ ### js-build-tools.bundle() ⇒ <code>stream.Stream</code>
818
+ Starting at each bundle's own entry point (dist.main for the primary bundle, or its own
819
+
820
+ **Kind**: static method of [<code>js-build-tools</code>](#module_js-build-tools)
652
821
  <a name="module_js-build-tools.build"></a>
653
822
 
654
823
  ### js-build-tools.build() ⇒ <code>stream.Stream</code>
@@ -804,7 +973,8 @@ Configurations for building the browser files.
804
973
  <a name="module_gulpConfig..AdditionalBundleConfig"></a>
805
974
 
806
975
  ### gulpConfig~AdditionalBundleConfig : <code>Object.&lt;string, Setting&gt;</code>
807
- One additional bundle - everything but `name` falls back to the primary bundle's own value when omitted, so an
976
+ One additional bundle - everything but `name` falls back to the primary bundle's own value when omitted, so an
977
+ additional bundle only has to specify what's actually different about it.
808
978
 
809
979
  **Kind**: inner typedef of [<code>gulpConfig</code>](#module_gulpConfig)
810
980
  **Properties**
@@ -861,7 +1031,7 @@ Configurations to minify and copy the images.
861
1031
  <a name="module_gulpConfig..LintConfig"></a>
862
1032
 
863
1033
  ### gulpConfig~LintConfig : <code>Object.&lt;string, Setting&gt;</code>
864
- Configurations for linting (see [module:partials.neostandardLint](module:partials.neostandardLint)).
1034
+ Configurations for linting (see [neostandardLint](#module_partials.neostandardLint)).
865
1035
 
866
1036
  **Kind**: inner typedef of [<code>gulpConfig</code>](#module_gulpConfig)
867
1037
  **Properties**
@@ -890,7 +1060,8 @@ Configurations to compile and generate the Readme file.
890
1060
  <a name="module_gulpConfig..DocsConfig"></a>
891
1061
 
892
1062
  ### gulpConfig~DocsConfig : <code>Object.&lt;string, Setting&gt;</code>
893
- Configurations for generating the HTML documentation of a project's own source, with either TypeDoc (real
1063
+ Configurations for generating the HTML documentation of a project's own source, with either TypeDoc (real
1064
+ TypeScript types) or jsdoc (a modern theme over jsdoc's own classic default) - see docs.method.
894
1065
 
895
1066
  **Kind**: inner typedef of [<code>gulpConfig</code>](#module_gulpConfig)
896
1067
  **Properties**
@@ -898,7 +1069,7 @@ Configurations for generating the HTML documentation of a project's own source,
898
1069
  | Name | Type | Description |
899
1070
  | --- | --- | --- |
900
1071
  | enabled | <code>BooleanSetting</code> | Toggle generating the documentation from the source. When it is on the build does this instead of generating the readme from the jsdoc comments of the compiled files. |
901
- | from | <code>StringSetting</code> | The directory holding the source, each folder in it becomes a module (TypeDoc) or is scanned recursively (jsdoc). |
1072
+ | from | <code>ArrayableSetting</code> | The directory holding the source, each folder in it becomes a module (TypeDoc) or is scanned recursively (jsdoc). jsdoc also takes a list of directories and files. |
902
1073
  | index | <code>StringSetting</code> | The markdown file used as the front page of the documentation. |
903
1074
  | logLevel | <code>StringSetting</code> | How much TypeDoc reports: Verbose, Info, Warn, Error or None. Not used by jsdoc. |
904
1075
  | method | <code>FlagStringSetting</code> | 'typedoc' or 'jsdoc'. False (the default) infers it from typescript.enabled - 'typedoc' when on, 'jsdoc' when off - so an existing TypeScript project's config needs no change to keep working exactly as it already does; set this explicitly to override that inference either way. |
package/dist/build.js CHANGED
@@ -17,6 +17,7 @@ var _gulp = require("gulp");
17
17
  var gulpConfig = _interopRequireWildcard(require("../gulp.config.js"));
18
18
  var _copyFonts = require("./copyFonts.js");
19
19
  var _images = require("./images.js");
20
+ var _resolveDocsMethod = require("./partials/resolveDocsMethod.js");
20
21
  var _sass = require("./sass.js");
21
22
  var _testFull = require("./testFull.js");
22
23
  var cache;
@@ -31,10 +32,7 @@ function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e;
31
32
  const build = (done = null) => {
32
33
  const buildActions = [(0, _partials.distSeries)(), _distMinify.distMinify];
33
34
  const generateDocs = gulpConfig.get('docs.enabled');
34
- // docs.method picks the engine explicitly; left unset (false, the default), it's inferred from
35
- // typescript.enabled - every existing TypeScript project's config, which never sets method, keeps producing
36
- // TypeDoc output exactly as it always has.
37
- const docsMethod = gulpConfig.get('docs.method') || (gulpConfig.get('typescript.enabled') ? 'typedoc' : 'jsdoc');
35
+ const docsMethod = (0, _resolveDocsMethod.resolveDocsMethod)();
38
36
  if (generateDocs) {
39
37
  // The documentation is generated from the source itself, the readme is written by hand
40
38
  buildActions.push(docsMethod === 'jsdoc' ? _jsdocDocs.jsdocDocs : _typeDocs.typeDocs);
package/dist/build.min.js CHANGED
@@ -1 +1 @@
1
- "use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.build=void 0;var cache,_bundle=require("./bundle.js"),_bundleMinify=require("./bundleMinify.js"),_partials=require("./partials.js"),_compileReadme=require("./compileReadme.js"),_typeDocs=require("./typeDocs.js"),_jsdocDocs=require("./jsdocDocs.js"),_distMinify=require("./distMinify.js"),_sourceLint=require("./sourceLint.js"),_gulp=require("gulp"),gulpConfig=_interopRequireWildcard(require("../gulp.config.js")),_copyFonts=require("./copyFonts.js"),_images=require("./images.js"),_sass=require("./sass.js"),_testFull=require("./testFull.js");function _interopRequireWildcard(e,s){if(!s&&e&&e.__esModule)return e;var i,t,r=Object.defineProperty,l={__proto__:null,default:e};if(Object(e)!==e)return l;if(cache||"function"!=typeof WeakMap||(cache=new WeakMap),cache){if(cache.has(e))return cache.get(e);cache.set(e,l)}for(t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((i=r&&Object.getOwnPropertyDescriptor(e,t))&&(i.get||i.set)?r(l,t,i):l[t]=e[t]);return l}const build=(e=null)=>{const s=[(0,_partials.distSeries)(),_distMinify.distMinify],i=gulpConfig.get("docs.enabled"),t=gulpConfig.get("docs.method")||(gulpConfig.get("typescript.enabled")?"typedoc":"jsdoc");i?s.push("jsdoc"===t?_jsdocDocs.jsdocDocs:_typeDocs.typeDocs):gulpConfig.get("typescript.enabled")&&s.push(_compileReadme.compileReadme),gulpConfig.get("browser.enabled")&&(s.push(_bundle.bundle),s.push(_bundleMinify.bundleMinify));const r=[(0,_gulp.series)(...s)];return i||gulpConfig.get("typescript.enabled")||r.push(_compileReadme.compileReadme),r.push(_testFull.testFull),gulpConfig.get("fonts.enabled")&&r.push(_copyFonts.copyFonts),gulpConfig.get("images.enabled")&&r.push(_images.images),gulpConfig.get("sass.enabled")&&r.push(_sass.sass),(0,_gulp.series)((0,_gulp.parallel)(_partials.clean,_sourceLint.sourceLint),(0,_gulp.parallel)(...r))(e)};exports.build=build;
1
+ "use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.build=void 0;var cache,_bundle=require("./bundle.js"),_bundleMinify=require("./bundleMinify.js"),_partials=require("./partials.js"),_compileReadme=require("./compileReadme.js"),_typeDocs=require("./typeDocs.js"),_jsdocDocs=require("./jsdocDocs.js"),_distMinify=require("./distMinify.js"),_sourceLint=require("./sourceLint.js"),_gulp=require("gulp"),gulpConfig=_interopRequireWildcard(require("../gulp.config.js")),_copyFonts=require("./copyFonts.js"),_images=require("./images.js"),_resolveDocsMethod=require("./partials/resolveDocsMethod.js"),_sass=require("./sass.js"),_testFull=require("./testFull.js");function _interopRequireWildcard(e,s){if(!s&&e&&e.__esModule)return e;var i,r,t=Object.defineProperty,l={__proto__:null,default:e};if(Object(e)!==e)return l;if(cache||"function"!=typeof WeakMap||(cache=new WeakMap),cache){if(cache.has(e))return cache.get(e);cache.set(e,l)}for(r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((i=t&&Object.getOwnPropertyDescriptor(e,r))&&(i.get||i.set)?t(l,r,i):l[r]=e[r]);return l}const build=(e=null)=>{const s=[(0,_partials.distSeries)(),_distMinify.distMinify],i=gulpConfig.get("docs.enabled"),r=(0,_resolveDocsMethod.resolveDocsMethod)();i?s.push("jsdoc"===r?_jsdocDocs.jsdocDocs:_typeDocs.typeDocs):gulpConfig.get("typescript.enabled")&&s.push(_compileReadme.compileReadme),gulpConfig.get("browser.enabled")&&(s.push(_bundle.bundle),s.push(_bundleMinify.bundleMinify));const t=[(0,_gulp.series)(...s)];return i||gulpConfig.get("typescript.enabled")||t.push(_compileReadme.compileReadme),t.push(_testFull.testFull),gulpConfig.get("fonts.enabled")&&t.push(_copyFonts.copyFonts),gulpConfig.get("images.enabled")&&t.push(_images.images),gulpConfig.get("sass.enabled")&&t.push(_sass.sass),(0,_gulp.series)((0,_gulp.parallel)(_partials.clean,_sourceLint.sourceLint),(0,_gulp.parallel)(...t))(e)};exports.build=build;
package/dist/bundle.js CHANGED
@@ -25,7 +25,7 @@ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e
25
25
  *
26
26
  * A bundle's name does double duty: it names the output file (name.js) and, via browserify's
27
27
  * `standalone` option, is also the name its exports are exposed under - as a global when loaded
28
- * with a bare <script> tag, or as the module when required via CommonJS/AMD. Without this, a
28
+ * with a bare `<script>` tag, or as the module when required via CommonJS/AMD. Without this, a
29
29
  * bundle built from a real entry point (one that actually exports something) builds successfully
30
30
  * but exposes nothing a consumer can reach.
31
31
  *
package/dist/docs.js ADDED
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.docs = void 0;
7
+ var _jsdocDocs = require("./jsdocDocs.js");
8
+ var _resolveDocsMethod = require("./partials/resolveDocsMethod.js");
9
+ var _typeDocs = require("./typeDocs.js");
10
+ /**
11
+ * Generate the HTML documentation with whichever engine docs.method (or its typescript.enabled-based default)
12
+ * resolves to - see {@link module:partials.resolveDocsMethod}. The standalone counterpart to build's own
13
+ * internal branching, for running `gulp docs` directly instead of as part of a full build.
14
+ * @memberOf module:js-build-tools
15
+ * @param {Function} [done]
16
+ * @returns {*}
17
+ */
18
+ const docs = (done = null) => ((0, _resolveDocsMethod.resolveDocsMethod)() === 'jsdoc' ? _jsdocDocs.jsdocDocs : _typeDocs.typeDocs)(done);
19
+ exports.docs = docs;
@@ -0,0 +1 @@
1
+ "use strict";Object.defineProperty(exports,"__esModule",{value:!0}),exports.docs=void 0;var _jsdocDocs=require("./jsdocDocs.js"),_resolveDocsMethod=require("./partials/resolveDocsMethod.js"),_typeDocs=require("./typeDocs.js");const docs=(o=null)=>("jsdoc"===(0,_resolveDocsMethod.resolveDocsMethod)()?_jsdocDocs.jsdocDocs:_typeDocs.typeDocs)(o);exports.docs=docs;
@@ -21,12 +21,13 @@ var _jsdocBase = _interopRequireDefault(require("../../jsdoc.base.js"));
21
21
  var cache;
22
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
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).
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
28
 
29
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;');
30
31
  const jsdocInstallHint = 'Install it in your project with: npm install --save-dev jsdoc';
31
32
  const themeInstallHint = name => `Install it in your project with: npm install --save-dev ${name}`;
32
33
 
@@ -78,11 +79,9 @@ const resolveJsdocBin = (projectPath = process.cwd()) => _nodePath.default.join(
78
79
  }), 'jsdoc.js');
79
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()]
@@ -95,7 +94,8 @@ const resolveJsdocTheme = (name, projectPath = process.cwd()) => {
95
94
  installHint: themeInstallHint(name),
96
95
  projectPath
97
96
  });
98
- return name === 'clean-jsdoc-theme' ? _nodePath.default.join(packageDir, 'dist') : packageDir;
97
+ const distDir = _nodePath.default.join(packageDir, 'dist');
98
+ return _nodeFs.default.existsSync(_nodePath.default.join(distDir, 'publish.js')) ? distDir : packageDir;
99
99
  };
100
100
 
101
101
  /**
@@ -105,7 +105,8 @@ 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.
@@ -120,12 +121,13 @@ const jsdocDocsFor = (srcPath = gulpConfig.get('docs.from'), outPath = gulpConfi
120
121
  const theme = gulpConfig.get('docs.theme') || 'clean-jsdoc-theme';
121
122
  const themeDir = resolveJsdocTheme(theme);
122
123
  const indexFile = gulpConfig.get('docs.index');
124
+ const title = gulpConfig.get('docs.title');
123
125
  await (0, _removeDirectory.removeDirectory)(outPath);
124
126
  const config = {
125
127
  ..._jsdocBase.default,
126
128
  source: {
127
129
  ..._jsdocBase.default.source,
128
- include: [_nodePath.default.resolve(srcPath)]
130
+ include: [].concat(srcPath).map(includePath => _nodePath.default.resolve(includePath))
129
131
  },
130
132
  opts: {
131
133
  destination: _nodePath.default.resolve(outPath),
@@ -134,6 +136,13 @@ const jsdocDocsFor = (srcPath = gulpConfig.get('docs.from'), outPath = gulpConfi
134
136
  // quick-start example, which sets this explicitly, not assumed from jsdoc's own classic defaults.
135
137
  recurse: true,
136
138
  template: themeDir,
139
+ // clean-jsdoc-theme's own option for the name in its header. Given as a link: a plain-text title links to the
140
+ // site root ("/"), while every page is in one folder, so index.html is the home page wherever they are served
141
+ ...(title ? {
142
+ theme_opts: {
143
+ title: `<a href="index.html" class="sidebar-title sidebar-title-anchor">${escapeHtml(title)}</a>`
144
+ }
145
+ } : {}),
137
146
  ...(indexFile && _nodeFs.default.existsSync(indexFile) ? {
138
147
  readme: _nodePath.default.resolve(indexFile)
139
148
  } : {})
@@ -144,7 +153,16 @@ const jsdocDocsFor = (srcPath = gulpConfig.get('docs.from'), outPath = gulpConfi
144
153
  const configPath = _nodePath.default.join(workDir, 'jsdoc.conf.json');
145
154
  _nodeFs.default.writeFileSync(configPath, JSON.stringify(config));
146
155
  const bin = resolveJsdocBin();
147
- await runJsdoc(bin, ['-c', configPath]);
156
+ // Pass on what jsdoc and the theme report (warnings such as a page which failed to render), which would
157
+ // otherwise be lost with the captured output
158
+ const {
159
+ stdout = '',
160
+ stderr = ''
161
+ } = (await runJsdoc(bin, ['-c', configPath])) || {};
162
+ const report = `${stdout}${stderr}`.trim();
163
+ if (report) {
164
+ console.warn(report);
165
+ }
148
166
  } finally {
149
167
  await (0, _removeDirectory.removeDirectory)(workDir);
150
168
  }
@@ -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,
@@ -0,0 +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; }
11
+ /**
12
+ * Pick which engine generates the HTML documentation: docs.method picks it explicitly; left unset (false, the
13
+ * default), it's inferred from typescript.enabled - every existing TypeScript project's config, which never
14
+ * sets method, keeps producing TypeDoc output exactly as it always has.
15
+ * @memberOf module:partials
16
+ * @returns {'typedoc'|'jsdoc'}
17
+ */
18
+ const resolveDocsMethod = () => gulpConfig.get('docs.method') || (gulpConfig.get('typescript.enabled') ? 'typedoc' : 'jsdoc');
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);