#!/usr/bin/env python from __future__ import absolute_import from __future__ import print_function from lib.template_parser import validate import argparse 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 check_our_files(): # type: () -> None parser = argparse.ArgumentParser() parser.add_argument('-m', '--modified', action='store_true', default=False, help='only check modified files') args = parser.parse_args() by_lang = cast( Dict[str, List[str]], lister.list_files( modified_only=args.modified, ftypes=['handlebars', 'html'], group_by_ftype=True)) check_handlebar_templates(by_lang['handlebars'], args.modified) check_html_templates(by_lang['html'], args.modified) def check_html_templates(templates, modified_only): # type: (Iterable[str], bool) -> None # Our files with .html extensions are usually for Django, but we also # have a few static .html files. # The file base.html has a bit of funny HTML that we can't parse here yet. # # We also have .html files that we vendored from Casper. # The casperjs files use HTML5 (whereas Zulip prefers XHTML), and # there are also cases where Casper deliberately uses invalid HTML, # so we exclude them from our linter. templates = filter( lambda fn: ('base.html' not in fn) and ('casperjs' not in fn), templates) templates = sorted(list(templates)) if not modified_only: assert len(templates) >= 10 # sanity check that we are actually doing work for fn in templates: # Many of our Django templates have strange indentation. The # indentation errors are often harmless, even stylistically # harmless, but they tend to be in files that might be old # and might eventually require more scrutiny for things like # localization. See github #1236. bad_files = [ 'static/html/5xx.html', 'templates/500.html', 'templates/confirmation/confirm.html', 'templates/corporate/mit.html', 'templates/corporate/privacy.html', 'templates/corporate/terms-enterprise.html', 'templates/corporate/zephyr-mirror.html', 'templates/corporate/zephyr.html', 'templates/zerver/accounts_home.html', 'templates/zerver/accounts_send_confirm.html', 'templates/zerver/api.html', 'templates/zerver/api_endpoints.html', 'templates/zerver/apps.html', 'templates/zerver/create_realm.html', 'templates/zerver/emails/followup/day1.html', 'templates/zerver/emails/followup/day2.html', 'templates/zerver/features.html', 'templates/zerver/hello.html', 'templates/zerver/home.html', 'templates/zerver/integrations.html', 'templates/zerver/invite_user.html', 'templates/zerver/left-sidebar.html', 'templates/zerver/login.html', 'templates/zerver/markdown_help.html', 'templates/zerver/register.html', 'templates/zerver/right-sidebar.html', 'templates/zerver/search_operators.html', ] validate(fn=fn, check_indent=(fn not in bad_files)) def check_handlebar_templates(templates, modified_only): # type: (Iterable[str], bool) -> None # Check all our handlebars templates. templates = [fn for fn in templates if fn.endswith('.handlebars')] if not modified_only: assert len(templates) >= 10 # sanity check that we are actually doing work for fn in templates: validate(fn=fn, check_indent=True) if __name__ == '__main__': check_our_files()