js-build-tools 5.3.1 → 5.4.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 +3 -1
- package/dist/build.js +63 -63
- package/dist/bundle.js +34 -27
- package/dist/bundle.min.js +1 -1
- package/dist/partials/typeDocsFor.js +31 -7
- package/dist/typeDocs.js +9 -9
- package/functions/bundle.mjs +6 -1
- package/functions/bundle.test.mjs +20 -0
- package/functions/partials/typeDocsFor.mjs +29 -5
- package/functions/partials/typeDocsFor.test.mjs +26 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -444,7 +444,9 @@ module.exports = babelConfig
|
|
|
444
444
|
the readme it generates. Instead, this can generate HTML documentation straight from the TypeScript source with
|
|
445
445
|
[TypeDoc](https://typedoc.org/). Every folder in your source directory becomes a module of the documentation, the default
|
|
446
446
|
export of each file (one function per file) is listed under the name of the file, and everything else a file exports (for
|
|
447
|
-
example the types in a `types.ts`) is listed as it is. Index files, tests and declaration files are left out.
|
|
447
|
+
example the types in a `types.ts`) is listed as it is. Index files, tests and declaration files are left out. A file
|
|
448
|
+
which sits directly in the source directory, beside the folders, is a module of its own (unless it is `index` or
|
|
449
|
+
`main`). The first comment of a folder's `index.ts` (or the header comment of such a file) describes its module. The
|
|
448
450
|
comments on your code are the documentation, and the types come from the code itself, so `@module`, `@memberOf`,
|
|
449
451
|
`@typedef` and the `{Type}` of `@param` are not needed.
|
|
450
452
|
|
package/dist/build.js
CHANGED
|
@@ -1,68 +1,68 @@
|
|
|
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.build = void 0
|
|
8
|
-
const _bundle = require('./bundle.js')
|
|
9
|
-
const _bundleLint = require('./bundleLint.js')
|
|
10
|
-
const _bundleMinify = require('./bundleMinify.js')
|
|
11
|
-
const _partials = require('./partials.js')
|
|
12
|
-
const _compileReadme = require('./compileReadme.js')
|
|
13
|
-
const _typeDocs = require('./typeDocs.js')
|
|
14
|
-
const _distLint = require('./distLint.js')
|
|
15
|
-
const _distMinify = require('./distMinify.js')
|
|
16
|
-
const _gulp = require('gulp')
|
|
17
|
-
const gulpConfig = _interopRequireWildcard(require('../gulp.config.js'))
|
|
18
|
-
const _copyFonts = require('./copyFonts.js')
|
|
19
|
-
const _images = require('./images.js')
|
|
20
|
-
const _sass = require('./sass.js')
|
|
21
|
-
const _testFull = require('./testFull.js')
|
|
22
|
-
function _interopRequireWildcard (e, t) { if (typeof WeakMap === 'function') var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; let o; let i; const f = { __proto__: null, default: e }; if (e === null || typeof e !== 'object' && typeof e !== 'function') return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f) } for (const t in e) t !== 'default' && {}.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) }
|
|
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.build = void 0
|
|
8
|
+
const _bundle = require('./bundle.js')
|
|
9
|
+
const _bundleLint = require('./bundleLint.js')
|
|
10
|
+
const _bundleMinify = require('./bundleMinify.js')
|
|
11
|
+
const _partials = require('./partials.js')
|
|
12
|
+
const _compileReadme = require('./compileReadme.js')
|
|
13
|
+
const _typeDocs = require('./typeDocs.js')
|
|
14
|
+
const _distLint = require('./distLint.js')
|
|
15
|
+
const _distMinify = require('./distMinify.js')
|
|
16
|
+
const _gulp = require('gulp')
|
|
17
|
+
const gulpConfig = _interopRequireWildcard(require('../gulp.config.js'))
|
|
18
|
+
const _copyFonts = require('./copyFonts.js')
|
|
19
|
+
const _images = require('./images.js')
|
|
20
|
+
const _sass = require('./sass.js')
|
|
21
|
+
const _testFull = require('./testFull.js')
|
|
22
|
+
function _interopRequireWildcard (e, t) { if (typeof WeakMap === 'function') var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; let o; let i; const f = { __proto__: null, default: e }; if (e === null || typeof e !== 'object' && typeof e !== 'function') return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f) } for (const t in e) t !== 'default' && {}.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) }
|
|
23
23
|
/**
|
|
24
24
|
* Runs several processes to build and validate the project.
|
|
25
25
|
* Cleans, distributes (lint and minify), bundles (lint and minify), creates the readme, then runs the tests.
|
|
26
26
|
* @memberOf module:js-build-tools
|
|
27
27
|
* @returns {stream.Stream}
|
|
28
|
-
*/
|
|
29
|
-
const build = (done = null) => {
|
|
30
|
-
const distLintMinify = (0, _gulp.parallel)(_distLint.distLint, _distMinify.distMinify)
|
|
31
|
-
const bundleLintMinify = (0, _gulp.parallel)(_bundleLint.bundleLint, _bundleMinify.bundleMinify)
|
|
32
|
-
const buildActions = [(0, _partials.distSeries)(), distLintMinify]
|
|
33
|
-
const generateDocs = gulpConfig.get('docs.enabled')
|
|
34
|
-
if (generateDocs) {
|
|
35
|
-
// The documentation is generated from the TypeScript source itself, the readme is written by hand
|
|
36
|
-
buildActions.push(_typeDocs.typeDocs)
|
|
37
|
-
} else if (gulpConfig.get('typescript.enabled')) {
|
|
38
|
-
// For ts usage, we need to run the readme on the dist directly since that is where the .js files are located
|
|
39
|
-
buildActions.push(_compileReadme.compileReadme)
|
|
40
|
-
}
|
|
41
|
-
if (gulpConfig.get('browser.enabled')) {
|
|
42
|
-
// If not 'nodeOnly' then we also want to bundle for browser after we complete the dist directory
|
|
43
|
-
buildActions.push(_bundle.bundle)
|
|
44
|
-
buildActions.push(bundleLintMinify)
|
|
45
|
-
}
|
|
46
|
-
const runActions = [(0, _gulp.series)(...buildActions)]
|
|
47
|
-
if (!generateDocs && !gulpConfig.get('typescript.enabled')) {
|
|
48
|
-
// Since we didn't run this in series after dist because of typescript, we need to run it now. Potentially faster here.
|
|
49
|
-
runActions.push(_compileReadme.compileReadme)
|
|
50
|
-
}
|
|
51
|
-
runActions.push(_testFull.testFull)
|
|
52
|
-
if (gulpConfig.get('fonts.enabled')) {
|
|
53
|
-
// Conditionally add Fonts process
|
|
54
|
-
runActions.push(_copyFonts.copyFonts)
|
|
55
|
-
}
|
|
56
|
-
if (gulpConfig.get('images.enabled')) {
|
|
57
|
-
// Conditionally add Images process
|
|
58
|
-
runActions.push(_images.images)
|
|
59
|
-
}
|
|
60
|
-
if (gulpConfig.get('sass.enabled')) {
|
|
61
|
-
// Conditionally add SASS process
|
|
62
|
-
runActions.push(_sass.sass)
|
|
63
|
-
}
|
|
64
|
-
// clean has to finish before anything writes into the output folders - images, fonts and sass all write into
|
|
65
|
-
// browser/, so running clean in parallel with them races (ENOTEMPTY errors from clean, or output deleted mid-write).
|
|
66
|
-
return (0, _gulp.series)(_partials.clean, (0, _gulp.parallel)(...runActions))(done)
|
|
67
|
-
}
|
|
68
|
-
exports.build = build
|
|
28
|
+
*/
|
|
29
|
+
const build = (done = null) => {
|
|
30
|
+
const distLintMinify = (0, _gulp.parallel)(_distLint.distLint, _distMinify.distMinify)
|
|
31
|
+
const bundleLintMinify = (0, _gulp.parallel)(_bundleLint.bundleLint, _bundleMinify.bundleMinify)
|
|
32
|
+
const buildActions = [(0, _partials.distSeries)(), distLintMinify]
|
|
33
|
+
const generateDocs = gulpConfig.get('docs.enabled')
|
|
34
|
+
if (generateDocs) {
|
|
35
|
+
// The documentation is generated from the TypeScript source itself, the readme is written by hand
|
|
36
|
+
buildActions.push(_typeDocs.typeDocs)
|
|
37
|
+
} else if (gulpConfig.get('typescript.enabled')) {
|
|
38
|
+
// For ts usage, we need to run the readme on the dist directly since that is where the .js files are located
|
|
39
|
+
buildActions.push(_compileReadme.compileReadme)
|
|
40
|
+
}
|
|
41
|
+
if (gulpConfig.get('browser.enabled')) {
|
|
42
|
+
// If not 'nodeOnly' then we also want to bundle for browser after we complete the dist directory
|
|
43
|
+
buildActions.push(_bundle.bundle)
|
|
44
|
+
buildActions.push(bundleLintMinify)
|
|
45
|
+
}
|
|
46
|
+
const runActions = [(0, _gulp.series)(...buildActions)]
|
|
47
|
+
if (!generateDocs && !gulpConfig.get('typescript.enabled')) {
|
|
48
|
+
// Since we didn't run this in series after dist because of typescript, we need to run it now. Potentially faster here.
|
|
49
|
+
runActions.push(_compileReadme.compileReadme)
|
|
50
|
+
}
|
|
51
|
+
runActions.push(_testFull.testFull)
|
|
52
|
+
if (gulpConfig.get('fonts.enabled')) {
|
|
53
|
+
// Conditionally add Fonts process
|
|
54
|
+
runActions.push(_copyFonts.copyFonts)
|
|
55
|
+
}
|
|
56
|
+
if (gulpConfig.get('images.enabled')) {
|
|
57
|
+
// Conditionally add Images process
|
|
58
|
+
runActions.push(_images.images)
|
|
59
|
+
}
|
|
60
|
+
if (gulpConfig.get('sass.enabled')) {
|
|
61
|
+
// Conditionally add SASS process
|
|
62
|
+
runActions.push(_sass.sass)
|
|
63
|
+
}
|
|
64
|
+
// clean has to finish before anything writes into the output folders - images, fonts and sass all write into
|
|
65
|
+
// browser/, so running clean in parallel with them races (ENOTEMPTY errors from clean, or output deleted mid-write).
|
|
66
|
+
return (0, _gulp.series)(_partials.clean, (0, _gulp.parallel)(...runActions))(done)
|
|
67
|
+
}
|
|
68
|
+
exports.build = build
|
package/dist/bundle.js
CHANGED
|
@@ -1,36 +1,43 @@
|
|
|
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.bundle = void 0
|
|
8
|
-
const _browserify = _interopRequireDefault(require('browserify'))
|
|
9
|
-
const _gulp = require('gulp')
|
|
10
|
-
const gulpConfig = _interopRequireWildcard(require('../gulp.config.js'))
|
|
11
|
-
const _vinylSourceStream = _interopRequireDefault(require('vinyl-source-stream'))
|
|
12
|
-
function _interopRequireWildcard (e, t) { if (typeof WeakMap === 'function') var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; let o; let i; const f = { __proto__: null, default: e }; if (e === null || typeof e !== 'object' && typeof e !== 'function') return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f) } for (const t in e) t !== 'default' && {}.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.bundle = void 0
|
|
8
|
+
const _browserify = _interopRequireDefault(require('browserify'))
|
|
9
|
+
const _gulp = require('gulp')
|
|
10
|
+
const gulpConfig = _interopRequireWildcard(require('../gulp.config.js'))
|
|
11
|
+
const _vinylSourceStream = _interopRequireDefault(require('vinyl-source-stream'))
|
|
12
|
+
function _interopRequireWildcard (e, t) { if (typeof WeakMap === 'function') var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; let o; let i; const f = { __proto__: null, default: e }; if (e === null || typeof e !== 'object' && typeof e !== 'function') return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f) } for (const t in e) t !== 'default' && {}.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 } }
|
|
14
14
|
/**
|
|
15
15
|
* Starting at the distribution entry point, bundle all the files into a single file and store them in the specified output directory.
|
|
16
16
|
*
|
|
17
|
+
* browser.name does double duty: it names the output file (browser.name.js) and, via browserify's `standalone`
|
|
18
|
+
* option, is also the name the bundle's exports are exposed under - as a global when loaded with a bare <script>
|
|
19
|
+
* tag, or as the module when required via CommonJS/AMD. Without this, a bundle built from a real entry point (one
|
|
20
|
+
* that actually exports something) builds successfully but exposes nothing a consumer can reach.
|
|
21
|
+
*
|
|
17
22
|
* Two escape hatches from browser.config.json keep an unwanted dependency (or a dependency's dependency) out of the
|
|
18
23
|
* bundle: 'ignore' replaces it with an empty object (safe when your code never actually calls into it - for example
|
|
19
24
|
* a library's default option value you always override with your own) and 'exclude' leaves it out entirely (your
|
|
20
25
|
* code must not require it, or provide it another way, such as a separate script tag).
|
|
21
26
|
* @memberOf module:js-build-tools
|
|
22
27
|
* @returns {stream.Stream}
|
|
23
|
-
*/
|
|
24
|
-
const bundle = () => {
|
|
25
|
-
const bundler = (0, _browserify.default)(gulpConfig.get('dist.main')
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
|
|
28
|
+
*/
|
|
29
|
+
const bundle = () => {
|
|
30
|
+
const bundler = (0, _browserify.default)(gulpConfig.get('dist.main'), {
|
|
31
|
+
standalone: gulpConfig.get('browser.name')
|
|
32
|
+
})
|
|
33
|
+
const ignore = gulpConfig.get('browser.ignore')
|
|
34
|
+
const exclude = gulpConfig.get('browser.exclude')
|
|
35
|
+
if (ignore && ignore.length) {
|
|
36
|
+
bundler.ignore(ignore)
|
|
37
|
+
}
|
|
38
|
+
if (exclude && exclude.length) {
|
|
39
|
+
bundler.exclude(exclude)
|
|
40
|
+
}
|
|
41
|
+
return bundler.bundle().pipe((0, _vinylSourceStream.default)(`${gulpConfig.get('browser.name')}.js`)).pipe((0, _gulp.dest)(gulpConfig.get('browser.to')))
|
|
42
|
+
}
|
|
43
|
+
exports.bundle = bundle
|
package/dist/bundle.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.bundle=void 0;var _browserify=_interopRequireDefault(require("browserify")),_gulp=require("gulp"),gulpConfig=_interopRequireWildcard(require("../gulp.config.js")),_vinylSourceStream=_interopRequireDefault(require("vinyl-source-stream"));function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var t=new WeakMap,
|
|
1
|
+
"use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.bundle=void 0;var _browserify=_interopRequireDefault(require("browserify")),_gulp=require("gulp"),gulpConfig=_interopRequireWildcard(require("../gulp.config.js")),_vinylSourceStream=_interopRequireDefault(require("vinyl-source-stream"));function _interopRequireWildcard(e,r){if("function"==typeof WeakMap)var t=new WeakMap,n=new WeakMap;return(_interopRequireWildcard=function(e,r){if(!r&&e&&e.__esModule)return e;var u,o,i={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return i;if(u=r?n:t){if(u.has(e))return u.get(e);u.set(e,i)}for(const r in e)"default"!==r&&{}.hasOwnProperty.call(e,r)&&((o=(u=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,r))&&(o.get||o.set)?u(i,r,o):i[r]=e[r]);return i})(e,r)}function _interopRequireDefault(e){return e&&e.__esModule?e:{default:e}}const bundle=()=>{const e=(0,_browserify.default)(gulpConfig.get("dist.main"),{standalone:gulpConfig.get("browser.name")}),r=gulpConfig.get("browser.ignore"),t=gulpConfig.get("browser.exclude");return r&&r.length&&e.ignore(r),t&&t.length&&e.exclude(t),e.bundle().pipe((0,_vinylSourceStream.default)(`${gulpConfig.get("browser.name")}.js`)).pipe((0,_gulp.dest)(gulpConfig.get("browser.to")))};exports.bundle=bundle;
|
|
@@ -4,7 +4,7 @@ require("core-js/modules/esnext.weak-map.delete-all.js");
|
|
|
4
4
|
Object.defineProperty(exports, "__esModule", {
|
|
5
5
|
value: true
|
|
6
6
|
});
|
|
7
|
-
exports.writeDocEntries = exports.typeDocsFor = exports.loadTypeDoc = exports.describeFolder = exports.describeExports = void 0;
|
|
7
|
+
exports.writeDocEntries = exports.typeDocsFor = exports.loadTypeDoc = exports.describeFolder = exports.describeFile = exports.describeExports = void 0;
|
|
8
8
|
require("core-js/modules/es.json.stringify.js");
|
|
9
9
|
require("core-js/modules/esnext.iterator.constructor.js");
|
|
10
10
|
require("core-js/modules/esnext.iterator.filter.js");
|
|
@@ -102,7 +102,20 @@ const describeExports = (ts, filePath) => {
|
|
|
102
102
|
exports.describeExports = describeExports;
|
|
103
103
|
const describeFolder = folderPath => {
|
|
104
104
|
const indexFile = ['index.ts', 'index.tsx', 'index.mts', 'index.cts'].map(name => _nodePath.default.join(folderPath, name)).find(file => _nodeFs.default.existsSync(file));
|
|
105
|
-
|
|
105
|
+
return indexFile ? describeFile(indexFile) : '';
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* The description of a source file for its module: its first doc comment without the tags (@module, @file, ...), when
|
|
110
|
+
* that comment is a header (it is followed by an import or export, so it does not document a declaration itself), or
|
|
111
|
+
* an empty string.
|
|
112
|
+
* @memberOf module:partials
|
|
113
|
+
* @param {string} filePath
|
|
114
|
+
* @returns {string}
|
|
115
|
+
*/
|
|
116
|
+
exports.describeFolder = describeFolder;
|
|
117
|
+
const describeFile = filePath => {
|
|
118
|
+
const comment = _nodeFs.default.readFileSync(filePath, 'utf8').match(/^\s*\/\*\*([\s\S]*?)\*\/\s*(import\b|export\s+(\*|\{[^}]*\}\s+from)|$)/);
|
|
106
119
|
if (!comment) {
|
|
107
120
|
return '';
|
|
108
121
|
}
|
|
@@ -116,14 +129,16 @@ const describeFolder = folderPath => {
|
|
|
116
129
|
* entry file, so the modules of the documentation mirror the folders. The default export of each source file is
|
|
117
130
|
* re-exported under the name of the file (the source files hold one function each), and anything else a file exports
|
|
118
131
|
* is re-exported as it is (that is where the types.ts files go). Index files (the barrels), tests and declaration
|
|
119
|
-
* files are left out, but the first doc comment of a folder's index file becomes the description of its module.
|
|
132
|
+
* files are left out, but the first doc comment of a folder's index file becomes the description of its module.
|
|
133
|
+
* A file which sits beside the folders (not an index or main file) is a module of its own, described by its header
|
|
134
|
+
* comment. A source directory with no folders gets a single entry called index.
|
|
120
135
|
* @memberOf module:partials
|
|
121
136
|
* @param {Object} ts - The TypeScript compiler API.
|
|
122
137
|
* @param {string} srcDir - The directory holding the TypeScript source.
|
|
123
138
|
* @param {string} entryDir - The directory to write the entry files into.
|
|
124
139
|
* @returns {Array<string>} The paths of the entry files.
|
|
125
140
|
*/
|
|
126
|
-
exports.
|
|
141
|
+
exports.describeFile = describeFile;
|
|
127
142
|
const writeDocEntries = (ts, srcDir, entryDir) => {
|
|
128
143
|
const absoluteSrc = _nodePath.default.resolve(srcDir);
|
|
129
144
|
_nodeFs.default.mkdirSync(entryDir, {
|
|
@@ -136,10 +151,19 @@ const writeDocEntries = (ts, srcDir, entryDir) => {
|
|
|
136
151
|
path: _nodePath.default.join(absoluteSrc, entry.name),
|
|
137
152
|
files: listSources(_nodePath.default.join(absoluteSrc, entry.name))
|
|
138
153
|
})).filter(folder => folder.files.length);
|
|
139
|
-
const
|
|
154
|
+
const rootFiles = _nodeFs.default.readdirSync(absoluteSrc, {
|
|
155
|
+
withFileTypes: true
|
|
156
|
+
}).filter(entry => entry.isFile() && isSource(entry.name) && !/^(index|main)\./.test(entry.name)).map(entry => _nodePath.default.join(absoluteSrc, entry.name));
|
|
157
|
+
// Folders make modules, and so do the files which sit beside them (except the barrel: index and main). A source
|
|
158
|
+
// directory with no folders gets a single module called index which holds its files.
|
|
159
|
+
const groups = folders.length ? [...folders, ...rootFiles.map(file => ({
|
|
160
|
+
name: toIdentifier(_nodePath.default.basename(file).replace(/\.[cm]?tsx?$/, '')),
|
|
161
|
+
files: [file],
|
|
162
|
+
description: describeFile(file)
|
|
163
|
+
})).filter(group => !folders.some(folder => folder.name === group.name))] : [{
|
|
140
164
|
name: 'index',
|
|
141
165
|
path: absoluteSrc,
|
|
142
|
-
files:
|
|
166
|
+
files: rootFiles
|
|
143
167
|
}];
|
|
144
168
|
return groups.map(group => {
|
|
145
169
|
const lines = group.files.filter(file => !/^index\./.test(_nodePath.default.basename(file))).sort().flatMap(file => {
|
|
@@ -151,7 +175,7 @@ const writeDocEntries = (ts, srcDir, entryDir) => {
|
|
|
151
175
|
const fileName = _nodePath.default.basename(file).replace(/\.[cm]?tsx?$/, '');
|
|
152
176
|
return [...(hasDefault ? [`export { default as ${toIdentifier(fileName)} } from '${modulePath}'`] : []), ...(hasNamed ? [`export * from '${modulePath}'`] : [])];
|
|
153
177
|
});
|
|
154
|
-
const description = group.path ? describeFolder(group.path) : '';
|
|
178
|
+
const description = group.description ?? (group.path ? describeFolder(group.path) : '');
|
|
155
179
|
// TypeDoc takes the first comment of an entry file which has the @module tag as the description of the module
|
|
156
180
|
const moduleComment = description ? `/**\n${description.split('\n').map(line => ` * ${line}`.trimEnd()).join('\n')}\n * @module\n */\n\n` : '';
|
|
157
181
|
const entryPath = _nodePath.default.join(entryDir, `${group.name}.ts`);
|
package/dist/typeDocs.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
'use strict'
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, '__esModule', {
|
|
4
|
-
value: true
|
|
5
|
-
})
|
|
6
|
-
exports.typeDocs = void 0
|
|
7
|
-
const _typeDocsFor = require('./partials/typeDocsFor.js')
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', {
|
|
4
|
+
value: true
|
|
5
|
+
})
|
|
6
|
+
exports.typeDocs = void 0
|
|
7
|
+
const _typeDocsFor = require('./partials/typeDocsFor.js')
|
|
8
8
|
/**
|
|
9
9
|
* Generate the HTML documentation of a TypeScript project from its source, with the modules mirroring the source
|
|
10
10
|
* folders. Turn it on with docs.enabled, see {@link module:partials.typeDocsFor}.
|
|
11
11
|
* @memberOf module:js-build-tools
|
|
12
12
|
* @returns {Function}
|
|
13
|
-
*/
|
|
14
|
-
const typeDocs = exports.typeDocs = (0, _typeDocsFor.typeDocsFor)()
|
|
13
|
+
*/
|
|
14
|
+
const typeDocs = exports.typeDocs = (0, _typeDocsFor.typeDocsFor)()
|
package/functions/bundle.mjs
CHANGED
|
@@ -6,6 +6,11 @@ import source from 'vinyl-source-stream'
|
|
|
6
6
|
/**
|
|
7
7
|
* Starting at the distribution entry point, bundle all the files into a single file and store them in the specified output directory.
|
|
8
8
|
*
|
|
9
|
+
* browser.name does double duty: it names the output file (browser.name.js) and, via browserify's `standalone`
|
|
10
|
+
* option, is also the name the bundle's exports are exposed under - as a global when loaded with a bare <script>
|
|
11
|
+
* tag, or as the module when required via CommonJS/AMD. Without this, a bundle built from a real entry point (one
|
|
12
|
+
* that actually exports something) builds successfully but exposes nothing a consumer can reach.
|
|
13
|
+
*
|
|
9
14
|
* Two escape hatches from browser.config.json keep an unwanted dependency (or a dependency's dependency) out of the
|
|
10
15
|
* bundle: 'ignore' replaces it with an empty object (safe when your code never actually calls into it - for example
|
|
11
16
|
* a library's default option value you always override with your own) and 'exclude' leaves it out entirely (your
|
|
@@ -14,7 +19,7 @@ import source from 'vinyl-source-stream'
|
|
|
14
19
|
* @returns {stream.Stream}
|
|
15
20
|
*/
|
|
16
21
|
export const bundle = () => {
|
|
17
|
-
const bundler = browserify(gulpConfig.get('dist.main'))
|
|
22
|
+
const bundler = browserify(gulpConfig.get('dist.main'), { standalone: gulpConfig.get('browser.name') })
|
|
18
23
|
const ignore = gulpConfig.get('browser.ignore')
|
|
19
24
|
const exclude = gulpConfig.get('browser.exclude')
|
|
20
25
|
if (ignore && ignore.length) {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
|
+
import path from 'path'
|
|
2
3
|
import * as setUp from './test-helpers/setUp.mjs'
|
|
3
4
|
import { bundle } from './bundle.mjs'
|
|
4
5
|
import { countMatches } from 'test-filesystem'
|
|
@@ -66,6 +67,25 @@ describe('bundle', () => {
|
|
|
66
67
|
done()
|
|
67
68
|
})
|
|
68
69
|
})
|
|
70
|
+
|
|
71
|
+
test('exposes browser.name as the standalone export, reachable by a real consumer', done => {
|
|
72
|
+
const destPath = gulpConfig.get('browser.to')
|
|
73
|
+
const bundledFile = `${destPath}/${gulpConfig.get('browser.name')}.js`
|
|
74
|
+
expect.assertions(2)
|
|
75
|
+
bundle()
|
|
76
|
+
.on('finish', () => {
|
|
77
|
+
// A UMD bundle (browserify's `standalone` option) resolves to its CommonJS branch when
|
|
78
|
+
// required like this, and to a `window.<browser.name>` global when loaded via a bare
|
|
79
|
+
// <script> tag in a real browser - both paths hit the same exported value.
|
|
80
|
+
const resolved = path.resolve(bundledFile)
|
|
81
|
+
delete require.cache[resolved]
|
|
82
|
+
const loaded = require(resolved)
|
|
83
|
+
expect(typeof loaded.file1).toBe('function')
|
|
84
|
+
expect(typeof loaded.file2).toBe('function')
|
|
85
|
+
done()
|
|
86
|
+
})
|
|
87
|
+
.on('error', error => done(error))
|
|
88
|
+
})
|
|
69
89
|
})
|
|
70
90
|
|
|
71
91
|
describe('bundle ignore / exclude', () => {
|
|
@@ -79,7 +79,19 @@ export const describeExports = (ts, filePath) => {
|
|
|
79
79
|
*/
|
|
80
80
|
export const describeFolder = folderPath => {
|
|
81
81
|
const indexFile = ['index.ts', 'index.tsx', 'index.mts', 'index.cts'].map(name => path.join(folderPath, name)).find(file => fs.existsSync(file))
|
|
82
|
-
|
|
82
|
+
return indexFile ? describeFile(indexFile) : ''
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* The description of a source file for its module: its first doc comment without the tags (@module, @file, ...), when
|
|
87
|
+
* that comment is a header (it is followed by an import or export, so it does not document a declaration itself), or
|
|
88
|
+
* an empty string.
|
|
89
|
+
* @memberOf module:partials
|
|
90
|
+
* @param {string} filePath
|
|
91
|
+
* @returns {string}
|
|
92
|
+
*/
|
|
93
|
+
export const describeFile = filePath => {
|
|
94
|
+
const comment = fs.readFileSync(filePath, 'utf8').match(/^\s*\/\*\*([\s\S]*?)\*\/\s*(import\b|export\s+(\*|\{[^}]*\}\s+from)|$)/)
|
|
83
95
|
if (!comment) {
|
|
84
96
|
return ''
|
|
85
97
|
}
|
|
@@ -93,7 +105,9 @@ export const describeFolder = folderPath => {
|
|
|
93
105
|
* entry file, so the modules of the documentation mirror the folders. The default export of each source file is
|
|
94
106
|
* re-exported under the name of the file (the source files hold one function each), and anything else a file exports
|
|
95
107
|
* is re-exported as it is (that is where the types.ts files go). Index files (the barrels), tests and declaration
|
|
96
|
-
* files are left out, but the first doc comment of a folder's index file becomes the description of its module.
|
|
108
|
+
* files are left out, but the first doc comment of a folder's index file becomes the description of its module.
|
|
109
|
+
* A file which sits beside the folders (not an index or main file) is a module of its own, described by its header
|
|
110
|
+
* comment. A source directory with no folders gets a single entry called index.
|
|
97
111
|
* @memberOf module:partials
|
|
98
112
|
* @param {Object} ts - The TypeScript compiler API.
|
|
99
113
|
* @param {string} srcDir - The directory holding the TypeScript source.
|
|
@@ -107,9 +121,19 @@ export const writeDocEntries = (ts, srcDir, entryDir) => {
|
|
|
107
121
|
.filter(entry => entry.isDirectory() && entry.name !== 'node_modules')
|
|
108
122
|
.map(entry => ({ name: entry.name, path: path.join(absoluteSrc, entry.name), files: listSources(path.join(absoluteSrc, entry.name)) }))
|
|
109
123
|
.filter(folder => folder.files.length)
|
|
124
|
+
const rootFiles = fs.readdirSync(absoluteSrc, { withFileTypes: true })
|
|
125
|
+
.filter(entry => entry.isFile() && isSource(entry.name) && !/^(index|main)\./.test(entry.name))
|
|
126
|
+
.map(entry => path.join(absoluteSrc, entry.name))
|
|
127
|
+
// Folders make modules, and so do the files which sit beside them (except the barrel: index and main). A source
|
|
128
|
+
// directory with no folders gets a single module called index which holds its files.
|
|
110
129
|
const groups = folders.length
|
|
111
|
-
?
|
|
112
|
-
|
|
130
|
+
? [
|
|
131
|
+
...folders,
|
|
132
|
+
...rootFiles
|
|
133
|
+
.map(file => ({ name: toIdentifier(path.basename(file).replace(/\.[cm]?tsx?$/, '')), files: [file], description: describeFile(file) }))
|
|
134
|
+
.filter(group => !folders.some(folder => folder.name === group.name))
|
|
135
|
+
]
|
|
136
|
+
: [{ name: 'index', path: absoluteSrc, files: rootFiles }]
|
|
113
137
|
return groups.map(group => {
|
|
114
138
|
const lines = group.files
|
|
115
139
|
.filter(file => !/^index\./.test(path.basename(file)))
|
|
@@ -123,7 +147,7 @@ export const writeDocEntries = (ts, srcDir, entryDir) => {
|
|
|
123
147
|
...(hasNamed ? [`export * from '${modulePath}'`] : [])
|
|
124
148
|
]
|
|
125
149
|
})
|
|
126
|
-
const description = group.path ? describeFolder(group.path) : ''
|
|
150
|
+
const description = group.description ?? (group.path ? describeFolder(group.path) : '')
|
|
127
151
|
// TypeDoc takes the first comment of an entry file which has the @module tag as the description of the module
|
|
128
152
|
const moduleComment = description ? `/**\n${description.split('\n').map(line => ` * ${line}`.trimEnd()).join('\n')}\n * @module\n */\n\n` : ''
|
|
129
153
|
const entryPath = path.join(entryDir, `${group.name}.ts`)
|
|
@@ -2,7 +2,7 @@ import fs from 'fs'
|
|
|
2
2
|
import path from 'node:path'
|
|
3
3
|
import ts from 'typescript'
|
|
4
4
|
import * as setUp from '../test-helpers/setUp.mjs'
|
|
5
|
-
import { describeExports, describeFolder, loadTypeDoc, typeDocsFor, writeDocEntries } from './typeDocsFor.mjs'
|
|
5
|
+
import { describeExports, describeFile, describeFolder, loadTypeDoc, typeDocsFor, writeDocEntries } from './typeDocsFor.mjs'
|
|
6
6
|
|
|
7
7
|
setUp.setDefaults('test-type-docs-for')
|
|
8
8
|
const gulpConfig = setUp.gulpConfig
|
|
@@ -66,6 +66,18 @@ describe('describeFolder', () => {
|
|
|
66
66
|
})
|
|
67
67
|
})
|
|
68
68
|
|
|
69
|
+
describe('describeFile', () => {
|
|
70
|
+
test('is the header comment of a file, without its tags', () => {
|
|
71
|
+
write(`${gulpConfig.get('srcPath')}/header.ts`, "/**\n * Simulate what a user does.\n * @module simulate\n */\nimport a from './a'\nexport default a\n")
|
|
72
|
+
expect(describeFile(`${gulpConfig.get('srcPath')}/header.ts`)).toBe('Simulate what a user does.')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('is empty when the first comment documents a declaration', () => {
|
|
76
|
+
write(`${gulpConfig.get('srcPath')}/declaration.ts`, '/**\n * Add two numbers.\n */\nconst add = (a: number, b: number) => a + b\nexport default add\n')
|
|
77
|
+
expect(describeFile(`${gulpConfig.get('srcPath')}/declaration.ts`)).toBe('')
|
|
78
|
+
})
|
|
79
|
+
})
|
|
80
|
+
|
|
69
81
|
describe('writeDocEntries', () => {
|
|
70
82
|
test('writes one entry file for each folder which has source', () => {
|
|
71
83
|
const entryDir = `${gulpConfig.get('srcPath')}/../entries`
|
|
@@ -104,6 +116,19 @@ describe('writeDocEntries', () => {
|
|
|
104
116
|
expect(fs.readFileSync(`${entryDir}/line.ts`, 'utf8').startsWith('export')).toBe(true)
|
|
105
117
|
})
|
|
106
118
|
|
|
119
|
+
test('makes a module of a file which sits beside the folders, but not of the barrel files', () => {
|
|
120
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
121
|
+
write(`${srcPath}/simulate.ts`, "/**\n * Simulate what a user does.\n */\nimport add from './point/add'\nexport const click = () => add(1, 2)\nexport default { click }\n")
|
|
122
|
+
write(`${srcPath}/simulate.test.ts`, "test('x', () => {})\n")
|
|
123
|
+
const entryDir = `${srcPath}/../entries`
|
|
124
|
+
const entries = writeDocEntries(ts, srcPath, entryDir)
|
|
125
|
+
expect(entries.map(entry => path.basename(entry)).sort()).toEqual(['line.ts', 'point.ts', 'simulate.ts'])
|
|
126
|
+
const absoluteSrc = path.resolve(srcPath).split(path.sep).join('/')
|
|
127
|
+
expect(fs.readFileSync(`${entryDir}/simulate.ts`, 'utf8')).toBe(
|
|
128
|
+
`/**\n * Simulate what a user does.\n * @module\n */\n\nexport { default as simulate } from '${absoluteSrc}/simulate'\nexport * from '${absoluteSrc}/simulate'\n`
|
|
129
|
+
)
|
|
130
|
+
})
|
|
131
|
+
|
|
107
132
|
test('makes one entry called index when the source has no folders', () => {
|
|
108
133
|
const flat = `${gulpConfig.get('srcPath')}/../flat`
|
|
109
134
|
write(`${flat}/one.ts`, 'export default 1\n')
|