| # Copyright 2014 The Chromium Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| import os |
| import re |
| |
| from tvcm import module |
| from tvcm import js_utils |
| from tvcm import parse_html_deps |
| from tvcm import style_sheet |
| |
| |
| def IsHTMLResourceTheModuleGivenConflictingResourceNames( |
| js_resource, html_resource): # pylint: disable=unused-argument |
| return 'polymer-element' in html_resource.contents |
| |
| |
| class HTMLModule(module.Module): |
| |
| @property |
| def _module_dir_name(self): |
| return os.path.dirname(self.resource.absolute_path) |
| |
| def Parse(self): |
| try: |
| parser_results = parse_html_deps.HTMLModuleParser().Parse(self.contents) |
| except Exception, ex: |
| raise Exception('While parsing %s: %s' % (self.name, str(ex))) |
| |
| self.dependency_metadata = Parse(self.loader, |
| self.name, self._module_dir_name, |
| self.isComponent(), |
| parser_results) |
| self._parser_results = parser_results |
| |
| def Load(self): |
| super(HTMLModule, self).Load() |
| |
| reachable_names = set([m.name |
| for m in self.all_dependent_modules_recursive]) |
| if 'tr.exportTo' in self.contents: |
| if 'base.base' not in reachable_names: |
| raise Exception('%s: Does not have a dependency on base' % |
| os.path.relpath(self.resource.absolute_path)) |
| |
| def GetTVCMDepsModuleType(self): |
| return 'tvcm.HTML_MODULE_TYPE' |
| |
| def AppendJSContentsToFile(self, |
| f, |
| use_include_tags_for_scripts, |
| dir_for_include_tag_root): |
| super(HTMLModule, self).AppendJSContentsToFile(f, |
| use_include_tags_for_scripts, |
| dir_for_include_tag_root) |
| for inline_script in self._parser_results.inline_scripts: |
| if not HasPolymerCall(inline_script.stripped_contents): |
| js = inline_script.contents |
| else: |
| js = GetInlineScriptContentWithPolymerizingApplied(inline_script) |
| |
| js = js_utils.EscapeJSIfNeeded(js) |
| |
| f.write(js) |
| f.write('\n') |
| |
| def AppendHTMLContentsToFile(self, f, ctl, minify=False): |
| super(HTMLModule, self).AppendHTMLContentsToFile(f, ctl) |
| |
| ctl.current_module = self |
| try: |
| for piece in self._parser_results.YieldHTMLInPieces(ctl, minify=minify): |
| f.write(piece) |
| finally: |
| ctl.current_module = None |
| |
| def HRefToResource(self, href, tag_for_err_msg): |
| return _HRefToResource(self.loader, self.name, self._module_dir_name, |
| href, tag_for_err_msg) |
| |
| def AppendDirectlyDependentFilenamesTo( |
| self, dependent_filenames, include_raw_scripts=True): |
| super(HTMLModule, self).AppendDirectlyDependentFilenamesTo( |
| dependent_filenames, include_raw_scripts) |
| for contents in self._parser_results.inline_stylesheets: |
| module_dirname = os.path.dirname(self.resource.absolute_path) |
| ss = style_sheet.ParsedStyleSheet( |
| self.loader, module_dirname, contents) |
| ss.AppendDirectlyDependentFilenamesTo(dependent_filenames) |
| |
| |
| def GetInlineScriptContentWithPolymerizingApplied(inline_script): |
| polymer_element_name = GetPolymerElementNameFromOpenTags( |
| inline_script.open_tags) |
| if polymer_element_name is None: |
| raise module.DepsException( |
| 'Tagless Polymer() call must be made inside a <polymer-element> tag') |
| |
| return UpdatePolymerCallsGivenElementName( |
| inline_script.stripped_contents, polymer_element_name) |
| |
| |
| def GetPolymerElementNameFromOpenTags(open_tags): |
| found_tag = None |
| for tag in reversed(open_tags): |
| if tag.tag == 'polymer-element': |
| found_tag = tag |
| break |
| |
| if not found_tag: |
| return None |
| |
| for attr in found_tag.attrs: |
| if attr[0] == 'name': |
| return attr[1] |
| |
| return None |
| |
| _POLYMER_RE_1 = 'Polymer(\s*?)\((\s*?)\{' |
| _POLYMER_RE_2 = 'Polymer(\s*?)\((\s*?)\)' |
| |
| |
| def HasPolymerCall(js): |
| if re.search(_POLYMER_RE_1, js) is not None: |
| return True |
| if re.search(_POLYMER_RE_2, js) is not None: |
| return True |
| return False |
| |
| |
| def UpdatePolymerCallsGivenElementName(js, polymer_element_name): |
| if re.search(_POLYMER_RE_1, js) is not None: |
| return re.sub(_POLYMER_RE_1, |
| 'Polymer\g<1>(\g<2>\'%s\', {' % polymer_element_name, |
| js, 0, re.DOTALL) |
| if re.search(_POLYMER_RE_2, js) is not None: |
| return re.sub(_POLYMER_RE_2, |
| 'Polymer\g<1>(\g<2>\'%s\')' % polymer_element_name, |
| js, 0, re.DOTALL) |
| assert False, 'This should never be reached' |
| |
| |
| def _HRefToResource( |
| loader, module_name, module_dir_name, href, tag_for_err_msg): |
| if href[0] == '/': |
| resource = loader.FindResourceGivenRelativePath( |
| os.path.normpath(href[1:])) |
| else: |
| abspath = os.path.normpath(os.path.join(module_dir_name, |
| os.path.normpath(href))) |
| resource = loader.FindResourceGivenAbsolutePath(abspath) |
| |
| if not resource: |
| raise module.DepsException( |
| 'In %s, the %s cannot be loaded because ' |
| 'it is not in the search path' % (module_name, tag_for_err_msg)) |
| try: |
| resource.contents |
| except: |
| raise module.DepsException('In %s, %s points at a nonexistent file ' % ( |
| module_name, tag_for_err_msg)) |
| return resource |
| |
| |
| def Parse(loader, module_name, module_dir_name, is_component, parser_results): |
| res = module.ModuleDependencyMetadata() |
| if is_component: |
| return res |
| |
| if parser_results.has_decl is False: |
| raise Exception('%s must have <!DOCTYPE html>' % module_name) |
| |
| # External script references.. |
| for href in parser_results.scripts_external: |
| resource = _HRefToResource(loader, module_name, module_dir_name, |
| href, |
| tag_for_err_msg='<script src="%s">' % href) |
| res.dependent_raw_script_relative_paths.append( |
| resource.unix_style_relative_path) |
| |
| # External imports. Mostly the same as <script>, but we know its a module. |
| for href in parser_results.imports: |
| if not href.endswith('.html'): |
| raise Exception( |
| 'In %s, the <link rel="import" href="%s"> must point at a ' |
| 'file with an html suffix' % (module_name, href)) |
| |
| resource = _HRefToResource( |
| loader, module_name, module_dir_name, href, |
| tag_for_err_msg='<link rel="import" href="%s">' % href) |
| res.dependent_module_names.append(resource.name) |
| |
| # Validate the in-line scripts. |
| for inline_script in parser_results.inline_scripts: |
| stripped_text = inline_script.stripped_contents |
| try: |
| js_utils.ValidateUsesStrictMode('_', stripped_text) |
| except: |
| raise Exception('%s has an inline script tag that is missing ' |
| 'a \'use strict\' directive.' % module_name) |
| |
| # Style sheets |
| for href in parser_results.stylesheets: |
| resource = _HRefToResource( |
| loader, module_name, module_dir_name, href, |
| tag_for_err_msg='<link rel="stylesheet" href="%s">' % href) |
| res.style_sheet_names.append(resource.name) |
| |
| return res |