Skip to content

build: highlight example sources files with bazel #14325

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
6 changes: 6 additions & 0 deletions src/material-examples/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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"],
Expand Down
21 changes: 21 additions & 0 deletions tools/highlight-files/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -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 changes: 45 additions & 0 deletions tools/highlight-files/highlight-files.ts
Original file line number Diff line number Diff line change
@@ -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 changes: 83 additions & 0 deletions tools/highlight-files/index.bzl
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions tools/highlight-files/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
}
}
3 changes: 2 additions & 1 deletion tools/markdown-to-html/BUILD.bazel
Original file line number Diff line number Diff line change
Expand Up @@ -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",
)
Expand Down
7 changes: 1 addition & 6 deletions tools/markdown-to-html/docs-marked-renderer.ts
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions tools/markdown-to-html/transform-markdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
*/

import {readFileSync, writeFileSync} from 'fs';
import * as marked from 'marked';
import {join} from 'path';
import {highlightCodeBlock} from '../highlight-files/highlight-code-block';
import {DocsMarkdownRenderer} from './docs-marked-renderer';
import * as marked from 'marked';

// Regular expression that matches the markdown extension of a given path.
const markdownExtension = /.md$/;
Expand All @@ -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
Expand Down