@eagleoutice/flowr 2.2.1 → 2.2.3
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/cli/flowr.js +2 -1
- package/cli/repl/commands/repl-cfg.js +30 -7
- package/cli/repl/commands/repl-dataflow.js +29 -6
- package/cli/repl/commands/repl-normalize.js +22 -2
- package/cli/repl/commands/repl-parse.js +50 -3
- package/cli/repl/core.js +4 -0
- package/cli/repl/print-version.d.ts +1 -0
- package/cli/repl/print-version.js +7 -2
- package/cli/repl/server/connection.js +11 -9
- package/cli/script-core/statistics-helper-core.js +1 -1
- package/config.js +8 -1
- package/core/pipeline-executor.d.ts +6 -0
- package/core/pipeline-executor.js +8 -0
- package/core/print/dataflow-printer.js +3 -0
- package/core/steps/all/core/01-parse-tree-sitter.d.ts +7 -0
- package/core/steps/pipeline/default-pipelines.d.ts +57 -47
- package/core/steps/pipeline/default-pipelines.js +23 -2
- package/core/steps/pipeline/pipeline.d.ts +1 -1
- package/core/steps/pipeline/pipeline.js +1 -1
- package/core/steps/pipeline-step.d.ts +1 -3
- package/dataflow/environments/resolve-by-name.d.ts +3 -2
- package/dataflow/environments/resolve-by-name.js +4 -4
- package/dataflow/extractor.d.ts +10 -0
- package/dataflow/extractor.js +11 -1
- package/dataflow/graph/dataflowgraph-builder.d.ts +11 -10
- package/dataflow/graph/dataflowgraph-builder.js +11 -10
- package/dataflow/graph/edge.d.ts +1 -1
- package/dataflow/graph/edge.js +2 -2
- package/dataflow/graph/vertex.d.ts +6 -6
- package/dataflow/graph/vertex.js +5 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +9 -5
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +22 -6
- package/documentation/doc-util/doc-cfg.js +2 -2
- package/documentation/doc-util/doc-dfg.d.ts +5 -3
- package/documentation/doc-util/doc-dfg.js +10 -8
- package/documentation/doc-util/doc-files.d.ts +1 -1
- package/documentation/doc-util/doc-files.js +1 -1
- package/documentation/doc-util/doc-normalized-ast.d.ts +2 -1
- package/documentation/doc-util/doc-normalized-ast.js +4 -5
- package/documentation/doc-util/doc-repl.d.ts +6 -2
- package/documentation/doc-util/doc-repl.js +10 -6
- package/documentation/doc-util/doc-structure.d.ts +1 -1
- package/documentation/doc-util/doc-types.d.ts +7 -5
- package/documentation/doc-util/doc-types.js +17 -12
- package/documentation/index.d.ts +9 -0
- package/documentation/index.js +26 -0
- package/documentation/print-capabilities-markdown.js +105 -19
- package/documentation/print-core-wiki.d.ts +1 -0
- package/documentation/print-core-wiki.js +406 -0
- package/documentation/print-dataflow-graph-wiki.js +27 -27
- package/documentation/print-interface-wiki.js +1 -3
- package/documentation/print-linting-and-testing-wiki.js +26 -8
- package/documentation/print-normalized-ast-wiki.js +22 -17
- package/documentation/print-query-wiki.js +37 -7
- package/documentation/print-search-wiki.js +2 -1
- package/package.json +10 -7
- package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
- package/queries/catalog/happens-before-query/happens-before-query-executor.d.ts +1 -1
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +2 -2
- package/queries/catalog/happens-before-query/happens-before-query-format.js +1 -1
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.d.ts +4 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +34 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +72 -0
- package/queries/catalog/resolve-value-query/resolve-value-query-format.js +49 -0
- package/queries/catalog/search-query/search-query-format.js +1 -1
- package/queries/query.d.ts +60 -1
- package/queries/query.js +3 -1
- package/r-bridge/data/data.d.ts +50 -9
- package/r-bridge/data/data.js +64 -10
- package/r-bridge/data/types.d.ts +7 -1
- package/r-bridge/lang-4.x/ast/model/processing/decorate.d.ts +2 -0
- package/r-bridge/lang-4.x/ast/model/processing/node-id.js +2 -5
- package/r-bridge/lang-4.x/ast/parser/json/format.d.ts +6 -0
- package/r-bridge/lang-4.x/ast/parser/json/format.js +6 -0
- package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +13 -2
- package/r-bridge/lang-4.x/ast/parser/json/parser.js +19 -3
- package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.d.ts +3 -0
- package/r-bridge/lang-4.x/ast/parser/main/internal/structure/normalize-root.js +3 -0
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +51 -29
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-types.d.ts +4 -1
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-types.js +3 -0
- package/r-bridge/parser.d.ts +10 -0
- package/r-bridge/parser.js +26 -2
- package/search/flowr-search-builder.d.ts +1 -2
- package/search/flowr-search-builder.js +1 -3
- package/util/cfg/cfg.d.ts +10 -1
- package/util/cfg/cfg.js +56 -2
- package/util/mermaid/dfg.d.ts +3 -0
- package/util/mermaid/dfg.js +24 -8
- package/util/range.d.ts +21 -0
- package/util/range.js +3 -0
- package/util/strings.d.ts +9 -0
- package/util/strings.js +14 -0
- package/util/version.js +1 -1
|
@@ -7,6 +7,9 @@ const retriever_1 = require("../../../../retriever");
|
|
|
7
7
|
const assert_1 = require("../../../../../util/assert");
|
|
8
8
|
const type_1 = require("../../model/type");
|
|
9
9
|
exports.RootId = 0;
|
|
10
|
+
/**
|
|
11
|
+
* Takes the raw {@link RShell} output and extracts the csv information contained
|
|
12
|
+
*/
|
|
10
13
|
function prepareParsedData(data) {
|
|
11
14
|
let json;
|
|
12
15
|
try {
|
|
@@ -36,6 +39,9 @@ function prepareParsedData(data) {
|
|
|
36
39
|
}
|
|
37
40
|
return roots;
|
|
38
41
|
}
|
|
42
|
+
/**
|
|
43
|
+
* Takes the CSV-Entries and maps them to the old json format for compatibility.
|
|
44
|
+
*/
|
|
39
45
|
function convertPreparedParsedData(roots) {
|
|
40
46
|
const partialEntry = {
|
|
41
47
|
token: type_1.RawRType.ExpressionList,
|
|
@@ -1,10 +1,21 @@
|
|
|
1
1
|
import type { IdGenerator, NormalizedAst } from '../../model/processing/decorate';
|
|
2
|
-
import type { NoInfo } from '../../model/model';
|
|
2
|
+
import type { NoInfo, RNode } from '../../model/model';
|
|
3
3
|
import type { ParseStepOutputTS } from '../../../../../core/steps/all/core/01-parse-tree-sitter';
|
|
4
4
|
import type { ParseStepOutput } from '../../../../parser';
|
|
5
5
|
export declare const parseLog: import("tslog").Logger<import("tslog").ILogObj>;
|
|
6
6
|
/**
|
|
7
7
|
* Take the output as produced by the parse step and normalize the AST from the R parser.
|
|
8
|
+
*
|
|
9
|
+
* @see {@link normalizeButNotDecorated} for a version that does not decorate the AST
|
|
10
|
+
* @see {@link normalizeTreeSitter} for a version that normalizes the AST from the TreeSitter parser
|
|
11
|
+
*/
|
|
12
|
+
export declare function normalize(parsed: ParseStepOutput<string>, getId?: IdGenerator<NoInfo>, file?: string): NormalizedAst;
|
|
13
|
+
/**
|
|
14
|
+
* Take the output as produced by the parse step and normalize the AST from the R parser.
|
|
15
|
+
* For additional decoration with ${@link decorateAst} use {@link normalize}.
|
|
16
|
+
*/
|
|
17
|
+
export declare function normalizeButNotDecorated({ parsed }: ParseStepOutput<string>): RNode;
|
|
18
|
+
/**
|
|
19
|
+
* Tree-Sitter pendant to {@link normalize}.
|
|
8
20
|
*/
|
|
9
|
-
export declare function normalize({ parsed }: ParseStepOutput<string>, getId?: IdGenerator<NoInfo>, file?: string): NormalizedAst;
|
|
10
21
|
export declare function normalizeTreeSitter({ parsed }: ParseStepOutputTS, getId?: IdGenerator<NoInfo>, file?: string): NormalizedAst;
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseLog = void 0;
|
|
4
4
|
exports.normalize = normalize;
|
|
5
|
+
exports.normalizeButNotDecorated = normalizeButNotDecorated;
|
|
5
6
|
exports.normalizeTreeSitter = normalizeTreeSitter;
|
|
6
7
|
const format_1 = require("./format");
|
|
7
8
|
const log_1 = require("../../../../../util/log");
|
|
@@ -11,13 +12,28 @@ const tree_sitter_normalize_1 = require("../../../tree-sitter/tree-sitter-normal
|
|
|
11
12
|
exports.parseLog = log_1.log.getSubLogger({ name: 'ast-parser' });
|
|
12
13
|
/**
|
|
13
14
|
* Take the output as produced by the parse step and normalize the AST from the R parser.
|
|
15
|
+
*
|
|
16
|
+
* @see {@link normalizeButNotDecorated} for a version that does not decorate the AST
|
|
17
|
+
* @see {@link normalizeTreeSitter} for a version that normalizes the AST from the TreeSitter parser
|
|
14
18
|
*/
|
|
15
|
-
function normalize(
|
|
19
|
+
function normalize(parsed, getId = (0, decorate_1.deterministicCountingIdGenerator)(0), file) {
|
|
20
|
+
return (0, decorate_1.decorateAst)(normalizeButNotDecorated(parsed), { getId, file });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Take the output as produced by the parse step and normalize the AST from the R parser.
|
|
24
|
+
* For additional decoration with ${@link decorateAst} use {@link normalize}.
|
|
25
|
+
*/
|
|
26
|
+
function normalizeButNotDecorated({ parsed }) {
|
|
16
27
|
const data = { currentRange: undefined, currentLexeme: undefined };
|
|
17
28
|
const object = (0, format_1.convertPreparedParsedData)((0, format_1.prepareParsedData)(parsed));
|
|
18
|
-
return (0,
|
|
29
|
+
return (0, normalize_root_1.normalizeRootObjToAst)(data, object);
|
|
19
30
|
}
|
|
31
|
+
/**
|
|
32
|
+
* Tree-Sitter pendant to {@link normalize}.
|
|
33
|
+
*/
|
|
20
34
|
function normalizeTreeSitter({ parsed }, getId = (0, decorate_1.deterministicCountingIdGenerator)(0), file) {
|
|
21
|
-
|
|
35
|
+
const result = (0, decorate_1.decorateAst)((0, tree_sitter_normalize_1.normalizeTreeSitterTreeToAst)(parsed), { getId, file });
|
|
36
|
+
result.hasError = parsed.rootNode.hasError;
|
|
37
|
+
return result;
|
|
22
38
|
}
|
|
23
39
|
//# sourceMappingURL=parser.js.map
|
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import type { NormalizerData } from '../../normalizer-data';
|
|
2
2
|
import type { RExpressionList } from '../../../../model/nodes/r-expression-list';
|
|
3
3
|
import type { JsonEntry } from '../../../json/format';
|
|
4
|
+
/**
|
|
5
|
+
* Takes the parse dta as object and produces an undecorated, normalized AST.
|
|
6
|
+
*/
|
|
4
7
|
export declare function normalizeRootObjToAst(data: NormalizerData, obj: JsonEntry): RExpressionList;
|
|
@@ -6,6 +6,9 @@ const normalize_expressions_1 = require("./normalize-expressions");
|
|
|
6
6
|
const log_1 = require("../../../../../../../util/log");
|
|
7
7
|
const arrays_1 = require("../../../../../../../util/arrays");
|
|
8
8
|
const type_1 = require("../../../../model/type");
|
|
9
|
+
/**
|
|
10
|
+
* Takes the parse dta as object and produces an undecorated, normalized AST.
|
|
11
|
+
*/
|
|
9
12
|
function normalizeRootObjToAst(data, obj) {
|
|
10
13
|
const exprContent = obj.token;
|
|
11
14
|
(0, normalize_meta_1.assureTokenType)(exprContent, type_1.RawRType.ExpressionList);
|
|
@@ -17,6 +17,14 @@ function normalizeTreeSitterTreeToAst(tree) {
|
|
|
17
17
|
}
|
|
18
18
|
return root;
|
|
19
19
|
}
|
|
20
|
+
function nonErrorChildren(node) {
|
|
21
|
+
if (node.hasError) {
|
|
22
|
+
return [];
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
return node.children;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
20
28
|
function convertTreeNode(node) {
|
|
21
29
|
// generally, the grammar source file dictates what children a node has in what order:
|
|
22
30
|
// https://github.com/r-lib/tree-sitter-r/blob/main/grammar.js
|
|
@@ -30,7 +38,7 @@ function convertTreeNode(node) {
|
|
|
30
38
|
};
|
|
31
39
|
switch (node.type) {
|
|
32
40
|
case tree_sitter_types_1.TreeSitterType.Program: {
|
|
33
|
-
const [comments, children] = splitComments(node
|
|
41
|
+
const [comments, children] = splitComments(nonErrorChildren(node));
|
|
34
42
|
const body = children.map(n => [n, convertTreeNode(n)]);
|
|
35
43
|
const remainingComments = linkCommentsToNextNodes(body, comments);
|
|
36
44
|
return {
|
|
@@ -45,7 +53,7 @@ function convertTreeNode(node) {
|
|
|
45
53
|
}
|
|
46
54
|
case tree_sitter_types_1.TreeSitterType.BracedExpression:
|
|
47
55
|
case tree_sitter_types_1.TreeSitterType.ParenthesizedExpression: {
|
|
48
|
-
const [comments, children] = splitComments(node
|
|
56
|
+
const [comments, children] = splitComments(nonErrorChildren(node));
|
|
49
57
|
const opening = children[0];
|
|
50
58
|
const body = children.slice(1, -1).map(n => [n, convertTreeNode(n)]);
|
|
51
59
|
const remainingComments = linkCommentsToNextNodes(body, comments);
|
|
@@ -78,9 +86,10 @@ function convertTreeNode(node) {
|
|
|
78
86
|
};
|
|
79
87
|
}
|
|
80
88
|
case tree_sitter_types_1.TreeSitterType.BinaryOperator: {
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
89
|
+
const children = nonErrorChildren(node);
|
|
90
|
+
const lhs = convertTreeNode(children[0]);
|
|
91
|
+
const rhs = convertTreeNode(children[children.length - 1]);
|
|
92
|
+
const [commentsBoth, [op]] = splitComments(children.slice(1, -1));
|
|
84
93
|
const comments = commentsBoth.map(c => c[1]);
|
|
85
94
|
const opSource = makeSourceRange(op);
|
|
86
95
|
const lhsAsArg = {
|
|
@@ -150,7 +159,7 @@ function convertTreeNode(node) {
|
|
|
150
159
|
}
|
|
151
160
|
}
|
|
152
161
|
case tree_sitter_types_1.TreeSitterType.UnaryOperator: {
|
|
153
|
-
const [op, operand] = node
|
|
162
|
+
const [op, operand] = nonErrorChildren(node);
|
|
154
163
|
return {
|
|
155
164
|
type: type_1.RType.UnaryOp,
|
|
156
165
|
operand: convertTreeNode(operand),
|
|
@@ -161,7 +170,7 @@ function convertTreeNode(node) {
|
|
|
161
170
|
};
|
|
162
171
|
}
|
|
163
172
|
case tree_sitter_types_1.TreeSitterType.NamespaceOperator: {
|
|
164
|
-
const [lhs, /* :: or ::: */ , rhs] = node
|
|
173
|
+
const [lhs, /* :: or ::: */ , rhs] = nonErrorChildren(node);
|
|
165
174
|
return {
|
|
166
175
|
type: type_1.RType.Symbol,
|
|
167
176
|
location: makeSourceRange(rhs),
|
|
@@ -176,6 +185,7 @@ function convertTreeNode(node) {
|
|
|
176
185
|
case tree_sitter_types_1.TreeSitterType.Na:
|
|
177
186
|
case tree_sitter_types_1.TreeSitterType.Null:
|
|
178
187
|
case tree_sitter_types_1.TreeSitterType.Dots:
|
|
188
|
+
case tree_sitter_types_1.TreeSitterType.DotDotI:
|
|
179
189
|
case tree_sitter_types_1.TreeSitterType.Identifier:
|
|
180
190
|
case tree_sitter_types_1.TreeSitterType.Return:
|
|
181
191
|
return {
|
|
@@ -187,22 +197,24 @@ function convertTreeNode(node) {
|
|
|
187
197
|
...defaultInfo
|
|
188
198
|
};
|
|
189
199
|
case tree_sitter_types_1.TreeSitterType.IfStatement: {
|
|
190
|
-
const [ifNode, /* ( */ , condition, /* ) */ , then, /* else */ , ...otherwise] = node
|
|
200
|
+
const [ifNode, /* ( */ , condition, /* ) */ , then, /* else */ , ...otherwise] = nonErrorChildren(node);
|
|
201
|
+
const filteredOtherwise = otherwise.filter(n => n.type !== tree_sitter_types_1.TreeSitterType.ElseStatement);
|
|
191
202
|
return {
|
|
192
203
|
type: type_1.RType.IfThenElse,
|
|
193
204
|
condition: convertTreeNode(condition),
|
|
194
205
|
then: (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(then)),
|
|
195
|
-
otherwise:
|
|
206
|
+
otherwise: filteredOtherwise.length > 0 ? (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(filteredOtherwise[0])) : undefined,
|
|
196
207
|
location: makeSourceRange(ifNode),
|
|
197
208
|
lexeme: ifNode.text,
|
|
198
209
|
...defaultInfo
|
|
199
210
|
};
|
|
200
211
|
}
|
|
201
212
|
case tree_sitter_types_1.TreeSitterType.ForStatement: {
|
|
202
|
-
const
|
|
203
|
-
const
|
|
204
|
-
const
|
|
205
|
-
const
|
|
213
|
+
const children = nonErrorChildren(node);
|
|
214
|
+
const forNode = children[0]; // we follow with a (
|
|
215
|
+
const variable = getNodesUntil(children, 'in', 2); // we follow with the "in"
|
|
216
|
+
const sequence = getNodesUntil(children, ')', 2 + variable.length + 1); // we follow with a (
|
|
217
|
+
const body = children[2 + variable.length + 1 + sequence.length + 1];
|
|
206
218
|
const [variableComments, [variableNode]] = splitComments(variable);
|
|
207
219
|
const [sequenceComments, [sequenceNode]] = splitComments(sequence);
|
|
208
220
|
return {
|
|
@@ -231,7 +243,7 @@ function convertTreeNode(node) {
|
|
|
231
243
|
};
|
|
232
244
|
}
|
|
233
245
|
case tree_sitter_types_1.TreeSitterType.WhileStatement: {
|
|
234
|
-
const [whileNode, /* ( */ , condition, /* ) */ , body] = node
|
|
246
|
+
const [whileNode, /* ( */ , condition, /* ) */ , body] = nonErrorChildren(node);
|
|
235
247
|
return {
|
|
236
248
|
type: type_1.RType.WhileLoop,
|
|
237
249
|
condition: convertTreeNode(condition),
|
|
@@ -242,7 +254,7 @@ function convertTreeNode(node) {
|
|
|
242
254
|
};
|
|
243
255
|
}
|
|
244
256
|
case tree_sitter_types_1.TreeSitterType.RepeatStatement: {
|
|
245
|
-
const [repeatNode, body] = node
|
|
257
|
+
const [repeatNode, body] = nonErrorChildren(node);
|
|
246
258
|
return {
|
|
247
259
|
type: type_1.RType.RepeatLoop,
|
|
248
260
|
body: (0, normalize_meta_1.ensureExpressionList)(convertTreeNode(body)),
|
|
@@ -252,7 +264,7 @@ function convertTreeNode(node) {
|
|
|
252
264
|
};
|
|
253
265
|
}
|
|
254
266
|
case tree_sitter_types_1.TreeSitterType.Call: {
|
|
255
|
-
const [func, argsParentheses] = node
|
|
267
|
+
const [func, argsParentheses] = nonErrorChildren(node);
|
|
256
268
|
// tree-sitter wraps next and break in a function call, but we don't, so unwrap
|
|
257
269
|
if (func.type === tree_sitter_types_1.TreeSitterType.Next || func.type == tree_sitter_types_1.TreeSitterType.Break) {
|
|
258
270
|
return {
|
|
@@ -260,7 +272,7 @@ function convertTreeNode(node) {
|
|
|
260
272
|
...defaultInfo
|
|
261
273
|
};
|
|
262
274
|
}
|
|
263
|
-
const args = (0, arrays_1.splitArrayOn)(argsParentheses.
|
|
275
|
+
const args = (0, arrays_1.splitArrayOn)(nonErrorChildren(argsParentheses).slice(1, -1), x => x.type === 'comma');
|
|
264
276
|
const funcRange = makeSourceRange(func);
|
|
265
277
|
const call = {
|
|
266
278
|
arguments: args.map(n => n.length == 0 ? r_function_call_1.EmptyArgument : convertTreeNode(n[0])),
|
|
@@ -302,7 +314,7 @@ function convertTreeNode(node) {
|
|
|
302
314
|
}
|
|
303
315
|
}
|
|
304
316
|
case tree_sitter_types_1.TreeSitterType.FunctionDefinition: {
|
|
305
|
-
const [name, paramsParens, body] = node
|
|
317
|
+
const [name, paramsParens, body] = nonErrorChildren(node);
|
|
306
318
|
const params = (0, arrays_1.splitArrayOn)(paramsParens.children.slice(1, -1), x => x.type === 'comma');
|
|
307
319
|
return {
|
|
308
320
|
type: type_1.RType.FunctionDefinition,
|
|
@@ -353,9 +365,9 @@ function convertTreeNode(node) {
|
|
|
353
365
|
case tree_sitter_types_1.TreeSitterType.Subset:
|
|
354
366
|
case tree_sitter_types_1.TreeSitterType.Subset2: {
|
|
355
367
|
// subset has children like a and [x]
|
|
356
|
-
const [func, content] = node
|
|
368
|
+
const [func, content] = nonErrorChildren(node);
|
|
357
369
|
// bracket is now [ or [[ and argsClosing is x] or x]]
|
|
358
|
-
const [bracket, ...argsClosing] = content
|
|
370
|
+
const [bracket, ...argsClosing] = nonErrorChildren(content);
|
|
359
371
|
const args = (0, arrays_1.splitArrayOn)(argsClosing.slice(0, -1), x => x.type === 'comma');
|
|
360
372
|
return {
|
|
361
373
|
type: type_1.RType.Access,
|
|
@@ -368,7 +380,7 @@ function convertTreeNode(node) {
|
|
|
368
380
|
};
|
|
369
381
|
}
|
|
370
382
|
case tree_sitter_types_1.TreeSitterType.ExtractOperator: {
|
|
371
|
-
const [lhs, operator, rhs] = node
|
|
383
|
+
const [lhs, operator, rhs] = nonErrorChildren(node);
|
|
372
384
|
const rhsRange = makeSourceRange(rhs);
|
|
373
385
|
return {
|
|
374
386
|
type: type_1.RType.Access,
|
|
@@ -395,11 +407,12 @@ function convertTreeNode(node) {
|
|
|
395
407
|
};
|
|
396
408
|
}
|
|
397
409
|
case tree_sitter_types_1.TreeSitterType.Parameter: {
|
|
398
|
-
const
|
|
410
|
+
const children = nonErrorChildren(node);
|
|
411
|
+
const name = children[0];
|
|
399
412
|
const nameRange = makeSourceRange(name);
|
|
400
413
|
let defaultValue = undefined;
|
|
401
|
-
if (
|
|
402
|
-
defaultValue = convertTreeNode(
|
|
414
|
+
if (children.length == 3) {
|
|
415
|
+
defaultValue = convertTreeNode(children[2]);
|
|
403
416
|
}
|
|
404
417
|
return {
|
|
405
418
|
type: type_1.RType.Parameter,
|
|
@@ -427,8 +440,9 @@ function convertTreeNode(node) {
|
|
|
427
440
|
};
|
|
428
441
|
}
|
|
429
442
|
case tree_sitter_types_1.TreeSitterType.Argument: {
|
|
430
|
-
|
|
431
|
-
|
|
443
|
+
const children = nonErrorChildren(node);
|
|
444
|
+
if (children.length == 1) {
|
|
445
|
+
const [arg] = children;
|
|
432
446
|
return {
|
|
433
447
|
type: type_1.RType.Argument,
|
|
434
448
|
name: undefined,
|
|
@@ -439,7 +453,7 @@ function convertTreeNode(node) {
|
|
|
439
453
|
};
|
|
440
454
|
}
|
|
441
455
|
else {
|
|
442
|
-
const [nameNode, /* = */ , valueNode] =
|
|
456
|
+
const [nameNode, /* = */ , valueNode] = children;
|
|
443
457
|
let name = convertTreeNode(nameNode);
|
|
444
458
|
// unescape argument names
|
|
445
459
|
if (name.type === type_1.RType.String) {
|
|
@@ -457,7 +471,7 @@ function convertTreeNode(node) {
|
|
|
457
471
|
return {
|
|
458
472
|
type: type_1.RType.Argument,
|
|
459
473
|
name: name,
|
|
460
|
-
value: convertTreeNode(valueNode),
|
|
474
|
+
value: valueNode ? convertTreeNode(valueNode) : undefined,
|
|
461
475
|
location: nameRange,
|
|
462
476
|
lexeme: nameNode.text,
|
|
463
477
|
info: {
|
|
@@ -468,8 +482,16 @@ function convertTreeNode(node) {
|
|
|
468
482
|
};
|
|
469
483
|
}
|
|
470
484
|
}
|
|
485
|
+
case tree_sitter_types_1.TreeSitterType.Comment:
|
|
486
|
+
return {
|
|
487
|
+
type: type_1.RType.Comment,
|
|
488
|
+
location: range,
|
|
489
|
+
content: node.text.slice(1),
|
|
490
|
+
lexeme: node.text,
|
|
491
|
+
...defaultInfo
|
|
492
|
+
};
|
|
471
493
|
default:
|
|
472
|
-
throw new normalizer_data_1.ParseError(`unexpected node type ${node.type}`);
|
|
494
|
+
throw new normalizer_data_1.ParseError(`unexpected node type ${node.type} at ${JSON.stringify(range)}`);
|
|
473
495
|
}
|
|
474
496
|
}
|
|
475
497
|
function makeSourceRange(node) {
|
|
@@ -7,6 +7,7 @@ export declare enum TreeSitterType {
|
|
|
7
7
|
NamespaceOperator = "namespace_operator",
|
|
8
8
|
Identifier = "identifier",
|
|
9
9
|
IfStatement = "if_statement",
|
|
10
|
+
ElseStatement = "else",
|
|
10
11
|
ForStatement = "for_statement",
|
|
11
12
|
WhileStatement = "while_statement",
|
|
12
13
|
RepeatStatement = "repeat_statement",
|
|
@@ -31,5 +32,7 @@ export declare enum TreeSitterType {
|
|
|
31
32
|
Parameter = "parameter",
|
|
32
33
|
Argument = "argument",
|
|
33
34
|
Dots = "dots",
|
|
34
|
-
|
|
35
|
+
DotDotI = "dot_dot_i",
|
|
36
|
+
Comment = "comment",
|
|
37
|
+
Error = "ERROR"
|
|
35
38
|
}
|
|
@@ -11,6 +11,7 @@ var TreeSitterType;
|
|
|
11
11
|
TreeSitterType["NamespaceOperator"] = "namespace_operator";
|
|
12
12
|
TreeSitterType["Identifier"] = "identifier";
|
|
13
13
|
TreeSitterType["IfStatement"] = "if_statement";
|
|
14
|
+
TreeSitterType["ElseStatement"] = "else";
|
|
14
15
|
TreeSitterType["ForStatement"] = "for_statement";
|
|
15
16
|
TreeSitterType["WhileStatement"] = "while_statement";
|
|
16
17
|
TreeSitterType["RepeatStatement"] = "repeat_statement";
|
|
@@ -35,6 +36,8 @@ var TreeSitterType;
|
|
|
35
36
|
TreeSitterType["Parameter"] = "parameter";
|
|
36
37
|
TreeSitterType["Argument"] = "argument";
|
|
37
38
|
TreeSitterType["Dots"] = "dots";
|
|
39
|
+
TreeSitterType["DotDotI"] = "dot_dot_i";
|
|
38
40
|
TreeSitterType["Comment"] = "comment";
|
|
41
|
+
TreeSitterType["Error"] = "ERROR";
|
|
39
42
|
})(TreeSitterType || (exports.TreeSitterType = TreeSitterType = {}));
|
|
40
43
|
//# sourceMappingURL=tree-sitter-types.js.map
|
package/r-bridge/parser.d.ts
CHANGED
|
@@ -27,6 +27,16 @@ export interface ParseRequiredInput<T> {
|
|
|
27
27
|
export interface ParseStepOutput<T> {
|
|
28
28
|
/** The parsed AST of the R code as given by the R parse side */
|
|
29
29
|
readonly parsed: T;
|
|
30
|
+
/** Additional meta information about the parse */
|
|
31
|
+
readonly '.parse-meta'?: {
|
|
32
|
+
/** The number of tokens in the AST */
|
|
33
|
+
readonly tokenCount: number;
|
|
34
|
+
};
|
|
30
35
|
}
|
|
36
|
+
/**
|
|
37
|
+
* Takes an input program and parses it using the given parser.
|
|
38
|
+
* @param _results - just a proxy for the pipeline, signifies that this function does not need prior knowledge of the pipeline
|
|
39
|
+
* @param input - the input to the parse step
|
|
40
|
+
*/
|
|
31
41
|
export declare function parseRequests<T extends KnownParserType>(_results: unknown, input: Partial<ParseRequiredInput<T>>): Promise<ParseStepOutput<T>>;
|
|
32
42
|
export {};
|
package/r-bridge/parser.js
CHANGED
|
@@ -1,14 +1,38 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.parseRequests = parseRequests;
|
|
4
|
+
function countChildren(node) {
|
|
5
|
+
let ret = 1;
|
|
6
|
+
for (const child of node.children) {
|
|
7
|
+
ret += countChildren(child);
|
|
8
|
+
}
|
|
9
|
+
return ret;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Takes an input program and parses it using the given parser.
|
|
13
|
+
* @param _results - just a proxy for the pipeline, signifies that this function does not need prior knowledge of the pipeline
|
|
14
|
+
* @param input - the input to the parse step
|
|
15
|
+
*/
|
|
4
16
|
async function parseRequests(_results, input) {
|
|
5
17
|
/* in the future, we want to expose all cases */
|
|
6
18
|
const request = (Array.isArray(input.request) ? input.request[0] : input.request);
|
|
7
19
|
if (input.parser?.async) {
|
|
8
|
-
|
|
20
|
+
const parsed = await input.parser.parse(request);
|
|
21
|
+
return {
|
|
22
|
+
parsed,
|
|
23
|
+
'.parse-meta': typeof parsed === 'object' && 'rootNode' in parsed ? {
|
|
24
|
+
tokenCount: countChildren(parsed.rootNode),
|
|
25
|
+
} : undefined
|
|
26
|
+
};
|
|
9
27
|
}
|
|
10
28
|
else {
|
|
11
|
-
|
|
29
|
+
const parsed = input.parser.parse(request);
|
|
30
|
+
return {
|
|
31
|
+
parsed,
|
|
32
|
+
'.parse-meta': typeof parsed === 'object' && 'rootNode' in parsed ? {
|
|
33
|
+
tokenCount: countChildren(parsed.rootNode),
|
|
34
|
+
} : undefined
|
|
35
|
+
};
|
|
12
36
|
}
|
|
13
37
|
}
|
|
14
38
|
//# sourceMappingURL=parser.js.map
|
|
@@ -111,7 +111,6 @@ export declare const Q: {
|
|
|
111
111
|
readonly id: (id: NodeId) => FlowrSearchBuilder<"get">;
|
|
112
112
|
};
|
|
113
113
|
export type FlowrSearchBuilderType<Generator extends GeneratorNames = GeneratorNames, Transformers extends TransformerNames[] = TransformerNames[], Info = ParentInformation, ElementType = FlowrSearchElements<Info, FlowrSearchElement<Info>[]>> = FlowrSearchBuilder<Generator, Transformers, Info, ElementType>;
|
|
114
|
-
type GetElements<F> = F extends FlowrSearchElements<infer Info, infer Elements> ? Elements extends FlowrSearchElement<Info>[] ? Elements : never : never;
|
|
115
114
|
/**
|
|
116
115
|
* The search query is a combination of a generator and a list of transformers
|
|
117
116
|
* and allows this view to pass such queries in a serialized form.
|
|
@@ -172,7 +171,7 @@ export declare class FlowrSearchBuilder<Generator extends GeneratorNames, Transf
|
|
|
172
171
|
/**
|
|
173
172
|
* merge combines the search results with those of another search.
|
|
174
173
|
*/
|
|
175
|
-
merge<Generator2 extends GeneratorNames, Transformers2 extends TransformerNames[], OtherElementType extends FlowrSearchElements<Info, FlowrSearchElement<Info>[]>>(other: FlowrSearchBuilder<Generator2, Transformers2, Info, OtherElementType>): FlowrSearchBuilder<Generator, Transformers, Info
|
|
174
|
+
merge<Generator2 extends GeneratorNames, Transformers2 extends TransformerNames[], OtherElementType extends FlowrSearchElements<Info, FlowrSearchElement<Info>[]>>(other: FlowrSearchBuilder<Generator2, Transformers2, Info, OtherElementType>): FlowrSearchBuilder<Generator, Transformers, Info>;
|
|
176
175
|
/**
|
|
177
176
|
* Construct the final search (this may happen automatically with most search handlers).
|
|
178
177
|
*
|
|
@@ -161,9 +161,7 @@ class FlowrSearchBuilder {
|
|
|
161
161
|
/**
|
|
162
162
|
* merge combines the search results with those of another search.
|
|
163
163
|
*/
|
|
164
|
-
merge(other /* | FlowrSearch<Info, Generator2, Transformers2, OtherElementType> */
|
|
165
|
-
// @ts-expect-error -- this works when merging, there is no info disparity
|
|
166
|
-
) {
|
|
164
|
+
merge(other /* | FlowrSearch<Info, Generator2, Transformers2, OtherElementType> */) {
|
|
167
165
|
this.search.push({ type: 'transformer', name: 'merge', args: { generator: other.generator, search: other.search } });
|
|
168
166
|
return this;
|
|
169
167
|
}
|
package/util/cfg/cfg.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { QuadSerializationConfiguration } from '../quads';
|
|
|
3
3
|
import type { NodeId } from '../../r-bridge/lang-4.x/ast/model/processing/node-id';
|
|
4
4
|
import type { NormalizedAst, ParentInformation } from '../../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
5
5
|
import { RFalse, RTrue } from '../../r-bridge/lang-4.x/convert-values';
|
|
6
|
+
import type { DataflowGraph } from '../../dataflow/graph/graph';
|
|
6
7
|
export declare const enum CfgVertexType {
|
|
7
8
|
/** Marks a break point in a construct (e.g., between the name and the value of an argument, or the formals and the body of a function) */
|
|
8
9
|
MidMarker = "mid-marker",
|
|
@@ -57,7 +58,15 @@ export interface ControlFlowInformation extends MergeableRecord {
|
|
|
57
58
|
graph: ControlFlowGraph;
|
|
58
59
|
}
|
|
59
60
|
export declare function emptyControlFlowInformation(): ControlFlowInformation;
|
|
60
|
-
|
|
61
|
+
/**
|
|
62
|
+
* Given a normalized AST this approximates the control flow graph of the program.
|
|
63
|
+
* This few is different from the computation of the dataflow graph and may differ,
|
|
64
|
+
* especially because it focuses on intra-procedural analysis.
|
|
65
|
+
*
|
|
66
|
+
* @param ast - the normalized AST
|
|
67
|
+
* @param graph - additional dataflow facts to consider by the control flow extraction
|
|
68
|
+
*/
|
|
69
|
+
export declare function extractCFG<Info = ParentInformation>(ast: NormalizedAst<Info>, graph?: DataflowGraph): ControlFlowInformation;
|
|
61
70
|
/**
|
|
62
71
|
* Returns true if the given CFG equals the other CFG. False otherwise.
|
|
63
72
|
*/
|
package/util/cfg/cfg.js
CHANGED
|
@@ -12,6 +12,8 @@ const json_1 = require("../json");
|
|
|
12
12
|
const fold_1 = require("../../r-bridge/lang-4.x/ast/model/processing/fold");
|
|
13
13
|
const convert_values_1 = require("../../r-bridge/lang-4.x/convert-values");
|
|
14
14
|
const r_function_call_1 = require("../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
|
|
15
|
+
const linker_1 = require("../../dataflow/internal/linker");
|
|
16
|
+
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
15
17
|
/**
|
|
16
18
|
* This class represents the control flow graph of an R program.
|
|
17
19
|
* The control flow may be hierarchical when confronted with function definitions (see {@link CfgVertex} and {@link CFG#rootVertexIds|rootVertexIds()}).
|
|
@@ -101,8 +103,25 @@ const cfgFolds = {
|
|
|
101
103
|
foldArgument: cfgArgumentOrParameter
|
|
102
104
|
}
|
|
103
105
|
};
|
|
104
|
-
function
|
|
105
|
-
return
|
|
106
|
+
function dataflowCfgFolds(dataflowGraph) {
|
|
107
|
+
return {
|
|
108
|
+
...cfgFolds,
|
|
109
|
+
functions: {
|
|
110
|
+
...cfgFolds.functions,
|
|
111
|
+
foldFunctionCall: cfgFunctionCallWithDataflow(dataflowGraph)
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Given a normalized AST this approximates the control flow graph of the program.
|
|
117
|
+
* This few is different from the computation of the dataflow graph and may differ,
|
|
118
|
+
* especially because it focuses on intra-procedural analysis.
|
|
119
|
+
*
|
|
120
|
+
* @param ast - the normalized AST
|
|
121
|
+
* @param graph - additional dataflow facts to consider by the control flow extraction
|
|
122
|
+
*/
|
|
123
|
+
function extractCFG(ast, graph) {
|
|
124
|
+
return (0, fold_1.foldAst)(ast.ast, graph ? dataflowCfgFolds(graph) : cfgFolds);
|
|
106
125
|
}
|
|
107
126
|
function cfgLeaf(type) {
|
|
108
127
|
return (leaf) => {
|
|
@@ -253,6 +272,9 @@ function cfgFunctionDefinition(fn, params, body) {
|
|
|
253
272
|
graph.addEdge(fn.info.id + '-params', exit, { label: 'FD' });
|
|
254
273
|
}
|
|
255
274
|
}
|
|
275
|
+
if (params.length === 0) {
|
|
276
|
+
graph.addEdge(fn.info.id + '-params', fn.info.id, { label: 'FD' });
|
|
277
|
+
}
|
|
256
278
|
for (const entry of body.entryPoints) {
|
|
257
279
|
graph.addEdge(entry, fn.info.id + '-params', { label: 'FD' });
|
|
258
280
|
}
|
|
@@ -296,6 +318,38 @@ function cfgFunctionCall(call, name, args) {
|
|
|
296
318
|
// should not contain any breaks, nexts, or returns, (except for the body if something like 'break()')
|
|
297
319
|
return info;
|
|
298
320
|
}
|
|
321
|
+
function cfgFunctionCallWithDataflow(graph) {
|
|
322
|
+
return (call, name, args) => {
|
|
323
|
+
const baseCFG = cfgFunctionCall(call, name, args);
|
|
324
|
+
/* try to resolve the call and link the target definitions */
|
|
325
|
+
const targets = (0, linker_1.getAllFunctionCallTargets)(call.info.id, graph);
|
|
326
|
+
const exits = [];
|
|
327
|
+
for (const target of targets) {
|
|
328
|
+
// we have to filter out non func-call targets as the call targets contains names and call ids
|
|
329
|
+
if ((0, vertex_1.isFunctionDefinitionVertex)(graph.getVertex(target))) {
|
|
330
|
+
baseCFG.graph.addEdge(call.info.id, target, { label: 'FD' });
|
|
331
|
+
exits.push(target + '-exit');
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (exits.length > 0) {
|
|
335
|
+
baseCFG.graph.addVertex({
|
|
336
|
+
id: call.info.id + '-resolved-call-exit',
|
|
337
|
+
name: 'resolved-call-exit',
|
|
338
|
+
type: "end-marker" /* CfgVertexType.EndMarker */
|
|
339
|
+
});
|
|
340
|
+
for (const exit of [...baseCFG.exitPoints, ...exits]) {
|
|
341
|
+
baseCFG.graph.addEdge(call.info.id + '-resolved-call-exit', exit, { label: 'FD' });
|
|
342
|
+
}
|
|
343
|
+
return {
|
|
344
|
+
...baseCFG,
|
|
345
|
+
exitPoints: [call.info.id + '-resolved-call-exit']
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
else {
|
|
349
|
+
return baseCFG;
|
|
350
|
+
}
|
|
351
|
+
};
|
|
352
|
+
}
|
|
299
353
|
function cfgArgumentOrParameter(node, name, value) {
|
|
300
354
|
const graph = new ControlFlowGraph();
|
|
301
355
|
const info = { graph, breaks: [], nexts: [], returns: [], exitPoints: [node.info.id + '-exit'], entryPoints: [node.info.id] };
|
package/util/mermaid/dfg.d.ts
CHANGED
|
@@ -18,6 +18,8 @@ interface MermaidGraph {
|
|
|
18
18
|
/** in the form of from-\>to because I am lazy, see {@link encodeEdge} */
|
|
19
19
|
presentEdges: Set<string>;
|
|
20
20
|
rootGraph: DataflowGraph;
|
|
21
|
+
/** if given, the dataflow graph will only focus on the "important" parts */
|
|
22
|
+
simplified?: boolean;
|
|
21
23
|
}
|
|
22
24
|
/**
|
|
23
25
|
* Prints a {@link SourceRange|range} as a human readable string.
|
|
@@ -33,6 +35,7 @@ interface MermaidGraphConfiguration {
|
|
|
33
35
|
markStyle?: MermaidMarkStyle;
|
|
34
36
|
rootGraph?: DataflowGraph;
|
|
35
37
|
presentEdges?: Set<string>;
|
|
38
|
+
simplified?: boolean;
|
|
36
39
|
}
|
|
37
40
|
export declare function graphToMermaid(config: MermaidGraphConfiguration): {
|
|
38
41
|
string: string;
|
package/util/mermaid/dfg.js
CHANGED
|
@@ -37,14 +37,24 @@ function subflowToMermaid(nodeId, exitPoints, subflow, mermaid, idPrefix = '') {
|
|
|
37
37
|
return;
|
|
38
38
|
}
|
|
39
39
|
const subflowId = `${idPrefix}flow-${nodeId}`;
|
|
40
|
-
mermaid.
|
|
40
|
+
if (mermaid.simplified) {
|
|
41
|
+
// get parent
|
|
42
|
+
const idMap = mermaid.rootGraph.idMap;
|
|
43
|
+
const node = idMap?.get(nodeId);
|
|
44
|
+
const nodeLexeme = node?.info.fullLexeme ?? node?.lexeme ?? '??';
|
|
45
|
+
mermaid.nodeLines.push(`\nsubgraph "${subflowId}" ["${(0, mermaid_1.escapeMarkdown)(nodeLexeme ?? 'function')}"]`);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
mermaid.nodeLines.push(`\nsubgraph "${subflowId}" [function ${nodeId}]`);
|
|
49
|
+
}
|
|
41
50
|
const subgraph = graphToMermaidGraph(subflow.graph, {
|
|
42
51
|
graph: mermaid.rootGraph,
|
|
43
52
|
rootGraph: mermaid.rootGraph,
|
|
44
53
|
idPrefix,
|
|
45
54
|
includeEnvironments: mermaid.includeEnvironments,
|
|
46
55
|
mark: mermaid.mark,
|
|
47
|
-
prefix: null
|
|
56
|
+
prefix: null,
|
|
57
|
+
simplified: mermaid.simplified
|
|
48
58
|
});
|
|
49
59
|
mermaid.nodeLines.push(...subgraph.nodeLines);
|
|
50
60
|
mermaid.edgeLines.push(...subgraph.edgeLines);
|
|
@@ -143,10 +153,16 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
|
|
|
143
153
|
}
|
|
144
154
|
const node = mermaid.rootGraph.idMap?.get(info.id);
|
|
145
155
|
const lexeme = node?.lexeme ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0]?.lexeme : '') ?? '??';
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
156
|
+
if (mermaid.simplified) {
|
|
157
|
+
const escapedName = '**' + (0, mermaid_1.escapeMarkdown)(node ? `${lexeme}` : '??') + '**' + (node ? `\n*${node.type}*` : '');
|
|
158
|
+
mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}\`"${close}`);
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
const escapedName = (0, mermaid_1.escapeMarkdown)(node ? `[${node.type}] ${lexeme}` : '??');
|
|
162
|
+
const deps = info.controlDependencies ? ', :may:' + info.controlDependencies.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
|
|
163
|
+
const n = node?.info.fullRange ?? node?.location ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0].location : undefined);
|
|
164
|
+
mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}${escapedName.length > 10 ? '\n ' : ' '}(${id}${deps})\n *${formatRange(n)}*${fCall ? displayFunctionArgMapping(info.args) : ''}\`"${close}`);
|
|
165
|
+
}
|
|
150
166
|
if (mark?.has(id)) {
|
|
151
167
|
mermaid.nodeLines.push(` style ${idPrefix}${id} ${mermaid.markStyle.vertex} `);
|
|
152
168
|
}
|
|
@@ -176,8 +192,8 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
|
|
|
176
192
|
}
|
|
177
193
|
}
|
|
178
194
|
// make the passing of root ids more performant again
|
|
179
|
-
function graphToMermaidGraph(rootIds, { graph, prefix = 'flowchart TD', idPrefix = '', includeEnvironments =
|
|
180
|
-
const mermaid = { nodeLines: prefix === null ? [] : [prefix], edgeLines: [], presentEdges, mark, rootGraph: rootGraph ?? graph, includeEnvironments, markStyle };
|
|
195
|
+
function graphToMermaidGraph(rootIds, { simplified, graph, prefix = 'flowchart TD', idPrefix = '', includeEnvironments = !simplified, mark, rootGraph, presentEdges = new Set(), markStyle = { vertex: 'stroke:teal,stroke-width:7px,stroke-opacity:.8;', edge: 'stroke:teal,stroke-width:4.2px,stroke-opacity:.8' } }) {
|
|
196
|
+
const mermaid = { nodeLines: prefix === null ? [] : [prefix], edgeLines: [], presentEdges, mark, rootGraph: rootGraph ?? graph, includeEnvironments, markStyle, simplified };
|
|
181
197
|
for (const [id, info] of graph.vertices(true)) {
|
|
182
198
|
if (rootIds.has(id)) {
|
|
183
199
|
vertexToMermaid(info, mermaid, id, idPrefix, mark);
|