eslint 8.49.0 → 8.51.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.
@@ -139,7 +139,7 @@ module.exports = class ConfigCommentParser {
139
139
  const items = {};
140
140
 
141
141
  string.split(",").forEach(name => {
142
- const trimmedName = name.trim();
142
+ const trimmedName = name.trim().replace(/^(?<quote>['"]?)(?<ruleId>.*)\k<quote>$/us, "$<ruleId>");
143
143
 
144
144
  if (trimmedName) {
145
145
  items[trimmedName] = true;
@@ -42,7 +42,8 @@ const
42
42
  ruleReplacements = require("../../conf/replacements.json");
43
43
  const { getRuleFromConfig } = require("../config/flat-config-helpers");
44
44
  const { FlatConfigArray } = require("../config/flat-config-array");
45
-
45
+ const { RuleValidator } = require("../config/rule-validator");
46
+ const { assertIsRuleOptions, assertIsRuleSeverity } = require("../config/flat-config-schema");
46
47
  const debug = require("debug")("eslint:linter");
47
48
  const MAX_AUTOFIX_PASSES = 10;
48
49
  const DEFAULT_PARSER_NAME = "espree";
@@ -50,7 +51,6 @@ const DEFAULT_ECMA_VERSION = 5;
50
51
  const commentParser = new ConfigCommentParser();
51
52
  const DEFAULT_ERROR_LOC = { start: { line: 1, column: 0 }, end: { line: 1, column: 1 } };
52
53
  const parserSymbol = Symbol.for("eslint.RuleTester.parser");
53
- const globals = require("../../conf/globals");
54
54
 
55
55
  //------------------------------------------------------------------------------
56
56
  // Typedefs
@@ -145,29 +145,6 @@ function isEspree(parser) {
145
145
  return !!(parser === espree || parser[parserSymbol] === espree);
146
146
  }
147
147
 
148
- /**
149
- * Retrieves globals for the given ecmaVersion.
150
- * @param {number} ecmaVersion The version to retrieve globals for.
151
- * @returns {Object} The globals for the given ecmaVersion.
152
- */
153
- function getGlobalsForEcmaVersion(ecmaVersion) {
154
-
155
- switch (ecmaVersion) {
156
- case 3:
157
- return globals.es3;
158
-
159
- case 5:
160
- return globals.es5;
161
-
162
- default:
163
- if (ecmaVersion < 2015) {
164
- return globals[`es${ecmaVersion + 2009}`];
165
- }
166
-
167
- return globals[`es${ecmaVersion}`];
168
- }
169
- }
170
-
171
148
  /**
172
149
  * Ensures that variables representing built-in properties of the Global Object,
173
150
  * and any globals declared by special block comments, are present in the global
@@ -361,13 +338,13 @@ function extractDirectiveComment(value) {
361
338
  * Parses comments in file to extract file-specific config of rules, globals
362
339
  * and environments and merges them with global config; also code blocks
363
340
  * where reporting is disabled or enabled and merges them with reporting config.
364
- * @param {ASTNode} ast The top node of the AST.
341
+ * @param {SourceCode} sourceCode The SourceCode object to get comments from.
365
342
  * @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
366
343
  * @param {string|null} warnInlineConfig If a string then it should warn directive comments as disabled. The string value is the config name what the setting came from.
367
344
  * @returns {{configuredRules: Object, enabledGlobals: {value:string,comment:Token}[], exportedVariables: Object, problems: LintMessage[], disableDirectives: DisableDirective[]}}
368
345
  * A collection of the directive comments that were found, along with any problems that occurred when parsing
369
346
  */
370
- function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
347
+ function getDirectiveComments(sourceCode, ruleMapper, warnInlineConfig) {
371
348
  const configuredRules = {};
372
349
  const enabledGlobals = Object.create(null);
373
350
  const exportedVariables = {};
@@ -377,7 +354,7 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
377
354
  builtInRules: Rules
378
355
  });
379
356
 
380
- ast.comments.filter(token => token.type !== "Shebang").forEach(comment => {
357
+ sourceCode.getInlineConfigNodes().filter(token => token.type !== "Shebang").forEach(comment => {
381
358
  const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
382
359
 
383
360
  const match = directivesPattern.exec(directivePart);
@@ -511,6 +488,69 @@ function getDirectiveComments(ast, ruleMapper, warnInlineConfig) {
511
488
  };
512
489
  }
513
490
 
491
+ /**
492
+ * Parses comments in file to extract disable directives.
493
+ * @param {SourceCode} sourceCode The SourceCode object to get comments from.
494
+ * @param {function(string): {create: Function}} ruleMapper A map from rule IDs to defined rules
495
+ * @returns {{problems: LintMessage[], disableDirectives: DisableDirective[]}}
496
+ * A collection of the directive comments that were found, along with any problems that occurred when parsing
497
+ */
498
+ function getDirectiveCommentsForFlatConfig(sourceCode, ruleMapper) {
499
+ const problems = [];
500
+ const disableDirectives = [];
501
+
502
+ sourceCode.getInlineConfigNodes().filter(token => token.type !== "Shebang").forEach(comment => {
503
+ const { directivePart, justificationPart } = extractDirectiveComment(comment.value);
504
+
505
+ const match = directivesPattern.exec(directivePart);
506
+
507
+ if (!match) {
508
+ return;
509
+ }
510
+ const directiveText = match[1];
511
+ const lineCommentSupported = /^eslint-disable-(next-)?line$/u.test(directiveText);
512
+
513
+ if (comment.type === "Line" && !lineCommentSupported) {
514
+ return;
515
+ }
516
+
517
+ if (directiveText === "eslint-disable-line" && comment.loc.start.line !== comment.loc.end.line) {
518
+ const message = `${directiveText} comment should not span multiple lines.`;
519
+
520
+ problems.push(createLintingProblem({
521
+ ruleId: null,
522
+ message,
523
+ loc: comment.loc
524
+ }));
525
+ return;
526
+ }
527
+
528
+ const directiveValue = directivePart.slice(match.index + directiveText.length);
529
+
530
+ switch (directiveText) {
531
+ case "eslint-disable":
532
+ case "eslint-enable":
533
+ case "eslint-disable-next-line":
534
+ case "eslint-disable-line": {
535
+ const directiveType = directiveText.slice("eslint-".length);
536
+ const options = { commentToken: comment, type: directiveType, value: directiveValue, justification: justificationPart, ruleMapper };
537
+ const { directives, directiveProblems } = createDisableDirectives(options);
538
+
539
+ disableDirectives.push(...directives);
540
+ problems.push(...directiveProblems);
541
+ break;
542
+ }
543
+
544
+ // no default
545
+ }
546
+ });
547
+
548
+ return {
549
+ problems,
550
+ disableDirectives
551
+ };
552
+ }
553
+
514
554
  /**
515
555
  * Normalize ECMAScript version from the initial config
516
556
  * @param {Parser} parser The parser which uses this options.
@@ -1313,7 +1353,7 @@ class Linter {
1313
1353
 
1314
1354
  const sourceCode = slots.lastSourceCode;
1315
1355
  const commentDirectives = options.allowInlineConfig
1316
- ? getDirectiveComments(sourceCode.ast, ruleId => getRule(slots, ruleId), options.warnInlineConfig)
1356
+ ? getDirectiveComments(sourceCode, ruleId => getRule(slots, ruleId), options.warnInlineConfig)
1317
1357
  : { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
1318
1358
 
1319
1359
  // augment global scope with declared global variables
@@ -1324,7 +1364,6 @@ class Linter {
1324
1364
  );
1325
1365
 
1326
1366
  const configuredRules = Object.assign({}, config.rules, commentDirectives.configuredRules);
1327
-
1328
1367
  let lintingProblems;
1329
1368
 
1330
1369
  try {
@@ -1540,19 +1579,6 @@ class Linter {
1540
1579
  languageOptions.ecmaVersion
1541
1580
  );
1542
1581
 
1543
- /*
1544
- * add configured globals and language globals
1545
- *
1546
- * using Object.assign instead of object spread for performance reasons
1547
- * https://github.com/eslint/eslint/issues/16302
1548
- */
1549
- const configuredGlobals = Object.assign(
1550
- {},
1551
- getGlobalsForEcmaVersion(languageOptions.ecmaVersion),
1552
- languageOptions.sourceType === "commonjs" ? globals.commonjs : void 0,
1553
- languageOptions.globals
1554
- );
1555
-
1556
1582
  // double check that there is a parser to avoid mysterious error messages
1557
1583
  if (!languageOptions.parser) {
1558
1584
  throw new TypeError(`No parser specified for ${options.filename}`);
@@ -1608,25 +1634,113 @@ class Linter {
1608
1634
  }
1609
1635
 
1610
1636
  const sourceCode = slots.lastSourceCode;
1611
- const commentDirectives = options.allowInlineConfig
1612
- ? getDirectiveComments(
1613
- sourceCode.ast,
1614
- ruleId => getRuleFromConfig(ruleId, config),
1615
- options.warnInlineConfig
1616
- )
1617
- : { configuredRules: {}, enabledGlobals: {}, exportedVariables: {}, problems: [], disableDirectives: [] };
1618
1637
 
1619
- // augment global scope with declared global variables
1620
- addDeclaredGlobals(
1621
- sourceCode.scopeManager.scopes[0],
1622
- configuredGlobals,
1623
- { exportedVariables: commentDirectives.exportedVariables, enabledGlobals: commentDirectives.enabledGlobals }
1624
- );
1638
+ /*
1639
+ * Make adjustments based on the language options. For JavaScript,
1640
+ * this is primarily about adding variables into the global scope
1641
+ * to account for ecmaVersion and configured globals.
1642
+ */
1643
+ sourceCode.applyLanguageOptions(languageOptions);
1625
1644
 
1626
- const configuredRules = Object.assign({}, config.rules, commentDirectives.configuredRules);
1645
+ const mergedInlineConfig = {
1646
+ rules: {}
1647
+ };
1648
+ const inlineConfigProblems = [];
1649
+
1650
+ /*
1651
+ * Inline config can be either enabled or disabled. If disabled, it's possible
1652
+ * to detect the inline config and emit a warning (though this is not required).
1653
+ * So we first check to see if inline config is allowed at all, and if so, we
1654
+ * need to check if it's a warning or not.
1655
+ */
1656
+ if (options.allowInlineConfig) {
1657
+
1658
+ // if inline config should warn then add the warnings
1659
+ if (options.warnInlineConfig) {
1660
+ sourceCode.getInlineConfigNodes().forEach(node => {
1661
+ inlineConfigProblems.push(createLintingProblem({
1662
+ ruleId: null,
1663
+ message: `'${sourceCode.text.slice(node.range[0], node.range[1])}' has no effect because you have 'noInlineConfig' setting in ${options.warnInlineConfig}.`,
1664
+ loc: node.loc,
1665
+ severity: 1
1666
+ }));
1667
+
1668
+ });
1669
+ } else {
1670
+ const inlineConfigResult = sourceCode.applyInlineConfig();
1671
+
1672
+ inlineConfigProblems.push(
1673
+ ...inlineConfigResult.problems
1674
+ .map(createLintingProblem)
1675
+ .map(problem => {
1676
+ problem.fatal = true;
1677
+ return problem;
1678
+ })
1679
+ );
1680
+
1681
+ // next we need to verify information about the specified rules
1682
+ const ruleValidator = new RuleValidator();
1683
+
1684
+ for (const { config: inlineConfig, node } of inlineConfigResult.configs) {
1685
+
1686
+ Object.keys(inlineConfig.rules).forEach(ruleId => {
1687
+ const rule = getRuleFromConfig(ruleId, config);
1688
+ const ruleValue = inlineConfig.rules[ruleId];
1689
+
1690
+ if (!rule) {
1691
+ inlineConfigProblems.push(createLintingProblem({ ruleId, loc: node.loc }));
1692
+ return;
1693
+ }
1694
+
1695
+ try {
1696
+
1697
+ const ruleOptions = Array.isArray(ruleValue) ? ruleValue : [ruleValue];
1698
+
1699
+ assertIsRuleOptions(ruleId, ruleValue);
1700
+ assertIsRuleSeverity(ruleId, ruleOptions[0]);
1701
+
1702
+ ruleValidator.validate({
1703
+ plugins: config.plugins,
1704
+ rules: {
1705
+ [ruleId]: ruleOptions
1706
+ }
1707
+ });
1708
+ mergedInlineConfig.rules[ruleId] = ruleValue;
1709
+ } catch (err) {
1710
+
1711
+ let baseMessage = err.message.slice(
1712
+ err.message.startsWith("Key \"rules\":")
1713
+ ? err.message.indexOf(":", 12) + 1
1714
+ : err.message.indexOf(":") + 1
1715
+ ).trim();
1716
+
1717
+ if (err.messageTemplate) {
1718
+ baseMessage += ` You passed "${ruleValue}".`;
1719
+ }
1720
+
1721
+ inlineConfigProblems.push(createLintingProblem({
1722
+ ruleId,
1723
+ message: `Inline configuration for rule "${ruleId}" is invalid:\n\t${baseMessage}\n`,
1724
+ loc: node.loc
1725
+ }));
1726
+ }
1727
+ });
1728
+ }
1729
+ }
1730
+ }
1627
1731
 
1732
+ const commentDirectives = options.allowInlineConfig && !options.warnInlineConfig
1733
+ ? getDirectiveCommentsForFlatConfig(
1734
+ sourceCode,
1735
+ ruleId => getRuleFromConfig(ruleId, config)
1736
+ )
1737
+ : { problems: [], disableDirectives: [] };
1738
+
1739
+ const configuredRules = Object.assign({}, config.rules, mergedInlineConfig.rules);
1628
1740
  let lintingProblems;
1629
1741
 
1742
+ sourceCode.finalize();
1743
+
1630
1744
  try {
1631
1745
  lintingProblems = runRules(
1632
1746
  sourceCode,
@@ -1667,6 +1781,7 @@ class Linter {
1667
1781
  disableFixes: options.disableFixes,
1668
1782
  problems: lintingProblems
1669
1783
  .concat(commentDirectives.problems)
1784
+ .concat(inlineConfigProblems)
1670
1785
  .sort((problemA, problemB) => problemA.line - problemB.line || problemA.column - problemB.column),
1671
1786
  reportUnusedDisableDirectives: options.reportUnusedDisableDirectives
1672
1787
  });
package/lib/options.js CHANGED
@@ -55,6 +55,7 @@ const optionator = require("optionator");
55
55
  * @property {string} [stdinFilename] Specify filename to process STDIN as
56
56
  * @property {boolean} quiet Report errors only
57
57
  * @property {boolean} [version] Output the version number
58
+ * @property {boolean} warnIgnored Show warnings when the file list includes ignored files
58
59
  * @property {string[]} _ Positional filenames or patterns
59
60
  */
60
61
 
@@ -139,6 +140,17 @@ module.exports = function(usingFlatConfig) {
139
140
  };
140
141
  }
141
142
 
143
+ let warnIgnoredFlag;
144
+
145
+ if (usingFlatConfig) {
146
+ warnIgnoredFlag = {
147
+ option: "warn-ignored",
148
+ type: "Boolean",
149
+ default: "true",
150
+ description: "Suppress warnings when the file list includes ignored files"
151
+ };
152
+ }
153
+
142
154
  return optionator({
143
155
  prepend: "eslint [options] file.js [file.js] [dir]",
144
156
  defaults: {
@@ -349,6 +361,7 @@ module.exports = function(usingFlatConfig) {
349
361
  default: "false",
350
362
  description: "Exit with exit code 2 in case of fatal error"
351
363
  },
364
+ warnIgnoredFlag,
352
365
  {
353
366
  option: "debug",
354
367
  type: "Boolean",
@@ -133,6 +133,15 @@ const suggestionObjectParameters = new Set([
133
133
  ]);
134
134
  const friendlySuggestionObjectParameterList = `[${[...suggestionObjectParameters].map(key => `'${key}'`).join(", ")}]`;
135
135
 
136
+ const forbiddenMethods = [
137
+ "applyInlineConfig",
138
+ "applyLanguageOptions",
139
+ "finalize"
140
+ ];
141
+
142
+ /** @type {Map<string,WeakSet>} */
143
+ const forbiddenMethodCalls = new Map(forbiddenMethods.map(methodName => ([methodName, new WeakSet()])));
144
+
136
145
  const hasOwnProperty = Function.call.bind(Object.hasOwnProperty);
137
146
 
138
147
  /**
@@ -291,6 +300,34 @@ function emitCodePathCurrentSegmentsWarning(ruleName) {
291
300
  }
292
301
  }
293
302
 
303
+ /**
304
+ * Function to replace forbidden `SourceCode` methods. Allows just one call per method.
305
+ * @param {string} methodName The name of the method to forbid.
306
+ * @param {Function} prototype The prototype with the original method to call.
307
+ * @returns {Function} The function that throws the error.
308
+ */
309
+ function throwForbiddenMethodError(methodName, prototype) {
310
+
311
+ const original = prototype[methodName];
312
+
313
+ return function(...args) {
314
+
315
+ const called = forbiddenMethodCalls.get(methodName);
316
+
317
+ /* eslint-disable no-invalid-this -- needed to operate as a method. */
318
+ if (!called.has(this)) {
319
+ called.add(this);
320
+
321
+ return original.apply(this, args);
322
+ }
323
+ /* eslint-enable no-invalid-this -- not needed past this point */
324
+
325
+ throw new Error(
326
+ `\`SourceCode#${methodName}()\` cannot be called inside a rule.`
327
+ );
328
+ };
329
+ }
330
+
294
331
  //------------------------------------------------------------------------------
295
332
  // Public Interface
296
333
  //------------------------------------------------------------------------------
@@ -498,6 +535,7 @@ class FlatRuleTester {
498
535
  }
499
536
 
500
537
  const baseConfig = [
538
+ { files: ["**"] }, // Make sure the default config matches for all files
501
539
  {
502
540
  plugins: {
503
541
 
@@ -679,11 +717,6 @@ class FlatRuleTester {
679
717
  }
680
718
  }
681
719
 
682
- // Verify the code.
683
- const { getComments } = SourceCode.prototype;
684
- const originalCurrentSegments = Object.getOwnPropertyDescriptor(CodePath.prototype, "currentSegments");
685
- let messages;
686
-
687
720
  // check for validation errors
688
721
  try {
689
722
  configs.normalizeSync();
@@ -693,6 +726,11 @@ class FlatRuleTester {
693
726
  throw error;
694
727
  }
695
728
 
729
+ // Verify the code.
730
+ const { getComments, applyLanguageOptions, applyInlineConfig, finalize } = SourceCode.prototype;
731
+ const originalCurrentSegments = Object.getOwnPropertyDescriptor(CodePath.prototype, "currentSegments");
732
+ let messages;
733
+
696
734
  try {
697
735
  SourceCode.prototype.getComments = getCommentsDeprecation;
698
736
  Object.defineProperty(CodePath.prototype, "currentSegments", {
@@ -702,10 +740,17 @@ class FlatRuleTester {
702
740
  }
703
741
  });
704
742
 
743
+ forbiddenMethods.forEach(methodName => {
744
+ SourceCode.prototype[methodName] = throwForbiddenMethodError(methodName, SourceCode.prototype);
745
+ });
746
+
705
747
  messages = linter.verify(code, configs, filename);
706
748
  } finally {
707
749
  SourceCode.prototype.getComments = getComments;
708
750
  Object.defineProperty(CodePath.prototype, "currentSegments", originalCurrentSegments);
751
+ SourceCode.prototype.applyInlineConfig = applyInlineConfig;
752
+ SourceCode.prototype.applyLanguageOptions = applyLanguageOptions;
753
+ SourceCode.prototype.finalize = finalize;
709
754
  }
710
755
 
711
756
 
@@ -163,6 +163,12 @@ const suggestionObjectParameters = new Set([
163
163
  ]);
164
164
  const friendlySuggestionObjectParameterList = `[${[...suggestionObjectParameters].map(key => `'${key}'`).join(", ")}]`;
165
165
 
166
+ const forbiddenMethods = [
167
+ "applyInlineConfig",
168
+ "applyLanguageOptions",
169
+ "finalize"
170
+ ];
171
+
166
172
  const hasOwnProperty = Function.call.bind(Object.hasOwnProperty);
167
173
 
168
174
  const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
@@ -186,7 +192,12 @@ const DEPRECATED_SOURCECODE_PASSTHROUGHS = {
186
192
  getTokens: "getTokens",
187
193
  getTokensAfter: "getTokensAfter",
188
194
  getTokensBefore: "getTokensBefore",
189
- getTokensBetween: "getTokensBetween"
195
+ getTokensBetween: "getTokensBetween",
196
+
197
+ getScope: "getScope",
198
+ getAncestors: "getAncestors",
199
+ getDeclaredVariables: "getDeclaredVariables",
200
+ markVariableAsUsed: "markVariableAsUsed"
190
201
  };
191
202
 
192
203
  /**
@@ -330,6 +341,19 @@ function getCommentsDeprecation() {
330
341
  );
331
342
  }
332
343
 
344
+ /**
345
+ * Function to replace forbidden `SourceCode` methods.
346
+ * @param {string} methodName The name of the method to forbid.
347
+ * @returns {Function} The function that throws the error.
348
+ */
349
+ function throwForbiddenMethodError(methodName) {
350
+ return () => {
351
+ throw new Error(
352
+ `\`SourceCode#${methodName}()\` cannot be called inside a rule.`
353
+ );
354
+ };
355
+ }
356
+
333
357
  /**
334
358
  * Emit a deprecation warning if function-style format is being used.
335
359
  * @param {string} ruleName Name of the rule.
@@ -391,6 +415,22 @@ function emitCodePathCurrentSegmentsWarning(ruleName) {
391
415
  }
392
416
  }
393
417
 
418
+ /**
419
+ * Emit a deprecation warning if `context.parserServices` is used.
420
+ * @param {string} ruleName Name of the rule.
421
+ * @returns {void}
422
+ */
423
+ function emitParserServicesWarning(ruleName) {
424
+ if (!emitParserServicesWarning[`warned-${ruleName}`]) {
425
+ emitParserServicesWarning[`warned-${ruleName}`] = true;
426
+ process.emitWarning(
427
+ `"${ruleName}" rule is using \`context.parserServices\`, which is deprecated and will be removed in ESLint v9. Please use \`sourceCode.parserServices\` instead.`,
428
+ "DeprecationWarning"
429
+ );
430
+ }
431
+ }
432
+
433
+
394
434
  //------------------------------------------------------------------------------
395
435
  // Public Interface
396
436
  //------------------------------------------------------------------------------
@@ -622,26 +662,37 @@ class RuleTester {
622
662
  freezeDeeply(context.settings);
623
663
  freezeDeeply(context.parserOptions);
624
664
 
625
- const newContext = Object.freeze(
626
- Object.create(
627
- context,
628
- Object.fromEntries(Object.keys(DEPRECATED_SOURCECODE_PASSTHROUGHS).map(methodName => [
629
- methodName,
630
- {
631
- value(...args) {
632
-
633
- // emit deprecation warning
634
- emitDeprecatedContextMethodWarning(ruleName, methodName);
635
-
636
- // call the original method
637
- return context[methodName].call(this, ...args);
638
- },
639
- enumerable: true
640
- }
641
- ]))
642
- )
665
+ // wrap all deprecated methods
666
+ const newContext = Object.create(
667
+ context,
668
+ Object.fromEntries(Object.keys(DEPRECATED_SOURCECODE_PASSTHROUGHS).map(methodName => [
669
+ methodName,
670
+ {
671
+ value(...args) {
672
+
673
+ // emit deprecation warning
674
+ emitDeprecatedContextMethodWarning(ruleName, methodName);
675
+
676
+ // call the original method
677
+ return context[methodName].call(this, ...args);
678
+ },
679
+ enumerable: true
680
+ }
681
+ ]))
643
682
  );
644
683
 
684
+ // emit warning about context.parserServices
685
+ const parserServices = context.parserServices;
686
+
687
+ Object.defineProperty(newContext, "parserServices", {
688
+ get() {
689
+ emitParserServicesWarning(ruleName);
690
+ return parserServices;
691
+ }
692
+ });
693
+
694
+ Object.freeze(newContext);
695
+
645
696
  return (typeof rule === "function" ? rule : rule.create)(newContext);
646
697
  }
647
698
  }));
@@ -761,7 +812,7 @@ class RuleTester {
761
812
  validate(config, "rule-tester", id => (id === ruleName ? rule : null));
762
813
 
763
814
  // Verify the code.
764
- const { getComments } = SourceCode.prototype;
815
+ const { getComments, applyLanguageOptions, applyInlineConfig, finalize } = SourceCode.prototype;
765
816
  const originalCurrentSegments = Object.getOwnPropertyDescriptor(CodePath.prototype, "currentSegments");
766
817
  let messages;
767
818
 
@@ -774,10 +825,17 @@ class RuleTester {
774
825
  }
775
826
  });
776
827
 
828
+ forbiddenMethods.forEach(methodName => {
829
+ SourceCode.prototype[methodName] = throwForbiddenMethodError(methodName);
830
+ });
831
+
777
832
  messages = linter.verify(code, config, filename);
778
833
  } finally {
779
834
  SourceCode.prototype.getComments = getComments;
780
835
  Object.defineProperty(CodePath.prototype, "currentSegments", originalCurrentSegments);
836
+ SourceCode.prototype.applyInlineConfig = applyInlineConfig;
837
+ SourceCode.prototype.applyLanguageOptions = applyLanguageOptions;
838
+ SourceCode.prototype.finalize = finalize;
781
839
  }
782
840
 
783
841
  const fatalErrorMessage = messages.find(m => m.fatal);