build: highlight example sources files with bazel (#14325)

Part of #13454
This commit is contained in:
Paul Gschwendtner
2018-11-30 00:46:46 +01:00
committed by Jeremy Elbourn
parent 6347ace05e
commit bb19dfc685
9 changed files with 174 additions and 10 deletions
+6
View File
@@ -3,6 +3,7 @@ package(default_visibility=["//visibility:public"])
load("@angular//:index.bzl", "ng_package")
load("//:packages.bzl", "CDK_TARGETS", "MATERIAL_TARGETS", "ROLLUP_GLOBALS")
load("//tools:defaults.bzl", "ng_module")
load("//tools/highlight-files:index.bzl", "highlight_files")
ng_module(
name = "examples",
@@ -21,6 +22,11 @@ ng_module(
tsconfig = ":tsconfig-build.json",
)
highlight_files(
name = "highlighted-files",
srcs = glob(["*/*.html", "*/*.css", "*/*.ts"])
)
ng_package(
name = "npm_package",
srcs = ["package.json"],
+21
View File
@@ -0,0 +1,21 @@
package(default_visibility = ["//visibility:public"])
load("@build_bazel_rules_nodejs//:defs.bzl", "nodejs_binary")
load("//tools:defaults.bzl", "ts_library")
nodejs_binary(
name = "highlight-files",
entry_point = "angular_material/tools/highlight-files/highlight-files.js",
data = [
"@matdeps//highlight.js",
"@matdeps//source-map-support",
":sources",
],
)
ts_library(
name = "sources",
srcs = glob(["**/*.ts"]),
deps = ["@matdeps//@types/node"],
tsconfig = ":tsconfig.json",
)
+45
View File
@@ -0,0 +1,45 @@
/**
* Script that will be used by the highlight_files Bazel rule in order to highlight
* multiple input files using highlight.js. The output will be HTML files.
*/
import {readFileSync, writeFileSync} from 'fs';
import {extname, join} from 'path';
import {highlightCodeBlock} from './highlight-code-block';
/**
* 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 bazel-bin path as first argument. All remaining arguments will be
// considered as markdown input files that need to be transformed.
const [bazelBinPath, ...inputFiles] = getBazelActionArguments();
// Walk through each input file and write transformed markdown output to the specified
// Bazel bin directory.
inputFiles.forEach(inputPath => {
const fileExtension = extname(inputPath).substring(1);
// Convert "my-component-example.ts" into "my-component-example-ts.html"
const baseOutputPath = inputPath.replace(`.${fileExtension}`, `-${fileExtension}.html`);
const outputPath = join(bazelBinPath, baseOutputPath);
const htmlOutput = highlightCodeBlock(readFileSync(inputPath, 'utf8'), fileExtension);
writeFileSync(outputPath, htmlOutput);
});
}
+83
View File
@@ -0,0 +1,83 @@
"""
Gets a path relative to the specified label. This is achieved by just removing the label
package path from the specified path. e.g. the path is "guides/test/my-text.md" and the
label package is "guides/". The expected path would be "test/my-text.md".
"""
def _relative_to_label(label, short_path):
# TODO(devversion): extract into generic utility under tools/
return short_path[len(label.package) + 1:]
"""
Implementation of the "highlight_files" rule. The implementation runs the
highlight-files executable in order to highlight the specified source files.
"""
def _highlight_files(ctx):
input_files = ctx.files.srcs;
args = ctx.actions.args()
expected_outputs = [];
# Do nothing if there are no input files. Bazel will throw if we schedule an action
# that returns no outputs.
if not input_files:
return None
# 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")
# Add the bazel bin directory to the command arguments. The script needs to know about
# the output directory because the input files are not in the same location as the bazel
# bin directory.
args.add(ctx.bin_dir.path)
for input_file in input_files:
# Extension of the input file (e.g. "ts" or "css")
file_extension = input_file.extension
# Determine the input file path relatively to the current package path. This is necessary
# because we want to preserve directories for the input files and `declare_file` expects a
# path that is relative to the current package. We remove the file extension including the dot
# because we will constructo an output file using a different extension.
relative_basepath = _relative_to_label(ctx.label, input_file.short_path)[
:-len(file_extension) - 1]
# Construct the output path from the relative basepath and file extension. For example:
# "autocomplete.ts" should result in "autocomplete-ts.html".
expected_outputs += [
ctx.actions.declare_file("%s-%s.html" % (relative_basepath, file_extension)),
]
# Add the path for the input file to the command line arguments, so that the executable
# can process it.
args.add(input_file.path)
# Run the highlight-files executable that highlights the specified source files.
ctx.actions.run(
inputs = input_files,
executable = ctx.executable._highlight_files,
outputs = expected_outputs,
arguments = [args],
)
return DefaultInfo(files = depset(expected_outputs))
"""
Rule definition for the "highlight_files" rule that can accept arbritary source files
that will be transformed into HTML files which reflect the highlighted source code of
the given files. The outputs can be referenced through the default output provider.
"""
highlight_files = rule(
implementation = _highlight_files,
attrs = {
"srcs": attr.label_list(allow_files = True),
# Executable for this rule that is responsible for highlighting the specified
# input files.
"_highlight_files": attr.label(
default = Label("//tools/highlight-files"),
executable = True,
cfg = "host"
)},
)
+12
View File
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"lib": ["es2015"],
"module": "commonjs",
"target": "es5",
"sourceMap": true,
"types": ["node"]
},
"bazelOptions": {
"suppressTsconfigOverrideWarnings": true
}
}
+2 -1
View File
@@ -8,7 +8,8 @@ ts_library(
srcs = glob(["**/*.ts"]),
deps = [
"@matdeps//@types/node",
"@matdeps//@types/marked"
"@matdeps//@types/marked",
"//tools/highlight-files:sources",
],
tsconfig = ":tsconfig.json",
)
@@ -1,6 +1,5 @@
import {MarkedOptions, Renderer} from 'marked';
import {Renderer} from 'marked';
import {basename, extname} from 'path';
import {highlightCodeBlock} from './highlight-code-block';
/** Regular expression that matches whitespace. */
const whitespaceRegex = /\W+/g;
@@ -14,10 +13,6 @@ const exampleCommentRegex = /<!--\W*example\(([^)]+)\)\W*-->/g;
*/
export class DocsMarkdownRenderer extends Renderer {
constructor(options?: MarkedOptions) {
super({highlight: highlightCodeBlock, baseUrl: 'material.angular.io/', ...options});
}
/**
* Transforms a markdown heading into the corresponding HTML output. In our case, we
* want to create a header-link for each H3 and H4 heading. This allows users to jump to
+4 -3
View File
@@ -4,9 +4,10 @@
*/
import {readFileSync, writeFileSync} from 'fs';
import {join} from 'path';
import {DocsMarkdownRenderer} from './docs-marked-renderer';
import * as marked from 'marked';
import {join} from 'path';
import {highlightCodeBlock} from '../highlight-files/highlight-code-block';
import {DocsMarkdownRenderer} from './docs-marked-renderer';
// Regular expression that matches the markdown extension of a given path.
const markdownExtension = /.md$/;
@@ -15,7 +16,7 @@ const markdownExtension = /.md$/;
const markdownRenderer = new DocsMarkdownRenderer();
// Setup our custom docs renderer by default.
marked.setOptions({renderer: markdownRenderer});
marked.setOptions({renderer: markdownRenderer, highlight: highlightCodeBlock});
if (require.main === module) {
// The script expects the bazel-bin path as first argument. All remaining arguments will be