js-build-tools 6.4.0 → 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.
|
@@ -8,6 +8,7 @@ exports.lintSource = void 0;
|
|
|
8
8
|
var gulpConfig = _interopRequireWildcard(require("../../gulp.config.js"));
|
|
9
9
|
var _gulp = require("gulp");
|
|
10
10
|
var _neostandardLint = require("./neostandardLint.js");
|
|
11
|
+
var _nodeStream = require("node:stream");
|
|
11
12
|
var cache;
|
|
12
13
|
function _interopRequireWildcard(e, t) { if (!t && e && e.__esModule) return e; var r, c, a = Object.defineProperty, n = { __proto__: null, default: e }; if (Object(e) !== e) return n; if (cache || "function" != typeof WeakMap || (cache = new WeakMap()), cache) { if (cache.has(e)) return cache.get(e); cache.set(e, n); } for (c in e) "default" !== c && {}.hasOwnProperty.call(e, c) && ((r = a && Object.getOwnPropertyDescriptor(e, c)) && (r.get || r.set) ? a(n, c, r) : n[c] = e[c]); return n; }
|
|
13
14
|
/**
|
|
@@ -30,12 +31,22 @@ const lintSource = ({
|
|
|
30
31
|
const linter = (0, _neostandardLint.neostandardLint)({
|
|
31
32
|
fix: true,
|
|
32
33
|
ts,
|
|
33
|
-
rules: gulpConfig.get('lint.rules')
|
|
34
|
-
failOnError
|
|
34
|
+
rules: gulpConfig.get('lint.rules')
|
|
35
35
|
});
|
|
36
|
-
|
|
37
|
-
//
|
|
38
|
-
|
|
36
|
+
// Fail only once dest() has written every fixed file: gulp exits as soon as a task fails, so failing from the
|
|
37
|
+
// linter itself (before dest() finished) could leave a file that dest() had opened, but not yet written, empty.
|
|
38
|
+
// dest() passes each file on only after writing it, so this last step's flush runs after the final write. Files
|
|
39
|
+
// are consumed here rather than passed on, so nothing downstream has to read them.
|
|
40
|
+
const written = new _nodeStream.Transform({
|
|
41
|
+
objectMode: true,
|
|
42
|
+
transform: (file, enc, callback) => callback(),
|
|
43
|
+
flush: callback => failOnError && linter.totals.errors ? callback(new Error(`neostandard found ${linter.totals.errors} lint error(s) that could not be fixed automatically.`)) : callback()
|
|
44
|
+
});
|
|
45
|
+
const saved = (0, _gulp.src)(patterns).pipe(linter).pipe((0, _gulp.dest)(srcPath));
|
|
46
|
+
saved.pipe(written);
|
|
47
|
+
// pipe() does not forward errors, and gulp only watches the returned stream, so pass any failure along.
|
|
48
|
+
linter.on('error', error => written.destroy(error));
|
|
49
|
+
saved.on('error', error => written.destroy(error));
|
|
39
50
|
return written;
|
|
40
51
|
};
|
|
41
52
|
exports.lintSource = lintSource;
|
|
@@ -113,7 +113,7 @@ const printFileReport = (file, result) => {
|
|
|
113
113
|
* @param {function(Object): Promise<{lintText: Function}>} [loadEslint] - Resolves an ESLint-shaped linter. Real
|
|
114
114
|
* callers should never need to pass this - it exists so tests can supply a stand-in, since this project's
|
|
115
115
|
* CommonJS-transform-based Jest setup cannot execute a real dynamic import() of neostandard (ESM-only).
|
|
116
|
-
* @returns {stream.Transform}
|
|
116
|
+
* @returns {stream.Transform} With a `totals` property ({errors, warnings}), complete once the stream ends.
|
|
117
117
|
*/
|
|
118
118
|
const neostandardLint = ({
|
|
119
119
|
fix = true,
|
|
@@ -126,7 +126,7 @@ const neostandardLint = ({
|
|
|
126
126
|
warnings: 0
|
|
127
127
|
};
|
|
128
128
|
let eslintPromise = null;
|
|
129
|
-
|
|
129
|
+
const linter = _through.default.obj(function (file, enc, callback) {
|
|
130
130
|
if (file.isNull()) {
|
|
131
131
|
callback(null, file);
|
|
132
132
|
return;
|
|
@@ -169,5 +169,8 @@ const neostandardLint = ({
|
|
|
169
169
|
}
|
|
170
170
|
callback();
|
|
171
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;
|
|
172
175
|
};
|
|
173
176
|
exports.neostandardLint = neostandardLint;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as gulpConfig from '../../gulp.config.mjs'
|
|
2
2
|
import { dest, src } from 'gulp'
|
|
3
3
|
import { neostandardLint } from './neostandardLint.mjs'
|
|
4
|
+
import { Transform } from 'node:stream'
|
|
4
5
|
|
|
5
6
|
/**
|
|
6
7
|
* Lint the project's source (srcPath: .js, .mjs and .cjs, plus .ts when typescript.enabled) with neostandard and
|
|
@@ -17,11 +18,24 @@ export const lintSource = ({ failOnError = false } = {}) => {
|
|
|
17
18
|
if (ts) {
|
|
18
19
|
patterns.push(`${srcPath}/**/*.ts`)
|
|
19
20
|
}
|
|
20
|
-
const linter = neostandardLint({ fix: true, ts, rules: gulpConfig.get('lint.rules')
|
|
21
|
-
|
|
21
|
+
const linter = neostandardLint({ fix: true, ts, rules: gulpConfig.get('lint.rules') })
|
|
22
|
+
// Fail only once dest() has written every fixed file: gulp exits as soon as a task fails, so failing from the
|
|
23
|
+
// linter itself (before dest() finished) could leave a file that dest() had opened, but not yet written, empty.
|
|
24
|
+
// dest() passes each file on only after writing it, so this last step's flush runs after the final write. Files
|
|
25
|
+
// are consumed here rather than passed on, so nothing downstream has to read them.
|
|
26
|
+
const written = new Transform({
|
|
27
|
+
objectMode: true,
|
|
28
|
+
transform: (file, enc, callback) => callback(),
|
|
29
|
+
flush: callback => failOnError && linter.totals.errors
|
|
30
|
+
? callback(new Error(`neostandard found ${linter.totals.errors} lint error(s) that could not be fixed automatically.`))
|
|
31
|
+
: callback()
|
|
32
|
+
})
|
|
33
|
+
const saved = src(patterns)
|
|
22
34
|
.pipe(linter)
|
|
23
35
|
.pipe(dest(srcPath))
|
|
24
|
-
|
|
25
|
-
|
|
36
|
+
saved.pipe(written)
|
|
37
|
+
// pipe() does not forward errors, and gulp only watches the returned stream, so pass any failure along.
|
|
38
|
+
linter.on('error', error => written.destroy(error))
|
|
39
|
+
saved.on('error', error => written.destroy(error))
|
|
26
40
|
return written
|
|
27
41
|
}
|
|
@@ -87,7 +87,7 @@ const printFileReport = (file, result) => {
|
|
|
87
87
|
* @param {function(Object): Promise<{lintText: Function}>} [loadEslint] - Resolves an ESLint-shaped linter. Real
|
|
88
88
|
* callers should never need to pass this - it exists so tests can supply a stand-in, since this project's
|
|
89
89
|
* CommonJS-transform-based Jest setup cannot execute a real dynamic import() of neostandard (ESM-only).
|
|
90
|
-
* @returns {stream.Transform}
|
|
90
|
+
* @returns {stream.Transform} With a `totals` property ({errors, warnings}), complete once the stream ends.
|
|
91
91
|
*/
|
|
92
92
|
export const neostandardLint = (
|
|
93
93
|
{ fix = true, ts = false, rules = {}, failOnError = false } = {},
|
|
@@ -95,7 +95,7 @@ export const neostandardLint = (
|
|
|
95
95
|
) => {
|
|
96
96
|
const totals = { errors: 0, warnings: 0 }
|
|
97
97
|
let eslintPromise = null
|
|
98
|
-
|
|
98
|
+
const linter = through.obj(
|
|
99
99
|
function (file, enc, callback) {
|
|
100
100
|
if (file.isNull()) {
|
|
101
101
|
callback(null, file)
|
|
@@ -136,4 +136,7 @@ export const neostandardLint = (
|
|
|
136
136
|
callback()
|
|
137
137
|
}
|
|
138
138
|
)
|
|
139
|
+
// Read by lintSource, which can only fail once the fixed files have been written, after this stream has ended.
|
|
140
|
+
linter.totals = totals
|
|
141
|
+
return linter
|
|
139
142
|
}
|
|
@@ -143,4 +143,24 @@ describe('lint', () => {
|
|
|
143
143
|
done(new Error('lint should have failed on the unused variable'))
|
|
144
144
|
})
|
|
145
145
|
}, 20000)
|
|
146
|
+
|
|
147
|
+
test('only fails once every fixed file has been written back', done => {
|
|
148
|
+
// gulp exits as soon as a task fails, so failing while a file is still being written can leave that file empty.
|
|
149
|
+
const srcPath = gulpConfig.get('srcPath')
|
|
150
|
+
const fixable = ['a', 'b', 'c'].map(name => `${srcPath}/fixable-${name}.js`)
|
|
151
|
+
fixable.forEach(file => fs.writeFileSync(file, 'const x = "y";\n\nmodule.exports = x;\n'))
|
|
152
|
+
fs.writeFileSync(`${srcPath}/unfixable.js`, 'const unused = 1\n')
|
|
153
|
+
const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
|
|
154
|
+
expect.assertions(fixable.length)
|
|
155
|
+
lint()
|
|
156
|
+
.on('error', () => {
|
|
157
|
+
logSpy.mockRestore()
|
|
158
|
+
fixable.forEach(file => expect(fs.readFileSync(file).toString()).toEqual('const x = \'y\'\n\nmodule.exports = x\n'))
|
|
159
|
+
done()
|
|
160
|
+
})
|
|
161
|
+
.on('finish', () => {
|
|
162
|
+
logSpy.mockRestore()
|
|
163
|
+
done(new Error('lint should have failed on the unused variable'))
|
|
164
|
+
})
|
|
165
|
+
}, 30000)
|
|
146
166
|
})
|