mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-04 14:03:30 +00:00 
			
		
		
		
	tools: Remove find-add-class tool.
I added this tool a few years ago, and I did have a vision for how it would improve our codebase, but I can't remember exactly where I was going with it. At this point the tool is just a little too noisy to be helpful. An example of it creating confusion was a recent PR where somebody was patching user_circle_class in the PM list, and we already had similar code in the buddy list, because they use the same CSS. I mean, there was possibly a way that the code could have been structured to remove some of the duplication, but it probably would have just moved the complexity around. I just don't think it's worth maintaining the tool at this point.
This commit is contained in:
		@@ -185,14 +185,6 @@ that we exempt may be deemed not worthwhile to fix.
 | 
			
		||||
We check our JavaScript code in a few different ways:
 | 
			
		||||
- We run eslint.
 | 
			
		||||
- We perform custom Zulip regex checks on the code.
 | 
			
		||||
- We verify that all addClass calls, with a few exceptions, explicitly
 | 
			
		||||
  contain a CSS class.
 | 
			
		||||
 | 
			
		||||
The last check happens via a call to `./tools/find-add-class`.  This
 | 
			
		||||
particular check is a work in progress, as we are trying to evolve a
 | 
			
		||||
more rigorous system for weeding out legacy CSS styles, and the ability
 | 
			
		||||
to quickly introspect our JS code for `addClass` calls is part of our
 | 
			
		||||
vision.
 | 
			
		||||
 | 
			
		||||
#### Puppet manifests
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,43 +0,0 @@
 | 
			
		||||
#!/usr/bin/env python3
 | 
			
		||||
 | 
			
		||||
from lib.find_add_class import display, find
 | 
			
		||||
import glob
 | 
			
		||||
import argparse
 | 
			
		||||
 | 
			
		||||
# check for the venv
 | 
			
		||||
from lib import sanity_check
 | 
			
		||||
sanity_check.check_venv(__file__)
 | 
			
		||||
 | 
			
		||||
def process_files():
 | 
			
		||||
    # type: () -> None
 | 
			
		||||
 | 
			
		||||
    description = '''
 | 
			
		||||
        Use this tool to find HTML classes that we use in our JS code.
 | 
			
		||||
        This looks for calls to addClass, and if you use the -v option,
 | 
			
		||||
        you will get a display of (fn, html_class) tuples that
 | 
			
		||||
        represent addClass calls.
 | 
			
		||||
 | 
			
		||||
        If you call it with no options, the tool acts as a linter, and
 | 
			
		||||
        it will complain if it can't resolve the class for an addClass()
 | 
			
		||||
        call.
 | 
			
		||||
        '''
 | 
			
		||||
 | 
			
		||||
    parser = argparse.ArgumentParser(description=description)
 | 
			
		||||
    parser.add_argument('-v', '--verbose',
 | 
			
		||||
                        action='store_true', default=False,
 | 
			
		||||
                        help='show where calls are')
 | 
			
		||||
    parser.add_argument('targets', nargs=argparse.REMAINDER)
 | 
			
		||||
    args = parser.parse_args()
 | 
			
		||||
 | 
			
		||||
    if args.targets == []:
 | 
			
		||||
        fns = glob.glob('static/js/*.js')
 | 
			
		||||
    else:
 | 
			
		||||
        fns = args.targets
 | 
			
		||||
 | 
			
		||||
    if args.verbose:
 | 
			
		||||
        display(fns)
 | 
			
		||||
    else:
 | 
			
		||||
        find(fns)
 | 
			
		||||
 | 
			
		||||
if __name__ == '__main__':
 | 
			
		||||
    process_files()
 | 
			
		||||
@@ -1,116 +0,0 @@
 | 
			
		||||
from typing import List, Set, Tuple
 | 
			
		||||
 | 
			
		||||
import os
 | 
			
		||||
import re
 | 
			
		||||
 | 
			
		||||
GENERIC_KEYWORDS = [
 | 
			
		||||
    'active',
 | 
			
		||||
    'alert',
 | 
			
		||||
    'danger',
 | 
			
		||||
    'condensed',
 | 
			
		||||
    'disabled',
 | 
			
		||||
    'enabled',
 | 
			
		||||
    'error',
 | 
			
		||||
    'expanded',
 | 
			
		||||
    'fade-out',
 | 
			
		||||
    'first',
 | 
			
		||||
    'hide',
 | 
			
		||||
    'in',
 | 
			
		||||
    'show',
 | 
			
		||||
    'notdisplayed',
 | 
			
		||||
    'popover',
 | 
			
		||||
    'no-border',
 | 
			
		||||
    'rtl',
 | 
			
		||||
    'second',
 | 
			
		||||
    'selected',
 | 
			
		||||
    'slide-left',
 | 
			
		||||
    'success',
 | 
			
		||||
    'text-error',
 | 
			
		||||
    'warning',
 | 
			
		||||
    'zoom-in',  # TODO: clean these up, they are confusing
 | 
			
		||||
    'zoom-out',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
def raise_error(fn, i, line):
 | 
			
		||||
    # type: (str, int, str) -> None
 | 
			
		||||
    error = '''
 | 
			
		||||
        In %s line %d there is the following line of code:
 | 
			
		||||
 | 
			
		||||
        %s
 | 
			
		||||
 | 
			
		||||
        Our tools want to be able to identify which modules
 | 
			
		||||
        add which HTML/CSS classes, and we need two things to
 | 
			
		||||
        happen:
 | 
			
		||||
 | 
			
		||||
            - The code must explicitly name the class.
 | 
			
		||||
            - Only one module can refer to that class (unless
 | 
			
		||||
              it is something generic like an alert class).
 | 
			
		||||
 | 
			
		||||
        If you get this error, you can usually address it by
 | 
			
		||||
        refactoring your code to be more explicit, or you can
 | 
			
		||||
        move the common code that sets the class to a library
 | 
			
		||||
        module.  If neither of those applies, you need to
 | 
			
		||||
        modify %s
 | 
			
		||||
        ''' % (fn, i, line, __file__)
 | 
			
		||||
    raise Exception(error)
 | 
			
		||||
 | 
			
		||||
def generic(html_class):
 | 
			
		||||
    # type: (str) -> bool
 | 
			
		||||
    for kw in GENERIC_KEYWORDS:
 | 
			
		||||
        if kw in html_class:
 | 
			
		||||
            return True
 | 
			
		||||
    return False
 | 
			
		||||
 | 
			
		||||
def display(fns):
 | 
			
		||||
    # type: (List[str]) -> None
 | 
			
		||||
    for tup in find(fns):
 | 
			
		||||
        # this format is for code generation purposes
 | 
			
		||||
        print(' ' * 8 + repr(tup) + ',')
 | 
			
		||||
 | 
			
		||||
def find(fns):
 | 
			
		||||
    # type: (List[str]) -> List[Tuple[str, str]]
 | 
			
		||||
    encountered = set()  # type: Set[str]
 | 
			
		||||
    tups = []  # type: List[Tuple[str, str]]
 | 
			
		||||
    for full_fn in fns:
 | 
			
		||||
        # Don't check frontend tests, since they may do all sorts of
 | 
			
		||||
        # extra hackery that isn't of interest to us.
 | 
			
		||||
        if full_fn.startswith("frontend_tests"):
 | 
			
		||||
            continue
 | 
			
		||||
        lines = list(open(full_fn))
 | 
			
		||||
        fn = os.path.basename(full_fn)
 | 
			
		||||
        module_classes = set()  # type: Set[str]
 | 
			
		||||
        for i, line in enumerate(lines):
 | 
			
		||||
            if 'addClass' in line:
 | 
			
		||||
                html_classes = []  # type: List[str]
 | 
			
		||||
                m = re.search(r'''addClass\(['"](.*?)['"]''', line)
 | 
			
		||||
                if m:
 | 
			
		||||
                    html_classes = [m.group(1)]
 | 
			
		||||
                if not html_classes:
 | 
			
		||||
                    if 'bar-success' in line:
 | 
			
		||||
                        html_classes = ['bar-success', 'bar-danger']
 | 
			
		||||
                    elif fn == 'hotspots.js' and 'arrow_placement' in line:
 | 
			
		||||
                        html_classes = ['arrow-top', 'arrow-left', 'arrow-bottom', 'arrow-right']
 | 
			
		||||
                    elif 'color_class' in line:
 | 
			
		||||
                        continue
 | 
			
		||||
                    elif 'stream_dark' in line:
 | 
			
		||||
                        continue
 | 
			
		||||
                    elif 'opts.' in line:
 | 
			
		||||
                        continue
 | 
			
		||||
                    elif fn == 'signup.js' and 'class_to_add' in line:
 | 
			
		||||
                        html_classes = ['error', 'success']
 | 
			
		||||
                    elif fn == 'ui_report.js' and 'status_classes' in line:
 | 
			
		||||
                        html_classes = ['alert']
 | 
			
		||||
 | 
			
		||||
                if not html_classes:
 | 
			
		||||
                    raise_error(full_fn, i, line)
 | 
			
		||||
                for html_class in html_classes:
 | 
			
		||||
                    if generic(html_class):
 | 
			
		||||
                        continue
 | 
			
		||||
                    if html_class in module_classes:
 | 
			
		||||
                        continue
 | 
			
		||||
                    if html_class in encountered:
 | 
			
		||||
                        raise_error(full_fn, i, line)
 | 
			
		||||
                    tups.append((fn, html_class))
 | 
			
		||||
                    module_classes.add(html_class)
 | 
			
		||||
                    encountered.add(html_class)
 | 
			
		||||
    return tups
 | 
			
		||||
@@ -51,8 +51,6 @@ def run():
 | 
			
		||||
        'frontend': ['js', 'ts', 'css', 'scss', 'hbs', 'html', 'lock'],
 | 
			
		||||
    }, exclude=EXCLUDED_FILES)
 | 
			
		||||
 | 
			
		||||
    linter_config.external_linter('add_class', ['tools/find-add-class'], ['js'],
 | 
			
		||||
                                  description="Compares addClass() between JavaSsript and CSS.")
 | 
			
		||||
    linter_config.external_linter('css', ['node', 'node_modules/.bin/stylelint'], ['css', 'scss'],
 | 
			
		||||
                                  fix_arg='--fix',
 | 
			
		||||
                                  description="Standard CSS style and formatting linter "
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user