Skip to content

Commit

Permalink
Mojo: Introduce Mojo JS bindings modules
Browse files Browse the repository at this point in the history
This CL introduces generated mojom.m.js modules for mojom JS bindings,
allowing most JS bindings consumers to import bindings with the
convenience and efficiency afforded by JS modules.

These modules can be used as-is by Component Extensions, Web Platform
Tests, and Blink Web Tests. A follow-up change will introduce a slight
variation on these modules to support consumption by WebUI pages.

Bug: 1004256
Change-Id: Ic2b4a6bcadf68023d2078bf065befafce3ccb19b
Tbr: sky@chromium.org
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2451589
Commit-Queue: Ken Rockot <rockot@google.com>
Reviewed-by: Oksana Zhuravlova <oksamyt@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815471}
  • Loading branch information
krockot authored and Commit Bot committed Oct 9, 2020
1 parent faea5c3 commit 3d21f6a
Show file tree
Hide file tree
Showing 23 changed files with 1,018 additions and 259 deletions.
1 change: 1 addition & 0 deletions BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -1052,6 +1052,7 @@ if (!is_ios) {
":layout_test_data_mojo_bindings",
":layout_test_data_mojo_bindings_lite",
"//content/shell:content_shell",
"//content/test:mojo_bindings_web_test_mojom_js_data_deps",
"//content/test:mojo_web_test_bindings_js_data_deps",
"//device/bluetooth/public/mojom:fake_bluetooth_interfaces_js_data_deps",
"//device/vr/public/mojom:mojom_js_data_deps",
Expand Down
8 changes: 8 additions & 0 deletions content/test/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -799,6 +799,14 @@ mojom("test_interfaces") {
sources = [ "echo.mojom" ]
}

mojom("mojo_bindings_web_test_mojom") {
testonly = true
sources = [
"data/mojo_bindings_web_test.test-mojom",
"data/mojo_bindings_web_test_types.test-mojom",
]
}

if (is_android) {
static_library("android_test_message_pump_support") {
testonly = true
Expand Down
53 changes: 53 additions & 0 deletions content/test/data/mojo_bindings_web_test.test-mojom
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2018 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.

module mojo_bindings_test.mojom;

// NOTE: This import exists to exercise automatic dependency loading in
// generated JS modules.
import "content/test/data/mojo_bindings_web_test_types.test-mojom";

// An interface whose definition covers various types of message signatures in
// order to exercise the lite JS mojom bindings.
interface TestMessageTarget {
enum NestedEnum {
kFoo,
kBar,
};

// Zero arguments, no reply.
Poke();

// Zero-argument request, zero-argument reply.
Ping() => ();

// Request and reply both with arguments.
Repeat(string? message, array<int32>? numbers)
=> (string? message, array<int32>? numbers);

Echo(NestedEnum nested) => (NestedEnum nested);

Deconstruct(TestStruct test_struct)
=> (int32 x, int32 y,
// Using TestStruct.StructEnum causes a compile failure. Use
// int32 instead.
// TODO(crbug.com/1011660): Change |z| to TestStruct.StructEnum.
int32 z);

Flatten(array<TestStruct> values) => (array<int32> values);
FlattenUnions(array<TestUnion> unions) => (array<int32> x, array<int32> s);

RequestSubinterface(pending_receiver<Subinterface> receiver,
pending_remote<SubinterfaceClient> client);
};

interface Subinterface {
Push(int32 value);
Flush();
};

interface SubinterfaceClient {
DidFlush(array<int32> values);
};

25 changes: 25 additions & 0 deletions content/test/data/mojo_bindings_web_test_types.test-mojom
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// 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.

module mojo_bindings_test.mojom;

struct TestStruct {
enum StructEnum {
kZero = 0,
kOne = 1,
};

const int32 kStructConst = 2;

int32 x;
int32 y = kStructConst;
StructEnum z = StructEnum.kOne;
const bool isValid = false;
};

union TestUnion {
int32 x;
TestStruct s;
};

113 changes: 100 additions & 13 deletions mojo/public/js/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -49,21 +49,68 @@ action("bindings") {
deps = [ "//mojo/public/interfaces/bindings:bindings_js__generator" ]
}

bindings_lite_sources = [
"bindings_lite.js",
"interface_support.js",
]
template("concatenate_files") {
action(target_name) {
script = "//mojo/public/tools/bindings/concatenate-files.py"
inputs = invoker.inputs
output = "$target_gen_dir/${invoker.output}"
outputs = [ output ]
args = rebase_path(inputs, root_build_dir) +
[ rebase_path(output, root_build_dir) ]
if (defined(invoker.deps)) {
deps = invoker.deps
}
}
}

concatenate_files("generate_mojo_internal_js") {
inputs = [
"mojo_internal_preamble.js.part",
"bindings_lite.js",
]
output = "mojo_internal.js"
}

bindings_lite_compiled_file = "$target_gen_dir/mojo_bindings_lite.js"
concatenate_files("generate_interface_support_js") {
inputs = [
"interface_support_preamble.js.part",
"interface_support.js",
]
output = "interface_support.js"
}

js_library("bindings_lite_sources") {
sources = [ "compile_preamble.js" ] + bindings_lite_sources
sources = [
"$target_gen_dir/interface_support.js",
"$target_gen_dir/mojo_internal.js",
"compile_preamble.js",
]
deps = [ "//mojo/public/interfaces/bindings:bindings_js_library_for_compile" ]
extra_deps = [
":generate_interface_support_js",
":generate_mojo_internal_js",
]
}

# All generated mojom JS modules consume the API defined by this module. The
# uncompiled source is simply a concatenation of the various pieces listed
# below.
concatenate_files("bindings_uncompiled_module") {
inputs = [
"bindings_module_preamble.js.part",
"bindings_lite.js",
"$root_gen_dir/mojo/public/interfaces/bindings/interface_control_messages.mojom-lite.js",
"interface_support.js",
"bindings_uncompiled_module_export.js.part",
]
output = "bindings_uncompiled.m.js"
deps = [ "//mojo/public/interfaces/bindings:bindings_js_library" ]
}

if (enable_mojom_closure_compile || enable_js_type_check) {
js_binary("bindings_lite") {
outputs = [ bindings_lite_compiled_file ]
outputs = [ "$target_gen_dir/mojo_bindings_lite.js" ]
sources = []
deps = [ ":bindings_lite_sources" ]
externs_list = [
"$externs_path/mojo_core.js",
Expand All @@ -78,18 +125,58 @@ if (enable_mojom_closure_compile || enable_js_type_check) {
"isolation_mode=IIFE",
]
}

concatenate_files("bindings_compiled_module") {
inputs = [
"$target_gen_dir/mojo_bindings_lite.js",
"bindings_module_export.js.part",
]
output = "bindings_compiled.m.js"
deps = [ ":bindings_lite" ]
}

copy("bindings_module") {
sources = [ "$target_gen_dir/bindings_compiled.m.js" ]
outputs = [ "$target_gen_dir/bindings.m.js" ]
deps = [ ":bindings_compiled_module" ]
}
} else {
action("bindings_lite") {
all_sources = bindings_lite_sources + [ "$root_gen_dir/mojo/public/interfaces/bindings/interface_control_messages.mojom-lite.js" ]
inputs = [
"$target_gen_dir/mojo_internal.js",
"$root_gen_dir/mojo/public/interfaces/bindings/interface_control_messages.mojom-lite-for-compile.js",
"$target_gen_dir/interface_support.js",
]
script = "//mojo/public/tools/bindings/concatenate_and_replace_closure_exports.py"
sources = all_sources
outputs = [ bindings_lite_compiled_file ]
args = rebase_path(all_sources, root_build_dir) +
[ rebase_path(bindings_lite_compiled_file, root_build_dir) ]
deps = [ "//mojo/public/interfaces/bindings:bindings_js__generator" ]
sources = inputs
outputs = [ "$target_gen_dir/mojo_bindings_lite.js" ]
args =
rebase_path(inputs, root_build_dir) +
[ rebase_path("$target_gen_dir/mojo_bindings_lite.js", root_build_dir) ]
deps = [
":generate_interface_support_js",
":generate_mojo_internal_js",
"//mojo/public/interfaces/bindings:bindings_js__generator",
]
}

copy("bindings_module") {
sources = [ "$target_gen_dir/bindings_uncompiled.m.js" ]
outputs = [ "$target_gen_dir/bindings.m.js" ]
deps = [ ":bindings_uncompiled_module" ]
}
}

# This is the library target used in the dependency tree of any JS libraries
# or binaries compiling against mojom JS bindings. This library is functionally
# equivalent to the bindings.m.js generated by the ":bindings_module" target and
# used at runtime by all consumers, except that this module includes all type
# annotations and is suitable for Closure compilation and type checking.
js_library("bindings_uncompiled.m") {
sources = [ "$target_gen_dir/bindings_uncompiled.m.js" ]
extra_deps = [ ":bindings_uncompiled_module" ]
}

grit("resources") {
source = "mojo_bindings_resources.grd"

Expand Down
27 changes: 0 additions & 27 deletions mojo/public/js/bindings_lite.js
Original file line number Diff line number Diff line change
@@ -1,33 +1,6 @@
// Copyright 2018 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.
'use strict';

goog.provide('mojo.internal');

// "self" is always defined as opposed to "this", which isn't defined in
// modules, or "window", which isn't defined in workers.
/** @const {!Object} */
mojo.internal.globalScope = self;

/**
* This is effectively the same as goog.provide, but it's made available under
* the mojo.internal namespace to avoid potential collisions in certain
* compilation environments.
*
* @param {string} namespace
* @export
*/
mojo.internal.exportModule = function(namespace) {
let current = mojo.internal.globalScope;
const parts = namespace.split('.');

for (let part; parts.length && (part = parts.shift());) {
if (!current[part])
current[part] = {};
current = current[part];
}
};

/** @const {number} */
mojo.internal.kArrayHeaderSize = 8;
Expand Down
3 changes: 3 additions & 0 deletions mojo/public/js/bindings_module_export.js.part
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const mojoTmp = self['mojo'];
delete self['mojo'];
export const mojo = mojoTmp;
4 changes: 4 additions & 0 deletions mojo/public/js/bindings_module_preamble.js.part
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const mojo = {
internal: { interfaceSupport: {} },
interfaceControl: {}
};
1 change: 1 addition & 0 deletions mojo/public/js/bindings_uncompiled_module_export.js.part
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export {mojo};
8 changes: 0 additions & 8 deletions mojo/public/js/interface_support.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,6 @@
// Copyright 2018 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.
'use strict';

goog.require('mojo.interfaceControl.RUN_MESSAGE_ID');
goog.require('mojo.interfaceControl.RunResponseMessageParamsSpec');
goog.require('mojo.internal');

goog.provide('mojo.internal.interfaceSupport');


/**
* Handles incoming interface control messages on a remote or router endpoint.
Expand Down
8 changes: 8 additions & 0 deletions mojo/public/js/interface_support_preamble.js.part
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'use strict';

goog.require('mojo.interfaceControl.RUN_MESSAGE_ID');
goog.require('mojo.interfaceControl.RunResponseMessageParamsSpec');
goog.require('mojo.internal');

goog.provide('mojo.internal.interfaceSupport');

27 changes: 27 additions & 0 deletions mojo/public/js/mojo_internal_preamble.js.part
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
'use strict';

goog.provide('mojo.internal');

// "self" is always defined as opposed to "this", which isn't defined in
// modules, or "window", which isn't defined in workers.
/** @const {!Object} */
mojo.internal.globalScope = self;

/**
* This is effectively the same as goog.provide, but it's made available under
* the mojo.internal namespace to avoid potential collisions in certain
* compilation environments.
*
* @param {string} namespace
* @export
*/
mojo.internal.exportModule = function(namespace) {
let current = mojo.internal.globalScope;
const parts = namespace.split('.');

for (let part; parts.length && (part = parts.shift());) {
if (!current[part])
current[part] = {};
current = current[part];
}
};
5 changes: 5 additions & 0 deletions mojo/public/tools/bindings/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -69,11 +69,16 @@ action("precompile_templates") {
"$mojom_generator_root/generators/js_templates/fuzzing.tmpl",
"$mojom_generator_root/generators/js_templates/interface_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/enum_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/enum_definition_for_module.tmpl",
"$mojom_generator_root/generators/js_templates/lite/interface_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/interface_definition_for_module.tmpl",
"$mojom_generator_root/generators/js_templates/lite/module_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/mojom-lite.js.tmpl",
"$mojom_generator_root/generators/js_templates/lite/mojom.m.js.tmpl",
"$mojom_generator_root/generators/js_templates/lite/struct_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/struct_definition_for_module.tmpl",
"$mojom_generator_root/generators/js_templates/lite/union_definition.tmpl",
"$mojom_generator_root/generators/js_templates/lite/union_definition_for_module.tmpl",
"$mojom_generator_root/generators/js_templates/module.amd.tmpl",
"$mojom_generator_root/generators/js_templates/module_definition.tmpl",
"$mojom_generator_root/generators/js_templates/struct_definition.tmpl",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,24 +1,13 @@
{%- macro enum_def(enum_spec_parent, enum_parent, enum) -%}
{# TODO: Less generic enum annotations would be nice. We do it this way because
the bindings generator is still too stupid to generate the right integral
constants directly. #}
{%- set enum_name = enum|lite_closure_type -%}

{% if generate_closure_exports -%}
goog.provide('{{enum_name}}');
goog.provide('{{enum_spec_parent}}.{{enum.name}}Spec');
{%- endif %}
{%- macro enum_def(enum) -%}
/**
* @const { {$: !mojo.internal.MojomType} }
* @export
*/
{{enum_spec_parent}}.{{enum.name}}Spec = { $: mojo.internal.Enum() };
export const {{enum|type_in_js_module}}Spec = { $: mojo.internal.Enum() };

/**
* @enum {number}
* @export
*/
{{enum_name}} = {
export const {{enum|type_in_js_module}} = {
{# Set up the enum here, but fill out the values later. #}
{%- for field in enum.fields %}
{{field.name}}: {{field.numeric_value}},
Expand Down
Loading

0 comments on commit 3d21f6a

Please sign in to comment.