• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

rokucommunity / bslint / #1041

03 Oct 2024 07:42PM UTC coverage: 91.278% (-0.5%) from 91.746%
#1041

Pull #96

TwitchBronBron
1.0.0-alpha.39
Pull Request #96: v1

927 of 1061 branches covered (87.37%)

Branch coverage included in aggregate %.

231 of 240 new or added lines in 12 files covered. (96.25%)

11 existing lines in 3 files now uncovered.

1009 of 1060 relevant lines covered (95.19%)

68.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

95.77
/src/createColorValidator.ts
1
import { BsDiagnostic, Location } from 'brighterscript';
2
import { messages } from './plugins/codeStyle/diagnosticMessages';
1✔
3
import { BsLintRules, RuleColorFormat, RuleColorCase, RuleColorAlpha, RuleColorAlphaDefaults, RuleColorCertCompliant } from './index';
4

5
export function createColorValidator(severity: Readonly<BsLintRules>) {
1✔
6
    const { colorFormat, colorCase, colorAlpha, colorAlphaDefaults, colorCertCompliant } = severity;
16✔
7
    return (text: string, location: Location, diagnostics: BsDiagnostic[]) => {
16✔
8
        const len = text.length;
69✔
9
        if (len < 7 || len > 12) {
69✔
10
            // we're only interested in string length is between 7 (#EBEBEB) to 12 ("0xEBEBEBFF") chars long
11
            return;
9✔
12
        }
13

14
        const hashHexRegex = /#[0-9A-Fa-f]{6}/g;
60✔
15
        const quotedNumericHexRegex = /0x[0-9A-Fa-f]{6}/g;
60✔
16
        const hashHexMatches = (text.startsWith('#') || text.startsWith('"#')) ? text.match(hashHexRegex) : undefined;
60✔
17
        const quotedNumericHexMatches = (text.startsWith('0x') || text.startsWith('"0x')) ? text.match(quotedNumericHexRegex) : undefined;
60✔
18

19
        if ((colorFormat === 'never') && (quotedNumericHexMatches || hashHexMatches)) {
60✔
20
            diagnostics.push(messages.expectedColorFormat(location));
3✔
21
            return;
3✔
22
        }
23
        const hashHexAlphaRegex = /#[0-9A-Fa-f]{8}/g;
57✔
24
        const quotedNumericHexAlphaRegex = /0x[0-9A-Fa-f]{8}/g;
57✔
25

26
        if (colorFormat === 'hash-hex') {
57✔
27
            if (quotedNumericHexMatches) {
7!
NEW
28
                diagnostics.push(messages.expectedColorFormat(location));
×
29
            }
30
            validateColorCase(hashHexMatches, location, diagnostics, colorCase, colorFormat);
7✔
31
            validateColorAlpha(text.match(hashHexAlphaRegex), hashHexMatches, quotedNumericHexMatches, location, diagnostics, colorAlpha, colorAlphaDefaults);
7✔
32
            validateColorCertCompliance(hashHexMatches, location, diagnostics, colorFormat, colorCertCompliant);
7✔
33

34
        } else if (colorFormat === 'quoted-numeric-hex') {
50!
35
            if (hashHexMatches) {
50!
NEW
36
                diagnostics.push(messages.expectedColorFormat(location));
×
37
            }
38
            validateColorCase(quotedNumericHexMatches, location, diagnostics, colorCase, colorFormat);
50✔
39
            validateColorAlpha(text.match(quotedNumericHexAlphaRegex), hashHexMatches, quotedNumericHexMatches, location, diagnostics, colorAlpha, colorAlphaDefaults);
50✔
40
            validateColorCertCompliance(quotedNumericHexMatches, location, diagnostics, colorFormat, colorCertCompliant);
50✔
41
        }
42
    };
43
}
44

45
function validateColorAlpha(alphaMatches: RegExpMatchArray, hashMatches: RegExpMatchArray, quotedNumericHexMatches: RegExpMatchArray, location: Location, diagnostics: (BsDiagnostic)[], alpha: RuleColorAlpha, alphaDefaults: RuleColorAlphaDefaults) {
46
    const validateColorAlpha = (alpha === 'never' || alpha === 'always' || alpha === 'allowed');
57✔
47
    if (validateColorAlpha) {
57✔
48
        if (alpha === 'never' && alphaMatches) {
32✔
49
            diagnostics.push(messages.expectedColorAlpha(location));
3✔
50
        }
51
        if ((alpha === 'always' && alphaMatches === null) && (hashMatches || quotedNumericHexMatches)) {
32✔
52
            diagnostics.push(messages.expectedColorAlpha(location));
2✔
53
        }
54
        if ((alphaDefaults === 'never' || alphaDefaults === 'only-hidden') && alphaMatches) {
32✔
55
            for (let i = 0; i < alphaMatches.length; i++) {
6✔
56
                const colorHashAlpha = alphaMatches[i];
6✔
57
                const alphaValue = colorHashAlpha.slice(-2).toLowerCase();
6✔
58
                if (alphaValue === 'ff' || (alphaDefaults === 'never' && alphaValue === '00')) {
6✔
59
                    diagnostics.push(messages.expectedColorAlphaDefaults(location));
3✔
60
                }
61
            }
62
        }
63
    }
64
}
65

66
function validateColorCase(matches: RegExpMatchArray, location: Location, diagnostics: (BsDiagnostic)[], colorCase: RuleColorCase, colorFormat: RuleColorFormat) {
67
    const validateColorCase = colorCase === 'upper' || colorCase === 'lower';
57✔
68
    if (validateColorCase && matches) {
57✔
69
        let colorValue = matches[0];
16✔
70
        const charsToStrip = (colorFormat === 'hash-hex') ? 1 : 2;
16✔
71
        colorValue = colorValue.substring(charsToStrip);
16✔
72
        if (colorCase === 'lower' && colorValue !== colorValue.toLowerCase()) {
16✔
73
            diagnostics.push(messages.expectedColorCase(location));
3✔
74
        }
75
        if (colorCase === 'upper' && colorValue !== colorValue.toUpperCase()) {
16✔
76
            diagnostics.push(messages.expectedColorCase(location));
8✔
77
        }
78
    }
79
}
80

81
function validateColorCertCompliance(matches: RegExpMatchArray, location: Location, diagnostics: (BsDiagnostic)[], colorFormat: RuleColorFormat, certCompliant: RuleColorCertCompliant) {
82
    const validateCertCompliant = certCompliant === 'always';
57✔
83
    if (validateCertCompliant && matches) {
57✔
84
        const BROADCAST_SAFE_BLACK = '161616';
4✔
85
        const BROADCAST_SAFE_WHITE = 'EBEBEB';
4✔
86
        const MAX_BLACK_LUMA = getColorLuma(BROADCAST_SAFE_BLACK);
4✔
87
        const MAX_WHITE_LUMA = getColorLuma(BROADCAST_SAFE_WHITE);
4✔
88
        let colorValue = matches[0];
4✔
89
        const charsToStrip = (colorFormat === 'hash-hex') ? 1 : 2;
4!
90
        colorValue = colorValue.substring(charsToStrip);
4✔
91
        const colorLuma = getColorLuma(colorValue);
4✔
92
        if (colorLuma > MAX_WHITE_LUMA || colorLuma < MAX_BLACK_LUMA) {
4✔
93
            diagnostics.push(messages.colorCertCompliance(location));
2✔
94
        }
95
    }
96
}
97

98
function getColorLuma(value: string) {
99
    const rgb = parseInt(value, 16); // Convert rrggbb to decimal
12✔
100
    const red = (rgb >> 16) & 0xff; // eslint-disable-line no-bitwise
12✔
101
    const green = (rgb >> 8) & 0xff; // eslint-disable-line no-bitwise
12✔
102
    const blue = (rgb >> 0) & 0xff; // eslint-disable-line no-bitwise
12✔
103
    // Per ITU-R BT.709
104
    return 0.2126 * red + 0.7152 * green + 0.0722 * blue; // eslint-disable-line
12✔
105
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc