-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Chore: Extract config comment parsing (#11091)
* Chore: Extract config comment parsing * Add more debug messages * Fix linting errors * Remove unused tests and constructor * Add comment to updated test * Fix lint issue
- Loading branch information
Showing
4 changed files
with
388 additions
and
112 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/** | ||
* @fileoverview Config Comment Parser | ||
* @author Nicholas C. Zakas | ||
*/ | ||
|
||
/* eslint-disable class-methods-use-this*/ | ||
"use strict"; | ||
|
||
//------------------------------------------------------------------------------ | ||
// Requirements | ||
//------------------------------------------------------------------------------ | ||
|
||
const levn = require("levn"), | ||
ConfigOps = require("../config/config-ops"); | ||
|
||
const debug = require("debug")("eslint:config-comment-parser"); | ||
|
||
//------------------------------------------------------------------------------ | ||
// Public Interface | ||
//------------------------------------------------------------------------------ | ||
|
||
/** | ||
* Object to parse ESLint configuration comments inside JavaScript files. | ||
* @name ConfigCommentParser | ||
*/ | ||
module.exports = class ConfigCommentParser { | ||
|
||
/** | ||
* Parses a list of "name:boolean_value" or/and "name" options divided by comma or | ||
* whitespace. Used for "global" and "exported" comments. | ||
* @param {string} string The string to parse. | ||
* @param {Comment} comment The comment node which has the string. | ||
* @returns {Object} Result map object of names and boolean values | ||
*/ | ||
parseBooleanConfig(string, comment) { | ||
debug("Parsing Boolean config"); | ||
|
||
const items = {}; | ||
|
||
// Collapse whitespace around `:` and `,` to make parsing easier | ||
const trimmedString = string.replace(/\s*([:,])\s*/g, "$1"); | ||
|
||
trimmedString.split(/\s|,+/).forEach(name => { | ||
if (!name) { | ||
return; | ||
} | ||
|
||
// value defaults to "false" (if not provided), e.g: "foo" => ["foo", "false"] | ||
const [key, value = "false"] = name.split(":"); | ||
|
||
items[key] = { | ||
value: value === "true", | ||
comment | ||
}; | ||
}); | ||
return items; | ||
} | ||
|
||
/** | ||
* Parses a JSON-like config. | ||
* @param {string} string The string to parse. | ||
* @param {Object} location Start line and column of comments for potential error message. | ||
* @returns {({success: true, config: Object}|{success: false, error: Problem})} Result map object | ||
*/ | ||
parseJsonConfig(string, location) { | ||
debug("Parsing JSON config"); | ||
|
||
let items = {}; | ||
|
||
// Parses a JSON-like comment by the same way as parsing CLI option. | ||
try { | ||
items = levn.parse("Object", string) || {}; | ||
|
||
// Some tests say that it should ignore invalid comments such as `/*eslint no-alert:abc*/`. | ||
// Also, commaless notations have invalid severity: | ||
// "no-alert: 2 no-console: 2" --> {"no-alert": "2 no-console: 2"} | ||
// Should ignore that case as well. | ||
if (ConfigOps.isEverySeverityValid(items)) { | ||
return { | ||
success: true, | ||
config: items | ||
}; | ||
} | ||
} catch (ex) { | ||
|
||
debug("Levn parsing failed; falling back to manual parsing."); | ||
|
||
// ignore to parse the string by a fallback. | ||
} | ||
|
||
/* | ||
* Optionator cannot parse commaless notations. | ||
* But we are supporting that. So this is a fallback for that. | ||
*/ | ||
items = {}; | ||
const normalizedString = string.replace(/([a-zA-Z0-9\-/]+):/g, "\"$1\":").replace(/(]|[0-9])\s+(?=")/, "$1,"); | ||
|
||
try { | ||
items = JSON.parse(`{${normalizedString}}`); | ||
} catch (ex) { | ||
debug("Manual parsing failed."); | ||
|
||
return { | ||
success: false, | ||
error: { | ||
ruleId: null, | ||
fatal: true, | ||
severity: 2, | ||
message: `Failed to parse JSON from '${normalizedString}': ${ex.message}`, | ||
line: location.start.line, | ||
column: location.start.column + 1 | ||
} | ||
}; | ||
|
||
} | ||
|
||
return { | ||
success: true, | ||
config: items | ||
}; | ||
} | ||
|
||
/** | ||
* Parses a config of values separated by comma. | ||
* @param {string} string The string to parse. | ||
* @returns {Object} Result map of values and true values | ||
*/ | ||
parseListConfig(string) { | ||
debug("Parsing list config"); | ||
|
||
const items = {}; | ||
|
||
// Collapse whitespace around commas | ||
string.replace(/\s*,\s*/g, ",").split(/,+/).forEach(name => { | ||
const trimmedName = name.trim(); | ||
|
||
if (trimmedName) { | ||
items[trimmedName] = true; | ||
} | ||
}); | ||
return items; | ||
} | ||
|
||
}; |
Oops, something went wrong.