js-build-tools 6.3.1 → 6.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/README.md +10 -3
  2. package/dist/lint.js +17 -0
  3. package/dist/lint.min.js +1 -0
  4. package/dist/partials/imagesFor.js +42 -43
  5. package/dist/partials/jsdocDocsFor.js +128 -128
  6. package/dist/partials/lintSource.js +52 -0
  7. package/dist/partials/loadPeer.js +71 -70
  8. package/dist/partials/minifyFor.js +16 -16
  9. package/dist/partials/neostandardLint.js +134 -123
  10. package/dist/partials.js +176 -169
  11. package/dist/partials.min.js +1 -1
  12. package/dist/sourceLint.js +11 -27
  13. package/dist/sourceLint.min.js +1 -1
  14. package/dist/test-helpers/isolateGulpCache.js +25 -0
  15. package/dist/utilities/dotGet.js +46 -46
  16. package/dist/utilities/dotNotate.js +48 -48
  17. package/dist/utilities/dotSet.js +37 -37
  18. package/functions/build.test.mjs +17 -7
  19. package/functions/bundle.test.mjs +0 -1
  20. package/functions/images.test.mjs +4 -1
  21. package/functions/lint.mjs +9 -0
  22. package/functions/partials/addToReadme.test.mjs +2 -1
  23. package/functions/partials/imagesFor.mjs +0 -1
  24. package/functions/partials/imagesFor.test.mjs +5 -2
  25. package/functions/partials/lintSource.mjs +41 -0
  26. package/functions/partials/loadPeer.mjs +1 -0
  27. package/functions/partials/loadPlaywright.test.mjs +1 -2
  28. package/functions/partials/minifyFor.mjs +1 -1
  29. package/functions/partials/neostandardLint.mjs +14 -4
  30. package/functions/partials/neostandardLint.test.mjs +14 -0
  31. package/functions/partials/runOnChange.test.mjs +5 -4
  32. package/functions/partials/tsFor.test.mjs +1 -0
  33. package/functions/partials.mjs +1 -0
  34. package/functions/partials.test.mjs +1 -1
  35. package/functions/sourceLint.mjs +4 -15
  36. package/functions/sourceLint.test.mjs +69 -0
  37. package/functions/test-helpers/isolateGulpCache.mjs +16 -0
  38. package/functions/test-helpers/setUp.mjs +7 -7
  39. package/functions/testFull.test.mjs +1 -1
  40. package/functions/testQuick.test.mjs +1 -1
  41. package/functions/utilities/convertMjsFilesForDocs.test.mjs +1 -0
  42. package/functions/utilities/dotGet.mjs +2 -2
  43. package/functions/utilities/dotNotate.mjs +2 -2
  44. package/functions/utilities/dotNotate.test.mjs +7 -0
  45. package/functions/utilities/dotSet.mjs +1 -1
  46. package/gulpfile.base.mjs +1 -0
  47. package/package.json +12 -2
@@ -1,34 +1,35 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.requirePeer = exports.importPeer = exports.importModule = void 0;
7
- require("core-js/modules/es.array.includes.js");
8
- var _nodeModule = require("node:module");
9
- var _nodePath = _interopRequireDefault(require("node:path"));
10
- var _nodeUrl = require("node:url");
11
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
- // Several dependencies ship ESM-only (standard, gulp-ts-compile, typedoc), but this package also publishes a CommonJS
13
- // build (dist/*.js) whose babel transform would turn even a dynamic import() into a require() that cannot load an ES
14
- // module. Hiding the import() inside a Function constructor keeps it a genuine dynamic import that works from either
15
- // build, because babel cannot see (and so cannot rewrite) an import expression which only exists as a runtime string.
16
- const dynamicImport = new Function('specifier', 'return import(specifier)');
17
-
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.requirePeer = exports.importPeer = exports.importModule = void 0;
7
+ require("core-js/modules/es.array.includes.js");
8
+ var _nodeModule = require("node:module");
9
+ var _nodePath = _interopRequireDefault(require("node:path"));
10
+ var _nodeUrl = require("node:url");
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ // Several dependencies ship ESM-only (standard, gulp-ts-compile, typedoc), but this package also publishes a CommonJS
13
+ // build (dist/*.js) whose babel transform would turn even a dynamic import() into a require() that cannot load an ES
14
+ // module. Hiding the import() inside a Function constructor keeps it a genuine dynamic import that works from either
15
+ // build, because babel cannot see (and so cannot rewrite) an import expression which only exists as a runtime string.
16
+ // eslint-disable-next-line no-new-func -- deliberate, see above
17
+ const dynamicImport = new Function('specifier', 'return import(specifier)');
18
+
18
19
  /**
19
20
  * Import an ES module (or any module) with a real dynamic import(), whichever build (ESM or CommonJS) this runs from.
20
21
  * @memberOf module:partials
21
22
  * @param {string} specifier - The package name, or the URL of a file.
22
23
  * @returns {Promise<Object>} The module namespace.
23
- */
24
- const importModule = specifier => dynamicImport(specifier);
25
- exports.importModule = importModule;
26
- const isMissing = (error, name) => error.code === 'MODULE_NOT_FOUND' && error.message.includes(`'${name}'`);
27
- const notInstalled = (name, {
28
- task,
29
- installHint
30
- }) => new Error(`The ${task} task needs the optional peer dependency ${name}, which is not installed. ${installHint}`);
31
-
24
+ */
25
+ const importModule = specifier => dynamicImport(specifier);
26
+ exports.importModule = importModule;
27
+ const isMissing = (error, name) => error.code === 'MODULE_NOT_FOUND' && error.message.includes(`'${name}'`);
28
+ const notInstalled = (name, {
29
+ task,
30
+ installHint
31
+ }) => new Error(`The ${task} task needs the optional peer dependency ${name}, which is not installed. ${installHint}`);
32
+
32
33
  /**
33
34
  * Load an optional peer dependency (one which is only needed once a task runs, so projects which never use that task
34
35
  * do not have to install it) with require(), from the project being built rather than from this package. When it is
@@ -42,29 +43,29 @@ const notInstalled = (name, {
42
43
  * @param {string} [options.projectPath=process.cwd()] - The folder of the project (which has the package.json) being built.
43
44
  * @returns {*} Whatever the package exports.
44
45
  * @throws {Error} With install instructions when the package is not installed.
45
- */
46
- const requirePeer = (name, {
47
- task,
48
- installHint,
49
- esmOnlyMessage,
50
- projectPath = process.cwd()
51
- }) => {
52
- try {
53
- return (0, _nodeModule.createRequire)(_nodePath.default.join(projectPath, 'package.json'))(name);
54
- } catch (error) {
55
- if (isMissing(error, name)) {
56
- throw notInstalled(name, {
57
- task,
58
- installHint
59
- });
60
- }
61
- if (error.code === 'ERR_REQUIRE_ESM' && esmOnlyMessage) {
62
- throw new Error(esmOnlyMessage);
63
- }
64
- throw error;
65
- }
66
- };
67
-
46
+ */
47
+ const requirePeer = (name, {
48
+ task,
49
+ installHint,
50
+ esmOnlyMessage,
51
+ projectPath = process.cwd()
52
+ }) => {
53
+ try {
54
+ return (0, _nodeModule.createRequire)(_nodePath.default.join(projectPath, 'package.json'))(name);
55
+ } catch (error) {
56
+ if (isMissing(error, name)) {
57
+ throw notInstalled(name, {
58
+ task,
59
+ installHint
60
+ });
61
+ }
62
+ if (error.code === 'ERR_REQUIRE_ESM' && esmOnlyMessage) {
63
+ throw new Error(esmOnlyMessage);
64
+ }
65
+ throw error;
66
+ }
67
+ };
68
+
68
69
  /**
69
70
  * Import an optional peer dependency which ships ESM-only, from the project being built. See {@link requirePeer}.
70
71
  * @memberOf module:partials
@@ -75,25 +76,25 @@ const requirePeer = (name, {
75
76
  * @param {string} [options.projectPath=process.cwd()] - The folder of the project (which has the package.json) being built.
76
77
  * @returns {Promise<Object>} The module namespace.
77
78
  * @throws {Error} With install instructions when the package is not installed.
78
- */
79
- exports.requirePeer = requirePeer;
80
- const importPeer = async (name, {
81
- task,
82
- installHint,
83
- projectPath = process.cwd()
84
- }) => {
85
- let resolved;
86
- try {
87
- resolved = (0, _nodeModule.createRequire)(_nodePath.default.join(projectPath, 'package.json')).resolve(name);
88
- } catch (error) {
89
- if (isMissing(error, name)) {
90
- throw notInstalled(name, {
91
- task,
92
- installHint
93
- });
94
- }
95
- throw error;
96
- }
97
- return importModule((0, _nodeUrl.pathToFileURL)(resolved).href);
98
- };
79
+ */
80
+ exports.requirePeer = requirePeer;
81
+ const importPeer = async (name, {
82
+ task,
83
+ installHint,
84
+ projectPath = process.cwd()
85
+ }) => {
86
+ let resolved;
87
+ try {
88
+ resolved = (0, _nodeModule.createRequire)(_nodePath.default.join(projectPath, 'package.json')).resolve(name);
89
+ } catch (error) {
90
+ if (isMissing(error, name)) {
91
+ throw notInstalled(name, {
92
+ task,
93
+ installHint
94
+ });
95
+ }
96
+ throw error;
97
+ }
98
+ return importModule((0, _nodeUrl.pathToFileURL)(resolved).href);
99
+ };
99
100
  exports.importPeer = importPeer;
@@ -1,21 +1,21 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.minifyFor = void 0;
7
- var _gulp = require("gulp");
8
- var _gulpUglifyEs = _interopRequireDefault(require("gulp-uglify-es"));
9
- var _gulpRename = _interopRequireDefault(require("gulp-rename"));
10
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
- const uglify = _gulpUglifyEs.default.hasOwnProperty('default') ? _gulpUglifyEs.default.default : _gulpUglifyEs.default;
12
-
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.minifyFor = void 0;
7
+ var _gulp = require("gulp");
8
+ var _gulpUglifyEs = _interopRequireDefault(require("gulp-uglify-es"));
9
+ var _gulpRename = _interopRequireDefault(require("gulp-rename"));
10
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
11
+ const uglify = Object.hasOwn(_gulpUglifyEs.default, 'default') ? _gulpUglifyEs.default.default : _gulpUglifyEs.default;
12
+
13
13
  /**
14
14
  * Minify files and rename the output with '.min' extension.
15
15
  * @memberOf module:partials
16
16
  * @returns {*}
17
- */
18
- const minifyFor = (srcSearch, destination) => (0, _gulp.src)(srcSearch).pipe(uglify()).pipe((0, _gulpRename.default)({
19
- extname: '.min.js'
20
- })).pipe((0, _gulp.dest)(destination));
17
+ */
18
+ const minifyFor = (srcSearch, destination) => (0, _gulp.src)(srcSearch).pipe(uglify()).pipe((0, _gulpRename.default)({
19
+ extname: '.min.js'
20
+ })).pipe((0, _gulp.dest)(destination));
21
21
  exports.minifyFor = minifyFor;
@@ -1,36 +1,36 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.neostandardLint = void 0;
7
- require("core-js/modules/esnext.iterator.constructor.js");
8
- require("core-js/modules/esnext.iterator.for-each.js");
9
- var _nodeFs = _interopRequireDefault(require("node:fs"));
10
- var _nodePath = _interopRequireDefault(require("node:path"));
11
- var _through = _interopRequireDefault(require("through2"));
12
- var _eslint = require("eslint");
13
- var _loadPeer = require("./loadPeer.js");
14
- function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
- // neostandard (js-build-tools' chosen style - a maintained, TypeScript-aware successor to `standard`, see
16
- // https://github.com/neostandard/neostandard) ships ESM-only, see importModule for how it is imported.
17
- const importNeostandard = () => (0, _loadPeer.importModule)('neostandard');
18
-
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.neostandardLint = void 0;
7
+ require("core-js/modules/esnext.iterator.constructor.js");
8
+ require("core-js/modules/esnext.iterator.for-each.js");
9
+ var _nodeFs = _interopRequireDefault(require("node:fs"));
10
+ var _nodePath = _interopRequireDefault(require("node:path"));
11
+ var _through = _interopRequireDefault(require("through2"));
12
+ var _eslint = require("eslint");
13
+ var _loadPeer = require("./loadPeer.js");
14
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
15
+ // neostandard (js-build-tools' chosen style - a maintained, TypeScript-aware successor to `standard`, see
16
+ // https://github.com/neostandard/neostandard) ships ESM-only, see importModule for how it is imported.
17
+ const importNeostandard = () => (0, _loadPeer.importModule)('neostandard');
18
+
19
19
  /**
20
20
  * Read the `env` a project already declared for Standard (the `standard` field in its package.json), so a project
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
24
  * @private
25
- */
26
- const readEnv = cwd => {
27
- try {
28
- return JSON.parse(_nodeFs.default.readFileSync(_nodePath.default.join(cwd, 'package.json'), 'utf8')).standard?.env ?? [];
29
- } catch {
30
- return [];
31
- }
32
- };
33
-
25
+ */
26
+ const readEnv = cwd => {
27
+ try {
28
+ return JSON.parse(_nodeFs.default.readFileSync(_nodePath.default.join(cwd, 'package.json'), 'utf8')).standard?.env ?? [];
29
+ } catch {
30
+ return [];
31
+ }
32
+ };
33
+
34
34
  /**
35
35
  * Build an ESLint instance configured with neostandard, honoring the project's own package.json `standard.env`,
36
36
  * plus an optional layer of rule overrides (see gulp.config.mjs's `lint.rules`) for a rule that is wrong for this
@@ -45,59 +45,60 @@ const readEnv = cwd => {
45
45
  * @param {Object<string, *>} [options.rules={}]
46
46
  * @returns {Promise<ESLint>} eslint's ESLint instance
47
47
  * @private
48
- */
49
- const buildEslint = async ({
50
- cwd,
51
- ts,
52
- fix,
53
- rules = {}
54
- }) => {
55
- const {
56
- neostandard,
57
- defaultFilePatterns
58
- } = await importNeostandard();
59
- const baseConfig = neostandard({
60
- ts,
61
- env: readEnv(cwd)
62
- });
63
- if (Object.keys(rules).length) {
64
- baseConfig.push({
65
- files: defaultFilePatterns.all,
66
- rules
67
- });
68
- }
69
- return new _eslint.ESLint({
70
- cwd,
71
- fix,
72
- overrideConfigFile: true,
73
- baseConfig
74
- });
75
- };
76
-
48
+ */
49
+ const buildEslint = async ({
50
+ cwd,
51
+ ts,
52
+ fix,
53
+ rules = {}
54
+ }) => {
55
+ const {
56
+ neostandard,
57
+ defaultFilePatterns
58
+ } = await importNeostandard();
59
+ const baseConfig = neostandard({
60
+ ts,
61
+ env: readEnv(cwd)
62
+ });
63
+ if (Object.keys(rules).length) {
64
+ baseConfig.push({
65
+ files: defaultFilePatterns.all,
66
+ rules
67
+ });
68
+ }
69
+ return new _eslint.ESLint({
70
+ cwd,
71
+ fix,
72
+ overrideConfigFile: true,
73
+ baseConfig
74
+ });
75
+ };
76
+
77
77
  /**
78
78
  * Print a file's lint messages, if it has any.
79
79
  * @memberOf module:partials
80
80
  * @param {Vinyl} file
81
81
  * @param {{messages: Array<{line: number, column: number, message: string}>, errorCount: number, warningCount: number}} result
82
82
  * @returns {undefined}
83
- */
84
- const printFileReport = (file, result) => {
85
- if (!result.messages.length) {
86
- return;
87
- }
88
- console.log(_nodePath.default.relative(file.cwd, file.path));
89
- result.messages.forEach(({
90
- line,
91
- column,
92
- message
93
- }) => console.log(`line ${line}:${column}\t${message}`));
94
- console.log(`✖ ${result.errorCount} error\t⚠ ${result.warningCount} warning\n`);
95
- };
96
-
83
+ */
84
+ const printFileReport = (file, result) => {
85
+ if (!result.messages.length) {
86
+ return;
87
+ }
88
+ console.log(_nodePath.default.relative(file.cwd, file.path));
89
+ result.messages.forEach(({
90
+ line,
91
+ column,
92
+ message
93
+ }) => console.log(`line ${line}:${column}\t${message}`));
94
+ console.log(`✖ ${result.errorCount} error\t⚠ ${result.warningCount} warning\n`);
95
+ };
96
+
97
97
  /**
98
98
  * Lint every file streaming through with neostandard and, unless `fix` is false, apply the automatic fixes to the
99
99
  * file's contents so a following `dest()` writes the fixed version. Remaining problems are printed along with a
100
- * summary once the stream ends; they never fail the build.
100
+ * summary once the stream ends; they only fail the stream when `failOnError` is set (the standalone `lint` task),
101
+ * never during `build`.
101
102
  *
102
103
  * One ESLint instance is built from the first file's own cwd and reused for the rest of the stream, since every
103
104
  * file in a given lint pass shares the same project (and so the same config).
@@ -107,59 +108,69 @@ const printFileReport = (file, result) => {
107
108
  * @param {boolean} [options.ts=false] - Lint `.ts` files too, with type-aware rules (see neostandard's `ts` option).
108
109
  * @param {Object<string, *>} [options.rules={}] - ESLint rule overrides layered on top of neostandard's own rules
109
110
  * (see gulp.config.mjs's `lint.rules`).
111
+ * @param {boolean} [options.failOnError=false] - Emit an error once the stream ends if any lint errors remain after
112
+ * fixing, so a command-line run exits non-zero.
110
113
  * @param {function(Object): Promise<{lintText: Function}>} [loadEslint] - Resolves an ESLint-shaped linter. Real
111
114
  * callers should never need to pass this - it exists so tests can supply a stand-in, since this project's
112
115
  * CommonJS-transform-based Jest setup cannot execute a real dynamic import() of neostandard (ESM-only).
113
- * @returns {stream.Transform}
114
- */
115
- const neostandardLint = ({
116
- fix = true,
117
- ts = false,
118
- rules = {}
119
- } = {}, loadEslint = buildEslint) => {
120
- const totals = {
121
- errors: 0,
122
- warnings: 0
123
- };
124
- let eslintPromise = null;
125
- return _through.default.obj(function (file, enc, callback) {
126
- if (file.isNull()) {
127
- callback(null, file);
128
- return;
129
- }
130
- if (file.isStream()) {
131
- callback(new Error('neostandardLint: streaming file contents are not supported.'));
132
- return;
133
- }
134
- if (!eslintPromise) {
135
- eslintPromise = loadEslint({
136
- cwd: file.cwd,
137
- ts,
138
- fix,
139
- rules
140
- });
141
- }
142
- eslintPromise.then(eslint => eslint.lintText(file.contents.toString(), {
143
- filePath: file.path
144
- })).then(results => {
145
- // No result at all means the file is ignored by the project's ESLint configuration.
146
- const [result] = results;
147
- if (result) {
148
- if (typeof result.output === 'string') {
149
- file.contents = Buffer.from(result.output);
150
- }
151
- totals.errors += result.errorCount;
152
- totals.warnings += result.warningCount;
153
- printFileReport(file, result);
154
- }
155
- callback(null, file);
156
- }, callback);
157
- }, function (callback) {
158
- console.log('neostandard linter results');
159
- console.log('======================================');
160
- console.log(`✖ Errors total: ${totals.errors}`);
161
- console.log(`⚠ Warnings total: ${totals.warnings}\n`);
162
- callback();
163
- });
164
- };
116
+ * @returns {stream.Transform} With a `totals` property ({errors, warnings}), complete once the stream ends.
117
+ */
118
+ const neostandardLint = ({
119
+ fix = true,
120
+ ts = false,
121
+ rules = {},
122
+ failOnError = false
123
+ } = {}, loadEslint = buildEslint) => {
124
+ const totals = {
125
+ errors: 0,
126
+ warnings: 0
127
+ };
128
+ let eslintPromise = null;
129
+ const linter = _through.default.obj(function (file, enc, callback) {
130
+ if (file.isNull()) {
131
+ callback(null, file);
132
+ return;
133
+ }
134
+ if (file.isStream()) {
135
+ callback(new Error('neostandardLint: streaming file contents are not supported.'));
136
+ return;
137
+ }
138
+ if (!eslintPromise) {
139
+ eslintPromise = loadEslint({
140
+ cwd: file.cwd,
141
+ ts,
142
+ fix,
143
+ rules
144
+ });
145
+ }
146
+ eslintPromise.then(eslint => eslint.lintText(file.contents.toString(), {
147
+ filePath: file.path
148
+ })).then(results => {
149
+ // No result at all means the file is ignored by the project's ESLint configuration.
150
+ const [result] = results;
151
+ if (result) {
152
+ if (typeof result.output === 'string') {
153
+ file.contents = Buffer.from(result.output);
154
+ }
155
+ totals.errors += result.errorCount;
156
+ totals.warnings += result.warningCount;
157
+ printFileReport(file, result);
158
+ }
159
+ callback(null, file);
160
+ }, callback);
161
+ }, function (callback) {
162
+ console.log('neostandard linter results');
163
+ console.log('======================================');
164
+ console.log(`✖ Errors total: ${totals.errors}`);
165
+ console.log(`⚠ Warnings total: ${totals.warnings}\n`);
166
+ if (failOnError && totals.errors) {
167
+ callback(new Error(`neostandard found ${totals.errors} lint error(s) that could not be fixed automatically.`));
168
+ return;
169
+ }
170
+ callback();
171
+ });
172
+ // Read by lintSource, which can only fail once the fixed files have been written, after this stream has ended.
173
+ linter.totals = totals;
174
+ return linter;
175
+ };
165
176
  exports.neostandardLint = neostandardLint;