@eagleoutice/flowr 2.4.7 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -38
- package/abstract-interpretation/data-frame/absint-visitor.js +3 -2
- package/benchmark/slicer.js +2 -2
- package/benchmark/summarizer/first-phase/process.js +1 -1
- package/benchmark/summarizer/second-phase/graph.js +2 -2
- package/cli/repl/commands/repl-query.js +11 -2
- package/cli/repl/core.d.ts +2 -2
- package/cli/repl/core.js +26 -7
- package/cli/repl/server/connection.js +3 -1
- package/cli/repl/server/messages/message-slice.d.ts +3 -0
- package/cli/repl/server/messages/message-slice.js +2 -0
- package/cli/slicer-app.js +7 -2
- package/control-flow/extract-cfg.d.ts +3 -3
- package/control-flow/extract-cfg.js +4 -4
- package/control-flow/useless-loop.js +30 -21
- package/dataflow/environments/built-in.d.ts +1 -1
- package/dataflow/environments/default-builtin-config.d.ts +9 -0
- package/dataflow/environments/default-builtin-config.js +21 -21
- package/dataflow/environments/environment.js +18 -9
- package/dataflow/environments/overwrite.js +2 -2
- package/dataflow/extractor.js +1 -1
- package/dataflow/graph/diff-dataflow-graph.js +4 -4
- package/dataflow/graph/graph.d.ts +3 -3
- package/dataflow/graph/graph.js +4 -1
- package/dataflow/graph/quads.js +4 -4
- package/dataflow/info.js +1 -1
- package/dataflow/internal/linker.d.ts +2 -0
- package/dataflow/internal/linker.js +18 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +3 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +68 -21
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +4 -4
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +5 -18
- package/dataflow/internal/process/functions/call/built-in/built-in-repeat-loop.js +1 -0
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +4 -5
- package/dataflow/internal/process/functions/call/common.js +4 -3
- package/documentation/doc-util/doc-query.js +6 -2
- package/documentation/doc-util/doc-types.d.ts +7 -2
- package/documentation/doc-util/doc-types.js +20 -4
- package/documentation/print-core-wiki.js +5 -1
- package/documentation/print-dataflow-graph-wiki.js +21 -12
- package/documentation/print-faq-wiki.js +5 -0
- package/documentation/print-interface-wiki.js +2 -0
- package/documentation/print-linter-wiki.js +2 -3
- package/documentation/print-linting-and-testing-wiki.js +4 -0
- package/documentation/print-query-wiki.js +22 -7
- package/documentation/print-readme.js +6 -0
- package/linter/linter-executor.js +25 -17
- package/linter/linter-format.d.ts +10 -1
- package/linter/linter-format.js +8 -0
- package/linter/linter-rules.d.ts +1 -0
- package/linter/rules/absolute-path.js +8 -8
- package/linter/rules/dataframe-access-validation.js +1 -1
- package/linter/rules/file-path-validity.js +8 -11
- package/linter/rules/naming-convention.d.ts +5 -1
- package/linter/rules/naming-convention.js +24 -8
- package/linter/rules/seeded-randomness.js +2 -2
- package/linter/rules/unused-definition.js +1 -1
- package/package.json +20 -15
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +5 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +14 -12
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +6 -5
- package/queries/catalog/call-context-query/call-context-query-format.js +1 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +2 -1
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +1 -1
- package/queries/catalog/config-query/config-query-executor.js +7 -1
- package/queries/catalog/config-query/config-query-format.d.ts +7 -0
- package/queries/catalog/config-query/config-query-format.js +72 -1
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +50 -75
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +50 -26
- package/queries/catalog/dependencies-query/dependencies-query-format.js +75 -20
- package/queries/catalog/dependencies-query/function-info/function-info.d.ts +2 -2
- package/queries/catalog/dependencies-query/function-info/visualize-functions.d.ts +2 -0
- package/queries/catalog/dependencies-query/function-info/visualize-functions.js +13 -0
- package/queries/catalog/happens-before-query/happens-before-query-executor.js +1 -1
- package/queries/catalog/linter-query/linter-query-format.js +4 -0
- package/queries/query-print.d.ts +2 -2
- package/queries/query-print.js +3 -2
- package/queries/query.d.ts +28 -21
- package/r-bridge/lang-4.x/tree-sitter/tree-sitter-executor.js +1 -1
- package/r-bridge/retriever.d.ts +14 -2
- package/r-bridge/retriever.js +10 -4
- package/search/flowr-search-builder.d.ts +1 -1
- package/search/flowr-search-builder.js +1 -1
- package/search/flowr-search-filters.d.ts +20 -10
- package/search/flowr-search-filters.js +19 -3
- package/search/search-executor/search-enrichers.d.ts +1 -1
- package/search/search-executor/search-enrichers.js +3 -2
- package/search/search-executor/search-generators.js +1 -1
- package/search/search-executor/search-transformer.js +1 -1
- package/util/formats/adapter-format.d.ts +6 -0
- package/util/formats/adapter-format.js +3 -0
- package/util/formats/adapter.d.ts +16 -0
- package/util/formats/adapter.js +42 -0
- package/util/formats/adapters/r-adapter.d.ts +4 -0
- package/util/formats/adapters/r-adapter.js +7 -0
- package/util/formats/adapters/rmd-adapter.d.ts +26 -0
- package/util/formats/adapters/rmd-adapter.js +91 -0
- package/util/objects.d.ts +11 -0
- package/util/objects.js +26 -0
- package/util/version.js +1 -1
|
@@ -21,6 +21,7 @@ const named_call_handling_1 = require("../named-call-handling");
|
|
|
21
21
|
const built_in_1 = require("../../../../../environments/built-in");
|
|
22
22
|
const unknown_side_effect_1 = require("../../../../../graph/unknown-side-effect");
|
|
23
23
|
const alias_tracking_1 = require("../../../../../eval/resolve/alias-tracking");
|
|
24
|
+
const r_value_1 = require("../../../../../eval/values/r-value");
|
|
24
25
|
function toReplacementSymbol(target, prefix, superAssignment) {
|
|
25
26
|
return {
|
|
26
27
|
type: type_1.RType.Symbol,
|
|
@@ -87,18 +88,57 @@ args, rootId, data, config) {
|
|
|
87
88
|
return (0, known_call_handling_1.processKnownFunctionCall)({ name, args, rootId, data, forceArgs: config.forceArgs, origin: 'default' }).information;
|
|
88
89
|
}
|
|
89
90
|
const { type, named } = target;
|
|
90
|
-
if (
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
91
|
+
if (type === type_1.RType.Symbol) {
|
|
92
|
+
if (!config.targetVariable) {
|
|
93
|
+
const res = (0, known_call_handling_1.processKnownFunctionCall)({
|
|
94
|
+
name,
|
|
95
|
+
args,
|
|
96
|
+
rootId,
|
|
97
|
+
data,
|
|
98
|
+
reverseOrder: !config.swapSourceAndTarget,
|
|
99
|
+
forceArgs: config.forceArgs,
|
|
100
|
+
origin: 'builtin:assignment'
|
|
101
|
+
});
|
|
102
|
+
return processAssignmentToSymbol({
|
|
103
|
+
...config,
|
|
104
|
+
nameOfAssignmentFunction: name.content,
|
|
105
|
+
source,
|
|
106
|
+
targetId: target.info.id,
|
|
107
|
+
args: getEffectiveOrder(config, res.processedArguments),
|
|
108
|
+
rootId,
|
|
109
|
+
data,
|
|
110
|
+
information: res.information,
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// try to resolve the variable first
|
|
115
|
+
const n = (0, alias_tracking_1.resolveIdToValue)(target.info.id, { environment: data.environment, resolve: data.flowrConfig.solver.variables, idMap: data.completeAst.idMap, full: true });
|
|
116
|
+
if (n.type === 'set' && n.elements.length === 1 && n.elements[0].type === 'string') {
|
|
117
|
+
const val = n.elements[0].value;
|
|
118
|
+
if ((0, r_value_1.isValue)(val)) {
|
|
119
|
+
const res = (0, known_call_handling_1.processKnownFunctionCall)({
|
|
120
|
+
name,
|
|
121
|
+
args,
|
|
122
|
+
rootId,
|
|
123
|
+
data,
|
|
124
|
+
reverseOrder: !config.swapSourceAndTarget,
|
|
125
|
+
forceArgs: config.forceArgs,
|
|
126
|
+
origin: 'builtin:assignment'
|
|
127
|
+
});
|
|
128
|
+
return processAssignmentToSymbol({
|
|
129
|
+
...config,
|
|
130
|
+
nameOfAssignmentFunction: name.content,
|
|
131
|
+
source,
|
|
132
|
+
targetId: target.info.id,
|
|
133
|
+
targetName: val.str,
|
|
134
|
+
args: getEffectiveOrder(config, res.processedArguments),
|
|
135
|
+
rootId,
|
|
136
|
+
data,
|
|
137
|
+
information: res.information,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
102
142
|
}
|
|
103
143
|
else if (config.canBeReplacement && type === type_1.RType.FunctionCall && named) {
|
|
104
144
|
/* as replacement functions take precedence over the lhs fn-call (i.e., `names(x) <- ...` is independent from the definition of `names`), we do not have to process the call */
|
|
@@ -127,7 +167,7 @@ args, rootId, data, config) {
|
|
|
127
167
|
...config,
|
|
128
168
|
nameOfAssignmentFunction: name.content,
|
|
129
169
|
source,
|
|
130
|
-
|
|
170
|
+
targetId: rootArg.info.id,
|
|
131
171
|
args: getEffectiveOrder(config, res.processedArguments),
|
|
132
172
|
rootId,
|
|
133
173
|
data,
|
|
@@ -155,12 +195,12 @@ function extractSourceAndTarget(args) {
|
|
|
155
195
|
* Promotes the ingoing/unknown references of target (an assignment) to definitions
|
|
156
196
|
*/
|
|
157
197
|
function produceWrittenNodes(rootId, target, referenceType, data, makeMaybe, value) {
|
|
158
|
-
return
|
|
198
|
+
return target.in.concat(target.unknownReferences).map(ref => ({
|
|
159
199
|
...ref,
|
|
160
200
|
type: referenceType,
|
|
161
201
|
definedAt: rootId,
|
|
162
202
|
controlDependencies: data.controlDependencies ?? (makeMaybe ? [] : undefined),
|
|
163
|
-
value
|
|
203
|
+
value
|
|
164
204
|
}));
|
|
165
205
|
}
|
|
166
206
|
function processAssignmentToString(target, args, name, rootId, data, config, source) {
|
|
@@ -190,7 +230,7 @@ function processAssignmentToString(target, args, name, rootId, data, config, sou
|
|
|
190
230
|
...config,
|
|
191
231
|
nameOfAssignmentFunction: name.content,
|
|
192
232
|
source,
|
|
193
|
-
|
|
233
|
+
targetId: symbol.info.id,
|
|
194
234
|
args: getEffectiveOrder(config, res.processedArguments),
|
|
195
235
|
rootId,
|
|
196
236
|
data,
|
|
@@ -269,19 +309,26 @@ function markAsAssignment(information, nodeToDefine, sourceIds, rootIdOfAssignme
|
|
|
269
309
|
* Helper function whenever it is known that the _target_ of an assignment is a (single) symbol (i.e. `x <- ...`, but not `names(x) <- ...`).
|
|
270
310
|
*/
|
|
271
311
|
function processAssignmentToSymbol(config) {
|
|
272
|
-
const { nameOfAssignmentFunction, source, args: [targetArg, sourceArg],
|
|
312
|
+
const { nameOfAssignmentFunction, source, args: [targetArg, sourceArg], targetId, targetName, rootId, data, information, makeMaybe, quoteSource } = config;
|
|
273
313
|
const referenceType = checkTargetReferenceType(source, sourceArg);
|
|
274
314
|
const aliases = (0, alias_tracking_1.getAliases)([source.info.id], information.graph, information.environment);
|
|
275
|
-
const writeNodes =
|
|
315
|
+
const writeNodes = targetName ? [{
|
|
316
|
+
nodeId: targetId,
|
|
317
|
+
name: targetName,
|
|
318
|
+
type: referenceType,
|
|
319
|
+
definedAt: rootId,
|
|
320
|
+
controlDependencies: data.controlDependencies ?? (makeMaybe ? [] : undefined),
|
|
321
|
+
value: aliases
|
|
322
|
+
}]
|
|
323
|
+
: produceWrittenNodes(rootId, targetArg, referenceType, data, makeMaybe ?? false, aliases);
|
|
276
324
|
if (writeNodes.length !== 1 && log_1.log.settings.minLevel <= 4 /* LogLevel.Warn */) {
|
|
277
325
|
log_1.log.warn(`Unexpected write number in assignment: ${JSON.stringify(writeNodes)}`);
|
|
278
326
|
}
|
|
279
327
|
// we drop the first arg which we use to pass along arguments :D
|
|
280
328
|
const readFromSourceWritten = sourceArg.out.slice(1);
|
|
281
329
|
const readTargets = [
|
|
282
|
-
{ nodeId: rootId, name: nameOfAssignmentFunction, controlDependencies: data.controlDependencies, type: identifier_1.ReferenceType.Function }
|
|
283
|
-
|
|
284
|
-
];
|
|
330
|
+
{ nodeId: rootId, name: nameOfAssignmentFunction, controlDependencies: data.controlDependencies, type: identifier_1.ReferenceType.Function }
|
|
331
|
+
].concat(sourceArg.unknownReferences, sourceArg.in, targetName ? targetArg.in : targetArg.in.filter(i => i.nodeId !== targetId), readFromSourceWritten);
|
|
285
332
|
information.environment = (0, overwrite_1.overwriteEnvironment)(sourceArg.environment, targetArg.environment);
|
|
286
333
|
// install assigned variables in environment
|
|
287
334
|
for (const write of writeNodes) {
|
|
@@ -181,8 +181,7 @@ function processExpressionList(name, args, rootId, data) {
|
|
|
181
181
|
graph: nextGraph,
|
|
182
182
|
/* if we have no group, we take the last evaluated expr */
|
|
183
183
|
entryPoint: meId,
|
|
184
|
-
exitPoints:
|
|
185
|
-
: exitPoints
|
|
184
|
+
exitPoints: exitPoints
|
|
186
185
|
};
|
|
187
186
|
}
|
|
188
187
|
//# sourceMappingURL=built-in-expression-list.js.map
|
|
@@ -30,14 +30,13 @@ function processForLoop(name, args, rootId, data) {
|
|
|
30
30
|
const variable = (0, processor_1.processDataflowFor)(variableArg, data);
|
|
31
31
|
// this should not be able to exit always!
|
|
32
32
|
const originalDependency = data.controlDependencies;
|
|
33
|
-
data = { ...data, controlDependencies: [...data.controlDependencies ?? [], { id: name.info.id, when: true }] };
|
|
34
33
|
let headEnvironments = (0, overwrite_1.overwriteEnvironment)(vector.environment, variable.environment);
|
|
35
34
|
const headGraph = variable.graph.mergeWith(vector.graph);
|
|
36
|
-
const writtenVariable =
|
|
35
|
+
const writtenVariable = variable.unknownReferences.concat(variable.in);
|
|
37
36
|
for (const write of writtenVariable) {
|
|
38
37
|
headEnvironments = (0, define_1.define)({ ...write, definedAt: name.info.id, type: identifier_1.ReferenceType.Variable }, false, headEnvironments, data.flowrConfig);
|
|
39
38
|
}
|
|
40
|
-
data = { ...data, environment: headEnvironments };
|
|
39
|
+
data = { ...data, controlDependencies: [...data.controlDependencies ?? [], { id: name.info.id, when: true }], environment: headEnvironments };
|
|
41
40
|
const body = (0, processor_1.processDataflowFor)(bodyArg, data);
|
|
42
41
|
const nextGraph = headGraph.mergeWith(body.graph);
|
|
43
42
|
const outEnvironment = (0, append_1.appendEnvironment)(headEnvironments, body.environment);
|
|
@@ -48,8 +47,9 @@ function processForLoop(name, args, rootId, data) {
|
|
|
48
47
|
nextGraph.addEdge(write.nodeId, vector.entryPoint, edge_1.EdgeType.DefinedBy);
|
|
49
48
|
nextGraph.setDefinitionOfVertex(write);
|
|
50
49
|
}
|
|
51
|
-
const outgoing =
|
|
50
|
+
const outgoing = variable.out.concat(writtenVariable, (0, environment_1.makeAllMaybe)(body.out, nextGraph, outEnvironment, true));
|
|
52
51
|
(0, linker_1.linkCircularRedefinitionsWithinALoop)(nextGraph, nameIdShares, body.out);
|
|
52
|
+
(0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences));
|
|
53
53
|
(0, common_1.patchFunctionCall)({
|
|
54
54
|
nextGraph,
|
|
55
55
|
rootId,
|
|
@@ -28,7 +28,7 @@ function processIfThenElse(name, args, rootId, data) {
|
|
|
28
28
|
logger_1.dataflowLogger.warn(`If-then-else ${rootId} forces exit in condition, skipping rest`);
|
|
29
29
|
return cond;
|
|
30
30
|
}
|
|
31
|
-
const originalDependency = data.controlDependencies;
|
|
31
|
+
const originalDependency = data.controlDependencies?.slice();
|
|
32
32
|
// currently we update the cd afterward :sweat:
|
|
33
33
|
data = { ...data, environment: cond.environment };
|
|
34
34
|
let then;
|
|
@@ -73,21 +73,10 @@ function processIfThenElse(name, args, rootId, data) {
|
|
|
73
73
|
const cdTrue = { id: rootId, when: true };
|
|
74
74
|
const cdFalse = { id: rootId, when: false };
|
|
75
75
|
// again within an if-then-else we consider all actives to be read
|
|
76
|
-
const ingoing = [
|
|
77
|
-
...cond.in,
|
|
78
|
-
...(makeThenMaybe ? (0, environment_1.makeAllMaybe)(then?.in, nextGraph, finalEnvironment, false, cdTrue) : then?.in ?? []),
|
|
79
|
-
...(makeOtherwiseMaybe ? (0, environment_1.makeAllMaybe)(otherwise?.in, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.in ?? []),
|
|
80
|
-
...cond.unknownReferences,
|
|
81
|
-
...(makeThenMaybe ? (0, environment_1.makeAllMaybe)(then?.unknownReferences, nextGraph, finalEnvironment, false, cdTrue) : then?.unknownReferences ?? []),
|
|
82
|
-
...(makeOtherwiseMaybe ? (0, environment_1.makeAllMaybe)(otherwise?.unknownReferences, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.unknownReferences ?? []),
|
|
83
|
-
];
|
|
76
|
+
const ingoing = cond.in.concat(makeThenMaybe ? (0, environment_1.makeAllMaybe)(then?.in, nextGraph, finalEnvironment, false, cdTrue) : then?.in ?? [], makeOtherwiseMaybe ? (0, environment_1.makeAllMaybe)(otherwise?.in, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.in ?? [], cond.unknownReferences, makeThenMaybe ? (0, environment_1.makeAllMaybe)(then?.unknownReferences, nextGraph, finalEnvironment, false, cdTrue) : then?.unknownReferences ?? [], makeOtherwiseMaybe ? (0, environment_1.makeAllMaybe)(otherwise?.unknownReferences, nextGraph, finalEnvironment, false, cdFalse) : otherwise?.unknownReferences ?? []);
|
|
84
77
|
// we assign all with a maybe marker
|
|
85
78
|
// we do not merge even if they appear in both branches because the maybe links will refer to different ids
|
|
86
|
-
const outgoing = [
|
|
87
|
-
...cond.out,
|
|
88
|
-
...(makeThenMaybe ? (0, environment_1.makeAllMaybe)(then?.out, nextGraph, finalEnvironment, true, cdTrue) : then?.out ?? []),
|
|
89
|
-
...(makeOtherwiseMaybe ? (0, environment_1.makeAllMaybe)(otherwise?.out, nextGraph, finalEnvironment, true, cdFalse) : otherwise?.out ?? []),
|
|
90
|
-
];
|
|
79
|
+
const outgoing = cond.out.concat((makeThenMaybe ? (0, environment_1.makeAllMaybe)(then?.out, nextGraph, finalEnvironment, true, cdTrue) : then?.out ?? []), (makeOtherwiseMaybe ? (0, environment_1.makeAllMaybe)(otherwise?.out, nextGraph, finalEnvironment, true, cdFalse) : otherwise?.out ?? []));
|
|
91
80
|
(0, common_1.patchFunctionCall)({
|
|
92
81
|
nextGraph,
|
|
93
82
|
rootId,
|
|
@@ -98,10 +87,8 @@ function processIfThenElse(name, args, rootId, data) {
|
|
|
98
87
|
});
|
|
99
88
|
// as an if always evaluates its condition, we add a 'reads'-edge
|
|
100
89
|
nextGraph.addEdge(name.info.id, cond.entryPoint, edge_1.EdgeType.Reads);
|
|
101
|
-
const exitPoints = [
|
|
102
|
-
|
|
103
|
-
...(otherwise?.exitPoints ?? []).map(e => ({ ...e, controlDependencies: makeOtherwiseMaybe ? [...data.controlDependencies ?? [], { id: rootId, when: false }] : e.controlDependencies }))
|
|
104
|
-
];
|
|
90
|
+
const exitPoints = (then?.exitPoints ?? []).map(e => ({ ...e, controlDependencies: makeThenMaybe ? [...data.controlDependencies ?? [], { id: rootId, when: true }] : e.controlDependencies }))
|
|
91
|
+
.concat((otherwise?.exitPoints ?? []).map(e => ({ ...e, controlDependencies: makeOtherwiseMaybe ? [...data.controlDependencies ?? [], { id: rootId, when: false }] : e.controlDependencies })));
|
|
105
92
|
return {
|
|
106
93
|
unknownReferences: [],
|
|
107
94
|
in: [{ nodeId: rootId, name: name.content, controlDependencies: originalDependency, type: identifier_1.ReferenceType.Function }, ...ingoing],
|
|
@@ -31,6 +31,7 @@ function processRepeatLoop(name, args, rootId, data) {
|
|
|
31
31
|
const body = processedArguments[0];
|
|
32
32
|
(0, assert_1.guard)(body !== undefined, () => `Repeat-Loop ${name.content} has no body, impossible!`);
|
|
33
33
|
(0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph, [])), body.out);
|
|
34
|
+
(0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences));
|
|
34
35
|
information.exitPoints = (0, info_1.filterOutLoopExitPoints)(information.exitPoints);
|
|
35
36
|
return information;
|
|
36
37
|
}
|
|
@@ -65,17 +65,16 @@ function processWhileLoop(name, args, rootId, data) {
|
|
|
65
65
|
information.graph.addEdge(name.info.id, condition.entryPoint, edge_1.EdgeType.Reads);
|
|
66
66
|
return condition;
|
|
67
67
|
}
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
...(0, environment_1.makeAllMaybe)(body.in, information.graph, information.environment, false)
|
|
71
|
-
], information.environment, [...condition.in, ...condition.unknownReferences], information.graph, true);
|
|
68
|
+
const cdTrue = { id: name.info.id, when: true };
|
|
69
|
+
const remainingInputs = (0, linker_1.linkInputs)((0, environment_1.makeAllMaybe)(body.unknownReferences, information.graph, information.environment, false, cdTrue).concat((0, environment_1.makeAllMaybe)(body.in, information.graph, information.environment, false, cdTrue)), information.environment, condition.in.concat(condition.unknownReferences), information.graph, true);
|
|
72
70
|
(0, linker_1.linkCircularRedefinitionsWithinALoop)(information.graph, (0, linker_1.produceNameSharedIdMap)((0, linker_1.findNonLocalReads)(information.graph, condition.in)), body.out);
|
|
71
|
+
(0, linker_1.reapplyLoopExitPoints)(body.exitPoints, body.in.concat(body.out, body.unknownReferences));
|
|
73
72
|
// as the while-loop always evaluates its condition
|
|
74
73
|
information.graph.addEdge(name.info.id, condition.entryPoint, edge_1.EdgeType.Reads);
|
|
75
74
|
return {
|
|
76
75
|
unknownReferences: [],
|
|
77
76
|
in: [{ nodeId: name.info.id, name: name.lexeme, controlDependencies: originalDependency, type: identifier_1.ReferenceType.Function }, ...remainingInputs],
|
|
78
|
-
out:
|
|
77
|
+
out: condition.out.concat((0, environment_1.makeAllMaybe)(body.out, information.graph, information.environment, true, cdTrue)),
|
|
79
78
|
entryPoint: name.info.id,
|
|
80
79
|
exitPoints: (0, info_1.filterOutLoopExitPoints)(body.exitPoints),
|
|
81
80
|
graph: information.graph,
|
|
@@ -29,11 +29,12 @@ function forceVertexArgumentValueReferences(rootId, value, graph, env) {
|
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
const containedSubflowIn =
|
|
32
|
+
const containedSubflowIn = graph.vertices(true)
|
|
33
33
|
.filter(([, info]) => (0, vertex_1.isFunctionDefinitionVertex)(info))
|
|
34
|
-
.flatMap(([, info]) => info)
|
|
34
|
+
.flatMap(([, info]) => info.subflow.in)
|
|
35
|
+
.toArray();
|
|
35
36
|
// try to resolve them against the current environment
|
|
36
|
-
for (const ref of
|
|
37
|
+
for (const ref of value.in.concat(containedSubflowIn)) {
|
|
37
38
|
if (ref.name) {
|
|
38
39
|
const resolved = ref.name ? (0, resolve_by_name_1.resolveByName)(ref.name, env, ref.type) ?? [] : [];
|
|
39
40
|
for (const resolve of resolved) {
|
|
@@ -25,7 +25,11 @@ async function showQuery(shell, code, queries, { showCode, collapseResult, colla
|
|
|
25
25
|
parser: shell,
|
|
26
26
|
request: (0, retriever_1.requestFromInput)(code)
|
|
27
27
|
}, config_1.defaultConfigOptions).allRemainingSteps();
|
|
28
|
-
const results = await Promise.resolve((0, query_1.executeQueries)({
|
|
28
|
+
const results = await Promise.resolve((0, query_1.executeQueries)({
|
|
29
|
+
dataflow: analysis.dataflow,
|
|
30
|
+
ast: analysis.normalize,
|
|
31
|
+
config: (0, config_1.cloneConfig)(config_1.defaultConfigOptions)
|
|
32
|
+
}, queries));
|
|
29
33
|
const duration = performance.now() - now;
|
|
30
34
|
const metaInfo = `
|
|
31
35
|
The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parsing and normalization and the query) within the generation environment.
|
|
@@ -48,7 +52,7 @@ ${collapseResult ? ' <details> <summary style="color:gray">Show Results</summary
|
|
|
48
52
|
|
|
49
53
|
_Results (prettified and summarized):_
|
|
50
54
|
|
|
51
|
-
${(0, query_print_1.asciiSummaryOfQueryResult)(ansi_1.markdownFormatter, duration, results, analysis)}
|
|
55
|
+
${(0, query_print_1.asciiSummaryOfQueryResult)(ansi_1.markdownFormatter, duration, results, analysis, queries)}
|
|
52
56
|
|
|
53
57
|
<details> <summary style="color:gray">Show Detailed Results as Json</summary>
|
|
54
58
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
|
+
export type TypeElementKind = 'interface' | 'type' | 'enum' | 'class' | 'variable';
|
|
2
3
|
export interface TypeElementInSource {
|
|
3
4
|
name: string;
|
|
4
5
|
node: ts.Node;
|
|
5
|
-
kind:
|
|
6
|
+
kind: TypeElementKind;
|
|
6
7
|
extends: string[];
|
|
7
8
|
generics: string[];
|
|
8
9
|
filePath: string;
|
|
@@ -73,5 +74,9 @@ export declare function printCodeOfElement({ program, info }: FnInfo, name: stri
|
|
|
73
74
|
*/
|
|
74
75
|
export declare function shortLink(name: string, hierarchy: readonly TypeElementInSource[], codeStyle?: boolean, realNameWrapper?: string): string;
|
|
75
76
|
export declare function shortLinkFile(name: string, hierarchy: readonly TypeElementInSource[]): string;
|
|
76
|
-
export
|
|
77
|
+
export interface GetDocumentationForTypeFilters {
|
|
78
|
+
fuzzy?: boolean;
|
|
79
|
+
type?: TypeElementKind;
|
|
80
|
+
}
|
|
81
|
+
export declare function getDocumentationForType(name: string, hierarchy: TypeElementInSource[], prefix?: string, filter?: GetDocumentationForTypeFilters): string;
|
|
77
82
|
export {};
|
|
@@ -32,7 +32,17 @@ const html_hover_over_1 = require("../../util/html-hover-over");
|
|
|
32
32
|
const doc_general_1 = require("./doc-general");
|
|
33
33
|
function getTypeScriptSourceFiles(fileNames) {
|
|
34
34
|
try {
|
|
35
|
-
const program = typescript_1.default.createProgram(fileNames, {
|
|
35
|
+
const program = typescript_1.default.createProgram(fileNames, {
|
|
36
|
+
target: typescript_1.default.ScriptTarget.ESNext,
|
|
37
|
+
skipLibCheck: true,
|
|
38
|
+
skipDefaultLibCheck: true,
|
|
39
|
+
allowJs: true,
|
|
40
|
+
checkJs: false,
|
|
41
|
+
strictNullChecks: false,
|
|
42
|
+
noUncheckedIndexedAccess: false,
|
|
43
|
+
noUncheckedSideEffectImports: false,
|
|
44
|
+
noCheck: true
|
|
45
|
+
});
|
|
36
46
|
return { program, files: fileNames.map(fileName => program.getSourceFile(fileName)).filter(file => !!file) };
|
|
37
47
|
}
|
|
38
48
|
catch (err) {
|
|
@@ -391,7 +401,7 @@ function fuzzyCompare(a, b) {
|
|
|
391
401
|
const bStr = b.toLowerCase().replace(/[^a-z0-9]/g, '-').trim();
|
|
392
402
|
return aStr === bStr || aStr.includes(bStr) || bStr.includes(aStr);
|
|
393
403
|
}
|
|
394
|
-
function retrieveNode(name, hierarchy, fuzzy = false) {
|
|
404
|
+
function retrieveNode(name, hierarchy, fuzzy = false, type = undefined) {
|
|
395
405
|
let container = undefined;
|
|
396
406
|
if (name.includes('::')) {
|
|
397
407
|
[container, name] = name.split(/:::?/);
|
|
@@ -406,6 +416,12 @@ function retrieveNode(name, hierarchy, fuzzy = false) {
|
|
|
406
416
|
return undefined;
|
|
407
417
|
}
|
|
408
418
|
}
|
|
419
|
+
if (type) {
|
|
420
|
+
node = node.filter(n => n.kind === type);
|
|
421
|
+
if (node.length === 0) {
|
|
422
|
+
return undefined;
|
|
423
|
+
}
|
|
424
|
+
}
|
|
409
425
|
return [container, name, node[0]];
|
|
410
426
|
}
|
|
411
427
|
/**
|
|
@@ -440,8 +456,8 @@ function shortLinkFile(name, hierarchy) {
|
|
|
440
456
|
const [, , node] = res;
|
|
441
457
|
return `<a href="${getTypePathLink(node)}">${getTypePathForTypeScript(node)}</a>`;
|
|
442
458
|
}
|
|
443
|
-
function getDocumentationForType(name, hierarchy, prefix = '',
|
|
444
|
-
const res = retrieveNode(name, hierarchy, fuzzy);
|
|
459
|
+
function getDocumentationForType(name, hierarchy, prefix = '', filter) {
|
|
460
|
+
const res = retrieveNode(name, hierarchy, filter?.fuzzy, filter?.type);
|
|
445
461
|
if (!res) {
|
|
446
462
|
return '';
|
|
447
463
|
}
|
|
@@ -50,6 +50,10 @@ async function getText(shell) {
|
|
|
50
50
|
rootFolder: path_1.default.resolve('./src'),
|
|
51
51
|
inlineTypes: doc_types_1.mermaidHide
|
|
52
52
|
});
|
|
53
|
+
const testInfo = (0, doc_types_1.getTypesFromFolder)({
|
|
54
|
+
rootFolder: path_1.default.resolve('./test'),
|
|
55
|
+
inlineTypes: doc_types_1.mermaidHide
|
|
56
|
+
}).info;
|
|
53
57
|
return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'core', rVersion: rversion })}
|
|
54
58
|
|
|
55
59
|
This wiki page provides an overview of the inner workings of _flowR_.
|
|
@@ -390,7 +394,7 @@ ${await (0, doc_repl_1.documentReplSession)(shell, [{
|
|
|
390
394
|
### Getting flowR to Talk
|
|
391
395
|
|
|
392
396
|
When using flowR from the CLI, you can use the ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'verbose')} option to get more information about what flowR is doing.
|
|
393
|
-
While coding, however, you can use the ${(0, doc_types_1.shortLink)(log_1.setMinLevelOfAllLogs.name,
|
|
397
|
+
While coding, however, you can use the ${(0, doc_types_1.shortLink)(log_1.setMinLevelOfAllLogs.name, testInfo)} function to set the minimum level of logs to be displayed (this works with the ${(0, doc_types_1.shortLink)(log_2.FlowrLogger.name, info)} abstraction).
|
|
394
398
|
In general, you can configure the levels of individual logs, such as the general \`log\` (obtained with ${(0, doc_types_1.shortLink)('getActiveLog', info)}) or the ${(0, doc_types_1.shortLink)('parseLog', info)}.
|
|
395
399
|
Please note that flowR makes no guarantees that log outputs are persistent across versions, and it is up to the implementors to provide sensible logging.
|
|
396
400
|
If you are an implementor and want to add logging, please make sure there are no larger runtime impliciations when logging is disabled.
|
|
@@ -74,7 +74,7 @@ async function explanation({ shell, name, type, description, code, expectedSubgr
|
|
|
74
74
|
<a id='${name.toLowerCase().replaceAll(' ', '-')}'> </a>
|
|
75
75
|
### ${index}) ${name}
|
|
76
76
|
|
|
77
|
-
Type: \`${type}\` (this is the
|
|
77
|
+
Type: \`${type}\` (this is the bit-flag value, e.g., when looking at the serialization)
|
|
78
78
|
|
|
79
79
|
${await subExplanation(shell, { name, description, code, expectedSubgraph })}
|
|
80
80
|
|
|
@@ -268,7 +268,7 @@ ${await (async () => {
|
|
|
268
268
|
const code = 'foo <- function() 3\nfoo()';
|
|
269
269
|
const [text, info] = await (0, doc_dfg_1.printDfGraphForCode)(shell, code, { exposeResult: true, mark: new Set([6, '6->0', '6->1', '6->3']) });
|
|
270
270
|
const numberOfEdges = [...info.dataflow.graph.edges()].flatMap(e => [...e[1].keys()]).length;
|
|
271
|
-
const callVertex =
|
|
271
|
+
const callVertex = info.dataflow.graph.vertices(true).find(([, vertex]) => vertex.tag === vertex_1.VertexType.FunctionCall && vertex.name === 'foo');
|
|
272
272
|
(0, assert_1.guard)(callVertex !== undefined, () => `Could not find call vertex for ${code}`);
|
|
273
273
|
const [callId] = callVertex;
|
|
274
274
|
return `
|
|
@@ -367,11 +367,11 @@ ${(0, doc_structure_1.block)({
|
|
|
367
367
|
content: `Now you might be asking yourself how to differentiate anonymous and named functions and what you have to keep in mind when working with them?
|
|
368
368
|
|
|
369
369
|
Unnamed functions have an array of signatures which you can use to identify them.
|
|
370
|
-
But in short
|
|
370
|
+
But in short: the \`origin\` attribute of the ${(0, doc_types_1.shortLink)('DataflowGraphVertexFunctionCall', vertexType.info)} is \`${unnamed_call_handling_1.UnnamedFunctionCallOrigin}\`.
|
|
371
371
|
Please be aware that unnamed functions still have a \`name\` property to give it a unique identifier that can be used for debugging and reference.
|
|
372
372
|
This name _always_ starts with \`${unnamed_call_handling_1.UnnamedFunctionCallPrefix}\`.
|
|
373
373
|
|
|
374
|
-
To identify these calls please do not rely on the [
|
|
374
|
+
To identify these calls please do not rely on the [normalized AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST). An expression like \`1 + 1\` will be correctly
|
|
375
375
|
identified as a syntactical binary operation. Yet, from a dataflow/semantic perspective this is equivalent to \`\` \`+\`(1, 1) \`\` (which is a named function call and marked as such in the dataflow graph).
|
|
376
376
|
To know which function is called, please rely on the ${linkEdgeName(edge_1.EdgeType.Calls)} edge.
|
|
377
377
|
`
|
|
@@ -458,9 +458,10 @@ vertices of function definitions or not (e.g., \`${new graph_1.DataflowGraph(und
|
|
|
458
458
|
|
|
459
459
|
${(0, doc_structure_1.details)('Example: Nested Function Definitions', await (async () => {
|
|
460
460
|
const [text, info] = await (0, doc_dfg_1.printDfGraphForCode)(shell, 'f <- function() { g <- function() 3 }', { mark: new Set([9, 6]), exposeResult: true });
|
|
461
|
-
const definitions =
|
|
461
|
+
const definitions = info.dataflow.graph.vertices(true)
|
|
462
462
|
.filter(([, vertex]) => vertex.tag === vertex_1.VertexType.FunctionDefinition)
|
|
463
|
-
.map(([id, vertex]) => `| \`${id}\` | { \`${[...vertex.subflow.graph].join('`, `')}\` } |`)
|
|
463
|
+
.map(([id, vertex]) => `| \`${id}\` | { \`${[...vertex.subflow.graph].join('`, `')}\` } |`)
|
|
464
|
+
.toArray();
|
|
464
465
|
return `
|
|
465
466
|
${text}
|
|
466
467
|
|
|
@@ -766,6 +767,7 @@ async function getText(shell) {
|
|
|
766
767
|
|
|
767
768
|
This page briefly summarizes flowR's dataflow graph, represented by the ${(0, doc_types_1.shortLink)(graph_1.DataflowGraph.name, vertexType.info)} class within the code.
|
|
768
769
|
In case you want to manually build such a graph (e.g., for testing), you can use the ${(0, doc_types_1.shortLink)(dataflowgraph_builder_1.DataflowGraphBuilder.name, vertexType.info)}.
|
|
770
|
+
If you are interested in which features we support and which features are still to be worked on, please refer to our [capabilities](${doc_files_1.FlowrWikiBaseRef}/Capabilities) page.
|
|
769
771
|
In summary, we discuss the following topics:
|
|
770
772
|
|
|
771
773
|
- [Vertices](#vertices)
|
|
@@ -777,7 +779,7 @@ In summary, we discuss the following topics:
|
|
|
777
779
|
|
|
778
780
|
Please be aware that the accompanied [dataflow information](#dataflow-information) (${(0, doc_types_1.shortLink)('DataflowInformation', vertexType.info)}) returned by _flowR_ contains things besides the graph,
|
|
779
781
|
like the entry and exit points of the subgraphs, and currently active references (see [below](#dataflow-information)).
|
|
780
|
-
Additionally, you may be interested in the set of [Unknown Side Effects](#unknown-side-effects) marking calls which _flowR_ is unable to handle correctly.
|
|
782
|
+
Additionally, you may be interested in the set of [Unknown Side Effects](#unknown-side-effects), marking calls which _flowR_ is unable to handle correctly.
|
|
781
783
|
|
|
782
784
|
Potentially, you are interested in another perspective that flowR provides, the [control flow graph](${doc_files_1.FlowrWikiBaseRef}/Control%20Flow%20Graph), so please check the correpsonding
|
|
783
785
|
wiki page if you are unsure.
|
|
@@ -829,16 +831,16 @@ From an implementation perspective all of these types are represented by respect
|
|
|
829
831
|
The following sections present details on the different types of vertices and edges, including examples and explanations.
|
|
830
832
|
|
|
831
833
|
> [!NOTE]
|
|
832
|
-
> Every dataflow vertex holds an \`id\` which links it to the respective node in the [normalized AST](${doc_files_1.FlowrWikiBaseRef}/Normalized
|
|
834
|
+
> Every dataflow vertex holds an \`id\` which links it to the respective node in the [normalized AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST).
|
|
833
835
|
> So if you want more information about the respective vertex, you can usually access more information
|
|
834
836
|
> using the <code>${(0, doc_types_1.shortLink)(`${graph_1.DataflowGraph.name}`, vertexType.info, false, 'i')}::idMap</code> linked to the dataflow graph:
|
|
835
837
|
${(0, doc_general_1.prefixLines)((0, doc_code_1.codeBlock)('ts', 'const node = graph.idMap.get(id);'), '> ')}
|
|
836
838
|
> In case you just need the name (\`lexeme\`) of the respective vertex, ${(0, doc_types_1.shortLink)(node_id_1.recoverName.name, vertexType.info)} can help you out:
|
|
837
839
|
${(0, doc_general_1.prefixLines)((0, doc_code_1.codeBlock)('ts', `const name = ${node_id_1.recoverName.name}(id, graph.idMap);`), '> ')}
|
|
838
840
|
>
|
|
839
|
-
> Please note that not every node in the normalized AST is represented in the dataflow graph.
|
|
841
|
+
> Please note, that not every node in the [normalized AST](${doc_files_1.FlowrWikiBaseRef}/Normalized-AST) is represented in the dataflow graph.
|
|
840
842
|
> For example, if the node is unreachable in a way that can be detected during the analysis and flowR
|
|
841
|
-
> is configured to ignore dead code. Likewise, empty argument wrappers do not have a corresponding
|
|
843
|
+
> is configured to ignore dead code (there are more powerful dead code capabilities with the [CFG](${doc_files_1.FlowrWikiBaseRef}/Control-Flow-Graph)). Likewise, empty argument wrappers do not have a corresponding
|
|
842
844
|
> dataflow graph vertex (as they are not relevant for the dataflow graph). It depends on the scenario what to do in such a case.
|
|
843
845
|
> For argument wrappers you can access the dataflow information for their value. For dead code, however, flowR currently contains
|
|
844
846
|
> some core heuristics that remove it which cannot be reversed easily. So please open [an issue](${doc_issue_1.NewIssueUrl}) if you encounter such a case and require the node to be present in the dataflow graph.
|
|
@@ -990,7 +992,8 @@ Depending on what you are interested in, there exists a plethora of functions an
|
|
|
990
992
|
* ${(0, doc_types_1.shortLink)(identify_link_to_last_call_relation_1.getValueOfArgument.name, vertexType.info)} to get the (syntactical) value of an argument in a function call
|
|
991
993
|
* ${(0, doc_types_1.shortLink)(dfg_get_origin_1.getOriginInDfg.name, vertexType.info)} to get information about where a read, call, ... comes from (see [below](#dfg-resolving-values))
|
|
992
994
|
|
|
993
|
-
Some of these functions have been explained in their respective wiki pages. However, some are part of the [Dataflow Graph API](${doc_files_1.FlowrWikiBaseRef}/Dataflow
|
|
995
|
+
Some of these functions have been explained in their respective wiki pages. However, some are part of the [Dataflow Graph API](${doc_files_1.FlowrWikiBaseRef}/Dataflow-Graph) and so we explain them here.
|
|
996
|
+
If you are interested in which features we support and which features are still to be worked on, please refer to our [capabilities](${doc_files_1.FlowrWikiBaseRef}/Capabilities) page.
|
|
994
997
|
|
|
995
998
|
${(0, doc_structure_1.section)('Resolving Values', 3, 'dfg-resolving-values')}
|
|
996
999
|
|
|
@@ -999,6 +1002,12 @@ These capabilities are exposed by the [resolve value Query](${doc_files_1.FlowrW
|
|
|
999
1002
|
|
|
1000
1003
|
${(0, doc_types_1.shortLink)(alias_tracking_1.resolveIdToValue.name, vertexType.info)} provides an environment-sensitive (see ${(0, doc_types_1.shortLink)('REnvironmentInformation', vertexType.info)})
|
|
1001
1004
|
value resolution depending on if the environment is provided.
|
|
1005
|
+
The idea of ${(0, doc_types_1.shortLink)(alias_tracking_1.resolveIdToValue.name, vertexType.info)} is to provide a compromise between precision and performance, to
|
|
1006
|
+
be used _during_ and _after_ the core analysis. After the dataflow analysis completes, there are much more expensive queries possible (such as the resolution of the data frame shape, see the [Query API](${doc_files_1.FlowrWikiBaseRef}/Query-API)).
|
|
1007
|
+
|
|
1008
|
+
Additionally, to ${(0, doc_types_1.shortLink)(alias_tracking_1.resolveIdToValue.name, vertexType.info)}, we offer the aforementioned ${(0, doc_types_1.shortLink)(identify_link_to_last_call_relation_1.getValueOfArgument.name, vertexType.info)} to retrieve the value of an argument in a function call.
|
|
1009
|
+
Be aware, that this function is currently not optimized for speed, so if you frequently require the values of multiple arguments of the same function call, you may want to open [an issue](${doc_issue_1.NewIssueUrl}) to request support for resolving
|
|
1010
|
+
multiple arguments at once.
|
|
1002
1011
|
|
|
1003
1012
|
${(0, doc_structure_1.section)('Assessing Edges', 3, 'dfg-assess-edge')}
|
|
1004
1013
|
|
|
@@ -1035,7 +1044,7 @@ ${(0, doc_types_1.printHierarchy)({ program: vertexType.program, info: vertexTyp
|
|
|
1035
1044
|
|
|
1036
1045
|
Their respective uses are documented alongside their implementation:
|
|
1037
1046
|
|
|
1038
|
-
${['SimpleOrigin', 'FunctionCallOrigin', 'BuiltInFunctionOrigin'].sort().map(key => `- ${(0, doc_types_1.shortLink)(
|
|
1047
|
+
${['SimpleOrigin', 'FunctionCallOrigin', 'BuiltInFunctionOrigin'].sort().map(key => `- ${(0, doc_types_1.shortLink)(key, vertexType.info)}\\\n${(0, doc_types_1.getDocumentationForType)(key, vertexType.info, '', { type: 'interface' })}`).join('\n')}
|
|
1039
1048
|
|
|
1040
1049
|
Please note, the current structure of this function is biased by what implementations already exist in flowR.
|
|
1041
1050
|
Hence, we do not just track definitions and constants, but also the origins of function calls, albeit we do not yet track the origins of values (only resorting to
|
|
@@ -15,6 +15,11 @@ ${qAndA('What are test labels and how do they work?', `
|
|
|
15
15
|
Tests are labeled based on the *flowR* capabilities that they test for. The list of supported capabilities can be found on the [Capabilities](${doc_files_1.FlowrWikiBaseRef}/Capabilities) wiki page. For more extensive information on test labels, see the [test labels wiki section](${doc_files_1.FlowrWikiBaseRef}/Linting-and-Testing#test-labels).
|
|
16
16
|
`)}
|
|
17
17
|
|
|
18
|
+
${qAndA('How to get a REPL with debug-info/hot-reload?', `
|
|
19
|
+
To enter the development repl, execute \`npm run main-dev\` in contrast to \`npm run flowr\` this will use an unminified build (keeping debug info)
|
|
20
|
+
and will also watch the source files for changes and automatically recompile them. Please note, that this may have negative performance implications.
|
|
21
|
+
`)}
|
|
22
|
+
|
|
18
23
|
${qAndA('How do I generate mermaid diagrams?', `
|
|
19
24
|
There are several ways to generate mermaid diagrams based on the input data that you want to use.
|
|
20
25
|
- From the AST (abstract syntax tree): ${(0, doc_files_1.getFilePathMd)('../util/mermaid/ast.ts')}
|
|
@@ -116,6 +116,8 @@ which is interpreted as an R expression by default but interpreted as a *co
|
|
|
116
116
|
The best command to get started with the REPL is ${(0, doc_cli_option_1.getReplCommand)('help')}.
|
|
117
117
|
Besides, you can leave the REPL either with the command ${(0, doc_cli_option_1.getReplCommand)('quit')} or by pressing <kbd>CTRL</kbd>+<kbd>C</kbd> twice.
|
|
118
118
|
|
|
119
|
+
> [!NOTE]
|
|
120
|
+
> If you develop flowR, you may want to launch the repl using the \`npm run main-dev\` command, this way, you get a non-minified version of flowR with debug information and hot-reloading of source files.
|
|
119
121
|
|
|
120
122
|
<details>
|
|
121
123
|
<summary>Available Commands</summary>
|
|
@@ -28,7 +28,7 @@ const SpecialTagColors = {
|
|
|
28
28
|
[linter_tags_1.LintingRuleTag.QuickFix]: 'lightgray'
|
|
29
29
|
};
|
|
30
30
|
function makeTagBadge(name, info) {
|
|
31
|
-
const doc = (0, doc_types_1.getDocumentationForType)('LintingRuleTag::' + name, info, '', true).replaceAll('\n', ' ');
|
|
31
|
+
const doc = (0, doc_types_1.getDocumentationForType)('LintingRuleTag::' + name, info, '', { fuzzy: true }).replaceAll('\n', ' ');
|
|
32
32
|
return (0, html_hover_over_1.textWithTooltip)(`<a href='#${name}'> + `-${SpecialTagColors[name] ?? 'teal'}) </a>`, doc);
|
|
33
33
|
}
|
|
34
34
|
function prettyPrintExpectedOutput(expected) {
|
|
@@ -66,7 +66,6 @@ These examples are synthesized from the test cases in: ${(0, doc_files_1.linkFlo
|
|
|
66
66
|
}
|
|
67
67
|
const testName = args[0].getText(report.source);
|
|
68
68
|
if (report.comments?.some(c => c.includes('@ignore-in-wiki'))) {
|
|
69
|
-
console.warn(`Skipping test case for linter rule ${testName} (${testFile}) as it is marked with @ignore-in-wiki`);
|
|
70
69
|
continue;
|
|
71
70
|
}
|
|
72
71
|
// drop any quotes around the test name
|
|
@@ -133,7 +132,7 @@ df[6, "value"]
|
|
|
133
132
|
}
|
|
134
133
|
return a.localeCompare(b);
|
|
135
134
|
}).map(t => makeTagBadge(t, types)).join(' ');
|
|
136
|
-
const certaintyDoc = (0, doc_types_1.getDocumentationForType)(`LintingRuleCertainty::${rule.info.certainty}`, types, '', true).replaceAll('\n', ' ');
|
|
135
|
+
const certaintyDoc = (0, doc_types_1.getDocumentationForType)(`LintingRuleCertainty::${rule.info.certainty}`, types, '', { fuzzy: true }).replaceAll('\n', ' ');
|
|
137
136
|
const certaintyText = `\`${(0, html_hover_over_1.textWithTooltip)(rule.info.certainty, certaintyDoc)}\``;
|
|
138
137
|
if (format === 'short') {
|
|
139
138
|
ruleExplanations.set(name, () => Promise.resolve(`
|
|
@@ -201,6 +201,10 @@ To get started, install the [vitest Extension](https://marketplace.visualstudio.
|
|
|
201
201
|
#### Webstorm
|
|
202
202
|
|
|
203
203
|
Please follow the official guide [here](https://www.jetbrains.com/help/webstorm/vitest.html).
|
|
204
|
+
Note that the working directory has to be set to the project root directory, not the test subdirectory!
|
|
205
|
+
Otherwise, the tests will not be instantiated.
|
|
206
|
+
|
|
207
|
+

|
|
204
208
|
|
|
205
209
|
<a id='ci-pipeline'></a>
|
|
206
210
|
## 🪈 CI Pipeline
|