mirror of https://github.com/zulip/zulip.git
linter: Add support for automatic checking for 4 space indents in CSS.
In this commit we modify our CSS parser not only to render the text from a given CSS tokens produced but also enforce 4 space indentation on it. Also we enforce some basic rules we would like our CSS to follow such as * Always have "\n" in between the starting of body({) and body itself and ending of the body and the closing of body(}). * Use 4 space indents while having but something within the block structure ( { .... } ). * Have single space after ',' in between multiple selectors. * Have only a single space in between selector and the starting of block structure ({ ... }) if block structure starts on same line as of selector. eg. body { body content here } Notice single space between 'body' and '{'. Fixes: #1659.
This commit is contained in:
parent
257187a239
commit
b3cbb13a79
|
@ -16,9 +16,9 @@ def validate(fn):
|
|||
text = open(fn).read()
|
||||
section_list = parse(text)
|
||||
if text != section_list.text():
|
||||
print('BOO! %s broken' % (fn,))
|
||||
open('foo.txt', 'w').write(section_list.text())
|
||||
os.system('diff %s foo.txt' % (fn,))
|
||||
print('%s seems to be broken:' % (fn,))
|
||||
open('/var/tmp/pretty_css.txt', 'w').write(section_list.text())
|
||||
os.system('diff %s /var/tmp/pretty_css.txt' % (fn,))
|
||||
sys.exit(1)
|
||||
|
||||
def check_our_files(filenames):
|
||||
|
|
|
@ -257,6 +257,99 @@ def parse_value(tokens, start, end):
|
|||
post_fluff=post_fluff,
|
||||
)
|
||||
|
||||
def handle_prefluff(pre_fluff, indent=False):
|
||||
# type: (str, bool) -> str
|
||||
pre_fluff_lines = pre_fluff.split('\n')
|
||||
formatted_pre_fluff_lines = []
|
||||
comment_indent = ''
|
||||
general_indent = ''
|
||||
if indent:
|
||||
general_indent = ' '
|
||||
for i, ln in enumerate(pre_fluff_lines):
|
||||
line_indent = ''
|
||||
if ln.strip() != '':
|
||||
if not i:
|
||||
line_indent = general_indent
|
||||
comment_indent = ' '
|
||||
else:
|
||||
if comment_indent:
|
||||
if ('*/' in ln or '*' in ln) and (ln.strip()[:2] in ('*/', '* ', '*')):
|
||||
line_indent = general_indent
|
||||
if '*/' in ln:
|
||||
comment_indent = ''
|
||||
else:
|
||||
line_indent = general_indent + comment_indent
|
||||
else:
|
||||
line_indent = general_indent
|
||||
comment_indent = ' '
|
||||
elif len(pre_fluff_lines) == 1 and indent and ln != '':
|
||||
line_indent = ' '
|
||||
formatted_pre_fluff_lines.append(line_indent + ln.strip())
|
||||
if formatted_pre_fluff_lines[-1] != '':
|
||||
if formatted_pre_fluff_lines[-1].strip() == '' and indent:
|
||||
formatted_pre_fluff_lines[-1] = ''
|
||||
formatted_pre_fluff_lines.append('')
|
||||
pre_fluff = '\n'.join(formatted_pre_fluff_lines)
|
||||
res = ''
|
||||
if indent:
|
||||
if '\n' in pre_fluff:
|
||||
res = pre_fluff + ' '
|
||||
elif pre_fluff == '':
|
||||
res = ' '
|
||||
else:
|
||||
res = pre_fluff.rstrip() + ' '
|
||||
else:
|
||||
res = pre_fluff
|
||||
|
||||
return res
|
||||
|
||||
def handle_postfluff(post_fluff, indent=False, space_after_first_line=False):
|
||||
# type: (str, bool, bool) -> str
|
||||
post_fluff_lines = post_fluff.split('\n')
|
||||
formatted_post_fluff_lines = []
|
||||
comment_indent = ''
|
||||
general_indent = ''
|
||||
if indent:
|
||||
general_indent = ' '
|
||||
for i, ln in enumerate(post_fluff_lines):
|
||||
line_indent = ''
|
||||
if ln.strip() != '':
|
||||
if i:
|
||||
if comment_indent:
|
||||
if ('*/' in ln or '*' in ln) and (ln.strip()[:2] in ('*/', '* ', '*')):
|
||||
line_indent = general_indent
|
||||
if '*/' in ln:
|
||||
comment_indent = ''
|
||||
else:
|
||||
line_indent = general_indent + comment_indent
|
||||
else:
|
||||
line_indent = general_indent
|
||||
comment_indent = ' '
|
||||
elif indent and not i and len(post_fluff_lines) > 2:
|
||||
formatted_post_fluff_lines.append('')
|
||||
line_indent = general_indent
|
||||
comment_indent = ' '
|
||||
elif space_after_first_line:
|
||||
line_indent = ' '
|
||||
if not i:
|
||||
comment_indent = ' '
|
||||
elif not i:
|
||||
comment_indent = ' '
|
||||
formatted_post_fluff_lines.append(line_indent + ln.strip())
|
||||
if len(formatted_post_fluff_lines) == 1 and not space_after_first_line:
|
||||
if formatted_post_fluff_lines[-1].strip() == '':
|
||||
if formatted_post_fluff_lines[-1] != '':
|
||||
formatted_post_fluff_lines[-1] = ' '
|
||||
else:
|
||||
formatted_post_fluff_lines.append('')
|
||||
elif formatted_post_fluff_lines[-1].strip() == '':
|
||||
formatted_post_fluff_lines[-1] = ''
|
||||
if len(formatted_post_fluff_lines) == 1 and indent:
|
||||
formatted_post_fluff_lines.append('')
|
||||
elif space_after_first_line:
|
||||
formatted_post_fluff_lines.append('')
|
||||
post_fluff = '\n'.join(formatted_post_fluff_lines)
|
||||
return post_fluff
|
||||
|
||||
#### Begin CSS classes here
|
||||
|
||||
|
@ -286,7 +379,14 @@ class CssNestedSection(object):
|
|||
res += self.pre_fluff
|
||||
res += self.selector_list.text()
|
||||
res += '{'
|
||||
res += self.section_list.text()
|
||||
section_list_lines = self.section_list.text().split('\n')
|
||||
formatted_section_list = []
|
||||
for ln in section_list_lines:
|
||||
if ln.strip() == '':
|
||||
formatted_section_list.append('')
|
||||
else:
|
||||
formatted_section_list.append(' ' + ln)
|
||||
res += '\n'.join(formatted_section_list)
|
||||
res += '}'
|
||||
res += self.post_fluff
|
||||
return res
|
||||
|
@ -303,10 +403,10 @@ class CssSection(object):
|
|||
def text(self):
|
||||
# type: () -> str
|
||||
res = ''
|
||||
res += self.pre_fluff
|
||||
res += handle_prefluff(self.pre_fluff)
|
||||
res += self.selector_list.text()
|
||||
res += self.declaration_block.text()
|
||||
res += self.post_fluff
|
||||
res += handle_postfluff(self.post_fluff, space_after_first_line=True)
|
||||
return res
|
||||
|
||||
class CssSelectorList(object):
|
||||
|
@ -317,7 +417,16 @@ class CssSelectorList(object):
|
|||
|
||||
def text(self):
|
||||
# type: () -> str
|
||||
res = ','.join(sel.text() for sel in self.selectors)
|
||||
res = ''
|
||||
for i, sel in enumerate(self.selectors):
|
||||
sel_list_render = sel.text()
|
||||
if i != 0 and sel_list_render[0] != '\n':
|
||||
res += ' '
|
||||
res += sel_list_render
|
||||
if i != len(self.selectors) - 1:
|
||||
res += ','
|
||||
if res[-1] != ' ' and res[-1] != '\n':
|
||||
res += ' '
|
||||
return res
|
||||
|
||||
class CssSelector(object):
|
||||
|
@ -331,9 +440,9 @@ class CssSelector(object):
|
|||
def text(self):
|
||||
# type: () -> str
|
||||
res = ''
|
||||
res += self.pre_fluff
|
||||
res += handle_prefluff(self.pre_fluff)
|
||||
res += ' '.join(level.s for level in self.levels)
|
||||
res += self.post_fluff
|
||||
res += handle_postfluff(self.post_fluff)
|
||||
return res
|
||||
|
||||
class CssDeclarationBlock(object):
|
||||
|
@ -363,7 +472,7 @@ class CssDeclaration(object):
|
|||
def text(self):
|
||||
# type: () -> str
|
||||
res = ''
|
||||
res += self.pre_fluff
|
||||
res += handle_prefluff(self.pre_fluff, True)
|
||||
res += self.css_property
|
||||
res += ':'
|
||||
value_text = self.css_value.text()
|
||||
|
@ -374,7 +483,7 @@ class CssDeclaration(object):
|
|||
res += ' '
|
||||
res += value_text.strip()
|
||||
res += ';'
|
||||
res += self.post_fluff
|
||||
res += handle_postfluff(self.post_fluff, True, True)
|
||||
return res
|
||||
|
||||
class CssValue(object):
|
||||
|
|
|
@ -11,6 +11,8 @@ try:
|
|||
CssParserException,
|
||||
CssSection,
|
||||
parse,
|
||||
handle_prefluff,
|
||||
handle_postfluff
|
||||
)
|
||||
except ImportError:
|
||||
print('ERROR!!! You need to run this via tools/test-tools.')
|
||||
|
@ -33,10 +35,10 @@ class ParserTestHappyPath(unittest.TestCase):
|
|||
}'''
|
||||
my_css = my_selector + ' ' + my_block
|
||||
res = parse(my_css)
|
||||
self.assertEqual(res.text(), my_css)
|
||||
self.assertEqual(res.text(), 'li.foo {\n color: red;\n}')
|
||||
section = cast(CssSection, res.sections[0])
|
||||
block = section.declaration_block
|
||||
self.assertEqual(block.text().strip(), my_block)
|
||||
self.assertEqual(block.text().strip(), '{\n color: red;\n}')
|
||||
declaration = block.declarations[0]
|
||||
self.assertEqual(declaration.css_property, 'color')
|
||||
self.assertEqual(declaration.css_value.text().strip(), 'red')
|
||||
|
@ -62,9 +64,7 @@ class ParserTestHappyPath(unittest.TestCase):
|
|||
p { color: red }
|
||||
'''
|
||||
|
||||
reformatted_css = '''
|
||||
p { color: red;}
|
||||
'''
|
||||
reformatted_css = '\np {\n color: red;\n}\n'
|
||||
|
||||
res = parse(my_css)
|
||||
|
||||
|
@ -126,7 +126,39 @@ class ParserTestHappyPath(unittest.TestCase):
|
|||
}'''
|
||||
res = parse(my_css)
|
||||
self.assertEqual(len(res.sections), 1)
|
||||
self.assertEqual(res.text(), my_css)
|
||||
self.assertEqual(res.text(), '\n @media (max-width: 300px) {\n h5 {\n margin: 0;\n }\n}')
|
||||
|
||||
def test_handle_prefluff(self):
|
||||
# type: () -> None
|
||||
PREFLUFF = ' \n '
|
||||
PREFLUFF1 = ' '
|
||||
PREFLUFF2 = ' /* some comment \nhere */'
|
||||
PREFLUFF3 = '\n /* some comment \nhere */'
|
||||
self.assertEqual(handle_prefluff(PREFLUFF), '\n')
|
||||
self.assertEqual(handle_prefluff(PREFLUFF, True), '\n ')
|
||||
self.assertEqual(handle_prefluff(PREFLUFF1), '')
|
||||
self.assertEqual(handle_prefluff(PREFLUFF1, True), '\n ')
|
||||
self.assertEqual(handle_prefluff(PREFLUFF2), '/* some comment\n here */\n')
|
||||
self.assertEqual(handle_prefluff(PREFLUFF3, True), '\n /* some comment\n here */\n ')
|
||||
|
||||
def test_handle_postfluff(self):
|
||||
# type: () -> None
|
||||
POSTFLUFF = '/* Comment Here */'
|
||||
POSTFLUFF1 = '/* Comment \nHere */'
|
||||
POSTFLUFF2 = ' '
|
||||
POSTFLUFF3 = '\n /* some comment \nhere */'
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF), '/* Comment Here */\n')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF, space_after_first_line=True), ' /* Comment Here */\n')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF, indent=True, space_after_first_line=True), ' /* Comment Here */\n')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF1), '/* Comment\n Here */')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF1, space_after_first_line=True), ' /* Comment\n Here */\n')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF1, indent=True, space_after_first_line=True), ' /* Comment\n Here */\n')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF2), '')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF2, space_after_first_line=True), '')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF2, indent=True, space_after_first_line=True), '\n')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF3), '\n/* some comment\n here */')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF3, space_after_first_line=True), '\n/* some comment\n here */\n')
|
||||
self.assertEqual(handle_postfluff(POSTFLUFF3, indent=True, space_after_first_line=True), '\n /* some comment\n here */\n')
|
||||
|
||||
class ParserTestSadPath(unittest.TestCase):
|
||||
'''
|
||||
|
|
Loading…
Reference in New Issue