text-runner-engine 7.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/actions/actions.d.ts +11 -0
- package/dist/actions/actions.js +36 -0
- package/dist/actions/built-in/check-image.d.ts +4 -0
- package/dist/actions/built-in/check-image.js +59 -0
- package/dist/actions/built-in/check-link.d.ts +4 -0
- package/dist/actions/built-in/check-link.js +127 -0
- package/dist/actions/built-in/test.d.ts +3 -0
- package/dist/actions/built-in/test.js +4 -0
- package/dist/actions/export.d.ts +18 -0
- package/dist/actions/export.js +2 -0
- package/dist/actions/external-action-manager.d.ts +10 -0
- package/dist/actions/external-action-manager.js +44 -0
- package/dist/actions/finder.d.ts +29 -0
- package/dist/actions/finder.js +99 -0
- package/dist/actions/index.d.ts +37 -0
- package/dist/actions/index.js +3 -0
- package/dist/actions/name.d.ts +2 -0
- package/dist/actions/name.js +6 -0
- package/dist/activities/extract-dynamic.d.ts +5 -0
- package/dist/activities/extract-dynamic.js +29 -0
- package/dist/activities/extract-images-and-links.d.ts +5 -0
- package/dist/activities/extract-images-and-links.js +32 -0
- package/dist/activities/index.d.ts +20 -0
- package/dist/activities/index.js +14 -0
- package/dist/activities/normalize-action-name.d.ts +3 -0
- package/dist/activities/normalize-action-name.js +13 -0
- package/dist/ast/index.d.ts +3 -0
- package/dist/ast/index.js +3 -0
- package/dist/ast/node-list.d.ts +41 -0
- package/dist/ast/node-list.js +128 -0
- package/dist/ast/node.d.ts +49 -0
- package/dist/ast/node.js +53 -0
- package/dist/commands/command.d.ts +9 -0
- package/dist/commands/command.js +2 -0
- package/dist/commands/debug.d.ts +16 -0
- package/dist/commands/debug.js +122 -0
- package/dist/commands/dynamic.d.ts +13 -0
- package/dist/commands/dynamic.js +57 -0
- package/dist/commands/index.d.ts +7 -0
- package/dist/commands/index.js +7 -0
- package/dist/commands/run.d.ts +14 -0
- package/dist/commands/run.js +66 -0
- package/dist/commands/static.d.ts +13 -0
- package/dist/commands/static.js +60 -0
- package/dist/commands/unused.d.ts +13 -0
- package/dist/commands/unused.js +43 -0
- package/dist/configuration/data.d.ts +46 -0
- package/dist/configuration/data.js +2 -0
- package/dist/configuration/defaults.d.ts +5 -0
- package/dist/configuration/defaults.js +50 -0
- package/dist/configuration/index.d.ts +5 -0
- package/dist/configuration/index.js +4 -0
- package/dist/configuration/publication.d.ts +42 -0
- package/dist/configuration/publication.js +51 -0
- package/dist/configuration/publications.d.ts +9 -0
- package/dist/configuration/publications.js +25 -0
- package/dist/errors/error.d.ts +2 -0
- package/dist/errors/error.js +9 -0
- package/dist/errors/node-error.d.ts +3 -0
- package/dist/errors/node-error.js +5 -0
- package/dist/errors/user-error.d.ts +13 -0
- package/dist/errors/user-error.js +16 -0
- package/dist/events/index.d.ts +49 -0
- package/dist/events/index.js +13 -0
- package/dist/filesystem/absolute-dir.d.ts +25 -0
- package/dist/filesystem/absolute-dir.js +42 -0
- package/dist/filesystem/absolute-file.d.ts +18 -0
- package/dist/filesystem/absolute-file.js +28 -0
- package/dist/filesystem/full-dir.d.ts +11 -0
- package/dist/filesystem/full-dir.js +15 -0
- package/dist/filesystem/full-file.d.ts +22 -0
- package/dist/filesystem/full-file.js +35 -0
- package/dist/filesystem/full-link.d.ts +40 -0
- package/dist/filesystem/full-link.js +80 -0
- package/dist/filesystem/full-path.d.ts +31 -0
- package/dist/filesystem/full-path.js +61 -0
- package/dist/filesystem/get-filenames.d.ts +15 -0
- package/dist/filesystem/get-filenames.js +73 -0
- package/dist/filesystem/has-directory.d.ts +2 -0
- package/dist/filesystem/has-directory.js +11 -0
- package/dist/filesystem/index.d.ts +15 -0
- package/dist/filesystem/index.js +15 -0
- package/dist/filesystem/is-markdown-file.d.ts +2 -0
- package/dist/filesystem/is-markdown-file.js +11 -0
- package/dist/filesystem/location.d.ts +17 -0
- package/dist/filesystem/location.js +26 -0
- package/dist/filesystem/relative-dir.d.ts +6 -0
- package/dist/filesystem/relative-dir.js +7 -0
- package/dist/filesystem/relative-link.d.ts +16 -0
- package/dist/filesystem/relative-link.js +18 -0
- package/dist/filesystem/source-dir.d.ts +19 -0
- package/dist/filesystem/source-dir.js +35 -0
- package/dist/filesystem/unknown-link.d.ts +15 -0
- package/dist/filesystem/unknown-link.js +23 -0
- package/dist/helpers/add-leading-dot-unless-empty.d.ts +2 -0
- package/dist/helpers/add-leading-dot-unless-empty.js +10 -0
- package/dist/helpers/add-leading-slash.d.ts +2 -0
- package/dist/helpers/add-leading-slash.js +9 -0
- package/dist/helpers/add-trailing-slash.d.ts +2 -0
- package/dist/helpers/add-trailing-slash.js +7 -0
- package/dist/helpers/index.d.ts +16 -0
- package/dist/helpers/index.js +16 -0
- package/dist/helpers/is-external-link.d.ts +2 -0
- package/dist/helpers/is-external-link.js +5 -0
- package/dist/helpers/is-link-to-anchor-in-other-file.d.ts +2 -0
- package/dist/helpers/is-link-to-anchor-in-other-file.js +4 -0
- package/dist/helpers/is-link-to-anchor-in-same-file.d.ts +2 -0
- package/dist/helpers/is-link-to-anchor-in-same-file.js +4 -0
- package/dist/helpers/is-mailto-link.d.ts +2 -0
- package/dist/helpers/is-mailto-link.js +4 -0
- package/dist/helpers/remove-double-slash.d.ts +3 -0
- package/dist/helpers/remove-double-slash.js +6 -0
- package/dist/helpers/remove-leading-slash.d.ts +2 -0
- package/dist/helpers/remove-leading-slash.js +7 -0
- package/dist/helpers/remove-trailing-colon.d.ts +2 -0
- package/dist/helpers/remove-trailing-colon.js +9 -0
- package/dist/helpers/straighten-link.d.ts +3 -0
- package/dist/helpers/straighten-link.js +15 -0
- package/dist/helpers/trim-all-line-ends.d.ts +3 -0
- package/dist/helpers/trim-all-line-ends.js +5 -0
- package/dist/helpers/trim-extension.d.ts +2 -0
- package/dist/helpers/trim-extension.js +5 -0
- package/dist/helpers/unixify.d.ts +3 -0
- package/dist/helpers/unixify.js +6 -0
- package/dist/link-targets/find.d.ts +4 -0
- package/dist/link-targets/find.js +9 -0
- package/dist/link-targets/index.d.ts +15 -0
- package/dist/link-targets/index.js +3 -0
- package/dist/link-targets/list.d.ts +18 -0
- package/dist/link-targets/list.js +74 -0
- package/dist/link-targets/target-url.d.ts +2 -0
- package/dist/link-targets/target-url.js +8 -0
- package/dist/parsers/html/html-parser.d.ts +28 -0
- package/dist/parsers/html/html-parser.js +153 -0
- package/dist/parsers/html/index.d.ts +2 -0
- package/dist/parsers/html/index.js +2 -0
- package/dist/parsers/html/parse-html-files.d.ts +6 -0
- package/dist/parsers/html/parse-html-files.js +16 -0
- package/dist/parsers/index.d.ts +3 -0
- package/dist/parsers/index.js +3 -0
- package/dist/parsers/markdown/closing-tag-parser.d.ts +13 -0
- package/dist/parsers/markdown/closing-tag-parser.js +29 -0
- package/dist/parsers/markdown/index.d.ts +3 -0
- package/dist/parsers/markdown/index.js +3 -0
- package/dist/parsers/markdown/md-parser.d.ts +50 -0
- package/dist/parsers/markdown/md-parser.js +316 -0
- package/dist/parsers/markdown/open-node-tracker.d.ts +14 -0
- package/dist/parsers/markdown/open-node-tracker.js +33 -0
- package/dist/parsers/markdown/parse.d.ts +5 -0
- package/dist/parsers/markdown/parse.js +15 -0
- package/dist/parsers/tag-mapper.d.ts +31 -0
- package/dist/parsers/tag-mapper.js +112 -0
- package/dist/run/activity-collector.d.ts +29 -0
- package/dist/run/activity-collector.js +35 -0
- package/dist/run/index.d.ts +9 -0
- package/dist/run/index.js +5 -0
- package/dist/run/name-refiner.d.ts +13 -0
- package/dist/run/name-refiner.js +20 -0
- package/dist/run/output-collector.d.ts +13 -0
- package/dist/run/output-collector.js +30 -0
- package/dist/run/parallel.d.ts +11 -0
- package/dist/run/parallel.js +13 -0
- package/dist/run/run-activity.d.ts +8 -0
- package/dist/run/run-activity.js +76 -0
- package/dist/run/sequential.d.ts +7 -0
- package/dist/run/sequential.js +10 -0
- package/dist/run/stopwatch.d.ts +12 -0
- package/dist/run/stopwatch.js +19 -0
- package/dist/text-runner.d.ts +15 -0
- package/dist/text-runner.js +15 -0
- package/dist/workspace/create.d.ts +4 -0
- package/dist/workspace/create.js +10 -0
- package/dist/workspace/index.d.ts +2 -0
- package/dist/workspace/index.js +2 -0
- package/package.json +45 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as ast from "../ast/index.js";
|
|
2
|
+
import * as files from "../filesystem/index.js";
|
|
3
|
+
export { extractDynamic } from "./extract-dynamic.js";
|
|
4
|
+
export { extractImagesAndLinks } from "./extract-images-and-links.js";
|
|
5
|
+
/** scaffoldActivity creates a test Activity from the given data */
|
|
6
|
+
export function scaffold(data = {}) {
|
|
7
|
+
return {
|
|
8
|
+
actionName: data.actionName || "foo",
|
|
9
|
+
document: new ast.NodeList(),
|
|
10
|
+
location: files.Location.scaffold(),
|
|
11
|
+
region: new ast.NodeList()
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import slugify from "@sindresorhus/slugify";
|
|
2
|
+
import { UserError } from "../errors/user-error.js";
|
|
3
|
+
export function normalizeActionName(actionName, location) {
|
|
4
|
+
const parts = actionName.split("/");
|
|
5
|
+
if (parts.length === 1) {
|
|
6
|
+
return slugify(actionName);
|
|
7
|
+
}
|
|
8
|
+
if (parts.length > 2) {
|
|
9
|
+
throw new UserError(`Illegal activity name: "${actionName}" contains ${parts.length} slashes`, "", location);
|
|
10
|
+
}
|
|
11
|
+
return parts[0] + "/" + slugify(parts[1]);
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=normalize-action-name.js.map
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Node, NodeScaffoldDataReadonly } from "./node.js";
|
|
2
|
+
export declare class NodeList extends Array<Node> {
|
|
3
|
+
/** Creates a new ast.NodeList containing an Node scaffoldedd from the given data */
|
|
4
|
+
static scaffold(data?: NodeScaffoldDataReadonly): NodeList;
|
|
5
|
+
/** Returns whether this ast.NodeList contains a node of the given type. */
|
|
6
|
+
hasNodeOfType(nodeType: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* provides exactly one node matching any of the given types,
|
|
9
|
+
* multiple or zero matches cause an exception
|
|
10
|
+
*/
|
|
11
|
+
nodeOfTypes(...nodeTypes: string[]): Node;
|
|
12
|
+
/**
|
|
13
|
+
* Assuming the given Node is an opening node,
|
|
14
|
+
* returns all nodes until it closes.
|
|
15
|
+
*/
|
|
16
|
+
nodesFor(openingNode: Node): NodeList;
|
|
17
|
+
/** Returns the Nodes matching any of the given types. */
|
|
18
|
+
nodesOfTypes(...nodeTypes: string[]): NodeList;
|
|
19
|
+
/** Returns all node types encountered in this list. */
|
|
20
|
+
nodeTypes(): string[];
|
|
21
|
+
/** Adds a new Node with the given data to this list. */
|
|
22
|
+
pushNode(data: NodeScaffoldDataReadonly): void;
|
|
23
|
+
/** Returns the concatenated textual content of all nodes in this list. */
|
|
24
|
+
text(): string;
|
|
25
|
+
/** Returns the textual content for the given node. */
|
|
26
|
+
textInNode(astNode: Node): string;
|
|
27
|
+
/**
|
|
28
|
+
* Returns the text in the node of the given types.
|
|
29
|
+
* Expects that exactly one matching node exists,
|
|
30
|
+
* throws otherwise.
|
|
31
|
+
*/
|
|
32
|
+
textInNodeOfType(...nodeTypes: string[]): string;
|
|
33
|
+
/**
|
|
34
|
+
* Returns the text in the node that has one of the given types.
|
|
35
|
+
* Expects that exactly one matching node exists, throws otherwise.
|
|
36
|
+
*/
|
|
37
|
+
textInNodeOfTypes(...nodeTypes: string[]): string;
|
|
38
|
+
/** provides the text in the nodes of the given types */
|
|
39
|
+
textInNodesOfType(...nodeTypes: string[]): string[];
|
|
40
|
+
}
|
|
41
|
+
//# sourceMappingURL=node-list.d.ts.map
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { UserError } from "../errors/user-error.js";
|
|
2
|
+
import { Node } from "./node.js";
|
|
3
|
+
export class NodeList extends Array {
|
|
4
|
+
/** Creates a new ast.NodeList containing an Node scaffoldedd from the given data */
|
|
5
|
+
static scaffold(data = {}) {
|
|
6
|
+
const result = new NodeList();
|
|
7
|
+
result.push(Node.scaffold(data));
|
|
8
|
+
return result;
|
|
9
|
+
}
|
|
10
|
+
/** Returns whether this ast.NodeList contains a node of the given type. */
|
|
11
|
+
hasNodeOfType(nodeType) {
|
|
12
|
+
const types = [nodeType];
|
|
13
|
+
types.push(nodeType + "_open");
|
|
14
|
+
return this.some(node => types.includes(node.type));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* provides exactly one node matching any of the given types,
|
|
18
|
+
* multiple or zero matches cause an exception
|
|
19
|
+
*/
|
|
20
|
+
nodeOfTypes(...nodeTypes) {
|
|
21
|
+
const nodes = this.nodesOfTypes(...nodeTypes);
|
|
22
|
+
if (nodes.length > 1) {
|
|
23
|
+
throw new UserError(`Found ${nodes.length} nodes of type '${nodeTypes.join("/")}'`, "The nodeOfTypes method expects to find only one matching node, but it found multiple.", nodes[0].location);
|
|
24
|
+
}
|
|
25
|
+
if (nodes.length === 0) {
|
|
26
|
+
const msg = `found no nodes of type '${nodeTypes.join("/")}'`;
|
|
27
|
+
let guidance = "The node types in this list are: ";
|
|
28
|
+
guidance += this.nodeTypes().join(", ");
|
|
29
|
+
throw new UserError(msg, guidance, this[0].location);
|
|
30
|
+
}
|
|
31
|
+
return nodes[0];
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Assuming the given Node is an opening node,
|
|
35
|
+
* returns all nodes until it closes.
|
|
36
|
+
*/
|
|
37
|
+
nodesFor(openingNode) {
|
|
38
|
+
if (openingNode == null) {
|
|
39
|
+
throw new UserError("no Node given", `Somebody called the Text-Runner API method "NodeList.getNodesFor()" without an argument.
|
|
40
|
+
This method provides all AST nodes until the given AST node closes.
|
|
41
|
+
This callstack should point you to the problem:
|
|
42
|
+
|
|
43
|
+
${new Error().stack}`);
|
|
44
|
+
}
|
|
45
|
+
let index = this.indexOf(openingNode);
|
|
46
|
+
if (index === -1) {
|
|
47
|
+
throw new UserError(`node '${openingNode.type}' not found in list`, "This ast.NodeList does not contain the given node.", openingNode.location);
|
|
48
|
+
}
|
|
49
|
+
const result = new NodeList();
|
|
50
|
+
if (!openingNode.isOpeningNode()) {
|
|
51
|
+
result.push(openingNode);
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
const endType = openingNode.endType();
|
|
55
|
+
let node;
|
|
56
|
+
do {
|
|
57
|
+
node = this[index];
|
|
58
|
+
result.push(node);
|
|
59
|
+
index += 1;
|
|
60
|
+
} while (node.type !== endType && index < this.length);
|
|
61
|
+
return result;
|
|
62
|
+
}
|
|
63
|
+
/** Returns the Nodes matching any of the given types. */
|
|
64
|
+
nodesOfTypes(...nodeTypes) {
|
|
65
|
+
const result = new NodeList();
|
|
66
|
+
const expectedTypes = [];
|
|
67
|
+
for (const nodeType of nodeTypes) {
|
|
68
|
+
expectedTypes.push(nodeType);
|
|
69
|
+
expectedTypes.push(nodeType + "_open");
|
|
70
|
+
}
|
|
71
|
+
for (const node of this) {
|
|
72
|
+
if (expectedTypes.includes(node.type)) {
|
|
73
|
+
result.push(node);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
77
|
+
}
|
|
78
|
+
/** Returns all node types encountered in this list. */
|
|
79
|
+
nodeTypes() {
|
|
80
|
+
return this.map(node => node.type);
|
|
81
|
+
}
|
|
82
|
+
/** Adds a new Node with the given data to this list. */
|
|
83
|
+
pushNode(data) {
|
|
84
|
+
this.push(Node.scaffold(data));
|
|
85
|
+
}
|
|
86
|
+
/** Returns the concatenated textual content of all nodes in this list. */
|
|
87
|
+
text() {
|
|
88
|
+
return this.map(node => node.content)
|
|
89
|
+
.filter(text => text)
|
|
90
|
+
.join(" ");
|
|
91
|
+
}
|
|
92
|
+
/** Returns the textual content for the given node. */
|
|
93
|
+
textInNode(astNode) {
|
|
94
|
+
return this.nodesFor(astNode).reduce((acc, node) => acc + node.content, "");
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Returns the text in the node of the given types.
|
|
98
|
+
* Expects that exactly one matching node exists,
|
|
99
|
+
* throws otherwise.
|
|
100
|
+
*/
|
|
101
|
+
textInNodeOfType(...nodeTypes) {
|
|
102
|
+
for (const nodeType of nodeTypes) {
|
|
103
|
+
if (!nodeType.endsWith("_open")) {
|
|
104
|
+
nodeTypes.push(nodeType + "_open");
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return this.textInNode(this.nodeOfTypes(...nodeTypes));
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Returns the text in the node that has one of the given types.
|
|
111
|
+
* Expects that exactly one matching node exists, throws otherwise.
|
|
112
|
+
*/
|
|
113
|
+
textInNodeOfTypes(...nodeTypes) {
|
|
114
|
+
const node = this.nodeOfTypes(...nodeTypes);
|
|
115
|
+
const nodes = this.nodesFor(node);
|
|
116
|
+
return nodes.text();
|
|
117
|
+
}
|
|
118
|
+
/** provides the text in the nodes of the given types */
|
|
119
|
+
textInNodesOfType(...nodeTypes) {
|
|
120
|
+
for (const nodeType of nodeTypes) {
|
|
121
|
+
if (!nodeType.endsWith("_open")) {
|
|
122
|
+
nodeTypes.push(nodeType + "_open");
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return this.nodesOfTypes(...nodeTypes).map(node => this.textInNode(node));
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
//# sourceMappingURL=node-list.js.map
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import * as files from "../filesystem/index.js";
|
|
2
|
+
export type NodeAttributes = Record<string, string>;
|
|
3
|
+
export interface NodeScaffoldData {
|
|
4
|
+
attributes?: NodeAttributes;
|
|
5
|
+
content?: string;
|
|
6
|
+
file?: files.FullFilePath | string;
|
|
7
|
+
line?: number;
|
|
8
|
+
sourceDir?: string;
|
|
9
|
+
tag?: NodeTag;
|
|
10
|
+
type?: NodeType;
|
|
11
|
+
}
|
|
12
|
+
export type NodeScaffoldDataReadonly = Readonly<NodeScaffoldData>;
|
|
13
|
+
/** the HTML tags */
|
|
14
|
+
export type NodeTag = "" | "/a" | "/b" | "/code" | "/pre" | "a" | "b" | "br" | "code" | "hr" | "i" | "img" | "li" | "ol" | "p" | "pre" | "ul";
|
|
15
|
+
/** the MarkdownIt node types */
|
|
16
|
+
export type NodeType = "anchor_close" | "anchor_open" | "bold_close" | "bold_open" | "bullet_list_close" | "bullet_list_open" | "code_close" | "code_open" | "fence_close" | "fence_open" | "h1_close" | "h1_open" | "h2_close" | "h2_open" | "h3_close" | "h3_open" | "h4_close" | "h4_open" | "h5_close" | "h5_open" | "h6_close" | "h6_open" | "heading_close" | "heading_open" | "hr" | "htmltag" | "image" | "linebreak" | "link_close" | "link_open" | "paragraph_close" | "paragraph_open" | "text";
|
|
17
|
+
/** a node in the standardized Markdown/HTML AST */
|
|
18
|
+
export declare class Node {
|
|
19
|
+
/** the attributes of the node */
|
|
20
|
+
readonly attributes: NodeAttributes;
|
|
21
|
+
/** textual content of this AST node */
|
|
22
|
+
readonly content: string;
|
|
23
|
+
/** the file in which this AstNode occurs */
|
|
24
|
+
readonly location: files.Location;
|
|
25
|
+
/** HTML type of AST node */
|
|
26
|
+
readonly tag: NodeTag;
|
|
27
|
+
/** markdown type of AST node */
|
|
28
|
+
type: NodeType;
|
|
29
|
+
constructor(data: {
|
|
30
|
+
attributes: NodeAttributes;
|
|
31
|
+
content: string;
|
|
32
|
+
location: files.Location;
|
|
33
|
+
tag: NodeTag;
|
|
34
|
+
type: NodeType;
|
|
35
|
+
});
|
|
36
|
+
static scaffold(data?: NodeScaffoldData): Node;
|
|
37
|
+
/** Returns the type of the corresponding ending node. */
|
|
38
|
+
endType(): string;
|
|
39
|
+
/**
|
|
40
|
+
* Returns the content of the "href" attribute for link tags,
|
|
41
|
+
* null otherwise.
|
|
42
|
+
*/
|
|
43
|
+
htmlLinkTarget(): null | string;
|
|
44
|
+
/** Returns whether this AstNode is a closing node. */
|
|
45
|
+
isClosingNode(): boolean;
|
|
46
|
+
/** Returns whether this AstNode is an opening node. */
|
|
47
|
+
isOpeningNode(): boolean;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=node.d.ts.map
|
package/dist/ast/node.js
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import * as files from "../filesystem/index.js";
|
|
2
|
+
/** a node in the standardized Markdown/HTML AST */
|
|
3
|
+
export class Node {
|
|
4
|
+
constructor(data) {
|
|
5
|
+
this.type = data.type;
|
|
6
|
+
this.tag = data.tag;
|
|
7
|
+
this.location = data.location;
|
|
8
|
+
this.content = data.content;
|
|
9
|
+
this.attributes = data.attributes;
|
|
10
|
+
}
|
|
11
|
+
static scaffold(data = {}) {
|
|
12
|
+
if (typeof data.file === "string") {
|
|
13
|
+
data.file = new files.FullFilePath(data.file);
|
|
14
|
+
}
|
|
15
|
+
return new Node({
|
|
16
|
+
attributes: data.attributes || {},
|
|
17
|
+
content: data.content || "",
|
|
18
|
+
location: new files.Location(new files.SourceDir(data.sourceDir || ""), data.file || new files.FullFilePath("file"), data.line || 1),
|
|
19
|
+
tag: data.tag != null ? data.tag : "hr",
|
|
20
|
+
type: data.type || "hr"
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
/** Returns the type of the corresponding ending node. */
|
|
24
|
+
endType() {
|
|
25
|
+
if (!this.isOpeningNode()) {
|
|
26
|
+
throw new Error("not an opening node");
|
|
27
|
+
}
|
|
28
|
+
return this.type.replace("open", "") + "close";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Returns the content of the "href" attribute for link tags,
|
|
32
|
+
* null otherwise.
|
|
33
|
+
*/
|
|
34
|
+
htmlLinkTarget() {
|
|
35
|
+
if (this.content == null) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
if (this.type !== "htmltag") {
|
|
39
|
+
return null;
|
|
40
|
+
}
|
|
41
|
+
const matches = /<a[^>]*href="([^"]*)".*?>/.exec(this.content);
|
|
42
|
+
return matches ? matches[1] : null;
|
|
43
|
+
}
|
|
44
|
+
/** Returns whether this AstNode is a closing node. */
|
|
45
|
+
isClosingNode() {
|
|
46
|
+
return this.type.endsWith("_close");
|
|
47
|
+
}
|
|
48
|
+
/** Returns whether this AstNode is an opening node. */
|
|
49
|
+
isOpeningNode() {
|
|
50
|
+
return this.type.endsWith("_open");
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=node.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import * as events from "../events/index.js";
|
|
2
|
+
/** Command describes a Text-Runner command */
|
|
3
|
+
export interface Command {
|
|
4
|
+
emit(event: events.Name, payload: events.Args): void;
|
|
5
|
+
/** executes this command */
|
|
6
|
+
execute(): Promise<void>;
|
|
7
|
+
on(event: events.Name, handler: events.Handler): void;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=command.d.ts.map
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import * as configuration from "../configuration/index.js";
|
|
3
|
+
import * as events from "../events/index.js";
|
|
4
|
+
import { Command } from "./command.js";
|
|
5
|
+
export declare const DebugSubCommandValues: readonly ["activities", "ast", "images", "links", "linkTargets"];
|
|
6
|
+
export type DebugSubcommand = (typeof DebugSubCommandValues)[number];
|
|
7
|
+
export declare class Debug implements Command {
|
|
8
|
+
emitter: EventEmitter;
|
|
9
|
+
subcommand: DebugSubcommand | undefined;
|
|
10
|
+
userConfig: configuration.APIData;
|
|
11
|
+
constructor(userConfig: configuration.APIData, subcommand: DebugSubcommand | undefined);
|
|
12
|
+
emit(name: events.Name, payload: events.Args): void;
|
|
13
|
+
execute(): Promise<void>;
|
|
14
|
+
on(name: events.Name, handler: events.Handler): this;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=debug.d.ts.map
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import * as util from "util";
|
|
3
|
+
import * as activities from "../activities/index.js";
|
|
4
|
+
import * as ast from "../ast/index.js";
|
|
5
|
+
import * as configuration from "../configuration/index.js";
|
|
6
|
+
import { UserError } from "../errors/user-error.js";
|
|
7
|
+
import * as files from "../filesystem/index.js";
|
|
8
|
+
import * as helpers from "../helpers/index.js";
|
|
9
|
+
import * as linkTargets from "../link-targets/index.js";
|
|
10
|
+
import * as parsers from "../parsers/index.js";
|
|
11
|
+
export const DebugSubCommandValues = ["activities", "ast", "images", "links", "linkTargets"];
|
|
12
|
+
export class Debug {
|
|
13
|
+
constructor(userConfig, subcommand) {
|
|
14
|
+
this.userConfig = userConfig;
|
|
15
|
+
this.subcommand = subcommand;
|
|
16
|
+
this.emitter = new EventEmitter();
|
|
17
|
+
}
|
|
18
|
+
emit(name, payload) {
|
|
19
|
+
this.emitter.emit(name, payload);
|
|
20
|
+
}
|
|
21
|
+
async execute() {
|
|
22
|
+
const config = await configuration.addDefaults(this.userConfig);
|
|
23
|
+
const filenames = await files.getFileNames(config);
|
|
24
|
+
if (filenames.length !== 1) {
|
|
25
|
+
const guidance = `Please tell me which file to debug
|
|
26
|
+
|
|
27
|
+
Example: text-runner debug --${this.subcommand} foo.md`;
|
|
28
|
+
throw new UserError("no files specified", guidance);
|
|
29
|
+
}
|
|
30
|
+
const guidance = `possible subcommands are:
|
|
31
|
+
--activities: active regions
|
|
32
|
+
--ast: AST nodes
|
|
33
|
+
--images: embedded images
|
|
34
|
+
--links: embedded links
|
|
35
|
+
--link-targets: document anchors to link to
|
|
36
|
+
|
|
37
|
+
Example: text-runner debug --images foo.md`;
|
|
38
|
+
const ASTs = await parsers.markdown.parse(filenames, config.sourceDir);
|
|
39
|
+
switch (this.subcommand) {
|
|
40
|
+
case "activities":
|
|
41
|
+
return debugActivities(ASTs, config);
|
|
42
|
+
case "ast":
|
|
43
|
+
return debugASTNodes(ASTs);
|
|
44
|
+
case "images":
|
|
45
|
+
return debugImages(ASTs);
|
|
46
|
+
case "links":
|
|
47
|
+
return debugLinks(ASTs);
|
|
48
|
+
case "linkTargets":
|
|
49
|
+
return debugLinkTargets(ASTs);
|
|
50
|
+
case undefined:
|
|
51
|
+
throw new UserError("missing debug sub-command", guidance);
|
|
52
|
+
default:
|
|
53
|
+
throw new UserError(`unknown debug sub-command: ${this.subcommand}`, guidance);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
on(name, handler) {
|
|
57
|
+
this.emitter.on(name, handler);
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function debugActivities(ASTs, config) {
|
|
62
|
+
console.log("\nACTIVITIES:");
|
|
63
|
+
const dynamicActivities = activities.extractDynamic(ASTs, config.regionMarker || "type");
|
|
64
|
+
if (dynamicActivities.length === 0) {
|
|
65
|
+
console.log("(none)");
|
|
66
|
+
}
|
|
67
|
+
else {
|
|
68
|
+
for (const act of dynamicActivities) {
|
|
69
|
+
console.log(`${act.location.file.platformified()}:${act.location.line} ${act.actionName}`);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function debugASTNodes(ASTs) {
|
|
74
|
+
console.log("AST NODES:");
|
|
75
|
+
for (const AST of ASTs) {
|
|
76
|
+
for (const node of AST) {
|
|
77
|
+
console.log(`${node.location.file.platformified()}:${node.location.line} ${node.type} ${showAttr(node)}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function debugImages(ASTs) {
|
|
82
|
+
console.log("\nIMAGES:");
|
|
83
|
+
const images = activities.extractImagesAndLinks(ASTs).filter(al => al.actionName === "check-image");
|
|
84
|
+
if (images.length === 0) {
|
|
85
|
+
console.log("(none)");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
for (const image of images) {
|
|
89
|
+
image.document = new ast.NodeList();
|
|
90
|
+
console.log(helpers.trimAllLineEnds(util.inspect(image, false, Infinity)));
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function debugLinks(ASTs) {
|
|
94
|
+
console.log("\nLINKS:");
|
|
95
|
+
const links = activities.extractImagesAndLinks(ASTs).filter(al => al.actionName === "check-link");
|
|
96
|
+
if (links.length === 0) {
|
|
97
|
+
console.log("(none)");
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
for (const image of links) {
|
|
101
|
+
image.document = new ast.NodeList();
|
|
102
|
+
console.log(helpers.trimAllLineEnds(util.inspect(image, false, Infinity)));
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function debugLinkTargets(ASTs) {
|
|
106
|
+
console.log("\nLINK TARGETS:");
|
|
107
|
+
const targets = linkTargets.find(ASTs);
|
|
108
|
+
for (const key of Object.keys(targets.targets)) {
|
|
109
|
+
console.log(key, targets.targets[key]);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function showAttr(node) {
|
|
113
|
+
if (node.type === "text") {
|
|
114
|
+
return `("${node.content.trim()}")`;
|
|
115
|
+
}
|
|
116
|
+
const keys = Object.keys(node.attributes);
|
|
117
|
+
if (keys.length === 0) {
|
|
118
|
+
return "";
|
|
119
|
+
}
|
|
120
|
+
return `(${node.attributes.type})`;
|
|
121
|
+
}
|
|
122
|
+
//# sourceMappingURL=debug.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import * as configuration from "../configuration/index.js";
|
|
3
|
+
import * as events from "../events/index.js";
|
|
4
|
+
import { Command } from "./command.js";
|
|
5
|
+
export declare class Dynamic implements Command {
|
|
6
|
+
emitter: EventEmitter;
|
|
7
|
+
userConfig: configuration.APIData;
|
|
8
|
+
constructor(userConfig: configuration.APIData);
|
|
9
|
+
emit(name: events.Name, payload: events.Args): void;
|
|
10
|
+
execute(): Promise<void>;
|
|
11
|
+
on(name: events.Name, handler: events.Handler): this;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=dynamic.d.ts.map
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import * as actions from "../actions/index.js";
|
|
3
|
+
import * as activities from "../activities/index.js";
|
|
4
|
+
import * as configuration from "../configuration/index.js";
|
|
5
|
+
import * as files from "../filesystem/index.js";
|
|
6
|
+
import * as linkTargets from "../link-targets/index.js";
|
|
7
|
+
import * as parsers from "../parsers/index.js";
|
|
8
|
+
import * as run from "../run/index.js";
|
|
9
|
+
import * as workspace from "../workspace/index.js";
|
|
10
|
+
export class Dynamic {
|
|
11
|
+
constructor(userConfig) {
|
|
12
|
+
this.userConfig = userConfig;
|
|
13
|
+
this.emitter = new EventEmitter();
|
|
14
|
+
}
|
|
15
|
+
emit(name, payload) {
|
|
16
|
+
this.emitter.emit(name, payload);
|
|
17
|
+
}
|
|
18
|
+
async execute() {
|
|
19
|
+
const originalDir = process.cwd();
|
|
20
|
+
try {
|
|
21
|
+
// step 1: determine full configuration
|
|
22
|
+
const config = await configuration.addDefaults(this.userConfig);
|
|
23
|
+
// step 2: create working dir
|
|
24
|
+
await workspace.create(config);
|
|
25
|
+
// step 3: find files
|
|
26
|
+
const filenames = await files.getFileNames(config);
|
|
27
|
+
if (filenames.length === 0) {
|
|
28
|
+
this.emit("result", { message: "no Markdown files found", status: "warning" });
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
// step 4: read and parse files
|
|
32
|
+
const ASTs = await parsers.markdown.parse(filenames, config.sourceDir);
|
|
33
|
+
// step 5: find link targets
|
|
34
|
+
const targets = linkTargets.find(ASTs);
|
|
35
|
+
// step 6: extract activities
|
|
36
|
+
const dynamicActivities = activities.extractDynamic(ASTs, config.regionMarker);
|
|
37
|
+
if (dynamicActivities.length === 0) {
|
|
38
|
+
this.emit("result", { message: "no activities found", status: "warning" });
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
// step 7: find actions
|
|
42
|
+
const actionFinder = await actions.Finder.loadDynamic(config.sourceDir);
|
|
43
|
+
// step 8: execute the ActivityList
|
|
44
|
+
this.emit("start", { stepCount: dynamicActivities.length });
|
|
45
|
+
process.chdir(config.workspace.platformified());
|
|
46
|
+
await run.sequential(dynamicActivities, actionFinder, config, targets, this);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
process.chdir(originalDir);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
on(name, handler) {
|
|
53
|
+
this.emitter.on(name, handler);
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=dynamic.js.map
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import * as configuration from "../configuration/index.js";
|
|
3
|
+
import * as events from "../events/index.js";
|
|
4
|
+
import * as command from "./index.js";
|
|
5
|
+
/** executes "text-runner run", prints everything, returns the number of errors encountered */
|
|
6
|
+
export declare class Run implements command.Command {
|
|
7
|
+
emitter: EventEmitter;
|
|
8
|
+
userConfig: configuration.APIData;
|
|
9
|
+
constructor(userConfig: configuration.APIData);
|
|
10
|
+
emit(name: events.Name, payload: events.Args): void;
|
|
11
|
+
execute(): Promise<void>;
|
|
12
|
+
on(name: events.Name, handler: events.Handler): this;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=run.d.ts.map
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import * as actions from "../actions/index.js";
|
|
3
|
+
import * as activities from "../activities/index.js";
|
|
4
|
+
import * as configuration from "../configuration/index.js";
|
|
5
|
+
import * as files from "../filesystem/index.js";
|
|
6
|
+
import * as linkTargets from "../link-targets/index.js";
|
|
7
|
+
import * as parser from "../parsers/index.js";
|
|
8
|
+
import * as run from "../run/index.js";
|
|
9
|
+
import * as workspace from "../workspace/index.js";
|
|
10
|
+
/** executes "text-runner run", prints everything, returns the number of errors encountered */
|
|
11
|
+
export class Run {
|
|
12
|
+
constructor(userConfig) {
|
|
13
|
+
this.userConfig = userConfig;
|
|
14
|
+
this.emitter = new EventEmitter();
|
|
15
|
+
}
|
|
16
|
+
emit(name, payload) {
|
|
17
|
+
this.emitter.emit(name, payload);
|
|
18
|
+
}
|
|
19
|
+
async execute() {
|
|
20
|
+
const originalDir = process.cwd();
|
|
21
|
+
try {
|
|
22
|
+
// step 1: determine full configuration
|
|
23
|
+
const config = await configuration.addDefaults(this.userConfig);
|
|
24
|
+
// step 2: create workspace
|
|
25
|
+
await workspace.create(config);
|
|
26
|
+
// step 3: find files
|
|
27
|
+
const filenames = await files.getFileNames(config);
|
|
28
|
+
if (filenames.length === 0) {
|
|
29
|
+
this.emit("result", { message: "no Markdown files found", status: "warning" });
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// step 4: read and parse files
|
|
33
|
+
const ASTs = await parser.markdown.parse(filenames, config.sourceDir);
|
|
34
|
+
// step 5: find link targets
|
|
35
|
+
const targets = linkTargets.find(ASTs);
|
|
36
|
+
// step 6: find actions
|
|
37
|
+
const actionFinder = await actions.Finder.load(config.sourceDir);
|
|
38
|
+
// step 7: extract activities
|
|
39
|
+
const dynamicActivities = activities.extractDynamic(ASTs, config.regionMarker);
|
|
40
|
+
const links = activities.extractImagesAndLinks(ASTs);
|
|
41
|
+
if (dynamicActivities.length + links.length === 0) {
|
|
42
|
+
this.emit("result", { message: "no activities found", status: "warning" });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
// step 8: execute the ActivityList
|
|
46
|
+
const startArgs = { stepCount: dynamicActivities.length + links.length };
|
|
47
|
+
this.emit("start", startArgs);
|
|
48
|
+
process.chdir(config.workspace.platformified());
|
|
49
|
+
// kick off the parallel jobs to run in the background
|
|
50
|
+
const parJobs = run.parallel(links, actionFinder, targets, config, this);
|
|
51
|
+
// execute the serial jobs
|
|
52
|
+
await run.sequential(dynamicActivities, actionFinder, config, targets, this);
|
|
53
|
+
await Promise.all(parJobs);
|
|
54
|
+
// step 9: cleanup
|
|
55
|
+
process.chdir(config.sourceDir.platformified());
|
|
56
|
+
}
|
|
57
|
+
finally {
|
|
58
|
+
process.chdir(originalDir);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
on(name, handler) {
|
|
62
|
+
this.emitter.on(name, handler);
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
import * as configuration from "../configuration/index.js";
|
|
3
|
+
import * as events from "../events/index.js";
|
|
4
|
+
import { Command } from "./command.js";
|
|
5
|
+
export declare class Static implements Command {
|
|
6
|
+
emitter: EventEmitter;
|
|
7
|
+
userConfig: configuration.APIData;
|
|
8
|
+
constructor(userConfig: configuration.APIData);
|
|
9
|
+
emit(name: events.Name, payload: events.Args): void;
|
|
10
|
+
execute(): Promise<void>;
|
|
11
|
+
on(name: events.Name, handler: events.Handler): this;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=static.d.ts.map
|