eslint 4.18.1 → 4.18.2
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/CHANGELOG.md +13 -0
- package/conf/environments.js +3 -1
- package/conf/eslint-recommended.js +0 -0
- package/lib/linter.js +368 -377
- package/lib/rules/max-len.js +2 -1
- package/lib/rules/template-tag-spacing.js +0 -0
- package/lib/util/interpolate.js +5 -1
- package/package.json +2 -2
- package/conf/default-config-options.js +0 -29
package/CHANGELOG.md
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
v4.18.2 - March 2, 2018
|
2
|
+
|
3
|
+
* 6b71fd0 Fix: table@4.0.2, because 4.0.3 needs "ajv": "^6.0.1" (#10022) (Mathieu Seiler)
|
4
|
+
* 3c697de Chore: fix incorrect comment about linter.verify return value (#10030) (Teddy Katz)
|
5
|
+
* 9df8653 Chore: refactor parser-loading out of linter.verify (#10028) (Teddy Katz)
|
6
|
+
* f6901d0 Fix: remove catastrophic backtracking vulnerability (fixes #10002) (#10019) (Jamie Davis)
|
7
|
+
* e4f52ce Chore: Simplify dataflow in linter.verify (#10020) (Teddy Katz)
|
8
|
+
* 33177cd Chore: make library files non-executable (#10021) (Teddy Katz)
|
9
|
+
* 558ccba Chore: refactor directive comment processing (#10007) (Teddy Katz)
|
10
|
+
* 18e15d9 Chore: avoid useless catch clauses that just rethrow errors (#10010) (Teddy Katz)
|
11
|
+
* a1c3759 Chore: refactor populating configs with defaults in linter (#10006) (Teddy Katz)
|
12
|
+
* aea07dc Fix: Make max-len ignoreStrings ignore JSXText (fixes #9954) (#9985) (Rachael Sim)
|
13
|
+
|
1
14
|
v4.18.1 - February 20, 2018
|
2
15
|
|
3
16
|
* f417506 Fix: ensure no-await-in-loop reports the correct node (fixes #9992) (#9993) (Teddy Katz)
|
package/conf/environments.js
CHANGED
File without changes
|
package/lib/linter.js
CHANGED
@@ -14,7 +14,6 @@ const eslintScope = require("eslint-scope"),
|
|
14
14
|
levn = require("levn"),
|
15
15
|
lodash = require("lodash"),
|
16
16
|
blankScriptAST = require("../conf/blank-script.json"),
|
17
|
-
defaultConfig = require("../conf/default-config-options.js"),
|
18
17
|
CodePathAnalyzer = require("./code-path-analysis/code-path-analyzer"),
|
19
18
|
ConfigOps = require("./config/config-ops"),
|
20
19
|
validator = require("./config/config-validator"),
|
@@ -33,6 +32,7 @@ const eslintScope = require("eslint-scope"),
|
|
33
32
|
|
34
33
|
const debug = require("debug")("eslint:linter");
|
35
34
|
const MAX_AUTOFIX_PASSES = 10;
|
35
|
+
const DEFAULT_PARSER_NAME = "espree";
|
36
36
|
|
37
37
|
//------------------------------------------------------------------------------
|
38
38
|
// Typedefs
|
@@ -178,32 +178,12 @@ function parseListConfig(string) {
|
|
178
178
|
* and any globals declared by special block comments, are present in the global
|
179
179
|
* scope.
|
180
180
|
* @param {Scope} globalScope The global scope.
|
181
|
-
* @param {Object}
|
182
|
-
* @param {
|
181
|
+
* @param {Object} configGlobals The globals declared in configuration
|
182
|
+
* @param {{exportedVariables: Object, enabledGlobals: Object}} commentDirectives Directives from comment configuration
|
183
183
|
* @returns {void}
|
184
184
|
*/
|
185
|
-
function addDeclaredGlobals(globalScope,
|
186
|
-
|
187
|
-
exportedGlobals = {},
|
188
|
-
explicitGlobals = {},
|
189
|
-
builtin = envContext.get("builtin");
|
190
|
-
|
191
|
-
Object.assign(declaredGlobals, builtin);
|
192
|
-
|
193
|
-
Object.keys(config.env).filter(name => config.env[name]).forEach(name => {
|
194
|
-
const env = envContext.get(name),
|
195
|
-
environmentGlobals = env && env.globals;
|
196
|
-
|
197
|
-
if (environmentGlobals) {
|
198
|
-
Object.assign(declaredGlobals, environmentGlobals);
|
199
|
-
}
|
200
|
-
});
|
201
|
-
|
202
|
-
Object.assign(exportedGlobals, config.exported);
|
203
|
-
Object.assign(declaredGlobals, config.globals);
|
204
|
-
Object.assign(explicitGlobals, config.astGlobals);
|
205
|
-
|
206
|
-
Object.keys(declaredGlobals).forEach(name => {
|
185
|
+
function addDeclaredGlobals(globalScope, configGlobals, commentDirectives) {
|
186
|
+
Object.keys(configGlobals).forEach(name => {
|
207
187
|
let variable = globalScope.set.get(name);
|
208
188
|
|
209
189
|
if (!variable) {
|
@@ -212,24 +192,24 @@ function addDeclaredGlobals(globalScope, config, envContext) {
|
|
212
192
|
globalScope.variables.push(variable);
|
213
193
|
globalScope.set.set(name, variable);
|
214
194
|
}
|
215
|
-
variable.writeable =
|
195
|
+
variable.writeable = configGlobals[name];
|
216
196
|
});
|
217
197
|
|
218
|
-
Object.keys(
|
198
|
+
Object.keys(commentDirectives.enabledGlobals).forEach(name => {
|
219
199
|
let variable = globalScope.set.get(name);
|
220
200
|
|
221
201
|
if (!variable) {
|
222
202
|
variable = new eslintScope.Variable(name, globalScope);
|
223
203
|
variable.eslintExplicitGlobal = true;
|
224
|
-
variable.eslintExplicitGlobalComment =
|
204
|
+
variable.eslintExplicitGlobalComment = commentDirectives.enabledGlobals[name].comment;
|
225
205
|
globalScope.variables.push(variable);
|
226
206
|
globalScope.set.set(name, variable);
|
227
207
|
}
|
228
|
-
variable.writeable =
|
208
|
+
variable.writeable = commentDirectives.enabledGlobals[name].value;
|
229
209
|
});
|
230
210
|
|
231
211
|
// mark all exported variables as such
|
232
|
-
Object.keys(
|
212
|
+
Object.keys(commentDirectives.exportedVariables).forEach(name => {
|
233
213
|
const variable = globalScope.set.get(name);
|
234
214
|
|
235
215
|
if (variable) {
|
@@ -283,108 +263,90 @@ function createDisableDirectives(type, loc, value) {
|
|
283
263
|
* where reporting is disabled or enabled and merges them with reporting config.
|
284
264
|
* @param {string} filename The file being checked.
|
285
265
|
* @param {ASTNode} ast The top node of the AST.
|
286
|
-
* @param {Object} config The existing configuration data.
|
287
266
|
* @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
|
288
|
-
* @returns {{
|
289
|
-
*
|
267
|
+
* @returns {{configuredRules: Object, enabledGlobals: Object, exportedVariables: Object, problems: Problem[], disableDirectives: DisableDirective[]}}
|
268
|
+
* A collection of the directive comments that were found, along with any problems that occurred when parsing
|
290
269
|
*/
|
291
|
-
function
|
292
|
-
|
293
|
-
const
|
294
|
-
|
295
|
-
astGlobals: {},
|
296
|
-
rules: {},
|
297
|
-
env: {}
|
298
|
-
};
|
299
|
-
const commentRules = {};
|
270
|
+
function getDirectiveComments(filename, ast, ruleMapper) {
|
271
|
+
const configuredRules = {};
|
272
|
+
const enabledGlobals = {};
|
273
|
+
const exportedVariables = {};
|
300
274
|
const problems = [];
|
301
275
|
const disableDirectives = [];
|
302
276
|
|
303
277
|
ast.comments.filter(token => token.type !== "Shebang").forEach(comment => {
|
278
|
+
const trimmedCommentText = comment.value.trim();
|
279
|
+
const match = /^(eslint(-\w+){0,3}|exported|globals?)(\s|$)/.exec(trimmedCommentText);
|
304
280
|
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
if (match) {
|
309
|
-
value = value.slice(match.index + match[1].length);
|
310
|
-
if (comment.type === "Block") {
|
311
|
-
switch (match[1]) {
|
312
|
-
case "exported":
|
313
|
-
Object.assign(commentConfig.exported, parseBooleanConfig(value, comment));
|
314
|
-
break;
|
315
|
-
|
316
|
-
case "globals":
|
317
|
-
case "global":
|
318
|
-
Object.assign(commentConfig.astGlobals, parseBooleanConfig(value, comment));
|
319
|
-
break;
|
320
|
-
|
321
|
-
case "eslint-disable":
|
322
|
-
[].push.apply(disableDirectives, createDisableDirectives("disable", comment.loc.start, value));
|
323
|
-
break;
|
324
|
-
|
325
|
-
case "eslint-disable-line":
|
326
|
-
if (comment.loc.start.line === comment.loc.end.line) {
|
327
|
-
[].push.apply(disableDirectives, createDisableDirectives("disable-line", comment.loc.start, value));
|
328
|
-
}
|
329
|
-
break;
|
330
|
-
|
331
|
-
case "eslint-disable-next-line":
|
332
|
-
if (comment.loc.start.line === comment.loc.end.line) {
|
333
|
-
[].push.apply(disableDirectives, createDisableDirectives("disable-next-line", comment.loc.start, value));
|
334
|
-
}
|
335
|
-
break;
|
336
|
-
|
337
|
-
case "eslint-enable":
|
338
|
-
[].push.apply(disableDirectives, createDisableDirectives("enable", comment.loc.start, value));
|
339
|
-
break;
|
340
|
-
|
341
|
-
case "eslint": {
|
342
|
-
const parseResult = parseJsonConfig(value, comment.loc);
|
343
|
-
|
344
|
-
if (parseResult.success) {
|
345
|
-
Object.keys(parseResult.config).forEach(name => {
|
346
|
-
const ruleValue = parseResult.config[name];
|
347
|
-
|
348
|
-
try {
|
349
|
-
validator.validateRuleOptions(ruleMapper(name), name, ruleValue);
|
350
|
-
} catch (err) {
|
351
|
-
problems.push({
|
352
|
-
ruleId: name,
|
353
|
-
severity: 2,
|
354
|
-
source: null,
|
355
|
-
message: err.message,
|
356
|
-
line: comment.loc.start.line,
|
357
|
-
column: comment.loc.start.column + 1,
|
358
|
-
endLine: comment.loc.end.line,
|
359
|
-
endColumn: comment.loc.end.column + 1,
|
360
|
-
nodeType: null
|
361
|
-
});
|
362
|
-
}
|
363
|
-
commentRules[name] = ruleValue;
|
364
|
-
});
|
365
|
-
} else {
|
366
|
-
problems.push(parseResult.error);
|
367
|
-
}
|
281
|
+
if (!match) {
|
282
|
+
return;
|
283
|
+
}
|
368
284
|
|
369
|
-
|
285
|
+
const directiveValue = trimmedCommentText.slice(match.index + match[1].length);
|
286
|
+
|
287
|
+
if (/^eslint-disable-(next-)?line$/.test(match[1]) && comment.loc.start.line === comment.loc.end.line) {
|
288
|
+
const directiveType = match[1].slice("eslint-".length);
|
289
|
+
|
290
|
+
[].push.apply(disableDirectives, createDisableDirectives(directiveType, comment.loc.start, directiveValue));
|
291
|
+
} else if (comment.type === "Block") {
|
292
|
+
switch (match[1]) {
|
293
|
+
case "exported":
|
294
|
+
Object.assign(exportedVariables, parseBooleanConfig(directiveValue, comment));
|
295
|
+
break;
|
296
|
+
|
297
|
+
case "globals":
|
298
|
+
case "global":
|
299
|
+
Object.assign(enabledGlobals, parseBooleanConfig(directiveValue, comment));
|
300
|
+
break;
|
301
|
+
|
302
|
+
case "eslint-disable":
|
303
|
+
[].push.apply(disableDirectives, createDisableDirectives("disable", comment.loc.start, directiveValue));
|
304
|
+
break;
|
305
|
+
|
306
|
+
case "eslint-enable":
|
307
|
+
[].push.apply(disableDirectives, createDisableDirectives("enable", comment.loc.start, directiveValue));
|
308
|
+
break;
|
309
|
+
|
310
|
+
case "eslint": {
|
311
|
+
const parseResult = parseJsonConfig(directiveValue, comment.loc);
|
312
|
+
|
313
|
+
if (parseResult.success) {
|
314
|
+
Object.keys(parseResult.config).forEach(name => {
|
315
|
+
const ruleValue = parseResult.config[name];
|
316
|
+
|
317
|
+
try {
|
318
|
+
validator.validateRuleOptions(ruleMapper(name), name, ruleValue);
|
319
|
+
} catch (err) {
|
320
|
+
problems.push({
|
321
|
+
ruleId: name,
|
322
|
+
severity: 2,
|
323
|
+
source: null,
|
324
|
+
message: err.message,
|
325
|
+
line: comment.loc.start.line,
|
326
|
+
column: comment.loc.start.column + 1,
|
327
|
+
endLine: comment.loc.end.line,
|
328
|
+
endColumn: comment.loc.end.column + 1,
|
329
|
+
nodeType: null
|
330
|
+
});
|
331
|
+
}
|
332
|
+
configuredRules[name] = ruleValue;
|
333
|
+
});
|
334
|
+
} else {
|
335
|
+
problems.push(parseResult.error);
|
370
336
|
}
|
371
337
|
|
372
|
-
|
373
|
-
}
|
374
|
-
} else { // comment.type === "Line"
|
375
|
-
if (match[1] === "eslint-disable-line") {
|
376
|
-
[].push.apply(disableDirectives, createDisableDirectives("disable-line", comment.loc.start, value));
|
377
|
-
} else if (match[1] === "eslint-disable-next-line") {
|
378
|
-
[].push.apply(disableDirectives, createDisableDirectives("disable-next-line", comment.loc.start, value));
|
338
|
+
break;
|
379
339
|
}
|
340
|
+
|
341
|
+
// no default
|
380
342
|
}
|
381
343
|
}
|
382
344
|
});
|
383
345
|
|
384
|
-
Object.assign(commentConfig.rules, commentRules);
|
385
|
-
|
386
346
|
return {
|
387
|
-
|
347
|
+
configuredRules,
|
348
|
+
enabledGlobals,
|
349
|
+
exportedVariables,
|
388
350
|
problems,
|
389
351
|
disableDirectives
|
390
352
|
};
|
@@ -414,81 +376,81 @@ function normalizeEcmaVersion(ecmaVersion, isModule) {
|
|
414
376
|
return ecmaVersion;
|
415
377
|
}
|
416
378
|
|
379
|
+
const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g;
|
380
|
+
|
417
381
|
/**
|
418
|
-
*
|
419
|
-
* @param
|
420
|
-
* @
|
421
|
-
* @returns {Object} Processed config
|
382
|
+
* Checks whether or not there is a comment which has "eslint-env *" in a given text.
|
383
|
+
* @param {string} text - A source code text to check.
|
384
|
+
* @returns {Object|null} A result of parseListConfig() with "eslint-env *" comment.
|
422
385
|
*/
|
423
|
-
function
|
424
|
-
|
425
|
-
const copiedRules = {};
|
426
|
-
let parserOptions = {};
|
386
|
+
function findEslintEnv(text) {
|
387
|
+
let match, retv;
|
427
388
|
|
428
|
-
|
429
|
-
Object.keys(config.rules).forEach(k => {
|
430
|
-
const rule = config.rules[k];
|
389
|
+
eslintEnvPattern.lastIndex = 0;
|
431
390
|
|
432
|
-
|
433
|
-
|
434
|
-
}
|
435
|
-
if (Array.isArray(rule)) {
|
436
|
-
copiedRules[k] = rule.slice();
|
437
|
-
} else {
|
438
|
-
copiedRules[k] = rule;
|
439
|
-
}
|
440
|
-
});
|
391
|
+
while ((match = eslintEnvPattern.exec(text))) {
|
392
|
+
retv = Object.assign(retv || {}, parseListConfig(match[1]));
|
441
393
|
}
|
442
394
|
|
443
|
-
|
444
|
-
|
445
|
-
Object.keys(config.env).forEach(envName => {
|
446
|
-
const env = envContext.get(envName);
|
395
|
+
return retv;
|
396
|
+
}
|
447
397
|
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
398
|
+
/**
|
399
|
+
* Normalizes the possible options for `linter.verify` and `linter.verifyAndFix` to a
|
400
|
+
* consistent shape.
|
401
|
+
* @param {(string|{reportUnusedDisableDirectives: boolean, filename: string, allowInlineConfig: boolean})} providedOptions Options
|
402
|
+
* @returns {{reportUnusedDisableDirectives: boolean, filename: string, allowInlineConfig: boolean}} Normalized options
|
403
|
+
*/
|
404
|
+
function normalizeVerifyOptions(providedOptions) {
|
405
|
+
const isObjectOptions = typeof providedOptions === "object";
|
406
|
+
const providedFilename = isObjectOptions ? providedOptions.filename : providedOptions;
|
453
407
|
|
454
|
-
|
455
|
-
|
456
|
-
|
457
|
-
|
458
|
-
env: ConfigOps.merge(defaultConfig.env, config.env || {}),
|
459
|
-
settings: ConfigOps.merge(defaultConfig.settings, config.settings || {}),
|
460
|
-
parserOptions: ConfigOps.merge(parserOptions, config.parserOptions || {})
|
408
|
+
return {
|
409
|
+
filename: typeof providedFilename === "string" ? providedFilename : "<input>",
|
410
|
+
allowInlineConfig: !isObjectOptions || providedOptions.allowInlineConfig !== false,
|
411
|
+
reportUnusedDisableDirectives: isObjectOptions && !!providedOptions.reportUnusedDisableDirectives
|
461
412
|
};
|
462
|
-
|
413
|
+
}
|
414
|
+
|
415
|
+
/**
|
416
|
+
* Combines the provided parserOptions with the options from environments
|
417
|
+
* @param {Object} providedOptions The provided 'parserOptions' key in a config
|
418
|
+
* @param {Environment[]} enabledEnvironments The environments enabled in configuration and with inline comments
|
419
|
+
* @returns {Object} Resulting parser options after merge
|
420
|
+
*/
|
421
|
+
function resolveParserOptions(providedOptions, enabledEnvironments) {
|
422
|
+
const parserOptionsFromEnv = enabledEnvironments
|
423
|
+
.filter(env => env.parserOptions)
|
424
|
+
.reduce((parserOptions, env) => ConfigOps.merge(parserOptions, env.parserOptions), {});
|
425
|
+
|
426
|
+
const mergedParserOptions = ConfigOps.merge(parserOptionsFromEnv, providedOptions || {});
|
427
|
+
|
428
|
+
const isModule = mergedParserOptions.sourceType === "module";
|
463
429
|
|
464
430
|
if (isModule) {
|
465
431
|
|
466
432
|
// can't have global return inside of modules
|
467
|
-
|
433
|
+
mergedParserOptions.ecmaFeatures = Object.assign({}, mergedParserOptions.ecmaFeatures, { globalReturn: false });
|
468
434
|
}
|
469
435
|
|
470
|
-
|
436
|
+
mergedParserOptions.ecmaVersion = normalizeEcmaVersion(mergedParserOptions.ecmaVersion, isModule);
|
471
437
|
|
472
|
-
return
|
438
|
+
return mergedParserOptions;
|
473
439
|
}
|
474
440
|
|
475
|
-
const eslintEnvPattern = /\/\*\s*eslint-env\s(.+?)\*\//g;
|
476
|
-
|
477
441
|
/**
|
478
|
-
*
|
479
|
-
* @param {
|
480
|
-
* @
|
442
|
+
* Combines the provided globals object with the globals from environments
|
443
|
+
* @param {Object} providedGlobals The 'globals' key in a config
|
444
|
+
* @param {Environments[]} enabledEnvironments The environments enabled in configuration and with inline comments
|
445
|
+
* @returns {Object} The resolved globals object
|
481
446
|
*/
|
482
|
-
function
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
}
|
490
|
-
|
491
|
-
return retv;
|
447
|
+
function resolveGlobals(providedGlobals, enabledEnvironments) {
|
448
|
+
return Object.assign.apply(
|
449
|
+
null,
|
450
|
+
[{}]
|
451
|
+
.concat(enabledEnvironments.filter(env => env.globals).map(env => env.globals))
|
452
|
+
.concat(providedGlobals)
|
453
|
+
);
|
492
454
|
}
|
493
455
|
|
494
456
|
/**
|
@@ -551,13 +513,16 @@ function analyzeScope(ast, parserOptions, visitorKeys) {
|
|
551
513
|
* as possible
|
552
514
|
* @param {string} text The text to parse.
|
553
515
|
* @param {Object} providedParserOptions Options to pass to the parser
|
554
|
-
* @param {
|
516
|
+
* @param {string} parserName The name of the parser
|
517
|
+
* @param {Map<string, Object>} parserMap A map from names to loaded parsers
|
555
518
|
* @param {string} filePath The path to the file being parsed.
|
556
519
|
* @returns {{success: false, error: Problem}|{success: true, sourceCode: SourceCode}}
|
557
520
|
* An object containing the AST and parser services if parsing was successful, or the error if parsing failed
|
558
521
|
* @private
|
559
522
|
*/
|
560
|
-
function parse(text, providedParserOptions,
|
523
|
+
function parse(text, providedParserOptions, parserName, parserMap, filePath) {
|
524
|
+
|
525
|
+
|
561
526
|
const textToParse = stripUnicodeBOM(text).replace(astUtils.SHEBANG_MATCHER, (match, captured) => `//${captured}`);
|
562
527
|
const parserOptions = Object.assign({}, providedParserOptions, {
|
563
528
|
loc: true,
|
@@ -570,6 +535,25 @@ function parse(text, providedParserOptions, parser, filePath) {
|
|
570
535
|
filePath
|
571
536
|
});
|
572
537
|
|
538
|
+
let parser;
|
539
|
+
|
540
|
+
try {
|
541
|
+
parser = parserMap.get(parserName) || require(parserName);
|
542
|
+
} catch (ex) {
|
543
|
+
return {
|
544
|
+
success: false,
|
545
|
+
error: {
|
546
|
+
ruleId: null,
|
547
|
+
fatal: true,
|
548
|
+
severity: 2,
|
549
|
+
source: null,
|
550
|
+
message: ex.message,
|
551
|
+
line: 0,
|
552
|
+
column: 0
|
553
|
+
}
|
554
|
+
};
|
555
|
+
}
|
556
|
+
|
573
557
|
/*
|
574
558
|
* Check for parsing errors first. If there's a parsing error, nothing
|
575
559
|
* else can happen. However, a parsing error does not throw an error
|
@@ -688,6 +672,21 @@ function markVariableAsUsed(scopeManager, currentNode, parserOptions, name) {
|
|
688
672
|
return false;
|
689
673
|
}
|
690
674
|
|
675
|
+
/**
|
676
|
+
* Runs a rule, and gets its listeners
|
677
|
+
* @param {Rule} rule A normalized rule with a `create` method
|
678
|
+
* @param {Context} ruleContext The context that should be passed to the rule
|
679
|
+
* @returns {Object} A map of selector listeners provided by the rule
|
680
|
+
*/
|
681
|
+
function createRuleListeners(rule, ruleContext) {
|
682
|
+
try {
|
683
|
+
return rule.create(ruleContext);
|
684
|
+
} catch (ex) {
|
685
|
+
ex.message = `Error while loading rule '${ruleContext.id}': ${ex.message}`;
|
686
|
+
throw ex;
|
687
|
+
}
|
688
|
+
}
|
689
|
+
|
691
690
|
// methods that exist on SourceCode object
|
692
691
|
const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
|
693
692
|
getSource: "getText",
|
@@ -726,7 +725,157 @@ const BASE_TRAVERSAL_CONTEXT = Object.freeze(
|
|
726
725
|
)
|
727
726
|
);
|
728
727
|
|
728
|
+
/**
|
729
|
+
* Runs the given rules on the given SourceCode object
|
730
|
+
* @param {SourceCode} sourceCode A SourceCode object for the given text
|
731
|
+
* @param {Object} configuredRules The rules configuration
|
732
|
+
* @param {function(string): Rule} ruleMapper A mapper function from rule names to rules
|
733
|
+
* @param {Object} parserOptions The options that were passed to the parser
|
734
|
+
* @param {string} parserName The name of the parser in the config
|
735
|
+
* @param {Object} settings The settings that were enabled in the config
|
736
|
+
* @param {string} filename The reported filename of the code
|
737
|
+
* @returns {Problem[]} An array of reported problems
|
738
|
+
*/
|
739
|
+
function runRules(sourceCode, configuredRules, ruleMapper, parserOptions, parserName, settings, filename) {
|
740
|
+
const emitter = createEmitter();
|
741
|
+
const traverser = new Traverser();
|
742
|
+
|
743
|
+
/*
|
744
|
+
* Create a frozen object with the ruleContext properties and methods that are shared by all rules.
|
745
|
+
* All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
|
746
|
+
* properties once for each rule.
|
747
|
+
*/
|
748
|
+
const sharedTraversalContext = Object.freeze(
|
749
|
+
Object.assign(
|
750
|
+
Object.create(BASE_TRAVERSAL_CONTEXT),
|
751
|
+
{
|
752
|
+
getAncestors: () => traverser.parents(),
|
753
|
+
getDeclaredVariables: sourceCode.scopeManager.getDeclaredVariables.bind(sourceCode.scopeManager),
|
754
|
+
getFilename: () => filename,
|
755
|
+
getScope: () => getScope(sourceCode.scopeManager, traverser.current(), parserOptions.ecmaVersion),
|
756
|
+
getSourceCode: () => sourceCode,
|
757
|
+
markVariableAsUsed: name => markVariableAsUsed(sourceCode.scopeManager, traverser.current(), parserOptions, name),
|
758
|
+
parserOptions,
|
759
|
+
parserPath: parserName,
|
760
|
+
parserServices: sourceCode.parserServices,
|
761
|
+
settings,
|
762
|
+
|
763
|
+
/**
|
764
|
+
* This is used to avoid breaking rules that used to monkeypatch the `Linter#report` method
|
765
|
+
* by using the `_linter` property on rule contexts.
|
766
|
+
*
|
767
|
+
* This should be removed in a major release after we create a better way to
|
768
|
+
* lint for unused disable comments.
|
769
|
+
* https://github.com/eslint/eslint/issues/9193
|
770
|
+
*/
|
771
|
+
_linter: {
|
772
|
+
report() {},
|
773
|
+
on: emitter.on
|
774
|
+
}
|
775
|
+
}
|
776
|
+
)
|
777
|
+
);
|
778
|
+
|
779
|
+
|
780
|
+
const lintingProblems = [];
|
781
|
+
|
782
|
+
Object.keys(configuredRules).forEach(ruleId => {
|
783
|
+
const severity = ConfigOps.getRuleSeverity(configuredRules[ruleId]);
|
784
|
+
|
785
|
+
if (severity === 0) {
|
786
|
+
return;
|
787
|
+
}
|
788
|
+
|
789
|
+
const rule = ruleMapper(ruleId);
|
790
|
+
const messageIds = rule.meta && rule.meta.messages;
|
791
|
+
let reportTranslator = null;
|
792
|
+
const ruleContext = Object.freeze(
|
793
|
+
Object.assign(
|
794
|
+
Object.create(sharedTraversalContext),
|
795
|
+
{
|
796
|
+
id: ruleId,
|
797
|
+
options: getRuleOptions(configuredRules[ruleId]),
|
798
|
+
report() {
|
799
|
+
|
800
|
+
/*
|
801
|
+
* Create a report translator lazily.
|
802
|
+
* In a vast majority of cases, any given rule reports zero errors on a given
|
803
|
+
* piece of code. Creating a translator lazily avoids the performance cost of
|
804
|
+
* creating a new translator function for each rule that usually doesn't get
|
805
|
+
* called.
|
806
|
+
*
|
807
|
+
* Using lazy report translators improves end-to-end performance by about 3%
|
808
|
+
* with Node 8.4.0.
|
809
|
+
*/
|
810
|
+
if (reportTranslator === null) {
|
811
|
+
reportTranslator = createReportTranslator({ ruleId, severity, sourceCode, messageIds });
|
812
|
+
}
|
813
|
+
const problem = reportTranslator.apply(null, arguments);
|
814
|
+
|
815
|
+
if (problem.fix && rule.meta && !rule.meta.fixable) {
|
816
|
+
throw new Error("Fixable rules should export a `meta.fixable` property.");
|
817
|
+
}
|
818
|
+
lintingProblems.push(problem);
|
819
|
+
|
820
|
+
/*
|
821
|
+
* This is used to avoid breaking rules that used monkeypatch Linter, and relied on
|
822
|
+
* `linter.report` getting called with report info every time a rule reports a problem.
|
823
|
+
* To continue to support this, make sure that `context._linter.report` is called every
|
824
|
+
* time a problem is reported by a rule, even though `context._linter` is no longer a
|
825
|
+
* `Linter` instance.
|
826
|
+
*
|
827
|
+
* This should be removed in a major release after we create a better way to
|
828
|
+
* lint for unused disable comments.
|
829
|
+
* https://github.com/eslint/eslint/issues/9193
|
830
|
+
*/
|
831
|
+
sharedTraversalContext._linter.report( // eslint-disable-line no-underscore-dangle
|
832
|
+
problem.ruleId,
|
833
|
+
problem.severity,
|
834
|
+
{ loc: { start: { line: problem.line, column: problem.column - 1 } } },
|
835
|
+
problem.message
|
836
|
+
);
|
837
|
+
}
|
838
|
+
}
|
839
|
+
)
|
840
|
+
);
|
841
|
+
|
842
|
+
const ruleListeners = createRuleListeners(rule, ruleContext);
|
843
|
+
|
844
|
+
// add all the selectors from the rule as listeners
|
845
|
+
Object.keys(ruleListeners).forEach(selector => {
|
846
|
+
emitter.on(
|
847
|
+
selector,
|
848
|
+
timing.enabled
|
849
|
+
? timing.time(ruleId, ruleListeners[selector])
|
850
|
+
: ruleListeners[selector]
|
851
|
+
);
|
852
|
+
});
|
853
|
+
});
|
854
|
+
|
855
|
+
const eventGenerator = new CodePathAnalyzer(new NodeEventGenerator(emitter));
|
856
|
+
|
857
|
+
/*
|
858
|
+
* Each node has a type property. Whenever a particular type of
|
859
|
+
* node is found, an event is fired. This allows any listeners to
|
860
|
+
* automatically be informed that this type of node has been found
|
861
|
+
* and react accordingly.
|
862
|
+
*/
|
863
|
+
traverser.traverse(sourceCode.ast, {
|
864
|
+
enter(node, parent) {
|
865
|
+
node.parent = parent;
|
866
|
+
eventGenerator.enterNode(node);
|
867
|
+
},
|
868
|
+
leave(node) {
|
869
|
+
eventGenerator.leaveNode(node);
|
870
|
+
},
|
871
|
+
visitorKeys: sourceCode.visitorKeys
|
872
|
+
});
|
873
|
+
|
874
|
+
return lintingProblems;
|
875
|
+
}
|
876
|
+
|
729
877
|
const lastSourceCodes = new WeakMap();
|
878
|
+
const loadedParserMaps = new WeakMap();
|
730
879
|
|
731
880
|
//------------------------------------------------------------------------------
|
732
881
|
// Public Interface
|
@@ -740,10 +889,10 @@ module.exports = class Linter {
|
|
740
889
|
|
741
890
|
constructor() {
|
742
891
|
lastSourceCodes.set(this, null);
|
892
|
+
loadedParserMaps.set(this, new Map());
|
743
893
|
this.version = pkg.version;
|
744
894
|
|
745
895
|
this.rules = new Rules();
|
746
|
-
this._parsers = new Map();
|
747
896
|
this.environments = new Environments();
|
748
897
|
}
|
749
898
|
|
@@ -761,7 +910,7 @@ module.exports = class Linter {
|
|
761
910
|
/**
|
762
911
|
* Same as linter.verify, except without support for processors.
|
763
912
|
* @param {string|SourceCode} textOrSourceCode The text to parse or a SourceCode object.
|
764
|
-
* @param {ESLintConfig}
|
913
|
+
* @param {ESLintConfig} providedConfig An ESLintConfig instance to configure everything.
|
765
914
|
* @param {(string|Object)} [filenameOrOptions] The optional filename of the file being checked.
|
766
915
|
* If this is not set, the filename will default to '<input>' in the rule context. If
|
767
916
|
* an object, then it has "filename", "saveState", and "allowInlineConfig" properties.
|
@@ -769,23 +918,14 @@ module.exports = class Linter {
|
|
769
918
|
* Useful if you want to validate JS without comments overriding rules.
|
770
919
|
* @param {boolean} [filenameOrOptions.reportUnusedDisableDirectives=false] Adds reported errors for unused
|
771
920
|
* eslint-disable directives
|
772
|
-
* @returns {Object[]} The results as an array of messages or
|
921
|
+
* @returns {Object[]} The results as an array of messages or an empty array if no messages.
|
773
922
|
*/
|
774
|
-
_verifyWithoutProcessors(textOrSourceCode,
|
775
|
-
|
776
|
-
|
777
|
-
|
778
|
-
reportUnusedDisableDirectives;
|
923
|
+
_verifyWithoutProcessors(textOrSourceCode, providedConfig, filenameOrOptions) {
|
924
|
+
const config = providedConfig || {};
|
925
|
+
const options = normalizeVerifyOptions(filenameOrOptions);
|
926
|
+
let text;
|
779
927
|
|
780
928
|
// evaluate arguments
|
781
|
-
if (typeof filenameOrOptions === "object") {
|
782
|
-
providedFilename = filenameOrOptions.filename;
|
783
|
-
allowInlineConfig = filenameOrOptions.allowInlineConfig;
|
784
|
-
reportUnusedDisableDirectives = filenameOrOptions.reportUnusedDisableDirectives;
|
785
|
-
} else {
|
786
|
-
providedFilename = filenameOrOptions;
|
787
|
-
}
|
788
|
-
|
789
929
|
if (typeof textOrSourceCode === "string") {
|
790
930
|
lastSourceCodes.set(this, null);
|
791
931
|
text = textOrSourceCode;
|
@@ -794,23 +934,18 @@ module.exports = class Linter {
|
|
794
934
|
text = textOrSourceCode.text;
|
795
935
|
}
|
796
936
|
|
797
|
-
const filename = typeof providedFilename === "string" ? providedFilename : "<input>";
|
798
|
-
|
799
937
|
// search and apply "eslint-env *".
|
800
938
|
const envInFile = findEslintEnv(text);
|
939
|
+
const resolvedEnvConfig = Object.assign({ builtin: true }, config.env, envInFile);
|
940
|
+
const enabledEnvs = Object.keys(resolvedEnvConfig)
|
941
|
+
.filter(envName => resolvedEnvConfig[envName])
|
942
|
+
.map(envName => this.environments.get(envName))
|
943
|
+
.filter(env => env);
|
801
944
|
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
config.env = Object.assign({}, config.env, envInFile);
|
807
|
-
} else {
|
808
|
-
config.env = envInFile;
|
809
|
-
}
|
810
|
-
}
|
811
|
-
|
812
|
-
// process initial config to make it safe to extend
|
813
|
-
config = prepareConfig(config, this.environments);
|
945
|
+
const parserOptions = resolveParserOptions(config.parserOptions || {}, enabledEnvs);
|
946
|
+
const configuredGlobals = resolveGlobals(config.globals || {}, enabledEnvs);
|
947
|
+
const parserName = config.parser || DEFAULT_PARSER_NAME;
|
948
|
+
const settings = config.settings || {};
|
814
949
|
|
815
950
|
if (!lastSourceCodes.get(this)) {
|
816
951
|
|
@@ -820,26 +955,12 @@ module.exports = class Linter {
|
|
820
955
|
return [];
|
821
956
|
}
|
822
957
|
|
823
|
-
let parser;
|
824
|
-
|
825
|
-
try {
|
826
|
-
parser = this._parsers.get(config.parser) || require(config.parser);
|
827
|
-
} catch (ex) {
|
828
|
-
return [{
|
829
|
-
ruleId: null,
|
830
|
-
fatal: true,
|
831
|
-
severity: 2,
|
832
|
-
source: null,
|
833
|
-
message: ex.message,
|
834
|
-
line: 0,
|
835
|
-
column: 0
|
836
|
-
}];
|
837
|
-
}
|
838
958
|
const parseResult = parse(
|
839
959
|
text,
|
840
|
-
|
841
|
-
|
842
|
-
|
960
|
+
parserOptions,
|
961
|
+
parserName,
|
962
|
+
loadedParserMaps.get(this),
|
963
|
+
options.filename
|
843
964
|
);
|
844
965
|
|
845
966
|
if (!parseResult.success) {
|
@@ -861,171 +982,41 @@ module.exports = class Linter {
|
|
861
982
|
ast: lastSourceCode.ast,
|
862
983
|
parserServices: lastSourceCode.parserServices,
|
863
984
|
visitorKeys: lastSourceCode.visitorKeys,
|
864
|
-
scopeManager: analyzeScope(lastSourceCode.ast,
|
985
|
+
scopeManager: analyzeScope(lastSourceCode.ast, parserOptions)
|
865
986
|
}));
|
866
987
|
}
|
867
988
|
}
|
868
989
|
|
869
|
-
const problems = [];
|
870
990
|
const sourceCode = lastSourceCodes.get(this);
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
if (allowInlineConfig !== false) {
|
875
|
-
const modifyConfigResult = modifyConfigsFromComments(filename, sourceCode.ast, config, ruleId => this.rules.get(ruleId));
|
876
|
-
|
877
|
-
config = modifyConfigResult.config;
|
878
|
-
modifyConfigResult.problems.forEach(problem => problems.push(problem));
|
879
|
-
disableDirectives = modifyConfigResult.disableDirectives;
|
880
|
-
} else {
|
881
|
-
disableDirectives = [];
|
882
|
-
}
|
883
|
-
|
884
|
-
const emitter = createEmitter();
|
885
|
-
const traverser = new Traverser();
|
886
|
-
const scopeManager = sourceCode.scopeManager;
|
887
|
-
|
888
|
-
/*
|
889
|
-
* Create a frozen object with the ruleContext properties and methods that are shared by all rules.
|
890
|
-
* All rule contexts will inherit from this object. This avoids the performance penalty of copying all the
|
891
|
-
* properties once for each rule.
|
892
|
-
*/
|
893
|
-
const sharedTraversalContext = Object.freeze(
|
894
|
-
Object.assign(
|
895
|
-
Object.create(BASE_TRAVERSAL_CONTEXT),
|
896
|
-
{
|
897
|
-
getAncestors: () => traverser.parents(),
|
898
|
-
getDeclaredVariables: scopeManager.getDeclaredVariables.bind(scopeManager),
|
899
|
-
getFilename: () => filename,
|
900
|
-
getScope: () => getScope(scopeManager, traverser.current(), config.parserOptions.ecmaVersion),
|
901
|
-
getSourceCode: () => sourceCode,
|
902
|
-
markVariableAsUsed: name => markVariableAsUsed(scopeManager, traverser.current(), config.parserOptions, name),
|
903
|
-
parserOptions: config.parserOptions,
|
904
|
-
parserPath: config.parser,
|
905
|
-
parserServices: sourceCode.parserServices,
|
906
|
-
settings: config.settings,
|
907
|
-
|
908
|
-
/**
|
909
|
-
* This is used to avoid breaking rules that used to monkeypatch the `Linter#report` method
|
910
|
-
* by using the `_linter` property on rule contexts.
|
911
|
-
*
|
912
|
-
* This should be removed in a major release after we create a better way to
|
913
|
-
* lint for unused disable comments.
|
914
|
-
* https://github.com/eslint/eslint/issues/9193
|
915
|
-
*/
|
916
|
-
_linter: {
|
917
|
-
report() {},
|
918
|
-
on: emitter.on
|
919
|
-
}
|
920
|
-
}
|
921
|
-
)
|
922
|
-
);
|
923
|
-
|
924
|
-
// enable appropriate rules
|
925
|
-
Object.keys(config.rules).forEach(ruleId => {
|
926
|
-
const severity = ConfigOps.getRuleSeverity(config.rules[ruleId]);
|
927
|
-
|
928
|
-
if (severity === 0) {
|
929
|
-
return;
|
930
|
-
}
|
931
|
-
|
932
|
-
const rule = this.rules.get(ruleId);
|
933
|
-
const messageIds = rule && rule.meta && rule.meta.messages;
|
934
|
-
let reportTranslator = null;
|
935
|
-
const ruleContext = Object.freeze(
|
936
|
-
Object.assign(
|
937
|
-
Object.create(sharedTraversalContext),
|
938
|
-
{
|
939
|
-
id: ruleId,
|
940
|
-
options: getRuleOptions(config.rules[ruleId]),
|
941
|
-
report() {
|
942
|
-
|
943
|
-
/*
|
944
|
-
* Create a report translator lazily.
|
945
|
-
* In a vast majority of cases, any given rule reports zero errors on a given
|
946
|
-
* piece of code. Creating a translator lazily avoids the performance cost of
|
947
|
-
* creating a new translator function for each rule that usually doesn't get
|
948
|
-
* called.
|
949
|
-
*
|
950
|
-
* Using lazy report translators improves end-to-end performance by about 3%
|
951
|
-
* with Node 8.4.0.
|
952
|
-
*/
|
953
|
-
if (reportTranslator === null) {
|
954
|
-
reportTranslator = createReportTranslator({ ruleId, severity, sourceCode, messageIds });
|
955
|
-
}
|
956
|
-
const problem = reportTranslator.apply(null, arguments);
|
957
|
-
|
958
|
-
if (problem.fix && rule.meta && !rule.meta.fixable) {
|
959
|
-
throw new Error("Fixable rules should export a `meta.fixable` property.");
|
960
|
-
}
|
961
|
-
problems.push(problem);
|
962
|
-
|
963
|
-
/*
|
964
|
-
* This is used to avoid breaking rules that used monkeypatch Linter, and relied on
|
965
|
-
* `linter.report` getting called with report info every time a rule reports a problem.
|
966
|
-
* To continue to support this, make sure that `context._linter.report` is called every
|
967
|
-
* time a problem is reported by a rule, even though `context._linter` is no longer a
|
968
|
-
* `Linter` instance.
|
969
|
-
*
|
970
|
-
* This should be removed in a major release after we create a better way to
|
971
|
-
* lint for unused disable comments.
|
972
|
-
* https://github.com/eslint/eslint/issues/9193
|
973
|
-
*/
|
974
|
-
sharedTraversalContext._linter.report( // eslint-disable-line no-underscore-dangle
|
975
|
-
problem.ruleId,
|
976
|
-
problem.severity,
|
977
|
-
{ loc: { start: { line: problem.line, column: problem.column - 1 } } },
|
978
|
-
problem.message
|
979
|
-
);
|
980
|
-
}
|
981
|
-
}
|
982
|
-
)
|
983
|
-
);
|
984
|
-
|
985
|
-
try {
|
986
|
-
const ruleListeners = rule.create(ruleContext);
|
987
|
-
|
988
|
-
// add all the selectors from the rule as listeners
|
989
|
-
Object.keys(ruleListeners).forEach(selector => {
|
990
|
-
emitter.on(
|
991
|
-
selector,
|
992
|
-
timing.enabled
|
993
|
-
? timing.time(ruleId, ruleListeners[selector])
|
994
|
-
: ruleListeners[selector]
|
995
|
-
);
|
996
|
-
});
|
997
|
-
} catch (ex) {
|
998
|
-
ex.message = `Error while loading rule '${ruleId}': ${ex.message}`;
|
999
|
-
throw ex;
|
1000
|
-
}
|
1001
|
-
});
|
991
|
+
const commentDirectives = options.allowInlineConfig
|
992
|
+
? getDirectiveComments(options.filename, sourceCode.ast, ruleId => this.rules.get(ruleId))
|
993
|
+
: { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
|
1002
994
|
|
1003
995
|
// augment global scope with declared global variables
|
1004
|
-
addDeclaredGlobals(
|
996
|
+
addDeclaredGlobals(
|
997
|
+
sourceCode.scopeManager.scopes[0],
|
998
|
+
configuredGlobals,
|
999
|
+
{ exportedVariables: commentDirectives.exportedVariables, enabledGlobals: commentDirectives.enabledGlobals }
|
1000
|
+
);
|
1005
1001
|
|
1006
|
-
const
|
1002
|
+
const configuredRules = Object.assign({}, config.rules, commentDirectives.configuredRules);
|
1007
1003
|
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
eventGenerator.enterNode(node);
|
1018
|
-
},
|
1019
|
-
leave(node) {
|
1020
|
-
eventGenerator.leaveNode(node);
|
1021
|
-
},
|
1022
|
-
visitorKeys: sourceCode.visitorKeys
|
1023
|
-
});
|
1004
|
+
const lintingProblems = runRules(
|
1005
|
+
sourceCode,
|
1006
|
+
configuredRules,
|
1007
|
+
ruleId => this.rules.get(ruleId),
|
1008
|
+
parserOptions,
|
1009
|
+
parserName,
|
1010
|
+
settings,
|
1011
|
+
options.filename
|
1012
|
+
);
|
1024
1013
|
|
1025
1014
|
return applyDisableDirectives({
|
1026
|
-
directives: disableDirectives,
|
1027
|
-
problems:
|
1028
|
-
|
1015
|
+
directives: commentDirectives.disableDirectives,
|
1016
|
+
problems: lintingProblems
|
1017
|
+
.concat(commentDirectives.problems)
|
1018
|
+
.sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
|
1019
|
+
reportUnusedDisableDirectives: options.reportUnusedDisableDirectives
|
1029
1020
|
});
|
1030
1021
|
}
|
1031
1022
|
|
@@ -1045,7 +1036,7 @@ module.exports = class Linter {
|
|
1045
1036
|
* @param {function(Array<Object[]>): Object[]} [filenameOrOptions.postprocess] postprocessor for report messages. If provided,
|
1046
1037
|
* this should accept an array of the message lists for each code block returned from the preprocessor,
|
1047
1038
|
* apply a mapping to the messages as appropriate, and return a one-dimensional array of messages
|
1048
|
-
* @returns {Object[]} The results as an array of messages or
|
1039
|
+
* @returns {Object[]} The results as an array of messages or an empty array if no messages.
|
1049
1040
|
*/
|
1050
1041
|
verify(textOrSourceCode, config, filenameOrOptions) {
|
1051
1042
|
const preprocess = filenameOrOptions && filenameOrOptions.preprocess || (rawText => [rawText]);
|
@@ -1102,7 +1093,7 @@ module.exports = class Linter {
|
|
1102
1093
|
* @returns {void}
|
1103
1094
|
*/
|
1104
1095
|
defineParser(parserId, parserModule) {
|
1105
|
-
this.
|
1096
|
+
loadedParserMaps.get(this).set(parserId, parserModule);
|
1106
1097
|
}
|
1107
1098
|
|
1108
1099
|
/**
|
package/lib/rules/max-len.js
CHANGED
@@ -213,7 +213,8 @@ module.exports = {
|
|
213
213
|
* @returns {ASTNode[]} An array of string nodes.
|
214
214
|
*/
|
215
215
|
function getAllStrings() {
|
216
|
-
return sourceCode.ast.tokens.filter(token => token.type === "String"
|
216
|
+
return sourceCode.ast.tokens.filter(token => (token.type === "String" ||
|
217
|
+
(token.type === "JSXText" && sourceCode.getNodeByRangeIndex(token.range[0] - 1).type === "JSXAttribute")));
|
217
218
|
}
|
218
219
|
|
219
220
|
/**
|
File without changes
|
package/lib/util/interpolate.js
CHANGED
@@ -13,7 +13,11 @@ module.exports = (text, data) => {
|
|
13
13
|
if (!data) {
|
14
14
|
return text;
|
15
15
|
}
|
16
|
-
|
16
|
+
|
17
|
+
// Substitution content for any {{ }} markers.
|
18
|
+
return text.replace(/\{\{([^{}]+?)\}\}/g, (fullMatch, termWithWhitespace) => {
|
19
|
+
const term = termWithWhitespace.trim();
|
20
|
+
|
17
21
|
if (term in data) {
|
18
22
|
return data[term];
|
19
23
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "eslint",
|
3
|
-
"version": "4.18.
|
3
|
+
"version": "4.18.2",
|
4
4
|
"author": "Nicholas C. Zakas <nicholas+npm@nczconsulting.com>",
|
5
5
|
"description": "An AST-based pattern checker for JavaScript.",
|
6
6
|
"bin": {
|
@@ -69,7 +69,7 @@
|
|
69
69
|
"semver": "^5.3.0",
|
70
70
|
"strip-ansi": "^4.0.0",
|
71
71
|
"strip-json-comments": "~2.0.1",
|
72
|
-
"table": "
|
72
|
+
"table": "4.0.2",
|
73
73
|
"text-table": "~0.2.0"
|
74
74
|
},
|
75
75
|
"devDependencies": {
|
@@ -1,29 +0,0 @@
|
|
1
|
-
/**
|
2
|
-
* @fileoverview Default config options
|
3
|
-
* @author Teddy Katz
|
4
|
-
*/
|
5
|
-
|
6
|
-
"use strict";
|
7
|
-
|
8
|
-
/**
|
9
|
-
* Freezes an object and all its nested properties
|
10
|
-
* @param {Object} obj The object to deeply freeze
|
11
|
-
* @returns {Object} `obj` after freezing it
|
12
|
-
*/
|
13
|
-
function deepFreeze(obj) {
|
14
|
-
if (obj === null || typeof obj !== "object") {
|
15
|
-
return obj;
|
16
|
-
}
|
17
|
-
|
18
|
-
Object.keys(obj).map(key => obj[key]).forEach(deepFreeze);
|
19
|
-
return Object.freeze(obj);
|
20
|
-
}
|
21
|
-
|
22
|
-
module.exports = deepFreeze({
|
23
|
-
env: {},
|
24
|
-
globals: {},
|
25
|
-
rules: {},
|
26
|
-
settings: {},
|
27
|
-
parser: "espree",
|
28
|
-
parserOptions: {}
|
29
|
-
});
|