js-build-tools 6.5.0 → 6.7.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.
Files changed (169) hide show
  1. package/LICENSE +674 -674
  2. package/README.md +762 -692
  3. package/babel.config.js +28 -28
  4. package/dist/build.js +75 -75
  5. package/dist/bundle.js +19 -19
  6. package/dist/bundleMinify.js +7 -7
  7. package/dist/compileReadme.js +4 -4
  8. package/dist/copyFiles.js +17 -17
  9. package/dist/copyFonts.js +4 -4
  10. package/dist/default.js +5 -5
  11. package/dist/dist.js +4 -4
  12. package/dist/distMinify.js +4 -4
  13. package/dist/docs.js +7 -7
  14. package/dist/images.js +4 -4
  15. package/dist/jsdocDocs.js +6 -6
  16. package/dist/lint.js +16 -16
  17. package/dist/partials/addToReadme.js +9 -9
  18. package/dist/partials/beginWatcher.js +4 -4
  19. package/dist/partials/clean.js +5 -5
  20. package/dist/partials/copyFor.js +9 -9
  21. package/dist/partials/distFor.js +6 -6
  22. package/dist/partials/distForSrc.js +5 -5
  23. package/dist/partials/distSeries.js +7 -7
  24. package/dist/partials/imagesFor.js +93 -56
  25. package/dist/partials/jsdocDocsFor.js +46 -46
  26. package/dist/partials/lintSource.js +51 -51
  27. package/dist/partials/loadPeer.js +99 -99
  28. package/dist/partials/loadPlaywright.js +14 -14
  29. package/dist/partials/minifyFor.js +20 -20
  30. package/dist/partials/neostandardLint.js +175 -175
  31. package/dist/partials/readmeTemplate.js +4 -4
  32. package/dist/partials/removeDirectory.js +11 -11
  33. package/dist/partials/resolveDocsMethod.js +6 -6
  34. package/dist/partials/runOnChange.js +31 -31
  35. package/dist/partials/sassFor.js +6 -6
  36. package/dist/partials/serveStatic.js +9 -9
  37. package/dist/partials/tsFor.js +32 -32
  38. package/dist/partials/typeDocsFor.js +57 -51
  39. package/dist/partials.js +176 -176
  40. package/dist/sourceLint.js +18 -18
  41. package/dist/test-helpers/isolateGulpCache.js +24 -24
  42. package/dist/test-helpers/setUp.js +4 -4
  43. package/dist/testFull.js +5 -5
  44. package/dist/testQuick.js +5 -5
  45. package/dist/typeDocs.js +5 -5
  46. package/dist/typeScript.js +4 -4
  47. package/dist/utilities/convertMjsFilesForDocs.js +12 -12
  48. package/dist/utilities/dotGet.js +54 -54
  49. package/dist/utilities/dotNotate.js +79 -79
  50. package/dist/utilities/dotSet.js +45 -45
  51. package/dist/utilities/esmNamedExportsToCjs.js +15 -15
  52. package/dist/utilities/getBundleConfigs.js +9 -9
  53. package/dist/utilities/isObject.js +6 -6
  54. package/dist/utilities/strAfter.js +7 -7
  55. package/dist/utilities/strBefore.js +7 -7
  56. package/dist/watchFull.js +4 -4
  57. package/dist/watchTest.js +4 -4
  58. package/functions/build.mjs +72 -72
  59. package/functions/build.test.mjs +763 -759
  60. package/functions/bundle.mjs +44 -44
  61. package/functions/bundle.test.mjs +219 -219
  62. package/functions/bundleMinify.mjs +16 -16
  63. package/functions/bundleMinify.test.mjs +37 -37
  64. package/functions/compileReadme.mjs +9 -9
  65. package/functions/compileReadme.test.mjs +18 -18
  66. package/functions/copyFiles.mjs +32 -32
  67. package/functions/copyFiles.test.mjs +78 -78
  68. package/functions/copyFonts.mjs +9 -9
  69. package/functions/copyFonts.test.mjs +32 -32
  70. package/functions/default.mjs +12 -12
  71. package/functions/default.test.mjs +33 -33
  72. package/functions/dist.mjs +8 -8
  73. package/functions/dist.test.mjs +44 -44
  74. package/functions/distMinify.mjs +9 -9
  75. package/functions/distMinify.test.mjs +15 -15
  76. package/functions/docs.mjs +13 -13
  77. package/functions/docs.test.mjs +45 -45
  78. package/functions/gulpConfigEntries.test.mjs +23 -23
  79. package/functions/images.mjs +8 -8
  80. package/functions/images.test.mjs +142 -142
  81. package/functions/jsdocDocs.mjs +10 -10
  82. package/functions/jsdocEsmExports.test.mjs +24 -24
  83. package/functions/lint.mjs +9 -9
  84. package/functions/partials/addToReadme.mjs +25 -25
  85. package/functions/partials/addToReadme.test.mjs +34 -34
  86. package/functions/partials/beginWatcher.mjs +9 -9
  87. package/functions/partials/beginWatcher.test.mjs +19 -19
  88. package/functions/partials/clean.mjs +13 -13
  89. package/functions/partials/clean.test.mjs +22 -22
  90. package/functions/partials/copyFor.mjs +15 -15
  91. package/functions/partials/copyFor.test.mjs +53 -53
  92. package/functions/partials/distFor.mjs +22 -22
  93. package/functions/partials/distFor.test.mjs +195 -195
  94. package/functions/partials/distForSrc.mjs +11 -11
  95. package/functions/partials/distForSrc.test.mjs +18 -18
  96. package/functions/partials/distSeries.mjs +21 -21
  97. package/functions/partials/distSeries.test.mjs +34 -34
  98. package/functions/partials/imagesFor.mjs +83 -50
  99. package/functions/partials/imagesFor.test.mjs +287 -229
  100. package/functions/partials/jsdocDocsFor.mjs +163 -152
  101. package/functions/partials/jsdocDocsFor.test.mjs +182 -152
  102. package/functions/partials/lintSource.mjs +41 -41
  103. package/functions/partials/loadPeer.mjs +76 -76
  104. package/functions/partials/loadPeer.test.mjs +58 -58
  105. package/functions/partials/loadPlaywright.mjs +23 -23
  106. package/functions/partials/loadPlaywright.test.mjs +70 -70
  107. package/functions/partials/minifyFor.mjs +15 -15
  108. package/functions/partials/minifyFor.test.mjs +49 -49
  109. package/functions/partials/neostandardLint.mjs +142 -142
  110. package/functions/partials/neostandardLint.test.mjs +131 -131
  111. package/functions/partials/readmeTemplate.mjs +12 -12
  112. package/functions/partials/readmeTemplate.test.mjs +34 -34
  113. package/functions/partials/removeDirectory.mjs +34 -34
  114. package/functions/partials/removeDirectory.test.mjs +72 -72
  115. package/functions/partials/resolveDocsMethod.mjs +10 -10
  116. package/functions/partials/resolveDocsMethod.test.mjs +33 -33
  117. package/functions/partials/runOnChange.mjs +54 -54
  118. package/functions/partials/runOnChange.test.mjs +95 -95
  119. package/functions/partials/sassFor.mjs +25 -25
  120. package/functions/partials/sassFor.test.mjs +81 -81
  121. package/functions/partials/serveStatic.mjs +47 -47
  122. package/functions/partials/serveStatic.test.mjs +71 -71
  123. package/functions/partials/tsFor.mjs +92 -92
  124. package/functions/partials/tsFor.test.mjs +88 -88
  125. package/functions/partials/typeDocsFor.mjs +231 -227
  126. package/functions/partials/typeDocsFor.test.mjs +263 -252
  127. package/functions/partials.mjs +31 -31
  128. package/functions/partials.test.mjs +7 -7
  129. package/functions/sass.mjs +4 -4
  130. package/functions/sass.test.mjs +31 -31
  131. package/functions/sourceLint.mjs +13 -13
  132. package/functions/sourceLint.test.mjs +166 -166
  133. package/functions/test-helpers/isolateGulpCache.mjs +16 -16
  134. package/functions/test-helpers/neostandardLintWithRealNeostandard.mjs +40 -40
  135. package/functions/test-helpers/setUp.mjs +100 -100
  136. package/functions/test-helpers/setUp.test.mjs +19 -19
  137. package/functions/testFull.mjs +17 -17
  138. package/functions/testFull.test.mjs +17 -17
  139. package/functions/testHelpers.mjs +10 -10
  140. package/functions/testHelpers.test.mjs +7 -7
  141. package/functions/testQuick.mjs +17 -17
  142. package/functions/testQuick.test.mjs +17 -17
  143. package/functions/typeDocs.mjs +9 -9
  144. package/functions/typeDocs.test.mjs +11 -11
  145. package/functions/typeScript.mjs +8 -8
  146. package/functions/typeScript.test.mjs +11 -11
  147. package/functions/utilities/convertMjsFilesForDocs.mjs +34 -34
  148. package/functions/utilities/convertMjsFilesForDocs.test.mjs +58 -58
  149. package/functions/utilities/dotGet.mjs +49 -49
  150. package/functions/utilities/dotNotate.mjs +73 -73
  151. package/functions/utilities/dotNotate.test.mjs +41 -41
  152. package/functions/utilities/dotSet.mjs +40 -40
  153. package/functions/utilities/esmNamedExportsToCjs.mjs +30 -30
  154. package/functions/utilities/esmNamedExportsToCjs.test.mjs +47 -47
  155. package/functions/utilities/getBundleConfigs.mjs +30 -30
  156. package/functions/utilities/isObject.mjs +8 -8
  157. package/functions/utilities/strAfter.mjs +12 -12
  158. package/functions/utilities/strBefore.mjs +12 -12
  159. package/functions/watchFull.mjs +9 -9
  160. package/functions/watchFull.test.mjs +41 -41
  161. package/functions/watchTest.mjs +10 -10
  162. package/functions/watchTest.test.mjs +49 -49
  163. package/gulp.config.js +4 -4
  164. package/gulp.config.mjs +344 -327
  165. package/gulpfile.base.js +51 -51
  166. package/gulpfile.base.mjs +29 -29
  167. package/jsdoc.base.js +16 -16
  168. package/jsdoc.esmExports.js +17 -17
  169. package/package.json +146 -145
@@ -1,31 +1,31 @@
1
- import fs from 'fs'
2
- import * as setUp from './test-helpers/setUp.mjs'
3
- import { sass } from './sass.mjs'
4
-
5
- setUp.setDefaults('test-sass')
6
- const gulpConfig = setUp.gulpConfig
7
-
8
- beforeEach(() => setUp.beforeEach().then(
9
- () => {
10
- const sassPath = gulpConfig.get('sass.path')
11
- return fs.mkdirSync(sassPath, { recursive: true })
12
- }
13
- ))
14
-
15
- afterEach(setUp.afterEach)
16
-
17
- describe('sass', () => {
18
- test('uses the configured paths', done => {
19
- const sassPath = gulpConfig.get('sass.path')
20
- expect.assertions(1)
21
- sass()
22
- .on('finish', () => {
23
- expect(fs.existsSync(sassPath)).toBeTruthy()
24
- done()
25
- })
26
- .on('error', error => {
27
- console.error('Encountered error', error)
28
- done()
29
- })
30
- }, 10000)
31
- })
1
+ import fs from 'fs'
2
+ import * as setUp from './test-helpers/setUp.mjs'
3
+ import { sass } from './sass.mjs'
4
+
5
+ setUp.setDefaults('test-sass')
6
+ const gulpConfig = setUp.gulpConfig
7
+
8
+ beforeEach(() => setUp.beforeEach().then(
9
+ () => {
10
+ const sassPath = gulpConfig.get('sass.path')
11
+ return fs.mkdirSync(sassPath, { recursive: true })
12
+ }
13
+ ))
14
+
15
+ afterEach(setUp.afterEach)
16
+
17
+ describe('sass', () => {
18
+ test('uses the configured paths', done => {
19
+ const sassPath = gulpConfig.get('sass.path')
20
+ expect.assertions(1)
21
+ sass()
22
+ .on('finish', () => {
23
+ expect(fs.existsSync(sassPath)).toBeTruthy()
24
+ done()
25
+ })
26
+ .on('error', error => {
27
+ console.error('Encountered error', error)
28
+ done()
29
+ })
30
+ }, 10000)
31
+ })
@@ -1,13 +1,13 @@
1
- import { lintSource } from './partials/lintSource.mjs'
2
-
3
- /**
4
- * Applies neostandard linting (js-build-tools' chosen style) to the real, hand-written source - not the compiled
5
- * dist/browser output, which is generated and so was never going to pass a hand-authored-code style check (every
6
- * compiler/bundler emits its own boilerplate - import aliasing, interop headers - that only looks like a style
7
- * violation). Includes test files: there is no reason to hold tests to a lower style bar than the rest of the
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.
10
- * @memberOf module:js-build-tools
11
- * @returns {*}
12
- */
13
- export const sourceLint = () => lintSource()
1
+ import { lintSource } from './partials/lintSource.mjs'
2
+
3
+ /**
4
+ * Applies neostandard linting (js-build-tools' chosen style) to the real, hand-written source - not the compiled
5
+ * dist/browser output, which is generated and so was never going to pass a hand-authored-code style check (every
6
+ * compiler/bundler emits its own boilerplate - import aliasing, interop headers - that only looks like a style
7
+ * violation). Includes test files: there is no reason to hold tests to a lower style bar than the rest of the
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.
10
+ * @memberOf module:js-build-tools
11
+ * @returns {*}
12
+ */
13
+ export const sourceLint = () => lintSource()
@@ -1,166 +1,166 @@
1
- /* eslint-disable no-template-curly-in-string -- fixture source code, the ${...} is meant to stay literal */
2
- import fs from 'fs'
3
- import * as setUp from './test-helpers/setUp.mjs'
4
- import { lint } from './lint.mjs'
5
- import { sourceLint } from './sourceLint.mjs'
6
- import { countMatches } from 'test-filesystem'
7
-
8
- // Run the real neostandard (in a subprocess) - Jest's CommonJS transform can't load the ESM-only package itself.
9
- jest.mock('./partials/neostandardLint.mjs', () => require('./test-helpers/neostandardLintWithRealNeostandard.mjs'))
10
-
11
- setUp.setDefaults('test-source-lint')
12
- const gulpConfig = setUp.gulpConfig
13
-
14
- const lintableContents = 'const x = "a";\n' +
15
- '\n' +
16
- 'module.exports = x;\n'
17
-
18
- const lintableTestContents = 'const y = "b";\n' +
19
- '\n' +
20
- 'module.exports = y;\n'
21
-
22
- beforeEach(
23
- () => setUp.beforeEach()
24
- .then(
25
- async () => {
26
- const srcPath = gulpConfig.get('srcPath')
27
- await fs.mkdirSync(srcPath, { recursive: true })
28
- fs.writeFileSync(`${srcPath}/example.js`, lintableContents)
29
- return fs.writeFileSync(`${srcPath}/example.test.js`, lintableTestContents)
30
- }
31
- )
32
- )
33
-
34
- afterEach(setUp.afterEach)
35
-
36
- describe('sourceLint', () => {
37
- test('fixes the real source in place, including test files', done => {
38
- const srcPath = gulpConfig.get('srcPath')
39
- expect.assertions(4)
40
- sourceLint()
41
- .on('finish', () => {
42
- const linted = fs.readFileSync(`${srcPath}/example.js`).toString()
43
- expect(countMatches(linted, '"')).toEqual(0)
44
- expect(countMatches(linted, ';')).toEqual(0)
45
- const lintedTest = fs.readFileSync(`${srcPath}/example.test.js`).toString()
46
- expect(countMatches(lintedTest, '"')).toEqual(0)
47
- expect(countMatches(lintedTest, ';')).toEqual(0)
48
- done()
49
- })
50
- .on('error', error => {
51
- console.error('Encountered error', error)
52
- done(error)
53
- })
54
- }, 20000)
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
-
73
- test('lint.rules actually suppresses a real neostandard finding', done => {
74
- const srcPath = gulpConfig.get('srcPath')
75
- // A fixture string containing literal ${...} text (simulating real module source, not an accidental
76
- // non-template string) - neostandard's no-template-curly-in-string rule flags this as an error by default.
77
- const fixtureContents = 'const fixture = \'import(`imagemin-${pluginName}`)\'\n\nmodule.exports = fixture\n'
78
- fs.writeFileSync(`${srcPath}/fixture.js`, fixtureContents)
79
- gulpConfig.set('lint.rules', { 'no-template-curly-in-string': 'off' })
80
- const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
81
- expect.assertions(1)
82
- sourceLint()
83
- .on('finish', () => {
84
- gulpConfig.set('lint.rules', {})
85
- expect(logSpy.mock.calls.flat().join('\n')).not.toMatch(/no-template-curly-in-string|template string expression/)
86
- logSpy.mockRestore()
87
- done()
88
- })
89
- .on('error', error => {
90
- gulpConfig.set('lint.rules', {})
91
- logSpy.mockRestore()
92
- console.error('Encountered error', error)
93
- done(error)
94
- })
95
- }, 20000)
96
-
97
- test('also lints .ts source when typescript.enabled', done => {
98
- const srcPath = gulpConfig.get('srcPath')
99
- gulpConfig.set('typescript.enabled', true)
100
- fs.writeFileSync(`${srcPath}/example.ts`, 'const z: string = "c";\n\nexport default z;\n')
101
- expect.assertions(2)
102
- sourceLint()
103
- .on('finish', () => {
104
- gulpConfig.set('typescript.enabled', false)
105
- const linted = fs.readFileSync(`${srcPath}/example.ts`).toString()
106
- expect(countMatches(linted, '"')).toEqual(0)
107
- expect(countMatches(linted, ';')).toEqual(0)
108
- done()
109
- })
110
- .on('error', error => {
111
- gulpConfig.set('typescript.enabled', false)
112
- console.error('Encountered error', error)
113
- done(error)
114
- })
115
- }, 20000)
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
-
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)
166
- })
1
+ /* eslint-disable no-template-curly-in-string -- fixture source code, the ${...} is meant to stay literal */
2
+ import fs from 'fs'
3
+ import * as setUp from './test-helpers/setUp.mjs'
4
+ import { lint } from './lint.mjs'
5
+ import { sourceLint } from './sourceLint.mjs'
6
+ import { countMatches } from 'test-filesystem'
7
+
8
+ // Run the real neostandard (in a subprocess) - Jest's CommonJS transform can't load the ESM-only package itself.
9
+ jest.mock('./partials/neostandardLint.mjs', () => require('./test-helpers/neostandardLintWithRealNeostandard.mjs'))
10
+
11
+ setUp.setDefaults('test-source-lint')
12
+ const gulpConfig = setUp.gulpConfig
13
+
14
+ const lintableContents = 'const x = "a";\n' +
15
+ '\n' +
16
+ 'module.exports = x;\n'
17
+
18
+ const lintableTestContents = 'const y = "b";\n' +
19
+ '\n' +
20
+ 'module.exports = y;\n'
21
+
22
+ beforeEach(
23
+ () => setUp.beforeEach()
24
+ .then(
25
+ async () => {
26
+ const srcPath = gulpConfig.get('srcPath')
27
+ await fs.mkdirSync(srcPath, { recursive: true })
28
+ fs.writeFileSync(`${srcPath}/example.js`, lintableContents)
29
+ return fs.writeFileSync(`${srcPath}/example.test.js`, lintableTestContents)
30
+ }
31
+ )
32
+ )
33
+
34
+ afterEach(setUp.afterEach)
35
+
36
+ describe('sourceLint', () => {
37
+ test('fixes the real source in place, including test files', done => {
38
+ const srcPath = gulpConfig.get('srcPath')
39
+ expect.assertions(4)
40
+ sourceLint()
41
+ .on('finish', () => {
42
+ const linted = fs.readFileSync(`${srcPath}/example.js`).toString()
43
+ expect(countMatches(linted, '"')).toEqual(0)
44
+ expect(countMatches(linted, ';')).toEqual(0)
45
+ const lintedTest = fs.readFileSync(`${srcPath}/example.test.js`).toString()
46
+ expect(countMatches(lintedTest, '"')).toEqual(0)
47
+ expect(countMatches(lintedTest, ';')).toEqual(0)
48
+ done()
49
+ })
50
+ .on('error', error => {
51
+ console.error('Encountered error', error)
52
+ done(error)
53
+ })
54
+ }, 20000)
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
+
73
+ test('lint.rules actually suppresses a real neostandard finding', done => {
74
+ const srcPath = gulpConfig.get('srcPath')
75
+ // A fixture string containing literal ${...} text (simulating real module source, not an accidental
76
+ // non-template string) - neostandard's no-template-curly-in-string rule flags this as an error by default.
77
+ const fixtureContents = 'const fixture = \'import(`imagemin-${pluginName}`)\'\n\nmodule.exports = fixture\n'
78
+ fs.writeFileSync(`${srcPath}/fixture.js`, fixtureContents)
79
+ gulpConfig.set('lint.rules', { 'no-template-curly-in-string': 'off' })
80
+ const logSpy = jest.spyOn(console, 'log').mockImplementation(() => {})
81
+ expect.assertions(1)
82
+ sourceLint()
83
+ .on('finish', () => {
84
+ gulpConfig.set('lint.rules', {})
85
+ expect(logSpy.mock.calls.flat().join('\n')).not.toMatch(/no-template-curly-in-string|template string expression/)
86
+ logSpy.mockRestore()
87
+ done()
88
+ })
89
+ .on('error', error => {
90
+ gulpConfig.set('lint.rules', {})
91
+ logSpy.mockRestore()
92
+ console.error('Encountered error', error)
93
+ done(error)
94
+ })
95
+ }, 20000)
96
+
97
+ test('also lints .ts source when typescript.enabled', done => {
98
+ const srcPath = gulpConfig.get('srcPath')
99
+ gulpConfig.set('typescript.enabled', true)
100
+ fs.writeFileSync(`${srcPath}/example.ts`, 'const z: string = "c";\n\nexport default z;\n')
101
+ expect.assertions(2)
102
+ sourceLint()
103
+ .on('finish', () => {
104
+ gulpConfig.set('typescript.enabled', false)
105
+ const linted = fs.readFileSync(`${srcPath}/example.ts`).toString()
106
+ expect(countMatches(linted, '"')).toEqual(0)
107
+ expect(countMatches(linted, ';')).toEqual(0)
108
+ done()
109
+ })
110
+ .on('error', error => {
111
+ gulpConfig.set('typescript.enabled', false)
112
+ console.error('Encountered error', error)
113
+ done(error)
114
+ })
115
+ }, 20000)
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
+
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)
166
+ })
@@ -1,16 +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
- }
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
+ }
@@ -1,40 +1,40 @@
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, defaultFilePatterns } from \'neostandard\'\n' +
10
- 'const { text, filePath, cwd, fix, ts, env, rules } = JSON.parse(readFileSync(0, \'utf8\'))\n' +
11
- 'const baseConfig = neostandard({ ts, env })\n' +
12
- 'if (Object.keys(rules).length) { baseConfig.push({ files: defaultFilePatterns.all, rules }) }\n' +
13
- 'const eslint = new ESLint({ cwd, fix, overrideConfigFile: true, baseConfig })\n' +
14
- 'process.stdout.write(JSON.stringify(await eslint.lintText(text, { filePath })))\n'
15
-
16
- const readEnv = cwd => {
17
- try {
18
- return JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8')).standard?.env ?? []
19
- } catch {
20
- return []
21
- }
22
- }
23
-
24
- export const loadEslintViaSubprocess = ({ cwd, ts, fix, rules = {} }) => Promise.resolve({
25
- lintText: (text, { filePath }) => Promise.resolve().then(() => JSON.parse(execFileSync(
26
- process.execPath,
27
- ['--input-type=module', '--eval', script],
28
- {
29
- input: JSON.stringify({ text, filePath, cwd, fix, ts, env: readEnv(cwd), rules }),
30
- encoding: 'utf8',
31
- cwd,
32
- maxBuffer: 256 * 1024 * 1024
33
- }
34
- )))
35
- })
36
-
37
- const actual = jest.requireActual('../partials/neostandardLint.mjs')
38
-
39
- // Drop-in replacement for the partial module (see jest.mock in the lint/build tests): same API, real neostandard.
40
- export const neostandardLint = (options) => actual.neostandardLint(options, loadEslintViaSubprocess)
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, defaultFilePatterns } from \'neostandard\'\n' +
10
+ 'const { text, filePath, cwd, fix, ts, env, rules } = JSON.parse(readFileSync(0, \'utf8\'))\n' +
11
+ 'const baseConfig = neostandard({ ts, env })\n' +
12
+ 'if (Object.keys(rules).length) { baseConfig.push({ files: defaultFilePatterns.all, rules }) }\n' +
13
+ 'const eslint = new ESLint({ cwd, fix, overrideConfigFile: true, baseConfig })\n' +
14
+ 'process.stdout.write(JSON.stringify(await eslint.lintText(text, { filePath })))\n'
15
+
16
+ const readEnv = cwd => {
17
+ try {
18
+ return JSON.parse(fs.readFileSync(path.join(cwd, 'package.json'), 'utf8')).standard?.env ?? []
19
+ } catch {
20
+ return []
21
+ }
22
+ }
23
+
24
+ export const loadEslintViaSubprocess = ({ cwd, ts, fix, rules = {} }) => Promise.resolve({
25
+ lintText: (text, { filePath }) => Promise.resolve().then(() => JSON.parse(execFileSync(
26
+ process.execPath,
27
+ ['--input-type=module', '--eval', script],
28
+ {
29
+ input: JSON.stringify({ text, filePath, cwd, fix, ts, env: readEnv(cwd), rules }),
30
+ encoding: 'utf8',
31
+ cwd,
32
+ maxBuffer: 256 * 1024 * 1024
33
+ }
34
+ )))
35
+ })
36
+
37
+ const actual = jest.requireActual('../partials/neostandardLint.mjs')
38
+
39
+ // Drop-in replacement for the partial module (see jest.mock in the lint/build tests): same API, real neostandard.
40
+ export const neostandardLint = (options) => actual.neostandardLint(options, loadEslintViaSubprocess)