diff --git a/closure/compiler/closure_js_aspect.bzl b/closure/compiler/closure_js_aspect.bzl index 1e0ea0020f..dc0b0d8959 100644 --- a/closure/compiler/closure_js_aspect.bzl +++ b/closure/compiler/closure_js_aspect.bzl @@ -15,6 +15,8 @@ load( "//closure/private:defs.bzl", "CLOSURE_WORKER_ATTR", + "ClosureJsLegacyRunfilesInfo", + "ClosureJsLibraryInfo", "JS_FILE_TYPE", "collect_js", "collect_runfiles", @@ -26,13 +28,13 @@ load( ) def _closure_js_aspect_impl(target, ctx): - if hasattr(target, "closure_js_library"): - return struct() + if ClosureJsLibraryInfo in target: + return [] # This aspect is currently a no-op in the open source world. We intend to add # content to it in the future. It is still provided to ensure the Skylark API # is well defined. - return struct() + return [] closure_js_aspect = aspect( implementation = _closure_js_aspect_impl, diff --git a/closure/compiler/closure_js_binary.bzl b/closure/compiler/closure_js_binary.bzl index 6ca0d4bcff..2298937123 100644 --- a/closure/compiler/closure_js_binary.bzl +++ b/closure/compiler/closure_js_binary.bzl @@ -17,6 +17,9 @@ load( "//closure/private:defs.bzl", "CLOSURE_JS_TOOLCHAIN_ATTRS", + "ClosureCssBinaryInfo", + "ClosureJsBinaryInfo", + "ClosureJsLibraryInfo", "JS_LANGUAGES", "JS_LANGUAGE_IN", "JS_LANGUAGE_OUT_DEFAULT", @@ -78,7 +81,7 @@ def _impl(ctx): ", ".join(JS_LANGUAGES.to_list()), )) - deps = unfurl(ctx.attr.deps, provider = "closure_js_library") + deps = unfurl(ctx.attr.deps, provider = ClosureJsLibraryInfo).exports js = collect_js(deps, ctx.attr._closure_library_base, css = ctx.attr.css) if not js.srcs: fail("There are no JS source files in the transitive closure") @@ -281,27 +284,26 @@ def _impl(ctx): # promise to compile. Its fulfillment is the prerogative of ancestors which # are free to ignore the binary in favor of the raw sauces propagated by the # closure_js_library provider, in which case, no compilation is performed. - return struct( - files = depset(files), - closure_js_library = js, - closure_js_binary = struct( + return [ + ClosureJsBinaryInfo( bin = ctx.outputs.bin, map = ctx.outputs.map, language = ctx.attr.language, ), - runfiles = ctx.runfiles( + js, + DefaultInfo(files = depset(files), runfiles = ctx.runfiles( files = files + ctx.files.data, transitive_files = depset(transitive = [ collect_runfiles(deps), collect_runfiles([ctx.attr.css]), collect_runfiles(ctx.attr.data), ]), - ), - ) + )), + ] def _validate_css_graph(ctx, js): if ctx.attr.css: - missing = difference(js.stylesheets, ctx.attr.css.closure_css_binary.labels) + missing = difference(js.stylesheets, ctx.attr.css[ClosureCssBinaryInfo].labels) if missing: fail("Dependent JS libraries depend on CSS libraries that weren't " + "compiled into the referenced CSS binary: " + @@ -315,7 +317,7 @@ closure_js_binary = rule( implementation = _impl, attrs = dict({ "compilation_level": attr.string(default = "ADVANCED"), - "css": attr.label(providers = ["closure_css_binary"]), + "css": attr.label(providers = [ClosureCssBinaryInfo]), "debug": attr.bool(default = False), "defs": attr.string_list(), # TODO(tjgq): Remove the deprecated STRICT/LOOSE in favor of PRUNE/PRUNE_LEGACY. @@ -332,7 +334,7 @@ closure_js_binary = rule( ), "deps": attr.label_list( aspects = [closure_js_aspect], - providers = ["closure_js_library"], + providers = [ClosureJsLibraryInfo], ), "entry_points": attr.string_list(), "formatting": attr.string(), diff --git a/closure/compiler/closure_js_library.bzl b/closure/compiler/closure_js_library.bzl index bfb93b712c..828c8fc8a5 100644 --- a/closure/compiler/closure_js_library.bzl +++ b/closure/compiler/closure_js_library.bzl @@ -17,6 +17,8 @@ load( "//closure/private:defs.bzl", "CLOSURE_JS_TOOLCHAIN_ATTRS", + "ClosureCssLibraryInfo", + "ClosureJsLibraryInfo", "JS_FILE_TYPE", "JS_LANGUAGE_IN", "collect_js", @@ -163,7 +165,7 @@ def _closure_js_library_impl( # Create a list of direct children of this rule. If any direct dependencies # have the exports attribute, those labels become direct dependencies here. - deps = unfurl(deps, provider = "closure_js_library") + deps = unfurl(deps, provider = ClosureJsLibraryInfo).exports # Collect all the transitive stuff the child rules have propagated. Bazel has # a special nested set data structure that makes this efficient. @@ -177,7 +179,7 @@ def _closure_js_library_impl( # which is a superset of the CSS libraries in its transitive closure. stylesheets = [] for dep in deps: - if hasattr(dep, "closure_css_library"): + if ClosureCssLibraryInfo in dep: stylesheets.append(dep.label) # JsChecker is a program that's run via the ClosureWorker persistent Bazel @@ -263,7 +265,7 @@ def _closure_js_library_impl( info_files = [] for dep in deps: # Polymorphic rules, e.g. closure_css_library, might not provide this. - info = getattr(dep.closure_js_library, "info", None) + info = getattr(dep[ClosureJsLibraryInfo], "info", None) if info: args.add("--dep", info) info_files.append(info) @@ -303,7 +305,7 @@ def _closure_js_library_impl( # interface because other Skylark rules can be designed to do things with # this data. Other Skylark rules can even export their own provider with the # same name to become polymorphically compatible with this one. - return struct( + return [ # Iterable of deps that should only become deps in parent rules. # Exports are not deps of the Target to which they belong. The exports # provider does not contain the exports its deps export. Targets in this @@ -320,10 +322,10 @@ def _closure_js_library_impl( # the exports attribute does not exist. The exports feature can be abused # by users to circumvent strict deps checking and therefore should be # used with caution. - exports = unfurl(exports), + unfurl(exports), # All of the subproviders below are considered optional and MUST be # accessed using getattr(x, y, default). See collect_js() in defs.bzl. - closure_js_library = struct( + ClosureJsLibraryInfo( # File pointing to a ClosureJsLibrary protobuf file in pbtxt format # that's generated by this specific Target. It contains some metadata # as well as information extracted from inside the srcs files, e.g. @@ -366,7 +368,7 @@ def _closure_js_library_impl( # of the srcs subprovider. This field exists for optimization. has_closure_library = js.has_closure_library, ), - ) + ] def _closure_js_library(ctx): if not ctx.files.srcs and not ctx.files.externs and not ctx.attr.exports: @@ -407,22 +409,22 @@ def _closure_js_library(ctx): ctx.outputs.typecheck, ) - return struct( - files = depset(), - exports = library.exports, - closure_js_library = library.closure_js_library, - # The usual suspects are exported as runfiles, in addition to raw source. - runfiles = ctx.runfiles( - files = srcs + ctx.files.data, - transitive_files = depset( - transitive = [ - collect_runfiles(unfurl(ctx.attr.deps, provider = "closure_js_library")), - collect_runfiles(ctx.attr.data), - collect_runfiles(library.exports), - ], + return library + [ + DefaultInfo( + files = depset(), + # The usual suspects are exported as runfiles, in addition to raw source. + runfiles = ctx.runfiles( + files = srcs + ctx.files.data, + transitive_files = depset( + transitive = [ + collect_runfiles(unfurl(ctx.attr.deps, provider = ClosureJsLibraryInfo).exports), + collect_runfiles(ctx.attr.data), + collect_runfiles(unfurl(ctx.attr.exports).exports), + ], + ), ), ), - ) + ] closure_js_library = rule( implementation = _closure_js_library, @@ -435,11 +437,11 @@ closure_js_library = rule( "data": attr.label_list(allow_files = True), "deps": attr.label_list( aspects = [closure_js_aspect], - providers = ["closure_js_library"], + providers = [ClosureJsLibraryInfo], ), "exports": attr.label_list( aspects = [closure_js_aspect], - providers = ["closure_js_library"], + providers = [ClosureJsLibraryInfo], ), "includes": attr.string_list(), "no_closure_library": attr.bool(), diff --git a/closure/private/defs.bzl b/closure/private/defs.bzl index 659446a98e..806c623970 100644 --- a/closure/private/defs.bzl +++ b/closure/private/defs.bzl @@ -61,6 +61,84 @@ CLOSURE_JS_TOOLCHAIN_ATTRS = { "_unusable_type_definition": UNUSABLE_TYPE_DEFINITION, } +ClosureJsLibraryInfo = provider("ClosureJsLibraryInfo", fields = { + "info": """ +File pointing to a ClosureJsLibrary protobuf file in pbtxt format +that's generated by this specific Target. It contains some metadata +as well as information extracted from inside the srcs files, e.g. +goog.provide'd namespaces. It is used for strict dependency +checking, a.k.a. layering checks. +""", + "infos": """ +NestedSet of all info files in the transitive closure. This +is used by JsCompiler to apply error suppression on a file-by-file +basis.""", + "ijs": "", + "ijs_files": "", + "srcs": """ +NestedSet of all JavaScript source File artifacts in the +transitive closure. These files MUST be JavaScript.""", + "js_module_roots": """ +NestedSet of all execroot path prefixes in the transitive +closure. For very simple projects, it will be empty. It is useful +for getting rid of Bazel generated directories, workspace names, +etc. out of module paths. It contains the cartesian product of +generated roots, external repository roots, and includes +prefixes. This is passed to JSCompiler via the --js_module_root +flag. See find_js_module_roots() in defs.bzl. """, + "modules": """ +NestedSet of all ES6 module name strings in the transitive +closure. These are generated from the source file path relative to +the longest matching root prefix. It is used to guarantee that +within any given transitive closure, no namespace collisions +exist. These MUST NOT begin with "/" or ".", or contain "..".""", + "descriptors": """ +NestedSet of all protobuf definitions in the transitive +closure. It is used so Closure Templates can have information about +the structure of protobufs so they can be easily rendered in .soy +files with type safety. See closure_js_template_library.bzl.""", + "stylesheets": """ +NestedSet