Repository: eslint/eslint
File: lib/linter/apply-disable-directives.js (JavaScript)

Code before:

/**
 * Groups a set of directives into sub-arrays by their parent comment.
 * @param {Iterable<Directive>} directives Unused directives to be removed.
 * @returns {Directive[][]} Directives grouped by their parent comment.
 */
function groupByParentDirective(directives) {
    const groups = new Map();

    for (const directive of directives) {
        const { unprocessedDirective: { parentDirective } } = directive;

        if (groups.has(parentDirective)) {
            groups.get(parentDirective).push(directive);
        } else {
            groups.set(parentDirective, [directive]);
        }
    }

    return [...groups.values()];
}

/**
 * Creates removal details for a set of directives within the same comment.
 * @param {Directive[]} directives Unused directives to be removed.
 * @param {Token} node The backing Comment token.
 * @param {SourceCode} sourceCode The source code object for the file being linted.
 * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
 */
function createIndividualDirectivesRemoval(directives, node, sourceCode) {

    const range = sourceCode.getRange(node);

    /*
     * `node.value` starts right after `//` or `/*`.
     * All calculated offsets will be relative to this index.
     */
    const commentValueStart = range[0] + "//".length;

    // Find where the list of rules starts. `\S+` matches with the directive name (e.g. `eslint-disable-line`)
    const listStartOffset = /^\s*\S+\s+/u.exec(node.value)[0].length;

    /*
     * Get the list text without any surrounding whitespace. In order to preserve the original
     * formatting, we don't want to change that whitespace.
     *
     *     // eslint-disable-line rule-one , rule-two , rule-three -- comment
     *                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     */
    const listText = node.value
        .slice(listStartOffset) // remove directive name and all whitespace before the list

Review comment (suggestion):
[Suggestion] Now that parent directives are used more between functions, it might make sense to write up a dedicated `ParentDirective` type for them. They come from `createDisableDirectives > { node, value, ruleIds }` so this inline object type is missing a bit of info.

Code after:

/**
 * Groups a set of directives into sub-arrays by their parent comment.
 * @param {Iterable<Directive>} directives Unused directives to be removed.
 * @returns {Directive[][]} Directives grouped by their parent comment.
 */
function groupByParentDirective(directives) {
    const groups = new Map();

    for (const directive of directives) {
        const { unprocessedDirective: { parentDirective } } = directive;

        if (groups.has(parentDirective)) {
            groups.get(parentDirective).push(directive);
        } else {
            groups.set(parentDirective, [directive]);
        }
    }

    return [...groups.values()];
}

/**
 * Creates removal details for a set of directives within the same comment.
 * @param {Directive[]} directives Unused directives to be removed.
 * @param {{node: Token, value: string}} parentDirective Data about the backing directive.
 * @param {SourceCode} sourceCode The source code object for the file being linted.
 * @returns {{ description, fix, unprocessedDirective }[]} Details for later creation of output Problems.
 */
function createIndividualDirectivesRemoval(directives, parentDirective, sourceCode) {

    /*
     * Get the list of the rules text without any surrounding whitespace. In order to preserve the original
     * formatting, we don't want to change that whitespace.
     *
     *     // eslint-disable-line rule-one , rule-two , rule-three -- comment
     *                            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
     */
    const listText = parentDirective.value.trim();

    // Calculate where it starts in the source code text
    const listStart = sourceCode.text.indexOf(listText, sourceCode.getRange(parentDirective.node)[0]);

    /*
     * We can assume that `listText` contains multiple elements.
     * Otherwise, this function wouldn't be called - if there is
     * only one rule in the list, then the whole comment must be removed.
     */

    return directives.map(directive => {
        const { ruleId } = directive;