eslint 9.4.0 → 9.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/README.md +2 -2
  2. package/lib/api.js +1 -1
  3. package/lib/config/default-config.js +5 -0
  4. package/lib/config/flat-config-array.js +71 -8
  5. package/lib/config/flat-config-schema.js +46 -62
  6. package/lib/eslint/eslint-helpers.js +27 -17
  7. package/lib/eslint/eslint.js +14 -10
  8. package/lib/languages/js/index.js +247 -0
  9. package/lib/{source-code → languages/js/source-code}/source-code.js +38 -18
  10. package/lib/languages/js/validate-language-options.js +181 -0
  11. package/lib/linter/apply-disable-directives.js +8 -3
  12. package/lib/linter/linter.js +122 -121
  13. package/lib/linter/report-translator.js +14 -7
  14. package/lib/linter/vfile.js +104 -0
  15. package/lib/rule-tester/rule-tester.js +5 -2
  16. package/lib/rules/no-sparse-arrays.js +26 -3
  17. package/messages/all-matched-files-ignored.js +21 -0
  18. package/package.json +11 -11
  19. /package/lib/{source-code → languages/js/source-code}/index.js +0 -0
  20. /package/lib/{source-code → languages/js/source-code}/token-store/backward-token-comment-cursor.js +0 -0
  21. /package/lib/{source-code → languages/js/source-code}/token-store/backward-token-cursor.js +0 -0
  22. /package/lib/{source-code → languages/js/source-code}/token-store/cursor.js +0 -0
  23. /package/lib/{source-code → languages/js/source-code}/token-store/cursors.js +0 -0
  24. /package/lib/{source-code → languages/js/source-code}/token-store/decorative-cursor.js +0 -0
  25. /package/lib/{source-code → languages/js/source-code}/token-store/filter-cursor.js +0 -0
  26. /package/lib/{source-code → languages/js/source-code}/token-store/forward-token-comment-cursor.js +0 -0
  27. /package/lib/{source-code → languages/js/source-code}/token-store/forward-token-cursor.js +0 -0
  28. /package/lib/{source-code → languages/js/source-code}/token-store/index.js +0 -0
  29. /package/lib/{source-code → languages/js/source-code}/token-store/limit-cursor.js +0 -0
  30. /package/lib/{source-code → languages/js/source-code}/token-store/padded-token-cursor.js +0 -0
  31. /package/lib/{source-code → languages/js/source-code}/token-store/skip-cursor.js +0 -0
  32. /package/lib/{source-code → languages/js/source-code}/token-store/utils.js +0 -0
@@ -0,0 +1,247 @@
1
+ /**
2
+ * @fileoverview JavaScript Language Object
3
+ * @author Nicholas C. Zakas
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //-----------------------------------------------------------------------------
9
+ // Requirements
10
+ //-----------------------------------------------------------------------------
11
+
12
+ const { SourceCode } = require("./source-code");
13
+ const createDebug = require("debug");
14
+ const astUtils = require("../../shared/ast-utils");
15
+ const eslintScope = require("eslint-scope");
16
+ const evk = require("eslint-visitor-keys");
17
+ const { validateLanguageOptions } = require("./validate-language-options");
18
+
19
+ //-----------------------------------------------------------------------------
20
+ // Type Definitions
21
+ //-----------------------------------------------------------------------------
22
+
23
+ /** @typedef {import("../../linter/vfile").VFile} VFile */
24
+
25
+ //-----------------------------------------------------------------------------
26
+ // Helpers
27
+ //-----------------------------------------------------------------------------
28
+
29
+ const debug = createDebug("eslint:languages:js");
30
+ const DEFAULT_ECMA_VERSION = 5;
31
+
32
+ /**
33
+ * Analyze scope of the given AST.
34
+ * @param {ASTNode} ast The `Program` node to analyze.
35
+ * @param {LanguageOptions} languageOptions The parser options.
36
+ * @param {Record<string, string[]>} visitorKeys The visitor keys.
37
+ * @returns {ScopeManager} The analysis result.
38
+ */
39
+ function analyzeScope(ast, languageOptions, visitorKeys) {
40
+ const parserOptions = languageOptions.parserOptions;
41
+ const ecmaFeatures = parserOptions.ecmaFeatures || {};
42
+ const ecmaVersion = languageOptions.ecmaVersion || DEFAULT_ECMA_VERSION;
43
+
44
+ return eslintScope.analyze(ast, {
45
+ ignoreEval: true,
46
+ nodejsScope: ecmaFeatures.globalReturn,
47
+ impliedStrict: ecmaFeatures.impliedStrict,
48
+ ecmaVersion: typeof ecmaVersion === "number" ? ecmaVersion : 6,
49
+ sourceType: languageOptions.sourceType || "script",
50
+ childVisitorKeys: visitorKeys || evk.KEYS,
51
+ fallback: evk.getKeys
52
+ });
53
+ }
54
+
55
+ //-----------------------------------------------------------------------------
56
+ // Exports
57
+ //-----------------------------------------------------------------------------
58
+
59
+ module.exports = {
60
+
61
+ fileType: "text",
62
+ lineStart: 1,
63
+ columnStart: 0,
64
+ nodeTypeKey: "type",
65
+ visitorKeys: evk.KEYS,
66
+
67
+ validateLanguageOptions,
68
+
69
+ /**
70
+ * Determines if a given node matches a given selector class.
71
+ * @param {string} className The class name to check.
72
+ * @param {ASTNode} node The node to check.
73
+ * @param {Array<ASTNode>} ancestry The ancestry of the node.
74
+ * @returns {boolean} True if there's a match, false if not.
75
+ * @throws {Error} When an unknown class name is passed.
76
+ */
77
+ matchesSelectorClass(className, node, ancestry) {
78
+
79
+ /*
80
+ * Copyright (c) 2013, Joel Feenstra
81
+ * All rights reserved.
82
+ *
83
+ * Redistribution and use in source and binary forms, with or without
84
+ * modification, are permitted provided that the following conditions are met:
85
+ * * Redistributions of source code must retain the above copyright
86
+ * notice, this list of conditions and the following disclaimer.
87
+ * * Redistributions in binary form must reproduce the above copyright
88
+ * notice, this list of conditions and the following disclaimer in the
89
+ * documentation and/or other materials provided with the distribution.
90
+ * * Neither the name of the ESQuery nor the names of its contributors may
91
+ * be used to endorse or promote products derived from this software without
92
+ * specific prior written permission.
93
+ *
94
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
95
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
96
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
97
+ * DISCLAIMED. IN NO EVENT SHALL JOEL FEENSTRA BE LIABLE FOR ANY
98
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
99
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
100
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
101
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
102
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
103
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
104
+ */
105
+
106
+ switch (className.toLowerCase()) {
107
+
108
+ case "statement":
109
+ if (node.type.slice(-9) === "Statement") {
110
+ return true;
111
+ }
112
+
113
+ // fallthrough: interface Declaration <: Statement { }
114
+
115
+ case "declaration":
116
+ return node.type.slice(-11) === "Declaration";
117
+
118
+ case "pattern":
119
+ if (node.type.slice(-7) === "Pattern") {
120
+ return true;
121
+ }
122
+
123
+ // fallthrough: interface Expression <: Node, Pattern { }
124
+
125
+ case "expression":
126
+ return node.type.slice(-10) === "Expression" ||
127
+ node.type.slice(-7) === "Literal" ||
128
+ (
129
+ node.type === "Identifier" &&
130
+ (ancestry.length === 0 || ancestry[0].type !== "MetaProperty")
131
+ ) ||
132
+ node.type === "MetaProperty";
133
+
134
+ case "function":
135
+ return node.type === "FunctionDeclaration" ||
136
+ node.type === "FunctionExpression" ||
137
+ node.type === "ArrowFunctionExpression";
138
+
139
+ default:
140
+ throw new Error(`Unknown class name: ${className}`);
141
+ }
142
+ },
143
+
144
+ /**
145
+ * Parses the given file into an AST.
146
+ * @param {VFile} file The virtual file to parse.
147
+ * @param {Object} options Additional options passed from ESLint.
148
+ * @param {LanguageOptions} options.languageOptions The language options.
149
+ * @returns {Object} The result of parsing.
150
+ */
151
+ parse(file, { languageOptions }) {
152
+
153
+ // Note: BOM already removed
154
+ const { body: text, path: filePath } = file;
155
+ const textToParse = text.replace(astUtils.shebangPattern, (match, captured) => `//${captured}`);
156
+ const { ecmaVersion, sourceType, parser } = languageOptions;
157
+ const parserOptions = Object.assign(
158
+ { ecmaVersion, sourceType },
159
+ languageOptions.parserOptions,
160
+ {
161
+ loc: true,
162
+ range: true,
163
+ raw: true,
164
+ tokens: true,
165
+ comment: true,
166
+ eslintVisitorKeys: true,
167
+ eslintScopeManager: true,
168
+ filePath
169
+ }
170
+ );
171
+
172
+ /*
173
+ * Check for parsing errors first. If there's a parsing error, nothing
174
+ * else can happen. However, a parsing error does not throw an error
175
+ * from this method - it's just considered a fatal error message, a
176
+ * problem that ESLint identified just like any other.
177
+ */
178
+ try {
179
+ debug("Parsing:", filePath);
180
+ const parseResult = (typeof parser.parseForESLint === "function")
181
+ ? parser.parseForESLint(textToParse, parserOptions)
182
+ : { ast: parser.parse(textToParse, parserOptions) };
183
+
184
+ debug("Parsing successful:", filePath);
185
+
186
+ const {
187
+ ast,
188
+ services: parserServices = {},
189
+ visitorKeys = evk.KEYS,
190
+ scopeManager
191
+ } = parseResult;
192
+
193
+ return {
194
+ ok: true,
195
+ ast,
196
+ parserServices,
197
+ visitorKeys,
198
+ scopeManager
199
+ };
200
+ } catch (ex) {
201
+
202
+ // If the message includes a leading line number, strip it:
203
+ const message = `Parsing error: ${ex.message.replace(/^line \d+:/iu, "").trim()}`;
204
+
205
+ debug("%s\n%s", message, ex.stack);
206
+
207
+ return {
208
+ ok: false,
209
+ errors: [{
210
+ message,
211
+ line: ex.lineNumber,
212
+ column: ex.column
213
+ }]
214
+ };
215
+ }
216
+
217
+ },
218
+
219
+ /**
220
+ * Creates a new `SourceCode` object from the given information.
221
+ * @param {VFile} file The virtual file to create a `SourceCode` object from.
222
+ * @param {Object} parseResult The result returned from `parse()`.
223
+ * @param {Object} options Additional options passed from ESLint.
224
+ * @param {LanguageOptions} options.languageOptions The language options.
225
+ * @returns {SourceCode} The new `SourceCode` object.
226
+ */
227
+ createSourceCode(file, parseResult, { languageOptions }) {
228
+
229
+ const { body: text, path: filePath, bom: hasBOM } = file;
230
+ const { ast, parserServices, visitorKeys } = parseResult;
231
+
232
+ debug("Scope analysis:", filePath);
233
+ const scopeManager = parseResult.scopeManager || analyzeScope(ast, languageOptions, visitorKeys);
234
+
235
+ debug("Scope analysis successful:", filePath);
236
+
237
+ return new SourceCode({
238
+ text,
239
+ ast,
240
+ hasBOM,
241
+ parserServices,
242
+ scopeManager,
243
+ visitorKeys
244
+ });
245
+ }
246
+
247
+ };
@@ -11,18 +11,16 @@
11
11
  const
12
12
  { isCommentToken } = require("@eslint-community/eslint-utils"),
13
13
  TokenStore = require("./token-store"),
14
- astUtils = require("../shared/ast-utils"),
15
- Traverser = require("../shared/traverser"),
16
- globals = require("../../conf/globals"),
14
+ astUtils = require("../../../shared/ast-utils"),
15
+ Traverser = require("../../../shared/traverser"),
16
+ globals = require("../../../../conf/globals"),
17
17
  {
18
18
  directivesPattern
19
- } = require("../shared/directives"),
19
+ } = require("../../../shared/directives"),
20
20
 
21
- /* eslint-disable n/no-restricted-require -- Should eventually be moved into SourceCode. */
22
- CodePathAnalyzer = require("../linter/code-path-analysis/code-path-analyzer"),
23
- createEmitter = require("../linter/safe-emitter"),
24
- ConfigCommentParser = require("../linter/config-comment-parser"),
25
- /* eslint-enable n/no-restricted-require -- Should eventually be moved into SourceCode. */
21
+ CodePathAnalyzer = require("../../../linter/code-path-analysis/code-path-analyzer"),
22
+ createEmitter = require("../../../linter/safe-emitter"),
23
+ ConfigCommentParser = require("../../../linter/config-comment-parser"),
26
24
 
27
25
  eslintScope = require("eslint-scope");
28
26
 
@@ -441,24 +439,28 @@ class SourceCode extends TokenStore {
441
439
  #steps;
442
440
 
443
441
  /**
442
+ * Creates a new instance.
444
443
  * @param {string|Object} textOrConfig The source code text or config object.
445
444
  * @param {string} textOrConfig.text The source code text.
446
445
  * @param {ASTNode} textOrConfig.ast The Program node of the AST representing the code. This AST should be created from the text that BOM was stripped.
446
+ * @param {boolean} textOrConfig.hasBOM Indicates if the text has a Unicode BOM.
447
447
  * @param {Object|null} textOrConfig.parserServices The parser services.
448
448
  * @param {ScopeManager|null} textOrConfig.scopeManager The scope of this source code.
449
449
  * @param {Object|null} textOrConfig.visitorKeys The visitor keys to traverse AST.
450
450
  * @param {ASTNode} [astIfNoConfig] The Program node of the AST representing the code. This AST should be created from the text that BOM was stripped.
451
451
  */
452
452
  constructor(textOrConfig, astIfNoConfig) {
453
- let text, ast, parserServices, scopeManager, visitorKeys;
453
+ let text, hasBOM, ast, parserServices, scopeManager, visitorKeys;
454
454
 
455
- // Process overloading.
455
+ // Process overloading of arguments
456
456
  if (typeof textOrConfig === "string") {
457
457
  text = textOrConfig;
458
458
  ast = astIfNoConfig;
459
+ hasBOM = false;
459
460
  } else if (typeof textOrConfig === "object" && textOrConfig !== null) {
460
461
  text = textOrConfig.text;
461
462
  ast = textOrConfig.ast;
463
+ hasBOM = textOrConfig.hasBOM;
462
464
  parserServices = textOrConfig.parserServices;
463
465
  scopeManager = textOrConfig.scopeManager;
464
466
  visitorKeys = textOrConfig.visitorKeys;
@@ -476,18 +478,39 @@ class SourceCode extends TokenStore {
476
478
  ["configNodes", void 0]
477
479
  ]);
478
480
 
481
+ /**
482
+ * Indicates if the AST is ESTree compatible.
483
+ * @type {boolean}
484
+ */
485
+ this.isESTree = ast.type === "Program";
486
+
487
+ /*
488
+ * Backwards compatibility for BOM handling.
489
+ *
490
+ * The `hasBOM` property has been available on the `SourceCode` object
491
+ * for a long time and is used to indicate if the source contains a BOM.
492
+ * The linter strips the BOM and just passes the `hasBOM` property to the
493
+ * `SourceCode` constructor to make it easier for languages to not deal with
494
+ * the BOM.
495
+ *
496
+ * However, the text passed in to the `SourceCode` constructor might still
497
+ * have a BOM if the constructor is called outside of the linter, so we still
498
+ * need to check for the BOM in the text.
499
+ */
500
+ const textHasBOM = text.charCodeAt(0) === 0xFEFF;
501
+
479
502
  /**
480
503
  * The flag to indicate that the source code has Unicode BOM.
481
504
  * @type {boolean}
482
505
  */
483
- this.hasBOM = (text.charCodeAt(0) === 0xFEFF);
506
+ this.hasBOM = textHasBOM || !!hasBOM;
484
507
 
485
508
  /**
486
509
  * The original text source code.
487
510
  * BOM was stripped from this text.
488
511
  * @type {string}
489
512
  */
490
- this.text = (this.hasBOM ? text.slice(1) : text);
513
+ this.text = (textHasBOM ? text.slice(1) : text);
491
514
 
492
515
  /**
493
516
  * The parsed AST for the source code.
@@ -1164,12 +1187,11 @@ class SourceCode extends TokenStore {
1164
1187
  */
1165
1188
  finalize() {
1166
1189
 
1167
- // Step 1: ensure that all of the necessary variables are up to date
1168
1190
  const varsCache = this[caches].get("vars");
1169
- const globalScope = this.scopeManager.scopes[0];
1170
1191
  const configGlobals = varsCache.get("configGlobals");
1171
1192
  const inlineGlobals = varsCache.get("inlineGlobals");
1172
1193
  const exportedVariables = varsCache.get("exportedVariables");
1194
+ const globalScope = this.scopeManager.scopes[0];
1173
1195
 
1174
1196
  addDeclaredGlobals(globalScope, configGlobals, inlineGlobals);
1175
1197
 
@@ -1227,9 +1249,7 @@ class SourceCode extends TokenStore {
1227
1249
  * Program node at the top level. This is not a perfect heuristic, but it
1228
1250
  * is good enough for now.
1229
1251
  */
1230
- const isESTree = this.ast.type === "Program";
1231
-
1232
- if (isESTree) {
1252
+ if (this.isESTree) {
1233
1253
  analyzer = new CodePathAnalyzer(analyzer);
1234
1254
 
1235
1255
  CODE_PATH_EVENTS.forEach(eventName => {
@@ -0,0 +1,181 @@
1
+ /**
2
+ * @fileoverview The schema to validate language options
3
+ * @author Nicholas C. Zakas
4
+ */
5
+
6
+ "use strict";
7
+
8
+ //-----------------------------------------------------------------------------
9
+ // Data
10
+ //-----------------------------------------------------------------------------
11
+
12
+ const globalVariablesValues = new Set([
13
+ true, "true", "writable", "writeable",
14
+ false, "false", "readonly", "readable", null,
15
+ "off"
16
+ ]);
17
+
18
+ //------------------------------------------------------------------------------
19
+ // Helpers
20
+ //------------------------------------------------------------------------------
21
+
22
+ /**
23
+ * Check if a value is a non-null object.
24
+ * @param {any} value The value to check.
25
+ * @returns {boolean} `true` if the value is a non-null object.
26
+ */
27
+ function isNonNullObject(value) {
28
+ return typeof value === "object" && value !== null;
29
+ }
30
+
31
+ /**
32
+ * Check if a value is a non-null non-array object.
33
+ * @param {any} value The value to check.
34
+ * @returns {boolean} `true` if the value is a non-null non-array object.
35
+ */
36
+ function isNonArrayObject(value) {
37
+ return isNonNullObject(value) && !Array.isArray(value);
38
+ }
39
+
40
+ /**
41
+ * Check if a value is undefined.
42
+ * @param {any} value The value to check.
43
+ * @returns {boolean} `true` if the value is undefined.
44
+ */
45
+ function isUndefined(value) {
46
+ return typeof value === "undefined";
47
+ }
48
+
49
+ //-----------------------------------------------------------------------------
50
+ // Schemas
51
+ //-----------------------------------------------------------------------------
52
+
53
+ /**
54
+ * Validates the ecmaVersion property.
55
+ * @param {string|number} ecmaVersion The value to check.
56
+ * @returns {void}
57
+ * @throws {TypeError} If the value is invalid.
58
+ */
59
+ function validateEcmaVersion(ecmaVersion) {
60
+
61
+ if (isUndefined(ecmaVersion)) {
62
+ throw new TypeError("Key \"ecmaVersion\": Expected an \"ecmaVersion\" property.");
63
+ }
64
+
65
+ if (typeof ecmaVersion !== "number" && ecmaVersion !== "latest") {
66
+ throw new TypeError("Key \"ecmaVersion\": Expected a number or \"latest\".");
67
+ }
68
+
69
+ }
70
+
71
+ /**
72
+ * Validates the sourceType property.
73
+ * @param {string} sourceType The value to check.
74
+ * @returns {void}
75
+ * @throws {TypeError} If the value is invalid.
76
+ */
77
+ function validateSourceType(sourceType) {
78
+
79
+ if (typeof sourceType !== "string" || !/^(?:script|module|commonjs)$/u.test(sourceType)) {
80
+ throw new TypeError("Key \"sourceType\": Expected \"script\", \"module\", or \"commonjs\".");
81
+ }
82
+
83
+ }
84
+
85
+ /**
86
+ * Validates the globals property.
87
+ * @param {Object} globals The value to check.
88
+ * @returns {void}
89
+ * @throws {TypeError} If the value is invalid.
90
+ */
91
+ function validateGlobals(globals) {
92
+
93
+ if (!isNonArrayObject(globals)) {
94
+ throw new TypeError("Key \"globals\": Expected an object.");
95
+ }
96
+
97
+ for (const key of Object.keys(globals)) {
98
+
99
+ // avoid hairy edge case
100
+ if (key === "__proto__") {
101
+ continue;
102
+ }
103
+
104
+ if (key !== key.trim()) {
105
+ throw new TypeError(`Key "globals": Global "${key}" has leading or trailing whitespace.`);
106
+ }
107
+
108
+ if (!globalVariablesValues.has(globals[key])) {
109
+ throw new TypeError(`Key "globals": Key "${key}": Expected "readonly", "writable", or "off".`);
110
+ }
111
+ }
112
+ }
113
+
114
+ /**
115
+ * Validates the parser property.
116
+ * @param {Object} parser The value to check.
117
+ * @returns {void}
118
+ * @throws {TypeError} If the value is invalid.
119
+ */
120
+ function validateParser(parser) {
121
+
122
+ if (!parser || typeof parser !== "object" ||
123
+ (typeof parser.parse !== "function" && typeof parser.parseForESLint !== "function")
124
+ ) {
125
+ throw new TypeError("Key \"parser\": Expected object with parse() or parseForESLint() method.");
126
+ }
127
+
128
+ }
129
+
130
+ /**
131
+ * Validates the language options.
132
+ * @param {Object} languageOptions The language options to validate.
133
+ * @returns {void}
134
+ * @throws {TypeError} If the language options are invalid.
135
+ */
136
+ function validateLanguageOptions(languageOptions) {
137
+
138
+ if (!isNonArrayObject(languageOptions)) {
139
+ throw new TypeError("Expected an object.");
140
+ }
141
+
142
+ const {
143
+ ecmaVersion,
144
+ sourceType,
145
+ globals,
146
+ parser,
147
+ parserOptions,
148
+ ...otherOptions
149
+ } = languageOptions;
150
+
151
+ if ("ecmaVersion" in languageOptions) {
152
+ validateEcmaVersion(ecmaVersion);
153
+ }
154
+
155
+ if ("sourceType" in languageOptions) {
156
+ validateSourceType(sourceType);
157
+ }
158
+
159
+ if ("globals" in languageOptions) {
160
+ validateGlobals(globals);
161
+ }
162
+
163
+ if ("parser" in languageOptions) {
164
+ validateParser(parser);
165
+ }
166
+
167
+ if ("parserOptions" in languageOptions) {
168
+ if (!isNonArrayObject(parserOptions)) {
169
+ throw new TypeError("Key \"parserOptions\": Expected an object.");
170
+ }
171
+ }
172
+
173
+ const otherOptionKeys = Object.keys(otherOptions);
174
+
175
+ if (otherOptionKeys.length > 0) {
176
+ throw new TypeError(`Unexpected key "${otherOptionKeys[0]}" found.`);
177
+ }
178
+
179
+ }
180
+
181
+ module.exports = { validateLanguageOptions };
@@ -369,6 +369,8 @@ function applyDirectives(options) {
369
369
 
370
370
  const processed = processUnusedDirectives(unusedDisableDirectivesToReport)
371
371
  .concat(processUnusedDirectives(unusedEnableDirectivesToReport));
372
+ const columnOffset = options.language.columnStart === 1 ? 0 : 1;
373
+ const lineOffset = options.language.lineStart === 1 ? 0 : 1;
372
374
 
373
375
  const unusedDirectives = processed
374
376
  .map(({ description, fix, unprocessedDirective }) => {
@@ -388,8 +390,8 @@ function applyDirectives(options) {
388
390
  return {
389
391
  ruleId: null,
390
392
  message,
391
- line: type === "disable-next-line" ? parentDirective.node.loc.start.line : line,
392
- column: type === "disable-next-line" ? parentDirective.node.loc.start.column + 1 : column,
393
+ line: type === "disable-next-line" ? parentDirective.node.loc.start.line + lineOffset : line,
394
+ column: type === "disable-next-line" ? parentDirective.node.loc.start.column + columnOffset : column,
393
395
  severity: options.reportUnusedDisableDirectives === "warn" ? 1 : 2,
394
396
  nodeType: null,
395
397
  ...options.disableFixes ? {} : { fix }
@@ -403,6 +405,7 @@ function applyDirectives(options) {
403
405
  * Given a list of directive comments (i.e. metadata about eslint-disable and eslint-enable comments) and a list
404
406
  * of reported problems, adds the suppression information to the problems.
405
407
  * @param {Object} options Information about directives and problems
408
+ * @param {Language} options.language The language being linted.
406
409
  * @param {{
407
410
  * type: ("disable"|"enable"|"disable-line"|"disable-next-line"),
408
411
  * ruleId: (string|null),
@@ -421,7 +424,7 @@ function applyDirectives(options) {
421
424
  * @returns {{ruleId: (string|null), line: number, column: number, suppressions?: {kind: string, justification: string}}[]}
422
425
  * An object with a list of reported problems, the suppressed of which contain the suppression information.
423
426
  */
424
- module.exports = ({ directives, disableFixes, problems, configuredRules, ruleFilter, reportUnusedDisableDirectives = "off" }) => {
427
+ module.exports = ({ language, directives, disableFixes, problems, configuredRules, ruleFilter, reportUnusedDisableDirectives = "off" }) => {
425
428
  const blockDirectives = directives
426
429
  .filter(directive => directive.type === "disable" || directive.type === "enable")
427
430
  .map(directive => Object.assign({}, directive, { unprocessedDirective: directive }))
@@ -470,6 +473,7 @@ module.exports = ({ directives, disableFixes, problems, configuredRules, ruleFil
470
473
  }
471
474
 
472
475
  const blockDirectivesResult = applyDirectives({
476
+ language,
473
477
  problems,
474
478
  directives: blockDirectives,
475
479
  disableFixes,
@@ -477,6 +481,7 @@ module.exports = ({ directives, disableFixes, problems, configuredRules, ruleFil
477
481
  rulesToIgnore
478
482
  });
479
483
  const lineDirectivesResult = applyDirectives({
484
+ language,
480
485
  problems: blockDirectivesResult.problems,
481
486
  directives: lineDirectives,
482
487
  disableFixes,