js-build-tools 6.3.0 → 6.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 +10 -3
- package/dist/lint.js +17 -0
- package/dist/lint.min.js +1 -0
- package/dist/partials/imagesFor.js +42 -43
- package/dist/partials/jsdocDocsFor.js +5 -3
- package/dist/partials/lintSource.js +41 -0
- package/dist/partials/loadPeer.js +71 -70
- package/dist/partials/minifyFor.js +16 -16
- package/dist/partials/neostandardLint.js +130 -122
- package/dist/partials.js +176 -169
- package/dist/partials.min.js +1 -1
- package/dist/sourceLint.js +11 -27
- package/dist/sourceLint.min.js +1 -1
- package/dist/test-helpers/isolateGulpCache.js +25 -0
- package/dist/utilities/dotGet.js +46 -46
- package/dist/utilities/dotNotate.js +48 -48
- package/dist/utilities/dotSet.js +37 -37
- package/functions/build.test.mjs +17 -7
- package/functions/bundle.test.mjs +0 -1
- package/functions/images.test.mjs +4 -1
- package/functions/lint.mjs +9 -0
- package/functions/partials/addToReadme.test.mjs +2 -1
- package/functions/partials/imagesFor.mjs +0 -1
- package/functions/partials/imagesFor.test.mjs +5 -2
- package/functions/partials/jsdocDocsFor.mjs +11 -3
- package/functions/partials/jsdocDocsFor.test.mjs +5 -2
- package/functions/partials/lintSource.mjs +27 -0
- package/functions/partials/loadPeer.mjs +1 -0
- package/functions/partials/loadPlaywright.test.mjs +1 -2
- package/functions/partials/minifyFor.mjs +1 -1
- package/functions/partials/neostandardLint.mjs +9 -2
- package/functions/partials/neostandardLint.test.mjs +14 -0
- package/functions/partials/runOnChange.test.mjs +5 -4
- package/functions/partials/tsFor.test.mjs +1 -0
- package/functions/partials.mjs +1 -0
- package/functions/partials.test.mjs +1 -1
- package/functions/sourceLint.mjs +4 -15
- package/functions/sourceLint.test.mjs +49 -0
- package/functions/test-helpers/isolateGulpCache.mjs +16 -0
- package/functions/test-helpers/setUp.mjs +7 -7
- package/functions/testFull.test.mjs +1 -1
- package/functions/testQuick.test.mjs +1 -1
- package/functions/utilities/convertMjsFilesForDocs.test.mjs +1 -0
- package/functions/utilities/dotGet.mjs +2 -2
- package/functions/utilities/dotNotate.mjs +2 -2
- package/functions/utilities/dotNotate.test.mjs +7 -0
- package/functions/utilities/dotSet.mjs +1 -1
- package/gulpfile.base.mjs +1 -0
- package/package.json +12 -2
|
@@ -92,14 +92,15 @@ describe('jsdocDocsFor', () => {
|
|
|
92
92
|
expect(['a.test.mjs', 'a.min.js', 'a.min.mjs', 'dir/_private.mjs', 'a.ts'].filter(documented)).toEqual([])
|
|
93
93
|
})
|
|
94
94
|
|
|
95
|
-
test('passes docs.title to the theme as a link to the home page of the docs, and leaves it out when unset', async () => {
|
|
95
|
+
test('passes docs.title to the theme as a link to the home page of the docs and as its page title, and leaves it out when unset', async () => {
|
|
96
96
|
gulpConfig.set('docs.enabled', true)
|
|
97
97
|
const srcPath = gulpConfig.get('srcPath')
|
|
98
98
|
const calls = {}
|
|
99
99
|
gulpConfig.set('docs.title', 'Tom & Jerry <Tools>')
|
|
100
100
|
await jsdocDocsFor(srcPath, `${srcPath}/../docs`, fakeRunJsdoc(calls))()
|
|
101
101
|
expect(calls.config.opts.theme_opts).toEqual({
|
|
102
|
-
title: '<a href="index.html" class="sidebar-title sidebar-title-anchor">Tom & Jerry <Tools></a>'
|
|
102
|
+
title: '<a href="index.html" class="sidebar-title sidebar-title-anchor">Tom & Jerry <Tools></a>',
|
|
103
|
+
homepageTitle: 'Tom & Jerry <Tools>'
|
|
103
104
|
})
|
|
104
105
|
|
|
105
106
|
gulpConfig.set('docs.title', '')
|
|
@@ -139,11 +140,13 @@ describe('jsdocDocsFor', () => {
|
|
|
139
140
|
describe('jsdocDocsFor, end to end with the real jsdoc CLI and clean-jsdoc-theme', () => {
|
|
140
141
|
test('produces a real browsable HTML page from real JSDoc comments', async () => {
|
|
141
142
|
gulpConfig.set('docs.enabled', true)
|
|
143
|
+
gulpConfig.set('docs.title', 'Tom & Jerry')
|
|
142
144
|
const outPath = `${gulpConfig.get('srcPath')}/../docs`
|
|
143
145
|
await jsdocDocsFor(gulpConfig.get('srcPath'), outPath)()
|
|
144
146
|
// clean-jsdoc-theme nests its real output under its own route folders (global/, source/...), not flat at
|
|
145
147
|
// outPath's own root - confirmed by actually running it, not assumed from the classic jsdoc template shape.
|
|
146
148
|
const files = fs.readdirSync(outPath, { recursive: true })
|
|
147
149
|
expect(files.some(file => file.endsWith('.html'))).toBe(true)
|
|
150
|
+
expect(fs.readFileSync(`${outPath}/index.html`, 'utf8')).toMatch(/<title>\s*Tom & Jerry\s*<\/title>/)
|
|
148
151
|
}, 30000)
|
|
149
152
|
})
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import * as gulpConfig from '../../gulp.config.mjs'
|
|
2
|
+
import { dest, src } from 'gulp'
|
|
3
|
+
import { neostandardLint } from './neostandardLint.mjs'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Lint the project's source (srcPath: .js, .mjs and .cjs, plus .ts when typescript.enabled) with neostandard and
|
|
7
|
+
* write the automatic fixes back in place. Shared by the sourceLint (build) and lint (standalone) tasks.
|
|
8
|
+
* @memberOf module:partials
|
|
9
|
+
* @param {Object} [options={}]
|
|
10
|
+
* @param {boolean} [options.failOnError=false] - Fail once linting finishes if any errors could not be fixed.
|
|
11
|
+
* @returns {stream.Stream}
|
|
12
|
+
*/
|
|
13
|
+
export const lintSource = ({ failOnError = false } = {}) => {
|
|
14
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
15
|
+
const ts = gulpConfig.get('typescript.enabled')
|
|
16
|
+
const patterns = [`${srcPath}/**/*.{js,mjs,cjs}`]
|
|
17
|
+
if (ts) {
|
|
18
|
+
patterns.push(`${srcPath}/**/*.ts`)
|
|
19
|
+
}
|
|
20
|
+
const linter = neostandardLint({ fix: true, ts, rules: gulpConfig.get('lint.rules'), failOnError })
|
|
21
|
+
const written = src(patterns)
|
|
22
|
+
.pipe(linter)
|
|
23
|
+
.pipe(dest(srcPath))
|
|
24
|
+
// pipe() does not forward errors, and gulp only watches the returned stream, so pass the linter's failure along.
|
|
25
|
+
linter.on('error', error => written.emit('error', error))
|
|
26
|
+
return written
|
|
27
|
+
}
|
|
@@ -6,6 +6,7 @@ import { pathToFileURL } from 'node:url'
|
|
|
6
6
|
// build (dist/*.js) whose babel transform would turn even a dynamic import() into a require() that cannot load an ES
|
|
7
7
|
// module. Hiding the import() inside a Function constructor keeps it a genuine dynamic import that works from either
|
|
8
8
|
// build, because babel cannot see (and so cannot rewrite) an import expression which only exists as a runtime string.
|
|
9
|
+
// eslint-disable-next-line no-new-func -- deliberate, see above
|
|
9
10
|
const dynamicImport = new Function('specifier', 'return import(specifier)')
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import fs from 'fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
2
|
import * as setUp from '../test-helpers/setUp.mjs'
|
|
4
3
|
import { loadPlaywright, launchBrowser } from './loadPlaywright.mjs'
|
|
5
4
|
import { serveStatic } from './serveStatic.mjs'
|
|
@@ -61,7 +60,7 @@ describe('a real page, served and loaded end to end', () => {
|
|
|
61
60
|
const page = await browser.newPage()
|
|
62
61
|
await page.goto(`${url}/index.html`)
|
|
63
62
|
expect(await page.title()).toBe('loaded via a real module script')
|
|
64
|
-
const backgroundColor = await page.evaluate(() => getComputedStyle(document.body).backgroundColor)
|
|
63
|
+
const backgroundColor = await page.evaluate(() => globalThis.getComputedStyle(document.body).backgroundColor)
|
|
65
64
|
expect(backgroundColor).toBe('rgb(1, 2, 3)')
|
|
66
65
|
} finally {
|
|
67
66
|
await browser.close()
|
|
@@ -2,7 +2,7 @@ import { dest, src } from 'gulp'
|
|
|
2
2
|
import { default as gulpUglify } from 'gulp-uglify-es'
|
|
3
3
|
import rename from 'gulp-rename'
|
|
4
4
|
|
|
5
|
-
const uglify =
|
|
5
|
+
const uglify = Object.hasOwn(gulpUglify, 'default') ? gulpUglify.default : gulpUglify
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Minify files and rename the output with '.min' extension.
|
|
@@ -71,7 +71,8 @@ const printFileReport = (file, result) => {
|
|
|
71
71
|
/**
|
|
72
72
|
* Lint every file streaming through with neostandard and, unless `fix` is false, apply the automatic fixes to the
|
|
73
73
|
* file's contents so a following `dest()` writes the fixed version. Remaining problems are printed along with a
|
|
74
|
-
* summary once the stream ends; they
|
|
74
|
+
* summary once the stream ends; they only fail the stream when `failOnError` is set (the standalone `lint` task),
|
|
75
|
+
* never during `build`.
|
|
75
76
|
*
|
|
76
77
|
* One ESLint instance is built from the first file's own cwd and reused for the rest of the stream, since every
|
|
77
78
|
* file in a given lint pass shares the same project (and so the same config).
|
|
@@ -81,13 +82,15 @@ const printFileReport = (file, result) => {
|
|
|
81
82
|
* @param {boolean} [options.ts=false] - Lint `.ts` files too, with type-aware rules (see neostandard's `ts` option).
|
|
82
83
|
* @param {Object<string, *>} [options.rules={}] - ESLint rule overrides layered on top of neostandard's own rules
|
|
83
84
|
* (see gulp.config.mjs's `lint.rules`).
|
|
85
|
+
* @param {boolean} [options.failOnError=false] - Emit an error once the stream ends if any lint errors remain after
|
|
86
|
+
* fixing, so a command-line run exits non-zero.
|
|
84
87
|
* @param {function(Object): Promise<{lintText: Function}>} [loadEslint] - Resolves an ESLint-shaped linter. Real
|
|
85
88
|
* callers should never need to pass this - it exists so tests can supply a stand-in, since this project's
|
|
86
89
|
* CommonJS-transform-based Jest setup cannot execute a real dynamic import() of neostandard (ESM-only).
|
|
87
90
|
* @returns {stream.Transform}
|
|
88
91
|
*/
|
|
89
92
|
export const neostandardLint = (
|
|
90
|
-
{ fix = true, ts = false, rules = {} } = {},
|
|
93
|
+
{ fix = true, ts = false, rules = {}, failOnError = false } = {},
|
|
91
94
|
loadEslint = buildEslint
|
|
92
95
|
) => {
|
|
93
96
|
const totals = { errors: 0, warnings: 0 }
|
|
@@ -126,6 +129,10 @@ export const neostandardLint = (
|
|
|
126
129
|
console.log('======================================')
|
|
127
130
|
console.log(`✖ Errors total: ${totals.errors}`)
|
|
128
131
|
console.log(`⚠ Warnings total: ${totals.warnings}\n`)
|
|
132
|
+
if (failOnError && totals.errors) {
|
|
133
|
+
callback(new Error(`neostandard found ${totals.errors} lint error(s) that could not be fixed automatically.`))
|
|
134
|
+
return
|
|
135
|
+
}
|
|
129
136
|
callback()
|
|
130
137
|
}
|
|
131
138
|
)
|
|
@@ -110,6 +110,20 @@ describe('neostandardLint', () => {
|
|
|
110
110
|
expect(logSpy).toHaveBeenCalledWith('⚠ Warnings total: 1\n')
|
|
111
111
|
})
|
|
112
112
|
|
|
113
|
+
test('with failOnError, fails the stream once it ends if any errors remain', async () => {
|
|
114
|
+
expect.assertions(2)
|
|
115
|
+
const eslint = fakeEslint(() => [{ messages: [{ line: 1, column: 1, message: 'bad thing' }], errorCount: 1, warningCount: 0 }])
|
|
116
|
+
await expect(run(neostandardLint({ failOnError: true }, () => Promise.resolve(eslint)), [makeFile(Buffer.from('a'))]))
|
|
117
|
+
.rejects.toThrow('neostandard found 1 lint error(s)')
|
|
118
|
+
expect(logSpy).toHaveBeenCalledWith('✖ Errors total: 1')
|
|
119
|
+
})
|
|
120
|
+
|
|
121
|
+
test('with failOnError, still passes when there are only warnings', async () => {
|
|
122
|
+
expect.assertions(1)
|
|
123
|
+
const eslint = fakeEslint(() => [{ messages: [{ line: 1, column: 1, message: 'just a warning' }], errorCount: 0, warningCount: 1 }])
|
|
124
|
+
await expect(run(neostandardLint({ failOnError: true }, () => Promise.resolve(eslint)), [makeFile(Buffer.from('a'))])).resolves.toHaveLength(1)
|
|
125
|
+
})
|
|
126
|
+
|
|
113
127
|
test('surfaces a failure to load or run the linter as a stream error', async () => {
|
|
114
128
|
expect.assertions(1)
|
|
115
129
|
await expect(run(neostandardLint({}, () => Promise.reject(new Error('cannot load'))), [makeFile(Buffer.from('x'))])).rejects.toThrow('cannot load')
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable no-template-curly-in-string -- fixture source code, the ${...} is meant to stay literal */
|
|
1
2
|
import fs from 'fs'
|
|
2
3
|
import * as setUp from '../test-helpers/setUp.mjs'
|
|
3
4
|
import { bundle } from '../bundle.mjs'
|
|
@@ -26,10 +27,10 @@ const srcFile = `${srcPath}/runOnChange.js`
|
|
|
26
27
|
const srcTsFile = `${srcPath}/runOnChange.ts`
|
|
27
28
|
|
|
28
29
|
beforeEach(() => {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
return setUp.beforeEach()
|
|
31
|
+
.then(() => fs.writeFileSync(srcTsFile, rawContents))
|
|
32
|
+
.then(() => fs.writeFileSync(srcFile, rawContents))
|
|
33
|
+
}
|
|
33
34
|
)
|
|
34
35
|
|
|
35
36
|
afterEach(() => {
|
package/functions/partials.mjs
CHANGED
|
@@ -18,6 +18,7 @@ export { imagesFor } from './partials/imagesFor.mjs'
|
|
|
18
18
|
export { importModule, importPeer, requirePeer } from './partials/loadPeer.mjs'
|
|
19
19
|
export { jsdocDocsFor } from './partials/jsdocDocsFor.mjs'
|
|
20
20
|
export { loadPlaywright, launchBrowser } from './partials/loadPlaywright.mjs'
|
|
21
|
+
export { lintSource } from './partials/lintSource.mjs'
|
|
21
22
|
export { minifyFor } from './partials/minifyFor.mjs'
|
|
22
23
|
export { neostandardLint } from './partials/neostandardLint.mjs'
|
|
23
24
|
export { readmeTemplate } from './partials/readmeTemplate.mjs'
|
package/functions/sourceLint.mjs
CHANGED
|
@@ -1,24 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { dest, src } from 'gulp'
|
|
3
|
-
import { neostandardLint } from './partials/neostandardLint.mjs'
|
|
1
|
+
import { lintSource } from './partials/lintSource.mjs'
|
|
4
2
|
|
|
5
3
|
/**
|
|
6
4
|
* Applies neostandard linting (js-build-tools' chosen style) to the real, hand-written source - not the compiled
|
|
7
5
|
* dist/browser output, which is generated and so was never going to pass a hand-authored-code style check (every
|
|
8
6
|
* compiler/bundler emits its own boilerplate - import aliasing, interop headers - that only looks like a style
|
|
9
7
|
* violation). Includes test files: there is no reason to hold tests to a lower style bar than the rest of the
|
|
10
|
-
* source. When typescript.enabled, the real TypeScript source is linted too, with type-aware rules.
|
|
8
|
+
* source. When typescript.enabled, the real TypeScript source is linted too, with type-aware rules. Runs as part of
|
|
9
|
+
* `build`, where remaining errors are reported but never fail it.
|
|
11
10
|
* @memberOf module:js-build-tools
|
|
12
11
|
* @returns {*}
|
|
13
12
|
*/
|
|
14
|
-
export const sourceLint = () =>
|
|
15
|
-
const srcPath = gulpConfig.get('srcPath')
|
|
16
|
-
const ts = gulpConfig.get('typescript.enabled')
|
|
17
|
-
const patterns = [`${srcPath}/**/*.js`]
|
|
18
|
-
if (ts) {
|
|
19
|
-
patterns.push(`${srcPath}/**/*.ts`)
|
|
20
|
-
}
|
|
21
|
-
return src(patterns)
|
|
22
|
-
.pipe(neostandardLint({ fix: true, ts, rules: gulpConfig.get('lint.rules') }))
|
|
23
|
-
.pipe(dest(srcPath))
|
|
24
|
-
}
|
|
13
|
+
export const sourceLint = () => lintSource()
|
|
@@ -1,5 +1,7 @@
|
|
|
1
|
+
/* eslint-disable no-template-curly-in-string -- fixture source code, the ${...} is meant to stay literal */
|
|
1
2
|
import fs from 'fs'
|
|
2
3
|
import * as setUp from './test-helpers/setUp.mjs'
|
|
4
|
+
import { lint } from './lint.mjs'
|
|
3
5
|
import { sourceLint } from './sourceLint.mjs'
|
|
4
6
|
import { countMatches } from 'test-filesystem'
|
|
5
7
|
|
|
@@ -51,6 +53,23 @@ describe('sourceLint', () => {
|
|
|
51
53
|
})
|
|
52
54
|
}, 20000)
|
|
53
55
|
|
|
56
|
+
test('also lints .mjs and .cjs source, not just .js', done => {
|
|
57
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
58
|
+
fs.writeFileSync(`${srcPath}/example.mjs`, 'const m = "d";\n\nexport default m;\n')
|
|
59
|
+
fs.writeFileSync(`${srcPath}/example.cjs`, 'const c = "e";\n\nmodule.exports = c;\n')
|
|
60
|
+
expect.assertions(2)
|
|
61
|
+
sourceLint()
|
|
62
|
+
.on('finish', () => {
|
|
63
|
+
expect(fs.readFileSync(`${srcPath}/example.mjs`).toString()).toEqual('const m = \'d\'\n\nexport default m\n')
|
|
64
|
+
expect(fs.readFileSync(`${srcPath}/example.cjs`).toString()).toEqual('const c = \'e\'\n\nmodule.exports = c\n')
|
|
65
|
+
done()
|
|
66
|
+
})
|
|
67
|
+
.on('error', error => {
|
|
68
|
+
console.error('Encountered error', error)
|
|
69
|
+
done(error)
|
|
70
|
+
})
|
|
71
|
+
}, 20000)
|
|
72
|
+
|
|
54
73
|
test('lint.rules actually suppresses a real neostandard finding', done => {
|
|
55
74
|
const srcPath = gulpConfig.get('srcPath')
|
|
56
75
|
// A fixture string containing literal ${...} text (simulating real module source, not an accidental
|
|
@@ -95,3 +114,33 @@ describe('sourceLint', () => {
|
|
|
95
114
|
})
|
|
96
115
|
}, 20000)
|
|
97
116
|
})
|
|
117
|
+
|
|
118
|
+
describe('lint', () => {
|
|
119
|
+
test('fixes the source and finishes without error when nothing unfixable remains', done => {
|
|
120
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
121
|
+
expect.assertions(1)
|
|
122
|
+
lint()
|
|
123
|
+
.on('finish', () => {
|
|
124
|
+
expect(countMatches(fs.readFileSync(`${srcPath}/example.js`).toString(), ';')).toEqual(0)
|
|
125
|
+
done()
|
|
126
|
+
})
|
|
127
|
+
.on('error', error => done(error))
|
|
128
|
+
}, 20000)
|
|
129
|
+
|
|
130
|
+
test('fails when an error remains that neostandard cannot fix', done => {
|
|
131
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
132
|
+
fs.writeFileSync(`${srcPath}/unfixable.js`, 'const unused = 1\n')
|
|
133
|
+
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
|
|
134
|
+
expect.assertions(1)
|
|
135
|
+
lint()
|
|
136
|
+
.on('error', error => {
|
|
137
|
+
logSpy.mockRestore()
|
|
138
|
+
expect(error.message).toMatch('neostandard found 1 lint error(s)')
|
|
139
|
+
done()
|
|
140
|
+
})
|
|
141
|
+
.on('finish', () => {
|
|
142
|
+
logSpy.mockRestore()
|
|
143
|
+
done(new Error('lint should have failed on the unused variable'))
|
|
144
|
+
})
|
|
145
|
+
}, 20000)
|
|
146
|
+
})
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import cache from 'gulp-cache'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Give this test file its own gulp-cache folder, and return a function that clears only that folder. gulp-cache
|
|
5
|
+
* otherwise keeps one cache in os.tmpdir() for every process, so a cache.clearAll() in one Jest worker could wipe it
|
|
6
|
+
* while another worker's images task was still using it, and gulp-cache then silently dropped that worker's
|
|
7
|
+
* images. Jest loads gulp-cache separately for each test file, so this only changes the copy that file uses.
|
|
8
|
+
* @memberOf module:testHelpers
|
|
9
|
+
* @param {string} name - Unique per test file, used in the cache folder name.
|
|
10
|
+
* @returns {function(): Promise<void>} Clears this test file's cache.
|
|
11
|
+
*/
|
|
12
|
+
export const isolateGulpCache = name => {
|
|
13
|
+
const fileCache = new cache.Cache({ cacheDirName: `js-build-tools-test-${name}` })
|
|
14
|
+
cache.defaultOptions.fileCache = fileCache
|
|
15
|
+
return () => new Promise((resolve, reject) => fileCache.clear(null, error => error ? reject(error) : resolve()))
|
|
16
|
+
}
|
|
@@ -60,41 +60,41 @@ export {
|
|
|
60
60
|
* @param {boolean} [exists=true]
|
|
61
61
|
* @returns {Promise<*|void>}
|
|
62
62
|
*/
|
|
63
|
-
|
|
63
|
+
createTempDir,
|
|
64
64
|
/**
|
|
65
65
|
* In the Jest.beforeEach function call this one to set up the temp directory.
|
|
66
66
|
* @memberOf module:testHelpers
|
|
67
67
|
* @returns {Promise<*|void>}
|
|
68
68
|
*/
|
|
69
|
-
|
|
69
|
+
beforeEach,
|
|
70
70
|
/**
|
|
71
71
|
* In the Jest.afterEach function call this one to clean up and remove the temp directory.
|
|
72
72
|
* @memberOf module:testHelpers
|
|
73
73
|
* @returns {Promise<*>}
|
|
74
74
|
*/
|
|
75
|
-
|
|
75
|
+
afterEach,
|
|
76
76
|
/**
|
|
77
77
|
* Return number of occurrences of substring in another string.
|
|
78
78
|
* @memberOf module:testHelpers
|
|
79
79
|
* @returns {int}
|
|
80
80
|
*/
|
|
81
|
-
|
|
81
|
+
countMatches,
|
|
82
82
|
/**
|
|
83
83
|
* Returns true if the given file or directory exists, otherwise false.
|
|
84
84
|
* @memberOf module:testHelpers
|
|
85
85
|
* @returns {boolean}
|
|
86
86
|
*/
|
|
87
|
-
|
|
87
|
+
fileExists,
|
|
88
88
|
/**
|
|
89
89
|
* Console log objects in a readable format, returns the given object.
|
|
90
90
|
* @memberOf module:testHelpers
|
|
91
91
|
* @returns {*}
|
|
92
92
|
*/
|
|
93
|
-
|
|
93
|
+
logObject,
|
|
94
94
|
/**
|
|
95
95
|
* Delete a directory and subcontents.
|
|
96
96
|
* @memberOf module:testHelpers
|
|
97
97
|
* @returns {Promise<*>}
|
|
98
98
|
*/
|
|
99
|
-
|
|
99
|
+
removeDirectory,
|
|
100
100
|
} from 'test-filesystem'
|
|
@@ -11,7 +11,7 @@ import { strBefore } from './strBefore.mjs'
|
|
|
11
11
|
* @returns {*} The value of the property
|
|
12
12
|
* @private
|
|
13
13
|
*/
|
|
14
|
-
export const dotGet = (arrayObject = {}, dotNotation= '', defaultValue = null) => {
|
|
14
|
+
export const dotGet = (arrayObject = {}, dotNotation = '', defaultValue = null) => {
|
|
15
15
|
if (!dotNotation) {
|
|
16
16
|
return arrayObject
|
|
17
17
|
}
|
|
@@ -22,7 +22,7 @@ export const dotGet = (arrayObject = {}, dotNotation= '', defaultValue = null) =
|
|
|
22
22
|
}
|
|
23
23
|
if (key === '*') {
|
|
24
24
|
const result = []
|
|
25
|
-
for (
|
|
25
|
+
for (const wildKey in arrayObject) {
|
|
26
26
|
const wildValue = arrayObject[wildKey]
|
|
27
27
|
if (lastKey) {
|
|
28
28
|
result[wildKey] = wildValue
|
|
@@ -15,7 +15,7 @@ const handleRetainObjects = (retainObjects = []) => {
|
|
|
15
15
|
*/
|
|
16
16
|
return (currentKey, value, results) => false
|
|
17
17
|
}
|
|
18
|
-
retainObjects = retainObjects.map(key => key.
|
|
18
|
+
retainObjects = retainObjects.map(key => key.replaceAll('.', '\\.'))
|
|
19
19
|
const retainRegex = new RegExp(`(${retainObjects.join('|')})$`)
|
|
20
20
|
/**
|
|
21
21
|
* Test if a key should be retained as an object.
|
|
@@ -44,7 +44,7 @@ const handleRetainObjects = (retainObjects = []) => {
|
|
|
44
44
|
* @private
|
|
45
45
|
*/
|
|
46
46
|
const performDotNotate = (arrayObject, didRetain, prepend = '', results = {}) => {
|
|
47
|
-
for (
|
|
47
|
+
for (const key in arrayObject) {
|
|
48
48
|
const value = arrayObject[key]
|
|
49
49
|
const currentKey = `${prepend}${key}`
|
|
50
50
|
if (didRetain(currentKey, value, results)) {
|
|
@@ -31,4 +31,11 @@ describe('dotNotate', () => {
|
|
|
31
31
|
options: { fix: true }
|
|
32
32
|
})
|
|
33
33
|
})
|
|
34
|
+
|
|
35
|
+
test('treats every dot in a retained key literally, not as a regex wildcard', () => {
|
|
36
|
+
expect(dotNotate({ a: { bXc: { d: 1 }, b: { c: { d: 2 } } } }, ['a.b.c'])).toEqual({
|
|
37
|
+
'a.bXc.d': 1,
|
|
38
|
+
'a.b.c': { d: 2 }
|
|
39
|
+
})
|
|
40
|
+
})
|
|
34
41
|
})
|
package/gulpfile.base.mjs
CHANGED
|
@@ -16,6 +16,7 @@ export { distMinify } from './functions/distMinify.mjs'
|
|
|
16
16
|
export * as gulpConfig from './gulp.config.mjs'
|
|
17
17
|
export { images } from './functions/images.mjs'
|
|
18
18
|
export { jsdocDocs } from './functions/jsdocDocs.mjs'
|
|
19
|
+
export { lint } from './functions/lint.mjs'
|
|
19
20
|
export * as partials from './functions/partials.mjs'
|
|
20
21
|
export { sass } from './functions/sass.mjs'
|
|
21
22
|
export { sourceLint } from './functions/sourceLint.mjs'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js-build-tools",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.4.0",
|
|
4
4
|
"description": "Standardised build process with gulp.",
|
|
5
5
|
"main": "gulpfile.base.js",
|
|
6
6
|
"exports": {
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"build": "gulp build",
|
|
22
22
|
"dev": "gulp",
|
|
23
23
|
"docs": "gulp docs",
|
|
24
|
+
"lint": "gulp lint",
|
|
24
25
|
"readme": "gulp readme",
|
|
25
26
|
"release": "release-it",
|
|
26
27
|
"release:dry-run": "release-it --dry-run",
|
|
@@ -124,12 +125,21 @@
|
|
|
124
125
|
"clean-jsdoc-theme": "^4.3.3",
|
|
125
126
|
"gulp-imagemin": "github:jheagle/gulp-imagemin#common-js-compatibility",
|
|
126
127
|
"jsdoc": "^4.0.5",
|
|
127
|
-
"playwright": "
|
|
128
|
+
"playwright": "^1.64.1",
|
|
128
129
|
"release-it": "^21.1.1",
|
|
129
130
|
"typedoc": "^0.28.20",
|
|
130
131
|
"typescript": "^6.0.3"
|
|
131
132
|
},
|
|
132
133
|
"engines": {
|
|
133
134
|
"node": ">=22.12.0"
|
|
135
|
+
},
|
|
136
|
+
"allowScripts": {
|
|
137
|
+
"gifsicle@5.3.0": true,
|
|
138
|
+
"mozjpeg@8.0.0": true,
|
|
139
|
+
"optipng-bin@7.0.1": true,
|
|
140
|
+
"core-js": false,
|
|
141
|
+
"core-js-pure": false,
|
|
142
|
+
"@parcel/watcher": false,
|
|
143
|
+
"unrs-resolver": false
|
|
134
144
|
}
|
|
135
145
|
}
|