File: find_invalid_css_variables.py

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (95 lines) | stat: -rw-r--r-- 3,322 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# Copyright 2020 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import argparse
import sys
import os
import re

sys.path += [os.path.dirname(os.path.dirname(__file__))]

from style_variable_generator.css_generator import CSSStyleGenerator
from style_variable_generator.presubmit_support import RunGit


# TODO(calamity): extend this checker to find unused C++ variables
def FindInvalidCSSVariables(file_to_json_strings, git_runner=RunGit):
    style_generator = CSSStyleGenerator()
    css_prefixes = set()
    referenced_vars = set()
    for f, json_string in file_to_json_strings.items():
        style_generator.AddJSONToModel(json_string, in_file=f)
        referenced_vars |= set(re.findall(r'\$([a-z_0-9]+)', json_string))

        context = style_generator.in_file_to_context.get(f, {}).get('CSS')
        if (not context or 'prefix' not in context):
            raise KeyError('This tool only works on files with a CSS prefix.')

        css_prefixes.add('--' + context['prefix'] + '-')

    unspecified_file_and_names = []
    css_var_names = style_generator.GetCSSVarNames()
    valid_names = set(css_var_names.keys())
    unused = set(css_var_names.values()).difference(referenced_vars)

    for css_prefix in css_prefixes:
        grep_result = git_runner([
            'grep', '-on',
            '\\%s[a-z0-9-]*' % css_prefix, '--', '*.css', '*.html', '*.js'
        ]).decode('utf-8').splitlines()
        found_files_and_names = [x.split(':') for x in grep_result]
        found_names = set()
        for (filename, line, name) in found_files_and_names:
            found_names.add(name)
            if name in valid_names and css_var_names[name] in unused:
                unused.remove(css_var_names[name])

        unspecified = found_names.difference(valid_names)
        for (filename, line, name) in found_files_and_names:
            if filename.find('test') != -1:
                continue

            if name in unspecified:
                unspecified_file_and_names.append('%s:%s:%s' %
                                                  (filename, line, name))

    return {
        'unspecified': unspecified_file_and_names,
        # TODO(calamity): This should also account for names referenced in json5
        # files.
        'unused': unused,
        'css_prefix': css_prefix,
    }


def main():
    parser = argparse.ArgumentParser(
        description='''Finds CSS variables in the codebase that are prefixed
        with |input_files|' CSS prefix but aren't specified in |input_files|.'''
    )
    parser.add_argument('targets', nargs='+', help='source json5 color files', )
    args = parser.parse_args()

    input_files = args.targets

    file_to_json_strings = {}
    for input_file in input_files:
        with open(input_file, 'r') as f:
            file_to_json_strings[input_file] = f.read()

    result = FindInvalidCSSVariables(file_to_json_strings)

    print('Has prefix %s but not in %s:' % (result['css_prefix'], input_files))
    for name in sorted(result['unspecified']):
        print(name)

    print('\nGenerated by %s but not used in codebase:' % input_files)
    for name in sorted(result['unused']):
        print(name)

    return 0


if __name__ == '__main__':
    sys.exit(main())