polymer.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652
  1. # Copyright 2019 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. # Generates Polymer3 UI elements (using JS modules) from existing Polymer2
  5. # elements (using HTML imports). This is useful for avoiding code duplication
  6. # while Polymer2 to Polymer3 migration is in progress.
  7. #
  8. # Variables:
  9. # html_file:
  10. # The input Polymer2 HTML file to be processed.
  11. #
  12. # js_file:
  13. # The input Polymer2 JS file to be processed, or the name of the output JS
  14. # file when no input JS file exists (see |html_type| below).
  15. #
  16. # in_folder:
  17. # The folder where |html_file| and |js_file| (when it exists) reside.
  18. #
  19. # out_folder:
  20. # The output folder for the generated Polymer JS file.
  21. #
  22. # html_type:
  23. # Specifies the type of the |html_file| such that the script knows how to
  24. # process the |html_file|. Available values are:
  25. # dom-module: A file holding a <dom-module> for a UI element (this is
  26. # the majority case). Note: having multiple <dom-module>s
  27. # within a single HTML file is not currently supported
  28. # style-module: A file holding a shared style <dom-module>
  29. # (no corresponding Polymer2 JS file exists)
  30. # custom-style: A file holding a <custom-style> (usually a *_vars_css.html
  31. # file, no corresponding Polymer2 JS file exists)
  32. # iron-iconset: A file holding one or more <iron-iconset-svg> instances
  33. # (no corresponding Polymer2 JS file exists)
  34. # v3-ready: A file holding HTML that is already written for Polymer3. A
  35. # Polymer3 JS file already exists for such cases. In this mode
  36. # HTML content is simply pasted within the JS file. This mode
  37. # will be the only supported mode after migration finishes.
  38. #
  39. # namespace_rewrites:
  40. # A list of string replacements for replacing global namespaced references
  41. # with explicitly imported dependencies in the generated JS module.
  42. # For example "cr.foo.Bar|Bar" will replace all occurrences of "cr.foo.Bar"
  43. # with "Bar".
  44. #
  45. # auto_imports:
  46. # A list of of auto-imports, to inform the script on which variables to
  47. # import from a JS module. For example "ui/webui/foo/bar/baz.html|Foo,Bar"
  48. # will result in something like "import {Foo, Bar} from ...;" when
  49. # encountering any dependency to that file.
  50. import argparse
  51. import io
  52. import os
  53. import re
  54. import sys
  55. from collections import OrderedDict
  56. _CWD = os.getcwd()
  57. _HERE_PATH = os.path.dirname(__file__)
  58. _ROOT = os.path.normpath(os.path.join(_HERE_PATH, '..', '..'))
  59. POLYMER_V1_DIR = 'third_party/polymer/v1_0/components-chromium/'
  60. POLYMER_V3_DIR = 'third_party/polymer/v3_0/components-chromium/'
  61. # Rewrite rules for replacing global namespace references like "cr.ui.Foo", to
  62. # "Foo" within a generated JS module. Populated from command line arguments.
  63. _namespace_rewrites = {}
  64. # Auto-imports map, populated from command line arguments. Specifies which
  65. # variables to import from a given dependency. For example this is used to
  66. # import |FocusOutlineManager| whenever a dependency to
  67. # ui/webui/resources/html/cr/ui/focus_outline_manager.html is encountered.
  68. _auto_imports = {}
  69. # Populated from command line arguments. Specifies a list of HTML imports to
  70. # ignore when converting HTML imports to JS modules.
  71. _ignore_imports = []
  72. _migrated_imports = []
  73. # Populated from command line arguments. Specifies whether "chrome://" URLs
  74. # should be preserved, or whether they should be converted to scheme-relative
  75. # URLs "//" (default behavior).
  76. _preserve_url_scheme = False
  77. # Use an OrderedDict, since the order these redirects are applied matters.
  78. _chrome_redirects = OrderedDict([
  79. ('//resources/polymer/v1_0/', POLYMER_V1_DIR),
  80. ('//resources/', 'ui/webui/resources/'),
  81. ])
  82. _chrome_reverse_redirects = {
  83. POLYMER_V3_DIR: '//resources/polymer/v3_0/',
  84. 'ui/webui/resources/': '//resources/',
  85. }
  86. # Helper class for converting dependencies expressed in HTML imports, to JS
  87. # imports. |to_js_import()| is the only public method exposed by this class.
  88. # Internally an HTML import path is
  89. #
  90. # 1) normalized, meaning converted from a chrome or scheme-relative or relative
  91. # URL to to an absolute path starting at the repo's root
  92. # 2) converted to an equivalent JS normalized path
  93. # 3) de-normalized, meaning converted back to a scheme or scheme-relative or
  94. # relative URL
  95. # 4) converted to a JS import statement
  96. class Dependency:
  97. def __init__(self, src, dst):
  98. self.html_file = src
  99. self.html_path = dst
  100. if self.html_path.startswith('chrome://'):
  101. self.input_format = 'scheme'
  102. self.input_scheme = 'chrome'
  103. elif self.html_path.startswith('chrome-extension://'):
  104. self.input_format = 'scheme'
  105. self.input_scheme = 'chrome-extension'
  106. elif self.html_path.startswith('//'):
  107. self.input_format = 'scheme-relative'
  108. else:
  109. self.input_format = 'relative'
  110. self.output_format = self.input_format
  111. self.html_path_normalized = self._to_html_normalized()
  112. self.js_path_normalized = self._to_js_normalized()
  113. self.js_path = self._to_js()
  114. def _to_html_normalized(self):
  115. if self.input_format == 'scheme' or self.input_format == 'scheme-relative':
  116. self.html_path_normalized = self.html_path
  117. if self.input_format == 'scheme':
  118. # Strip the URL scheme.
  119. colon_index = self.html_path_normalized.find(':')
  120. self.html_path_normalized = self.html_path_normalized[colon_index + 1:]
  121. for r in _chrome_redirects:
  122. if self.html_path_normalized.startswith(r):
  123. self.html_path_normalized = (self.html_path_normalized.replace(
  124. r, _chrome_redirects[r]))
  125. break
  126. return self.html_path_normalized
  127. input_dir = os.path.relpath(os.path.dirname(self.html_file), _ROOT)
  128. return os.path.normpath(
  129. os.path.join(input_dir, self.html_path)).replace("\\", "/")
  130. def _to_js_normalized(self):
  131. if re.match(POLYMER_V1_DIR, self.html_path_normalized):
  132. return (self.html_path_normalized
  133. .replace(POLYMER_V1_DIR, POLYMER_V3_DIR)
  134. .replace(r'.html', '.js'))
  135. if self.html_path_normalized == 'ui/webui/resources/html/polymer.html':
  136. if self.output_format == 'relative':
  137. self.output_format = 'scheme'
  138. self.input_scheme = 'chrome'
  139. return POLYMER_V3_DIR + 'polymer/polymer_bundled.min.js'
  140. extension = ('.js'
  141. if self.html_path_normalized in _migrated_imports else '.m.js')
  142. if re.match(r'ui/webui/resources/html/', self.html_path_normalized):
  143. return (self.html_path_normalized
  144. .replace(r'ui/webui/resources/html/', 'ui/webui/resources/js/')
  145. .replace(r'.html', extension))
  146. return self.html_path_normalized.replace(r'.html', extension)
  147. def _to_js(self):
  148. js_path = self.js_path_normalized
  149. if self.output_format == 'scheme' or self.output_format == 'scheme-relative':
  150. for r in _chrome_reverse_redirects:
  151. if self.js_path_normalized.startswith(r):
  152. js_path = self.js_path_normalized.replace(
  153. r, _chrome_reverse_redirects[r])
  154. break
  155. # Restore the original scheme if |preserve_url_scheme| is enabled.
  156. if _preserve_url_scheme and self.output_format == 'scheme':
  157. js_path = self.input_scheme + ":" + js_path
  158. return js_path
  159. assert self.output_format == 'relative'
  160. input_dir = os.path.relpath(os.path.dirname(self.html_file), _ROOT)
  161. relpath = os.path.relpath(
  162. self.js_path_normalized, input_dir).replace("\\", "/")
  163. # Prepend "./" if |relpath| refers to a relative subpath, that is not "../".
  164. # This prefix is required for JS Modules paths.
  165. if not relpath.startswith('.'):
  166. relpath = './' + relpath
  167. return relpath
  168. def to_js_import(self, auto_imports):
  169. if self.html_path_normalized in auto_imports:
  170. imports = auto_imports[self.html_path_normalized]
  171. return 'import {%s} from \'%s\';' % (', '.join(imports), self.js_path)
  172. return 'import \'%s\';' % self.js_path
  173. def _generate_js_imports(html_file, html_type):
  174. output = []
  175. imports_start_offset = -1
  176. imports_end_index = -1
  177. imports_found = False
  178. with io.open(html_file, encoding='utf-8', mode='r') as f:
  179. lines = f.readlines()
  180. for i, line in enumerate(lines):
  181. match = re.search(r'\s*<link rel="import" href="(.*)"', line)
  182. if match:
  183. if not imports_found:
  184. imports_found = True
  185. imports_start_offset = i
  186. # Include the previous line if it is an opening <if> tag.
  187. if (i > 0):
  188. previous_line = lines[i - 1]
  189. if re.search(r'^\s*<if', previous_line):
  190. imports_start_offset -= 1
  191. previous_line = '// ' + previous_line
  192. output.append(previous_line.rstrip('\n'))
  193. imports_end_index = i - imports_start_offset
  194. # Convert HTML import URL to equivalent JS import URL.
  195. dep = Dependency(html_file, match.group(1))
  196. auto_imports = _auto_imports
  197. # Override default polymer.html auto import for non dom-module cases.
  198. if html_type == 'iron-iconset':
  199. auto_imports = _auto_imports.copy()
  200. auto_imports["ui/webui/resources/html/polymer.html"] = ["html"]
  201. elif html_type == 'custom-style' or html_type == 'style-module':
  202. auto_imports = _auto_imports.copy()
  203. del auto_imports["ui/webui/resources/html/polymer.html"]
  204. js_import = dep.to_js_import(auto_imports)
  205. if dep.html_path_normalized in _ignore_imports:
  206. output.append('// ' + js_import)
  207. else:
  208. output.append(js_import)
  209. elif imports_found:
  210. if re.search(r'^\s*</?if', line):
  211. line = '// ' + line
  212. output.append(line.rstrip('\n'))
  213. if len(output) == 0:
  214. return output
  215. # Include the next line if it is a closing </if> tag.
  216. if re.search(r'^// \s*</if>', output[imports_end_index + 1]):
  217. imports_end_index += 1
  218. return output[0:imports_end_index + 1]
  219. def _extract_dom_module_id(html_file):
  220. with io.open(html_file, encoding='utf-8', mode='r') as f:
  221. contents = f.read()
  222. match = re.search(r'\s*<dom-module id="(.*)"', contents)
  223. assert match
  224. return match.group(1)
  225. def _add_template_markers(html_template):
  226. return '<!--_html_template_start_-->%s<!--_html_template_end_-->' % \
  227. html_template;
  228. def _extract_template(html_file, html_type):
  229. if html_type == 'v3-ready':
  230. with io.open(html_file, encoding='utf-8', mode='r') as f:
  231. template = f.read()
  232. return _add_template_markers('\n' + template)
  233. if html_type == 'dom-module':
  234. with io.open(html_file, encoding='utf-8', mode='r') as f:
  235. lines = f.readlines()
  236. start_line = -1
  237. end_line = -1
  238. for i, line in enumerate(lines):
  239. if re.match(r'\s*<dom-module ', line):
  240. assert start_line == -1
  241. assert end_line == -1
  242. assert re.match(r'\s*<template', lines[i + 1])
  243. start_line = i + 2;
  244. if re.match(r'\s*</dom-module>', line):
  245. assert start_line != -1
  246. assert end_line == -1
  247. assert re.match(r'\s*</template>', lines[i - 2])
  248. assert re.match(r'\s*<script ', lines[i - 1])
  249. end_line = i - 3;
  250. # Should not have an iron-iconset-svg in a dom-module file.
  251. assert not re.match(r'\s*<iron-iconset-svg ', line)
  252. # If an opening <dom-module> tag was found, check that a closing one was
  253. # found as well.
  254. if start_line != - 1:
  255. assert end_line != -1
  256. return _add_template_markers('\n' + ''.join(lines[start_line:end_line + 1]))
  257. if html_type == 'style-module':
  258. with io.open(html_file, encoding='utf-8', mode='r') as f:
  259. lines = f.readlines()
  260. start_line = -1
  261. end_line = -1
  262. for i, line in enumerate(lines):
  263. if re.match(r'\s*<dom-module ', line):
  264. assert start_line == -1
  265. assert end_line == -1
  266. assert re.match(r'\s*<template', lines[i + 1])
  267. start_line = i + 1;
  268. if re.match(r'\s*</dom-module>', line):
  269. assert start_line != -1
  270. assert end_line == -1
  271. assert re.match(r'\s*</template>', lines[i - 1])
  272. end_line = i - 1;
  273. return '\n' + ''.join(lines[start_line:end_line + 1])
  274. if html_type == 'iron-iconset':
  275. templates = []
  276. with io.open(html_file, encoding='utf-8', mode='r') as f:
  277. lines = f.readlines()
  278. start_line = -1
  279. end_line = -1
  280. for i, line in enumerate(lines):
  281. if re.match(r'\s*<iron-iconset-svg ', line):
  282. assert start_line == -1
  283. assert end_line == -1
  284. start_line = i;
  285. if re.match(r'\s*</iron-iconset-svg>', line):
  286. assert start_line != -1
  287. assert end_line == -1
  288. end_line = i
  289. templates.append(''.join(lines[start_line:end_line + 1]))
  290. # Reset indices.
  291. start_line = -1
  292. end_line = -1
  293. return '\n' + ''.join(templates)
  294. assert html_type == 'custom-style'
  295. with io.open(html_file, encoding='utf-8', mode='r') as f:
  296. lines = f.readlines()
  297. start_line = -1
  298. end_line = -1
  299. for i, line in enumerate(lines):
  300. if re.match(r'\s*<custom-style>', line):
  301. assert start_line == -1
  302. assert end_line == -1
  303. start_line = i;
  304. if re.match(r'\s*</custom-style>', line):
  305. assert start_line != -1
  306. assert end_line == -1
  307. end_line = i;
  308. return '\n' + ''.join(lines[start_line:end_line + 1])
  309. # Replace various global references with their non-namespaced version, for
  310. # example "cr.ui.Foo" becomes "Foo".
  311. def _rewrite_namespaces(string):
  312. for rewrite in _namespace_rewrites:
  313. string = string.replace(rewrite, _namespace_rewrites[rewrite])
  314. return string
  315. def process_v3_ready(js_file, html_file):
  316. # Extract HTML template and place in JS file.
  317. html_template = _extract_template(html_file, 'v3-ready')
  318. with io.open(js_file, encoding='utf-8') as f:
  319. lines = f.readlines()
  320. HTML_TEMPLATE_REGEX = '{__html_template__}'
  321. found = 0
  322. for i, line in enumerate(lines):
  323. if HTML_TEMPLATE_REGEX in line:
  324. found += 1
  325. line = line.replace(HTML_TEMPLATE_REGEX, html_template)
  326. lines[i] = line
  327. if found == 0:
  328. raise AssertionError('No HTML placeholder ' + HTML_TEMPLATE_REGEX +
  329. ' found in ' + js_file)
  330. if found > 1:
  331. raise AssertionError('Multiple HTML placeholders ' + HTML_TEMPLATE_REGEX +
  332. ' found in ' + js_file)
  333. out_filename = os.path.basename(js_file)
  334. return lines, out_filename
  335. def _process_dom_module(js_file, html_file):
  336. html_template = _extract_template(html_file, 'dom-module')
  337. js_imports = _generate_js_imports(html_file, 'dom-module')
  338. # Remove IFFE opening/closing lines.
  339. IIFE_OPENING = '(function() {\n'
  340. IIFE_OPENING_ARROW = '(() => {\n'
  341. IIFE_CLOSING = '})();'
  342. # Remove this line.
  343. CR_DEFINE_START_REGEX = r'cr.define\('
  344. # Ignore all lines after this comment, including the line it appears on.
  345. CR_DEFINE_END_REGEX = r'\s*// #cr_define_end'
  346. # Replace export annotations with 'export'.
  347. EXPORT_LINE_REGEX = '/* #export */'
  348. # Ignore lines with an ignore annotation.
  349. IGNORE_LINE_REGEX = '\s*/\* #ignore \*/(\S|\s)*'
  350. # Special syntax used for files using ES class syntax. (OOBE screens)
  351. JS_IMPORTS_PLACEHOLDER_REGEX = '/* #js_imports_placeholder */';
  352. HTML_TEMPLATE_PLACEHOLDER_REGEX = '/* #html_template_placeholder */';
  353. with io.open(js_file, encoding='utf-8') as f:
  354. lines = f.readlines()
  355. imports_added = False
  356. html_content_added = False
  357. iife_found = False
  358. cr_define_found = False
  359. cr_define_end_line = -1
  360. for i, line in enumerate(lines):
  361. if not imports_added:
  362. if line.startswith(IIFE_OPENING) or line.startswith(IIFE_OPENING_ARROW):
  363. assert not cr_define_found, 'cr.define() and IFFE in the same file'
  364. # Replace the IIFE opening line with the JS imports.
  365. line = '\n'.join(js_imports) + '\n\n'
  366. imports_added = True
  367. iife_found = True
  368. elif re.match(CR_DEFINE_START_REGEX, line):
  369. assert not cr_define_found, 'Multiple cr.define()s are not supported'
  370. assert not iife_found, 'cr.define() and IFFE in the same file'
  371. line = '\n'.join(js_imports) + '\n\n'
  372. cr_define_found = True
  373. imports_added = True
  374. elif JS_IMPORTS_PLACEHOLDER_REGEX in line:
  375. line = line.replace(JS_IMPORTS_PLACEHOLDER_REGEX,
  376. '\n'.join(js_imports) + '\n')
  377. imports_added = True
  378. elif 'Polymer({\n' in line:
  379. # Place the JS imports right before the opening "Polymer({" line.
  380. line = '\n'.join(js_imports) + '\n\n' + line
  381. imports_added = True
  382. # Place the HTML content right after the opening "Polymer({" line if using
  383. # the Polymer() factory method, or replace HTML_TEMPLATE_PLACEHOLDER_REGEX
  384. # with the HTML content if the files is using ES6 class syntax.
  385. # Note: There is currently an assumption that only one Polymer() declaration,
  386. # or one class declaration exists per file.
  387. error_message = """Multiple Polymer() declarations found, or mixed ES6 class
  388. syntax with Polymer() declarations in the same file"""
  389. if 'Polymer({' in line:
  390. assert not html_content_added, error_message
  391. line = line.replace(
  392. r'Polymer({',
  393. 'Polymer({\n _template: html`%s`,' % html_template)
  394. html_content_added = True
  395. elif HTML_TEMPLATE_PLACEHOLDER_REGEX in line:
  396. assert not html_content_added, error_message
  397. line = line.replace(HTML_TEMPLATE_PLACEHOLDER_REGEX,
  398. 'static get template() {\n return html`%s`;\n }' % html_template)
  399. html_content_added = True
  400. line = line.replace(EXPORT_LINE_REGEX, 'export')
  401. if re.match(CR_DEFINE_END_REGEX, line):
  402. assert cr_define_found, 'Found cr_define_end without cr.define()'
  403. cr_define_end_line = i
  404. break
  405. if re.match(IGNORE_LINE_REGEX, line):
  406. line = ''
  407. line = _rewrite_namespaces(line)
  408. lines[i] = line
  409. if cr_define_found:
  410. assert cr_define_end_line != -1, 'No cr_define_end found'
  411. lines = lines[0:cr_define_end_line]
  412. if iife_found:
  413. last_line = lines[-1]
  414. assert last_line.startswith(IIFE_CLOSING), 'Could not detect IIFE closing'
  415. lines[-1] = ''
  416. # Use .m.js extension for the generated JS file, since both files need to be
  417. # served by a chrome:// URL side-by-side.
  418. out_filename = os.path.basename(js_file).replace('.js', '.m.js')
  419. return lines, out_filename
  420. def _process_style_module(js_file, html_file):
  421. html_template = _extract_template(html_file, 'style-module')
  422. js_imports = _generate_js_imports(html_file, 'style-module')
  423. style_id = _extract_dom_module_id(html_file)
  424. # Add |assetpath| attribute so that relative CSS url()s are resolved
  425. # correctly. Without this they are resolved with respect to the main HTML
  426. # documents location (unlike Polymer2). Note: This is assuming that only style
  427. # modules under ui/webui/resources/ are processed by polymer_modulizer(), for
  428. # example cr_icons_css.html.
  429. js_template = \
  430. """%(js_imports)s
  431. const template = document.createElement('template');
  432. template.innerHTML = `
  433. <dom-module id="%(style_id)s" assetpath="chrome://resources/">%(html_template)s</dom-module>
  434. `;
  435. document.body.appendChild(template.content.cloneNode(true));""" % {
  436. 'html_template': html_template,
  437. 'js_imports': '\n'.join(js_imports),
  438. 'style_id': style_id,
  439. }
  440. out_filename = os.path.basename(js_file)
  441. return js_template, out_filename
  442. def _process_custom_style(js_file, html_file):
  443. html_template = _extract_template(html_file, 'custom-style')
  444. js_imports = _generate_js_imports(html_file, 'custom-style')
  445. js_template = \
  446. """%(js_imports)s
  447. const $_documentContainer = document.createElement('template');
  448. $_documentContainer.innerHTML = `%(html_template)s`;
  449. document.head.appendChild($_documentContainer.content);""" % {
  450. 'js_imports': '\n'.join(js_imports),
  451. 'html_template': html_template,
  452. }
  453. out_filename = os.path.basename(js_file)
  454. return js_template, out_filename
  455. def _process_iron_iconset(js_file, html_file):
  456. html_template = _extract_template(html_file, 'iron-iconset')
  457. js_imports = _generate_js_imports(html_file, 'iron-iconset')
  458. js_template = \
  459. """%(js_imports)s
  460. const template = html`%(html_template)s`;
  461. document.head.appendChild(template.content);
  462. """ % {
  463. 'js_imports': '\n'.join(js_imports),
  464. 'html_template': html_template,
  465. }
  466. out_filename = os.path.basename(js_file)
  467. return js_template, out_filename
  468. def _resetGlobals():
  469. global _namespace_rewrites
  470. _namespace_rewrites = {}
  471. global _auto_imports
  472. _auto_imports = {}
  473. global _ignore_imports
  474. _ignore_imports = []
  475. global _migrated_imports
  476. _migrated_imports = []
  477. def main(argv):
  478. parser = argparse.ArgumentParser()
  479. parser.add_argument('--in_folder', required=True)
  480. parser.add_argument('--out_folder', required=True)
  481. parser.add_argument('--js_file', required=True)
  482. parser.add_argument('--html_file', required=True)
  483. parser.add_argument('--namespace_rewrites', required=False, nargs="*")
  484. parser.add_argument('--ignore_imports', required=False, nargs="*")
  485. parser.add_argument('--auto_imports', required=False, nargs="*")
  486. parser.add_argument('--migrated_imports', required=False, nargs="*")
  487. parser.add_argument('--preserve_url_scheme', action="store_true")
  488. parser.add_argument(
  489. '--html_type', choices=['dom-module', 'style-module', 'custom-style',
  490. 'iron-iconset', 'v3-ready'],
  491. required=True)
  492. args = parser.parse_args(argv)
  493. # Extract namespace rewrites from arguments.
  494. if args.namespace_rewrites:
  495. for r in args.namespace_rewrites:
  496. before, after = r.split('|')
  497. _namespace_rewrites[before] = after
  498. # Extract automatic imports from arguments.
  499. if args.auto_imports:
  500. global _auto_imports
  501. for entry in args.auto_imports:
  502. path, imports = entry.split('|')
  503. _auto_imports[path] = imports.split(',')
  504. # Extract ignored imports from arguments.
  505. if args.ignore_imports:
  506. assert args.html_type != 'v3-ready'
  507. global _ignore_imports
  508. _ignore_imports = args.ignore_imports
  509. # Extract migrated imports from arguments.
  510. if args.migrated_imports:
  511. assert args.html_type != 'v3-ready'
  512. global _migrated_imports
  513. _migrated_imports = args.migrated_imports
  514. # Extract |preserve_url_scheme| from arguments.
  515. global _preserve_url_scheme
  516. _preserve_url_scheme = args.preserve_url_scheme
  517. in_folder = os.path.normpath(os.path.join(_CWD, args.in_folder))
  518. out_folder = os.path.normpath(os.path.join(_CWD, args.out_folder))
  519. js_file = os.path.join(in_folder, args.js_file)
  520. html_file = os.path.join(in_folder, args.html_file)
  521. result = ()
  522. if args.html_type == 'dom-module':
  523. result = _process_dom_module(js_file, html_file)
  524. if args.html_type == 'style-module':
  525. result = _process_style_module(js_file, html_file)
  526. elif args.html_type == 'custom-style':
  527. result = _process_custom_style(js_file, html_file)
  528. elif args.html_type == 'iron-iconset':
  529. result = _process_iron_iconset(js_file, html_file)
  530. elif args.html_type == 'v3-ready':
  531. result = process_v3_ready(js_file, html_file)
  532. # Reconstruct file.
  533. # Specify the newline character so that the exact same file is generated
  534. # across platforms.
  535. with io.open(os.path.join(out_folder, result[1]), mode='wb') as f:
  536. for l in result[0]:
  537. f.write(l.encode('utf-8'))
  538. # Reset global variables so that main() can be invoked multiple times during
  539. # testing without leaking state from one test to the next.
  540. _resetGlobals()
  541. return
  542. if __name__ == '__main__':
  543. main(sys.argv[1:])