private addAction()

in DevSkim-VSCode-Plugin/server/src/utility_classes/suppressions.ts [99:249]


    private addAction(ruleID: string, documentContents: string, startCharacter: number, lineStart: number,
        langID: string, isReviewRule: boolean, daysOffset: number = -1): DevSkimAutoFixEdit
    {
        let action: DevSkimAutoFixEdit = Object.create(null);
        let regex: RegExp = (isReviewRule)
            ? DevSkimSuppression.reviewRegEx
            : DevSkimSuppression.suppressionRegEx;
        let startingWhitespace = " ";

        this.setActionFixName(isReviewRule, action, ruleID, daysOffset);

        //make the day in the future that a time based expression will expire
        const date = new Date();
        if (!isReviewRule && daysOffset > 0)
        {
            date.setDate(date.getDate() + daysOffset);
        }

        //find the end of the current line of the finding
        let XRegExp = require('xregexp');
        let range: Range;
        let match;

        //start off generating a new suppression.  If its going on the same line as the finding look for the
        //newline (if it exists) and insert just before it
        if(this.dsSettings.suppressionCommentPlacement == "same line as finding")
        {
            //check to see if this is the end of the document or not, as there is no newline at the end
            match = XRegExp.exec(documentContents, DocumentUtilities.newlinePattern, startCharacter);
            if (match)
            {
                let columnStart = (lineStart == 0)
                    ? match.index
                    : match.index - documentContents.substr(0, match.index).lastIndexOf("\n") - 1;
                range = Range.create(lineStart, columnStart, lineStart, columnStart + match[0].length);
                documentContents = documentContents.substr(0, match.index);
            }
            else
            {
                //replace with end of file
                let columnStart = (lineStart == 0)
                    ? documentContents.length
                    : documentContents.length - documentContents.lastIndexOf("\n") - 1;
                range = Range.create(lineStart, columnStart, lineStart, columnStart);
            }
        }
        //if the suppression goes on the line above the logic is much simpler - we just insert at the front
        //of the line and below we add a newline at the end of the suppression
        else
        {
            range = Range.create(lineStart, 0, lineStart, 0);
            startingWhitespace = DocumentUtilities.GetLeadingWhiteSpace(documentContents, lineStart);

        }

        // if there is an existing suppression that has expired (or there for a different issue)
        // then it needs to be replaced
        let existingSuppression : DevSkimSuppressionFinding;
        let suppressionStart : number = startCharacter;
        let suppressionLine : number = lineStart;

        //this checks for any existing suppression, regardless of whether it is expired, or for a different finding, because regardless
        //that comment gets modified
        existingSuppression= DevSkimSuppression.isFindingCommented(startCharacter,documentContents,ruleID,langID, isReviewRule, true);
        //yep, there is an existing suppression, so start working off of its location
        if (existingSuppression.showSuppressionFinding)
        {
            suppressionStart = DocumentUtilities.GetDocumentPosition(documentContents, existingSuppression.suppressionRange.start.line);
            suppressionLine = existingSuppression.suppressionRange.start.line;
        }
        //now get the actual suppression text out so it can be modified
        match = XRegExp.exec(documentContents, regex, suppressionStart);
        if (match && DocumentUtilities.GetLineNumber(documentContents, match.index) == suppressionLine)
        {
            //parse the existing suppression and set the range/text to modify it
            let columnStart: number = (suppressionLine == 0) ? match.index : match.index - documentContents.substr(0, match.index).lastIndexOf("\n") - 1;
            range = Range.create(suppressionLine, columnStart, suppressionLine, columnStart + match[0].length);
            if (match[1] !== undefined && match[1] != null && match[1].length > 0)
            {
                //the existing ruleID was found, so just set it to that string (may include other rules too)
                //this would be an instance where the date has expired
                if (match[1].indexOf(ruleID) >= 0)
                {
                    ruleID = match[1];
                }
                //the finding rule id wasn't found, so this is an instance where there is a separate finding suppressed
                //on the same line.  Append
                else
                {
                    ruleID = ruleID + "," + match[1];
                }
            }
            if (isReviewRule || daysOffset > 0)
            {
                action.text = this.makeActionString(ruleID, isReviewRule, date);
            }
            else
            {
                action.text = this.makeActionString(ruleID, isReviewRule);
            }
        }

        // if there is not an existing suppression we need to create the full suppression text
        else
        {
            let StartComment: string = "";
            let EndComment : string = "";

            //select the right comment type, based on the user settings and the
            //comment capability of the programming language
            if(this.dsSettings.suppressionCommentStyle == "block")
            {
                StartComment = SourceContext.GetBlockCommentStart(langID);
                EndComment = SourceContext.GetBlockCommentEnd(langID);
                if (!StartComment || StartComment.length < 1 || !EndComment || EndComment.length < 1)
                {
                    StartComment = SourceContext.GetLineComment(langID);
                }                   
            }
            else
            {
                StartComment = SourceContext.GetLineComment(langID);
                if (!StartComment || StartComment.length < 1)
                {
                    StartComment = SourceContext.GetBlockCommentStart(langID);
                    EndComment = SourceContext.GetBlockCommentEnd(langID);
                }                
            }
            
            
            let optionalNewline: string = "";
            
            //we will need a newline if this suppression is supposed to go above the finding
            if (this.dsSettings.suppressionCommentPlacement == "line above finding") 
            {
                optionalNewline = DocumentUtilities.GetNewlineCharacter(documentContents);
            }
            
            //make the actual text inserted as the suppression            
            if (isReviewRule || daysOffset > 0)
            {
                action.text = startingWhitespace + StartComment + this.makeActionString(ruleID, isReviewRule, date) + " " + EndComment + optionalNewline;
            }
            else
            {
                action.text = startingWhitespace + StartComment + this.makeActionString(ruleID, isReviewRule) + " " + EndComment + optionalNewline;
            }
        }
        action.range = range;
        return action;
    }