es-check 9.2.0 → 9.3.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 +40 -15
- package/esm-wrapper.mjs +8 -0
- package/index.js +137 -46
- package/package.json +14 -4
- package/utils.js +117 -4
package/README.md
CHANGED
|
@@ -153,6 +153,7 @@ Here's a comprehensive list of all available options:
|
|
|
153
153
|
| `--browserslistEnv <env>` | Browserslist environment to use (default: production) |
|
|
154
154
|
| `--config <path>` | Path to custom .escheckrc config file |
|
|
155
155
|
| `--batchSize <number>` | Number of files to process concurrently (0 for unlimited, default: 0) |
|
|
156
|
+
| `--noCache` | Disable file caching (cache is enabled by default) |
|
|
156
157
|
| `-h, --help` | Display help for command |
|
|
157
158
|
|
|
158
159
|
### Shell Completion
|
|
@@ -203,7 +204,7 @@ es-check es6 './dist/**/*.js' --module
|
|
|
203
204
|
**Checking files with hash bang:**
|
|
204
205
|
|
|
205
206
|
```sh
|
|
206
|
-
es-check es6 './
|
|
207
|
+
es-check es6 './tests/*.js' --allowHashBang
|
|
207
208
|
```
|
|
208
209
|
|
|
209
210
|
**Skipping specific files or directories:**
|
|
@@ -284,7 +285,7 @@ es-check es6 ./js/*.js
|
|
|
284
285
|
es-check es6 ./js/*.js ./dist/*.js
|
|
285
286
|
```
|
|
286
287
|
|
|
287
|
-
### Using ES Check in Node
|
|
288
|
+
### Using ES Check in Node (Programmatic API)
|
|
288
289
|
|
|
289
290
|
In addition to its CLI utility, ES Check can be used programmatically in Node.js applications:
|
|
290
291
|
|
|
@@ -292,25 +293,30 @@ In addition to its CLI utility, ES Check can be used programmatically in Node.js
|
|
|
292
293
|
const { runChecks, loadConfig } = require('es-check');
|
|
293
294
|
|
|
294
295
|
async function checkMyFiles() {
|
|
295
|
-
const
|
|
296
|
+
const configs = [{
|
|
296
297
|
ecmaVersion: 'es5',
|
|
297
298
|
files: ['dist/**/*.js'],
|
|
298
299
|
module: false,
|
|
299
300
|
checkFeatures: true
|
|
300
|
-
};
|
|
301
|
+
}];
|
|
301
302
|
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
const result = await runChecks(configs);
|
|
304
|
+
|
|
305
|
+
if (result.success) {
|
|
304
306
|
console.log('All files passed ES5 check!');
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
307
|
+
// Output: All files passed ES5 check!
|
|
308
|
+
} else {
|
|
309
|
+
console.error(`ES Check failed with ${result.errors.length} errors`);
|
|
310
|
+
result.errors.forEach(error => {
|
|
311
|
+
console.error(`- ${error.file}: ${error.err.message}`);
|
|
312
|
+
});
|
|
313
|
+
// Example output:
|
|
314
|
+
// ES Check failed with 2 errors
|
|
315
|
+
// - dist/app.js: Unsupported features used: const, arrow-functions but your target is ES5.
|
|
316
|
+
// - dist/utils.js: Unsupported features used: template-literals but your target is ES5.
|
|
308
317
|
}
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
async function checkWithConfig() {
|
|
312
|
-
const configs = await loadConfig('./.escheckrc');
|
|
313
|
-
await runChecks(configs, logger);
|
|
318
|
+
|
|
319
|
+
return result;
|
|
314
320
|
}
|
|
315
321
|
```
|
|
316
322
|
|
|
@@ -525,7 +531,26 @@ es-check --checkBrowser --checkFeatures ./dist/**/*.js
|
|
|
525
531
|
|
|
526
532
|
## Performance Optimization
|
|
527
533
|
|
|
528
|
-
ES Check
|
|
534
|
+
ES Check includes several performance optimizations:
|
|
535
|
+
|
|
536
|
+
### File Caching
|
|
537
|
+
File caching is **enabled by default** for faster re-checking:
|
|
538
|
+
|
|
539
|
+
```sh
|
|
540
|
+
# Cache is enabled by default
|
|
541
|
+
es-check es5 './dist/**/*.js'
|
|
542
|
+
|
|
543
|
+
# Disable cache if needed
|
|
544
|
+
es-check es5 './dist/**/*.js' --noCache
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
We observed ~28% performance improvement in our [benchmark tests](./benchmarks/README.md). Your results may vary based on file sizes and system configuration. Try the benchmarks yourself:
|
|
548
|
+
```sh
|
|
549
|
+
node benchmarks/compare-tools.js 3 ./benchmarks/test-files
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### Batch Processing
|
|
553
|
+
The `--batchSize` option optimizes memory usage:
|
|
529
554
|
|
|
530
555
|
```sh
|
|
531
556
|
# Process all files in parallel (default)
|
package/esm-wrapper.mjs
ADDED
package/index.js
CHANGED
|
@@ -11,7 +11,7 @@ let polyfillDetector = null;
|
|
|
11
11
|
const pkg = require('./package.json')
|
|
12
12
|
const { lilconfig } = require('lilconfig');
|
|
13
13
|
const { JS_VERSIONS } = require('./constants');
|
|
14
|
-
const { parseIgnoreList, createLogger, generateBashCompletion, generateZshCompletion, processBatchedFiles, readFileAsync, parseCode } = require('./utils');
|
|
14
|
+
const { parseIgnoreList, createLogger, generateBashCompletion, generateZshCompletion, processBatchedFiles, readFileAsync, clearFileCache, getFileCacheStats, parseCode, determineInvocationType, determineLogLevel, handleESVersionError } = require('./utils');
|
|
15
15
|
|
|
16
16
|
program.configureOutput({
|
|
17
17
|
writeOut: (str) => process.stdout.write(str),
|
|
@@ -99,6 +99,7 @@ program
|
|
|
99
99
|
.option('--browserslistEnv <env>', 'browserslist environment to use')
|
|
100
100
|
.option('--config <path>', 'path to custom .escheckrc config file')
|
|
101
101
|
.option('--batchSize <number>', 'number of files to process concurrently (0 for unlimited)', '0')
|
|
102
|
+
.option('--noCache', 'disable file caching (caching is enabled by default)', false)
|
|
102
103
|
|
|
103
104
|
async function loadConfig(customConfigPath) {
|
|
104
105
|
const logger = createLogger();
|
|
@@ -180,6 +181,7 @@ program
|
|
|
180
181
|
browserslistPath: options.browserslistPath !== undefined ? options.browserslistPath : baseConfig.browserslistPath,
|
|
181
182
|
browserslistEnv: options.browserslistEnv !== undefined ? options.browserslistEnv : baseConfig.browserslistEnv,
|
|
182
183
|
batchSize: options.batchSize !== undefined ? options.batchSize : baseConfig.batchSize,
|
|
184
|
+
cache: options.noCache ? false : (baseConfig.cache !== undefined ? baseConfig.cache : true),
|
|
183
185
|
};
|
|
184
186
|
|
|
185
187
|
if (ecmaVersionArg !== undefined) {
|
|
@@ -203,8 +205,17 @@ program
|
|
|
203
205
|
return runChecks(configs, logger);
|
|
204
206
|
})
|
|
205
207
|
|
|
206
|
-
async function runChecks(configs,
|
|
208
|
+
async function runChecks(configs, loggerOrOptions) {
|
|
209
|
+
const { isNodeAPI, logger } = determineInvocationType(loggerOrOptions);
|
|
210
|
+
|
|
211
|
+
const logLevels = determineLogLevel(logger);
|
|
212
|
+
const isDebug = logLevels?.isDebug || false;
|
|
213
|
+
const isWarn = logLevels?.isWarn || false;
|
|
214
|
+
const isInfo = logLevels?.isInfo || false;
|
|
215
|
+
const isError = logLevels?.isError || false;
|
|
216
|
+
|
|
207
217
|
let hasErrors = false;
|
|
218
|
+
const allErrors = [];
|
|
208
219
|
|
|
209
220
|
for (const config of configs) {
|
|
210
221
|
const expectedEcmaVersion = config.ecmaVersion;
|
|
@@ -227,47 +238,88 @@ async function runChecks(configs, logger) {
|
|
|
227
238
|
const checkBrowser = config.checkBrowser;
|
|
228
239
|
const ignoreFilePath = config.ignoreFile || config['ignore-file'];
|
|
229
240
|
|
|
230
|
-
|
|
241
|
+
const ignoreFileExists = ignoreFilePath && fs.existsSync(ignoreFilePath);
|
|
242
|
+
const shouldWarnAboutIgnoreFile = ignoreFilePath && !ignoreFileExists && isWarn;
|
|
243
|
+
if (shouldWarnAboutIgnoreFile) {
|
|
231
244
|
logger.warn(`Warning: Ignore file '${ignoreFilePath}' does not exist or is not accessible`);
|
|
232
245
|
}
|
|
233
246
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
247
|
+
const hasEcmaVersion = Boolean(expectedEcmaVersion);
|
|
248
|
+
const hasBrowserCheck = Boolean(config.checkBrowser);
|
|
249
|
+
const missingVersionSpecification = !hasEcmaVersion && !hasBrowserCheck;
|
|
250
|
+
|
|
251
|
+
if (missingVersionSpecification) {
|
|
252
|
+
if (logger) logger.error('No ecmaScript version or checkBrowser option specified in configuration');
|
|
253
|
+
if (!isNodeAPI) {
|
|
254
|
+
process.exit(1);
|
|
255
|
+
} else {
|
|
256
|
+
allErrors.push({ err: new Error('No ecmaScript version or checkBrowser option specified in configuration'), file: 'config' });
|
|
257
|
+
hasErrors = true;
|
|
258
|
+
continue;
|
|
259
|
+
}
|
|
237
260
|
}
|
|
238
261
|
|
|
239
|
-
if (looseGlobMatching &&
|
|
262
|
+
if (looseGlobMatching && isDebug) {
|
|
240
263
|
logger.debug('ES-Check: loose-glob-matching is set');
|
|
241
264
|
}
|
|
242
265
|
|
|
243
266
|
const globOpts = { nodir: true }
|
|
244
267
|
let allMatchedFiles = [];
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
268
|
+
|
|
269
|
+
const hasFilePatterns = patternsToGlob.length > 0;
|
|
270
|
+
const shouldEnforceFilePatterns = !hasFilePatterns && !looseGlobMatching;
|
|
271
|
+
|
|
272
|
+
if (shouldEnforceFilePatterns) {
|
|
273
|
+
if (logger) logger.error('ES-Check: No file patterns specified to check.');
|
|
274
|
+
if (!isNodeAPI) {
|
|
275
|
+
process.exit(1);
|
|
276
|
+
} else {
|
|
277
|
+
allErrors.push({ err: new Error('No file patterns specified to check'), file: 'config' });
|
|
278
|
+
hasErrors = true;
|
|
279
|
+
continue;
|
|
280
|
+
}
|
|
248
281
|
}
|
|
249
282
|
|
|
250
283
|
patternsToGlob.forEach((pattern) => {
|
|
251
284
|
const globbedFiles = glob.sync(pattern, globOpts);
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
285
|
+
const noFilesFound = globbedFiles.length === 0;
|
|
286
|
+
const shouldErrorOnNoFiles = noFilesFound && !looseGlobMatching;
|
|
287
|
+
|
|
288
|
+
if (shouldErrorOnNoFiles) {
|
|
289
|
+
if (logger) logger.error(`ES-Check: Did not find any files to check for pattern: ${pattern}.`);
|
|
290
|
+
if (!isNodeAPI) {
|
|
291
|
+
process.exit(1);
|
|
292
|
+
} else {
|
|
293
|
+
allErrors.push({ err: new Error(`Did not find any files to check for pattern: ${pattern}`), file: 'glob' });
|
|
294
|
+
hasErrors = true;
|
|
295
|
+
}
|
|
255
296
|
}
|
|
256
297
|
allMatchedFiles = allMatchedFiles.concat(globbedFiles);
|
|
257
298
|
});
|
|
258
299
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
300
|
+
const noMatchedFiles = allMatchedFiles.length === 0;
|
|
301
|
+
const shouldErrorOnNoMatchedFiles = noMatchedFiles && hasFilePatterns && !looseGlobMatching;
|
|
302
|
+
const shouldWarnOnNoMatchedFiles = noMatchedFiles && looseGlobMatching;
|
|
303
|
+
|
|
304
|
+
if (noMatchedFiles) {
|
|
305
|
+
if (shouldErrorOnNoMatchedFiles) {
|
|
306
|
+
if (logger) logger.error(`ES-Check: Did not find any files to check across all patterns: ${patternsToGlob.join(', ')}.`);
|
|
307
|
+
if (!isNodeAPI) {
|
|
308
|
+
process.exit(1);
|
|
309
|
+
} else {
|
|
310
|
+
allErrors.push({ err: new Error(`Did not find any files to check across all patterns: ${patternsToGlob.join(', ')}`), file: 'glob' });
|
|
311
|
+
hasErrors = true;
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
} else if (shouldWarnOnNoMatchedFiles) {
|
|
315
|
+
if (logger) logger.warn('ES-Check: No file patterns specified or no files found (running in loose mode).');
|
|
265
316
|
}
|
|
266
317
|
}
|
|
267
318
|
|
|
268
319
|
let ecmaVersion
|
|
269
320
|
|
|
270
321
|
const isBrowserslistCheck = Boolean(expectedEcmaVersion === 'checkBrowser' || checkBrowser !== undefined);
|
|
322
|
+
|
|
271
323
|
if (isBrowserslistCheck) {
|
|
272
324
|
const browserslistQuery = config.browserslistQuery;
|
|
273
325
|
try {
|
|
@@ -280,12 +332,18 @@ async function runChecks(configs, logger) {
|
|
|
280
332
|
|
|
281
333
|
ecmaVersion = esVersionFromBrowserslist.toString();
|
|
282
334
|
|
|
283
|
-
if (
|
|
335
|
+
if (isDebug) {
|
|
284
336
|
logger.debug(`ES-Check: Using ES${ecmaVersion} based on browserslist configuration`);
|
|
285
337
|
}
|
|
286
338
|
} catch (err) {
|
|
287
|
-
logger.error(`Error determining ES version from browserslist: ${err.message}`);
|
|
288
|
-
|
|
339
|
+
if (logger) logger.error(`Error determining ES version from browserslist: ${err.message}`);
|
|
340
|
+
if (!isNodeAPI) {
|
|
341
|
+
process.exit(1);
|
|
342
|
+
} else {
|
|
343
|
+
allErrors.push({ err: new Error(`Error determining ES version from browserslist: ${err.message}`), file: 'browserslist' });
|
|
344
|
+
hasErrors = true;
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
289
347
|
}
|
|
290
348
|
} else {
|
|
291
349
|
switch (expectedEcmaVersion) {
|
|
@@ -293,8 +351,14 @@ async function runChecks(configs, logger) {
|
|
|
293
351
|
ecmaVersion = '3'
|
|
294
352
|
break
|
|
295
353
|
case 'es4':
|
|
296
|
-
logger.error('ES4 is not supported.')
|
|
297
|
-
|
|
354
|
+
if (logger) logger.error('ES4 is not supported.')
|
|
355
|
+
if (!isNodeAPI) {
|
|
356
|
+
process.exit(1)
|
|
357
|
+
} else {
|
|
358
|
+
allErrors.push({ err: new Error('ES4 is not supported'), file: 'config' });
|
|
359
|
+
hasErrors = true;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
298
362
|
case 'es5':
|
|
299
363
|
ecmaVersion = '5'
|
|
300
364
|
break
|
|
@@ -343,28 +407,34 @@ async function runChecks(configs, logger) {
|
|
|
343
407
|
ecmaVersion = '16'
|
|
344
408
|
break
|
|
345
409
|
default:
|
|
346
|
-
logger.error('Invalid ecmaScript version, please pass a valid version, use --help for help')
|
|
347
|
-
|
|
410
|
+
if (logger) logger.error('Invalid ecmaScript version, please pass a valid version, use --help for help')
|
|
411
|
+
if (!isNodeAPI) {
|
|
412
|
+
process.exit(1)
|
|
413
|
+
} else {
|
|
414
|
+
allErrors.push({ err: new Error('Invalid ecmaScript version'), file: 'config' });
|
|
415
|
+
hasErrors = true;
|
|
416
|
+
continue;
|
|
417
|
+
}
|
|
348
418
|
}
|
|
349
419
|
}
|
|
350
420
|
|
|
351
421
|
const errArray = []
|
|
352
422
|
const acornOpts = { ecmaVersion: parseInt(ecmaVersion, 10), silent: true }
|
|
353
423
|
|
|
354
|
-
if (
|
|
424
|
+
if (isDebug) {
|
|
355
425
|
logger.debug(`ES-Check: Going to check files using version ${ecmaVersion}`)
|
|
356
426
|
}
|
|
357
427
|
|
|
358
428
|
if (esmodule) {
|
|
359
429
|
acornOpts.sourceType = 'module'
|
|
360
|
-
if (
|
|
430
|
+
if (isDebug) {
|
|
361
431
|
logger.debug('ES-Check: esmodule is set')
|
|
362
432
|
}
|
|
363
433
|
}
|
|
364
434
|
|
|
365
435
|
if (allowHashBang) {
|
|
366
436
|
acornOpts.allowHashBang = true
|
|
367
|
-
if (
|
|
437
|
+
if (isDebug) {
|
|
368
438
|
logger.debug('ES-Check: allowHashBang is set')
|
|
369
439
|
}
|
|
370
440
|
}
|
|
@@ -388,25 +458,29 @@ async function runChecks(configs, logger) {
|
|
|
388
458
|
|
|
389
459
|
const ignoreList = parseIgnoreList(config);
|
|
390
460
|
|
|
391
|
-
if (ignoreList.size > 0 &&
|
|
461
|
+
if (ignoreList.size > 0 && isDebug) {
|
|
392
462
|
logger.debug('ES-Check: ignoring features:', Array.from(ignoreList).join(', '));
|
|
393
463
|
}
|
|
394
464
|
|
|
395
465
|
const batchSize = parseInt(config.batchSize || '0', 10);
|
|
396
466
|
|
|
397
467
|
const processFile = async (file) => {
|
|
398
|
-
const
|
|
468
|
+
const useCache = config.cache !== false;
|
|
469
|
+
const { content: code, error: readError } = await readFileAsync(file, fs, useCache);
|
|
399
470
|
if (readError) {
|
|
400
471
|
return readError;
|
|
401
472
|
}
|
|
402
473
|
|
|
403
|
-
if (
|
|
474
|
+
if (isDebug) {
|
|
404
475
|
logger.debug(`ES-Check: checking ${file}`)
|
|
405
476
|
}
|
|
406
477
|
|
|
407
|
-
const
|
|
478
|
+
const needsFullAST = checkFeatures;
|
|
479
|
+
const parserOptions = needsFullAST ? acornOpts : { ...acornOpts, locations: false, ranges: false, onComment: null };
|
|
480
|
+
|
|
481
|
+
const { ast, error: parseError } = parseCode(code, parserOptions, acorn, file);
|
|
408
482
|
if (parseError) {
|
|
409
|
-
if (
|
|
483
|
+
if (isDebug) {
|
|
410
484
|
logger.debug(`ES-Check: failed to parse file: ${file} \n - error: ${parseError.err}`)
|
|
411
485
|
}
|
|
412
486
|
return parseError;
|
|
@@ -424,7 +498,7 @@ async function runChecks(configs, logger) {
|
|
|
424
498
|
{ ast, checkForPolyfills }
|
|
425
499
|
);
|
|
426
500
|
|
|
427
|
-
if (
|
|
501
|
+
if (isDebug) {
|
|
428
502
|
const stringifiedFeatures = JSON.stringify(foundFeatures, null, 2);
|
|
429
503
|
logger.debug(`Features found in ${file}: ${stringifiedFeatures}`);
|
|
430
504
|
}
|
|
@@ -435,11 +509,11 @@ async function runChecks(configs, logger) {
|
|
|
435
509
|
polyfillDetector = require('./polyfillDetector');
|
|
436
510
|
}
|
|
437
511
|
|
|
438
|
-
const polyfills = polyfillDetector.detectPolyfills(code, logger);
|
|
512
|
+
const polyfills = polyfillDetector.detectPolyfills(code, logger || { debug: () => {}, isLevelEnabled: () => false });
|
|
439
513
|
|
|
440
514
|
filteredUnsupportedFeatures = polyfillDetector.filterPolyfilled(unsupportedFeatures, polyfills);
|
|
441
515
|
|
|
442
|
-
if (
|
|
516
|
+
if (isDebug && filteredUnsupportedFeatures.length !== unsupportedFeatures.length) {
|
|
443
517
|
logger.debug(`ES-Check: Polyfills reduced unsupported features from ${unsupportedFeatures.length} to ${filteredUnsupportedFeatures.length}`);
|
|
444
518
|
}
|
|
445
519
|
}
|
|
@@ -461,9 +535,11 @@ async function runChecks(configs, logger) {
|
|
|
461
535
|
errArray.push(...errors);
|
|
462
536
|
|
|
463
537
|
if (errArray.length > 0) {
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
logger.
|
|
538
|
+
allErrors.push(...errArray);
|
|
539
|
+
if (logger) {
|
|
540
|
+
logger.error(`ES-Check: there were ${errArray.length} ES version matching errors.`)
|
|
541
|
+
errArray.forEach((o) => {
|
|
542
|
+
logger.info(`
|
|
467
543
|
ES-Check Error:
|
|
468
544
|
----
|
|
469
545
|
· erroring file: ${o.file}
|
|
@@ -472,16 +548,29 @@ async function runChecks(configs, logger) {
|
|
|
472
548
|
----\n
|
|
473
549
|
${o.stack}
|
|
474
550
|
`)
|
|
475
|
-
|
|
551
|
+
})
|
|
552
|
+
}
|
|
476
553
|
hasErrors = true;
|
|
477
|
-
|
|
478
|
-
|
|
554
|
+
|
|
555
|
+
if (!isNodeAPI) {
|
|
556
|
+
process.exit(1)
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
559
|
+
} else {
|
|
560
|
+
if (logger) logger.info(`ES-Check: there were no ES version matching errors! 🎉`)
|
|
479
561
|
}
|
|
480
|
-
logger.info(`ES-Check: there were no ES version matching errors! 🎉`)
|
|
481
562
|
}
|
|
482
563
|
|
|
483
564
|
if (hasErrors) {
|
|
484
|
-
|
|
565
|
+
if (!isNodeAPI) {
|
|
566
|
+
process.exit(1);
|
|
567
|
+
} else {
|
|
568
|
+
return { success: false, errors: allErrors };
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
if (isNodeAPI) {
|
|
573
|
+
return { success: true, errors: [] };
|
|
485
574
|
}
|
|
486
575
|
}
|
|
487
576
|
|
|
@@ -491,5 +580,7 @@ if (require.main === module) {
|
|
|
491
580
|
|
|
492
581
|
module.exports = {
|
|
493
582
|
runChecks,
|
|
494
|
-
loadConfig
|
|
583
|
+
loadConfig,
|
|
584
|
+
// Export commonly used utilities
|
|
585
|
+
createLogger
|
|
495
586
|
}
|
package/package.json
CHANGED
|
@@ -1,16 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "es-check",
|
|
3
|
-
"version": "9.
|
|
3
|
+
"version": "9.3.0",
|
|
4
4
|
"description": "Checks the ECMAScript version of .js glob against a specified version of ECMAScript with a shell command",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"license": "MIT",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"import": "./esm-wrapper.mjs",
|
|
10
|
+
"require": "./index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
7
13
|
"files": [
|
|
8
14
|
"index.js",
|
|
9
15
|
"utils.js",
|
|
10
16
|
"detectFeatures.js",
|
|
11
17
|
"constants.js",
|
|
12
18
|
"browserslist.js",
|
|
13
|
-
"polyfillDetector.js"
|
|
19
|
+
"polyfillDetector.js",
|
|
20
|
+
"esm-wrapper.mjs"
|
|
14
21
|
],
|
|
15
22
|
"bin": {
|
|
16
23
|
"es-check": "index.js"
|
|
@@ -27,7 +34,10 @@
|
|
|
27
34
|
"release": "release-it --no-git.requireUpstream",
|
|
28
35
|
"report:coverage": "nyc report --reporter=lcov > coverage.lcov && codecov",
|
|
29
36
|
"setup": "pnpm install --reporter=silent",
|
|
30
|
-
"test": "nyc mocha test.js utils.test.js browserslist.test.js polyfillDetector.test.js detectFeatures.test.js --timeout 10s",
|
|
37
|
+
"test": "nyc mocha test.js utils.test.js browserslist.test.js polyfillDetector.test.js detectFeatures.test.js --timeout 10s && npm run test:e2e",
|
|
38
|
+
"test:e2e": "npm run test:e2e:cli && npm run test:e2e:esm",
|
|
39
|
+
"test:e2e:cli": "node e2e/test-cli.js",
|
|
40
|
+
"test:e2e:esm": "node e2e/test-esm-import.mjs",
|
|
31
41
|
"update": "codependence --update",
|
|
32
42
|
"benchmark": "./benchmarks/run-benchmarks.sh",
|
|
33
43
|
"site:dev": "pnpm --filter es-check-docs run dev",
|
|
@@ -57,7 +67,7 @@
|
|
|
57
67
|
"codependence": "^0.3.1",
|
|
58
68
|
"commitizen": "4.3.1",
|
|
59
69
|
"conventional-changelog-cli": "^5.0.0",
|
|
60
|
-
"eslint": "9.
|
|
70
|
+
"eslint": "9.33.0",
|
|
61
71
|
"eslint-config-prettier": "10.1.8",
|
|
62
72
|
"eslint-plugin-es5": "^1.5.0",
|
|
63
73
|
"husky": "9.1.7",
|
package/utils.js
CHANGED
|
@@ -361,18 +361,35 @@ async function processBatchedFiles(files, processor, batchSize = 0) {
|
|
|
361
361
|
return results;
|
|
362
362
|
}
|
|
363
363
|
|
|
364
|
+
const SimpleCache = require('./cache');
|
|
365
|
+
const fileCache = new SimpleCache(500, 60000);
|
|
366
|
+
|
|
364
367
|
/**
|
|
365
368
|
* Read file asynchronously with error handling
|
|
366
369
|
* @param {string} file - File path to read
|
|
367
370
|
* @param {Object} fs - File system module
|
|
371
|
+
* @param {boolean} useCache - Whether to use file cache (default: false)
|
|
368
372
|
* @returns {Promise<{content: string, error: null} | {content: null, error: Object}>}
|
|
369
373
|
*/
|
|
370
|
-
async function readFileAsync(file, fs) {
|
|
374
|
+
async function readFileAsync(file, fs, useCache = false) {
|
|
375
|
+
if (useCache) {
|
|
376
|
+
const cached = fileCache.get(file);
|
|
377
|
+
if (cached !== undefined) {
|
|
378
|
+
return cached;
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
371
382
|
try {
|
|
372
383
|
const content = await fs.promises.readFile(file, 'utf8');
|
|
373
|
-
|
|
384
|
+
const result = { content, error: null };
|
|
385
|
+
|
|
386
|
+
if (useCache) {
|
|
387
|
+
fileCache.set(file, result);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
return result;
|
|
374
391
|
} catch (err) {
|
|
375
|
-
|
|
392
|
+
const result = {
|
|
376
393
|
content: null,
|
|
377
394
|
error: {
|
|
378
395
|
err,
|
|
@@ -380,9 +397,29 @@ async function readFileAsync(file, fs) {
|
|
|
380
397
|
stack: err.stack
|
|
381
398
|
}
|
|
382
399
|
};
|
|
400
|
+
|
|
401
|
+
if (useCache) {
|
|
402
|
+
fileCache.set(file, result);
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return result;
|
|
383
406
|
}
|
|
384
407
|
}
|
|
385
408
|
|
|
409
|
+
/**
|
|
410
|
+
* Clear the file cache
|
|
411
|
+
*/
|
|
412
|
+
function clearFileCache() {
|
|
413
|
+
fileCache.clear();
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Get file cache statistics
|
|
418
|
+
*/
|
|
419
|
+
function getFileCacheStats() {
|
|
420
|
+
return fileCache.getStats();
|
|
421
|
+
}
|
|
422
|
+
|
|
386
423
|
/**
|
|
387
424
|
* Parse code with acorn and handle errors
|
|
388
425
|
* @param {string} code - Code to parse
|
|
@@ -407,6 +444,77 @@ function parseCode(code, acornOpts, acorn, file) {
|
|
|
407
444
|
}
|
|
408
445
|
}
|
|
409
446
|
|
|
447
|
+
/**
|
|
448
|
+
* Determine how runChecks is being invoked (CLI vs Node API)
|
|
449
|
+
* @param {Object|null} loggerOrOptions - Logger or options object passed to runChecks
|
|
450
|
+
* @returns {{isNodeAPI: boolean, logger: Object|null}}
|
|
451
|
+
*/
|
|
452
|
+
function determineInvocationType(loggerOrOptions) {
|
|
453
|
+
let isNodeAPI = false;
|
|
454
|
+
let logger = null;
|
|
455
|
+
|
|
456
|
+
if (!loggerOrOptions) {
|
|
457
|
+
isNodeAPI = true;
|
|
458
|
+
logger = null;
|
|
459
|
+
} else if (typeof loggerOrOptions === 'object' && !loggerOrOptions.info && !loggerOrOptions.error) {
|
|
460
|
+
isNodeAPI = true;
|
|
461
|
+
logger = loggerOrOptions.logger || null;
|
|
462
|
+
} else {
|
|
463
|
+
isNodeAPI = false;
|
|
464
|
+
logger = loggerOrOptions;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
return { isNodeAPI, logger };
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
/**
|
|
471
|
+
* Determine log levels based on logger capabilities
|
|
472
|
+
* @param {Object|null} logger - Logger object
|
|
473
|
+
* @returns {Object|null} Object with log level flags or null if no logger
|
|
474
|
+
*/
|
|
475
|
+
function determineLogLevel(logger) {
|
|
476
|
+
if (!logger || !logger.isLevelEnabled) {
|
|
477
|
+
return null;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
return {
|
|
481
|
+
isDebug: logger.isLevelEnabled('debug'),
|
|
482
|
+
isWarn: logger.isLevelEnabled('warn'),
|
|
483
|
+
isInfo: logger.isLevelEnabled('info'),
|
|
484
|
+
isError: logger.isLevelEnabled('error')
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Handle ES version errors uniformly for different error types
|
|
490
|
+
* @param {Object} options - Options object
|
|
491
|
+
* @param {string} options.errorType - Type of error ('browserslist', 'es3', 'default')
|
|
492
|
+
* @param {string} options.errorMessage - Error message to display
|
|
493
|
+
* @param {Object|null} options.logger - Logger object
|
|
494
|
+
* @param {boolean} options.isNodeAPI - Whether running as Node API
|
|
495
|
+
* @param {Array} options.allErrors - Array to collect errors
|
|
496
|
+
* @param {string} [options.file='config'] - File reference for error
|
|
497
|
+
* @returns {{shouldContinue: boolean, hasErrors: boolean}}
|
|
498
|
+
*/
|
|
499
|
+
function handleESVersionError(options) {
|
|
500
|
+
const { errorType, errorMessage, logger, isNodeAPI, allErrors, file = 'config' } = options;
|
|
501
|
+
|
|
502
|
+
if (logger) {
|
|
503
|
+
logger.error(errorMessage);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (!isNodeAPI) {
|
|
507
|
+
process.exit(1);
|
|
508
|
+
return { shouldContinue: false, hasErrors: true };
|
|
509
|
+
} else {
|
|
510
|
+
allErrors.push({
|
|
511
|
+
err: new Error(errorMessage),
|
|
512
|
+
file
|
|
513
|
+
});
|
|
514
|
+
return { shouldContinue: true, hasErrors: true };
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
410
518
|
module.exports = {
|
|
411
519
|
parseIgnoreList,
|
|
412
520
|
checkVarKindMatch,
|
|
@@ -419,5 +527,10 @@ module.exports = {
|
|
|
419
527
|
generateZshCompletion,
|
|
420
528
|
processBatchedFiles,
|
|
421
529
|
readFileAsync,
|
|
422
|
-
|
|
530
|
+
clearFileCache,
|
|
531
|
+
getFileCacheStats,
|
|
532
|
+
parseCode,
|
|
533
|
+
determineInvocationType,
|
|
534
|
+
determineLogLevel,
|
|
535
|
+
handleESVersionError
|
|
423
536
|
};
|