function _canonicalizedPropertyValues()

in tools/PasswordRulesParser.js [143:263]


function _canonicalizedPropertyValues(propertyValues, keepCustomCharacterClassFormatCompliant)
{
    let asciiPrintableBitSet = new Array("~".codePointAt(0) - " ".codePointAt(0) + 1);

    for (let propertyValue of propertyValues) {
        if (propertyValue instanceof NamedCharacterClass) {
            if (propertyValue.name === Identifier.UNICODE) {
                return [new NamedCharacterClass(Identifier.UNICODE)];
            }

            if (propertyValue.name === Identifier.ASCII_PRINTABLE) {
                return [new NamedCharacterClass(Identifier.ASCII_PRINTABLE)];
            }

            _markBitsForNamedCharacterClass(asciiPrintableBitSet, propertyValue);
        }
        else if (propertyValue instanceof CustomCharacterClass) {
            _markBitsForCustomCharacterClass(asciiPrintableBitSet, propertyValue);
        }
    }

    let charactersSeen = [];

    function checkRange(start, end) {
        let temp = [];
        for (let i = _bitSetIndexForCharacter(start); i <= _bitSetIndexForCharacter(end); ++i) {
            if (asciiPrintableBitSet[i]) {
                temp.push(_characterAtBitSetIndex(i));
            }
        }

        let result = temp.length === (_bitSetIndexForCharacter(end) - _bitSetIndexForCharacter(start) + 1);
        if (!result) {
            charactersSeen = charactersSeen.concat(temp);
        }
        return result;
    }

    let hasAllUpper = checkRange("A", "Z");
    let hasAllLower = checkRange("a", "z");
    let hasAllDigits = checkRange("0", "9");

    // Check for special characters, accounting for characters that are given special treatment (i.e. '-' and ']')
    let hasAllSpecial = false;
    let hasDash = false;
    let hasRightSquareBracket = false;
    let temp = [];
    for (let i = _bitSetIndexForCharacter(" "); i <= _bitSetIndexForCharacter("/"); ++i) {
        if (!asciiPrintableBitSet[i]) {
            continue;
        }

        let character = _characterAtBitSetIndex(i);
        if (keepCustomCharacterClassFormatCompliant && character === "-") {
            hasDash = true;
        }
        else {
            temp.push(character);
        }
    }
    for (let i = _bitSetIndexForCharacter(":"); i <= _bitSetIndexForCharacter("@"); ++i) {
        if (asciiPrintableBitSet[i]) {
            temp.push(_characterAtBitSetIndex(i));
        }
    }
    for (let i = _bitSetIndexForCharacter("["); i <= _bitSetIndexForCharacter("`"); ++i) {
        if (!asciiPrintableBitSet[i]) {
            continue;
        }

        let character = _characterAtBitSetIndex(i);
        if (keepCustomCharacterClassFormatCompliant && character === "]") {
            hasRightSquareBracket = true;
        }
        else {
            temp.push(character);
        }
    }
    for (let i = _bitSetIndexForCharacter("{"); i <= _bitSetIndexForCharacter("~"); ++i) {
        if (asciiPrintableBitSet[i]) {
            temp.push(_characterAtBitSetIndex(i));
        }
    }

    if (hasDash) {
        temp.unshift("-");
    }
    if (hasRightSquareBracket) {
        temp.push("]");
    }

    let numberOfSpecialCharacters = (_bitSetIndexForCharacter("/") - _bitSetIndexForCharacter(" ") + 1)
        + (_bitSetIndexForCharacter("@") - _bitSetIndexForCharacter(":") + 1)
        + (_bitSetIndexForCharacter("`") - _bitSetIndexForCharacter("[") + 1)
        + (_bitSetIndexForCharacter("~") - _bitSetIndexForCharacter("{") + 1);
    hasAllSpecial = temp.length === numberOfSpecialCharacters;
    if (!hasAllSpecial) {
        charactersSeen = charactersSeen.concat(temp);
    }

    let result = [];
    if (hasAllUpper && hasAllLower && hasAllDigits && hasAllSpecial) {
        return [new NamedCharacterClass(Identifier.ASCII_PRINTABLE)];
    }
    if (hasAllUpper) {
        result.push(new NamedCharacterClass(Identifier.UPPER));
    }
    if (hasAllLower) {
        result.push(new NamedCharacterClass(Identifier.LOWER));
    }
    if (hasAllDigits) {
        result.push(new NamedCharacterClass(Identifier.DIGIT));
    }
    if (hasAllSpecial) {
        result.push(new NamedCharacterClass(Identifier.SPECIAL));
    }
    if (charactersSeen.length) {
        result.push(new CustomCharacterClass(charactersSeen));
    }
    return result;
}