@eagleoutice/flowr 2.1.8 → 2.1.10

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.
Files changed (85) hide show
  1. package/README.md +3 -0
  2. package/benchmark/summarizer/first-phase/process.js +6 -5
  3. package/cli/repl/commands/repl-dataflow.js +5 -2
  4. package/cli/repl/commands/repl-normalize.js +5 -2
  5. package/cli/repl/commands/repl-query.js +2 -2
  6. package/cli/repl/server/messages/message-query.js +1 -1
  7. package/config.d.ts +21 -0
  8. package/config.js +19 -2
  9. package/dataflow/environments/built-in.d.ts +2 -0
  10. package/dataflow/environments/built-in.js +2 -0
  11. package/dataflow/environments/default-builtin-config.js +48 -8
  12. package/dataflow/environments/define.js +78 -0
  13. package/dataflow/environments/environment.d.ts +46 -8
  14. package/dataflow/environments/environment.js +24 -1
  15. package/dataflow/environments/identifier.d.ts +60 -10
  16. package/dataflow/environments/identifier.js +11 -2
  17. package/dataflow/environments/resolve-by-name.d.ts +10 -5
  18. package/dataflow/environments/resolve-by-name.js +103 -5
  19. package/dataflow/extractor.js +5 -4
  20. package/dataflow/graph/dataflowgraph-builder.d.ts +6 -0
  21. package/dataflow/graph/dataflowgraph-builder.js +8 -0
  22. package/dataflow/graph/edge.d.ts +10 -4
  23. package/dataflow/graph/edge.js +12 -5
  24. package/dataflow/graph/graph.d.ts +41 -3
  25. package/dataflow/graph/graph.js +39 -34
  26. package/dataflow/graph/vertex.d.ts +122 -8
  27. package/dataflow/graph/vertex.js +19 -0
  28. package/dataflow/info.d.ts +79 -11
  29. package/dataflow/info.js +20 -0
  30. package/dataflow/internal/linker.d.ts +4 -2
  31. package/dataflow/internal/linker.js +12 -5
  32. package/dataflow/internal/process/functions/call/built-in/built-in-access.d.ts +11 -0
  33. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +141 -49
  34. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.d.ts +8 -3
  35. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +40 -11
  36. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.d.ts +16 -0
  37. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +83 -6
  38. package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +3 -3
  39. package/dataflow/internal/process/functions/call/built-in/built-in-list.d.ts +15 -0
  40. package/dataflow/internal/process/functions/call/built-in/built-in-list.js +50 -0
  41. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.d.ts +1 -1
  42. package/dataflow/internal/process/functions/call/built-in/built-in-replacement.js +29 -1
  43. package/dataflow/internal/process/functions/call/common.js +16 -2
  44. package/dataflow/internal/process/functions/call/known-call-handling.d.ts +2 -1
  45. package/dataflow/internal/process/functions/call/known-call-handling.js +3 -2
  46. package/documentation/doc-util/doc-dfg.d.ts +0 -1
  47. package/documentation/doc-util/doc-dfg.js +1 -14
  48. package/documentation/print-capabilities-markdown.js +1 -1
  49. package/documentation/print-dataflow-graph-wiki.js +26 -7
  50. package/documentation/print-interface-wiki.js +6 -1
  51. package/documentation/print-linting-and-testing-wiki.js +60 -26
  52. package/documentation/print-query-wiki.js +1 -1
  53. package/package.json +17 -3
  54. package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
  55. package/queries/catalog/call-context-query/call-context-query-format.d.ts +13 -0
  56. package/queries/catalog/call-context-query/call-context-query-format.js +3 -1
  57. package/queries/catalog/call-context-query/cascade-action.d.ts +8 -0
  58. package/queries/catalog/call-context-query/cascade-action.js +13 -0
  59. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +11 -1
  60. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +41 -4
  61. package/queries/catalog/dependencies-query/dependencies-query-format.js +4 -0
  62. package/queries/query.d.ts +4 -4
  63. package/queries/query.js +17 -5
  64. package/r-bridge/lang-4.x/ast/model/model.d.ts +3 -0
  65. package/r-bridge/lang-4.x/ast/model/nodes/r-number.d.ts +5 -1
  66. package/r-bridge/lang-4.x/ast/model/processing/node-id.d.ts +6 -1
  67. package/r-bridge/lang-4.x/ast/model/processing/node-id.js +6 -1
  68. package/slicing/static/slice-call.d.ts +7 -2
  69. package/slicing/static/slice-call.js +33 -44
  70. package/slicing/static/static-slicer.d.ts +5 -1
  71. package/slicing/static/static-slicer.js +22 -8
  72. package/slicing/static/visiting-queue.d.ts +4 -4
  73. package/slicing/static/visiting-queue.js +5 -3
  74. package/statistics/output/print-stats.js +2 -1
  75. package/statistics/summarizer/post-process/histogram.js +2 -1
  76. package/statistics/summarizer/post-process/post-process-output.js +2 -1
  77. package/statistics/summarizer/second-phase/process.js +3 -3
  78. package/util/arrays.d.ts +1 -1
  79. package/util/arrays.js +3 -3
  80. package/util/cfg/cfg.js +4 -2
  81. package/util/list-access.d.ts +48 -0
  82. package/util/list-access.js +115 -0
  83. package/util/mermaid/cfg.js +1 -1
  84. package/util/summarizer.js +2 -2
  85. package/util/version.js +1 -1
@@ -35,7 +35,7 @@ function forceVertexArgumentValueReferences(rootId, value, graph, env) {
35
35
  // try to resolve them against the current environment
36
36
  for (const ref of [...value.in, ...containedSubflowIn.flatMap(n => n.subflow.in)]) {
37
37
  if (ref.name) {
38
- const resolved = (0, resolve_by_name_1.resolveByName)(ref.name, env, ref.type) ?? [];
38
+ const resolved = ref.name ? (0, resolve_by_name_1.resolveByName)(ref.name, env, ref.type) ?? [] : [];
39
39
  for (const resolve of resolved) {
40
40
  graph.addEdge(ref.nodeId, resolve.nodeId, edge_1.EdgeType.Reads);
41
41
  }
@@ -77,7 +77,12 @@ function processAllArguments({ functionName, args, data, finalGraph, functionRoo
77
77
  if ((0, info_1.happensInEveryBranch)(resolved.controlDependencies)) {
78
78
  assumeItMayHaveAHigherTarget = false;
79
79
  }
80
- finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, edge_1.EdgeType.Reads);
80
+ // When only a single index is referenced, we don't need to reference the whole object
81
+ const resolvedInGraphDef = resolved;
82
+ const isContainer = checkForContainer(resolvedInGraphDef?.indicesCollection);
83
+ if (isContainer || isContainer === undefined) {
84
+ finalGraph.addEdge(ingoing.nodeId, resolved.nodeId, edge_1.EdgeType.Reads);
85
+ }
81
86
  }
82
87
  if (assumeItMayHaveAHigherTarget) {
83
88
  remainingReadInArgs.push(ingoing);
@@ -113,4 +118,13 @@ function patchFunctionCall({ nextGraph, rootId, name, data, argumentProcessResul
113
118
  }
114
119
  }
115
120
  }
121
+ /**
122
+ * Check whether passed {@link indices} are containers or whether their sub-indices are containers.
123
+ */
124
+ function checkForContainer(indices) {
125
+ return indices?.every((indices) => {
126
+ const areSubIndicesContainers = indices.indices.every(index => 'subIndices' in index && checkForContainer(index.subIndices));
127
+ return indices.isContainer || areSubIndicesContainers;
128
+ });
129
+ }
116
130
  //# sourceMappingURL=common.js.map
@@ -8,6 +8,7 @@ import type { NodeId } from '../../../../../r-bridge/lang-4.x/ast/model/processi
8
8
  import type { RNode } from '../../../../../r-bridge/lang-4.x/ast/model/model';
9
9
  import type { IdentifierReference } from '../../../../environments/identifier';
10
10
  import { DataflowGraph } from '../../../../graph/graph';
11
+ import type { ContainerIndicesCollection } from '../../../../graph/vertex';
11
12
  export interface ProcessKnownFunctionCallInput<OtherInfo> extends ForceArguments {
12
13
  readonly name: RSymbol<OtherInfo & ParentInformation>;
13
14
  readonly args: readonly (RNode<OtherInfo & ParentInformation> | RFunctionArgument<OtherInfo & ParentInformation>)[];
@@ -28,4 +29,4 @@ export interface ProcessKnownFunctionCallResult {
28
29
  readonly fnRef: IdentifierReference;
29
30
  }
30
31
  export declare function markNonStandardEvaluationEdges(markAsNSE: readonly number[], callArgs: readonly (DataflowInformation | undefined)[], finalGraph: DataflowGraph, rootId: NodeId): void;
31
- export declare function processKnownFunctionCall<OtherInfo>({ name, args, rootId, data, reverseOrder, markAsNSE, forceArgs, patchData, hasUnknownSideEffect }: ProcessKnownFunctionCallInput<OtherInfo>): ProcessKnownFunctionCallResult;
32
+ export declare function processKnownFunctionCall<OtherInfo>({ name, args, rootId, data, reverseOrder, markAsNSE, forceArgs, patchData, hasUnknownSideEffect }: ProcessKnownFunctionCallInput<OtherInfo>, indicesCollection?: ContainerIndicesCollection): ProcessKnownFunctionCallResult;
@@ -23,7 +23,7 @@ function markNonStandardEvaluationEdges(markAsNSE, callArgs, finalGraph, rootId)
23
23
  }
24
24
  }
25
25
  }
26
- function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect }) {
26
+ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = false, markAsNSE = undefined, forceArgs, patchData = d => d, hasUnknownSideEffect }, indicesCollection = undefined) {
27
27
  const functionName = (0, processor_1.processDataflowFor)(name, data);
28
28
  const finalGraph = new graph_1.DataflowGraph(data.completeAst.idMap);
29
29
  const functionCallName = name.content;
@@ -41,7 +41,8 @@ function processKnownFunctionCall({ name, args, rootId, data, reverseOrder = fal
41
41
  /* will be overwritten accordingly */
42
42
  onlyBuiltin: false,
43
43
  controlDependencies: data.controlDependencies,
44
- args: reverseOrder ? [...callArgs].reverse() : callArgs
44
+ args: reverseOrder ? [...callArgs].reverse() : callArgs,
45
+ indicesCollection: indicesCollection,
45
46
  });
46
47
  if (hasUnknownSideEffect) {
47
48
  finalGraph.markIdForUnknownSideEffects(rootId);
@@ -10,7 +10,6 @@ export interface PrintDataflowGraphOptions {
10
10
  readonly codeOpen?: boolean;
11
11
  readonly exposeResult?: boolean;
12
12
  readonly switchCodeAndGraph?: boolean;
13
- readonly hideEnvInMermaid?: boolean;
14
13
  }
15
14
  export declare function formatSideEffect(ef: UnknownSidEffect): string;
16
15
  export declare function printDfGraphForCode(shell: RShell, code: string, options: PrintDataflowGraphOptions & {
@@ -32,7 +32,7 @@ function formatSideEffect(ef) {
32
32
  return `${ef}`;
33
33
  }
34
34
  }
35
- async function printDfGraphForCode(shell, code, { mark, showCode = true, codeOpen = false, exposeResult, switchCodeAndGraph = false, hideEnvInMermaid = false } = {}) {
35
+ async function printDfGraphForCode(shell, code, { mark, showCode = true, codeOpen = false, exposeResult, switchCodeAndGraph = false } = {}) {
36
36
  const now = performance.now();
37
37
  const result = await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
38
38
  shell,
@@ -60,19 +60,6 @@ We encountered ${result.dataflow.graph.unknownSideEffects.size > 0 ? 'unknown si
60
60
 
61
61
  ${switchCodeAndGraph ? dfGraph : codeText}
62
62
 
63
- <details>
64
-
65
- <summary style="color:gray">Mermaid Code ${(mark?.size ?? 0) > 0 ? '(without markings)' : ''}</summary>
66
-
67
- \`\`\`
68
- ${(0, dfg_1.graphToMermaid)({
69
- graph: result.dataflow.graph,
70
- prefix: 'flowchart LR',
71
- includeEnvironments: !hideEnvInMermaid
72
- }).string}
73
- \`\`\`
74
-
75
- </details>
76
63
 
77
64
  </details>
78
65
 
@@ -39,7 +39,7 @@ function printAsMarkdown(capabilities, depth = 0, lines = []) {
39
39
  function getPreamble() {
40
40
  const currentDateAndTime = new Date().toISOString().replace('T', ', ').replace(/\.\d+Z$/, ' UTC');
41
41
  const shortenFilename = module.filename.replace(/^.*src\//, 'src/');
42
- return `_This document was generated from '${shortenFilename}' on ${currentDateAndTime} summarizig flowR's current capabilities (v${(0, version_1.flowrVersion)().format()})._
42
+ return `_This document was generated from '${shortenFilename}' on ${currentDateAndTime} summarizing flowR's current capabilities (v${(0, version_1.flowrVersion)().format()})._
43
43
 
44
44
  The code-font behind each capability name is a link to the capability's id. This id can be used to reference the capability in a labeled test within flowR.
45
45
  Besides, we use colored bullets like this:
@@ -561,26 +561,45 @@ However, nested definitions can carry it (in the nested case, \`x\` is defined b
561
561
  code: 'foo <- function() x\nfoo()',
562
562
  expectedSubgraph: (0, dataflowgraph_builder_1.emptyGraph)().returns('2@foo', '1@x')
563
563
  }, []]);
564
+ const lateBindingExample = `
565
+ f <- function() x
566
+ x <- 3
567
+ f()
568
+ `.trim();
569
+ const dfInfo = await (0, doc_dfg_1.printDfGraphForCode)(shell, lateBindingExample, { switchCodeAndGraph: true, codeOpen: true, mark: new Set([1, '1->5', '9->5']) });
564
570
  edgeExplanations.set(edge_1.EdgeType.DefinesOnCall, [{
565
571
  shell: shell,
566
572
  name: 'DefinesOnCall Edge',
567
573
  type: edge_1.EdgeType.DefinesOnCall,
568
- description: `**This edge is automatically joined with ${linkEdgeName(edge_1.EdgeType.DefinedByOnCall)}!**
574
+ description: `*This edge is usually joined with ${linkEdgeName(edge_1.EdgeType.DefinedByOnCall)}!*
569
575
 
570
- Link an Argument to whichever parameter they cause to be defined if the related function call is invoked.`,
576
+ Links an Argument to whichever parameter they cause to be defined if the related function call is invoked.
577
+
578
+ In the context of functions which access their closure environment these edges play another tricky role as there are many cases
579
+ made more difficult by R's way of allowing closure environments to later receive variables.
580
+ Consider the following scenario in which we first define a function which returns the value of a variable named \`x\` and then define \`x\`
581
+ only after we defined the function:
582
+
583
+ ${dfInfo}
584
+
585
+ The final call evaluates to \`3\` (similar to if we would have defined \`x\` before the function definition).
586
+ Within a dataflow graph you can see this with two edges. The \`x\` within the function body will have a ${linkEdgeName(edge_1.EdgeType.DefinedByOnCall)}
587
+ to every definition it _may_ refer to. In turn, each call vertex calling the function which encloses the use of \`x\` will have a
588
+ ${linkEdgeName(edge_1.EdgeType.DefinesOnCall)} edge to the definition(s) it causes to be active within the function body.
589
+ `,
571
590
  code: 'f <- function(x) {}\nf(x=1)',
572
591
  // here we use the ids as the argument wrappers are not easily selected with slicing criteria
573
- expectedSubgraph: (0, dataflowgraph_builder_1.emptyGraph)().definesOnCall('$11', '$1')
592
+ expectedSubgraph: (0, dataflowgraph_builder_1.emptyGraph)().definesOnCall('$11', '$1').definedByOnCall('$1', '$11')
574
593
  }, []]);
575
594
  edgeExplanations.set(edge_1.EdgeType.DefinedByOnCall, [{
576
595
  shell: shell,
577
596
  name: 'DefinedByOnCall Edge',
578
597
  type: edge_1.EdgeType.DefinedByOnCall,
579
- description: `**This edge is automatically joined with ${linkEdgeName(edge_1.EdgeType.DefinesOnCall)}!**
598
+ description: `*This edge is usually joined with ${linkEdgeName(edge_1.EdgeType.DefinesOnCall)}!*
580
599
 
581
- This represents the other direction of ${linkEdgeName(edge_1.EdgeType.DefinesOnCall)} (i.e., links the parameter to the argument). This is just for completeness.`,
600
+ This represents the other part of the ${linkEdgeName(edge_1.EdgeType.DefinesOnCall)} edge (e.g., links the parameter to the argument). Please look there for further documentation.`,
582
601
  code: 'f <- function(x) {}\nf(x=1)',
583
- expectedSubgraph: (0, dataflowgraph_builder_1.emptyGraph)().definesOnCall('$11', '$1')
602
+ expectedSubgraph: (0, dataflowgraph_builder_1.emptyGraph)().definesOnCall('$11', '$1').definedByOnCall('$1', '$11')
584
603
  }, []]);
585
604
  edgeExplanations.set(edge_1.EdgeType.Argument, [{
586
605
  shell: shell,
@@ -611,7 +630,7 @@ Marks cases in which R's non-standard evaluation mechanisms cause the default se
611
630
  ${(0, doc_structure_1.block)({
612
631
  type: 'NOTE',
613
632
  content: `
614
- What to do if you encounter this vertex?
633
+ What to do if you encounter a vertex marked with this edge?
615
634
 
616
635
  This depends on your analysis. To handle many real-world sources correctly you are probably fine with just ignoring it.
617
636
  Yet, you may choose to follow these references for other queries. For now, _flowR's_ support for non-standard evaluation is limited.
@@ -171,6 +171,7 @@ The following summarizes the configuration options:
171
171
  - \`semantics\`: allows to configure the way _flowR_ handles R, although we currently only support \`semantics/environment/overwriteBuiltIns\`.
172
172
  You may use this to overwrite _flowR_'s handling of built-in function and even completely clear the preset definitions shipped with flowR.
173
173
  See [Configure BuiltIn Semantics](#configure-builtin-semantics) for more information.
174
+ - \`solver\`: allows to configure how _flowR_ resolves variables and their values (currently we support: ${Object.values(config_1.VariableResolve).map(v => `\`${v}\``).join(', ')}), as well as if pointer analysis should be active.
174
175
 
175
176
  So you can configure _flowR_ by adding a file like the following:
176
177
 
@@ -189,6 +190,10 @@ ${(0, doc_code_1.codeBlock)('json', JSON.stringify({
189
190
  ]
190
191
  }
191
192
  }
193
+ },
194
+ solver: {
195
+ variables: config_1.VariableResolve.Alias,
196
+ pointerTracking: true
192
197
  }
193
198
  }, null, 2))}
194
199
 
@@ -233,7 +238,7 @@ _flowR_ can be used as a [module](${doc_files_1.FlowrNpmRef}) and offers several
233
238
  ### Using the \`${shell_1.RShell.name}\` to Interact with R
234
239
 
235
240
  The \`${shell_1.RShell.name}\` class allows to interface with the \`R\`&nbsp;ecosystem installed on the host system.
236
- For now there are no (real) alternatives, although we plan on providing more flexible drop-in replacements.
241
+ For now, there are no (real) alternatives, although we plan on providing more flexible drop-in replacements.
237
242
 
238
243
  > [!IMPORTANT]
239
244
  > Each \`${shell_1.RShell.name}\` controls a new instance of the R&nbsp;interpreter, make sure to call \`${shell_1.RShell.name}::${shell.close.name}()\` when you’re done.
@@ -3,9 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const log_1 = require("../../test/functionality/_helper/log");
4
4
  const doc_code_1 = require("./doc-util/doc-code");
5
5
  const doc_files_1 = require("./doc-util/doc-files");
6
+ const doc_structure_1 = require("./doc-util/doc-structure");
6
7
  function getText() {
7
8
  return `
8
- For the latest code-coverage information, see [codecov.io](${doc_files_1.FlowrCodecovRef}),
9
+ For the latest code coverage information, see [codecov.io](${doc_files_1.FlowrCodecovRef}),
9
10
  for the latest benchmark results, see the [benchmark results](${doc_files_1.FlowrSiteBaseRef}/wiki/stats/benchmark) wiki page.
10
11
 
11
12
  - [Testing Suites](#testing-suites)
@@ -13,32 +14,37 @@ for the latest benchmark results, see the [benchmark results](${doc_files_1.Flow
13
14
  - [Test Structure](#test-structure)
14
15
  - [Writing a Test](#writing-a-test)
15
16
  - [Running Only Some Tests](#running-only-some-tests)
17
+ - [System Tests](#system-tests)
16
18
  - [Performance Tests](#performance-tests)
17
19
  - [Oh no, the tests are slow](#oh-no-the-tests-are-slow)
18
20
  - [Testing Within Your IDE](#testing-within-your-ide)
19
- - [Using Visual Studio Code](#vs-code)
20
- - [Using WebStorm](#webstorm)
21
+ - [VS Code](#vs-code)
22
+ - [Webstorm](#webstorm)
21
23
  - [CI Pipeline](#ci-pipeline)
22
24
  - [Linting](#linting)
23
25
  - [Oh no, the linter fails](#oh-no-the-linter-fails)
24
26
  - [License Checker](#license-checker)
27
+ - [Debugging](#debugging)
28
+ - [VS Code](#vs-code-1)
25
29
 
26
30
  ## Testing Suites
27
31
 
28
- Currently, flowR contains two testing suites: one for [functionality](#functionality-tests) and one for [performance](#performance-tests). We explain each of them in the following.
29
- In addition to running those tests, you can use the more generalized \`npm run checkup\`. This will include the construction of the docker image, the generation of the wiki pages, and the linter.
32
+ Currently, flowR contains three testing suites: one for [functionality](#functionality-tests),
33
+ one for [system tests](#system-tests), and one for [performance](#performance-tests). We explain each of them in the following.
34
+ In addition to running those tests, you can use the more generalized \`npm run checkup\`.
35
+ This command includes the construction of the docker image, the generation of the wiki pages, and the linter.
30
36
 
31
37
  ### Functionality Tests
32
38
 
33
39
  The functionality tests represent conventional unit (and depending on your terminology component/api) tests.
34
40
  We use [vitest](https://vitest.dev/) as our testing framework.
35
- You can run the tests by issuing:
41
+ You can run the tests by issuing (some quick benchmarks may be available with \`vitest bench\`):
36
42
 
37
43
  ${(0, doc_code_1.codeBlock)('shell', 'npm run test')}
38
44
 
39
45
  Within the commandline,
40
- this should automatically drop you into a watch mode which will automatically re-run the tests if you change the code.
41
- If, at any time there are too many errors, you can use \`--bail=<value>\` to stop the tests after a certain number of errors.
46
+ this should automatically drop you into a watch mode which will automatically re-run (potentially) affected tests if you change the code.
47
+ If, at any time there are too many errors for you to comprehend, you can use \`--bail=<value>\` to stop the tests after a certain number of errors.
42
48
  For example:
43
49
 
44
50
  ${(0, doc_code_1.codeBlock)('shell', 'npm run test -- --bail=1')}
@@ -51,10 +57,10 @@ To run all tests, including a coverage report and label summary, run:
51
57
 
52
58
  ${(0, doc_code_1.codeBlock)('shell', 'npm run test-full')}
53
59
 
54
- However, depending on your local R version, your network connection and potentially other factors, some tests may be skipped automatically as they don't apply to your current system setup
55
- (or can't be tested with the current prerequisites).
60
+ However, depending on your local version of&nbsp;R, your network connection, and other factors (each test may have a set of criteria),
61
+ some tests may be skipped automatically as they do not apply to your current system setup (or cannot be tested with the current prerequisites).
56
62
  Each test can specify such requirements as part of the \`TestConfiguration\`, which is then used in the \`test.skipIf\` function of _vitest_.
57
- It is up to the [ci](#ci-pipeline) to run the tests on different systems to ensure that those tests are ensured to run.
63
+ It is up to the [ci](#ci-pipeline) to run the tests on different systems to ensure that those tests run.
58
64
 
59
65
  #### Test Structure
60
66
 
@@ -62,12 +68,18 @@ All functionality tests are to be located under [test/functionality](${doc_files
62
68
 
63
69
  This folder contains three special and important elements:
64
70
 
65
- - \`test-setup\` which is the entry point if *all* tests are run. It should automatically disable logging statements and configure global variables (e.g., if installation tests should run).
66
- - \`_helper\` which contains helper functions to be used by other tests.
67
- - \`test-summary\` which may produce a summary of the covered capabilities.
71
+ - \`test-setup.ts\` which is the entry point if *all* tests are run. It should automatically disable logging statements and configure global variables (e.g., if installation tests should run).
72
+ - \`_helper/\` folder which contains helper functions to be used by other tests.
73
+ - \`test-summary.ts\` which may produce a summary of the covered capabilities.
68
74
 
69
- We name all tests using the \`.test.ts\` suffix and try to run them in parallel.
70
- Whenever this is not possible (e.g., when using \`withShell\`), please use \`describe.sequential\` to disable parallel execution for the respective test.
75
+ ${(0, doc_structure_1.block)({
76
+ type: 'WARNING',
77
+ content: `
78
+ We name all test files using the \`.test.ts\` suffix and try to run them in parallel.
79
+ Whenever this is not possible (e.g., when using \`withShell\`), please use \`describe.sequential\`
80
+ to disable parallel execution for the respective test (otherwise, such tests are flaky).
81
+ `
82
+ })}
71
83
 
72
84
  #### Writing a Test
73
85
 
@@ -86,10 +98,11 @@ assertDataflow(label('simple variable', ['name-normal']), shell,
86
98
  `)}
87
99
 
88
100
  When writing dataflow tests, additional settings can be used to reduce the amount of graph data that needs to be pre-written. Notably:
101
+
89
102
  - \`expectIsSubgraph\` indicates that the expected graph is a subgraph, rather than the full graph that the test should generate. The test will then only check if the supplied graph is contained in the result graph, rather than an exact match.
90
103
  - \`resolveIdsAsCriterion\` indicates that the ids given in the expected (sub)graph should be resolved as [slicing criteria](${doc_files_1.FlowrWikiBaseRef}/Terminology#slicing-criterion) rather than actual ids. For example, passing \`12@a\` as an id in the expected (sub)graph will cause it to be resolved as the corresponding id.
91
104
 
92
- The following example shows both in use.
105
+ The following example shows both in use:
93
106
  ${(0, doc_code_1.codeBlock)('typescript', `
94
107
  assertDataflow(label('without distractors', [...OperatorDatabase['<-'].capabilities, 'numbers', 'name-normal', 'newlines', 'name-escaped']),
95
108
  shell, '\`a\` <- 2\\na',
@@ -108,10 +121,25 @@ assertDataflow(label('without distractors', [...OperatorDatabase['<-'].capabilit
108
121
  To run only some tests, vitest allows you to [filter](https://vitest.dev/guide/filtering.html) tests.
109
122
  Besides, you can use the watch mode (with \`npm run test\`) to only run tests that are affected by your changes.
110
123
 
124
+ ### System Tests
125
+
126
+ In contrast to the [functionality tests](#functionality-tests), the system tests use runners like the \`npm\` scripts
127
+ to test the behavior of the whole system, for example, by running the CLI or the server.
128
+ They are slower and hence not part of \`npm run test\` but can be run using:
129
+ ${(0, doc_code_1.codeBlock)('shell', 'npm run test:system')}
130
+ To work, they require you to set up your system correctly (e.g., have \`npm\` available on your path).
131
+ The CI environment will make sure of that. At the moment, these tests are not labeled and only intended
132
+ to check basic availability of *flowR*'s core features (as we test the functionality of these features dedicately
133
+ with the [functionality tests](#functionality-tests)).
134
+
135
+ Have a look at the [test/system-tests](${doc_files_1.RemoteFlowrFilePathBaseRef}test/system-tests) folder for more information.
136
+
137
+
138
+
111
139
  ### Performance Tests
112
140
 
113
141
  The performance test suite of *flowR* uses several suites to check for variations in the required times for certain steps.
114
- Although we measure wall time in the CI (which is subject to rather large variations), it should give a rough idea of the performance of *flowR*.
142
+ Although we measure wall time in the CI (which is subject to rather large variations), it should give a rough idea *flowR*'s performance.
115
143
  Furthermore, the respective scripts can be used locally as well.
116
144
  To run them, issue:
117
145
 
@@ -143,18 +171,18 @@ Please follow the official guide [here](https://www.jetbrains.com/help/webstorm/
143
171
 
144
172
  ## CI Pipeline
145
173
 
146
- We have several workflows defined in [.github/workflows](../.github/workflows/).
174
+ We have several workflows defined in [.github/workflows](${doc_files_1.RemoteFlowrFilePathBaseRef}/.github/workflows/).
147
175
  We explain the most important workflows in the following:
148
176
 
149
- - [qa.yaml](../.github/workflows/qa.yaml) is the main workflow that will run different steps depending on several factors. It is responsible for:
177
+ - [qa.yaml](${doc_files_1.RemoteFlowrFilePathBaseRef}/.github/workflows/qa.yaml) is the main workflow that will run different steps depending on several factors. It is responsible for:
150
178
  - running the [functionality](#functionality-tests) and [performance tests](#performance-tests)
151
179
  - uploading the results to the [benchmark page](${doc_files_1.FlowrSiteBaseRef}/wiki/stats/benchmark) for releases
152
180
  - running the [functionality tests](#functionality-tests) on different operating systems (Windows, macOS, Linux) and with different versions of R
153
181
  - reporting code coverage
154
182
  - running the [linter](#linting) and reporting its results
155
183
  - deploying the documentation to [GitHub Pages](${doc_files_1.FlowrSiteBaseRef}/doc/)
156
- - [release.yaml](../.github/workflows/release.yaml) is responsible for creating a new release, only to be run by repository owners. Furthermore, it adds the new docker image to [docker hub](${doc_files_1.FlowrDockerRef}).
157
- - [broken-links-and-wiki.yaml](../.github/workflows/broken-links-and-wiki.yaml) repeatedly tests that all links are not dead!
184
+ - [release.yaml](${doc_files_1.RemoteFlowrFilePathBaseRef}/.github/workflows/release.yaml) is responsible for creating a new release, only to be run by repository owners. Furthermore, it adds the new docker image to [docker hub](${doc_files_1.FlowrDockerRef}).
185
+ - [broken-links-and-wiki.yaml](${doc_files_1.RemoteFlowrFilePathBaseRef}/.github/workflows/broken-links-and-wiki.yaml) repeatedly tests that all links are not dead!
158
186
 
159
187
  ## Linting
160
188
 
@@ -163,11 +191,11 @@ The main one:
163
191
 
164
192
  ${(0, doc_code_1.codeBlock)('shell', 'npm run lint')}
165
193
 
166
- And a weaker version of the first (allowing for *todo* comments) which is run automatically in the [pre-push githook](../.githooks/pre-push) as explained in the [CONTRIBUTING.md](../.github/CONTRIBUTING.md):
194
+ And a weaker version of the first (allowing for *todo* comments) which is run automatically in the [pre-push githook](${doc_files_1.RemoteFlowrFilePathBaseRef}/.githooks/pre-push) as explained in the [CONTRIBUTING.md](${doc_files_1.RemoteFlowrFilePathBaseRef}/.github/CONTRIBUTING.md):
167
195
 
168
196
  ${(0, doc_code_1.codeBlock)('shell', 'npm run lint-local')}
169
197
 
170
- Besides checking coding style (as defined in the [package.json](../package.json)), the *full* linter runs the [license checker](#license-checker).
198
+ Besides checking coding style (as defined in the [package.json](${doc_files_1.RemoteFlowrFilePathBaseRef}/package.json)), the *full* linter runs the [license checker](#license-checker).
171
199
 
172
200
  In case you are unaware,
173
201
  eslint can automatically fix several linting problems[](https://eslint.org/docs/latest/use/command-line-interface#fix-problems).
@@ -178,14 +206,20 @@ ${(0, doc_code_1.codeBlock)('shell', 'npm run lint-local -- --fix')}
178
206
  ### Oh no, the linter fails
179
207
 
180
208
  By now, the rules should be rather stable and so, if the linter fails,
181
- it is usually best if you (if necessary) read the respective description and fix the respective problem.
209
+ it is usually best if you (when necessary) read the respective description and fix the respective problem.
182
210
  Rules in this project cover general JavaScript issues [using regular ESLint](https://eslint.org/docs/latest/rules), TypeScript-specific issues [using typescript-eslint](https://typescript-eslint.io/rules/), and code formatting [with ESLint Stylistic](https://eslint.style/packages/default#rules).
183
211
 
184
212
  However, in case you think that the linter is wrong, please do not hesitate to open a [new issue](${doc_files_1.FlowrGithubBaseRef}/flowr/issues/new/choose).
185
213
 
186
214
  ### License Checker
187
215
 
188
- *flowR* is licensed under the [GPLv3 License](${doc_files_1.FlowrGithubBaseRef}/flowr/blob/main/LICENSE) requiring us to only rely on [compatible licenses](https://www.gnu.org/licenses/license-list.en.html). For now, this list is hardcoded as part of the npm [\`license-compat\`](../package.json) script so it can very well be that a new dependency you add causes the checker to fail &mdash; *even though it is compatible*. In that case, please either open a [new issue](${doc_files_1.FlowrGithubBaseRef}/flowr/issues/new/choose) or directly add the license to the list (including a reference to why it is compatible).
216
+ *flowR* is licensed under the [GPLv3 License](${doc_files_1.FlowrGithubBaseRef}/flowr/blob/main/LICENSE) requiring us to only rely on [compatible licenses](https://www.gnu.org/licenses/license-list.en.html). For now, this list is hardcoded as part of the npm [\`license-compat\`](${doc_files_1.RemoteFlowrFilePathBaseRef}/package.json) script so it can very well be that a new dependency you add causes the checker to fail &mdash; *even though it is compatible*. In that case, please either open a [new issue](${doc_files_1.FlowrGithubBaseRef}/flowr/issues/new/choose) or directly add the license to the list (including a reference to why it is compatible).
217
+
218
+
219
+ ## Debugging
220
+ ### VS Code
221
+ When working with VS Code, you can attach a debugger to the REPL. This works automatically by running the \`Start Debugging\` command (\`F5\` by default).
222
+ You can also set the \`Auto Attach Filter\` setting to automatically attach the debugger, when running \`npm run flowr\`.
189
223
  `;
190
224
  }
191
225
  if (require.main === module) {
@@ -418,7 +418,7 @@ ${(0, doc_query_1.tocForQueryType)('virtual')}
418
418
 
419
419
  Although it is probably better to consult the detailed explanations below, if you want to have a look at the scehma, here is its description:
420
420
 
421
- ${(0, schema_1.describeSchema)(query_1.QueriesSchema, ansi_1.markdownFormatter)}
421
+ ${(0, schema_1.describeSchema)((0, query_1.QueriesSchema)(), ansi_1.markdownFormatter)}
422
422
 
423
423
  </details>
424
424
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.1.8",
3
+ "version": "2.1.10",
4
4
  "description": "Static Dataflow Analyzer and Program Slicer for the R Programming Language",
5
5
  "types": "dist/src/index.d.ts",
6
6
  "repository": {
@@ -36,12 +36,13 @@
36
36
  "lint": "npm run license-compat -- --summary && npx eslint --version && npx eslint src/ test/",
37
37
  "license-compat": "license-checker --onlyAllow 'MIT;MIT OR X11;GPLv2;LGPL;GNUGPL;ISC;Apache-2.0;FreeBSD;BSD-2-Clause;clearbsd;ModifiedBSD;BSD-3-Clause;Python-2.0;Unlicense;WTFPL;BlueOak-1.0.0;CC-BY-4.0;CC-BY-3.0;CC0-1.0;0BSD'",
38
38
  "doc": "typedoc",
39
- "test": "vitest --config test/vitest.config.mts",
39
+ "test": "vitest --exclude \"test/system-tests/**\" --config test/vitest.config.mts",
40
+ "test:system": "vitest --dir test/system-tests --config test/system-tests/vitest.config.mts",
40
41
  "test:coverage": "npm run test -- --coverage",
41
42
  "performance-test": "func() { cd test/performance/ && bash run-all-suites.sh $1 $2 $3; cd ../../; }; func",
42
43
  "test-full": "npm run test:coverage -- --no-watch -- --make-summary --test-installation",
43
44
  "detect-circular-deps": "npx madge --extensions ts,tsx --circular src/",
44
- "checkup": "npm run flowr -- --execute \":version\" && npm run lint && npm run test-full -- --allowOnly=false && docker build -t test-flowr -f scripts/Dockerfile . && npm run doc && npm-run-all wiki:*"
45
+ "checkup": "npm run flowr -- --execute \":version\" && npm run lint && npm run test-full -- --allowOnly=false && npm run test:system -- --no-watch && docker build -t test-flowr -f scripts/Dockerfile . && npm run doc && npm-run-all wiki:*"
45
46
  },
46
47
  "keywords": [
47
48
  "static code analysis",
@@ -84,6 +85,19 @@
84
85
  "**/node_modules/**/*",
85
86
  "**/index.ts"
86
87
  ],
88
+ "highlightLanguages": [
89
+ "bash",
90
+ "console",
91
+ "css",
92
+ "html",
93
+ "javascript",
94
+ "json",
95
+ "jsonc",
96
+ "json5",
97
+ "tsx",
98
+ "typescript",
99
+ "r"
100
+ ],
87
101
  "theme": "hierarchy",
88
102
  "out": "doc",
89
103
  "readme": "README.md",
@@ -209,7 +209,7 @@ function executeCallContextQueries({ graph, ast }, queries) {
209
209
  let linkedIds = undefined;
210
210
  if (cfg && isSubCallQuery(query)) {
211
211
  /* if we have a linkTo query, we have to find the last call */
212
- const lastCall = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(nodeId, cfg.graph, graph, query.linkTo.callName);
212
+ const lastCall = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(nodeId, cfg.graph, graph, query.linkTo);
213
213
  if (lastCall) {
214
214
  linkedIds = lastCall;
215
215
  }
@@ -6,6 +6,9 @@ import Joi from 'joi';
6
6
  import type { PipelineOutput } from '../../../core/steps/pipeline/pipeline';
7
7
  import type { DEFAULT_DATAFLOW_PIPELINE } from '../../../core/steps/pipeline/default-pipelines';
8
8
  import { CallTargets } from './identify-link-to-last-call-relation';
9
+ import type { DataflowGraph } from '../../../dataflow/graph/graph';
10
+ import type { DataflowGraphVertexInfo } from '../../../dataflow/graph/vertex';
11
+ import type { CascadeAction } from './cascade-action';
9
12
  export interface FileFilter<FilterType> {
10
13
  /**
11
14
  * Regex that a node's file attribute must match to be considered
@@ -52,6 +55,16 @@ interface LinkToLastCall<CallName extends RegExp | string = RegExp | string> ext
52
55
  readonly type: 'link-to-last-call';
53
56
  /** Regex regarding the function name of the last call. Similar to {@link DefaultCallContextQueryFormat#callName}, strings are interpreted as a `RegExp`. */
54
57
  readonly callName: CallName;
58
+ /**
59
+ * Should we ignore this (source) call?
60
+ * Currently, there is no well working serialization for this.
61
+ */
62
+ readonly ignoreIf?: (id: NodeId, graph: DataflowGraph) => boolean;
63
+ /**
64
+ * Should we continue searching after the link was created?
65
+ * Currently, there is no well working serialization for this.
66
+ */
67
+ readonly cascadeIf?: (target: DataflowGraphVertexInfo, from: NodeId, graph: DataflowGraph) => CascadeAction;
55
68
  }
56
69
  export type LinkTo<CallName extends RegExp | string> = LinkToLastCall<CallName>;
57
70
  export interface SubCallContextQueryFormat<CallName extends RegExp | string = RegExp | string> extends DefaultCallContextQueryFormat<CallName> {
@@ -32,7 +32,9 @@ exports.CallContextQueryDefinition = {
32
32
  }).optional().description('Filter that, when set, a node\'s file attribute must match to be considered'),
33
33
  linkTo: joi_1.default.object({
34
34
  type: joi_1.default.string().valid('link-to-last-call').required().description('The type of the linkTo sub-query.'),
35
- callName: joi_1.default.string().required().description('Regex regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression.')
35
+ callName: joi_1.default.string().required().description('Regex regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression.'),
36
+ ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
37
+ cascadeIf: joi_1.default.function().optional().description('Should we continue searching after the link was created? Currently, there is no well working serialization for this.')
36
38
  }).optional().description('Links the current call to the last call of the given kind. This way, you can link a call like `points` to the latest graphics plot etc.')
37
39
  }).description('Call context query used to find calls in the dataflow graph')
38
40
  };
@@ -0,0 +1,8 @@
1
+ export declare enum CascadeAction {
2
+ /** The action is to start the cascade */
3
+ Stop = "stop",
4
+ /** The action is to continue the cascade */
5
+ Continue = "continue",
6
+ /** The action is to skip the current node */
7
+ Skip = "skip"
8
+ }
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CascadeAction = void 0;
4
+ var CascadeAction;
5
+ (function (CascadeAction) {
6
+ /** The action is to start the cascade */
7
+ CascadeAction["Stop"] = "stop";
8
+ /** The action is to continue the cascade */
9
+ CascadeAction["Continue"] = "continue";
10
+ /** The action is to skip the current node */
11
+ CascadeAction["Skip"] = "skip";
12
+ })(CascadeAction || (exports.CascadeAction = CascadeAction = {}));
13
+ //# sourceMappingURL=cascade-action.js.map
@@ -1,6 +1,10 @@
1
1
  import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
2
2
  import type { ControlFlowGraph } from '../../../util/cfg/cfg';
3
3
  import type { DataflowGraph } from '../../../dataflow/graph/graph';
4
+ import type { DataflowGraphVertexFunctionCall } from '../../../dataflow/graph/vertex';
5
+ import { RType } from '../../../r-bridge/lang-4.x/ast/model/type';
6
+ import type { RNodeWithParent } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
7
+ import type { LinkTo } from './call-context-query-format';
4
8
  export declare enum CallTargets {
5
9
  /** call targets a function that is not defined locally (e.g., the call targets a library function) */
6
10
  OnlyGlobal = "global",
@@ -14,4 +18,10 @@ export declare enum CallTargets {
14
18
  Any = "any"
15
19
  }
16
20
  export declare function satisfiesCallTargets(id: NodeId, graph: DataflowGraph, callTarget: CallTargets): NodeId[] | 'no';
17
- export declare function identifyLinkToLastCallRelation(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, linkTo: RegExp): NodeId[];
21
+ export declare function getValueOfArgument<Types extends readonly RType[] = readonly RType[]>(graph: DataflowGraph, call: DataflowGraphVertexFunctionCall | undefined, argument: {
22
+ name?: string;
23
+ index: number;
24
+ }, additionalAllowedTypes?: Types): (RNodeWithParent & {
25
+ type: Types[number];
26
+ }) | undefined;
27
+ export declare function identifyLinkToLastCallRelation(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, { callName, ignoreIf, cascadeIf }: LinkTo<RegExp>): NodeId[];