Skip to content

build: package docs content into npm package #14411

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions src/material-examples/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package(default_visibility=["//visibility:public"])

load("//:packages.bzl", "CDK_TARGETS", "MATERIAL_TARGETS", "ROLLUP_GLOBALS")
load("//:packages.bzl", "CDK_TARGETS", "MATERIAL_TARGETS", "ROLLUP_GLOBALS", "MATERIAL_PACKAGES",
"CDK_PACKAGES")
load("//tools:defaults.bzl", "ng_module", "ng_package")
load("//tools/highlight-files:index.bzl", "highlight_files")
load("//tools/package-docs-content:index.bzl", "package_docs_content")

ng_module(
name = "examples",
Expand All @@ -21,17 +23,56 @@ ng_module(
tsconfig = ":tsconfig-build.json",
)

highlight_files(
name = "highlighted-files",
filegroup(
name = "example-source-files",
srcs = glob(["*/*.html", "*/*.css", "*/*.ts"])
)

filegroup(
name = "material-overviews",
srcs = ["//src/lib/%s:overview" % name for name in MATERIAL_PACKAGES]
)

filegroup(
name = "cdk-overviews",
srcs = ["//src/cdk/%s:overview" % name for name in CDK_PACKAGES]
)

highlight_files(
name = "highlighted-source-files",
srcs = [":example-source-files"]
)

package_docs_content(
name = "docs-content",
srcs = {
# We want to package the guides in to the docs content. These will be displayed
# in the documentation.
"//guides": "guides",

# For the live-examples in our docs, we want to package the highlighted files
# into the docs content. These will be used to show the source code for examples.
":highlighted-source-files": "examples-highlighted",

# In order to be able to run examples in StackBlitz, we also want to package the
# plain source files into the docs-content.
":example-source-files": "examples-source",

# Package the overviews for "@angular/material" and "@angular/cdk" into the docs content
":material-overviews": "overviews/material",
":cdk-overviews": "overviews/cdk",

# TODO(devversion): we need to also package the API html files here
}
)

ng_package(
name = "npm_package",
srcs = ["package.json"],
entry_point = "src/material-examples/public_api.js",
globals = ROLLUP_GLOBALS,
deps = [":examples"],
data = [":docs-content"],
# TODO(devversion): re-enable once we have set up the proper compiler for the ng_package
tags = ["manual"],
)
Expand Down
20 changes: 20 additions & 0 deletions tools/package-docs-content/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package(default_visibility = ["//visibility:public"])

load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
load("//tools:defaults.bzl", "ts_library")

nodejs_binary(
name = "package-docs-content",
entry_point = "angular_material/tools/package-docs-content/package-docs-content.js",
data = [
"@matdeps//source-map-support",
":sources",
],
)

ts_library(
name = "sources",
srcs = glob(["**/*.ts"]),
deps = ["@matdeps//@types/node"],
tsconfig = ":tsconfig.json",
)
82 changes: 82 additions & 0 deletions tools/package-docs-content/index.bzl
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
"""
Implementation of the "package_docs_content" rule. The implementation runs the
packager executable in order to group all specified files into the given sections.
"""
def _package_docs_content(ctx):
# Directory that will contain all grouped input files. This directory will be created
# relatively to the current target package. (e.g. "bin/src/material-examples/docs-content")
output_dir = ctx.attr.name;

# Arguments that will be passed to the packager executable.
args = ctx.actions.args()

# List of outputs that should be generated by the packager action. Bazel will automatically
# throw an error if any output has not been generated properly.
expected_outputs = [];

# Support passing arguments through a parameter file. This is necessary because on Windows
# there is an argument limit and we need to handle a large amount of input files. Bazel
# switches between parameter file and normal argument passing based on the operating system.
# Read more here: https://docs.bazel.build/versions/master/skylark/lib/Args.html#use_param_file
args.use_param_file(param_file_arg = "--param-file=%s")

# Walk through each defined input target and the associated section and compute the
# output file which will be added to the executable arguments.
for input_target, section_name in ctx.attr.srcs.items():
section_files = input_target.files.to_list()

for input_file in section_files:
# For each input file, we want to create a copy that is stored in the output directory
# within its specified section. e.g. "pkg_bin/docs-content/guides/getting-started.html"
output_file = ctx.actions.declare_file(
"%s/%s/%s" % (output_dir, section_name, input_file.basename))

# Add the output file to the expected outputs so that Bazel throws an error if the file
# hasn't been generated properly.
expected_outputs += [output_file]

# Pass the input file path and the output file path to the packager executable. We need
# to do this for each file because we cannot determine the general path to the output
# directory in a reliable way because Bazel targets cannot just "declare" a directory.
# See: https://docs.bazel.build/versions/master/skylark/lib/actions.html
args.add("%s,%s" % (input_file.path, output_file.path))

# Do nothing if there are no input files. Bazel will throw if we schedule an action
# that returns no outputs.
if not ctx.files.srcs:
return None

# Run the packager executable that groups the specified source files and writes them
# to the given output directory.
ctx.actions.run(
inputs = ctx.files.srcs,
executable = ctx.executable._packager,
outputs = expected_outputs,
arguments = [args],
)

return DefaultInfo(files = depset(expected_outputs))

"""
Rule definition for the "package_docs_content" rule that can accept arbritary source files
that will be grouped into specified sections. This is being used to package the docs
content into a desired folder structure that can be shared with the docs application.
"""
package_docs_content = rule(
implementation = _package_docs_content,
attrs = {
# This defines the sources for the "package_docs_content" rule. Instead of just
# accepting a list of labels, this rule requires the developer to specify a label
# keyed dictionary. This allows developers to specify where specific targets
# should be grouped into. This helpful when publishing the docs content because
# the docs repository does not about the directory structure of the generated files.
"srcs": attr.label_keyed_string_dict(allow_files = True),

# Executable for this rule that is responsible for packaging the specified
# targets into the associated sections.
"_packager": attr.label(
default = Label("//tools/package-docs-content"),
executable = True,
cfg = "host"
)},
)
38 changes: 38 additions & 0 deletions tools/package-docs-content/package-docs-content.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* Script that will be dispatched by the "package_docs_content" rule and is responsible for
* copying input files to a new location. The new location will be computed within the Bazel
* rule implementation so that we don't need to compute the output paths with their sections
* multiple times.
*/

import {readFileSync, writeFileSync} from 'fs';

/**
* Determines the command line arguments for the current Bazel action. Since this action can
* have a large set of input files, Bazel may write the arguments into a parameter file.
* This function is responsible for handling normal argument passing or Bazel parameter files.
* Read more here: https://docs.bazel.build/versions/master/skylark/lib/Args.html#use_param_file
*/
function getBazelActionArguments() {
const args = process.argv.slice(2);

// If Bazel uses a parameter file, we've specified that it passes the file in the following
// format: "arg0 arg1 --param-file={path_to_param_file}"
if (args[0].startsWith('--param-file=')) {
return readFileSync(args[0].split('=')[1], 'utf8').trim().split('\n');
}

return args;
}

if (require.main === module) {
// The script expects the output path as first argument. All remaining arguments will be
// considered as markdown input files that need to be transformed.
getBazelActionArguments().forEach(argument => {
// Each argument that has been passed consists of an input file path and the expected
// output path. e.g. {path_to_input_file},{expected_output_path}
const [inputFilePath, outputPath] = argument.split(',', 2);

writeFileSync(outputPath, readFileSync(inputFilePath, 'utf8'));
});
}
12 changes: 12 additions & 0 deletions tools/package-docs-content/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"lib": ["es2015"],
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"types": ["node"]
},
"bazelOptions": {
"suppressTsconfigOverrideWarnings": true
}
}