1# Copyright 2014 The Chromium Authors. All rights reserved. 2# Use of this source code is governed by a BSD-style license that can be 3# found in the LICENSE file. 4 5import os 6import re 7 8from py_vulcanize import js_utils 9from py_vulcanize import module 10from py_vulcanize import parse_html_deps 11from py_vulcanize import style_sheet 12 13 14def IsHTMLResourceTheModuleGivenConflictingResourceNames( 15 js_resource, html_resource): # pylint: disable=unused-argument 16 return 'polymer-element' in html_resource.contents 17 18 19class HTMLModule(module.Module): 20 21 @property 22 def _module_dir_name(self): 23 return os.path.dirname(self.resource.absolute_path) 24 25 def Parse(self): 26 try: 27 parser_results = parse_html_deps.HTMLModuleParser().Parse(self.contents) 28 except Exception as ex: 29 raise Exception('While parsing %s: %s' % (self.name, str(ex))) 30 31 self.dependency_metadata = Parse(self.loader, 32 self.name, 33 self._module_dir_name, 34 self.IsThirdPartyComponent(), 35 parser_results) 36 self._parser_results = parser_results 37 38 def Load(self): 39 super(HTMLModule, self).Load() 40 41 reachable_names = set([m.name 42 for m in self.all_dependent_modules_recursive]) 43 if 'tr.exportTo' in self.contents: 44 if 'tracing.base.base' not in reachable_names: 45 raise Exception('%s: Does not have a dependency on base' % 46 os.path.relpath(self.resource.absolute_path)) 47 48 def GetTVCMDepsModuleType(self): 49 return 'py_vulcanize.HTML_MODULE_TYPE' 50 51 def AppendJSContentsToFile(self, 52 f, 53 use_include_tags_for_scripts, 54 dir_for_include_tag_root): 55 super(HTMLModule, self).AppendJSContentsToFile(f, 56 use_include_tags_for_scripts, 57 dir_for_include_tag_root) 58 for inline_script in self._parser_results.inline_scripts: 59 if not HasPolymerCall(inline_script.stripped_contents): 60 js = inline_script.contents 61 else: 62 js = GetInlineScriptContentWithPolymerizingApplied(inline_script) 63 64 js = js_utils.EscapeJSIfNeeded(js) 65 66 f.write(js) 67 f.write('\n') 68 69 def AppendHTMLContentsToFile(self, f, ctl, minify=False): 70 super(HTMLModule, self).AppendHTMLContentsToFile(f, ctl) 71 72 ctl.current_module = self 73 try: 74 for piece in self._parser_results.YieldHTMLInPieces(ctl, minify=minify): 75 f.write(piece) 76 finally: 77 ctl.current_module = None 78 79 def HRefToResource(self, href, tag_for_err_msg): 80 return _HRefToResource(self.loader, self.name, self._module_dir_name, 81 href, tag_for_err_msg) 82 83 def AppendDirectlyDependentFilenamesTo( 84 self, dependent_filenames, include_raw_scripts=True): 85 super(HTMLModule, self).AppendDirectlyDependentFilenamesTo( 86 dependent_filenames, include_raw_scripts) 87 for contents in self._parser_results.inline_stylesheets: 88 module_dirname = os.path.dirname(self.resource.absolute_path) 89 ss = style_sheet.ParsedStyleSheet( 90 self.loader, module_dirname, contents) 91 ss.AppendDirectlyDependentFilenamesTo(dependent_filenames) 92 93 94def GetInlineScriptContentWithPolymerizingApplied(inline_script): 95 polymer_element_name = GetPolymerElementNameFromOpenTags( 96 inline_script.open_tags) 97 if polymer_element_name is None: 98 raise module.DepsException( 99 'Tagless Polymer() call must be made inside a <polymer-element> tag') 100 101 return UpdatePolymerCallsGivenElementName( 102 inline_script.stripped_contents, polymer_element_name) 103 104 105def GetPolymerElementNameFromOpenTags(open_tags): 106 found_tag = None 107 for tag in reversed(open_tags): 108 if tag.tag == 'polymer-element': 109 found_tag = tag 110 break 111 112 if not found_tag: 113 return None 114 115 return found_tag.attrs.get('name', None) 116 117_POLYMER_RE_1 = 'Polymer(\s*?)\((\s*?)\{' 118_POLYMER_RE_2 = 'Polymer(\s*?)\((\s*?)\)' 119 120 121def HasPolymerCall(js): 122 if re.search(_POLYMER_RE_1, js) is not None: 123 return True 124 if re.search(_POLYMER_RE_2, js) is not None: 125 return True 126 return False 127 128 129def UpdatePolymerCallsGivenElementName(js, polymer_element_name): 130 if re.search(_POLYMER_RE_1, js) is not None: 131 return re.sub(_POLYMER_RE_1, 132 'Polymer\g<1>(\g<2>\'%s\', {' % polymer_element_name, 133 js, 0, re.DOTALL) 134 if re.search(_POLYMER_RE_2, js) is not None: 135 return re.sub(_POLYMER_RE_2, 136 'Polymer\g<1>(\g<2>\'%s\')' % polymer_element_name, 137 js, 0, re.DOTALL) 138 assert False, 'This should never be reached' 139 140 141def _HRefToResource( 142 loader, module_name, module_dir_name, href, tag_for_err_msg): 143 if href[0] == '/': 144 resource = loader.FindResourceGivenRelativePath( 145 os.path.normpath(href[1:])) 146 else: 147 abspath = os.path.normpath(os.path.join(module_dir_name, 148 os.path.normpath(href))) 149 resource = loader.FindResourceGivenAbsolutePath(abspath) 150 151 if not resource: 152 raise module.DepsException( 153 'In %s, the %s cannot be loaded because ' 154 'it is not in the search path' % (module_name, tag_for_err_msg)) 155 try: 156 resource.contents 157 except: 158 raise module.DepsException('In %s, %s points at a nonexistent file ' % ( 159 module_name, tag_for_err_msg)) 160 return resource 161 162 163def Parse(loader, module_name, module_dir_name, is_component, parser_results): 164 res = module.ModuleDependencyMetadata() 165 if is_component: 166 return res 167 168 # External script references. 169 for href in parser_results.scripts_external: 170 resource = _HRefToResource(loader, module_name, module_dir_name, 171 href, 172 tag_for_err_msg='<script src="%s">' % href) 173 res.dependent_raw_script_relative_paths.append( 174 resource.unix_style_relative_path) 175 176 # External imports. Mostly the same as <script>, but we know its a module. 177 for href in parser_results.imports: 178 if not href.endswith('.html'): 179 raise Exception( 180 'In %s, the <link rel="import" href="%s"> must point at a ' 181 'file with an html suffix' % (module_name, href)) 182 183 resource = _HRefToResource( 184 loader, module_name, module_dir_name, href, 185 tag_for_err_msg='<link rel="import" href="%s">' % href) 186 res.dependent_module_names.append(resource.name) 187 188 # Style sheets. 189 for href in parser_results.stylesheets: 190 resource = _HRefToResource( 191 loader, module_name, module_dir_name, href, 192 tag_for_err_msg='<link rel="stylesheet" href="%s">' % href) 193 res.style_sheet_names.append(resource.name) 194 195 return res 196