mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
build: add rules for generating block/element API data (#52480)
Adds build rules for "artificially" generating `DocEntry` collections for block and element APIs. The two rules are very similar, but _just_ different enough that it's worth having two separate implementations. PR Close #52480
This commit is contained in:
parent
a3abe1671c
commit
64db486edc
18 changed files with 613 additions and 3 deletions
|
|
@ -1168,10 +1168,11 @@ groups:
|
|||
'tools/esm-interop/**/{*,.*}',
|
||||
'tools/gulp-tasks/**/{*,.*}',
|
||||
'tools/legacy-saucelabs/**/{*,.*}',
|
||||
'tools/manual_api_docs/**/{*,.*}',
|
||||
'tools/npm-patches/**/{*,.*}',
|
||||
'tools/rxjs/**/{*,.*}',
|
||||
'tools/saucelabs/**/{*,.*}',
|
||||
'tools/saucelabs-daemon/**/{*,.*}',
|
||||
'tools/saucelabs/**/{*,.*}',
|
||||
'tools/symbol-extractor/**/{*,.*}',
|
||||
'tools/testing/**/{*,.*}',
|
||||
'tools/tslint/**/{*,.*}',
|
||||
|
|
|
|||
37
tools/manual_api_docs/BUILD.bazel
Normal file
37
tools/manual_api_docs/BUILD.bazel
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
load("//tools:defaults.bzl", "nodejs_binary", "ts_library")
|
||||
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
ts_library(
|
||||
name = "generate_element_api_json_lib",
|
||||
srcs = ["generate_element_api_json.ts"],
|
||||
deps = [
|
||||
"//packages/compiler-cli",
|
||||
"@npm//@types/node",
|
||||
],
|
||||
)
|
||||
|
||||
nodejs_binary(
|
||||
name = "generate_element_api_json",
|
||||
data = [
|
||||
":generate_element_api_json_lib",
|
||||
],
|
||||
entry_point = ":generate_element_api_json.ts",
|
||||
)
|
||||
|
||||
ts_library(
|
||||
name = "generate_block_api_json_lib",
|
||||
srcs = ["generate_block_api_json.ts"],
|
||||
deps = [
|
||||
"//packages/compiler-cli",
|
||||
"@npm//@types/node",
|
||||
],
|
||||
)
|
||||
|
||||
nodejs_binary(
|
||||
name = "generate_block_api_json",
|
||||
data = [
|
||||
":generate_block_api_json_lib",
|
||||
],
|
||||
entry_point = ":generate_block_api_json.ts",
|
||||
)
|
||||
6
tools/manual_api_docs/blocks/BUILD.bazel
Normal file
6
tools/manual_api_docs/blocks/BUILD.bazel
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
load("//tools/manual_api_docs:generate_block_api_json.bzl", "generate_block_api_json")
|
||||
|
||||
generate_block_api_json(
|
||||
name = "blocks",
|
||||
srcs = glob(["*.md"]),
|
||||
)
|
||||
63
tools/manual_api_docs/blocks/defer.md
Normal file
63
tools/manual_api_docs/blocks/defer.md
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
A type of [block](api/core/defer) that can be used to defer load the JavaScript for components,
|
||||
directives and pipes used inside a component template.
|
||||
|
||||
## Syntax
|
||||
|
||||
```html
|
||||
@defer ( on <trigger>; when <condition>; prefetch on <trigger>; prefetch when <condition> ) {
|
||||
<!-- deferred template fragment -->
|
||||
<calendar-cmp />
|
||||
} @placeholder ( minimum? <duration> ) {
|
||||
<!-- placeholder template fragment -->
|
||||
<p>Placeholder</p>
|
||||
} @loading ( minimum? <duration>; after? <duration> ) {
|
||||
<!-- loading template fragment -->
|
||||
<img alt="loading image" src="loading.gif" />
|
||||
} @error {
|
||||
<!-- error template fragment -->
|
||||
<p>An loading error occured</p>
|
||||
}
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
### Blocks
|
||||
|
||||
Supported sections of a defer block. Note: only the @defer block template fragment is deferred
|
||||
loaded. The remaining optional blocks are eagerly loaded.
|
||||
|
||||
| block | Description |
|
||||
|----------------|----------------------------------------------------------|
|
||||
| `@defer` | The defer loaded block of content |
|
||||
| `@placeholder` | Content shown prior to defer loading (Optional) |
|
||||
| `@loading` | Content shown during defer loading (Optional) |
|
||||
| `@error` | Content shown when defer loading errors occur (Optional) |
|
||||
|
||||
<h3>Triggers</h3>
|
||||
|
||||
Triggers provide conditions for when defer loading occurs. Some allow a template reference variable
|
||||
as an optional parameter. Separate multiple triggers with a semicolon.
|
||||
|
||||
| trigger | Triggers... |
|
||||
|---------------------------------|-----------------------------------------------|
|
||||
| `on idle` | when the browser reports idle state (default) |
|
||||
| `on viewport(<elementRef>?)` | when the element enters the viewport |
|
||||
| `on interaction(<elementRef>?)` | when clicked, touched, or focused |
|
||||
| `on hover(<elementRef>?)` | when element has been hovered |
|
||||
| `on immediate` | when the page finishes rendering |
|
||||
| `on timer(<duration>)` | after a specific timeout |
|
||||
| `when <condition>` | on a custom condition |
|
||||
|
||||
<h2>Prefetch</h2>
|
||||
|
||||
Configures prefetching of the defer block used in the `@defer` parameters, but does not affect
|
||||
rendering. Rendering is handled by the standard `on` and `when` conditions. Separate multiple
|
||||
prefetch configurations with a semicolon.
|
||||
|
||||
```html
|
||||
@defer (prefetch on <trigger>; prefetch when <condition>) {
|
||||
<!-- deferred template fragment -->
|
||||
}
|
||||
```
|
||||
|
||||
Learn more in the [defer loading guide](guide/defer).
|
||||
54
tools/manual_api_docs/blocks/for.md
Normal file
54
tools/manual_api_docs/blocks/for.md
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
The `@for` block repeatedly renders content of a block for each item in a collection.
|
||||
|
||||
## Syntax
|
||||
|
||||
```html
|
||||
@for (item of items; track item.name) {
|
||||
<li> {{ item.name }} </li>
|
||||
} @empty {
|
||||
<li> There are no items. </li>
|
||||
}
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
The `@for` block renders its content in response to changes in a collection. Collections can be any
|
||||
JavaScript [iterable](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols),
|
||||
but there are performance advantages of using a regular `Array`.
|
||||
|
||||
You can optionally include an `@empty` section immediately after the `@for` block content. The
|
||||
content of the `@empty` block displays when there are no items.
|
||||
|
||||
<h3> track and objects identity </h3>
|
||||
|
||||
The value of the `track` expression determines a key used to associate array items with the views in
|
||||
the DOM. Having clear indication of the item identity allows Angular to execute a minimal set of DOM
|
||||
operations as items are added, removed or moved in a collection.
|
||||
|
||||
Loops over immutable data without `trackBy` as one of the most common causes for performance issues
|
||||
across Angular applications. Because of the potential for poor performance, the `track` expression
|
||||
is required for the `@for` loops. When in doubt, using `track $index` is a good default.
|
||||
|
||||
<h3> `$index` and other contextual variables </h3>
|
||||
|
||||
Inside `@for` contents, several implicit variables are always available:
|
||||
|
||||
| Variable | Meaning |
|
||||
| -------- | ------- |
|
||||
| `$count` | Number of items in a collection iterated over |
|
||||
| `$index` | Index of the current row |
|
||||
| `$first` | Whether the current row is the first row |
|
||||
| `$last` | Whether the current row is the last row |
|
||||
| `$even` | Whether the current row index is even |
|
||||
| `$odd` | Whether the current row index is odd |
|
||||
|
||||
These variables are always available with these names, but can be aliased via a `let` segment:
|
||||
|
||||
```html
|
||||
@for (item of items; track item.id; let idx = $index, e = $even) {
|
||||
Item #{{ idx }}: {{ item.name }}
|
||||
}
|
||||
```
|
||||
|
||||
The aliasing is especially useful in case of using nested `@for` blocks where contextual variable
|
||||
names could collide.
|
||||
27
tools/manual_api_docs/blocks/if.md
Normal file
27
tools/manual_api_docs/blocks/if.md
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
The `@if` block conditionally displays its content when its condition expression is truthy.
|
||||
|
||||
## Syntax
|
||||
|
||||
```html
|
||||
@if (a > b) {
|
||||
{{a}} is greater than {{b}}
|
||||
} @else if (b > a) {
|
||||
{{a}} is less than {{b}}
|
||||
} @else {
|
||||
{{a}} is equal to {{b}}
|
||||
}
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
Content is added and removed from the DOM based on the evaluation of conditional expressions in
|
||||
the `@if` and `@else` blocks.
|
||||
|
||||
The built-in `@if` supports referencing of expression results to keep a solution for common coding
|
||||
patterns:
|
||||
|
||||
```html
|
||||
@if (users$ | async; as users) {
|
||||
{{ users.length }}
|
||||
}
|
||||
```
|
||||
29
tools/manual_api_docs/blocks/switch.md
Normal file
29
tools/manual_api_docs/blocks/switch.md
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
The `@switch` block is inspired by the JavaScript `switch` statement:
|
||||
|
||||
## Syntax
|
||||
|
||||
```html
|
||||
@switch (condition) {
|
||||
@case (caseA) {
|
||||
Case A.
|
||||
}
|
||||
@case (caseB) {
|
||||
Case B.
|
||||
}
|
||||
@default {
|
||||
Default case.
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Description
|
||||
|
||||
The `@switch` blocks displays content selected by one of the cases matching against the conditional
|
||||
expression. The value of the conditional expression is compared to the case expression using
|
||||
the `===` operator.
|
||||
|
||||
The `@default` block is optional and can be omitted. If no `@case` matches the expression and there
|
||||
is no `@default` block, nothing is shown.
|
||||
|
||||
**`@switch` does not have fallthrough**, so you do not need an equivalent to a `break` or `return`
|
||||
statement.
|
||||
6
tools/manual_api_docs/elements/BUILD.bazel
Normal file
6
tools/manual_api_docs/elements/BUILD.bazel
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
load("//tools/manual_api_docs:generate_element_api_json.bzl", "generate_element_api_json")
|
||||
|
||||
generate_element_api_json(
|
||||
name = "elements",
|
||||
srcs = glob(["*.md"]),
|
||||
)
|
||||
119
tools/manual_api_docs/elements/ng-container.md
Normal file
119
tools/manual_api_docs/elements/ng-container.md
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
A special element that can hold structural directives without adding new elements to the DOM.
|
||||
|
||||
The `<ng-container>` allows us to use structural directives without any extra element, making sure
|
||||
that the only DOM changes being applied are those dictated by the directives themselves.
|
||||
|
||||
This not only increases performance \(even so slightly\) since the browser ends up rendering less
|
||||
elements but can also be a valuable asset in having cleaner DOMs and styles alike.
|
||||
|
||||
It can for example enable us to use structural directives without breaking styling dependent on a
|
||||
precise DOM structure \(as for example the ones we get when using flex containers, margins, the
|
||||
child combinator selector, etc.\).
|
||||
|
||||
## Usage notes
|
||||
|
||||
### With `*NgIf`s
|
||||
|
||||
One common use case of `<ng-container>` is alongside the `*ngIf` structural directive. By using the
|
||||
special element we can produce very clean templates easy to understand and work with.
|
||||
|
||||
For example, we may want to have a number of elements shown conditionally but they do not need to be
|
||||
all under the same root element. That can be easily done by wrapping them in such a block:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ng-container *ngIf="condition">
|
||||
…
|
||||
</ng-container>
|
||||
|
||||
</code-example>
|
||||
|
||||
This can also be augmented with an `else` statement alongside an `<ng-template>` as:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ng-container *ngIf="condition; else templateA">
|
||||
…
|
||||
</ng-container>
|
||||
<ng-template #templateA>
|
||||
…
|
||||
</ng-template>
|
||||
|
||||
</code-example>
|
||||
|
||||
### Combination of multiple structural directives
|
||||
|
||||
Multiple structural directives cannot be used on the same element; if you need to take advantage of
|
||||
more than one structural directive, it is advised to use an `<ng-container>` per structural
|
||||
directive.
|
||||
|
||||
The most common scenario is with `*ngIf` and `*ngFor`. For example, let's imagine that we have a
|
||||
list of items but each item needs to be displayed only if a certain condition is true. We could be
|
||||
tempted to try something like:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ul>
|
||||
<li *ngFor="let item of items" *ngIf="item.isValid">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
</code-example>
|
||||
|
||||
As we said that would not work, what we can do is to simply move one of the structural directives to
|
||||
an `<ng-container>` element, which would then wrap the other one, like so:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ul>
|
||||
<ng-container *ngFor="let item of items">
|
||||
<li *ngIf="item.isValid">
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ng-container>
|
||||
</ul>
|
||||
|
||||
</code-example>
|
||||
|
||||
This would work as intended without introducing any new unnecessary elements in the DOM.
|
||||
|
||||
For more information see [one structural directive per element](guide/structural-directives#one-per-element).
|
||||
|
||||
### Use alongside ngTemplateOutlet
|
||||
|
||||
The `NgTemplateOutlet` directive can be applied to any element but most of the time it's applied
|
||||
to `<ng-container>` ones. By combining the two, we get a very clear and easy to follow HTML and DOM
|
||||
structure in which no extra elements are necessary and template views are instantiated where
|
||||
requested.
|
||||
|
||||
For example, imagine a situation in which we have a large HTML, in which a small portion needs to be
|
||||
repeated in different places. A simple solution is to define an `<ng-template>` containing our
|
||||
repeating HTML and render that where necessary by using `<ng-container>` alongside
|
||||
an `NgTemplateOutlet`.
|
||||
|
||||
Like so:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<!-- … -->
|
||||
|
||||
<ng-container *ngTemplateOutlet="tmpl; context: {$implicit: 'Hello'}">
|
||||
</ng-container>
|
||||
|
||||
<!-- … -->
|
||||
|
||||
<ng-container *ngTemplateOutlet="tmpl; context: {$implicit: 'World'}">
|
||||
</ng-container>
|
||||
|
||||
<!-- … -->
|
||||
|
||||
<ng-template #tmpl let-text>
|
||||
<h1>{{ text }}</h1>
|
||||
</ng-template>
|
||||
|
||||
</code-example>
|
||||
|
||||
For more information regarding `NgTemplateOutlet`, see
|
||||
the [`NgTemplateOutlet`s api documentation page](api/common/NgTemplateOutlet).
|
||||
|
||||
12
tools/manual_api_docs/elements/ng-content.md
Normal file
12
tools/manual_api_docs/elements/ng-content.md
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
The `<ng-content>` element specifies where to project content inside a component template.
|
||||
|
||||
## Attributes
|
||||
|
||||
| Attribute | Description |
|
||||
|---------------|-------------------------------------------------------------------------|
|
||||
| `select` | CSS selector. Matching elements are projected into this `<ng-content>`. |
|
||||
|
||||
Only select elements from the projected content that match the given CSS `selector`.
|
||||
|
||||
Angular supports [selectors](https://developer.mozilla.org/docs/Web/CSS/CSS_Selectors) for any
|
||||
combination of tag name, attribute, CSS class, and the `:not` pseudo-class.
|
||||
66
tools/manual_api_docs/elements/ng-template.md
Normal file
66
tools/manual_api_docs/elements/ng-template.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
Angular's `<ng-template>` element defines a template that is not rendered by default.
|
||||
|
||||
With `<ng-template>`, you can define template content that is only being rendered by Angular when
|
||||
you, whether directly or indirectly, specifically instruct it to do so, allowing you to have full
|
||||
control over how and when the content is displayed.
|
||||
|
||||
<div class="alter is-helpful">
|
||||
|
||||
Note that if you wrap content inside an `<ng-template>` without instructing Angular to render it,
|
||||
such content will not appear on a page. For example, see the following HTML code, when handling it
|
||||
Angular won't render the middle "Hip!" in the phrase "Hip! Hip! Hooray!" because of the
|
||||
surrounding `<ng-template>`.
|
||||
|
||||
```html
|
||||
<p>Hip!</p>
|
||||
<ng-template>
|
||||
<p>Hip!</p>
|
||||
</ng-template>
|
||||
<p>Hooray!</p>
|
||||
```
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
## Usage notes
|
||||
|
||||
### Structural Directives
|
||||
|
||||
One of the main uses for `<ng-template>` is to hold template content that will be used
|
||||
by [Structural directives](guide/structural-directives). Those directives can add and remove copies
|
||||
of the template content based on their own logic.
|
||||
|
||||
When using
|
||||
the [structural directive shorthand](guide/structural-directives#structural-directive-shorthand),
|
||||
Angular creates an `<ng-template>` element behind the scenes.
|
||||
|
||||
### TemplateRef
|
||||
|
||||
`<ng-template>` elements are represented as instances of the `TemplateRef` class.
|
||||
|
||||
To add copies of the template to the DOM, pass this object to the `ViewContainerRef`
|
||||
method `createEmbeddedView()`.
|
||||
|
||||
### Template Variables
|
||||
|
||||
`<ng-template>` elements can be referenced in templates
|
||||
using [standard template variables](guide/template-reference-variables#how-angular-assigns-values-to-template-variables).
|
||||
|
||||
*This is how `<ng-template>` elements are used as `ngIf` else clauses.*
|
||||
|
||||
Such template variables can be used in conjunction with `ngTemplateOutlet` directives to render the
|
||||
content defined inside `<ng-template>` tags.
|
||||
|
||||
### Querying
|
||||
|
||||
A [Query](api/core/Query) \(such as `ViewChild`\) can find the `TemplateRef` associated to
|
||||
an `<ng-template>` element so that it can be used programmatically; for instance, to pass it to
|
||||
the `ViewContainerRef` method `createEmbeddedView()`.
|
||||
|
||||
### Context
|
||||
|
||||
Inside the `<ng-template>` tags you can reference variables present in the surrounding outer
|
||||
template.
|
||||
Additionally, a context object can be associated with `<ng-template>` elements.
|
||||
Such an object contains variables that can be accessed from within the template contents via
|
||||
template \(`let` and `as`\) declarations.
|
||||
54
tools/manual_api_docs/generate_block_api_json.bzl
Normal file
54
tools/manual_api_docs/generate_block_api_json.bzl
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
load("@build_bazel_rules_nodejs//:providers.bzl", "run_node")
|
||||
|
||||
def _generate_block_api_json(ctx):
|
||||
"""Implementation of the generate_block_api_json rule"""
|
||||
|
||||
# Define arguments that will be passed to the underlying nodejs program.
|
||||
args = ctx.actions.args()
|
||||
|
||||
# Use a param file for consistency with other doc generation rules.
|
||||
args.set_param_file_format("multiline")
|
||||
args.use_param_file("%s", use_always = True)
|
||||
|
||||
# Pass the set of source files from which the API data will be generated.
|
||||
args.add_joined(ctx.files.srcs, join_with = ",")
|
||||
|
||||
# Pass the name of the output JSON file.
|
||||
manifest = ctx.actions.declare_file("blocks.json")
|
||||
args.add(manifest.path)
|
||||
|
||||
# Define an action that runs the nodejs_binary executable. This is
|
||||
# the main thing that this rule does.
|
||||
run_node(
|
||||
ctx = ctx,
|
||||
inputs = depset(ctx.files.srcs),
|
||||
executable = "_generate_block_api_json",
|
||||
outputs = [manifest],
|
||||
arguments = [args],
|
||||
)
|
||||
|
||||
# The return value describes what the rule is producing. In this case we need to specify
|
||||
# the "DefaultInfo" with the output JSON manifest.
|
||||
return [DefaultInfo(files = depset([manifest]))]
|
||||
|
||||
generate_block_api_json = rule(
|
||||
# Point to the starlark function that will execute for this rule.
|
||||
implementation = _generate_block_api_json,
|
||||
doc = """Rule that generates an Angular API doc collection for hand-written block APIs""",
|
||||
|
||||
# The attributes that can be set to this rule.
|
||||
attrs = {
|
||||
"srcs": attr.label_list(
|
||||
doc = """The source files for this rule, must include one or more markdown files.""",
|
||||
allow_empty = False,
|
||||
allow_files = True,
|
||||
),
|
||||
|
||||
# The executable for this rule (private).
|
||||
"_generate_block_api_json": attr.label(
|
||||
default = Label("//tools/manual_api_docs:generate_block_api_json"),
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
),
|
||||
},
|
||||
)
|
||||
33
tools/manual_api_docs/generate_block_api_json.ts
Normal file
33
tools/manual_api_docs/generate_block_api_json.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DocEntry, EntryType} from '@angular/compiler-cli';
|
||||
import {readFileSync, writeFileSync} from 'fs';
|
||||
import {basename} from 'path';
|
||||
|
||||
function main() {
|
||||
const [paramFilePath] = process.argv.slice(2);
|
||||
const rawParamLines = readFileSync(paramFilePath, {encoding: 'utf8'}).split('\n');
|
||||
const [srcs, outputFileExecRootRelativePath] = rawParamLines;
|
||||
|
||||
const entries: DocEntry[] = srcs.split(',').map(sourceFilePath => {
|
||||
const fileContent = readFileSync(sourceFilePath, {encoding: 'utf8'});
|
||||
|
||||
return {
|
||||
name: `@${basename(sourceFilePath, '.md')}`,
|
||||
entryType: EntryType.Block,
|
||||
description: fileContent,
|
||||
rawComment: fileContent,
|
||||
jsdocTags: [],
|
||||
};
|
||||
});
|
||||
|
||||
writeFileSync(outputFileExecRootRelativePath, JSON.stringify(entries), {encoding: 'utf8'});
|
||||
}
|
||||
|
||||
main();
|
||||
54
tools/manual_api_docs/generate_element_api_json.bzl
Normal file
54
tools/manual_api_docs/generate_element_api_json.bzl
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
load("@build_bazel_rules_nodejs//:providers.bzl", "run_node")
|
||||
|
||||
def _generate_element_api_json(ctx):
|
||||
"""Implementation of the generate_element_api_json rule"""
|
||||
|
||||
# Define arguments that will be passed to the underlying nodejs program.
|
||||
args = ctx.actions.args()
|
||||
|
||||
# Use a param file for consistency with other doc generation rules.
|
||||
args.set_param_file_format("multiline")
|
||||
args.use_param_file("%s", use_always = True)
|
||||
|
||||
# Pass the set of source files from which the API data will be generated.
|
||||
args.add_joined(ctx.files.srcs, join_with = ",")
|
||||
|
||||
# Pass the name of the output JSON file.
|
||||
manifest = ctx.actions.declare_file("elements.json")
|
||||
args.add(manifest.path)
|
||||
|
||||
# Define an action that runs the nodejs_binary executable. This is
|
||||
# the main thing that this rule does.
|
||||
run_node(
|
||||
ctx = ctx,
|
||||
inputs = depset(ctx.files.srcs),
|
||||
executable = "_generate_element_api_json",
|
||||
outputs = [manifest],
|
||||
arguments = [args],
|
||||
)
|
||||
|
||||
# The return value describes what the rule is producing. In this case we need to specify
|
||||
# the "DefaultInfo" with the output JSON manifest.
|
||||
return [DefaultInfo(files = depset([manifest]))]
|
||||
|
||||
generate_element_api_json = rule(
|
||||
# Point to the starlark function that will execute for this rule.
|
||||
implementation = _generate_element_api_json,
|
||||
doc = """Rule that generates an Angular API doc collection for hand-written element APIs""",
|
||||
|
||||
# The attributes that can be set to this rule.
|
||||
attrs = {
|
||||
"srcs": attr.label_list(
|
||||
doc = """The source files for this rule, must include one or more markdown files.""",
|
||||
allow_empty = False,
|
||||
allow_files = True,
|
||||
),
|
||||
|
||||
# The executable for this rule (private).
|
||||
"_generate_element_api_json": attr.label(
|
||||
default = Label("//tools/manual_api_docs:generate_element_api_json"),
|
||||
executable = True,
|
||||
cfg = "exec",
|
||||
),
|
||||
},
|
||||
)
|
||||
33
tools/manual_api_docs/generate_element_api_json.ts
Normal file
33
tools/manual_api_docs/generate_element_api_json.ts
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/**
|
||||
* @license
|
||||
* Copyright Google LLC All Rights Reserved.
|
||||
*
|
||||
* Use of this source code is governed by an MIT-style license that can be
|
||||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {DocEntry, EntryType} from '@angular/compiler-cli';
|
||||
import {readFileSync, writeFileSync} from 'fs';
|
||||
import {basename} from 'path';
|
||||
|
||||
function main() {
|
||||
const [paramFilePath] = process.argv.slice(2);
|
||||
const rawParamLines = readFileSync(paramFilePath, {encoding: 'utf8'}).split('\n');
|
||||
const [srcs, outputFileExecRootRelativePath] = rawParamLines;
|
||||
|
||||
const entries: DocEntry[] = srcs.split(',').map(sourceFilePath => {
|
||||
const fileContent = readFileSync(sourceFilePath, {encoding: 'utf8'});
|
||||
|
||||
return {
|
||||
name: basename(sourceFilePath, '.md'),
|
||||
entryType: EntryType.Element,
|
||||
description: fileContent,
|
||||
rawComment: fileContent,
|
||||
jsdocTags: [],
|
||||
};
|
||||
});
|
||||
|
||||
writeFileSync(outputFileExecRootRelativePath, JSON.stringify(entries), {encoding: 'utf8'});
|
||||
}
|
||||
|
||||
main();
|
||||
12
tools/manual_api_docs/test/BUILD.bazel
Normal file
12
tools/manual_api_docs/test/BUILD.bazel
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
load("//tools/manual_api_docs:generate_element_api_json.bzl", "generate_element_api_json")
|
||||
load("//tools/manual_api_docs:generate_block_api_json.bzl", "generate_block_api_json")
|
||||
|
||||
generate_element_api_json(
|
||||
name = "element_test",
|
||||
srcs = ["dummy.md"],
|
||||
)
|
||||
|
||||
generate_block_api_json(
|
||||
name = "block_test",
|
||||
srcs = ["dummy.md"],
|
||||
)
|
||||
1
tools/manual_api_docs/test/dummy.md
Normal file
1
tools/manual_api_docs/test/dummy.md
Normal file
|
|
@ -0,0 +1 @@
|
|||
## This is the content of the file
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
{
|
||||
// This tsconfig is only used by IDEs, no actual builds.
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"declaration": true,
|
||||
|
|
@ -10,8 +11,10 @@
|
|||
"outDir": "../dist/tools/",
|
||||
"noImplicitAny": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"paths": {},
|
||||
"rootDir": ".",
|
||||
"paths": {
|
||||
"@angular/*": ["../packages/*"]
|
||||
},
|
||||
"rootDirs": [".", ".."],
|
||||
"sourceMap": true,
|
||||
"inlineSources": true,
|
||||
"lib": [
|
||||
|
|
|
|||
Loading…
Reference in a new issue