mirror of
https://github.com/zulip/zulip.git
synced 2025-11-15 19:31:58 +00:00
Add tools/find-add-class to tools/lint-all.
The find-add-class tool, when in lint mode, verifies that we can understand all calls to addClass from our JS code. When in non-lint mode, i.e. verbose mode, the tool prints out a list of tuples of (fn, class) that we can use as we wish in other tools.
This commit is contained in:
47
tools/find-add-class
Executable file
47
tools/find-add-class
Executable file
@@ -0,0 +1,47 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from lib.find_add_class import display, find
|
||||||
|
import glob
|
||||||
|
import optparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from six.moves import filter
|
||||||
|
try:
|
||||||
|
import lister
|
||||||
|
from typing import cast, Callable, Dict, Iterable, List
|
||||||
|
except ImportError as e:
|
||||||
|
print("ImportError: {}".format(e))
|
||||||
|
print("You need to run the Zulip linters inside a Zulip dev environment.")
|
||||||
|
print("If you are using Vagrant, you can `vagrant ssh` to enter the Vagrant guest.")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
def process_files():
|
||||||
|
# type: () -> None
|
||||||
|
|
||||||
|
usage = '''
|
||||||
|
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 = optparse.OptionParser(usage=usage)
|
||||||
|
parser.add_option('--verbose', '-v',
|
||||||
|
action='store_true', default=False,
|
||||||
|
help='Show where calls are.')
|
||||||
|
(options, _) = parser.parse_args()
|
||||||
|
|
||||||
|
fns = glob.glob('static/js/*.js')
|
||||||
|
if options.verbose:
|
||||||
|
display(fns)
|
||||||
|
else:
|
||||||
|
find(fns)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
process_files()
|
||||||
98
tools/lib/find_add_class.py
Normal file
98
tools/lib/find_add_class.py
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
from typing import Set, Tuple
|
||||||
|
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
|
||||||
|
GENERIC_KEYWORDS = [
|
||||||
|
'active',
|
||||||
|
'alert',
|
||||||
|
'danger',
|
||||||
|
'condensed',
|
||||||
|
'disabled',
|
||||||
|
'error',
|
||||||
|
'expanded',
|
||||||
|
'hide',
|
||||||
|
'notdisplayed',
|
||||||
|
'popover',
|
||||||
|
'success',
|
||||||
|
'text-error',
|
||||||
|
'warning',
|
||||||
|
]
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
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 fn in fns:
|
||||||
|
lines = list(open(fn))
|
||||||
|
fn = os.path.basename(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('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 'color_class' in line:
|
||||||
|
continue
|
||||||
|
elif 'stream_dark' in line:
|
||||||
|
continue
|
||||||
|
elif fn == 'signup.js' and 'class_to_add' in line:
|
||||||
|
html_classes = ['error', 'success']
|
||||||
|
elif fn == 'ui.js' and 'status_classes' in line:
|
||||||
|
html_classes = ['alert']
|
||||||
|
|
||||||
|
if not html_classes:
|
||||||
|
raise_error(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(fn, i, line)
|
||||||
|
tups.append((fn, html_class))
|
||||||
|
module_classes.add(html_class)
|
||||||
|
encountered.add(html_class)
|
||||||
|
return tups
|
||||||
@@ -401,6 +401,12 @@ try:
|
|||||||
result = subprocess.call(args)
|
result = subprocess.call(args)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@lint
|
||||||
|
def add_class():
|
||||||
|
# type: () -> int
|
||||||
|
result = subprocess.call(['tools/find-add-class'])
|
||||||
|
return result
|
||||||
|
|
||||||
@lint
|
@lint
|
||||||
def css():
|
def css():
|
||||||
# type: () -> int
|
# type: () -> int
|
||||||
|
|||||||
Reference in New Issue
Block a user