<commit_before>/* @internal */
namespace ts.codefix {
    const fixIdPrefix = "unusedIdentifier_prefix";
    const fixIdDelete = "unusedIdentifier_delete";
    const errorCodes = [
        Diagnostics._0_is_declared_but_its_value_is_never_read.code,
        Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code,
    ];
    registerCodeFix({
        errorCodes,
        getCodeActions(context) {
            const { sourceFile } = context;
            const token = getToken(sourceFile, context.span.start);
            const result: CodeFixAction[] = [];

            const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token));
            if (deletion.length) {
                const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), [token.getText()]);
                result.push({ description, changes: deletion, fixId: fixIdDelete });
            }

            const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, context.errorCode, sourceFile, token));
            if (prefix.length) {
                const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Prefix_0_with_an_underscore), [token.getText()]);
                result.push({ description, changes: prefix, fixId: fixIdPrefix });
            }

            return result;
        },
        fixIds: [fixIdPrefix, fixIdDelete],
        getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
            const { sourceFile } = context;
            const token = getToken(diag.file!, diag.start!);
            switch (context.fixId) {
                case fixIdPrefix:
                    if (isIdentifier(token) && canPrefix(token)) {
                        tryPrefixDeclaration(changes, diag.code, sourceFile, token);
                    }
                    break;
                case fixIdDelete:
                    tryDeleteDeclaration(changes, sourceFile, token);
                    break;
                default:
                    Debug.fail(JSON.stringify(context.fixId));
            }
        }),
    });

    function getToken(sourceFile: SourceFile, pos: number): Node {
        const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
        // this handles var ["computed"] = 12;
        return token.kind === SyntaxKind.OpenBracketToken ? getTokenAtPosition(sourceFile, pos + 1, /*includeJsDocComment*/ false) : token;
    }

    function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void {
        // Don't offer to prefix a property.
        if (errorCode !== Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code && isIdentifier(token) && canPrefix(token)) {
            changes.replaceNode(sourceFile, token, createIdentifier(`_${token.text}`));
        }
    }

    function canPrefix(token: Identifier): boolean {
        switch (token.parent.kind) {
            case SyntaxKind.Parameter:
                return true;
            case SyntaxKind.VariableDeclaration: {
                const varDecl = token.parent as VariableDeclaration;
                switch (varDecl.parent.parent.kind) {
                    case SyntaxKind.ForOfStatement:
                    case SyntaxKind.ForInStatement:
                        return true;
                }
            }
        }
        return false;
    }

    function tryDeleteDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void {
        switch (token.kind) {
            case SyntaxKind.Identifier:
                tryDeleteIdentifier(changes, sourceFile, <Identifier>token);
                break;
            case SyntaxKind.PropertyDeclaration:
            case SyntaxKind.NamespaceImport:
                changes.deleteNode(sourceFile, token.parent);
                break;
            default:
                tryDeleteDefault(changes, sourceFile, token);
        }
    }

    function tryDeleteDefault(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void {
        if (isDeclarationName(token)) {
            changes.deleteNode(sourceFile, token.parent);
        }
        else if (isLiteralComputedPropertyDeclarationName(token)) {
            changes.deleteNode(sourceFile, token.parent.parent);
        }
    }

    function tryDeleteIdentifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, identifier: Identifier): void {
        const parent = identifier.parent;
        switch (parent.kind) {
            case SyntaxKind.VariableDeclaration:
                tryDeleteVariableDeclaration(changes, sourceFile, <VariableDeclaration>parent);
                break;

            case SyntaxKind.TypeParameter:
                const typeParameters = (<DeclarationWithTypeParameters>parent.parent).typeParameters;
                if (typeParameters.length === 1) {
                    const previousToken = getTokenAtPosition(sourceFile, typeParameters.pos - 1, /*includeJsDocComment*/ false);
                    const nextToken = getTokenAtPosition(sourceFile, typeParameters.end, /*includeJsDocComment*/ false);
                    Debug.assert(previousToken.kind === SyntaxKind.LessThanToken);
                    Debug.assert(nextToken.kind === SyntaxKind.GreaterThanToken);

                    changes.deleteNodeRange(sourceFile, previousToken, nextToken);
                }
                else {
                    changes.deleteNodeInList(sourceFile, parent);
                }
                break;

            case SyntaxKind.Parameter:
                const oldFunction = parent.parent;
                if (isArrowFunction(oldFunction) && oldFunction.parameters.length === 1) {
                    // Lambdas with exactly one parameter are special because, after removal, there
                    // must be an empty parameter list (i.e. `()`) and this won't necessarily be the
                    // case if the parameter is simply removed (e.g. in `x => 1`).
                    const newFunction = updateArrowFunction(
                        oldFunction,
                        oldFunction.modifiers,
                        oldFunction.typeParameters,
                        /*parameters*/ undefined,
                        oldFunction.type,
                        oldFunction.equalsGreaterThanToken,
                        oldFunction.body);

                    suppressLeadingAndTrailingTrivia(newFunction);<commit_msg>Add explanatory comment<commit_after>/* @internal */
namespace ts.codefix {
    const fixIdPrefix = "unusedIdentifier_prefix";
    const fixIdDelete = "unusedIdentifier_delete";
    const errorCodes = [
        Diagnostics._0_is_declared_but_its_value_is_never_read.code,
        Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code,
    ];
    registerCodeFix({
        errorCodes,
        getCodeActions(context) {
            const { sourceFile } = context;
            const token = getToken(sourceFile, context.span.start);
            const result: CodeFixAction[] = [];

            const deletion = textChanges.ChangeTracker.with(context, t => tryDeleteDeclaration(t, sourceFile, token));
            if (deletion.length) {
                const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Remove_declaration_for_Colon_0), [token.getText()]);
                result.push({ description, changes: deletion, fixId: fixIdDelete });
            }

            const prefix = textChanges.ChangeTracker.with(context, t => tryPrefixDeclaration(t, context.errorCode, sourceFile, token));
            if (prefix.length) {
                const description = formatStringFromArgs(getLocaleSpecificMessage(Diagnostics.Prefix_0_with_an_underscore), [token.getText()]);
                result.push({ description, changes: prefix, fixId: fixIdPrefix });
            }

            return result;
        },
        fixIds: [fixIdPrefix, fixIdDelete],
        getAllCodeActions: context => codeFixAll(context, errorCodes, (changes, diag) => {
            const { sourceFile } = context;
            const token = getToken(diag.file!, diag.start!);
            switch (context.fixId) {
                case fixIdPrefix:
                    if (isIdentifier(token) && canPrefix(token)) {
                        tryPrefixDeclaration(changes, diag.code, sourceFile, token);
                    }
                    break;
                case fixIdDelete:
                    tryDeleteDeclaration(changes, sourceFile, token);
                    break;
                default:
                    Debug.fail(JSON.stringify(context.fixId));
            }
        }),
    });

    function getToken(sourceFile: SourceFile, pos: number): Node {
        const token = getTokenAtPosition(sourceFile, pos, /*includeJsDocComment*/ false);
        // this handles var ["computed"] = 12;
        return token.kind === SyntaxKind.OpenBracketToken ? getTokenAtPosition(sourceFile, pos + 1, /*includeJsDocComment*/ false) : token;
    }

    function tryPrefixDeclaration(changes: textChanges.ChangeTracker, errorCode: number, sourceFile: SourceFile, token: Node): void {
        // Don't offer to prefix a property.
        if (errorCode !== Diagnostics.Property_0_is_declared_but_its_value_is_never_read.code && isIdentifier(token) && canPrefix(token)) {
            changes.replaceNode(sourceFile, token, createIdentifier(`_${token.text}`));
        }
    }

    function canPrefix(token: Identifier): boolean {
        switch (token.parent.kind) {
            case SyntaxKind.Parameter:
                return true;
            case SyntaxKind.VariableDeclaration: {
                const varDecl = token.parent as VariableDeclaration;
                switch (varDecl.parent.parent.kind) {
                    case SyntaxKind.ForOfStatement:
                    case SyntaxKind.ForInStatement:
                        return true;
                }
            }
        }
        return false;
    }

    function tryDeleteDeclaration(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void {
        switch (token.kind) {
            case SyntaxKind.Identifier:
                tryDeleteIdentifier(changes, sourceFile, <Identifier>token);
                break;
            case SyntaxKind.PropertyDeclaration:
            case SyntaxKind.NamespaceImport:
                changes.deleteNode(sourceFile, token.parent);
                break;
            default:
                tryDeleteDefault(changes, sourceFile, token);
        }
    }

    function tryDeleteDefault(changes: textChanges.ChangeTracker, sourceFile: SourceFile, token: Node): void {
        if (isDeclarationName(token)) {
            changes.deleteNode(sourceFile, token.parent);
        }
        else if (isLiteralComputedPropertyDeclarationName(token)) {
            changes.deleteNode(sourceFile, token.parent.parent);
        }
    }

    function tryDeleteIdentifier(changes: textChanges.ChangeTracker, sourceFile: SourceFile, identifier: Identifier): void {
        const parent = identifier.parent;
        switch (parent.kind) {
            case SyntaxKind.VariableDeclaration:
                tryDeleteVariableDeclaration(changes, sourceFile, <VariableDeclaration>parent);
                break;

            case SyntaxKind.TypeParameter:
                const typeParameters = (<DeclarationWithTypeParameters>parent.parent).typeParameters;
                if (typeParameters.length === 1) {
                    const previousToken = getTokenAtPosition(sourceFile, typeParameters.pos - 1, /*includeJsDocComment*/ false);
                    const nextToken = getTokenAtPosition(sourceFile, typeParameters.end, /*includeJsDocComment*/ false);
                    Debug.assert(previousToken.kind === SyntaxKind.LessThanToken);
                    Debug.assert(nextToken.kind === SyntaxKind.GreaterThanToken);

                    changes.deleteNodeRange(sourceFile, previousToken, nextToken);
                }
                else {
                    changes.deleteNodeInList(sourceFile, parent);
                }
                break;

            case SyntaxKind.Parameter:
                const oldFunction = parent.parent;
                if (isArrowFunction(oldFunction) && oldFunction.parameters.length === 1) {
                    // Lambdas with exactly one parameter are special because, after removal, there
                    // must be an empty parameter list (i.e. `()`) and this won't necessarily be the
                    // case if the parameter is simply removed (e.g. in `x => 1`).
                    const newFunction = updateArrowFunction(
                        oldFunction,
                        oldFunction.modifiers,
                        oldFunction.typeParameters,
                        /*parameters*/ undefined,
                        oldFunction.type,
                        oldFunction.equalsGreaterThanToken,
                        oldFunction.body);

                    // Drop leading and trailing trivia of the new function because we're only going
                    // to replace the span (vs the full span) of the old function - the old leading
                    // and trailing trivia will remain.
                    suppressLeadingAndTrailingTrivia(newFunction);
{'fraction_non_alphanumeric': 0.0878785623930352, 'fraction_numerical': 0.0017858471612471167, 'mean_word_length': 2.032490974729242, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 19, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4255153', 'n_tokens_mistral': 3305, 'n_tokens_neox': 3145, 'n_words': 698}