File: html_to_wrapper.py

package info (click to toggle)
chromium 120.0.6099.224-1~deb11u1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 6,112,112 kB
  • sloc: cpp: 32,907,025; ansic: 8,148,123; javascript: 3,679,536; python: 2,031,248; asm: 959,718; java: 804,675; xml: 617,256; sh: 111,417; objc: 100,835; perl: 88,443; cs: 53,032; makefile: 29,579; fortran: 24,137; php: 21,162; tcl: 21,147; sql: 20,809; ruby: 17,735; pascal: 12,864; yacc: 8,045; lisp: 3,388; lex: 1,323; ada: 727; awk: 329; jsp: 267; csh: 117; exp: 43; sed: 37
file content (166 lines) | stat: -rw-r--r-- 6,263 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
# Copyright 2022 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

# Genaretes a wrapper TS file around a source HTML file holding either
#  1) a Polymer element template or
#  2) an <iron-iconset-svg> definitions
#
# Note: The HTML file must be named either 'icons.html' or be suffixed with
# '_icons.html' for this tool to treat them as #2. Consequently, files holding
# Polymer element templates should not use such naming to be treated as #1.
#
# In case #1 the wrapper exports a getTemplate() function that can be used at
# runtime to import the template. This is useful for implementing Web Components
# using JS modules, where all the HTML needs to reside in a JS file (no more
# HTML imports).
#
# In case #2 the wrapper adds the <iron-iconset-svg> element to <head>, so that
# it can be used by <iron-icon> instances.

import argparse
import io
import shutil
import sys
import tempfile
from os import path, getcwd, makedirs

_HERE_PATH = path.dirname(__file__)
_SRC_PATH = path.normpath(path.join(_HERE_PATH, '..', '..'))
_CWD = getcwd()

sys.path.append(path.join(_SRC_PATH, 'third_party', 'node'))
import node

# Template for non-Polymer elements.
_NON_POLYMER_ELEMENT_TEMPLATE = """import {getTrustedHTML} from '%(scheme)s//resources/js/static_types.js';
export function getTemplate() {
  return getTrustedHTML`<!--_html_template_start_-->%(content)s<!--_html_template_end_-->`;
}"""

# Template for Polymer elements.
_ELEMENT_TEMPLATE = """import {html} from '%(scheme)s//resources/polymer/v3_0/polymer/polymer_bundled.min.js';
export function getTemplate() {
  return html`<!--_html_template_start_-->%(content)s<!--_html_template_end_-->`;
}"""

_ICONS_TEMPLATE = """import '%(scheme)s//resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
import {html} from '%(scheme)s//resources/polymer/v3_0/polymer/polymer_bundled.min.js';

const template = html`%(content)s`;
document.head.appendChild(template.content);
"""

# Token used to detect whether the underlying custom element is based on
# Polymer.
POLYMER_TOKEN = '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'


# Detects whether the element to be wrapped is using Polymer or native APIs.
def get_wrapper_element_template(template_type, definition_file):
  if template_type == 'native':
    return _NON_POLYMER_ELEMENT_TEMPLATE

  if template_type == 'polymer':
    return _ELEMENT_TEMPLATE

  if template_type == 'detect':
    with io.open(definition_file, encoding='utf-8', mode='r') as f:
      content = f.read()
      return _ELEMENT_TEMPLATE if POLYMER_TOKEN in content else \
          _NON_POLYMER_ELEMENT_TEMPLATE


def main(argv):
  parser = argparse.ArgumentParser()
  parser.add_argument('--in_folder', required=True)
  parser.add_argument('--out_folder', required=True)
  parser.add_argument('--in_files', required=True, nargs="*")
  parser.add_argument('--minify', action='store_true')
  parser.add_argument('--use_js', action='store_true')
  parser.add_argument('--template',
                      choices=['polymer', 'native', 'detect'],
                      default='polymer')
  parser.add_argument('--scheme',
                      choices=['chrome', 'relative'],
                      default='relative')

  args = parser.parse_args(argv)

  in_folder = path.normpath(path.join(_CWD, args.in_folder))
  out_folder = path.normpath(path.join(_CWD, args.out_folder))
  extension = '.js' if args.use_js else '.ts'

  results = []

  # The folder to be used to read the HTML files to be wrapped.
  wrapper_in_folder = in_folder

  if args.minify:
    # Minify the HTML files with html-minifier before generating the wrapper
    # .ts files.
    # Note: Passing all HTML files to html-minifier all at once because
    # passing them individually takes a lot longer.
    # Storing the output in a temporary folder, which is used further below when
    # creating the final wrapper files.
    tmp_out_dir = tempfile.mkdtemp(dir=out_folder)
    try:
      wrapper_in_folder = tmp_out_dir

      # Using the programmatic Node API to invoke html-minifier, because the
      # built-in command line API does not support explicitly specifying
      # multiple files to be processed, and only supports specifying an input
      # folder, which would lead to potentially processing unnecessary HTML
      # files that are not part of the build (stale), or handled by other
      # html_to_wrapper targets.
      node.RunNode(
          [path.join(_HERE_PATH, 'html_minifier.js'), in_folder, tmp_out_dir] +
          args.in_files)
    except RuntimeError as err:
      shutil.rmtree(tmp_out_dir)
      raise err

  out_files = []

  # Wrap the input files (minified or not) with an enclosing .ts file.
  for in_file in args.in_files:
    wrapper_in_file = path.join(wrapper_in_folder, in_file)

    with io.open(wrapper_in_file, encoding='utf-8', mode='r') as f:
      html_content = f.read()

      template = None
      filename = path.basename(in_file)
      if filename == 'icons.html' or filename.endswith('_icons.html'):
        assert args.template != 'native', (
            'Polymer icons files not supported with template="native"')
        template = _ICONS_TEMPLATE
      else:
        # Locate the file that holds the web component's definition. Assumed to
        # be in the same folder as input HTML template file.
        definition_file = path.splitext(path.join(in_folder,
                                                  in_file))[0] + extension
        template = get_wrapper_element_template(args.template, definition_file)

      wrapper = template % {
          'content': html_content,
          'scheme': 'chrome:' if args.scheme == 'chrome' else '',
      }

      out_folder_for_file = path.join(out_folder, path.dirname(in_file))
      makedirs(out_folder_for_file, exist_ok=True)
      out_file = path.join(out_folder, in_file) + extension
      out_files.append(out_file)
      with io.open(out_file, mode='wb') as f:
        f.write(wrapper.encode('utf-8'))

  if args.minify:
    # Delete the temporary folder that was holding minified HTML files, no
    # longer needed.
    shutil.rmtree(tmp_out_dir)

  return


if __name__ == '__main__':
  main(sys.argv[1:])