summaryrefslogtreecommitdiff
path: root/chromium/third_party/devtools-frontend/src/scripts
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/devtools-frontend/src/scripts')
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/build/build_debug_applications.py77
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/build/build_release_applications.py30
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/build/code_generator_frontend.py25
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/build/copy_devtools_modules.py4
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/build/copy_to_gen.gni15
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/build/generate_protocol_externs.py84
-rwxr-xr-xchromium/third_party/devtools-frontend/src/scripts/build/generate_supported_css.py8
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/build/modular_build.py15
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/component_server/README.md13
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/component_server/server.js165
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/deps/ensure_symlink.py64
-rwxr-xr-xchromium/third_party/devtools-frontend/src/scripts/deps/manage_node_deps.py29
-rwxr-xr-xchromium/third_party/devtools-frontend/src/scripts/deps/roll_codemirror.py87
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/devtools_paths.py4
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/check_license_header.js15
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/es_modules_import.js13
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/hosted_mode/BUILD.gn9
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/hosted_mode/launch_chrome.js130
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/hosted_mode/server.js75
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/hosted_mode/start_chrome_and_server.js12
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/localization/check_localizability.js24
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/localization/check_localizable_resources.js2
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/localization/utils/check_localized_strings.js27
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/npm_test.js177
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/protocol_typescript/protocol_dts_generator.ts15
-rw-r--r--chromium/third_party/devtools-frontend/src/scripts/suggest_owners.js102
26 files changed, 586 insertions, 635 deletions
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/build_debug_applications.py b/chromium/third_party/devtools-frontend/src/scripts/build/build_debug_applications.py
deleted file mode 100644
index 825b6cbe85d..00000000000
--- a/chromium/third_party/devtools-frontend/src/scripts/build/build_debug_applications.py
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/usr/bin/env python
-# -*- coding: UTF-8 -*-
-#
-# Copyright 2016 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.
-"""
-Builds applications in debug mode:
-- Copies the module directories into their destinations.
-- Copies app.html as-is.
-"""
-
-from os import path
-from os.path import join
-import os
-import shutil
-import sys
-
-import modular_build
-
-
-def main(argv):
- try:
- input_path_flag_index = argv.index('--input_path')
- input_path = argv[input_path_flag_index + 1]
- output_path_flag_index = argv.index('--output_path')
- output_path = argv[output_path_flag_index + 1]
- build_stamp_index = argv.index('--build_stamp')
- build_stamp_path = argv[build_stamp_index + 1]
- except:
- print('Usage: %s app_1 app_2 ... app_N --input_path <input_path> --output_path <output_path>' % argv[0])
- raise
-
- symlink_dir_or_copy(input_path, output_path)
-
- with open(build_stamp_path, 'w') as file:
- file.write('stamp')
-
-
-def symlink_dir_or_copy(src, dest):
- if hasattr(os, 'symlink'):
- if path.exists(dest):
- if os.path.islink(dest):
- os.unlink(dest)
- else:
- shutil.rmtree(dest)
- os.symlink(join(os.getcwd(), src), dest)
- else:
- for filename in os.listdir(src):
- new_src = join(os.getcwd(), src, filename)
- if os.path.isdir(new_src):
- copy_dir(new_src, join(dest, filename))
- else:
- copy_file(new_src, join(dest, filename), safe=True)
-
-
-def copy_file(src, dest, safe=False):
- if safe and path.exists(dest):
- os.remove(dest)
- shutil.copy(src, dest)
-
-
-def copy_dir(src, dest):
- if path.exists(dest):
- shutil.rmtree(dest)
- for src_dir, dirs, files in os.walk(src):
- subpath = path.relpath(src_dir, src)
- dest_dir = path.normpath(join(dest, subpath))
- os.makedirs(dest_dir)
- for name in files:
- src_name = join(os.getcwd(), src_dir, name)
- dest_name = join(dest_dir, name)
- copy_file(src_name, dest_name)
-
-
-if __name__ == '__main__':
- sys.exit(main(sys.argv))
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/build_release_applications.py b/chromium/third_party/devtools-frontend/src/scripts/build/build_release_applications.py
index 9a128cc6aee..f74f92cd7dd 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/build/build_release_applications.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/build/build_release_applications.py
@@ -8,7 +8,6 @@
Builds applications in release mode:
- Concatenates autostart modules, application modules' module.json descriptors,
and the application loader into a single script.
-- Builds app.html referencing the application script.
"""
from cStringIO import StringIO
@@ -45,11 +44,8 @@ MODULE_LIST = [
for subfolder in os.listdir(FRONT_END_DIRECTORY)
if path.isdir(os.path.join(FRONT_END_DIRECTORY, subfolder))
]
-
-ROLLUP_ARGS = [
- '--no-treeshake', '--format', 'esm', '--context', 'self', '--external',
- ','.join([path.abspath(module) for module in MODULE_LIST])
-]
+EXTERNAL_MODULE_LIST = ','.join(
+ [path.abspath(module) for module in MODULE_LIST])
def main(argv):
@@ -91,7 +87,6 @@ def concatenated_module_filename(module_name, output_dir):
# Outputs:
-# <app_name>.html
# <app_name>.js
# <module_name>_module.js
class ReleaseBuilder(object):
@@ -121,9 +116,6 @@ class ReleaseBuilder(object):
return result
def build_app(self):
- if self.descriptors.has_html:
- html_entrypoint = self.app_file('html')
- write_file(join(self.output_dir, html_entrypoint), read_file(join(self.application_dir, html_entrypoint)))
self._build_app_script()
for module in filter(lambda desc: (not desc.get('type') or desc.get('type') == 'remote'),
self.descriptors.application.values()):
@@ -221,14 +213,22 @@ class ReleaseBuilder(object):
js_entrypoint = join(self.application_dir, module_name, module_name + '.js')
out = ''
if self.use_rollup:
- rollup_process = subprocess.Popen(
- [devtools_paths.node_path(), devtools_paths.rollup_path()] + ROLLUP_ARGS + ['--input', js_entrypoint],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE)
+ rollup_process = subprocess.Popen([
+ devtools_paths.node_path(),
+ devtools_paths.rollup_path(), '--config',
+ join(FRONT_END_DIRECTORY, 'rollup.config.js'), '--input',
+ js_entrypoint, '--external', EXTERNAL_MODULE_LIST
+ ],
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE)
out, error = rollup_process.communicate()
+ if rollup_process.returncode != 0:
+ print(error)
+ sys.exit(rollup_process.returncode)
else:
out = read_file(js_entrypoint)
- write_file(join(self.output_dir, module_name, module_name + '.js'), minify_js(out))
+ write_file(join(self.output_dir, module_name, module_name + '.js'),
+ minify_js(out))
legacyFileName = module_name + '-legacy.js'
if legacyFileName in modules:
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/code_generator_frontend.py b/chromium/third_party/devtools-frontend/src/scripts/build/code_generator_frontend.py
index 3d7d6d08812..502481fab57 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/build/code_generator_frontend.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/build/code_generator_frontend.py
@@ -159,13 +159,15 @@ class Templates:
return "/".join(components)
- file_header_ = ("""// Copyright (c) 2020 The Chromium Authors. All rights reserved.
+ file_header_ = (
+ """// Copyright (c) 2020 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.
-""" + "// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) + """
+""" + "// File is generated by %s\n\n" % get_this_script_path_(sys.argv[0]) +
+ """
/**
* @typedef {{
- * registerCommand: function(string, !Array.<!{name: string, type: string, optional: boolean}>, !Array.<string>, boolean):void,
+ * registerCommand: function(string, !Array.<!{name: string, type: string, optional: boolean}>, !Array.<string>):void,
* registerEnum: function(string, !Object<string, string>):void,
* registerEvent: function(string, !Array<string>):void,
* }}
@@ -220,6 +222,14 @@ class Generator:
if "commands" in json_domain:
for json_command in json_domain["commands"]:
+ if "parameters" in json_command:
+ for param in json_command["parameters"]:
+ if "enum" in param:
+ enum_name = "%s.%sRequest%s" % (
+ domain_name,
+ to_title_case(json_command["name"]),
+ to_title_case(param["name"]))
+ Generator.process_enum(param, enum_name)
Generator.process_command(json_command, domain_name)
Generator.backend_js_domain_initializer_list.append("\n")
@@ -277,14 +287,11 @@ class Generator:
backend_js_reply_param_list.append("\"%s\"" % json_return_name)
js_reply_list = "[%s]" % ", ".join(backend_js_reply_param_list)
- if "error" in json_command:
- has_error_data_param = "true"
- else:
- has_error_data_param = "false"
Generator.backend_js_domain_initializer_list.append(
- "inspectorBackend.registerCommand(\"%s.%s\", [%s], %s, %s);\n" %
- (domain_name, json_command_name, js_parameters_text, js_reply_list, has_error_data_param))
+ "inspectorBackend.registerCommand(\"%s.%s\", [%s], %s);\n" %
+ (domain_name, json_command_name, js_parameters_text,
+ js_reply_list))
Generator.go()
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/copy_devtools_modules.py b/chromium/third_party/devtools-frontend/src/scripts/build/copy_devtools_modules.py
index 4434e1a97d4..9ebb32940b3 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/build/copy_devtools_modules.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/build/copy_devtools_modules.py
@@ -36,8 +36,8 @@ def main(argv):
for file_name in devtools_modules:
file_content = read_file(join(input_path, file_name))
- minified = rjsmin.jsmin(file_content)
- write_file(join(output_path, relpath(file_name, 'front_end')), minified)
+ write_file(join(output_path, relpath(file_name, 'front_end')),
+ file_content)
if __name__ == '__main__':
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/copy_to_gen.gni b/chromium/third_party/devtools-frontend/src/scripts/build/copy_to_gen.gni
new file mode 100644
index 00000000000..61b37673251
--- /dev/null
+++ b/chromium/third_party/devtools-frontend/src/scripts/build/copy_to_gen.gni
@@ -0,0 +1,15 @@
+# Copyright 2019 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.
+
+template("copy_to_gen") {
+ copy(target_name) {
+ forward_variables_from(invoker,
+ [
+ "sources",
+ "visibility",
+ "deps",
+ ])
+ outputs = [ "{{source_gen_dir}}/{{source_file_part}}" ]
+ }
+}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/generate_protocol_externs.py b/chromium/third_party/devtools-frontend/src/scripts/build/generate_protocol_externs.py
index d579f64d552..a649fb6f325 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/build/generate_protocol_externs.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/build/generate_protocol_externs.py
@@ -84,13 +84,17 @@ def generate_enum(name, json):
return "\n/** @enum {string} */\n%s = {\n%s\n};\n" % (name, (",\n".join(enum_members)))
-def param_type(domain_name, param):
+def param_type(domain_name, param, command=None):
+ if "enum" in param and command:
+ return "Protocol.%s.%sRequest%s" % (domain_name,
+ to_title_case(command["name"]),
+ to_title_case(param_name(param)))
if "type" in param:
if param["type"] == "array":
items = param["items"]
return "!Array<%s>" % param_type(domain_name, items)
else:
- return type_traits[param["type"]]
+ return "Protocol.%s" % param["type"]
if "$ref" in param:
type_id = full_qualified_type_id(domain_name, param["$ref"])
if type_id in ref_types:
@@ -118,8 +122,15 @@ def generate_protocol_externs(output_path, file1, file2):
load_schema(file2, domains)
output_file = open(output_path, "w")
output_file.write("var ProtocolProxyApi = {};\n")
- output_file.write("/** @typedef {string} */")
- output_file.write("Protocol.binary;")
+
+ # Add basic types from protocol to closure
+ for protocolName, closureName in type_traits.items():
+ output_file.write("/** @typedef {%s} */\n" % closureName)
+ output_file.write("Protocol.%s;\n" % protocolName)
+
+ # Used for enforcing whether a dispatcher uses an object or not
+ output_file.write("/** @typedef {boolean} */\n")
+ output_file.write("Protocol.UsesObjectNotation;\n")
for domain in domains:
domain_name = domain["domain"]
@@ -139,11 +150,19 @@ def generate_protocol_externs(output_path, file1, file2):
if "commands" in domain:
for command in domain["commands"]:
- output_file.write("\n/**\n")
params = []
in_param_to_type = {}
out_param_to_type = {}
has_return_value = "returns" in command
+
+ if "parameters" in command:
+ for param in command["parameters"]:
+ if "enum" in param:
+ enum_name = param_type(domain_name, param, command)
+ output_file.write(generate_enum(enum_name, param))
+
+ output_file.write("\n/**\n")
+
if "parameters" in command:
# Only declare trailing optional parameters as optional in
# JSDoc annotations.
@@ -158,13 +177,18 @@ def generate_protocol_externs(output_path, file1, file2):
real_in_param_name = "opt_" + in_param_name if in_param_name in trailing_optional else in_param_name
params.append(real_in_param_name)
if "optional" in in_param:
- in_param_to_type[in_param_name] = "(%s|undefined)" % param_type(domain_name, in_param)
+ in_param_to_type[
+ in_param_name] = "(%s|undefined)" % param_type(
+ domain_name, in_param, command)
annotation_suffix = "=" if in_param_name in trailing_optional else "|undefined"
else:
- in_param_to_type[in_param_name] = param_type(domain_name, in_param)
+ in_param_to_type[in_param_name] = param_type(
+ domain_name, in_param, command)
annotation_suffix = ""
output_file.write(
- " * @param {%s%s} %s\n" % (param_type(domain_name, in_param), annotation_suffix, real_in_param_name))
+ " * @param {%s%s} %s\n" %
+ (param_type(domain_name, in_param, command),
+ annotation_suffix, real_in_param_name))
returns = []
returns.append("?Protocol.Error")
if ("error" in command):
@@ -192,7 +216,8 @@ def generate_protocol_externs(output_path, file1, file2):
"Protocol.%sAgent.prototype.%s = function(%s) {};\n" % (domain_name, command["name"], ", ".join(params)))
request_object_properties = []
- request_type = "Protocol.%sAgent.%sRequest" % (domain_name, to_title_case(command["name"]))
+ request_type = "Protocol.%s.%sRequest" % (
+ domain_name, to_title_case(command["name"]))
for param in in_param_to_type:
request_object_properties.append("%s: %s" % (param, in_param_to_type[param]))
if request_object_properties:
@@ -202,7 +227,8 @@ def generate_protocol_externs(output_path, file1, file2):
output_file.write("%s;\n" % request_type)
response_object_properties = []
- response_type = "Protocol.%sAgent.%sResponse" % (domain_name, to_title_case(command["name"]))
+ response_type = "Protocol.%s.%sResponse" % (
+ domain_name, to_title_case(command["name"]))
for param in out_param_to_type:
response_object_properties.append("%s: %s" % (param, out_param_to_type[param]))
if response_object_properties:
@@ -251,6 +277,13 @@ def generate_protocol_externs(output_path, file1, file2):
else:
output_file.write("/** @interface */\n")
output_file.write("Protocol.%sDispatcher = function() {};\n" % domain_name)
+ output_file.write("/** @interface */\n")
+ output_file.write("ProtocolProxyApi.%sDispatcher = function() {};\n" %
+ domain_name)
+ # Include the workaround for https://github.com/microsoft/TypeScript/issues/38640
+ output_file.write(
+ "var ProtocolProxyApiWorkaround_%sDispatcher = ProtocolProxyApi.%sDispatcher;\n"
+ % (domain_name, domain_name))
if "events" in domain:
for event in domain["events"]:
params = []
@@ -267,6 +300,33 @@ def generate_protocol_externs(output_path, file1, file2):
output_file.write(
"Protocol.%sDispatcher.prototype.%s = function(%s) {};\n" % (domain_name, event["name"], ", ".join(params)))
+ # Generate a Event typedef that is used in dispatchers
+ if ("parameters" in event):
+ output_file.write("/**\n")
+ output_file.write("* @typedef {{")
+ for param in event["parameters"]:
+ full_param_type = param_type(domain_name, param)
+ if ("optional" in param):
+ full_param_type = "(%s|undefined)" % full_param_type
+ output_file.write("%s: %s," %
+ (param["name"], full_param_type))
+ output_file.write("}} */\n")
+ else:
+ output_file.write("/**\n")
+ output_file.write("* @typedef {Object}")
+ output_file.write("*/\n")
+ output_file.write("Protocol.%s.%sEvent;\n" %
+ (domain_name, to_title_case(event["name"])))
+
+ # Add the interface method to the dispatcher type, which takes 1 event as argument
+ output_file.write("/**\n")
+ output_file.write("@param {!Protocol.%s.%sEvent} request\n" %
+ (domain_name, to_title_case(event["name"])))
+ output_file.write("*/\n")
+ output_file.write(
+ "ProtocolProxyApi.%sDispatcher.prototype.%s = function(request) {};\n"
+ % (domain_name, event["name"]))
+
for domain in domains:
domain_name = domain["domain"]
uppercase_length = 0
@@ -277,7 +337,9 @@ def generate_protocol_externs(output_path, file1, file2):
output_file.write("ProtocolClient.TargetBase.prototype.%s = function(){};\n" %
(domain_name[:uppercase_length].lower() + domain_name[uppercase_length:] + "Agent"))
- output_file.write("/**\n * @param {!Protocol.%sDispatcher} dispatcher\n */\n" % domain_name)
+ output_file.write(
+ "/**\n * @param {!Protocol.%sDispatcher|!ProtocolProxyApi.%sDispatcher} dispatcher\n */\n"
+ % (domain_name, domain_name))
output_file.write("ProtocolClient.TargetBase.prototype.register%sDispatcher = function(dispatcher) {}\n" % domain_name)
output_file.close()
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/generate_supported_css.py b/chromium/third_party/devtools-frontend/src/scripts/build/generate_supported_css.py
index beb6ab9e3d6..a20ff587375 100755
--- a/chromium/third_party/devtools-frontend/src/scripts/build/generate_supported_css.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/build/generate_supported_css.py
@@ -64,10 +64,16 @@ def properties_from_file(file_name):
if "alias_for" in entry:
aliases_for.append([entry["name"], entry["alias_for"]])
continue
+ # Filter out internal properties.
+ if entry["name"].startswith("-internal-"):
+ continue
properties.append(_keep_only_required_keys(entry))
property_names[entry["name"]] = entry
if "keywords" in entry:
- property_values[entry["name"]] = {"values": entry["keywords"]}
+ keywords = list(
+ filter(lambda keyword: not keyword.startswith("-internal-"),
+ entry["keywords"]))
+ property_values[entry["name"]] = {"values": keywords}
properties.sort(key=lambda entry: entry["name"])
aliases_for.sort(key=lambda entry: entry[0])
diff --git a/chromium/third_party/devtools-frontend/src/scripts/build/modular_build.py b/chromium/third_party/devtools-frontend/src/scripts/build/modular_build.py
index 4f7a2e47169..fa65a213c0a 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/build/modular_build.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/build/modular_build.py
@@ -56,20 +56,19 @@ def concatenate_scripts(file_names, module_dir, output_dir, output):
class Descriptors:
- def __init__(self, application_name, application_dir, application_descriptor, module_descriptors, extends, has_html, worker):
+ def __init__(self, application_name, application_dir,
+ application_descriptor, module_descriptors, extends, worker):
self.application_name = application_name
self.application_dir = application_dir
self.application = application_descriptor
self._cached_sorted_modules = None
self.modules = module_descriptors
self.extends = extends
- self.has_html = has_html
self.worker = worker
def application_json(self):
result = dict()
result['modules'] = self.application.values()
- result['has_html'] = self.has_html
return json.dumps(result)
def all_compiled_files(self):
@@ -178,7 +177,9 @@ class DescriptorLoader:
all_module_descriptors[name] = descriptors[name]
for name in result.application:
all_application_descriptors[name] = result.application[name]
- return Descriptors('all', self.application_dir, all_application_descriptors, all_module_descriptors, None, False, False)
+ return Descriptors('all', self.application_dir,
+ all_application_descriptors, all_module_descriptors,
+ None, False)
def _load_application(self, application_descriptor_name, all_module_descriptors):
module_descriptors = {}
@@ -188,7 +189,6 @@ class DescriptorLoader:
extends = descriptor_json['extends'] if 'extends' in descriptor_json else None
if extends:
extends = self._load_application(extends, all_module_descriptors)
- has_html = True if 'has_html' in descriptor_json and descriptor_json['has_html'] else False
worker = True if 'worker' in descriptor_json and descriptor_json['worker'] else False
for (module_name, module) in application_descriptor.items():
@@ -203,8 +203,9 @@ class DescriptorLoader:
bail_error('Module "%s" (dependency of "%s") not listed in application descriptor %s' %
(dep, module['name'], application_descriptor_filename))
- return Descriptors(application_descriptor_name, self.application_dir, application_descriptor, module_descriptors, extends,
- has_html, worker)
+ return Descriptors(application_descriptor_name, self.application_dir,
+ application_descriptor, module_descriptors, extends,
+ worker)
def _read_module_descriptor(self, module_name, application_descriptor_filename):
json_filename = path.join(self.application_dir, module_name, 'module.json')
diff --git a/chromium/third_party/devtools-frontend/src/scripts/component_server/README.md b/chromium/third_party/devtools-frontend/src/scripts/component_server/README.md
new file mode 100644
index 00000000000..59189a4bc0f
--- /dev/null
+++ b/chromium/third_party/devtools-frontend/src/scripts/component_server/README.md
@@ -0,0 +1,13 @@
+# Components dev server
+
+This server serves up examples of the web components built within DevTools and provides a useful way to document various states of components.
+
+For more background, see the [initial proposal and design doc](https://docs.google.com/document/d/1P6qtACf4aryfT9OSHxNFI3okMKt9oUrtzOKCws5bOec/edit?pli=1).
+
+To add an example for your component:
+
+1. Create `front_end/component_docs/DIR` where `DIR` is the name of your component.
+2. Within the new `DIR`, add HTML files. Each one of these is a standalone example. You should name the HTML file based on what it's documenting, e.g. `basic.html` or `data-missing.html`. This file should import your component and render it with the data you need.
+3. Update `front_end/component_docs/BUILD.gn` to add each of your `*.html` files to the `sources` array. You will also need to update the `deps` array to ensure the component examples depend on your component's source file.
+4. Run `npm run components-server` to fire up a server on `localhost:8090`. You should now see your component listed and you can click on the link to view the examples.
+5. **Note**: the server assumes your built target is `Default`. If not, run the server and pass the `--target` flag: `npm run components-server -- --target=Release`.
diff --git a/chromium/third_party/devtools-frontend/src/scripts/component_server/server.js b/chromium/third_party/devtools-frontend/src/scripts/component_server/server.js
new file mode 100644
index 00000000000..7dfb0b9f6f5
--- /dev/null
+++ b/chromium/third_party/devtools-frontend/src/scripts/component_server/server.js
@@ -0,0 +1,165 @@
+// Copyright (c) 2020 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.
+
+const fs = require('fs');
+const http = require('http');
+const path = require('path');
+const parseURL = require('url').parse;
+const {argv} = require('yargs');
+
+const serverPort = parseInt(process.env.PORT, 10) || 8090;
+
+const target = argv.target || 'Default';
+const devtoolsFrontendFolder = path.resolve(path.join(__dirname, '..', '..', 'out', target, 'gen', 'front_end'));
+
+if (!fs.existsSync(devtoolsFrontendFolder)) {
+ console.error(`ERROR: Generated front_end folder (${devtoolsFrontendFolder}) does not exist.`);
+ console.log(
+ 'The components server works from the built Ninja output; you may need to run Ninja to update your built DevTools.');
+ console.log('If you build to a target other than default, you need to pass --target=X as an argument');
+ process.exit(1);
+}
+
+http.createServer(requestHandler).listen(serverPort);
+console.log(`Started components server at http://localhost:${serverPort}\n`);
+
+function createComponentIndexFile(componentPath, componentExamples) {
+ const componentName = componentPath.replace('/', '');
+ // clang-format off
+ return `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width" />
+ <title>DevTools component: ${componentName}</title>
+ <style>
+ h1 { text-transform: capitalize; }
+
+ .example {
+ padding: 5px;
+ margin: 10px;
+ }
+ iframe { display: block; width: 100%; }
+ </style>
+ </head>
+ <body>
+ <h1>${componentName}</h1>
+ ${componentExamples.map(example => {
+ const fullPath = path.join('component_docs', componentName, example);
+ return `<div class="example">
+ <h3><a href="${fullPath}">${example}</a></h3>
+ <iframe src="${fullPath}"></iframe>
+ </div>`;
+ }).join('\n')}
+ </body>
+ </html>`;
+ // clang-format on
+}
+
+function createServerIndexFile(componentNames) {
+ // clang-format off
+ return `<!DOCTYPE html>
+ <html>
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width" />
+ <title>DevTools components</title>
+ <style>
+ a { text-transform: capitalize; }
+ </style>
+ </head>
+ <body>
+ <h1>DevTools components</h1>
+ <ul>
+ ${componentNames.map(name => {
+ return `<li><a href='/${name}'>${name}</a></li>`;
+ }).join('\n')}
+ </ul>
+ </body>
+ </html>`;
+ // clang-format on
+}
+
+async function getExamplesForPath(filePath) {
+ const componentDirectory = path.join(devtoolsFrontendFolder, 'component_docs', filePath);
+ const contents = await fs.promises.readdir(componentDirectory);
+
+ return createComponentIndexFile(filePath, contents);
+}
+
+function respondWithHtml(response, html) {
+ response.setHeader('Content-Type', 'text/html; charset=utf-8');
+ response.writeHead(200);
+ response.write(html, 'utf8');
+ response.end();
+}
+
+function send404(response, message) {
+ response.writeHead(404);
+ response.write(message, 'utf8');
+ response.end();
+}
+
+async function requestHandler(request, response) {
+ const filePath = parseURL(request.url).pathname;
+
+ if (filePath === '/favicon.ico') {
+ send404(response, '404, no favicon');
+ return;
+ }
+
+ if (filePath === '/' || filePath === '/index.html') {
+ const components = await fs.promises.readdir(path.join(devtoolsFrontendFolder, 'component_docs'));
+ const html = createServerIndexFile(components);
+ respondWithHtml(response, html);
+ } else if (path.extname(filePath) === '') {
+ // This means it's a component path like /breadcrumbs.
+ const componentHtml = await getExamplesForPath(filePath);
+ respondWithHtml(response, componentHtml);
+ } else {
+ // This means it's an asset like a JS file.
+ const fullPath = path.join(devtoolsFrontendFolder, filePath);
+
+ if (!fullPath.startsWith(devtoolsFrontendFolder)) {
+ console.error(`Path ${fullPath} is outside the DevTools Frontend root dir.`);
+ process.exit(1);
+ }
+ const errorsAccesingFile = await fs.promises.access(fullPath, fs.constants.R_OK);
+
+ if (errorsAccesingFile) {
+ console.error(`File ${fullPath} does not exist.`);
+ send404(response, '404, File not found');
+ return;
+ }
+
+ let encoding = 'utf8';
+ if (fullPath.endsWith('.wasm') || fullPath.endsWith('.png') || fullPath.endsWith('.jpg')) {
+ encoding = 'binary';
+ }
+
+ const fileContents = await fs.promises.readFile(fullPath, encoding);
+
+ encoding = 'utf8';
+ if (fullPath.endsWith('.js')) {
+ response.setHeader('Content-Type', 'text/javascript; charset=utf-8');
+ } else if (fullPath.endsWith('.css')) {
+ response.setHeader('Content-Type', 'text/css; charset=utf-8');
+ } else if (fullPath.endsWith('.wasm')) {
+ response.setHeader('Content-Type', 'application/wasm');
+ encoding = 'binary';
+ } else if (fullPath.endsWith('.svg')) {
+ response.setHeader('Content-Type', 'image/svg+xml; charset=utf-8');
+ } else if (fullPath.endsWith('.png')) {
+ response.setHeader('Content-Type', 'image/png');
+ encoding = 'binary';
+ } else if (fullPath.endsWith('.jpg')) {
+ response.setHeader('Content-Type', 'image/jpg');
+ encoding = 'binary';
+ }
+
+ response.writeHead(200);
+ response.write(fileContents, encoding);
+ response.end();
+ }
+}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/deps/ensure_symlink.py b/chromium/third_party/devtools-frontend/src/scripts/deps/ensure_symlink.py
new file mode 100644
index 00000000000..1db12df864d
--- /dev/null
+++ b/chromium/third_party/devtools-frontend/src/scripts/deps/ensure_symlink.py
@@ -0,0 +1,64 @@
+#!/usr/bin/env python
+#
+# Copyright 2020 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.
+"""
+Ensure Devtools-frontend is properly symlinked on gclient sync
+
+In order to use:
+Ensure your .gclient file that manages chromium.src contains this hook
+after your list of solutions:
+
+hooks = [
+ {
+ # Ensure devtools-frontend is symlinked in the correct location
+ 'name': 'Symlink devtools-frontend',
+ 'pattern': '.',
+ 'action': [
+ 'python',
+ '<path>/<to>/devtools-frontend/scripts/deps/ensure_symlink.py',
+ '<path>/<to>/src',
+ '<path>/<to>/devtools-frontend'
+ ],
+ }
+]
+"""
+
+import argparse
+import os
+import sys
+import subprocess
+
+DEVTOOLS_FRONTEND_CHROMIUM_LOCATION = './third_party/devtools-frontend/src'
+
+
+def symlink(src, dst):
+ os_symlink = getattr(os, 'symlink', None)
+ if callable(os_symlink):
+ # symlink is only available on Unix
+ os_symlink(src, dst)
+ else:
+ # use mklink on windows
+ subprocess.check_call(['mklink', '/D', dst, src], shell=True)
+
+
+def parse_options(cli_args):
+ parser = argparse.ArgumentParser(
+ description='Ensure Devtools is symlinked in a full checkout.')
+ parser.add_argument('chromium_dir', help='Root of the Chromium Directory')
+ parser.add_argument('devtools_dir', help='Root of the DevTools directory')
+ return parser.parse_args(cli_args)
+
+
+def ensure_symlink(options):
+ chromium_devtools_path = os.path.normpath(
+ os.path.join(options.chromium_dir,
+ DEVTOOLS_FRONTEND_CHROMIUM_LOCATION))
+ if not os.path.exists(chromium_devtools_path):
+ symlink(os.path.normpath(options.devtools_dir), chromium_devtools_path)
+
+
+if __name__ == '__main__':
+ OPTIONS = parse_options(sys.argv[1:])
+ ensure_symlink(OPTIONS)
diff --git a/chromium/third_party/devtools-frontend/src/scripts/deps/manage_node_deps.py b/chromium/third_party/devtools-frontend/src/scripts/deps/manage_node_deps.py
index 3350c039ec5..1cd41896fce 100755
--- a/chromium/third_party/devtools-frontend/src/scripts/deps/manage_node_deps.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/deps/manage_node_deps.py
@@ -27,12 +27,14 @@ LICENSES = [
"BSD-3-Clause",
"CC0-1.0",
"CC-BY-3.0",
+ "CC-BY-4.0",
"ISC",
]
# List all DEPS here.
DEPS = {
"@types/chai": "4.2.0",
+ "@types/estree": "0.0.45",
"@types/filesystem": "0.0.29",
"@types/mocha": "5.2.7",
"@types/puppeteer": "2.0.0",
@@ -53,12 +55,15 @@ DEPS = {
"karma-sourcemap-loader": "0.3.0",
"license-checker": "25.0.1",
"mocha": "7.1.1",
- "puppeteer": "3.0.3",
+ "puppeteer": "4.0.0",
"recast": "0.18.2",
"rimraf": "3.0.2",
"rollup": "2.3.3",
- "typescript": "3.9.2-insiders.20200509",
- "yargs": "15.3.1"
+ "rollup-plugin-terser": "5.3.0",
+ "stylelint": "13.5.0",
+ "stylelint-config-standard": "20.0.0",
+ "typescript": "3.9.3",
+ "yargs": "15.3.1",
}
def exec_command(cmd):
@@ -104,6 +109,7 @@ def strip_private_fields():
pkg_file.truncate(0)
pkg_file.seek(0)
json.dump(pkg_data, pkg_file, indent=2, sort_keys=True, separators=(',', ': '))
+ pkg_file.write('\n')
except:
print('Unable to fix: %s' % pkg)
return True
@@ -148,6 +154,7 @@ def append_package_json_entries():
pkg_file.truncate(0)
pkg_file.seek(0)
json.dump(pkg_data, pkg_file, indent=2, sort_keys=True, separators=(',', ': '))
+ pkg_file.write('\n')
except:
print('Unable to fix: %s' % sys.exc_info()[0])
@@ -169,6 +176,7 @@ def remove_package_json_entries():
pkg_file.truncate(0)
pkg_file.seek(0)
json.dump(pkg_data, pkg_file, indent=2, sort_keys=True, separators=(',', ': '))
+ pkg_file.write('\n')
except:
print('Unable to fix: %s' % pkg)
return True
@@ -185,6 +193,18 @@ def addClangFormat():
return False
+def addOwnersFile():
+ with open(path.join(devtools_paths.node_modules_path(), 'OWNERS'),
+ 'w+') as owners_file:
+ try:
+ owners_file.write('file://INFRA_OWNERS')
+ owners_file.write('')
+ except:
+ print('Unable to write OWNERS file')
+ return True
+ return False
+
+
def run_npm_command(npm_command_args=None):
for (name, version) in DEPS.items():
if (version.find(u'^') == 0):
@@ -215,6 +235,9 @@ def run_npm_command(npm_command_args=None):
if addClangFormat():
return True
+ if addOwnersFile():
+ return True
+
if run_custom_command:
return custom_command_result
diff --git a/chromium/third_party/devtools-frontend/src/scripts/deps/roll_codemirror.py b/chromium/third_party/devtools-frontend/src/scripts/deps/roll_codemirror.py
deleted file mode 100755
index 01de71fc975..00000000000
--- a/chromium/third_party/devtools-frontend/src/scripts/deps/roll_codemirror.py
+++ /dev/null
@@ -1,87 +0,0 @@
-#!/usr/bin/env python
-#
-# Copyright 2019 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.
-"""
-Helper script to update CodeMirror from upstream.
-"""
-
-import argparse
-import glob
-import os
-import shutil
-import subprocess
-import sys
-
-
-def parse_options(cli_args):
- parser = argparse.ArgumentParser(description='Roll CodeMirror')
- parser.add_argument('cm_dir', help='CodeMirror directory')
- parser.add_argument('devtools_dir', help='DevTools directory')
- return parser.parse_args(cli_args)
-
-
-def run_npm(options):
- print 'Building CodeMirror in %s' % os.path.abspath(options.cm_dir)
- subprocess.check_output(['npm', 'install'], cwd=options.cm_dir, stderr=subprocess.PIPE)
- subprocess.check_output(['npm', 'run', 'build'], cwd=options.cm_dir, stderr=subprocess.PIPE)
-
-
-def copy_lib_files(options):
- print 'Copying codemirror.js and codemirror.css'
- result = ''
- target_dir = os.path.join(options.devtools_dir, 'front_end', 'cm')
-
- with open(os.path.join(options.cm_dir, 'lib', 'codemirror.js'), 'r') as read:
- lines = read.readlines()
- with open(os.path.join(target_dir, 'codemirror.js'), 'w') as write:
- for line in lines:
- if 'CodeMirror.version =' in line:
- result = line.strip()
- write.write(line)
-
- with open(os.path.join(options.cm_dir, 'lib', 'codemirror.css'), 'r') as read:
- lines = read.readlines()
- found_stop = False
- with open(os.path.join(target_dir, 'codemirror.css'), 'w') as write:
- for line in lines:
- if found_stop:
- write.write(line)
- elif '/* STOP */' in line:
- found_stop = True
- assert found_stop
- return result
-
-
-def find_and_copy_js_files(source_dir, target_dir, filter_fn):
- for f in os.listdir(target_dir):
- if not filter_fn(f):
- continue
- target_file = os.path.join(target_dir, f)
- if not os.path.isfile(os.path.join(target_dir, f)):
- continue
- source = glob.glob(os.path.join(source_dir, '*', f))
- assert len(source) == 1
- source_file = source[0]
- print 'Copying %s from %s' % (target_file, source_file)
- shutil.copyfile(source_file, target_file)
-
-
-def copy_cm_files(options):
- source_dir = os.path.join(options.cm_dir, 'addon')
- target_dir = os.path.join(options.devtools_dir, 'front_end', 'cm')
-
- def cm_filter(f):
- return f.endswith('.js') and f != 'codemirror.js' and f != 'cm.js'
-
- find_and_copy_js_files(source_dir, target_dir, cm_filter)
-
-
-
-if __name__ == '__main__':
- OPTIONS = parse_options(sys.argv[1:])
- run_npm(OPTIONS)
- copy_cm_files(OPTIONS)
- VERSION = copy_lib_files(OPTIONS)
- print VERSION
diff --git a/chromium/third_party/devtools-frontend/src/scripts/devtools_paths.py b/chromium/third_party/devtools-frontend/src/scripts/devtools_paths.py
index 543cfa6e2dc..66b71d3388b 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/devtools_paths.py
+++ b/chromium/third_party/devtools-frontend/src/scripts/devtools_paths.py
@@ -78,10 +78,6 @@ def typescript_compiler_path():
return path.join(node_modules_path(), 'typescript', 'bin', 'tsc')
-def boot_perf_test_path():
- return path.join(devtools_root_path(), 'test', 'perf', 'bootperf.js')
-
-
def hosted_mode_script_path():
return path.join(devtools_root_path(), 'scripts', 'hosted_mode', 'server.js')
diff --git a/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/check_license_header.js b/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/check_license_header.js
index b358b6a687b..018c341fb00 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/check_license_header.js
+++ b/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/check_license_header.js
@@ -54,25 +54,10 @@ const BLOCK_REGEX = new RegExp('[\\s\\\\n\\*]*' + BLOCK_LICENSE_HEADER.join('[\\
const LICENSE_HEADER_ADDITION = LINE_LICENSE_HEADER.map(line => `// ${line}`).join('\n') + '\n\n';
const EXCLUDED_FILES = [
- // FIXME: CodeMirror bundles must be moved to third_party
- 'cm/active-line.js',
- 'cm/brace-fold.js',
- 'cm/closebrackets.js',
- 'cm/codemirror.js',
- 'cm/comment.js',
- 'cm/foldcode.js',
- 'cm/foldgutter.js',
- 'cm/mark-selection.js',
- 'cm/matchbrackets.js',
- 'cm/multiplex.js',
- 'cm/overlay.js',
- 'cm/simple.js',
// FIXME: Dagre bundles must be moved to third_party
'dagre_layout/dagre.js',
// FIXME: Diff bundles must be moved to third_party
'diff/diff_match_patch.js',
- // FIXME: Acorn bundles must be moved to third_party
- 'formatter_worker/acorn/acorn_loose.js',
];
const OTHER_LICENSE_HEADERS = [
diff --git a/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/es_modules_import.js b/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/es_modules_import.js
index 4222441e452..5e943ebd6c0 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/es_modules_import.js
+++ b/chromium/third_party/devtools-frontend/src/scripts/eslint_rules/lib/es_modules_import.js
@@ -11,12 +11,17 @@
const path = require('path');
const FRONT_END_DIRECTORY = path.join(__dirname, '..', '..', '..', 'front_end');
+const INSPECTOR_OVERLAY_DIRECTORY = path.join(__dirname, '..', '..', '..', 'front_end', 'inspector_overlay');
const EXEMPTED_THIRD_PARTY_MODULES = new Set([
// lit-html is exempt as it doesn't expose all its modules from the root file
path.join(FRONT_END_DIRECTORY, 'third_party', 'lit-html'),
// wasmparser is exempt as it doesn't expose all its modules from the root file
path.join(FRONT_END_DIRECTORY, 'third_party', 'wasmparser'),
+ // acorn is exempt as it doesn't expose all its modules from the root file
+ path.join(FRONT_END_DIRECTORY, 'third_party', 'acorn'),
+ // acorn-loose is exempt as it doesn't expose all its modules from the root file
+ path.join(FRONT_END_DIRECTORY, 'third_party', 'acorn-loose'),
]);
const CROSS_NAMESPACE_MESSAGE =
@@ -53,7 +58,7 @@ function checkImportExtension(importPath, context, node) {
return;
}
- if (!importPath.endsWith('.js')) {
+ if (!importPath.endsWith('.js') && !importPath.endsWith('.mjs')) {
context.report({
node,
message: 'Missing file extension for import "{{importPath}}"',
@@ -149,7 +154,7 @@ module.exports = {
//
// Don't use `importPath` here, as `path.normalize` removes
// the `./` from same-folder import paths.
- if (!node.source.value.startsWith('.') && !/^\w+$/.test(node.source.value)) {
+ if (!node.source.value.startsWith('.') && !/^[\w\-_]+$/.test(node.source.value)) {
context.report({
node,
message: 'Invalid relative URL import. An import should start with either "../" or "./".',
@@ -160,6 +165,10 @@ module.exports = {
return;
}
+ if (importingFileName.startsWith(INSPECTOR_OVERLAY_DIRECTORY)) {
+ return;
+ }
+
if (isSideEffectImportSpecifier(node.specifiers)) {
return;
}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/BUILD.gn b/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/BUILD.gn
new file mode 100644
index 00000000000..c709a53178b
--- /dev/null
+++ b/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/BUILD.gn
@@ -0,0 +1,9 @@
+# Copyright 2020 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("../build/copy_to_gen.gni")
+
+copy_to_gen("hosted_mode") {
+ sources = [ "server.js" ]
+}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/launch_chrome.js b/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/launch_chrome.js
deleted file mode 100644
index 5a3c95141a2..00000000000
--- a/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/launch_chrome.js
+++ /dev/null
@@ -1,130 +0,0 @@
-// Copyright 2016 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.
-
-const childProcess = require('child_process');
-const fs = require('fs');
-const path = require('path');
-const shell = childProcess.execSync;
-
-const utils = require('../utils');
-
-const REMOTE_DEBUGGING_PORT = parseInt(process.env.REMOTE_DEBUGGING_PORT, 10) || 9222;
-const SERVER_PORT = parseInt(process.env.PORT, 10) || 8090;
-const CHROMIUM_DEFAULT_PATH = path.resolve(__dirname, '..', '..', 'third_party', 'chrome', 'chrome-linux', 'chrome');
-const CHROME_PROFILE_PATH = path.resolve(__dirname, '..', '..', '.dev_profile');
-
-const Flags = {
- RESET_PROFILE: '--reset-profile',
-};
-
-if (utils.includes(process.argv, Flags.RESET_PROFILE)) {
- console.log('Removing your dev profile for Chrome Canary / Chromium at:');
- console.log(CHROME_PROFILE_PATH, '\n');
- utils.removeRecursive(CHROME_PROFILE_PATH);
-}
-
-const chromeArgs = [
- `--remote-debugging-port=${REMOTE_DEBUGGING_PORT}`,
- `--custom-devtools-frontend=http://localhost:${SERVER_PORT}/front_end/`, '--no-first-run',
- `http://localhost:${REMOTE_DEBUGGING_PORT}#custom=true`, 'https://devtools.chrome.com',
- `--user-data-dir=${CHROME_PROFILE_PATH}`
-].concat(process.argv.slice(2));
-
-if (process.platform === 'win32') {
- launchChromeWindows();
- return;
-}
-if (process.platform === 'darwin') {
- launchChromeMac();
- return;
-}
-if (process.platform === 'linux') {
- launchChromeLinux();
- return;
-}
-
-throw new Error(`Unrecognized platform detected: ${process.platform}`);
-
-function launchChromeWindows() {
- let chromeCanaryPath;
- if (utils.isFile(process.env.CHROMIUM_PATH)) {
- chromeCanaryPath = process.env.CHROMIUM_PATH;
- } else {
- const suffix = '\\Google\\Chrome SxS\\Application\\chrome.exe';
- const prefixes = [process.env.LOCALAPPDATA, process.env.PROGRAMFILES, process.env['PROGRAMFILES(X86)']];
- for (let i = 0; i < prefixes.length; i++) {
- const prefix = prefixes[i];
- try {
- chromeCanaryPath = path.join(prefix, suffix);
- fs.accessSync(chromeCanaryPath);
- break;
- } catch (e) {
- }
- }
- }
- launchChrome(chromeCanaryPath, chromeArgs);
-}
-
-function launchChromeMac() {
- let chromeExecPath;
- if (utils.isFile(process.env.CHROMIUM_PATH)) {
- chromeExecPath = process.env.CHROMIUM_PATH;
- } else {
- const lsregister =
- '/System/Library/Frameworks/CoreServices.framework/Versions/A/Frameworks/LaunchServices.framework/Versions/A/Support/lsregister';
- const chromeCanaryPath = shellOutput(
- `${lsregister} -dump | grep -i 'applications/google chrome canary.app$' | awk '{$1=""; print $0}' | head -n 1`);
- chromeExecPath = `${chromeCanaryPath}/Contents/MacOS/Google Chrome Canary`;
- }
- launchChrome(chromeExecPath, chromeArgs);
-}
-
-function launchChromeLinux() {
- let chromiumPath;
- if (utils.isFile(process.env.CHROMIUM_PATH)) {
- chromiumPath = process.env.CHROMIUM_PATH;
- } else if (utils.isFile(CHROMIUM_DEFAULT_PATH)) {
- chromiumPath = CHROMIUM_DEFAULT_PATH;
- } else {
- onLaunchChromeError();
- return;
- }
- launchChrome(chromiumPath, chromeArgs);
-}
-
-function launchChrome(filePath, chromeArgs) {
- console.log(`Launching Chrome from ${filePath}`);
- console.log('Chrome args:', chromeArgs.join(' '), '\n');
- let child;
- try {
- child = childProcess.spawn(filePath, chromeArgs, {
- stdio: 'inherit',
- });
- } catch (error) {
- onLaunchChromeError();
- return;
- }
- child.on('error', onLaunchChromeError);
- child.on('exit', onExit);
- function onExit(code) {
- console.log('Exited Chrome with code', code);
- }
-}
-
-function onLaunchChromeError() {
- if (process.platform !== 'linux') {
- console.log('ERROR: Cannot find Chrome Canary on your computer');
- console.log('Install Chome Canary at:');
- console.log('https://www.google.com/chrome/browser/canary.html\n');
- } else {
- console.log('ERROR: Could not launch Chromium');
- console.log('The environment variable CHROMIUM_PATH must be set to executable of a build of Chromium');
- console.log('If you do not have a recent build of chromium, you can get one from:');
- console.log('https://download-chromium.appspot.com/\n');
- }
-}
-
-function shellOutput(command) {
- return shell(command).toString().trim();
-}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/server.js b/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/server.js
index 84c1ae2a626..de362c6e4b3 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/server.js
+++ b/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/server.js
@@ -6,11 +6,9 @@ const http = require('http');
const path = require('path');
const parseURL = require('url').parse;
-const utils = require('../utils');
-
const remoteDebuggingPort = parseInt(process.env.REMOTE_DEBUGGING_PORT, 10) || 9222;
const serverPort = parseInt(process.env.PORT, 10) || 8090;
-const devtoolsFolder = path.resolve(path.join(__dirname, '../..'));
+const devtoolsFolder = path.resolve(path.join(__dirname, '..', '..'));
http.createServer(requestHandler).listen(serverPort);
console.log(`Started hosted mode server at http://localhost:${serverPort}\n`);
@@ -26,18 +24,6 @@ function requestHandler(request, response) {
return;
}
- const proxiedFile = proxy(filePath, sendResponse);
- if (proxiedFile) {
- proxiedFile.then(data => sendResponse(200, data)).catch(handleProxyError);
- return;
- }
-
- function handleProxyError(err) {
- console.log(`Error serving the file ${filePath}:`, err);
- console.log(`Make sure you opened Chrome with the flag "--remote-debugging-port=${remoteDebuggingPort}"`);
- sendResponse(500, '500 - Internal Server Error');
- }
-
const absoluteFilePath = path.join(devtoolsFolder, filePath);
if (!path.resolve(absoluteFilePath).startsWith(devtoolsFolder)) {
console.log(`File requested (${absoluteFilePath}) is outside of devtools folder: ${devtoolsFolder}`);
@@ -80,7 +66,7 @@ function requestHandler(request, response) {
}
let encoding = 'utf8';
- if (path.endsWith('.js')) {
+ if (path.endsWith('.js') || path.endsWith('.mjs')) {
response.setHeader('Content-Type', 'text/javascript; charset=utf-8');
} else if (path.endsWith('.css')) {
response.setHeader('Content-Type', 'text/css; charset=utf-8');
@@ -132,60 +118,3 @@ function requestHandler(request, response) {
response.end();
}
}
-
-const proxyFilePathToURL = {
- '/favicon.ico': () => 'https://chrome-devtools-frontend.appspot.com/favicon.ico',
-};
-
-const proxyFileCache = new Map();
-
-function proxy(filePath) {
- if (!(filePath in proxyFilePathToURL)) {
- return null;
- }
- if (process.env.CHROMIUM_COMMIT) {
- return onProxyFileURL(proxyFilePathToURL[filePath](process.env.CHROMIUM_COMMIT));
- }
- return utils.fetch(`http://localhost:${remoteDebuggingPort}/json/version`)
- .then(onBrowserMetadata)
- .then(onProxyFileURL);
-
- function onBrowserMetadata(metadata) {
- const metadataObject = JSON.parse(metadata);
- const match = metadataObject['WebKit-Version'].match(/\s\(@(\b[0-9a-f]{5,40}\b)/);
- const commitHash = match[1];
- const proxyFileURL = proxyFilePathToURL[filePath](commitHash);
- return proxyFileURL;
- }
-
- function onProxyFileURL(proxyFileURL) {
- if (proxyFileCache.has(proxyFileURL)) {
- return Promise.resolve(proxyFileCache.get(proxyFileURL));
- }
- return utils.fetch(proxyFileURL).then(cacheProxyFile.bind(null, proxyFileURL)).catch(onMissingFile);
- }
-
- function onMissingFile() {
- const isFullCheckout = utils.shellOutput('git config --get remote.origin.url') ===
- 'https://chromium.googlesource.com/chromium/src.git';
- let earlierCommitHash;
- const gitLogCommand = 'git log --max-count=1 --grep="Commit-Position" --before="12 hours ago"';
- if (isFullCheckout) {
- earlierCommitHash = utils.shellOutput(`${gitLogCommand} --pretty=format:"%H"`);
- } else {
- const commitMessage = utils.shellOutput(`${gitLogCommand}`);
- earlierCommitHash = commitMessage.match(/Cr-Mirrored-Commit: (.*)/)[1];
- }
- const fallbackURL = proxyFilePathToURL[filePath](earlierCommitHash);
- console.log('WARNING: Unable to fetch generated file based on browser\'s revision');
- console.log('Fetching earlier revision of same file as fallback');
- console.log('There may be a mismatch between the front-end and back-end');
- console.log(fallbackURL, '\n');
- return utils.fetch(fallbackURL).then(cacheProxyFile.bind(null, fallbackURL));
- }
-
- function cacheProxyFile(proxyFileURL, data) {
- proxyFileCache.set(proxyFileURL, data);
- return data;
- }
-}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/start_chrome_and_server.js b/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/start_chrome_and_server.js
deleted file mode 100644
index d42e3e01d14..00000000000
--- a/chromium/third_party/devtools-frontend/src/scripts/hosted_mode/start_chrome_and_server.js
+++ /dev/null
@@ -1,12 +0,0 @@
-// Copyright 2016 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.
-
-const childProcess = require('child_process');
-
-const chrome = childProcess.fork('scripts/hosted_mode/launch_chrome.js', process.argv.slice(2));
-const server = childProcess.fork('scripts/hosted_mode/server.js');
-
-chrome.on('exit', function() {
- server.kill();
-});
diff --git a/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizability.js b/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizability.js
index 88c1cc5b6a9..f5d90d5cc57 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizability.js
+++ b/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizability.js
@@ -90,6 +90,13 @@ function includesConditionalExpression(listOfElements) {
return listOfElements.filter(ele => ele !== undefined && ele.type === espreeTypes.COND_EXPR).length > 0;
}
+function includesGritPlaceholders(cookedValue) {
+ // $[0-9] is a GRIT placeholder for Chromium l10n, unfortunately it cannot be escaped.
+ // https://chromium-review.googlesource.com/c/chromium/src/+/1405148
+ const regexPattern = /\$[0-9]+/g;
+ return regexPattern.test(cookedValue);
+}
+
function addError(error, errors) {
if (!errors.includes(error)) {
errors.push(error);
@@ -211,6 +218,15 @@ function analyzeNode(parentNode, node, filePath, errors) {
code}. Please extract conditional(s) out of the localization call.`,
errors);
}
+
+ if (node.arguments[0].type === espreeTypes.LITERAL && includesGritPlaceholders(node.arguments[0].value)) {
+ addError(
+ `${localizationUtils.getRelativeFilePathFromSrc(filePath)}${
+ localizationUtils.getLocationMessage(node.loc)}: possible placeholder(s) found in ${
+ code}. Please extract placeholders(s) out of the localization call.`,
+ errors);
+ }
+
break;
}
@@ -222,6 +238,14 @@ function analyzeNode(parentNode, node, filePath, errors) {
code}. Please extract conditional(s) out of the localization call.`,
errors);
}
+
+ if (includesGritPlaceholders(node.quasi.quasis[0].value.cooked)) {
+ addError(
+ `${localizationUtils.getRelativeFilePathFromSrc(filePath)}${
+ localizationUtils.getLocationMessage(node.loc)}: possible placeholder(s) found in ${
+ code}. Please extract placeholders(s) out of the localization call.`,
+ errors);
+ }
break;
}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizable_resources.js b/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizable_resources.js
index dd21e7d47f1..837e69cf36e 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizable_resources.js
+++ b/chromium/third_party/devtools-frontend/src/scripts/localization/check_localizable_resources.js
@@ -85,7 +85,7 @@ async function autofix(existingError) {
if (shouldAddExampleTag) {
message += ' Add example tag(s) <ex> for messages that contain placeholder(s)';
}
- message += '\nFor more details, see devtools/docs/langpacks/grdp_files.md';
+ message += '\nFor more details, see src/docs/localization/grdp_files.md';
}
if (resourceRemoved && duplicateRemoved(keysToRemoveFromGRD)) {
message += '\nDuplicate <message> entries are removed. Please verify the retained descriptions are correct.';
diff --git a/chromium/third_party/devtools-frontend/src/scripts/localization/utils/check_localized_strings.js b/chromium/third_party/devtools-frontend/src/scripts/localization/utils/check_localized_strings.js
index ea706c12ad3..652ad6e9c66 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/localization/utils/check_localized_strings.js
+++ b/chromium/third_party/devtools-frontend/src/scripts/localization/utils/check_localized_strings.js
@@ -86,7 +86,9 @@ async function validateGrdFile(shouldAutoFix) {
const fileLines = fileContent.split('\n');
const newLines = [];
let errors = '';
- fileLines.forEach(line => errors += validateGrdLine(line, newLines));
+ fileLines.forEach(line => {
+ errors += validateGrdLine(line, newLines);
+ });
if (errors !== '' && shouldAutoFix) {
await writeFileAsync(localizationUtils.GRD_PATH, newLines.join('\n'));
}
@@ -129,9 +131,9 @@ async function validateGrdpFiles(shouldAutoFix) {
let errors = '';
const renameFilePromises = [];
const grdpFilesToAddToGrd = [];
- frontendDirsToGrdpFiles.forEach(
- (grdpFiles, dir) => errors +=
- validateGrdpFile(dir, grdpFiles, grdFileContent, shouldAutoFix, renameFilePromises, grdpFilesToAddToGrd));
+ frontendDirsToGrdpFiles.forEach((grdpFiles, dir) => {
+ errors += validateGrdpFile(dir, grdpFiles, grdFileContent, shouldAutoFix, renameFilePromises, grdpFilesToAddToGrd);
+ });
if (grdpFilesToAddToGrd.length > 0) {
await localizationUtils.addChildGRDPFilePathsToGRD(grdpFilesToAddToGrd.sort());
}
@@ -582,9 +584,11 @@ function getAndReportResourcesToRemove() {
// Example error message:
// third_party/devtools-frontend/front_end/accessibility/accessibility_strings.grdp Line 300: IDS_DEVTOOLS_c9bbad3047af039c14d0e7ec957bb867
for (const [ids, messages] of keysToRemoveFromGRD) {
- messages.forEach(
- message => errorStr += `${localizationUtils.getRelativeFilePathFromSrc(message.grdpPath)}${
- localizationUtils.getLocationMessage(message.location)}: ${ids}\n\n`);
+ messages.forEach(message => {
+ const path = localizationUtils.getRelativeFilePathFromSrc(message.grdpPath);
+ const msg = localizationUtils.getLocationMessage(message.location);
+ errorStr += `${path}${msg}: ${ids}\n\n`;
+ });
}
return errorStr;
}
@@ -599,10 +603,11 @@ function getAndReportIDSKeysToModify() {
errorStr += 'Please update the key(s) by changing the "name" value.\n\n';
for (const [expectedIDSKey, messages] of messagesToModify) {
- messages.forEach(
- message => errorStr += `${localizationUtils.getRelativeFilePathFromSrc(message.grdpPath)}${
- localizationUtils.getLocationMessage(
- message.location)}:\n${message.actualIDSKey} --> ${expectedIDSKey}\n\n`);
+ messages.forEach(message => {
+ const path = localizationUtils.getRelativeFilePathFromSrc(message.grdpPath);
+ const msg = localizationUtils.getLocationMessage(message.location);
+ errorStr += `${path}${msg}:\n${message.actualIDSKey} --> ${expectedIDSKey}\n\n`;
+ });
}
return errorStr;
}
diff --git a/chromium/third_party/devtools-frontend/src/scripts/npm_test.js b/chromium/third_party/devtools-frontend/src/scripts/npm_test.js
index a35bab85376..c2e6e44b84e 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/npm_test.js
+++ b/chromium/third_party/devtools-frontend/src/scripts/npm_test.js
@@ -5,7 +5,6 @@
const childProcess = require('child_process');
const fs = require('fs');
const path = require('path');
-const shell = require('child_process').execSync;
const utils = require('./utils');
const Flags = {
@@ -19,12 +18,8 @@ const Flags = {
const IS_DEBUG_ENABLED =
utils.includes(process.argv, Flags.DEBUG_DEVTOOLS) || utils.includes(process.argv, Flags.DEBUG_DEVTOOLS_SHORTHAND);
const CUSTOM_CHROMIUM_PATH = utils.parseArgs(process.argv)[Flags.CHROMIUM_PATH];
-const IS_FETCH_CONTENT_SHELL = utils.includes(process.argv, Flags.FETCH_CONTENT_SHELL);
const TARGET = utils.parseArgs(process.argv)[Flags.TARGET] || 'Release';
-const CONTENT_SHELL_ZIP = 'content-shell.zip';
-const MAX_CONTENT_SHELLS = 10;
-const PLATFORM = getPlatform();
const PYTHON = process.platform === 'win32' ? 'python.bat' : 'python';
const CURRENT_PATH = process.env.PWD || process.cwd(); // Using env.PWD to account for symlinks.
@@ -34,76 +29,22 @@ const RELEASE_PATH = path.resolve(CHROMIUM_SRC_PATH, 'out', TARGET);
const BLINK_TEST_PATH = path.resolve(CHROMIUM_SRC_PATH, 'third_party', 'blink', 'tools', 'run_web_tests.py');
const DEVTOOLS_PATH = path.resolve(CHROMIUM_SRC_PATH, 'third_party', 'devtools-frontend', 'src');
const CACHE_PATH = path.resolve(DEVTOOLS_PATH, '.test_cache');
-const SOURCE_PATH = path.resolve(DEVTOOLS_PATH, 'front_end');
function main() {
if (!utils.isDir(CACHE_PATH)) {
fs.mkdirSync(CACHE_PATH);
}
- deleteOldContentShells();
const hasUserCompiledContentShell = utils.isFile(getContentShellBinaryPath(RELEASE_PATH));
- if (!IS_FETCH_CONTENT_SHELL && hasUserCompiledContentShell) {
- const outDir = path.resolve(RELEASE_PATH, '..');
- if (!IS_DEBUG_ENABLED) {
- compileFrontend();
- }
-
- runTests(outDir, IS_DEBUG_ENABLED);
+ if (!hasUserCompiledContentShell) {
return;
}
+ const outDir = path.resolve(RELEASE_PATH, '..');
- findPreviousUploadedPosition(findMostRecentChromiumCommit())
- .then(onUploadedCommitPosition)
- .catch(onError);
-
- function onError(error) {
- console.log('Unable to run tests because of error:', error);
- console.log(`Try removing the .test_cache folder [${CACHE_PATH}] and retrying`);
- }
+ runTests(outDir, IS_DEBUG_ENABLED);
}
main();
-function compileFrontend() {
- console.log('Compiling devtools frontend');
- try {
- shell(`ninja -C ${RELEASE_PATH} devtools_frontend_resources`, {cwd: CHROMIUM_SRC_PATH});
- } catch (err) {
- console.log(err.stdout.toString());
- console.log('ERROR: Cannot compile frontend\n' + err);
- process.exit(1);
- }
-}
-
-function onUploadedCommitPosition(commitPosition) {
- const contentShellDirPath = path.resolve(CACHE_PATH, commitPosition, 'out', TARGET);
- const contentShellResourcesPath = path.resolve(contentShellDirPath, 'resources');
- const contentShellPath = path.resolve(CACHE_PATH, commitPosition, 'out');
-
- const hasCachedContentShell = utils.isFile(getContentShellBinaryPath(contentShellDirPath));
- if (hasCachedContentShell) {
- console.log(`Using cached content shell at: ${contentShellPath}`);
- copyFrontend(contentShellResourcesPath);
- return runTests(contentShellPath, true);
- }
- const url = `http://commondatastorage.googleapis.com/chromium-browser-snapshots/${PLATFORM}/${commitPosition
- }/${CONTENT_SHELL_ZIP}`;
- return prepareContentShellDirectory(commitPosition)
- .then(() => downloadContentShell(url, commitPosition))
- .then(extractContentShell)
- .then(() => copyFrontend(contentShellResourcesPath))
- .then(() => runTests(contentShellPath, true));
-}
-
-function copyFrontend(contentShellResourcesPath) {
- const devtoolsResourcesPath = path.resolve(contentShellResourcesPath, 'inspector');
- const copiedFrontendPath = path.resolve(devtoolsResourcesPath, 'front_end');
- const debugFrontendPath = path.resolve(devtoolsResourcesPath, 'debug');
- utils.removeRecursive(copiedFrontendPath);
- utils.removeRecursive(debugFrontendPath);
- utils.copyRecursive(SOURCE_PATH, devtoolsResourcesPath);
- fs.renameSync(copiedFrontendPath, debugFrontendPath);
-}
function getChromiumSrcPath(isThirdParty) {
if (isThirdParty)
@@ -124,118 +65,6 @@ function getChromiumSrcPath(isThirdParty) {
return srcPath;
}
-function getPlatform() {
- if (process.platform === 'linux') {
- return 'Linux_x64';
- }
- if (process.platform === 'win32') {
- return 'Win_x64';
- }
- if (process.platform === 'darwin') {
- return 'Mac';
- }
-
- throw new Error(`Unrecognized platform detected: ${process.platform}`);
-}
-
-function findMostRecentChromiumCommit() {
- const commitMessage = shell('git log --max-count=1 --grep="Cr-Commit-Position"').toString().trim();
- const commitPosition = commitMessage.match(/Cr-Commit-Position: refs\/heads\/master@\{#([0-9]+)\}/)[1];
- return commitPosition;
-}
-
-function deleteOldContentShells() {
- const files = fs.readdirSync(CACHE_PATH);
- if (files.length < MAX_CONTENT_SHELLS) {
- return;
- }
- files.sort((a, b) => parseInt(b, 10) - parseInt(a, 10));
- const remainingNumberOfContentShells = MAX_CONTENT_SHELLS / 2;
- const oldContentShellDirs = files.slice(remainingNumberOfContentShells);
- for (let i = 0; i < oldContentShellDirs.length; i++) {
- utils.removeRecursive(path.resolve(CACHE_PATH, oldContentShellDirs[i]));
- }
- console.log(`Removed old content shells: ${oldContentShellDirs}`);
-}
-
-function findPreviousUploadedPosition(commitPosition) {
- const previousPosition = commitPosition - 100;
- const positionsListURL =
- `http://commondatastorage.googleapis.com/chromium-browser-snapshots/?delimiter=/&prefix=${PLATFORM
- }/&marker=${PLATFORM}/${previousPosition}/`;
- return utils.fetch(positionsListURL).then(onPositionsList).catch(onError);
-
- function onPositionsList(buffer) {
- const positions = buffer.toString('binary')
- .match(/([^<>]+)(?=<\/Prefix><\/CommonPrefixes>)/g)
- .map(prefixedPosition => prefixedPosition.split('/')[1])
- .map(positionString => parseInt(positionString, 10));
- const positionSet = new Set(positions);
- let previousUploadedPosition = commitPosition;
- while (commitPosition - previousUploadedPosition < 100) {
- if (positionSet.has(previousUploadedPosition)) {
- return previousUploadedPosition.toString();
- }
- previousUploadedPosition--;
- }
- onError();
- }
-
- function onError(error) {
- if (error) {
- console.log(`Received error: ${error} trying to fetch positions list from url: ${positionsListURL}`);
- }
- throw new Error(`Unable to find a previous upload position for commit position: ${commitPosition}`);
- }
-}
-
-async function prepareContentShellDirectory(folder) {
- const contentShellPath = path.join(CACHE_PATH, folder);
- if (utils.isDir(contentShellPath)) {
- utils.removeRecursive(contentShellPath);
- }
- fs.mkdirSync(contentShellPath);
- return folder;
-}
-
-function downloadContentShell(url, folder) {
- console.log('Downloading content shell from:', url);
- console.log('NOTE: Download is ~35-65 MB depending on OS');
- return utils.fetch(url).then(writeZip).catch(onError);
-
- function writeZip(buffer) {
- console.log('Completed download of content shell');
- const contentShellZipPath = path.join(CACHE_PATH, folder, CONTENT_SHELL_ZIP);
- fs.writeFileSync(contentShellZipPath, buffer);
- return contentShellZipPath;
- }
-
- function onError(error) {
- console.log(`Received error: ${error} trying to download content shell from url: ${url}`);
- throw new Error('Unable to download content shell');
- }
-}
-
-function extractContentShell(contentShellZipPath) {
- console.log(`Extracting content shell zip: ${contentShellZipPath}`);
- const unzipScriptPath = path.resolve(__dirname, 'unzip.py');
- const src = contentShellZipPath;
- const dest = path.resolve(path.dirname(src), 'out');
- shell(`${PYTHON} ${unzipScriptPath} ${src} ${dest}`);
- fs.unlinkSync(src);
- const originalDirPath = path.resolve(dest, 'content-shell');
- const newDirPath = path.resolve(dest, TARGET);
- fs.renameSync(originalDirPath, newDirPath);
- fs.chmodSync(getContentShellBinaryPath(newDirPath), '755');
- if (process.platform === 'darwin') {
- const helperPath = path.resolve(
- newDirPath, 'Content Shell.app', 'Contents', 'Frameworks', 'Content Shell Helper.app', 'Contents', 'MacOS',
- 'Content Shell Helper');
- fs.chmodSync(helperPath, '755');
- }
- return dest;
-}
-
function getContentShellBinaryPath(dirPath) {
if (process.platform === 'linux') {
return path.resolve(dirPath, 'content_shell');
diff --git a/chromium/third_party/devtools-frontend/src/scripts/protocol_typescript/protocol_dts_generator.ts b/chromium/third_party/devtools-frontend/src/scripts/protocol_typescript/protocol_dts_generator.ts
index f489ef74dfe..b0de18245b1 100644
--- a/chromium/third_party/devtools-frontend/src/scripts/protocol_typescript/protocol_dts_generator.ts
+++ b/chromium/third_party/devtools-frontend/src/scripts/protocol_typescript/protocol_dts_generator.ts
@@ -81,6 +81,13 @@ const emitGlobalTypeDefs = () => {
emitLine('getError(): string|undefined;');
numIndents--;
emitLine('}');
+ emitLine('export type UsesObjectNotation = true;');
+ emitLine('export interface Dispatcher {');
+ numIndents++;
+ emitLine('/** This dispatcher requires objects as parameters, rather than multiple arguments */');
+ emitLine('usesObjectNotation(): UsesObjectNotation;');
+ numIndents--;
+ emitLine('}');
};
const emitDomain = (domain: Protocol.Domain) => {
@@ -368,7 +375,7 @@ const emitDomainApi = (domain: Protocol.Domain, modulePrefix: string) => {
domain.commands.forEach(c => emitApiCommand(c, domainName, modulePrefix));
}
emitCloseBlock();
- emitOpenBlock(`export interface ${domainName}Dispatcher`);
+ emitOpenBlock(`export interface ${domainName}Dispatcher extends Protocol.Dispatcher`);
if (domain.events) {
domain.events.forEach(e => emitApiEvent(e, domainName, modulePrefix));
}
@@ -395,6 +402,12 @@ const emitApi = (moduleName: string, protocolModuleName: string, domains: Protoc
domains.forEach(d => emitDomainApi(d, protocolModulePrefix));
emitCloseBlock();
emitLine();
+
+ emitLine('// Include the workaround for https://github.com/microsoft/TypeScript/issues/38640');
+ domains.forEach(d => {
+ emitLine(
+ `interface ProtocolProxyApiWorkaround_${d.domain}Dispatcher extends ProtocolProxyApi.${d.domain}Dispatcher {}`);
+ });
};
const flushEmitToFile = (path: string) => {
diff --git a/chromium/third_party/devtools-frontend/src/scripts/suggest_owners.js b/chromium/third_party/devtools-frontend/src/scripts/suggest_owners.js
new file mode 100644
index 00000000000..becf8781b64
--- /dev/null
+++ b/chromium/third_party/devtools-frontend/src/scripts/suggest_owners.js
@@ -0,0 +1,102 @@
+// Copyright 2020 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.
+
+// Suggest owners based on authoring and reviewing contributions.
+// Usage: node suggest-owners.js <since-date> <path>
+const {promisify} = require('util');
+const exec = promisify(require('child_process').exec);
+const readline = require('readline');
+const fs = require('fs');
+const path = require('path');
+const file_path = process.argv[3];
+const date = process.argv[2];
+
+readline.Interface.prototype.question[promisify.custom] = function(prompt) {
+ return new Promise(
+ resolve => readline.Interface.prototype.question.call(this, prompt, resolve),
+ );
+};
+readline.Interface.prototype.questionAsync = promisify(
+ readline.Interface.prototype.question,
+);
+
+(async function() {
+ const {stdout} = await exec(`git log --numstat --since=${date} ${file_path}`, {maxBuffer: 1024 * 1024 * 128});
+ const structured_log = [];
+ // Parse git log into a list of commit objects.
+ for (const line of stdout.split('\n')) {
+ if (line.startsWith('commit')) {
+ // Start of a new commit
+ const match = /^commit (?<hash>\p{ASCII_Hex_Digit}+)/u.exec(line);
+ structured_log.push({
+ commit: match.groups.hash,
+ contributors: new Set(),
+ });
+ continue;
+ }
+ const commit = structured_log[structured_log.length - 1];
+ let match;
+ if ((match = line.match(/^Author: .*<(?<author>.+@.+\..+)>$/))) {
+ commit.contributors.add(match.groups.author);
+ } else if ((match = line.match(/Reviewed-by: .*<(?<reviewer>.+@.+\..+)>$/))) {
+ commit.contributors.add(match.groups.reviewer);
+ }
+ }
+
+ // Attribute commits to contributors.
+ const contributor_to_commits = new Map();
+ for (commit of structured_log) {
+ for (const contributor of commit.contributors) {
+ if (!contributor_to_commits.has(contributor)) {
+ contributor_to_commits.set(contributor, 1);
+ } else {
+ contributor_to_commits.set(contributor, contributor_to_commits.get(contributor) + 1);
+ }
+ }
+ }
+
+ // Output contributors.
+ let list = [];
+ for (const [contributor, commits] of contributor_to_commits) {
+ list.push({contributor, commits});
+ }
+ list.sort((a, b) => b.commits - a.commits);
+ console.log('Contributions');
+ for (const {contributor, commits} of list) {
+ console.log(` ${contributor.padEnd(30)}: ${String(commits).padStart(3)}`);
+ }
+
+ const owners_path = path.join(file_path, 'OWNERS');
+ // Output existing OWNERS file if exists.
+ if (fs.existsSync(owners_path)) {
+ console.log('Content of existing OWNERS file\n');
+ console.log(fs.readFileSync(owners_path).toString());
+ }
+
+ // Prompt cut off value to suggest owners.
+ const rl = readline.createInterface({
+ input: process.stdin,
+ output: process.stdout,
+ });
+ const input = await rl.questionAsync('Cut off at: ');
+ const cutoff = parseInt(input, 10);
+ if (isNaN(cutoff)) {
+ return;
+ }
+
+ console.log('Proposed owners');
+ list = list.filter(item => item.commits >= cutoff)
+ .sort((a, b) => a.contributor.toLowerCase().localeCompare(b.contributor.toLowerCase()));
+ for (const {contributor} of list) {
+ console.log(' ' + contributor);
+ }
+
+ // Prompt to write to OWNERS file.
+ if ((await rl.questionAsync(`Write to ${owners_path} ?`)).toLowerCase() === 'y') {
+ fs.writeFileSync(owners_path, list.map(e => e.contributor).join('\n') + '\n');
+ await exec(`git add ${owners_path}`);
+ }
+
+ rl.close();
+})();