js-build-tools 5.7.0 → 6.0.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 +1 -1
- package/dist/build.js +65 -64
- package/dist/build.min.js +1 -1
- package/dist/bundle.js +40 -40
- package/dist/bundleMinify.js +18 -18
- package/dist/compileReadme.js +7 -7
- package/dist/copyFonts.js +10 -10
- package/dist/default.js +12 -12
- package/dist/dist.js +7 -7
- package/dist/distMinify.js +10 -10
- package/dist/images.js +7 -7
- package/dist/partials/addToReadme.js +24 -24
- package/dist/partials/imagesFor.js +42 -42
- package/dist/partials/loadPeer.js +70 -70
- package/dist/partials/neostandardLint.js +144 -0
- package/dist/partials/tsFor.js +70 -70
- package/dist/partials/typeDocsFor.js +202 -202
- package/dist/partials.js +136 -136
- package/dist/partials.min.js +1 -1
- package/dist/sass.js +7 -7
- package/dist/sourceLint.js +33 -0
- package/dist/sourceLint.min.js +1 -0
- package/dist/test-helpers/neostandardLintWithRealNeostandard.js +48 -0
- package/dist/test-helpers/setUp.js +94 -94
- package/dist/testFull.js +13 -13
- package/dist/testHelpers.js +8 -8
- package/dist/testQuick.js +13 -13
- package/dist/typeDocs.js +9 -9
- package/dist/typeScript.js +6 -6
- package/dist/utilities/convertMjsFilesForDocs.js +36 -36
- package/dist/utilities/esmNamedExportsToCjs.js +18 -18
- package/dist/utilities/getBundleConfigs.js +27 -27
- package/dist/watchFull.js +7 -7
- package/dist/watchTest.js +11 -11
- package/functions/build.mjs +9 -8
- package/functions/build.test.mjs +18 -25
- package/functions/partials/neostandardLint.mjs +118 -0
- package/functions/partials/neostandardLint.test.mjs +109 -0
- package/functions/partials.mjs +1 -1
- package/functions/sourceLint.mjs +24 -0
- package/functions/sourceLint.test.mjs +73 -0
- package/functions/test-helpers/neostandardLintWithRealNeostandard.mjs +38 -0
- package/gulpfile.base.js +2 -4
- package/gulpfile.base.mjs +1 -2
- package/package.json +7 -6
- package/dist/bundleLint.js +0 -28
- package/dist/bundleLint.min.js +0 -1
- package/dist/distLint.js +0 -20
- package/dist/distLint.min.js +0 -1
- package/dist/partials/standardLint.js +0 -94
- package/dist/test-helpers/standardLintWithRealStandard.js +0 -28
- package/functions/bundleLint.mjs +0 -18
- package/functions/bundleLint.test.mjs +0 -85
- package/functions/distLint.mjs +0 -12
- package/functions/distLint.test.mjs +0 -62
- package/functions/partials/standardLint.mjs +0 -78
- package/functions/partials/standardLint.test.mjs +0 -99
- package/functions/test-helpers/standardLintWithRealStandard.mjs +0 -21
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import fs from 'node:fs'
|
|
2
|
+
import path from 'node:path'
|
|
3
|
+
import through from 'through2'
|
|
4
|
+
import { ESLint } from 'eslint'
|
|
5
|
+
import { importModule } from './loadPeer.mjs'
|
|
6
|
+
|
|
7
|
+
// neostandard (js-build-tools' chosen style - a maintained, TypeScript-aware successor to `standard`, see
|
|
8
|
+
// https://github.com/neostandard/neostandard) ships ESM-only, see importModule for how it is imported.
|
|
9
|
+
const importNeostandard = () => importModule('neostandard').then(({ neostandard }) => neostandard)
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Read the `env` a project already declared for Standard (the `standard` field in its package.json), so a project
|
|
13
|
+
* migrating from `standard` keeps its globals (jest, browser, ...) without touching package.json.
|
|
14
|
+
* @param {string} cwd
|
|
15
|
+
* @returns {Array<string>}
|
|
16
|
+
*/
|
|
17
|
+
const readEnv = cwd => {
|
|
18
|
+
try {
|
|
19
|
+
return JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8')).standard?.env ?? []
|
|
20
|
+
} catch {
|
|
21
|
+
return []
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Build an ESLint instance configured with neostandard, honoring the project's own package.json `standard.env`.
|
|
27
|
+
* @param {Object} options
|
|
28
|
+
* @param {string} options.cwd
|
|
29
|
+
* @param {boolean} options.ts
|
|
30
|
+
* @param {boolean} options.fix
|
|
31
|
+
* @returns {Promise<import('eslint').ESLint>}
|
|
32
|
+
*/
|
|
33
|
+
const buildEslint = async ({ cwd, ts, fix }) => {
|
|
34
|
+
const neostandard = await importNeostandard()
|
|
35
|
+
return new ESLint({
|
|
36
|
+
cwd,
|
|
37
|
+
fix,
|
|
38
|
+
overrideConfigFile: true,
|
|
39
|
+
baseConfig: neostandard({ ts, env: readEnv(cwd) })
|
|
40
|
+
})
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Print a file's lint messages, if it has any.
|
|
45
|
+
* @memberOf module:partials
|
|
46
|
+
* @param {import('vinyl')} file
|
|
47
|
+
* @param {{messages: Array<{line: number, column: number, message: string}>, errorCount: number, warningCount: number}} result
|
|
48
|
+
* @returns {undefined}
|
|
49
|
+
*/
|
|
50
|
+
const printFileReport = (file, result) => {
|
|
51
|
+
if (!result.messages.length) {
|
|
52
|
+
return
|
|
53
|
+
}
|
|
54
|
+
console.log(path.relative(file.cwd, file.path))
|
|
55
|
+
result.messages.forEach(({ line, column, message }) => console.log(`line ${line}:${column}\t${message}`))
|
|
56
|
+
console.log(`✖ ${result.errorCount} error\t⚠ ${result.warningCount} warning\n`)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Lint every file streaming through with neostandard and, unless `fix` is false, apply the automatic fixes to the
|
|
61
|
+
* file's contents so a following `dest()` writes the fixed version. Remaining problems are printed along with a
|
|
62
|
+
* summary once the stream ends; they never fail the build.
|
|
63
|
+
*
|
|
64
|
+
* One ESLint instance is built from the first file's own cwd and reused for the rest of the stream, since every
|
|
65
|
+
* file in a given lint pass shares the same project (and so the same config).
|
|
66
|
+
* @memberOf module:partials
|
|
67
|
+
* @param {Object} [options={}]
|
|
68
|
+
* @param {boolean} [options.fix=true] - Apply neostandard's automatic fixes to the file contents.
|
|
69
|
+
* @param {boolean} [options.ts=false] - Lint `.ts` files too, with type-aware rules (see neostandard's `ts` option).
|
|
70
|
+
* @param {function(Object): Promise<{lintText: Function}>} [loadEslint] - Resolves an ESLint-shaped linter. Real
|
|
71
|
+
* callers should never need to pass this - it exists so tests can supply a stand-in, since this project's
|
|
72
|
+
* CommonJS-transform-based Jest setup cannot execute a real dynamic import() of neostandard (ESM-only).
|
|
73
|
+
* @returns {import('stream').Transform}
|
|
74
|
+
*/
|
|
75
|
+
export const neostandardLint = (
|
|
76
|
+
{ fix = true, ts = false } = {},
|
|
77
|
+
loadEslint = buildEslint
|
|
78
|
+
) => {
|
|
79
|
+
const totals = { errors: 0, warnings: 0 }
|
|
80
|
+
let eslintPromise = null
|
|
81
|
+
return through.obj(
|
|
82
|
+
function (file, enc, callback) {
|
|
83
|
+
if (file.isNull()) {
|
|
84
|
+
callback(null, file)
|
|
85
|
+
return
|
|
86
|
+
}
|
|
87
|
+
if (file.isStream()) {
|
|
88
|
+
callback(new Error('neostandardLint: streaming file contents are not supported.'))
|
|
89
|
+
return
|
|
90
|
+
}
|
|
91
|
+
if (!eslintPromise) {
|
|
92
|
+
eslintPromise = loadEslint({ cwd: file.cwd, ts, fix })
|
|
93
|
+
}
|
|
94
|
+
eslintPromise
|
|
95
|
+
.then(eslint => eslint.lintText(file.contents.toString(), { filePath: file.path }))
|
|
96
|
+
.then(results => {
|
|
97
|
+
// No result at all means the file is ignored by the project's ESLint configuration.
|
|
98
|
+
const [result] = results
|
|
99
|
+
if (result) {
|
|
100
|
+
if (typeof result.output === 'string') {
|
|
101
|
+
file.contents = Buffer.from(result.output)
|
|
102
|
+
}
|
|
103
|
+
totals.errors += result.errorCount
|
|
104
|
+
totals.warnings += result.warningCount
|
|
105
|
+
printFileReport(file, result)
|
|
106
|
+
}
|
|
107
|
+
callback(null, file)
|
|
108
|
+
}, callback)
|
|
109
|
+
},
|
|
110
|
+
function (callback) {
|
|
111
|
+
console.log('neostandard linter results')
|
|
112
|
+
console.log('======================================')
|
|
113
|
+
console.log(`✖ Errors total: ${totals.errors}`)
|
|
114
|
+
console.log(`⚠ Warnings total: ${totals.warnings}\n`)
|
|
115
|
+
callback()
|
|
116
|
+
}
|
|
117
|
+
)
|
|
118
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import Vinyl from 'vinyl'
|
|
2
|
+
import { Readable } from 'node:stream'
|
|
3
|
+
import { neostandardLint } from './neostandardLint.mjs'
|
|
4
|
+
|
|
5
|
+
const makeFile = (contents, filePath = '/project/src/example.js') => new Vinyl({
|
|
6
|
+
cwd: '/project',
|
|
7
|
+
base: '/project/src',
|
|
8
|
+
path: filePath,
|
|
9
|
+
contents
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const run = (transform, files) => new Promise((resolve, reject) => {
|
|
13
|
+
const out = []
|
|
14
|
+
transform.on('data', file => out.push(file)).on('end', () => resolve(out)).on('error', reject)
|
|
15
|
+
files.forEach(file => transform.write(file))
|
|
16
|
+
transform.end()
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
const fakeEslint = (resultFor) => ({
|
|
20
|
+
lintText: jest.fn((text, options) => Promise.resolve(resultFor(text, options)))
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
let logSpy
|
|
24
|
+
|
|
25
|
+
beforeEach(() => {
|
|
26
|
+
logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
afterEach(() => {
|
|
30
|
+
logSpy.mockRestore()
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
describe('neostandardLint', () => {
|
|
34
|
+
test('replaces file contents with the fixed output and hands ESLint the file path', async () => {
|
|
35
|
+
expect.assertions(3)
|
|
36
|
+
const eslint = fakeEslint((text) => [{ messages: [], errorCount: 0, warningCount: 0, output: text.replace(/"/g, '\'') }])
|
|
37
|
+
const [linted] = await run(neostandardLint({ fix: true }, () => Promise.resolve(eslint)), [makeFile(Buffer.from('const a = "b"'))])
|
|
38
|
+
expect(linted.contents.toString()).toEqual('const a = \'b\'')
|
|
39
|
+
expect(eslint.lintText).toHaveBeenCalledWith('const a = "b"', { filePath: '/project/src/example.js' })
|
|
40
|
+
expect(linted.path).toEqual('/project/src/example.js')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
test('leaves the contents alone when ESLint has no fixed output (nothing needed fixing)', async () => {
|
|
44
|
+
expect.assertions(1)
|
|
45
|
+
const eslint = fakeEslint(() => [{ messages: [], errorCount: 0, warningCount: 0 }])
|
|
46
|
+
const [linted] = await run(neostandardLint({}, () => Promise.resolve(eslint)), [makeFile(Buffer.from('const a = 1'))])
|
|
47
|
+
expect(linted.contents.toString()).toEqual('const a = 1')
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
test('builds the linter once per stream, from the first file, and reuses it for the rest', async () => {
|
|
51
|
+
expect.assertions(1)
|
|
52
|
+
const loadEslint = jest.fn(() => Promise.resolve(fakeEslint(() => [{ messages: [], errorCount: 0, warningCount: 0 }])))
|
|
53
|
+
await run(
|
|
54
|
+
neostandardLint({}, loadEslint),
|
|
55
|
+
[makeFile(Buffer.from('a'), '/project/src/a.js'), makeFile(Buffer.from('b'), '/project/src/b.js')]
|
|
56
|
+
)
|
|
57
|
+
expect(loadEslint).toHaveBeenCalledTimes(1)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
test('passes fix and ts through to the loader', async () => {
|
|
61
|
+
expect.assertions(1)
|
|
62
|
+
const loadEslint = jest.fn(() => Promise.resolve(fakeEslint(() => [{ messages: [], errorCount: 0, warningCount: 0 }])))
|
|
63
|
+
await run(neostandardLint({ fix: false, ts: true }, loadEslint), [makeFile(Buffer.from('x'))])
|
|
64
|
+
expect(loadEslint).toHaveBeenCalledWith({ cwd: '/project', ts: true, fix: false })
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
test('passes a file through untouched when the project ignores it (ESLint returns no results)', async () => {
|
|
68
|
+
expect.assertions(2)
|
|
69
|
+
const eslint = fakeEslint(() => [])
|
|
70
|
+
const [linted] = await run(neostandardLint({}, () => Promise.resolve(eslint)), [makeFile(Buffer.from('var x=1'))])
|
|
71
|
+
expect(linted.contents.toString()).toEqual('var x=1')
|
|
72
|
+
expect(logSpy).toHaveBeenCalledWith('✖ Errors total: 0')
|
|
73
|
+
})
|
|
74
|
+
|
|
75
|
+
test('skips null-content files without linting them', async () => {
|
|
76
|
+
expect.assertions(2)
|
|
77
|
+
const eslint = fakeEslint(() => [])
|
|
78
|
+
const [passed] = await run(neostandardLint({}, () => Promise.resolve(eslint)), [makeFile(null)])
|
|
79
|
+
expect(passed.isNull()).toBeTruthy()
|
|
80
|
+
expect(eslint.lintText).not.toHaveBeenCalled()
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test('errors on streaming file contents, which cannot be linted', async () => {
|
|
84
|
+
expect.assertions(1)
|
|
85
|
+
const streamFile = makeFile(Readable.from(['x']))
|
|
86
|
+
await expect(run(neostandardLint({}, () => Promise.resolve(fakeEslint(() => []))), [streamFile])).rejects.toThrow(/streaming/)
|
|
87
|
+
})
|
|
88
|
+
|
|
89
|
+
test('prints per-file problems and a summary of totals across all files, without failing', async () => {
|
|
90
|
+
expect.assertions(5)
|
|
91
|
+
const eslint = fakeEslint((text, { filePath }) => filePath.endsWith('a.js')
|
|
92
|
+
? [{ messages: [{ line: 2, column: 7, message: 'unused b' }, { line: 3, column: 1, message: 'bad thing' }], errorCount: 2, warningCount: 0 }]
|
|
93
|
+
: [{ messages: [{ line: 1, column: 1, message: 'just a warning' }], errorCount: 0, warningCount: 1 }])
|
|
94
|
+
const out = await run(
|
|
95
|
+
neostandardLint({}, () => Promise.resolve(eslint)),
|
|
96
|
+
[makeFile(Buffer.from('a'), '/project/src/a.js'), makeFile(Buffer.from('b'), '/project/src/b.js')]
|
|
97
|
+
)
|
|
98
|
+
expect(out).toHaveLength(2)
|
|
99
|
+
expect(logSpy).toHaveBeenCalledWith('src/a.js')
|
|
100
|
+
expect(logSpy).toHaveBeenCalledWith('line 2:7\tunused b')
|
|
101
|
+
expect(logSpy).toHaveBeenCalledWith('✖ Errors total: 2')
|
|
102
|
+
expect(logSpy).toHaveBeenCalledWith('⚠ Warnings total: 1\n')
|
|
103
|
+
})
|
|
104
|
+
|
|
105
|
+
test('surfaces a failure to load or run the linter as a stream error', async () => {
|
|
106
|
+
expect.assertions(1)
|
|
107
|
+
await expect(run(neostandardLint({}, () => Promise.reject(new Error('cannot load'))), [makeFile(Buffer.from('x'))])).rejects.toThrow('cannot load')
|
|
108
|
+
})
|
|
109
|
+
})
|
package/functions/partials.mjs
CHANGED
|
@@ -17,10 +17,10 @@ export { distSeries } from './partials/distSeries.mjs'
|
|
|
17
17
|
export { imagesFor } from './partials/imagesFor.mjs'
|
|
18
18
|
export { importModule, importPeer, requirePeer } from './partials/loadPeer.mjs'
|
|
19
19
|
export { minifyFor } from './partials/minifyFor.mjs'
|
|
20
|
+
export { neostandardLint } from './partials/neostandardLint.mjs'
|
|
20
21
|
export { readmeTemplate } from './partials/readmeTemplate.mjs'
|
|
21
22
|
export { removeDirectory } from './partials/removeDirectory.mjs'
|
|
22
23
|
export { runOnChange } from './partials/runOnChange.mjs'
|
|
23
24
|
export { sassFor } from './partials/sassFor.mjs'
|
|
24
|
-
export { standardLint } from './partials/standardLint.mjs'
|
|
25
25
|
export { tsFor } from './partials/tsFor.mjs'
|
|
26
26
|
export { typeDocsFor } from './partials/typeDocsFor.mjs'
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import * as gulpConfig from '../gulp.config.mjs'
|
|
2
|
+
import { dest, src } from 'gulp'
|
|
3
|
+
import { neostandardLint } from './partials/neostandardLint.mjs'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Applies neostandard linting (js-build-tools' chosen style) to the real, hand-written source - not the compiled
|
|
7
|
+
* dist/browser output, which is generated and so was never going to pass a hand-authored-code style check (every
|
|
8
|
+
* compiler/bundler emits its own boilerplate - import aliasing, interop headers - that only looks like a style
|
|
9
|
+
* 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.
|
|
11
|
+
* @memberOf module:js-build-tools
|
|
12
|
+
* @returns {*}
|
|
13
|
+
*/
|
|
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 }))
|
|
23
|
+
.pipe(dest(srcPath))
|
|
24
|
+
}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import * as setUp from './test-helpers/setUp.mjs'
|
|
3
|
+
import { sourceLint } from './sourceLint.mjs'
|
|
4
|
+
import { countMatches } from 'test-filesystem'
|
|
5
|
+
|
|
6
|
+
// Run the real neostandard (in a subprocess) - Jest's CommonJS transform can't load the ESM-only package itself.
|
|
7
|
+
jest.mock('./partials/neostandardLint.mjs', () => require('./test-helpers/neostandardLintWithRealNeostandard.mjs'))
|
|
8
|
+
|
|
9
|
+
setUp.setDefaults('test-source-lint')
|
|
10
|
+
const gulpConfig = setUp.gulpConfig
|
|
11
|
+
|
|
12
|
+
const lintableContents = 'const x = "a";\n' +
|
|
13
|
+
'\n' +
|
|
14
|
+
'module.exports = x;\n'
|
|
15
|
+
|
|
16
|
+
const lintableTestContents = 'const y = "b";\n' +
|
|
17
|
+
'\n' +
|
|
18
|
+
'module.exports = y;\n'
|
|
19
|
+
|
|
20
|
+
beforeEach(
|
|
21
|
+
() => setUp.beforeEach()
|
|
22
|
+
.then(
|
|
23
|
+
async () => {
|
|
24
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
25
|
+
await fs.mkdirSync(srcPath, { recursive: true })
|
|
26
|
+
fs.writeFileSync(`${srcPath}/example.js`, lintableContents)
|
|
27
|
+
return fs.writeFileSync(`${srcPath}/example.test.js`, lintableTestContents)
|
|
28
|
+
}
|
|
29
|
+
)
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
afterEach(setUp.afterEach)
|
|
33
|
+
|
|
34
|
+
describe('sourceLint', () => {
|
|
35
|
+
test('fixes the real source in place, including test files', done => {
|
|
36
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
37
|
+
expect.assertions(4)
|
|
38
|
+
sourceLint()
|
|
39
|
+
.on('finish', () => {
|
|
40
|
+
const linted = fs.readFileSync(`${srcPath}/example.js`).toString()
|
|
41
|
+
expect(countMatches(linted, '"')).toEqual(0)
|
|
42
|
+
expect(countMatches(linted, ';')).toEqual(0)
|
|
43
|
+
const lintedTest = fs.readFileSync(`${srcPath}/example.test.js`).toString()
|
|
44
|
+
expect(countMatches(lintedTest, '"')).toEqual(0)
|
|
45
|
+
expect(countMatches(lintedTest, ';')).toEqual(0)
|
|
46
|
+
done()
|
|
47
|
+
})
|
|
48
|
+
.on('error', error => {
|
|
49
|
+
console.error('Encountered error', error)
|
|
50
|
+
done(error)
|
|
51
|
+
})
|
|
52
|
+
}, 20000)
|
|
53
|
+
|
|
54
|
+
test('also lints .ts source when typescript.enabled', done => {
|
|
55
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
56
|
+
gulpConfig.set('typescript.enabled', true)
|
|
57
|
+
fs.writeFileSync(`${srcPath}/example.ts`, 'const z: string = "c";\n\nexport default z;\n')
|
|
58
|
+
expect.assertions(2)
|
|
59
|
+
sourceLint()
|
|
60
|
+
.on('finish', () => {
|
|
61
|
+
gulpConfig.set('typescript.enabled', false)
|
|
62
|
+
const linted = fs.readFileSync(`${srcPath}/example.ts`).toString()
|
|
63
|
+
expect(countMatches(linted, '"')).toEqual(0)
|
|
64
|
+
expect(countMatches(linted, ';')).toEqual(0)
|
|
65
|
+
done()
|
|
66
|
+
})
|
|
67
|
+
.on('error', error => {
|
|
68
|
+
gulpConfig.set('typescript.enabled', false)
|
|
69
|
+
console.error('Encountered error', error)
|
|
70
|
+
done(error)
|
|
71
|
+
})
|
|
72
|
+
}, 20000)
|
|
73
|
+
})
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process'
|
|
2
|
+
import fs from 'node:fs'
|
|
3
|
+
import path from 'node:path'
|
|
4
|
+
|
|
5
|
+
// Jest's CommonJS transform cannot load `neostandard` (ESM-only) or run a real dynamic import(), so tests that need
|
|
6
|
+
// genuine neostandard behavior run the actual package in a plain Node subprocess instead of faking it.
|
|
7
|
+
const script = 'import { readFileSync } from \'node:fs\'\n' +
|
|
8
|
+
'import { ESLint } from \'eslint\'\n' +
|
|
9
|
+
'import { neostandard } from \'neostandard\'\n' +
|
|
10
|
+
'const { text, filePath, cwd, fix, ts, env } = JSON.parse(readFileSync(0, \'utf8\'))\n' +
|
|
11
|
+
'const eslint = new ESLint({ cwd, fix, overrideConfigFile: true, baseConfig: neostandard({ ts, env }) })\n' +
|
|
12
|
+
'process.stdout.write(JSON.stringify(await eslint.lintText(text, { filePath })))\n'
|
|
13
|
+
|
|
14
|
+
const readEnv = cwd => {
|
|
15
|
+
try {
|
|
16
|
+
return JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8')).standard?.env ?? []
|
|
17
|
+
} catch {
|
|
18
|
+
return []
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export const loadEslintViaSubprocess = ({ cwd, ts, fix }) => Promise.resolve({
|
|
23
|
+
lintText: (text, { filePath }) => Promise.resolve().then(() => JSON.parse(execFileSync(
|
|
24
|
+
process.execPath,
|
|
25
|
+
['--input-type=module', '--eval', script],
|
|
26
|
+
{
|
|
27
|
+
input: JSON.stringify({ text, filePath, cwd, fix, ts, env: readEnv(cwd) }),
|
|
28
|
+
encoding: 'utf8',
|
|
29
|
+
cwd,
|
|
30
|
+
maxBuffer: 256 * 1024 * 1024
|
|
31
|
+
}
|
|
32
|
+
)))
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const actual = jest.requireActual('../partials/neostandardLint.mjs')
|
|
36
|
+
|
|
37
|
+
// Drop-in replacement for the partial module (see jest.mock in the lint/build tests): same API, real neostandard.
|
|
38
|
+
export const neostandardLint = (options) => actual.neostandardLint(options, loadEslintViaSubprocess)
|
package/gulpfile.base.js
CHANGED
|
@@ -8,18 +8,17 @@
|
|
|
8
8
|
|
|
9
9
|
const build = require('./dist/build.js')
|
|
10
10
|
const bundle = require('./dist/bundle.js')
|
|
11
|
-
const bundleLint = require('./dist/bundleLint.js')
|
|
12
11
|
const bundleMinify = require('./dist/bundleMinify.js')
|
|
13
12
|
const compileReadme = require('./dist/compileReadme.js')
|
|
14
13
|
const copyFonts = require('./dist/copyFonts.js')
|
|
15
14
|
const defaultCmd = require('./dist/default.js')
|
|
16
15
|
const dist = require('./dist/dist.js')
|
|
17
|
-
const distLint = require('./dist/distLint.js')
|
|
18
16
|
const distMinify = require('./dist/distMinify.js')
|
|
19
17
|
const gulpConfig = require('./gulp.config.js')
|
|
20
18
|
const images = require('./dist/images.js')
|
|
21
19
|
const partials = require('./dist/partials.js')
|
|
22
20
|
const sass = require('./dist/sass.js')
|
|
21
|
+
const sourceLint = require('./dist/sourceLint.js')
|
|
23
22
|
const testFull = require('./dist/testFull.js')
|
|
24
23
|
const testHelpers = require('./dist/testHelpers.js')
|
|
25
24
|
const testQuick = require('./dist/testQuick.js')
|
|
@@ -31,19 +30,18 @@ const watchTest = require('./dist/watchTest.js')
|
|
|
31
30
|
module.exports = {
|
|
32
31
|
build,
|
|
33
32
|
bundle,
|
|
34
|
-
bundleLint,
|
|
35
33
|
bundleMinify,
|
|
36
34
|
copyFonts,
|
|
37
35
|
defaultCmd,
|
|
38
36
|
docs: typeDocs,
|
|
39
37
|
dist,
|
|
40
|
-
distLint,
|
|
41
38
|
distMinify,
|
|
42
39
|
gulpConfig,
|
|
43
40
|
images,
|
|
44
41
|
partials,
|
|
45
42
|
readme: compileReadme,
|
|
46
43
|
sass,
|
|
44
|
+
sourceLint,
|
|
47
45
|
testFull,
|
|
48
46
|
testHelpers,
|
|
49
47
|
testQuick,
|
package/gulpfile.base.mjs
CHANGED
|
@@ -7,18 +7,17 @@
|
|
|
7
7
|
*/
|
|
8
8
|
export { build } from './functions/build.mjs'
|
|
9
9
|
export { bundle } from './functions/bundle.mjs'
|
|
10
|
-
export { bundleLint } from './functions/bundleLint.mjs'
|
|
11
10
|
export { bundleMinify } from './functions/bundleMinify.mjs'
|
|
12
11
|
export { compileReadme as readme } from './functions/compileReadme.mjs'
|
|
13
12
|
export { copyFonts } from './functions/copyFonts.mjs'
|
|
14
13
|
export { defaultCmd } from './functions/default.mjs'
|
|
15
14
|
export { dist } from './functions/dist.mjs'
|
|
16
|
-
export { distLint } from './functions/distLint.mjs'
|
|
17
15
|
export { distMinify } from './functions/distMinify.mjs'
|
|
18
16
|
export * as gulpConfig from './gulp.config.mjs'
|
|
19
17
|
export { images } from './functions/images.mjs'
|
|
20
18
|
export * as partials from './functions/partials.mjs'
|
|
21
19
|
export { sass } from './functions/sass.mjs'
|
|
20
|
+
export { sourceLint } from './functions/sourceLint.mjs'
|
|
22
21
|
export { testFull } from './functions/testFull.mjs'
|
|
23
22
|
export * as testHelpers from './functions/testHelpers.mjs'
|
|
24
23
|
export { testQuick } from './functions/testQuick.mjs'
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js-build-tools",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "6.0.0",
|
|
4
4
|
"description": "Standardised build process with gulp.",
|
|
5
5
|
"main": "gulpfile.base.js",
|
|
6
6
|
"exports": {
|
|
@@ -50,12 +50,13 @@
|
|
|
50
50
|
"@babel/plugin-transform-modules-commonjs": "^7.29.7",
|
|
51
51
|
"@babel/preset-env": "^7.29.7",
|
|
52
52
|
"@babel/preset-typescript": "^7.29.7",
|
|
53
|
-
"@babel/runtime-corejs3": "^8.0.
|
|
53
|
+
"@babel/runtime-corejs3": "^8.0.7",
|
|
54
54
|
"autoprefixer": "^10.6.1",
|
|
55
55
|
"babel-jest": "^30.5.2",
|
|
56
56
|
"browserify": "^17.0.1",
|
|
57
57
|
"core-js": "^3.50.0",
|
|
58
58
|
"cssnano": "^6.1.2",
|
|
59
|
+
"eslint": "^10.12.0",
|
|
59
60
|
"glob": "^13.0.6",
|
|
60
61
|
"gulp": "^5.0.1",
|
|
61
62
|
"gulp-babel": "^8.1.0",
|
|
@@ -69,11 +70,11 @@
|
|
|
69
70
|
"jest-environment-jsdom": "^30.5.2",
|
|
70
71
|
"jsdoc-to-markdown": "^9.1.3",
|
|
71
72
|
"merge-stream": "^2.0.0",
|
|
72
|
-
"
|
|
73
|
+
"neostandard": "^0.14.1",
|
|
74
|
+
"postcss": "^8.5.30",
|
|
73
75
|
"regenerator-runtime": "^0.14.1",
|
|
74
|
-
"sass": "^1.105.
|
|
75
|
-
"
|
|
76
|
-
"test-filesystem": "^1.5.1",
|
|
76
|
+
"sass": "^1.105.1",
|
|
77
|
+
"test-filesystem": "^2.0.0",
|
|
77
78
|
"through2": "^4.0.2",
|
|
78
79
|
"vinyl-source-stream": "^2.0.0"
|
|
79
80
|
},
|
package/dist/bundleLint.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
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.bundleLint = void 0
|
|
8
|
-
require('core-js/modules/esnext.iterator.constructor.js')
|
|
9
|
-
require('core-js/modules/esnext.iterator.map.js')
|
|
10
|
-
const _gulp = require('gulp')
|
|
11
|
-
const gulpConfig = _interopRequireWildcard(require('../gulp.config.js'))
|
|
12
|
-
const _standardLint = require('./partials/standardLint.js')
|
|
13
|
-
const _getBundleConfigs = require('./utilities/getBundleConfigs.js')
|
|
14
|
-
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) }
|
|
15
|
-
/**
|
|
16
|
-
* Applies Standard code style linting to every bundled file (the primary bundle, plus any
|
|
17
|
-
* additional ones from browser.bundles). The lint step itself never varies per bundle, so this is
|
|
18
|
-
* one shared src()/dest() pipeline fed every bundle's filename at once, rather than one pipeline
|
|
19
|
-
* per bundle - gulp's src()/dest() both accept an array of paths natively.
|
|
20
|
-
* @memberOf module:js-build-tools
|
|
21
|
-
* @returns {stream.Stream}
|
|
22
|
-
*/
|
|
23
|
-
const bundleLint = () => (0, _gulp.src)((0, _getBundleConfigs.getBundleConfigs)().map(({
|
|
24
|
-
name
|
|
25
|
-
}) => `${gulpConfig.get('browser.to')}/${name}.js`)).pipe((0, _standardLint.standardLint)({
|
|
26
|
-
fix: true
|
|
27
|
-
})).pipe((0, _gulp.dest)(gulpConfig.get('browser.to')))
|
|
28
|
-
exports.bundleLint = bundleLint
|
package/dist/bundleLint.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.bundleLint=void 0,require("core-js/modules/esnext.iterator.constructor.js"),require("core-js/modules/esnext.iterator.map.js");var _gulp=require("gulp"),gulpConfig=_interopRequireWildcard(require("../gulp.config.js")),_standardLint=require("./partials/standardLint.js"),_getBundleConfigs=require("./utilities/getBundleConfigs.js");function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var r=new WeakMap,n=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var i,o,u={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return u;if(i=t?n:r){if(i.has(e))return i.get(e);i.set(e,u)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((o=(i=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(o.get||o.set)?i(u,t,o):u[t]=e[t]);return u})(e,t)}const bundleLint=()=>(0,_gulp.src)((0,_getBundleConfigs.getBundleConfigs)().map(({name:e})=>`${gulpConfig.get("browser.to")}/${e}.js`)).pipe((0,_standardLint.standardLint)({fix:!0})).pipe((0,_gulp.dest)(gulpConfig.get("browser.to")));exports.bundleLint=bundleLint;
|
package/dist/distLint.js
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
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.distLint = void 0
|
|
8
|
-
const gulpConfig = _interopRequireWildcard(require('../gulp.config.js'))
|
|
9
|
-
const _gulp = require('gulp')
|
|
10
|
-
const _standardLint = require('./partials/standardLint.js')
|
|
11
|
-
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) }
|
|
12
|
-
/**
|
|
13
|
-
* Applies Standard code style linting to distribution files.
|
|
14
|
-
* @memberOf module:js-build-tools
|
|
15
|
-
* @returns {*}
|
|
16
|
-
*/
|
|
17
|
-
const distLint = () => (0, _gulp.src)(gulpConfig.get('browser.from')).pipe((0, _standardLint.standardLint)({
|
|
18
|
-
fix: true
|
|
19
|
-
})).pipe((0, _gulp.dest)(gulpConfig.get('dist.to')))
|
|
20
|
-
exports.distLint = distLint
|
package/dist/distLint.min.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
"use strict";require("core-js/modules/esnext.weak-map.delete-all.js"),Object.defineProperty(exports,"__esModule",{value:!0}),exports.distLint=void 0;var gulpConfig=_interopRequireWildcard(require("../gulp.config.js")),_gulp=require("gulp"),_standardLint=require("./partials/standardLint.js");function _interopRequireWildcard(e,t){if("function"==typeof WeakMap)var r=new WeakMap,i=new WeakMap;return(_interopRequireWildcard=function(e,t){if(!t&&e&&e.__esModule)return e;var n,o,s={__proto__:null,default:e};if(null===e||"object"!=typeof e&&"function"!=typeof e)return s;if(n=t?i:r){if(n.has(e))return n.get(e);n.set(e,s)}for(const t in e)"default"!==t&&{}.hasOwnProperty.call(e,t)&&((o=(n=Object.defineProperty)&&Object.getOwnPropertyDescriptor(e,t))&&(o.get||o.set)?n(s,t,o):s[t]=e[t]);return s})(e,t)}const distLint=()=>(0,_gulp.src)(gulpConfig.get("browser.from")).pipe((0,_standardLint.standardLint)({fix:!0})).pipe((0,_gulp.dest)(gulpConfig.get("dist.to")));exports.distLint=distLint;
|
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.standardLint = void 0;
|
|
7
|
-
require("core-js/modules/esnext.iterator.constructor.js");
|
|
8
|
-
require("core-js/modules/esnext.iterator.for-each.js");
|
|
9
|
-
var _nodePath = _interopRequireDefault(require("node:path"));
|
|
10
|
-
var _through = _interopRequireDefault(require("through2"));
|
|
11
|
-
var _loadPeer = require("./loadPeer.js");
|
|
12
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
|
-
// `standard` (17+) ships ESM-only, see importModule for how it is imported.
|
|
14
|
-
const importStandard = () => (0, _loadPeer.importModule)('standard');
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Print a file's lint messages, if it has any.
|
|
18
|
-
* @memberOf module:partials
|
|
19
|
-
* @param {import('vinyl')} file
|
|
20
|
-
* @param {{messages: Array<{line: number, column: number, message: string}>, errorCount: number, warningCount: number}} result
|
|
21
|
-
* @returns {undefined}
|
|
22
|
-
*/
|
|
23
|
-
const printFileReport = (file, result) => {
|
|
24
|
-
if (!result.messages.length) {
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
console.log(_nodePath.default.relative(file.cwd, file.path));
|
|
28
|
-
result.messages.forEach(({
|
|
29
|
-
line,
|
|
30
|
-
column,
|
|
31
|
-
message
|
|
32
|
-
}) => console.log(`line ${line}:${column}\t${message}`));
|
|
33
|
-
console.log(`✖ ${result.errorCount} error\t⚠ ${result.warningCount} warning\n`);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
/**
|
|
37
|
-
* Lint every file streaming through with JavaScript Standard Style and, unless `fix` is false, apply the automatic
|
|
38
|
-
* fixes to the file's contents so a following `dest()` writes the fixed version. Remaining problems are printed
|
|
39
|
-
* along with a summary once the stream ends; they never fail the build.
|
|
40
|
-
*
|
|
41
|
-
* Project-level Standard configuration (the `standard` field in package.json: ignore, env, globals, ...) is honored
|
|
42
|
-
* because the file's own path and cwd are handed to Standard.
|
|
43
|
-
* @memberOf module:partials
|
|
44
|
-
* @param {Object} [options={}]
|
|
45
|
-
* @param {boolean} [options.fix=true] - Apply Standard's automatic fixes to the file contents.
|
|
46
|
-
* @param {function(): Promise<{lintText: Function}>} [loadStandard] - Resolves the `standard` module. Real callers
|
|
47
|
-
* should never need to pass this - it exists so tests can supply a stand-in, since this project's
|
|
48
|
-
* CommonJS-transform-based Jest setup cannot execute a real dynamic import() of an ES module.
|
|
49
|
-
* @returns {import('stream').Transform}
|
|
50
|
-
*/
|
|
51
|
-
const standardLint = ({
|
|
52
|
-
fix = true
|
|
53
|
-
} = {}, loadStandard = () => importStandard().then(({
|
|
54
|
-
default: standard
|
|
55
|
-
}) => standard)) => {
|
|
56
|
-
const totals = {
|
|
57
|
-
errors: 0,
|
|
58
|
-
warnings: 0
|
|
59
|
-
};
|
|
60
|
-
return _through.default.obj(function (file, enc, callback) {
|
|
61
|
-
if (file.isNull()) {
|
|
62
|
-
callback(null, file);
|
|
63
|
-
return;
|
|
64
|
-
}
|
|
65
|
-
if (file.isStream()) {
|
|
66
|
-
callback(new Error('standardLint: streaming file contents are not supported.'));
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
loadStandard().then(standard => standard.lintText(file.contents.toString(), {
|
|
70
|
-
filename: file.path,
|
|
71
|
-
cwd: file.cwd,
|
|
72
|
-
fix
|
|
73
|
-
})).then(results => {
|
|
74
|
-
// No result at all means the file is ignored by the project's Standard configuration.
|
|
75
|
-
const [result] = results;
|
|
76
|
-
if (result) {
|
|
77
|
-
if (typeof result.output === 'string') {
|
|
78
|
-
file.contents = Buffer.from(result.output);
|
|
79
|
-
}
|
|
80
|
-
totals.errors += result.errorCount;
|
|
81
|
-
totals.warnings += result.warningCount;
|
|
82
|
-
printFileReport(file, result);
|
|
83
|
-
}
|
|
84
|
-
callback(null, file);
|
|
85
|
-
}, callback);
|
|
86
|
-
}, function (callback) {
|
|
87
|
-
console.log('Standard linter results');
|
|
88
|
-
console.log('======================================');
|
|
89
|
-
console.log(`✖ Errors total: ${totals.errors}`);
|
|
90
|
-
console.log(`⚠ Warnings total: ${totals.warnings}\n`);
|
|
91
|
-
callback();
|
|
92
|
-
});
|
|
93
|
-
};
|
|
94
|
-
exports.standardLint = standardLint;
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.standardLint = exports.loadStandardViaSubprocess = void 0;
|
|
7
|
-
require("core-js/modules/es.json.stringify.js");
|
|
8
|
-
var _nodeChild_process = require("node:child_process");
|
|
9
|
-
// Jest's CommonJS transform cannot load `standard` (ESM-only) or run a real dynamic import(), so tests that need
|
|
10
|
-
// genuine Standard behavior run the actual `standard` package in a plain Node subprocess instead of faking it.
|
|
11
|
-
const script = 'import { readFileSync } from \'node:fs\'\n' + 'import standard from \'standard\'\n' + 'const { text, options } = JSON.parse(readFileSync(0, \'utf8\'))\n' + 'process.stdout.write(JSON.stringify(await standard.lintText(text, options)))\n';
|
|
12
|
-
const loadStandardViaSubprocess = () => Promise.resolve({
|
|
13
|
-
lintText: (text, options) => Promise.resolve().then(() => JSON.parse((0, _nodeChild_process.execFileSync)(process.execPath, ['--input-type=module', '--eval', script], {
|
|
14
|
-
input: JSON.stringify({
|
|
15
|
-
text,
|
|
16
|
-
options
|
|
17
|
-
}),
|
|
18
|
-
encoding: 'utf8',
|
|
19
|
-
cwd: process.cwd(),
|
|
20
|
-
maxBuffer: 256 * 1024 * 1024
|
|
21
|
-
})))
|
|
22
|
-
});
|
|
23
|
-
exports.loadStandardViaSubprocess = loadStandardViaSubprocess;
|
|
24
|
-
const actual = jest.requireActual('../partials/standardLint.js');
|
|
25
|
-
|
|
26
|
-
// Drop-in replacement for the partial module (see jest.mock in the lint/build tests): same API, real Standard.
|
|
27
|
-
const standardLint = options => actual.standardLint(options, loadStandardViaSubprocess);
|
|
28
|
-
exports.standardLint = standardLint;
|