<commit_before>import * as ts from 'typescript';
import * as Lint from 'tslint';

import {ErrorTolerantWalker} from './utils/ErrorTolerantWalker';
import {Utils} from './utils/Utils';
import {ExtendedMetadata} from './utils/ExtendedMetadata';

/**
 * Implementation of the no-http-string rule.
 */
export class Rule extends Lint.Rules.AbstractRule {

    public static metadata: ExtendedMetadata = {
        ruleName: 'no-http-string',
        type: 'maintainability',
        /* tslint:disable:no-http-string */
        description: 'Do not use strings that start with \'http:\'. URL strings should start with \'https:\'. ',
        /* tslint:enable:no-http-string */
        options: null,
        optionsDescription: '',
        typescriptOnly: true,
        issueClass: 'SDL',
        issueType: 'Error',
        severity: 'Critical',
        level: 'Mandatory',
        group: 'Security',
        recommendation: '[true, "http://www.example.com/?.*", "http://www.examples.com/?.*"],',
        commonWeaknessEnumeration: '319'
    };

    public static FAILURE_STRING: string = 'Forbidden http url in string: ';

    public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
        return this.applyWithWalker(new NoHttpStringWalker(sourceFile, this.getOptions()));
    }

}

class NoHttpStringWalker extends ErrorTolerantWalker {
    protected visitStringLiteral(node: ts.StringLiteral): void {
        const stringText : string = (<ts.LiteralExpression>node).text;
        if (/.*http:.*/.test(stringText)) {
            if (!this.isSuppressed(stringText)) {
                const failureString = Rule.FAILURE_STRING + '\'' + stringText + '\'';
                const failure = this.createFailure(node.getStart(), node.getWidth(), failureString);
                this.addFailure(failure);
            }
        }
        super.visitStringLiteral(node);
    }

    private isSuppressed(stringText: string) : boolean {
        const allExceptions : string[] = NoHttpStringWalker.getExceptions(this.getOptions());
        return Utils.exists(allExceptions, (exception: string) : boolean => {
            return new RegExp(exception).test(stringText);
        });
    }

    private static getExceptions(options : Lint.IOptions) : string[] {
        if (options.ruleArguments instanceof Array) {
            return options.ruleArguments[0];
        }
        if (options instanceof Array) {
            return <string[]><any>options; // MSE version of tslint somehow requires this
        }
        return null;
    }
}
<commit_msg>#337 Performance: Replace noHttpStringRule regex with indexOf<commit_after>import * as ts from 'typescript';
import * as Lint from 'tslint';

import {ErrorTolerantWalker} from './utils/ErrorTolerantWalker';
import {Utils} from './utils/Utils';
import {ExtendedMetadata} from './utils/ExtendedMetadata';

/**
 * Implementation of the no-http-string rule.
 */
export class Rule extends Lint.Rules.AbstractRule {

    public static metadata: ExtendedMetadata = {
        ruleName: 'no-http-string',
        type: 'maintainability',
        /* tslint:disable:no-http-string */
        description: 'Do not use strings that start with \'http:\'. URL strings should start with \'https:\'. ',
        /* tslint:enable:no-http-string */
        options: null,
        optionsDescription: '',
        typescriptOnly: true,
        issueClass: 'SDL',
        issueType: 'Error',
        severity: 'Critical',
        level: 'Mandatory',
        group: 'Security',
        recommendation: '[true, "http://www.example.com/?.*", "http://www.examples.com/?.*"],',
        commonWeaknessEnumeration: '319'
    };

    public static FAILURE_STRING: string = 'Forbidden http url in string: ';

    public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] {
        return this.applyWithWalker(new NoHttpStringWalker(sourceFile, this.getOptions()));
    }

}

class NoHttpStringWalker extends ErrorTolerantWalker {
    protected visitStringLiteral(node: ts.StringLiteral): void {
        const stringText : string = (<ts.LiteralExpression>node).text;
        // tslint:disable no-http-string
        if (stringText.indexOf('http:') !== -1) {
            if (!this.isSuppressed(stringText)) {
                const failureString = Rule.FAILURE_STRING + '\'' + stringText + '\'';
                const failure = this.createFailure(node.getStart(), node.getWidth(), failureString);
                this.addFailure(failure);
            }
        }
        super.visitStringLiteral(node);
    }

    private isSuppressed(stringText: string) : boolean {
        const allExceptions : string[] = NoHttpStringWalker.getExceptions(this.getOptions());
        return Utils.exists(allExceptions, (exception: string) : boolean => {
            return new RegExp(exception).test(stringText);
        });
    }

    private static getExceptions(options : Lint.IOptions) : string[] {
        if (options.ruleArguments instanceof Array) {
            return options.ruleArguments[0];
        }
        if (options instanceof Array) {
            return <string[]><any>options; // MSE version of tslint somehow requires this
        }
        return null;
    }
}

{'fraction_non_alphanumeric': 0.12744150067685167, 'fraction_numerical': 0.002320634306710501, 'mean_word_length': 2.7451122375090513, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 4, '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': '2191738', 'n_tokens_mistral': 1463, 'n_tokens_neox': 1405, 'n_words': 337}