@eagleoutice/flowr 2.9.4 → 2.9.6
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 +20 -20
- package/control-flow/cfg-dead-code.js +12 -5
- package/dataflow/environments/append.js +9 -2
- package/dataflow/environments/environment.js +2 -2
- package/dataflow/environments/overwrite.js +9 -2
- package/dataflow/fn/recursive-function.js +1 -1
- package/package.json +1 -1
- package/project/plugins/file-plugins/files/flowr-rmarkdown-file.d.ts +3 -0
- package/project/plugins/file-plugins/files/flowr-rmarkdown-file.js +3 -0
- package/project/plugins/file-plugins/files/flowr-sweave-file.d.ts +70 -0
- package/project/plugins/file-plugins/files/flowr-sweave-file.js +163 -0
- package/project/plugins/file-plugins/notebooks/flowr-analyzer-sweave-file-plugin.d.ts +22 -0
- package/project/plugins/file-plugins/notebooks/flowr-analyzer-sweave-file-plugin.js +33 -0
- package/project/plugins/flowr-analyzer-plugin-defaults.js +2 -0
- package/project/plugins/plugin-registry.d.ts +2 -1
- package/project/plugins/plugin-registry.js +2 -0
- package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.js +1 -1
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +3 -2
- package/queries/catalog/call-context-query/call-context-query-executor.js +16 -11
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
- package/queries/catalog/call-context-query/identify-link-to-nested-call-relation.js +7 -4
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +99 -81
- package/queries/query.js +4 -3
- package/r-bridge/data/data.d.ts +20 -0
- package/r-bridge/data/data.js +24 -0
- package/util/version.js +1 -1
package/README.md
CHANGED
|
@@ -24,7 +24,7 @@ It offers a wide variety of features, for example:
|
|
|
24
24
|
|
|
25
25
|
```shell
|
|
26
26
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
27
|
-
flowR repl using flowR v2.9.
|
|
27
|
+
flowR repl using flowR v2.9.5, R grammar v14 (tree-sitter engine)
|
|
28
28
|
R> :query @linter "read.csv(\"/root/x.txt\")"
|
|
29
29
|
```
|
|
30
30
|
|
|
@@ -33,15 +33,15 @@ It offers a wide variety of features, for example:
|
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
```text
|
|
36
|
-
Query: linter (
|
|
36
|
+
Query: linter (3 ms)
|
|
37
37
|
╰ Deprecated Functions (deprecated-functions):
|
|
38
|
-
╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs:
|
|
38
|
+
╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 1, processTimeMs: 0
|
|
39
39
|
╰ File Path Validity (file-path-validity):
|
|
40
40
|
╰ certain:
|
|
41
41
|
╰ Path `/root/x.txt` at 1.1-23
|
|
42
|
-
╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 0, processTimeMs:
|
|
42
|
+
╰ Metadata: totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 0, processTimeMs: 0
|
|
43
43
|
╰ Seeded Randomness (seeded-randomness):
|
|
44
|
-
╰ Metadata: consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs:
|
|
44
|
+
╰ Metadata: consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 1, processTimeMs: 0
|
|
45
45
|
╰ Absolute Paths (absolute-file-paths):
|
|
46
46
|
╰ certain:
|
|
47
47
|
╰ Path `/root/x.txt` at 1.1-23
|
|
@@ -53,12 +53,12 @@ It offers a wide variety of features, for example:
|
|
|
53
53
|
╰ Network Functions (network-functions):
|
|
54
54
|
╰ Metadata: totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0
|
|
55
55
|
╰ Dataframe Access Validation (dataframe-access-validation):
|
|
56
|
-
╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs:
|
|
56
|
+
╰ Metadata: numOperations: 0, numAccesses: 0, totalAccessed: 0, searchTimeMs: 0, processTimeMs: 1
|
|
57
57
|
╰ Dead Code (dead-code):
|
|
58
|
-
╰ Metadata: consideredNodes: 5, searchTimeMs:
|
|
58
|
+
╰ Metadata: consideredNodes: 5, searchTimeMs: 0, processTimeMs: 0
|
|
59
59
|
╰ Useless Loops (useless-loop):
|
|
60
60
|
╰ Metadata: numOfUselessLoops: 0, searchTimeMs: 0, processTimeMs: 0
|
|
61
|
-
All queries together required ≈
|
|
61
|
+
All queries together required ≈3 ms (1ms accuracy, total 3 ms)
|
|
62
62
|
```
|
|
63
63
|
|
|
64
64
|
|
|
@@ -82,13 +82,13 @@ It offers a wide variety of features, for example:
|
|
|
82
82
|
|
|
83
83
|
Query: **linter** (3 ms)\
|
|
84
84
|
╰ **Deprecated Functions** (deprecated-functions):\
|
|
85
|
-
╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs:
|
|
85
|
+
╰ _Metadata_: <code>totalCalls: 0, totalFunctionDefinitions: 0, searchTimeMs: 0, processTimeMs: 0</code>\
|
|
86
86
|
╰ **File Path Validity** (file-path-validity):\
|
|
87
87
|
╰ certain:\
|
|
88
88
|
╰ Path `/root/x.txt` at 1.1-23\
|
|
89
|
-
╰ _Metadata_: <code>totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs:
|
|
89
|
+
╰ _Metadata_: <code>totalReads: 1, totalUnknown: 0, totalWritesBeforeAlways: 0, totalValid: 0, searchTimeMs: 1, processTimeMs: 0</code>\
|
|
90
90
|
╰ **Seeded Randomness** (seeded-randomness):\
|
|
91
|
-
╰ _Metadata_: <code>consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 0, processTimeMs:
|
|
91
|
+
╰ _Metadata_: <code>consumerCalls: 0, callsWithFunctionProducers: 0, callsWithAssignmentProducers: 0, callsWithNonConstantProducers: 0, callsWithOtherBranchProducers: 0, searchTimeMs: 0, processTimeMs: 0</code>\
|
|
92
92
|
╰ **Absolute Paths** (absolute-file-paths):\
|
|
93
93
|
╰ certain:\
|
|
94
94
|
╰ Path `/root/x.txt` at 1.1-23\
|
|
@@ -109,7 +109,7 @@ It offers a wide variety of features, for example:
|
|
|
109
109
|
|
|
110
110
|
<details> <summary style="color:gray">Show Detailed Results as Json</summary>
|
|
111
111
|
|
|
112
|
-
The analysis required
|
|
112
|
+
The analysis required _3.2 ms_ (including parsing and normalization and the query) within the generation environment.
|
|
113
113
|
|
|
114
114
|
In general, the JSON contains the Ids of the nodes in question as they are present in the normalized AST or the dataflow graph of flowR.
|
|
115
115
|
Please consult the [Interface](https://github.com/flowr-analysis/flowr/wiki/Interface) wiki page for more information on how to get those.
|
|
@@ -126,7 +126,7 @@ It offers a wide variety of features, for example:
|
|
|
126
126
|
".meta": {
|
|
127
127
|
"totalCalls": 0,
|
|
128
128
|
"totalFunctionDefinitions": 0,
|
|
129
|
-
"searchTimeMs":
|
|
129
|
+
"searchTimeMs": 0,
|
|
130
130
|
"processTimeMs": 0
|
|
131
131
|
}
|
|
132
132
|
},
|
|
@@ -149,7 +149,7 @@ It offers a wide variety of features, for example:
|
|
|
149
149
|
"totalUnknown": 0,
|
|
150
150
|
"totalWritesBeforeAlways": 0,
|
|
151
151
|
"totalValid": 0,
|
|
152
|
-
"searchTimeMs":
|
|
152
|
+
"searchTimeMs": 1,
|
|
153
153
|
"processTimeMs": 0
|
|
154
154
|
}
|
|
155
155
|
},
|
|
@@ -162,7 +162,7 @@ It offers a wide variety of features, for example:
|
|
|
162
162
|
"callsWithNonConstantProducers": 0,
|
|
163
163
|
"callsWithOtherBranchProducers": 0,
|
|
164
164
|
"searchTimeMs": 0,
|
|
165
|
-
"processTimeMs":
|
|
165
|
+
"processTimeMs": 0
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
168
|
"absolute-file-paths": {
|
|
@@ -308,7 +308,7 @@ It offers a wide variety of features, for example:
|
|
|
308
308
|
|
|
309
309
|
```shell
|
|
310
310
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
311
|
-
flowR repl using flowR v2.9.
|
|
311
|
+
flowR repl using flowR v2.9.5, R grammar v14 (tree-sitter engine)
|
|
312
312
|
R> :query @static-slice (11@sum) file://test/testfiles/example.R
|
|
313
313
|
```
|
|
314
314
|
|
|
@@ -322,7 +322,7 @@ It offers a wide variety of features, for example:
|
|
|
322
322
|
N <- 10
|
|
323
323
|
for(i in 1:(N-1)) sum <- sum + i + w
|
|
324
324
|
sum
|
|
325
|
-
All queries together required ≈
|
|
325
|
+
All queries together required ≈3 ms (1ms accuracy, total 3 ms)
|
|
326
326
|
```
|
|
327
327
|
|
|
328
328
|
|
|
@@ -356,7 +356,7 @@ It offers a wide variety of features, for example:
|
|
|
356
356
|
|
|
357
357
|
|
|
358
358
|
* 🚀 **fast call-graph, data-, and control-flow graphs**\
|
|
359
|
-
Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">
|
|
359
|
+
Within just [<i><span title="This measurement is automatically fetched from the latest benchmark!">99.6 ms</span></i> (as of Feb 5, 2026)](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark),
|
|
360
360
|
_flowR_ can analyze the data- and control-flow of the average real-world R script. See the [benchmarks](https://flowr-analysis.github.io/flowr/wiki/stats/benchmark) for more information,
|
|
361
361
|
and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/wiki/dataflow-graph) for more details on the dataflow graphs as well as call graphs.
|
|
362
362
|
|
|
@@ -392,7 +392,7 @@ It offers a wide variety of features, for example:
|
|
|
392
392
|
|
|
393
393
|
```shell
|
|
394
394
|
$ docker run -it --rm eagleoutice/flowr # or npm run flowr
|
|
395
|
-
flowR repl using flowR v2.9.
|
|
395
|
+
flowR repl using flowR v2.9.5, R grammar v14 (tree-sitter engine)
|
|
396
396
|
R> :dataflow* test/testfiles/example.R
|
|
397
397
|
```
|
|
398
398
|
|
|
@@ -697,7 +697,7 @@ It offers a wide variety of features, for example:
|
|
|
697
697
|
```
|
|
698
698
|
|
|
699
699
|
|
|
700
|
-
(The analysis required
|
|
700
|
+
(The analysis required _4.3 ms_ (including parse and normalize, using the [tree-sitter](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
|
|
701
701
|
|
|
702
702
|
|
|
703
703
|
|
|
@@ -41,16 +41,17 @@ class CfgConditionalDeadCodeRemoval extends semantic_cfg_guided_visitor_1.Semant
|
|
|
41
41
|
this.cachedConditions.set(id, value ? logic_1.Ternary.Always : logic_1.Ternary.Never);
|
|
42
42
|
}
|
|
43
43
|
startVisitor() {
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
const cfg = this.config.controlFlow.graph;
|
|
45
|
+
this.invertedCfg = (0, invert_cfg_1.invertCfg)(cfg);
|
|
46
|
+
for (const [from, targets] of cfg.edges()) {
|
|
46
47
|
for (const [target, edge] of targets) {
|
|
47
48
|
if (edge.label === 1 /* CfgEdgeType.Cd */) {
|
|
48
49
|
const og = this.getValue(edge.caused);
|
|
49
50
|
if (og === logic_1.Ternary.Always && edge.when === 'FALSE') {
|
|
50
|
-
|
|
51
|
+
cfg.removeEdge(from, target);
|
|
51
52
|
}
|
|
52
53
|
else if (og === logic_1.Ternary.Never && edge.when === 'TRUE') {
|
|
53
|
-
|
|
54
|
+
cfg.removeEdge(from, target);
|
|
54
55
|
}
|
|
55
56
|
}
|
|
56
57
|
else if (edge.label === 0 /* CfgEdgeType.Fd */ && this.isUnconditionalJump(target)) {
|
|
@@ -58,7 +59,7 @@ class CfgConditionalDeadCodeRemoval extends semantic_cfg_guided_visitor_1.Semant
|
|
|
58
59
|
for (const end of this.getCfgVertex(target)?.end ?? []) {
|
|
59
60
|
for (const [target, edge] of this.invertedCfg.outgoingEdges(end) ?? []) {
|
|
60
61
|
if (edge.label === 0 /* CfgEdgeType.Fd */) {
|
|
61
|
-
|
|
62
|
+
cfg.removeEdge(target, end);
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
}
|
|
@@ -67,6 +68,9 @@ class CfgConditionalDeadCodeRemoval extends semantic_cfg_guided_visitor_1.Semant
|
|
|
67
68
|
}
|
|
68
69
|
}
|
|
69
70
|
handleValuesFor(id, valueId) {
|
|
71
|
+
if (this.cachedConditions.has(id)) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
70
74
|
const values = (0, general_1.valueSetGuard)((0, alias_tracking_1.resolveIdToValue)(valueId, {
|
|
71
75
|
graph: this.config.dfg,
|
|
72
76
|
full: true,
|
|
@@ -114,6 +118,9 @@ class CfgConditionalDeadCodeRemoval extends semantic_cfg_guided_visitor_1.Semant
|
|
|
114
118
|
this.cachedStatements.set(data.call.id, true);
|
|
115
119
|
}
|
|
116
120
|
onStopIfNotCall(data) {
|
|
121
|
+
if (this.cachedStatements.has(data.call.id)) {
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
117
124
|
const arg = this.getBoolArgValue(data);
|
|
118
125
|
if (arg !== undefined) {
|
|
119
126
|
this.cachedStatements.set(data.call.id, !arg);
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.uniqueMergeValuesInDefinitions = uniqueMergeValuesInDefinitions;
|
|
4
4
|
exports.appendEnvironment = appendEnvironment;
|
|
5
|
-
const
|
|
5
|
+
const scoping_1 = require("./scoping");
|
|
6
6
|
/**
|
|
7
7
|
* Merges two arrays of identifier definitions, ensuring uniqueness based on `nodeId` and `definedAt`.
|
|
8
8
|
*/
|
|
@@ -23,7 +23,14 @@ function appendEnvironment(base, next) {
|
|
|
23
23
|
else if (next === undefined) {
|
|
24
24
|
return base;
|
|
25
25
|
}
|
|
26
|
-
|
|
26
|
+
if (base.level !== next.level) {
|
|
27
|
+
while (next.level < base.level) {
|
|
28
|
+
next = (0, scoping_1.pushLocalEnvironment)(next);
|
|
29
|
+
}
|
|
30
|
+
while (next.level > base.level) {
|
|
31
|
+
base = (0, scoping_1.pushLocalEnvironment)(base);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
27
34
|
return {
|
|
28
35
|
current: base.current.append(next.current),
|
|
29
36
|
level: base.level,
|
|
@@ -164,7 +164,7 @@ class Environment {
|
|
|
164
164
|
* This always recurses parents.
|
|
165
165
|
*/
|
|
166
166
|
overwrite(other, applyCds) {
|
|
167
|
-
if (this.builtInEnv || this === other || !other) {
|
|
167
|
+
if (this.builtInEnv || this === other || !other || this.n !== other.n) {
|
|
168
168
|
return this;
|
|
169
169
|
}
|
|
170
170
|
const map = new Map(this.memory);
|
|
@@ -211,7 +211,7 @@ class Environment {
|
|
|
211
211
|
* This always recurses parents.
|
|
212
212
|
*/
|
|
213
213
|
append(other) {
|
|
214
|
-
if (!other || this.builtInEnv) {
|
|
214
|
+
if (!other || this.builtInEnv || this === other || this.n !== other.n) {
|
|
215
215
|
return this;
|
|
216
216
|
}
|
|
217
217
|
const map = new Map(this.memory);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.overwriteEnvironment = overwriteEnvironment;
|
|
4
|
-
const
|
|
4
|
+
const scoping_1 = require("./scoping");
|
|
5
5
|
/**
|
|
6
6
|
* Assumes, that all definitions within next replace those within base (given the same name).
|
|
7
7
|
* <b>But</b> if all definitions within next are maybe, then they are appended to the base definitions (updating them to be `maybe` from now on as well), similar to {@link appendEnvironment}.
|
|
@@ -14,7 +14,14 @@ function overwriteEnvironment(base, next, applyCds) {
|
|
|
14
14
|
else if (next === undefined) {
|
|
15
15
|
return base;
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
if (base.level !== next.level) {
|
|
18
|
+
while (next.level < base.level) {
|
|
19
|
+
next = (0, scoping_1.pushLocalEnvironment)(next);
|
|
20
|
+
}
|
|
21
|
+
while (next.level > base.level) {
|
|
22
|
+
base = (0, scoping_1.pushLocalEnvironment)(base);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
18
25
|
return {
|
|
19
26
|
current: base.current.overwrite(next.current, applyCds),
|
|
20
27
|
level: base.level
|
|
@@ -7,7 +7,7 @@ const vertex_1 = require("../graph/vertex");
|
|
|
7
7
|
*/
|
|
8
8
|
function isFunctionRecursive(id, graph) {
|
|
9
9
|
const vert = graph.getVertex(id);
|
|
10
|
-
if (!
|
|
10
|
+
if (!(0, vertex_1.isFunctionDefinitionVertex)(vert)) {
|
|
11
11
|
return false;
|
|
12
12
|
}
|
|
13
13
|
const seen = new Set();
|
package/package.json
CHANGED
|
@@ -13,6 +13,9 @@ export declare class FlowrRMarkdownFile extends FlowrFile<string> {
|
|
|
13
13
|
* @param file - the file to load as R Markdown
|
|
14
14
|
*/
|
|
15
15
|
constructor(file: FlowrFileProvider<string>);
|
|
16
|
+
/**
|
|
17
|
+
* Gets the parsed R Markdown information
|
|
18
|
+
*/
|
|
16
19
|
get rmd(): RmdInfo;
|
|
17
20
|
/**
|
|
18
21
|
* Loads and parses the content of the wrapped file.
|
|
@@ -27,6 +27,9 @@ class FlowrRMarkdownFile extends flowr_file_1.FlowrFile {
|
|
|
27
27
|
super(file.path(), file.roles ? [...file.roles, flowr_file_1.FileRole.Source] : [flowr_file_1.FileRole.Source]);
|
|
28
28
|
this.wrapped = file;
|
|
29
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Gets the parsed R Markdown information
|
|
32
|
+
*/
|
|
30
33
|
get rmd() {
|
|
31
34
|
if (!this.data) {
|
|
32
35
|
this.loadContent();
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { FlowrFileProvider } from '../../../context/flowr-file';
|
|
2
|
+
import { FlowrFile } from '../../../context/flowr-file';
|
|
3
|
+
/**
|
|
4
|
+
* This decorates a text file and parses its contents as a Sweave (latex with R code) file.
|
|
5
|
+
* Finally, it provides access to the single cells, and all cells fused together as one R file.
|
|
6
|
+
* So far, this does *not* support `\Sexpr` calls.
|
|
7
|
+
*/
|
|
8
|
+
export declare class FlowrSweaveFile extends FlowrFile<string> {
|
|
9
|
+
private readonly wrapped;
|
|
10
|
+
private data?;
|
|
11
|
+
/**
|
|
12
|
+
* Prefer the static {@link FlowrSweaveFile.from} method
|
|
13
|
+
* @param file - the file to load as Sweave
|
|
14
|
+
*/
|
|
15
|
+
constructor(file: FlowrFileProvider<string>);
|
|
16
|
+
/**
|
|
17
|
+
* The content of the Sweave file.
|
|
18
|
+
*/
|
|
19
|
+
get rnw(): SweaveInfo;
|
|
20
|
+
/**
|
|
21
|
+
* Loads and parses the content of the wrapped file.
|
|
22
|
+
* @returns the content of the Sweave file, which is the R code without the latex code, no-eval blocks, ...
|
|
23
|
+
*/
|
|
24
|
+
protected loadContent(): string;
|
|
25
|
+
static from(file: FlowrFileProvider<string> | FlowrSweaveFile): FlowrSweaveFile;
|
|
26
|
+
}
|
|
27
|
+
export interface SweaveInfo {
|
|
28
|
+
/**
|
|
29
|
+
* The R code without the latex code, no-eval blocks, ...
|
|
30
|
+
*/
|
|
31
|
+
content: string;
|
|
32
|
+
/**
|
|
33
|
+
* All code blocks, including those that should not be evaluated and the latex code.
|
|
34
|
+
*/
|
|
35
|
+
blocks: SweaveCodeBlock[];
|
|
36
|
+
}
|
|
37
|
+
interface SweaveBlockBasis {
|
|
38
|
+
type: 'content' | 'reuse';
|
|
39
|
+
startLine: number;
|
|
40
|
+
}
|
|
41
|
+
export interface SweaveCodeBlockContent extends SweaveBlockBasis {
|
|
42
|
+
type: 'content';
|
|
43
|
+
content: string;
|
|
44
|
+
options: SweaveBlockOptions;
|
|
45
|
+
}
|
|
46
|
+
export interface SweaveCodeBlockReuse extends SweaveBlockBasis {
|
|
47
|
+
type: 'reuse';
|
|
48
|
+
reuse: string;
|
|
49
|
+
}
|
|
50
|
+
type SweaveCodeBlock = SweaveCodeBlockContent | SweaveCodeBlockReuse;
|
|
51
|
+
export interface SweaveBlockOptions {
|
|
52
|
+
name?: string;
|
|
53
|
+
eval?: boolean;
|
|
54
|
+
}
|
|
55
|
+
export interface SweaveReuseOptions {
|
|
56
|
+
reuse: string;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Parse a Sweave file into joined content and blocks
|
|
60
|
+
* @param raw - raw contents of file
|
|
61
|
+
* @returns Joined Content and Blocks
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseSweave(raw: string): SweaveInfo;
|
|
64
|
+
/**
|
|
65
|
+
* Parses a Sweave Code Block Start if it can find one
|
|
66
|
+
* @param line - the line to parse
|
|
67
|
+
* @returns info about options and name if code block start was found
|
|
68
|
+
*/
|
|
69
|
+
export declare function parseSweaveCodeblockStart(line: string): SweaveBlockOptions | SweaveReuseOptions | undefined;
|
|
70
|
+
export {};
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FlowrSweaveFile = void 0;
|
|
4
|
+
exports.parseSweave = parseSweave;
|
|
5
|
+
exports.parseSweaveCodeblockStart = parseSweaveCodeblockStart;
|
|
6
|
+
const flowr_file_1 = require("../../../context/flowr-file");
|
|
7
|
+
const assert_1 = require("../../../../util/assert");
|
|
8
|
+
/**
|
|
9
|
+
* This decorates a text file and parses its contents as a Sweave (latex with R code) file.
|
|
10
|
+
* Finally, it provides access to the single cells, and all cells fused together as one R file.
|
|
11
|
+
* So far, this does *not* support `\Sexpr` calls.
|
|
12
|
+
*/
|
|
13
|
+
class FlowrSweaveFile extends flowr_file_1.FlowrFile {
|
|
14
|
+
wrapped;
|
|
15
|
+
data;
|
|
16
|
+
/**
|
|
17
|
+
* Prefer the static {@link FlowrSweaveFile.from} method
|
|
18
|
+
* @param file - the file to load as Sweave
|
|
19
|
+
*/
|
|
20
|
+
constructor(file) {
|
|
21
|
+
super(file.path(), file.roles ? [...file.roles, flowr_file_1.FileRole.Source] : [flowr_file_1.FileRole.Source]);
|
|
22
|
+
this.wrapped = file;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* The content of the Sweave file.
|
|
26
|
+
*/
|
|
27
|
+
get rnw() {
|
|
28
|
+
if (!this.data) {
|
|
29
|
+
this.loadContent();
|
|
30
|
+
}
|
|
31
|
+
(0, assert_1.guard)(this.data);
|
|
32
|
+
return this.data;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Loads and parses the content of the wrapped file.
|
|
36
|
+
* @returns the content of the Sweave file, which is the R code without the latex code, no-eval blocks, ...
|
|
37
|
+
*/
|
|
38
|
+
loadContent() {
|
|
39
|
+
this.data = parseSweave(this.wrapped.content());
|
|
40
|
+
return this.data.content;
|
|
41
|
+
}
|
|
42
|
+
static from(file) {
|
|
43
|
+
return file instanceof FlowrSweaveFile ? file : new FlowrSweaveFile(file);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.FlowrSweaveFile = FlowrSweaveFile;
|
|
47
|
+
const CodeBlockStartPattern = /^<<([^>]*)>>(?<reuse>=)?/;
|
|
48
|
+
const ReusePattern = /^<<([^>]*)>>/;
|
|
49
|
+
/**
|
|
50
|
+
* Parse a Sweave file into joined content and blocks
|
|
51
|
+
* @param raw - raw contents of file
|
|
52
|
+
* @returns Joined Content and Blocks
|
|
53
|
+
*/
|
|
54
|
+
function parseSweave(raw) {
|
|
55
|
+
const lines = raw.split(/\r?\n/);
|
|
56
|
+
const blocks = [];
|
|
57
|
+
let currentBlock = undefined;
|
|
58
|
+
let lineNum = 0;
|
|
59
|
+
for (const line of lines) {
|
|
60
|
+
lineNum++;
|
|
61
|
+
if (currentBlock) { // Inside Code Block
|
|
62
|
+
if (isEndOfCodeBlock(line)) {
|
|
63
|
+
// drop the last '\n' and push the block
|
|
64
|
+
if (currentBlock.content.endsWith('\n')) {
|
|
65
|
+
currentBlock.content = currentBlock.content.slice(0, -1);
|
|
66
|
+
}
|
|
67
|
+
blocks.push(currentBlock);
|
|
68
|
+
currentBlock = undefined;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const reuseMatch = line.match(ReusePattern);
|
|
73
|
+
if (reuseMatch) {
|
|
74
|
+
// we found a reuse inside a code block, we inline the content!
|
|
75
|
+
const reuseName = reuseMatch[1].trim();
|
|
76
|
+
const reuseBlock = blocks.find(b => 'options' in b && b.options.name === reuseName);
|
|
77
|
+
if (reuseBlock && 'options' in reuseBlock) {
|
|
78
|
+
currentBlock.content += reuseBlock.content + '\n';
|
|
79
|
+
}
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
currentBlock.content += line + '\n';
|
|
84
|
+
}
|
|
85
|
+
else { // Latex Code / Outside Code Block
|
|
86
|
+
const result = parseSweaveCodeblockStart(line);
|
|
87
|
+
if (result) {
|
|
88
|
+
if ('reuse' in result) {
|
|
89
|
+
blocks.push({ type: 'reuse', reuse: result.reuse, startLine: lineNum });
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
currentBlock = {
|
|
93
|
+
type: 'content',
|
|
94
|
+
options: result,
|
|
95
|
+
content: '',
|
|
96
|
+
startLine: lineNum
|
|
97
|
+
};
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const content = [];
|
|
102
|
+
for (const block of blocks) {
|
|
103
|
+
// add empty lines until startline is met; the start line is still exclusive!
|
|
104
|
+
while (content.length < block.startLine) {
|
|
105
|
+
content.push('');
|
|
106
|
+
}
|
|
107
|
+
if ('reuse' in block) {
|
|
108
|
+
const reuseBlock = blocks.find(b => 'options' in b && b.options.name === block.reuse);
|
|
109
|
+
if (reuseBlock && 'options' in reuseBlock) {
|
|
110
|
+
content.push(...reuseBlock.content.split('\n'));
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
else if (block.options.eval !== false) {
|
|
114
|
+
content.push(...block.content.split('\n'));
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
content: content.join('\n'),
|
|
119
|
+
blocks: blocks
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
const evalWithFlagPattern = /eval\s*=\s*(TRUE|FALSE)/i;
|
|
123
|
+
/**
|
|
124
|
+
* Parses a Sweave Code Block Start if it can find one
|
|
125
|
+
* @param line - the line to parse
|
|
126
|
+
* @returns info about options and name if code block start was found
|
|
127
|
+
*/
|
|
128
|
+
function parseSweaveCodeblockStart(line) {
|
|
129
|
+
const match = line.match(CodeBlockStartPattern);
|
|
130
|
+
if (match) {
|
|
131
|
+
// No options provided (i.e <<>>=)
|
|
132
|
+
if (match[1] === '') {
|
|
133
|
+
return {};
|
|
134
|
+
}
|
|
135
|
+
const options = match[1].split(',');
|
|
136
|
+
let name = undefined;
|
|
137
|
+
let evalOpt = undefined;
|
|
138
|
+
// The first option can have no key and is then interpreted as the label of the block
|
|
139
|
+
if (!options[0].includes('=')) {
|
|
140
|
+
name = options[0].trim();
|
|
141
|
+
}
|
|
142
|
+
if (match.groups?.reuse === undefined) {
|
|
143
|
+
// this reuses!
|
|
144
|
+
return name ? { reuse: name } : {};
|
|
145
|
+
}
|
|
146
|
+
// Search for eval option
|
|
147
|
+
for (let i = name ? 1 : 0; i < options.length; i++) {
|
|
148
|
+
const opt = options[i].trim();
|
|
149
|
+
const evalMatch = opt.match(evalWithFlagPattern);
|
|
150
|
+
if (evalMatch) {
|
|
151
|
+
evalOpt = evalMatch[1].toUpperCase() === 'TRUE';
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
name, eval: evalOpt
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
function isEndOfCodeBlock(line) {
|
|
161
|
+
return line.startsWith('@');
|
|
162
|
+
}
|
|
163
|
+
//# sourceMappingURL=flowr-sweave-file.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { PathLike } from 'fs';
|
|
2
|
+
import { SemVer } from 'semver';
|
|
3
|
+
import type { FlowrAnalyzerContext } from '../../../context/flowr-analyzer-context';
|
|
4
|
+
import { type FlowrFileProvider } from '../../../context/flowr-file';
|
|
5
|
+
import { FlowrAnalyzerFilePlugin } from '../flowr-analyzer-file-plugin';
|
|
6
|
+
import { FlowrSweaveFile } from '../files/flowr-sweave-file';
|
|
7
|
+
/**
|
|
8
|
+
* The plugin provides support for Sweave (`.Rnw`) files
|
|
9
|
+
*/
|
|
10
|
+
export declare class FlowrAnalyzerSweaveFilePlugin extends FlowrAnalyzerFilePlugin {
|
|
11
|
+
readonly name = "sweave-file-plugin";
|
|
12
|
+
readonly description = "Parses R Sweave files";
|
|
13
|
+
readonly version: SemVer;
|
|
14
|
+
private readonly pattern;
|
|
15
|
+
/**
|
|
16
|
+
* Creates a new instance of the Sweave file plugin.
|
|
17
|
+
* @param filePattern - The pattern to identify Sweave files, see {@link SweavePattern} for the default pattern.
|
|
18
|
+
*/
|
|
19
|
+
constructor(filePattern?: RegExp);
|
|
20
|
+
applies(file: PathLike): boolean;
|
|
21
|
+
protected process(_ctx: FlowrAnalyzerContext, arg: FlowrFileProvider<string>): FlowrSweaveFile;
|
|
22
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.FlowrAnalyzerSweaveFilePlugin = void 0;
|
|
4
|
+
const semver_1 = require("semver");
|
|
5
|
+
const flowr_analyzer_file_plugin_1 = require("../flowr-analyzer-file-plugin");
|
|
6
|
+
const built_in_source_1 = require("../../../../dataflow/internal/process/functions/call/built-in/built-in-source");
|
|
7
|
+
const flowr_sweave_file_1 = require("../files/flowr-sweave-file");
|
|
8
|
+
const SweavePattern = /\.Rnw$/i;
|
|
9
|
+
/**
|
|
10
|
+
* The plugin provides support for Sweave (`.Rnw`) files
|
|
11
|
+
*/
|
|
12
|
+
class FlowrAnalyzerSweaveFilePlugin extends flowr_analyzer_file_plugin_1.FlowrAnalyzerFilePlugin {
|
|
13
|
+
name = 'sweave-file-plugin';
|
|
14
|
+
description = 'Parses R Sweave files';
|
|
15
|
+
version = new semver_1.SemVer('0.1.0');
|
|
16
|
+
pattern;
|
|
17
|
+
/**
|
|
18
|
+
* Creates a new instance of the Sweave file plugin.
|
|
19
|
+
* @param filePattern - The pattern to identify Sweave files, see {@link SweavePattern} for the default pattern.
|
|
20
|
+
*/
|
|
21
|
+
constructor(filePattern = SweavePattern) {
|
|
22
|
+
super();
|
|
23
|
+
this.pattern = filePattern;
|
|
24
|
+
}
|
|
25
|
+
applies(file) {
|
|
26
|
+
return this.pattern.test((0, built_in_source_1.platformBasename)(file.toString()));
|
|
27
|
+
}
|
|
28
|
+
process(_ctx, arg) {
|
|
29
|
+
return flowr_sweave_file_1.FlowrSweaveFile.from(arg);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
exports.FlowrAnalyzerSweaveFilePlugin = FlowrAnalyzerSweaveFilePlugin;
|
|
33
|
+
//# sourceMappingURL=flowr-analyzer-sweave-file-plugin.js.map
|
|
@@ -13,6 +13,7 @@ const flowr_analyzer_vignette_file_plugin_1 = require("./file-plugins/flowr-anal
|
|
|
13
13
|
const flowr_analyzer_test_file_plugin_1 = require("./file-plugins/flowr-analyzer-test-file-plugin");
|
|
14
14
|
const flowr_analyzer_license_file_plugin_1 = require("./file-plugins/flowr-analyzer-license-file-plugin");
|
|
15
15
|
const flowr_analyzer_meta_description_file_plugin_1 = require("./package-version-plugins/flowr-analyzer-meta-description-file-plugin");
|
|
16
|
+
const flowr_analyzer_sweave_file_plugin_1 = require("./file-plugins/notebooks/flowr-analyzer-sweave-file-plugin");
|
|
16
17
|
/**
|
|
17
18
|
* Provides the default set of Flowr Analyzer plugins.
|
|
18
19
|
*/
|
|
@@ -26,6 +27,7 @@ function FlowrAnalyzerPluginDefaults() {
|
|
|
26
27
|
new flowr_analyzer_meta_description_file_plugin_1.FlowrAnalyzerMetaDescriptionFilePlugin(),
|
|
27
28
|
new flowr_analyzer_rmd_file_plugin_1.FlowrAnalyzerRmdFilePlugin(),
|
|
28
29
|
new flowr_analyzer_qmd_file_plugin_1.FlowrAnalyzerQmdFilePlugin(),
|
|
30
|
+
new flowr_analyzer_sweave_file_plugin_1.FlowrAnalyzerSweaveFilePlugin(),
|
|
29
31
|
new flowr_analyzer_license_file_plugin_1.FlowrAnalyzerLicenseFilePlugin(),
|
|
30
32
|
new flowr_analyzer_jupyter_file_plugin_1.FlowrAnalyzerJupyterFilePlugin(),
|
|
31
33
|
new flowr_analyzer_namespace_files_plugin_1.FlowrAnalyzerNamespaceFilesPlugin(),
|
|
@@ -11,10 +11,11 @@ import { FlowrAnalyzerMetaVignetteFilesPlugin } from './file-plugins/flowr-analy
|
|
|
11
11
|
import { FlowrAnalyzerMetaTestFilesPlugin } from './file-plugins/flowr-analyzer-test-file-plugin';
|
|
12
12
|
import { FlowrAnalyzerLicenseFilePlugin } from './file-plugins/flowr-analyzer-license-file-plugin';
|
|
13
13
|
import { FlowrAnalyzerMetaDescriptionFilePlugin } from './package-version-plugins/flowr-analyzer-meta-description-file-plugin';
|
|
14
|
+
import { FlowrAnalyzerSweaveFilePlugin } from './file-plugins/notebooks/flowr-analyzer-sweave-file-plugin';
|
|
14
15
|
/**
|
|
15
16
|
* The built-in Flowr Analyzer plugins that are always available.
|
|
16
17
|
*/
|
|
17
|
-
export declare const BuiltInPlugins: [["file:description", typeof FlowrAnalyzerDescriptionFilePlugin], ["versions:description", typeof FlowrAnalyzerPackageVersionsDescriptionFilePlugin], ["loading-order:description", typeof FlowrAnalyzerLoadingOrderDescriptionFilePlugin], ["meta:description", typeof FlowrAnalyzerMetaDescriptionFilePlugin], ["files:vignette", typeof FlowrAnalyzerMetaVignetteFilesPlugin], ["files:test", typeof FlowrAnalyzerMetaTestFilesPlugin], ["file:rmd", typeof FlowrAnalyzerRmdFilePlugin], ["file:qmd", typeof FlowrAnalyzerQmdFilePlugin], ["file:ipynb", typeof FlowrAnalyzerJupyterFilePlugin], ["file:namespace", typeof FlowrAnalyzerNamespaceFilesPlugin], ["file:news", typeof FlowrAnalyzerNewsFilePlugin], ["file:license", typeof FlowrAnalyzerLicenseFilePlugin]];
|
|
18
|
+
export declare const BuiltInPlugins: [["file:description", typeof FlowrAnalyzerDescriptionFilePlugin], ["versions:description", typeof FlowrAnalyzerPackageVersionsDescriptionFilePlugin], ["loading-order:description", typeof FlowrAnalyzerLoadingOrderDescriptionFilePlugin], ["meta:description", typeof FlowrAnalyzerMetaDescriptionFilePlugin], ["files:vignette", typeof FlowrAnalyzerMetaVignetteFilesPlugin], ["files:test", typeof FlowrAnalyzerMetaTestFilesPlugin], ["file:rmd", typeof FlowrAnalyzerRmdFilePlugin], ["file:qmd", typeof FlowrAnalyzerQmdFilePlugin], ["file:rnw", typeof FlowrAnalyzerSweaveFilePlugin], ["file:ipynb", typeof FlowrAnalyzerJupyterFilePlugin], ["file:namespace", typeof FlowrAnalyzerNamespaceFilesPlugin], ["file:news", typeof FlowrAnalyzerNewsFilePlugin], ["file:license", typeof FlowrAnalyzerLicenseFilePlugin]];
|
|
18
19
|
export type BuiltInFlowrPluginName = typeof BuiltInPlugins[number][0];
|
|
19
20
|
export type BuiltInFlowrPluginArgs<N extends BuiltInFlowrPluginName> = N extends typeof BuiltInPlugins[number][0] ? ConstructorParameters<Extract<typeof BuiltInPlugins[number], [N, PluginProducer]>[1]> : never;
|
|
20
21
|
type PluginProducer = new (...args: never[]) => FlowrAnalyzerPlugin;
|
|
@@ -17,6 +17,7 @@ const flowr_analyzer_vignette_file_plugin_1 = require("./file-plugins/flowr-anal
|
|
|
17
17
|
const flowr_analyzer_test_file_plugin_1 = require("./file-plugins/flowr-analyzer-test-file-plugin");
|
|
18
18
|
const flowr_analyzer_license_file_plugin_1 = require("./file-plugins/flowr-analyzer-license-file-plugin");
|
|
19
19
|
const flowr_analyzer_meta_description_file_plugin_1 = require("./package-version-plugins/flowr-analyzer-meta-description-file-plugin");
|
|
20
|
+
const flowr_analyzer_sweave_file_plugin_1 = require("./file-plugins/notebooks/flowr-analyzer-sweave-file-plugin");
|
|
20
21
|
/**
|
|
21
22
|
* The built-in Flowr Analyzer plugins that are always available.
|
|
22
23
|
*/
|
|
@@ -29,6 +30,7 @@ exports.BuiltInPlugins = [
|
|
|
29
30
|
['files:test', flowr_analyzer_test_file_plugin_1.FlowrAnalyzerMetaTestFilesPlugin],
|
|
30
31
|
['file:rmd', flowr_analyzer_rmd_file_plugin_1.FlowrAnalyzerRmdFilePlugin],
|
|
31
32
|
['file:qmd', flowr_analyzer_qmd_file_plugin_1.FlowrAnalyzerQmdFilePlugin],
|
|
33
|
+
['file:rnw', flowr_analyzer_sweave_file_plugin_1.FlowrAnalyzerSweaveFilePlugin],
|
|
32
34
|
['file:ipynb', flowr_analyzer_jupyter_file_plugin_1.FlowrAnalyzerJupyterFilePlugin],
|
|
33
35
|
['file:namespace', flowr_analyzer_namespace_files_plugin_1.FlowrAnalyzerNamespaceFilesPlugin],
|
|
34
36
|
['file:news', flowr_analyzer_news_file_plugin_1.FlowrAnalyzerNewsFilePlugin],
|
|
@@ -24,7 +24,7 @@ class FlowrAnalyzerProjectDiscoveryPlugin extends flowr_analyzer_plugin_1.FlowrA
|
|
|
24
24
|
}
|
|
25
25
|
}
|
|
26
26
|
exports.FlowrAnalyzerProjectDiscoveryPlugin = FlowrAnalyzerProjectDiscoveryPlugin;
|
|
27
|
-
const discoverRSourcesRegex = /\.(r|rmd|ipynb|qmd)$/i;
|
|
27
|
+
const discoverRSourcesRegex = /\.(r|rmd|ipynb|qmd|rnw)$/i;
|
|
28
28
|
const ignorePathsWith = /(\.git|\.svn|\.hg|renv|packrat|node_modules|__pycache__|\.Rproj\.user)/i;
|
|
29
29
|
const excludeRequestsForPaths = /vignettes?|tests?|revdep|inst|data/i;
|
|
30
30
|
/**
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { CallContextQuery, CallContextQueryResult, CallNameTypes, LinkTo } from './call-context-query-format';
|
|
2
2
|
import type { BasicQueryData } from '../../base-query-format';
|
|
3
|
+
export type PromotedCallTest = (t: string) => boolean;
|
|
3
4
|
/**
|
|
4
5
|
*
|
|
5
6
|
*/
|
|
6
|
-
export declare function promoteCallName(callName: CallNameTypes, exact?: boolean):
|
|
7
|
+
export declare function promoteCallName(callName: CallNameTypes, exact?: boolean): PromotedCallTest;
|
|
7
8
|
export type PromotedLinkTo<LT = LinkTo> = Omit<LT, 'callName'> & {
|
|
8
|
-
callName:
|
|
9
|
+
callName: PromotedCallTest;
|
|
9
10
|
};
|
|
10
11
|
/**
|
|
11
12
|
* Multi-stage call context query resolve.
|
|
@@ -48,13 +48,16 @@ function isSubCallQuery(query) {
|
|
|
48
48
|
*/
|
|
49
49
|
function promoteCallName(callName, exact = false) {
|
|
50
50
|
if (Array.isArray(callName)) {
|
|
51
|
-
|
|
51
|
+
const s = new Set(callName);
|
|
52
|
+
return (t) => s.has(t);
|
|
52
53
|
}
|
|
53
54
|
else if (exact) {
|
|
54
|
-
|
|
55
|
+
const s = new Set([typeof callName === 'string' ? callName : callName.source]);
|
|
56
|
+
return (t) => s.has(t);
|
|
55
57
|
}
|
|
56
58
|
else {
|
|
57
|
-
|
|
59
|
+
const r = new RegExp(callName);
|
|
60
|
+
return (t) => r.test(t);
|
|
58
61
|
}
|
|
59
62
|
}
|
|
60
63
|
function promoteQueryCallNames(queries) {
|
|
@@ -98,7 +101,7 @@ function retrieveAllCallAliases(nodeId, graph) {
|
|
|
98
101
|
const aliases = new Map();
|
|
99
102
|
const visited = new Set();
|
|
100
103
|
/* we store the current call name */
|
|
101
|
-
|
|
104
|
+
const queue = [[(0, node_id_1.recoverContent)(nodeId, graph) ?? '', nodeId]];
|
|
102
105
|
while (queue.length > 0) {
|
|
103
106
|
const [str, id] = queue.shift();
|
|
104
107
|
if (visited.has(id)) {
|
|
@@ -120,12 +123,13 @@ function retrieveAllCallAliases(nodeId, graph) {
|
|
|
120
123
|
}
|
|
121
124
|
const [info, outgoing] = vertex;
|
|
122
125
|
if (info.tag !== vertex_1.VertexType.FunctionCall) {
|
|
126
|
+
const wantedTypes = edge_1.EdgeType.Reads | edge_1.EdgeType.DefinedBy | edge_1.EdgeType.DefinedByOnCall;
|
|
123
127
|
const x = outgoing.entries()
|
|
124
|
-
.filter(([, e]) => edge_1.DfEdge.includesType(e,
|
|
128
|
+
.filter(([, e]) => edge_1.DfEdge.includesType(e, wantedTypes))
|
|
125
129
|
.map(([t]) => [(0, node_id_1.recoverContent)(t, graph) ?? '', t])
|
|
126
130
|
.toArray();
|
|
127
131
|
/** only follow defined-by and reads */
|
|
128
|
-
queue
|
|
132
|
+
queue.push(...x);
|
|
129
133
|
continue;
|
|
130
134
|
}
|
|
131
135
|
let track = edge_1.EdgeType.Calls | edge_1.EdgeType.Reads | edge_1.EdgeType.DefinedBy | edge_1.EdgeType.DefinedByOnCall;
|
|
@@ -164,7 +168,7 @@ function doesFilepathMatch(file, filter) {
|
|
|
164
168
|
if (file === undefined) {
|
|
165
169
|
return filter.includeUndefinedFiles ?? true;
|
|
166
170
|
}
|
|
167
|
-
return filter.filter
|
|
171
|
+
return filter.filter(file);
|
|
168
172
|
}
|
|
169
173
|
function isParameterDefaultValue(nodeId, ast) {
|
|
170
174
|
let node = ast.idMap.get(nodeId);
|
|
@@ -172,7 +176,8 @@ function isParameterDefaultValue(nodeId, ast) {
|
|
|
172
176
|
if (node.info.role === "param-value" /* RoleInParent.ParameterDefaultValue */) {
|
|
173
177
|
return true;
|
|
174
178
|
}
|
|
175
|
-
|
|
179
|
+
const nip = node.info.parent;
|
|
180
|
+
node = nip ? ast.idMap.get(nip) : undefined;
|
|
176
181
|
}
|
|
177
182
|
return false;
|
|
178
183
|
}
|
|
@@ -196,7 +201,7 @@ async function executeCallContextQueries({ analyzer }, queries) {
|
|
|
196
201
|
const { promotedQueries, requiresCfg } = promoteQueryCallNames(queries);
|
|
197
202
|
let cfg = undefined;
|
|
198
203
|
if (requiresCfg) {
|
|
199
|
-
cfg = await analyzer.controlflow(
|
|
204
|
+
cfg = await analyzer.controlflow(undefined, cfg_kind_1.CfgKind.Quick);
|
|
200
205
|
}
|
|
201
206
|
const calls = cfg ? (0, extract_cfg_1.getCallsInCfg)(cfg, dataflow.graph) : undefined;
|
|
202
207
|
const queriesWhichWantAliases = promotedQueries.filter(q => q.includeAliases);
|
|
@@ -211,14 +216,14 @@ async function executeCallContextQueries({ analyzer }, queries) {
|
|
|
211
216
|
const targets = retrieveAllCallAliases(nodeId, dataflow.graph);
|
|
212
217
|
for (const [l, ids] of targets.entries()) {
|
|
213
218
|
for (const query of queriesWhichWantAliases) {
|
|
214
|
-
if (query.callName
|
|
219
|
+
if (query.callName(l)) {
|
|
215
220
|
initialIdCollector.add(query.kind ?? '.', query.subkind ?? '.', (0, objects_1.compactRecord)({ id: nodeId, name: info.name, aliasRoots: ids }));
|
|
216
221
|
}
|
|
217
222
|
}
|
|
218
223
|
}
|
|
219
224
|
}
|
|
220
225
|
const n = identifier_1.Identifier.getName(info.name);
|
|
221
|
-
for (const query of promotedQueries.filter(q => !q.includeAliases &&
|
|
226
|
+
for (const query of promotedQueries.filter(q => !q.includeAliases && q.callName(n))) {
|
|
222
227
|
const file = ast.idMap.get(nodeId)?.info.file;
|
|
223
228
|
if (!doesFilepathMatch(file, query.fileFilter)) {
|
|
224
229
|
continue;
|
|
@@ -135,7 +135,7 @@ function identifyLinkToLastCallRelationSync(from, cfg, graph, { callName, cascad
|
|
|
135
135
|
}
|
|
136
136
|
const found = [];
|
|
137
137
|
const cNameCheck = callName instanceof RegExp ? ({ name }) => callName.test(identifier_1.Identifier.getName(name))
|
|
138
|
-
: ({ name }) => callName
|
|
138
|
+
: ({ name }) => callName(identifier_1.Identifier.getName(name));
|
|
139
139
|
const getVertex = knownCalls ?
|
|
140
140
|
(node) => knownCalls.get(node) :
|
|
141
141
|
(node) => {
|
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.identifyLinkToNestedRelation = identifyLinkToNestedRelation;
|
|
4
4
|
const call_graph_1 = require("../../../dataflow/graph/call-graph");
|
|
5
|
+
const vertex_1 = require("../../../dataflow/graph/vertex");
|
|
6
|
+
const identifier_1 = require("../../../dataflow/environments/identifier");
|
|
5
7
|
/**
|
|
6
8
|
* **Please refer to {@link identifyLinkToRelation}.**
|
|
7
9
|
*
|
|
@@ -14,15 +16,16 @@ async function identifyLinkToNestedRelation(from, analyzer, { callName, ignoreIf
|
|
|
14
16
|
if (ignoreIf?.(from, df.graph)) {
|
|
15
17
|
return [];
|
|
16
18
|
}
|
|
19
|
+
const test = callName instanceof RegExp ? (t) => callName.test(t) : callName;
|
|
17
20
|
const found = [];
|
|
18
21
|
const cg = await analyzer.callGraph();
|
|
19
22
|
const subCg = (0, call_graph_1.getSubCallGraph)(cg, new Set([from]));
|
|
20
|
-
for (const [,
|
|
21
|
-
if (
|
|
23
|
+
for (const [, t] of subCg.vertices(true)) {
|
|
24
|
+
if (!(0, vertex_1.isFunctionCallVertex)(t)) {
|
|
22
25
|
continue;
|
|
23
26
|
}
|
|
24
|
-
if (
|
|
25
|
-
found.push(id);
|
|
27
|
+
if (test(identifier_1.Identifier.toString(t.name))) {
|
|
28
|
+
found.push(t.id);
|
|
26
29
|
}
|
|
27
30
|
}
|
|
28
31
|
return found;
|
|
@@ -4,26 +4,39 @@ exports.executeDependenciesQuery = executeDependenciesQuery;
|
|
|
4
4
|
const query_1 = require("../../query");
|
|
5
5
|
const dependencies_query_format_1 = require("./dependencies-query-format");
|
|
6
6
|
const vertex_1 = require("../../../dataflow/graph/vertex");
|
|
7
|
-
const log_1 = require("../../../util/log");
|
|
8
7
|
const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
|
|
9
8
|
const objects_1 = require("../../../util/objects");
|
|
10
9
|
const function_info_1 = require("./function-info/function-info");
|
|
11
10
|
const identify_link_to_last_call_relation_1 = require("../call-context-query/identify-link-to-last-call-relation");
|
|
12
11
|
const resolve_argument_1 = require("../../../dataflow/eval/resolve/resolve-argument");
|
|
13
12
|
const assert_1 = require("../../../util/assert");
|
|
13
|
+
const log_1 = require("../../../util/log");
|
|
14
14
|
/**
|
|
15
15
|
* Executes a dependencies query.
|
|
16
16
|
*/
|
|
17
17
|
async function executeDependenciesQuery({ analyzer, }, queries) {
|
|
18
|
+
let query = queries[0];
|
|
18
19
|
if (queries.length !== 1) {
|
|
19
|
-
|
|
20
|
+
// merge
|
|
21
|
+
for (let i = 1; i < queries.length; i++) {
|
|
22
|
+
const q = queries[i];
|
|
23
|
+
query = {
|
|
24
|
+
...query,
|
|
25
|
+
enabledCategories: query.enabledCategories === undefined && q.enabledCategories === undefined ? undefined : [...(query.enabledCategories ?? []), ...(q.enabledCategories ?? [])],
|
|
26
|
+
ignoreDefaultFunctions: query.ignoreDefaultFunctions || q.ignoreDefaultFunctions,
|
|
27
|
+
additionalCategories: {
|
|
28
|
+
...query.additionalCategories,
|
|
29
|
+
...q.additionalCategories
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
log_1.log.info('Merged multiple dependencies queries into one:', query);
|
|
20
34
|
}
|
|
21
35
|
const data = { analyzer };
|
|
22
36
|
const normalize = await analyzer.normalize();
|
|
23
37
|
const dataflow = await analyzer.dataflow();
|
|
24
38
|
const config = analyzer.flowrConfig;
|
|
25
39
|
const now = Date.now();
|
|
26
|
-
const [query] = queries;
|
|
27
40
|
const ignoreDefault = query.ignoreDefaultFunctions ?? false;
|
|
28
41
|
const functions = new Map(Object.entries(dependencies_query_format_1.DefaultDependencyCategories).map(([c, v]) => {
|
|
29
42
|
return [c, getFunctionsToCheck(query[`${c}Functions`], c, query.enabledCategories, ignoreDefault, v.functions)];
|
|
@@ -35,12 +48,12 @@ async function executeDependenciesQuery({ analyzer, }, queries) {
|
|
|
35
48
|
}
|
|
36
49
|
}
|
|
37
50
|
const queryResults = functions.values().toArray().flat().length === 0 ? { kinds: {}, '.meta': { timing: 0 } } :
|
|
38
|
-
await (0, query_1.executeQueriesOfSameType)(data, functions.entries().
|
|
51
|
+
await (0, query_1.executeQueriesOfSameType)(data, functions.entries().flatMap(makeCallContextQuery).toArray());
|
|
39
52
|
const g = (0, dependencies_query_format_1.getAllCategories)(queries);
|
|
53
|
+
const enabled = query.enabledCategories;
|
|
40
54
|
const results = Object.fromEntries(await Promise.all(functions.entries().map(async ([c, f]) => {
|
|
41
55
|
const results = getResults(queries, { dataflow, config, normalize }, queryResults, c, f, data);
|
|
42
56
|
// only default categories allow additional analyses, so we null-coalesce here!
|
|
43
|
-
const enabled = query.enabledCategories;
|
|
44
57
|
if (enabled === undefined || (enabled?.length > 0 && enabled.includes(c))) {
|
|
45
58
|
await g[c]?.additionalAnalysis?.(data, ignoreDefault, f, queryResults, results);
|
|
46
59
|
}
|
|
@@ -53,7 +66,7 @@ async function executeDependenciesQuery({ analyzer, }, queries) {
|
|
|
53
66
|
...results,
|
|
54
67
|
};
|
|
55
68
|
}
|
|
56
|
-
function makeCallContextQuery(
|
|
69
|
+
function makeCallContextQuery([kind, functions]) {
|
|
57
70
|
return functions.map(f => ({
|
|
58
71
|
type: 'call-context',
|
|
59
72
|
callName: f.name,
|
|
@@ -75,90 +88,95 @@ const readOnlyModes = new Set(['r', 'rt', 'rb']);
|
|
|
75
88
|
const writeOnlyModes = new Set(['w', 'wt', 'wb', 'a', 'at', 'ab']);
|
|
76
89
|
function getResults(queries, { dataflow, config, normalize }, results, kind, functions, data) {
|
|
77
90
|
const defaultValue = (0, dependencies_query_format_1.getAllCategories)(queries)[kind].defaultValue;
|
|
91
|
+
const vars = config.solver.variables;
|
|
78
92
|
const functionMap = new Map(functions.map(f => [f.name, f]));
|
|
79
93
|
const kindEntries = Object.entries(results?.kinds[kind]?.subkinds ?? {});
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
if (
|
|
93
|
-
|
|
94
|
+
const finalResults = [];
|
|
95
|
+
const ictx = data.analyzer.inspectContext();
|
|
96
|
+
const d = ictx.deps;
|
|
97
|
+
const dfg = dataflow.graph;
|
|
98
|
+
for (const [name, results] of kindEntries) {
|
|
99
|
+
for (const { id, linkedIds } of results) {
|
|
100
|
+
const vertex = dfg.getVertex(id);
|
|
101
|
+
const info = functionMap.get(name);
|
|
102
|
+
const args = (0, resolve_argument_1.getArgumentStringValue)(vars, dfg, vertex, info.argIdx, info.argName, info.resolveValue, ictx);
|
|
103
|
+
const linkedArgs = collectValuesFromLinks(args, { dataflow, config, ctx: ictx }, linkedIds);
|
|
104
|
+
const linked = dropInfoOnLinkedIds(linkedIds);
|
|
105
|
+
function ignoreOnArgVal() {
|
|
106
|
+
if (info.ignoreIf === 'arg-true' || info.ignoreIf === 'arg-false') {
|
|
107
|
+
const margs = info.additionalArgs?.val;
|
|
108
|
+
(0, assert_1.guard)(margs, 'Need additional argument val when checking for arg-true');
|
|
109
|
+
const valArgs = (0, resolve_argument_1.getArgumentStringValue)(vars, dfg, vertex, margs.argIdx, margs.argName, margs.resolveValue, data?.analyzer.inspectContext());
|
|
110
|
+
const valValues = valArgs?.values().flatMap(v => Array.from(v)).toArray() ?? [];
|
|
111
|
+
if (valValues.length === 0) {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
if (info.ignoreIf === 'arg-true' && valValues.every(v => v === 'TRUE')) {
|
|
115
|
+
// all values are TRUE, so we can ignore this
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
else if (info.ignoreIf === 'arg-false' && valValues.every(v => v === 'FALSE')) {
|
|
119
|
+
// all values are FALSE, so we can ignore this
|
|
120
|
+
return true;
|
|
121
|
+
}
|
|
94
122
|
}
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
const foundValues = linkedArgs ?? args;
|
|
126
|
+
if (!foundValues) {
|
|
127
|
+
if (info.ignoreIf === 'arg-missing') {
|
|
128
|
+
continue;
|
|
98
129
|
}
|
|
99
|
-
else if (
|
|
100
|
-
|
|
101
|
-
return true;
|
|
130
|
+
else if (ignoreOnArgVal()) {
|
|
131
|
+
continue;
|
|
102
132
|
}
|
|
103
|
-
|
|
104
|
-
return false;
|
|
105
|
-
}
|
|
106
|
-
const foundValues = linkedArgs ?? args;
|
|
107
|
-
if (!foundValues) {
|
|
108
|
-
if (info.ignoreIf === 'arg-missing') {
|
|
109
|
-
return [];
|
|
110
|
-
}
|
|
111
|
-
else if (ignoreOnArgVal()) {
|
|
112
|
-
return [];
|
|
113
|
-
}
|
|
114
|
-
const record = (0, objects_1.compactRecord)({
|
|
115
|
-
nodeId: id,
|
|
116
|
-
functionName: vertex.name,
|
|
117
|
-
lexemeOfArgument: undefined,
|
|
118
|
-
linkedIds: linked?.length ? linked : undefined,
|
|
119
|
-
value: info.defaultValue ?? defaultValue
|
|
120
|
-
});
|
|
121
|
-
return record ? [record] : [];
|
|
122
|
-
}
|
|
123
|
-
else if (info.ignoreIf === 'mode-only-read' || info.ignoreIf === 'mode-only-write') {
|
|
124
|
-
(0, assert_1.guard)('mode' in (info.additionalArgs ?? {}), 'Need additional argument mode when checking for mode');
|
|
125
|
-
const margs = info.additionalArgs?.mode;
|
|
126
|
-
(0, assert_1.guard)(margs, 'Need additional argument mode when checking for mode');
|
|
127
|
-
const modeArgs = (0, resolve_argument_1.getArgumentStringValue)(config.solver.variables, dataflow.graph, vertex, margs.argIdx, margs.argName, margs.resolveValue, data?.analyzer.inspectContext());
|
|
128
|
-
const modeValues = modeArgs?.values().flatMap(v => Array.from(v)) ?? [];
|
|
129
|
-
if (info.ignoreIf === 'mode-only-read' && modeValues.every(m => m && readOnlyModes.has(m))) {
|
|
130
|
-
// all modes are read-only, so we can ignore this
|
|
131
|
-
return [];
|
|
132
|
-
}
|
|
133
|
-
else if (info.ignoreIf === 'mode-only-write' && modeValues.every(m => m && writeOnlyModes.has(m))) {
|
|
134
|
-
// all modes are write-only, so we can ignore this
|
|
135
|
-
return [];
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
else if (ignoreOnArgVal()) {
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
const results = [];
|
|
142
|
-
for (const [arg, values] of foundValues.entries()) {
|
|
143
|
-
for (const value of values) {
|
|
144
|
-
const dep = value ? data?.analyzer.inspectContext().deps.getDependency(value) ?? undefined : undefined;
|
|
145
|
-
const result = (0, objects_1.compactRecord)({
|
|
133
|
+
const record = (0, objects_1.compactRecord)({
|
|
146
134
|
nodeId: id,
|
|
147
135
|
functionName: vertex.name,
|
|
148
|
-
lexemeOfArgument:
|
|
136
|
+
lexemeOfArgument: undefined,
|
|
149
137
|
linkedIds: linked?.length ? linked : undefined,
|
|
150
|
-
value:
|
|
151
|
-
versionConstraints: dep?.versionConstraints,
|
|
152
|
-
derivedVersion: dep?.derivedVersion,
|
|
153
|
-
namespaceInfo: dep?.namespaceInfo
|
|
138
|
+
value: info.defaultValue ?? defaultValue
|
|
154
139
|
});
|
|
155
|
-
if (
|
|
156
|
-
|
|
140
|
+
if (record) {
|
|
141
|
+
finalResults.push(record);
|
|
142
|
+
}
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
else if (info.ignoreIf === 'mode-only-read' || info.ignoreIf === 'mode-only-write') {
|
|
146
|
+
const margs = info.additionalArgs?.mode;
|
|
147
|
+
(0, assert_1.guard)(margs, 'Need additional argument mode when checking for mode');
|
|
148
|
+
const modeArgs = (0, resolve_argument_1.getArgumentStringValue)(vars, dfg, vertex, margs.argIdx, margs.argName, margs.resolveValue, data?.analyzer.inspectContext());
|
|
149
|
+
const modeValues = modeArgs?.values().flatMap(v => Array.from(v)) ?? [];
|
|
150
|
+
if (info.ignoreIf === 'mode-only-read' && modeValues.every(m => m && readOnlyModes.has(m))) {
|
|
151
|
+
// all modes are read-only, so we can ignore this
|
|
152
|
+
continue;
|
|
153
|
+
}
|
|
154
|
+
else if (info.ignoreIf === 'mode-only-write' && modeValues.every(m => m && writeOnlyModes.has(m))) {
|
|
155
|
+
// all modes are write-only, so we can ignore this
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
else if (ignoreOnArgVal()) {
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
162
|
+
for (const [arg, values] of foundValues.entries()) {
|
|
163
|
+
for (const value of values) {
|
|
164
|
+
const dep = value ? d.getDependency(value) ?? undefined : undefined;
|
|
165
|
+
finalResults.push((0, objects_1.compactRecord)({
|
|
166
|
+
nodeId: id,
|
|
167
|
+
functionName: vertex.name,
|
|
168
|
+
lexemeOfArgument: getLexeme(value, arg),
|
|
169
|
+
linkedIds: linked?.length ? linked : undefined,
|
|
170
|
+
value: value ?? info.defaultValue ?? defaultValue,
|
|
171
|
+
versionConstraints: dep?.versionConstraints,
|
|
172
|
+
derivedVersion: dep?.derivedVersion,
|
|
173
|
+
namespaceInfo: dep?.namespaceInfo
|
|
174
|
+
}));
|
|
157
175
|
}
|
|
158
176
|
}
|
|
159
177
|
}
|
|
160
|
-
|
|
161
|
-
|
|
178
|
+
}
|
|
179
|
+
return finalResults;
|
|
162
180
|
function getLexeme(argument, id) {
|
|
163
181
|
if ((argument && argument !== dependencies_query_format_1.Unknown) || !id) {
|
|
164
182
|
return undefined;
|
|
@@ -174,7 +192,7 @@ function collectValuesFromLinks(args, data, linkedIds) {
|
|
|
174
192
|
if (!linkedIds || linkedIds.length === 0) {
|
|
175
193
|
return undefined;
|
|
176
194
|
}
|
|
177
|
-
const hasAtLeastAValue = args !== undefined &&
|
|
195
|
+
const hasAtLeastAValue = args !== undefined && args.values().flatMap(x => Array.from(x)).toArray().some(v => v !== dependencies_query_format_1.Unknown && v !== undefined);
|
|
178
196
|
const map = new Map();
|
|
179
197
|
for (const linkedId of linkedIds) {
|
|
180
198
|
if (typeof linkedId !== 'object' || !linkedId.info) {
|
|
@@ -187,7 +205,7 @@ function collectValuesFromLinks(args, data, linkedIds) {
|
|
|
187
205
|
}
|
|
188
206
|
// collect this one!
|
|
189
207
|
const vertex = data.dataflow.graph.getVertex(linkedId.id);
|
|
190
|
-
if (vertex
|
|
208
|
+
if (vertex?.tag !== vertex_1.VertexType.FunctionCall) {
|
|
191
209
|
continue;
|
|
192
210
|
}
|
|
193
211
|
const args = (0, resolve_argument_1.getArgumentStringValue)(data.config.solver.variables, data.dataflow.graph, vertex, info.argIdx, info.argName, info.resolveValue, data.ctx);
|
|
@@ -209,7 +227,7 @@ function getFunctionsToCheck(customFunctions, functionFlag, enabled, ignoreDefau
|
|
|
209
227
|
if (enabled !== undefined && (enabled?.length === 0 || enabled.indexOf(functionFlag) < 0)) {
|
|
210
228
|
return [];
|
|
211
229
|
}
|
|
212
|
-
let functions = ignoreDefaultFunctions ? [] :
|
|
230
|
+
let functions = ignoreDefaultFunctions ? [] : defaultFunctions.slice();
|
|
213
231
|
if (customFunctions) {
|
|
214
232
|
functions = functions.concat(customFunctions);
|
|
215
233
|
}
|
package/queries/query.js
CHANGED
|
@@ -73,10 +73,11 @@ exports.SupportedQueries = {
|
|
|
73
73
|
*/
|
|
74
74
|
async function executeQueriesOfSameType(data, queries) {
|
|
75
75
|
(0, assert_1.guard)(queries.length > 0, 'At least one query must be provided');
|
|
76
|
+
const qzt = queries[0].type;
|
|
76
77
|
/* every query must have the same type */
|
|
77
|
-
(0, assert_1.guard)(queries.every(q => q.type ===
|
|
78
|
-
const query = exports.SupportedQueries[
|
|
79
|
-
(0, assert_1.guard)(query !== undefined, `Unsupported query type: ${
|
|
78
|
+
(0, assert_1.guard)(queries.every(q => q.type === qzt), 'All queries must have the same type');
|
|
79
|
+
const query = exports.SupportedQueries[qzt];
|
|
80
|
+
(0, assert_1.guard)(query !== undefined, `Unsupported query type: ${qzt}`);
|
|
80
81
|
return query.executor(data, queries);
|
|
81
82
|
}
|
|
82
83
|
function isVirtualQuery(query) {
|
package/r-bridge/data/data.d.ts
CHANGED
|
@@ -664,6 +664,26 @@ export declare const flowrCapabilities: {
|
|
|
664
664
|
readonly id: "system-calls";
|
|
665
665
|
readonly supported: "not";
|
|
666
666
|
readonly description: "_Handle [`system`](https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/system), `system.*`, ..._ We do not support system calls but treat them as unknown function calls.";
|
|
667
|
+
}, {
|
|
668
|
+
readonly name: "R-Markdown files";
|
|
669
|
+
readonly id: "file:rmd";
|
|
670
|
+
readonly supported: "fully";
|
|
671
|
+
readonly description: "Support R-Markdown files as R sources.";
|
|
672
|
+
}, {
|
|
673
|
+
readonly name: "Jupyter Notebook";
|
|
674
|
+
readonly id: "file:ipynb";
|
|
675
|
+
readonly supported: "partially";
|
|
676
|
+
readonly description: "Support Jupyter Notebooks as R sources.";
|
|
677
|
+
}, {
|
|
678
|
+
readonly name: "Quarto";
|
|
679
|
+
readonly id: "file:qmd";
|
|
680
|
+
readonly supported: "partially";
|
|
681
|
+
readonly description: "Support Quarto files as R sources.";
|
|
682
|
+
}, {
|
|
683
|
+
readonly name: "Sweave";
|
|
684
|
+
readonly id: "file:rnw";
|
|
685
|
+
readonly supported: "partially";
|
|
686
|
+
readonly description: "Support for Sweave files as R sources.";
|
|
667
687
|
}];
|
|
668
688
|
}, {
|
|
669
689
|
readonly name: "Pre-Processors/external Tooling";
|
package/r-bridge/data/data.js
CHANGED
|
@@ -829,6 +829,30 @@ ${await (0, doc_dfg_1.printDfGraphForCode)(parser, code, { simplified: true })}
|
|
|
829
829
|
id: 'system-calls',
|
|
830
830
|
supported: 'not',
|
|
831
831
|
description: '_Handle [`system`](https://www.rdocumentation.org/packages/base/versions/3.6.2/topics/system), `system.*`, ..._ We do not support system calls but treat them as unknown function calls.'
|
|
832
|
+
},
|
|
833
|
+
{
|
|
834
|
+
name: 'R-Markdown files',
|
|
835
|
+
id: 'file:rmd',
|
|
836
|
+
supported: 'fully',
|
|
837
|
+
description: 'Support R-Markdown files as R sources.'
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
name: 'Jupyter Notebook',
|
|
841
|
+
id: 'file:ipynb',
|
|
842
|
+
supported: 'partially',
|
|
843
|
+
description: 'Support Jupyter Notebooks as R sources.'
|
|
844
|
+
},
|
|
845
|
+
{
|
|
846
|
+
name: 'Quarto',
|
|
847
|
+
id: 'file:qmd',
|
|
848
|
+
supported: 'partially',
|
|
849
|
+
description: 'Support Quarto files as R sources.'
|
|
850
|
+
},
|
|
851
|
+
{
|
|
852
|
+
name: 'Sweave',
|
|
853
|
+
id: 'file:rnw',
|
|
854
|
+
supported: 'partially',
|
|
855
|
+
description: 'Support for Sweave files as R sources.'
|
|
832
856
|
}
|
|
833
857
|
]
|
|
834
858
|
},
|
package/util/version.js
CHANGED
|
@@ -6,7 +6,7 @@ exports.printVersionInformation = printVersionInformation;
|
|
|
6
6
|
const semver_1 = require("semver");
|
|
7
7
|
const assert_1 = require("./assert");
|
|
8
8
|
// this is automatically replaced with the current version by release-it
|
|
9
|
-
const version = '2.9.
|
|
9
|
+
const version = '2.9.6';
|
|
10
10
|
/**
|
|
11
11
|
* Retrieves the current flowR version as a new {@link SemVer} object.
|
|
12
12
|
*/
|