@eagleoutice/flowr 2.2.13 → 2.2.14

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 (77) hide show
  1. package/README.md +4 -4
  2. package/cli/repl/commands/repl-cfg.d.ts +2 -2
  3. package/cli/repl/commands/repl-cfg.js +4 -4
  4. package/cli/repl/commands/repl-commands.js +2 -2
  5. package/cli/repl/server/connection.js +1 -1
  6. package/cli/script-core/statistics-helper-core.js +1 -1
  7. package/control-flow/extract-cfg.d.ts +2 -2
  8. package/control-flow/extract-cfg.js +10 -10
  9. package/documentation/doc-util/doc-cfg.d.ts +1 -1
  10. package/documentation/doc-util/doc-cfg.js +3 -3
  11. package/documentation/print-cfg-wiki.js +25 -25
  12. package/documentation/print-linter-wiki.d.ts +1 -0
  13. package/documentation/print-linter-wiki.js +76 -0
  14. package/linter/linter-executor.d.ts +9 -0
  15. package/linter/linter-executor.js +26 -0
  16. package/linter/linter-format.d.ts +65 -0
  17. package/linter/linter-format.js +9 -0
  18. package/linter/linter-rules.d.ts +42 -0
  19. package/linter/linter-rules.js +14 -0
  20. package/linter/rules/1-deprecated-functions.d.ts +34 -0
  21. package/linter/rules/1-deprecated-functions.js +54 -0
  22. package/linter/rules/2-file-path-validity.d.ts +48 -0
  23. package/linter/rules/2-file-path-validity.js +93 -0
  24. package/package.json +2 -1
  25. package/queries/catalog/call-context-query/call-context-query-executor.js +1 -1
  26. package/queries/catalog/call-context-query/call-context-query-format.d.ts +2 -2
  27. package/queries/catalog/call-context-query/call-context-query-format.js +5 -1
  28. package/queries/catalog/cluster-query/cluster-query-format.d.ts +2 -0
  29. package/queries/catalog/cluster-query/cluster-query-format.js +5 -1
  30. package/queries/catalog/config-query/config-query-format.d.ts +1 -0
  31. package/queries/catalog/config-query/config-query-format.js +2 -1
  32. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +1 -0
  33. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +2 -1
  34. package/queries/catalog/dataflow-query/dataflow-query-format.d.ts +2 -0
  35. package/queries/catalog/dataflow-query/dataflow-query-format.js +9 -1
  36. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +1 -0
  37. package/queries/catalog/dependencies-query/dependencies-query-format.js +10 -1
  38. package/queries/catalog/happens-before-query/happens-before-query-format.d.ts +1 -0
  39. package/queries/catalog/happens-before-query/happens-before-query-format.js +2 -1
  40. package/queries/catalog/id-map-query/id-map-query-format.d.ts +1 -0
  41. package/queries/catalog/id-map-query/id-map-query-format.js +2 -1
  42. package/queries/catalog/lineage-query/lineage-query-format.d.ts +1 -0
  43. package/queries/catalog/lineage-query/lineage-query-format.js +5 -1
  44. package/queries/catalog/linter-query/linter-query-executor.d.ts +3 -0
  45. package/queries/catalog/linter-query/linter-query-executor.js +28 -0
  46. package/queries/catalog/linter-query/linter-query-format.d.ts +80 -0
  47. package/queries/catalog/linter-query/linter-query-format.js +43 -0
  48. package/queries/catalog/location-map-query/location-map-query-format.d.ts +1 -0
  49. package/queries/catalog/location-map-query/location-map-query-format.js +2 -1
  50. package/queries/catalog/normalized-ast-query/normalized-ast-query-format.d.ts +1 -0
  51. package/queries/catalog/normalized-ast-query/normalized-ast-query-format.js +2 -1
  52. package/queries/catalog/origin-query/origin-query-format.d.ts +2 -0
  53. package/queries/catalog/origin-query/origin-query-format.js +5 -1
  54. package/queries/catalog/project-query/project-query-executor.js +1 -1
  55. package/queries/catalog/project-query/project-query-format.d.ts +1 -0
  56. package/queries/catalog/project-query/project-query-format.js +2 -1
  57. package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +1 -0
  58. package/queries/catalog/resolve-value-query/resolve-value-query-format.js +2 -1
  59. package/queries/catalog/search-query/search-query-format.d.ts +1 -0
  60. package/queries/catalog/search-query/search-query-format.js +5 -1
  61. package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +2 -0
  62. package/queries/catalog/static-slice-query/static-slice-query-format.js +9 -1
  63. package/queries/query.d.ts +83 -1
  64. package/queries/query.js +2 -0
  65. package/r-bridge/retriever.js +1 -1
  66. package/search/flowr-search-builder.d.ts +31 -2
  67. package/search/flowr-search-builder.js +30 -0
  68. package/search/flowr-search.d.ts +7 -1
  69. package/search/search-executor/search-enrichers.d.ts +73 -0
  70. package/search/search-executor/search-enrichers.js +98 -0
  71. package/search/search-executor/search-generators.d.ts +6 -1
  72. package/search/search-executor/search-generators.js +21 -1
  73. package/search/search-executor/search-mappers.d.ts +19 -0
  74. package/search/search-executor/search-mappers.js +21 -0
  75. package/search/search-executor/search-transformer.d.ts +12 -0
  76. package/search/search-executor/search-transformer.js +11 -1
  77. package/util/version.js +1 -1
package/README.md CHANGED
@@ -51,7 +51,7 @@ It offers a wide variety of features, for example:
51
51
 
52
52
  ```shell
53
53
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
54
- flowR repl using flowR v2.2.12, R v4.4.3 (r-shell engine)
54
+ flowR repl using flowR v2.2.13, R v4.4.3 (r-shell engine)
55
55
  R> :slicer test/testfiles/example.R --criterion "11@sum"
56
56
  ```
57
57
 
@@ -98,7 +98,7 @@ It offers a wide variety of features, for example:
98
98
 
99
99
 
100
100
  * 🚀 **fast data- and control-flow graphs**\
101
- Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">124.8 ms</span></i> (as of Mar 17, 2025),
101
+ Within just <i><span title="This measurement is automatically fetched from the latest benchmark!">139.5 ms</span></i> (as of May 27, 2025),
102
102
  _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,
103
103
  and consult the [wiki pages](https://github.com/flowr-analysis/flowr/wiki/Dataflow-Graph) for more details on the dataflow graph.
104
104
 
@@ -134,7 +134,7 @@ It offers a wide variety of features, for example:
134
134
 
135
135
  ```shell
136
136
  $ docker run -it --rm eagleoutice/flowr # or npm run flowr
137
- flowR repl using flowR v2.2.12, R v4.4.3 (r-shell engine)
137
+ flowR repl using flowR v2.2.13, R v4.4.3 (r-shell engine)
138
138
  R> :dataflow* test/testfiles/example.R
139
139
  ```
140
140
 
@@ -435,7 +435,7 @@ It offers a wide variety of features, for example:
435
435
  ```
436
436
 
437
437
 
438
- (The analysis required _22.6 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
438
+ (The analysis required _22.0 ms_ (including parse and normalize, using the [r-shell](https://github.com/flowr-analysis/flowr/wiki/Engines) engine) within the generation environment.)
439
439
 
440
440
 
441
441
 
@@ -1,5 +1,5 @@
1
1
  import type { ReplCommand } from './repl-main';
2
2
  export declare const controlflowCommand: ReplCommand;
3
3
  export declare const controlflowStarCommand: ReplCommand;
4
- export declare const controlflowBBCommand: ReplCommand;
5
- export declare const controlflowBBStarCommand: ReplCommand;
4
+ export declare const controlflowBbCommand: ReplCommand;
5
+ export declare const controlflowBbStarCommand: ReplCommand;
@@ -33,7 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  };
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.controlflowBBStarCommand = exports.controlflowBBCommand = exports.controlflowStarCommand = exports.controlflowCommand = void 0;
36
+ exports.controlflowBbStarCommand = exports.controlflowBbCommand = exports.controlflowStarCommand = exports.controlflowCommand = void 0;
37
37
  const extract_cfg_1 = require("../../../control-flow/extract-cfg");
38
38
  const default_pipelines_1 = require("../../../core/steps/pipeline/default-pipelines");
39
39
  const retriever_1 = require("../../../r-bridge/retriever");
@@ -53,7 +53,7 @@ function formatInfo(out, type) {
53
53
  }
54
54
  async function produceAndPrintCfg(shell, remainingLine, output, simplifications, cfgConverter) {
55
55
  const result = await controlflow(shell, handleString(remainingLine));
56
- const cfg = (0, extract_cfg_1.extractCFG)(result.normalize, result.dataflow.graph, [...cfg_simplification_1.DefaultCfgSimplificationOrder, ...simplifications]);
56
+ const cfg = (0, extract_cfg_1.extractCfg)(result.normalize, result.dataflow.graph, [...cfg_simplification_1.DefaultCfgSimplificationOrder, ...simplifications]);
57
57
  const mermaid = cfgConverter(cfg, result.normalize);
58
58
  output.stdout(mermaid);
59
59
  try {
@@ -82,7 +82,7 @@ exports.controlflowStarCommand = {
82
82
  await produceAndPrintCfg(shell, remainingLine, output, [], cfg_1.cfgToMermaidUrl);
83
83
  }
84
84
  };
85
- exports.controlflowBBCommand = {
85
+ exports.controlflowBbCommand = {
86
86
  description: `Get mermaid code for the control-flow graph with basic blocks, start with '${retriever_1.fileProtocol}' to indicate a file`,
87
87
  usageExample: ':controlflowbb',
88
88
  aliases: ['cfgb', 'cfb'],
@@ -91,7 +91,7 @@ exports.controlflowBBCommand = {
91
91
  await produceAndPrintCfg(shell, remainingLine, output, ['to-basic-blocks'], cfg_1.cfgToMermaid);
92
92
  }
93
93
  };
94
- exports.controlflowBBStarCommand = {
94
+ exports.controlflowBbStarCommand = {
95
95
  description: 'Returns the URL to mermaid.live',
96
96
  usageExample: ':controlflowbb*',
97
97
  aliases: ['cfgb*', 'cfb*'],
@@ -85,8 +85,8 @@ const _commands = {
85
85
  'dataflowsimple*': repl_dataflow_1.dataflowSimpleStarCommand,
86
86
  'controlflow': repl_cfg_1.controlflowCommand,
87
87
  'controlflow*': repl_cfg_1.controlflowStarCommand,
88
- 'controlflowbb': repl_cfg_1.controlflowBBCommand,
89
- 'controlflowbb*': repl_cfg_1.controlflowBBStarCommand,
88
+ 'controlflowbb': repl_cfg_1.controlflowBbCommand,
89
+ 'controlflowbb*': repl_cfg_1.controlflowBbStarCommand,
90
90
  'lineage': repl_lineage_1.lineageCommand,
91
91
  'query': repl_query_1.queryCommand,
92
92
  'query*': repl_query_1.queryStarCommand
@@ -160,7 +160,7 @@ class FlowRServerConnection {
160
160
  async sendFileAnalysisResponse(slicer, results, message) {
161
161
  let cfg = undefined;
162
162
  if (message.cfg) {
163
- cfg = (0, extract_cfg_1.extractCFG)(results.normalize, results.dataflow?.graph);
163
+ cfg = (0, extract_cfg_1.extractCfg)(results.normalize, results.dataflow?.graph);
164
164
  }
165
165
  const config = () => ({ context: message.filename ?? 'unknown', getId: (0, quads_1.defaultQuadIdGenerator)() });
166
166
  const sanitizedResults = sanitizeAnalysisResults(results);
@@ -58,7 +58,7 @@ async function getStatsForSingleFile(options) {
58
58
  if (stats.outputs.size === 1) {
59
59
  if (options['dump-json']) {
60
60
  const [, output] = [...stats.outputs.entries()][0];
61
- const cfg = (0, extract_cfg_1.extractCFG)(output.normalize, output.dataflow.graph);
61
+ const cfg = (0, extract_cfg_1.extractCfg)(output.normalize, output.dataflow.graph);
62
62
  statistics_file_1.statisticsFileProvider.append('output-json', 'parse', await (0, print_1.printStepResult)(_00_parse_1.PARSE_WITH_R_SHELL_STEP, output.parse, 2 /* StepOutputFormat.Json */));
63
63
  statistics_file_1.statisticsFileProvider.append('output-json', 'normalize', await (0, print_1.printStepResult)(_10_normalize_1.NORMALIZE, output.normalize, 2 /* StepOutputFormat.Json */));
64
64
  statistics_file_1.statisticsFileProvider.append('output-json', 'dataflow', await (0, print_1.printStepResult)(_20_dataflow_1.STATIC_DATAFLOW, output.dataflow, 2 /* StepOutputFormat.Json */));
@@ -14,9 +14,9 @@ import type { CfgSimplificationPassName } from './cfg-simplification';
14
14
  *
15
15
  * @see {@link extractSimpleCfg} - for a simplified version of this function
16
16
  */
17
- export declare function extractCFG<Info = ParentInformation>(ast: NormalizedAst<Info>, graph?: DataflowGraph, simplifications?: readonly CfgSimplificationPassName[]): ControlFlowInformation;
17
+ export declare function extractCfg<Info = ParentInformation>(ast: NormalizedAst<Info>, graph?: DataflowGraph, simplifications?: readonly CfgSimplificationPassName[]): ControlFlowInformation;
18
18
  /**
19
- * Simplified version of {@link extractCFG} that is much quicker, but much simpler!
19
+ * Simplified version of {@link extractCfg} that is much quicker, but much simpler!
20
20
  */
21
21
  export declare function extractSimpleCfg<Info = ParentInformation>(ast: NormalizedAst<Info>): ControlFlowInformation<import("./control-flow-graph").CfgSimpleVertex>;
22
22
  export declare const ResolvedCallSuffix = "-resolved-call-exit";
@@ -1,7 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.ResolvedCallSuffix = void 0;
4
- exports.extractCFG = extractCFG;
4
+ exports.extractCfg = extractCfg;
5
5
  exports.extractSimpleCfg = extractSimpleCfg;
6
6
  exports.cfg2quads = cfg2quads;
7
7
  const quads_1 = require("../util/quads");
@@ -62,11 +62,11 @@ function dataflowCfgFolds(dataflowGraph) {
62
62
  *
63
63
  * @see {@link extractSimpleCfg} - for a simplified version of this function
64
64
  */
65
- function extractCFG(ast, graph, simplifications) {
65
+ function extractCfg(ast, graph, simplifications) {
66
66
  return (0, cfg_simplification_1.simplifyControlFlowInformation)((0, fold_1.foldAst)(ast.ast, graph ? dataflowCfgFolds(graph) : cfgFolds), simplifications);
67
67
  }
68
68
  /**
69
- * Simplified version of {@link extractCFG} that is much quicker, but much simpler!
69
+ * Simplified version of {@link extractCfg} that is much quicker, but much simpler!
70
70
  */
71
71
  function extractSimpleCfg(ast) {
72
72
  return (0, fold_1.foldAst)(ast.ast, cfgFolds);
@@ -272,11 +272,11 @@ function cfgFunctionCall(call, name, args, exit = 'exit') {
272
272
  exports.ResolvedCallSuffix = '-resolved-call-exit';
273
273
  function cfgFunctionCallWithDataflow(graph) {
274
274
  return (call, name, args) => {
275
- const baseCFG = cfgFunctionCall(call, name, args);
275
+ const baseCfg = cfgFunctionCall(call, name, args);
276
276
  /* try to resolve the call and link the target definitions */
277
277
  const targets = (0, linker_1.getAllFunctionCallTargets)(call.info.id, graph);
278
278
  const exits = [];
279
- const callVertex = baseCFG.graph.getVertex(call.info.id);
279
+ const callVertex = baseCfg.graph.getVertex(call.info.id);
280
280
  (0, assert_1.guard)(callVertex !== undefined, 'cfgFunctionCallWithDataflow: call vertex not found');
281
281
  for (const target of targets) {
282
282
  // we have to filter out non func-call targets as the call targets contains names and call ids
@@ -287,21 +287,21 @@ function cfgFunctionCallWithDataflow(graph) {
287
287
  }
288
288
  }
289
289
  if (exits.length > 0) {
290
- baseCFG.graph.addVertex({
290
+ baseCfg.graph.addVertex({
291
291
  id: call.info.id + exports.ResolvedCallSuffix,
292
292
  type: control_flow_graph_1.CfgVertexType.EndMarker,
293
293
  root: call.info.id
294
294
  });
295
- for (const exit of [...baseCFG.exitPoints, ...exits]) {
296
- baseCFG.graph.addEdge(call.info.id + exports.ResolvedCallSuffix, exit, { label: 0 /* CfgEdgeType.Fd */ });
295
+ for (const exit of [...baseCfg.exitPoints, ...exits]) {
296
+ baseCfg.graph.addEdge(call.info.id + exports.ResolvedCallSuffix, exit, { label: 0 /* CfgEdgeType.Fd */ });
297
297
  }
298
298
  return {
299
- ...baseCFG,
299
+ ...baseCfg,
300
300
  exitPoints: [call.info.id + exports.ResolvedCallSuffix]
301
301
  };
302
302
  }
303
303
  else {
304
- return baseCFG;
304
+ return baseCfg;
305
305
  }
306
306
  };
307
307
  }
@@ -19,5 +19,5 @@ export interface PrintCfgOptions {
19
19
  readonly simplify?: boolean;
20
20
  readonly useDfg?: boolean;
21
21
  }
22
- export declare function printCFGCode(parser: KnownParser, code: string, { showCode, openCode, prefix, simplifications, simplify, useDfg }?: PrintCfgOptions): Promise<string>;
22
+ export declare function printCfgCode(parser: KnownParser, code: string, { showCode, openCode, prefix, simplifications, simplify, useDfg }?: PrintCfgOptions): Promise<string>;
23
23
  export {};
@@ -2,7 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getCfg = getCfg;
4
4
  exports.printCfg = printCfg;
5
- exports.printCFGCode = printCFGCode;
5
+ exports.printCfgCode = printCfgCode;
6
6
  const extract_cfg_1 = require("../../control-flow/extract-cfg");
7
7
  const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines");
8
8
  const retriever_1 = require("../../r-bridge/retriever");
@@ -17,7 +17,7 @@ async function getCfg(parser, code, simplifications = [], useDfg = true) {
17
17
  }).allRemainingSteps() : await (0, default_pipelines_1.createNormalizePipeline)(parser, {
18
18
  request: (0, retriever_1.requestFromInput)(code)
19
19
  }).allRemainingSteps();
20
- const cfg = (0, extract_cfg_1.extractCFG)(result.normalize, useDfg ? result.dataflow.graph : undefined, [...cfg_simplification_1.DefaultCfgSimplificationOrder, ...simplifications]);
20
+ const cfg = (0, extract_cfg_1.extractCfg)(result.normalize, useDfg ? result.dataflow.graph : undefined, [...cfg_simplification_1.DefaultCfgSimplificationOrder, ...simplifications]);
21
21
  return {
22
22
  info: cfg,
23
23
  ast: result.normalize,
@@ -29,7 +29,7 @@ function printCfg(cfg, ast, prefix = 'flowchart BT\n', simplify = false) {
29
29
  ${(0, doc_code_1.codeBlock)('mermaid', (0, cfg_1.cfgToMermaid)(cfg, ast, prefix, simplify))}
30
30
  `;
31
31
  }
32
- async function printCFGCode(parser, code, { showCode = true, openCode = false, prefix = 'flowchart BT\n', simplifications = [], simplify = false, useDfg = true } = {}) {
32
+ async function printCfgCode(parser, code, { showCode = true, openCode = false, prefix = 'flowchart BT\n', simplifications = [], simplify = false, useDfg = true } = {}) {
33
33
  const now = performance.now();
34
34
  const res = await getCfg(parser, code, simplifications, useDfg);
35
35
  const duration = performance.now() - now;
@@ -167,7 +167,7 @@ ${(0, doc_code_1.codeBlock)('r', 'x <- 2 * 3 + 1')}
167
167
 
168
168
  The corresponding CFG is a directed, labeled graph with two types of edges (control and flow dependencies).
169
169
 
170
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
170
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
171
171
 
172
172
  ${(0, doc_structure_1.block)({
173
173
  type: 'IMPORTANT',
@@ -180,30 +180,30 @@ Expressions, such as \`2 * 3\` get an additional node with an artificial id that
180
180
 
181
181
  To gain a better understanding, let's have a look at a simple program with a single branching structure:
182
182
 
183
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u) 3 else 2', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
183
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u) 3 else 2', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
184
184
 
185
185
  Here, you can see the \`if\` node followed by the condition (in this case merely \`u\`) that then splits into two branches for the two possible outcomes.
186
186
  The \`if\` structure is terminated by the corresponding \`-exit\` node (see the [structure](#cfg-structure) section for more details).
187
187
 
188
188
  For you to compare, the following shows the CFG of an \`if\` without an \`else\` branch:
189
189
 
190
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
190
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n' })}
191
191
 
192
192
  Activating the calculation of basic blocks produces the following:
193
193
 
194
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'] })}
194
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'] })}
195
195
 
196
196
  Which is probably much more readable if compacted (although the reconstucted code can sometimes be slightly mislieading as flowR tries its best to make it syntactically correct and hence add closing braces etc. which are technically not part of the respective block):
197
197
 
198
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
198
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'if(u || v) 3', { showCode: true, openCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
199
199
 
200
200
  The control flow graph also harmonizes with function definitions, and calls:
201
201
 
202
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'f <- function() { 3 }\nf()', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })}
202
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'f <- function() { 3 }\nf()', { showCode: true, openCode: true, prefix: 'flowchart RL\n' })}
203
203
 
204
204
  ${(0, doc_structure_1.section)('Structure of the Control Flow Graph', 2, 'cfg-structure')}
205
205
 
206
- You can produce your very own control flow graph with ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCFG.name, types.info)}.
206
+ You can produce your very own control flow graph with ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)}.
207
207
  The ${(0, doc_types_1.shortLink)(control_flow_graph_1.ControlFlowGraph.name, types.info)} class describes everything required to model the control flow graph, with its edge types described by
208
208
  ${(0, doc_types_1.shortLink)('CfgEdge', types.info)} and its vertices by ${(0, doc_types_1.shortLink)('CfgSimpleVertex', types.info)}.
209
209
  However, you should be aware of the ${(0, doc_types_1.shortLink)('ControlFlowInformation', types.info)} interface which adds some additional information the the CFG
@@ -214,7 +214,7 @@ ${(0, doc_types_1.printHierarchy)({ info: types.info, root: 'ControlFlowInformat
214
214
  To check whether the CFG has the expected shape, you can use the test function ${(0, doc_types_1.shortLink)('assertCfg', testTypes.info)} which supports testing for
215
215
  sub-graphs as well (it provides diffing capabilities similar to ${(0, doc_types_1.shortLink)('assertDataflow', testTypes.info)}).
216
216
  As the CFG may become unhandy for larger programs, there are simplifications available with ${(0, doc_types_1.shortLink)(cfg_simplification_1.simplifyControlFlowInformation.name, types.info)}
217
- (these can be passed on to the ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCFG.name, types.info)} function as well).
217
+ (these can be passed on to the ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)} function as well).
218
218
 
219
219
  ${(0, doc_structure_1.section)('CFG Vertices', 3, 'cfg-structure-vertices')}
220
220
 
@@ -258,7 +258,7 @@ ${(0, doc_structure_1.section)('Flow Dependencies', 4, 'cfg-flow-dependency')}
258
258
  The most common edge is the flow dependency&nbsp;(FD) which simply signals that the source vertex happens _after_ the target vertex in the control flow.
259
259
  So \`x; y\` would produce a flow dependency from \`y\` to \`x\` (additionally to the program-enveloping root expression list):
260
260
 
261
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'x; y', { showCode: false, prefix: 'flowchart RL\n' })}
261
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'x; y', { showCode: false, prefix: 'flowchart RL\n' })}
262
262
 
263
263
  ${(0, doc_structure_1.section)('Control Dependencies', 4, 'cfg-control-dependency')}
264
264
 
@@ -271,12 +271,12 @@ The extra \`caused\` link signals the vertex that caused the control flow influe
271
271
 
272
272
 
273
273
  ${await (async () => {
274
- const exa = await (0, doc_cfg_1.printCFGCode)(shell, 'if(u) 3 else 2', { showCode: true, prefix: 'flowchart RL\n' });
274
+ const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'if(u) 3 else 2', { showCode: true, prefix: 'flowchart RL\n' });
275
275
  return (0, doc_structure_1.details)('Example: if-else', exa);
276
276
  })()}
277
277
 
278
278
  ${await (async () => {
279
- const exa = await (0, doc_cfg_1.printCFGCode)(shell, 'while(u) b', { showCode: true, prefix: 'flowchart RL\n' });
279
+ const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'while(u) b', { showCode: true, prefix: 'flowchart RL\n' });
280
280
  return (0, doc_structure_1.details)('Example: while-loop', exa);
281
281
  })()}
282
282
  <br/>
@@ -286,12 +286,12 @@ Additionally, the control flow graph does not have to be connected. If you use a
286
286
  the corresponding exit markers are not reachable from the entry:
287
287
 
288
288
  ${await (async () => {
289
- const exa = await (0, doc_cfg_1.printCFGCode)(shell, 'repeat { b }; after', { showCode: true, prefix: 'flowchart RL\n' });
289
+ const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'repeat { b }; after', { showCode: true, prefix: 'flowchart RL\n' });
290
290
  return (0, doc_structure_1.details)('Example: repeat-loop (infinite)', exa);
291
291
  })()}
292
292
 
293
293
  ${await (async () => {
294
- const exa = await (0, doc_cfg_1.printCFGCode)(shell, 'repeat { b; if(u) break; }; after', { showCode: true, prefix: 'flowchart RL\n' });
294
+ const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'repeat { b; if(u) break; }; after', { showCode: true, prefix: 'flowchart RL\n' });
295
295
  return (0, doc_structure_1.details)('Example: repeat-loop (with break)', exa);
296
296
  })()}
297
297
  <br/>
@@ -299,22 +299,22 @@ ${await (async () => {
299
299
  In the context of a for-loop, the control dependency refer to whether the respective vector still has values to iterate over.
300
300
 
301
301
  ${await (async () => {
302
- const exa = await (0, doc_cfg_1.printCFGCode)(shell, 'for(i in 1:10) b', { showCode: true, prefix: 'flowchart RL\n' });
302
+ const exa = await (0, doc_cfg_1.printCfgCode)(shell, 'for(i in 1:10) b', { showCode: true, prefix: 'flowchart RL\n' });
303
303
  return (0, doc_structure_1.details)('Example: for-loop', exa);
304
304
  })()}
305
305
 
306
306
  ${(0, doc_structure_1.section)('Extra: Call Links', 4, 'cfg-call-links')}
307
307
 
308
- If you generate the CFG with the ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCFG.name, types.info)} function you can (and, if you want to gain inter-procedural information, should)
308
+ If you generate the CFG with the ${(0, doc_types_1.shortLink)(extract_cfg_1.extractCfg.name, types.info)} function you can (and, if you want to gain inter-procedural information, should)
309
309
  pass a matching [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph) to it to incorporate the dataflow perspective into the CFG.
310
310
 
311
311
  The difference becomes obvious when we look at the code \`f <- function() b; f()\` first without the dataflow graph:
312
312
 
313
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'f <- function() b; f()', { showCode: true, prefix: 'flowchart RL\n', useDfg: false })}
313
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'f <- function() b; f()', { showCode: true, prefix: 'flowchart RL\n', useDfg: false })}
314
314
 
315
315
  And now, including dataflow information:
316
316
 
317
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'f <- function() b; f()', { showCode: true, prefix: 'flowchart RL\n', useDfg: true })}
317
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'f <- function() b; f()', { showCode: true, prefix: 'flowchart RL\n', useDfg: true })}
318
318
 
319
319
  There are two important additions:
320
320
 
@@ -325,7 +325,7 @@ There are two important additions:
325
325
  For built-in functions that are provided by flowR's built-in configuration (see the [interface wiki page](${doc_files_1.FlowrWikiBaseRef}/Interface)) the CFG does not contain
326
326
  the additional information directly:
327
327
 
328
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'print(3)', { showCode: true, prefix: 'flowchart RL\n' })}
328
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'print(3)', { showCode: true, prefix: 'flowchart RL\n' })}
329
329
 
330
330
  This is due to the fact that the [dataflow graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph) does contain the required call information (and there are no new control vertices to add as the built-in call has no target in the source code):
331
331
 
@@ -340,16 +340,16 @@ Yet, we can request basic blocks or transform an existing CFG into basic blocks
340
340
 
341
341
  Any program without any (un-)conditional jumps now contains a single basic block:
342
342
 
343
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'x <- 2 * 3 + 1', { showCode: true, openCode: true, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
343
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: true, openCode: true, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
344
344
 
345
345
  While the CFG without basic blocks is much bigger:
346
346
 
347
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
347
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n' })}
348
348
 
349
349
  In a way, using the basic blocks perspective does not remove any of these vertices (we just usually visualize them compacted as their execution order should be "obvious").
350
350
  The vertices are still there, as elems of the ${(0, doc_types_1.shortLink)('CfgBasicBlockVertex', types.info)}:
351
351
 
352
- ${await (0, doc_cfg_1.printCFGCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: false })}
352
+ ${await (0, doc_cfg_1.printCfgCode)(shell, 'x <- 2 * 3 + 1', { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: false })}
353
353
 
354
354
  The benefit (for comprehensibility and algorithms) becomes more apparent when we look at a more complicated program:
355
355
 
@@ -357,12 +357,12 @@ ${(0, doc_code_1.codeBlock)('r', CfgLongExample)}
357
357
 
358
358
  With basic blocks, this code looks like this:
359
359
 
360
- ${await (0, doc_cfg_1.printCFGCode)(shell, CfgLongExample, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
360
+ ${await (0, doc_cfg_1.printCfgCode)(shell, CfgLongExample, { showCode: false, prefix: 'flowchart RL\n', simplifications: ['to-basic-blocks'], simplify: true })}
361
361
 
362
362
  Now, without basic blocks, this is a different story...
363
363
 
364
364
  ${await (async () => {
365
- const exa = await (0, doc_cfg_1.printCFGCode)(shell, CfgLongExample, { showCode: false, prefix: 'flowchart RL\n' });
365
+ const exa = await (0, doc_cfg_1.printCfgCode)(shell, CfgLongExample, { showCode: false, prefix: 'flowchart RL\n' });
366
366
  return (0, doc_structure_1.details)('The full CFG', exa);
367
367
  })()}
368
368
 
@@ -529,7 +529,7 @@ ${await (async function () {
529
529
  (0, assert_1.guard)(plusVertex.type === control_flow_graph_1.CfgVertexType.Expression);
530
530
  const numOfExits = plusVertex.end?.length ?? 0;
531
531
  (0, assert_1.guard)(plusVertex.end && numOfExits === 1);
532
- return `${await (0, doc_cfg_1.printCFGCode)(shell, 'x + 1', { showCode: true, prefix: 'flowchart RL\n' })}
532
+ return `${await (0, doc_cfg_1.printCfgCode)(shell, 'x + 1', { showCode: true, prefix: 'flowchart RL\n' })}
533
533
 
534
534
  Looking at the binary operation vertex for \`+\` (with id \`${plusVertexId}\`) we see that it is linked to a single exit ("end marker") point: \`${plusVertex.end[0]}\`.
535
535
  Checking this vertex essentially reveals all exit points of the expression &dash; in this case, this simply refers to the operands of the addition.
@@ -544,7 +544,7 @@ ${(0, doc_structure_1.details)('Example: Exit Points for an if', await (async fu
544
544
  (0, assert_1.guard)(ifVertex.type === control_flow_graph_1.CfgVertexType.Statement);
545
545
  const numOfExits = ifVertex.end?.length ?? 0;
546
546
  (0, assert_1.guard)(ifVertex.end && numOfExits === 1);
547
- return `${await (0, doc_cfg_1.printCFGCode)(shell, expr, { showCode: true, prefix: 'flowchart RL\n' })}
547
+ return `${await (0, doc_cfg_1.printCfgCode)(shell, expr, { showCode: true, prefix: 'flowchart RL\n' })}
548
548
 
549
549
  Looking at the if vertex for (with id \`${ifVertexId}\`) we see that it is again linked to a single exit point: \`${ifVertex.end[0]}\`.
550
550
  Yet, now this exit vertex is linked to the two branches of the if statement (the \`then\` and \`else\` branch).
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const log_1 = require("../../test/functionality/_helper/log");
7
+ const doc_auto_gen_1 = require("./doc-util/doc-auto-gen");
8
+ const doc_files_1 = require("./doc-util/doc-files");
9
+ const linter_rules_1 = require("../linter/linter-rules");
10
+ const doc_code_1 = require("./doc-util/doc-code");
11
+ const shell_1 = require("../r-bridge/shell");
12
+ const doc_query_1 = require("./doc-util/doc-query");
13
+ const doc_types_1 = require("./doc-util/doc-types");
14
+ const path_1 = __importDefault(require("path"));
15
+ async function getText(shell) {
16
+ const rVersion = (await shell.usedRVersion())?.format() ?? 'unknown';
17
+ return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'linter', rVersion })}
18
+
19
+ This page describes the flowR linter, which is a tool that utilizes flowR's dataflow analysis to find common issues in R scripts. The linter can currently be used through the linter [query](${doc_files_1.FlowrWikiBaseRef}/Query%20API).
20
+
21
+ ## Linting Rules
22
+
23
+ The following linting rules are available:
24
+
25
+ ${await rule(shell, 'deprecated-functions', 'DeprecatedFunctionsConfig', 'Deprecated Functions', 'This rule detects the usage of deprecated functions in code based on a predefined list of known deprecated functions.', `
26
+ first <- data.frame(x = c(1, 2, 3), y = c(1, 2, 3))
27
+ second <- data.frame(x = c(1, 3, 2), y = c(1, 3, 2))
28
+ dplyr::all_equal(first, second)
29
+ `)}
30
+
31
+ ${await rule(shell, 'file-path-validity', 'FilePathValidityConfig', 'File Path Validity', 'This rule finds places in the code where files are being read from. In such places, it checks whether the file path is valid and whether the file exists on disk.', `
32
+ my_data <- read.csv("C:/Users/me/Documents/My R Scripts/Reproducible.csv")
33
+ `)}
34
+
35
+ `.trim();
36
+ }
37
+ async function rule(shell, name, configType, friendlyName, description, example) {
38
+ const types = (0, doc_types_1.getTypesFromFolderAsMermaid)({
39
+ rootFolder: path_1.default.resolve('./src/linter/'),
40
+ typeName: configType,
41
+ inlineTypes: doc_types_1.mermaidHide
42
+ });
43
+ return `
44
+ ### ${friendlyName} (\`${name}\`)
45
+
46
+ ${description}
47
+
48
+ <details>
49
+
50
+ #### Configuration
51
+
52
+ Linting rules can be configured by passing a configuration object to the linter query as shown in the example below. The \`${name}\` rule accepts the following configuration options:
53
+
54
+ ${Object.getOwnPropertyNames(linter_rules_1.LintingRules[name].defaultConfig).sort().map(key => `- ${(0, doc_types_1.shortLink)(`${configType}:::${key}`, types.info)}\\\n${(0, doc_types_1.getDocumentationForType)(`${configType}::${key}`, types.info)}`).join('\n')}
55
+
56
+ #### Example
57
+
58
+ ${(0, doc_code_1.codeBlock)('r', example)}
59
+
60
+ The linting query can be used to run this rule on the above example:
61
+
62
+ ${await (0, doc_query_1.showQuery)(shell, example, [{ type: 'linter', rules: [{ name, config: {} }] }], { collapseQuery: true })}
63
+
64
+ </details>
65
+ `.trim();
66
+ }
67
+ if (require.main === module) {
68
+ (0, log_1.setMinLevelOfAllLogs)(6 /* LogLevel.Fatal */);
69
+ const shell = new shell_1.RShell();
70
+ void getText(shell).then(str => {
71
+ console.log(str);
72
+ }).finally(() => {
73
+ shell.close();
74
+ });
75
+ }
76
+ //# sourceMappingURL=print-linter-wiki.js.map
@@ -0,0 +1,9 @@
1
+ import type { LintingRuleConfig, LintingRuleNames } from './linter-rules';
2
+ import type { NormalizedAst } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
3
+ import type { DataflowInformation } from '../dataflow/info';
4
+ import type { LintingResults } from './linter-format';
5
+ import type { DeepPartial } from 'ts-essentials';
6
+ export declare function executeLintingRule<Name extends LintingRuleNames>(ruleName: Name, input: {
7
+ normalize: NormalizedAst;
8
+ dataflow: DataflowInformation;
9
+ }, config?: DeepPartial<LintingRuleConfig<Name>>): LintingResults<Name>;
@@ -0,0 +1,26 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.executeLintingRule = executeLintingRule;
4
+ const linter_rules_1 = require("./linter-rules");
5
+ const flowr_search_executor_1 = require("../search/flowr-search-executor");
6
+ const flowr_search_1 = require("../search/flowr-search");
7
+ function executeLintingRule(ruleName, input, config) {
8
+ const rule = linter_rules_1.LintingRules[ruleName];
9
+ const fullConfig = { ...rule.defaultConfig, ...config };
10
+ const ruleSearch = rule.createSearch(fullConfig, input);
11
+ const searchStart = Date.now();
12
+ const searchResult = (0, flowr_search_executor_1.runSearch)(ruleSearch, input);
13
+ const searchTime = Date.now() - searchStart;
14
+ const processStart = Date.now();
15
+ const result = rule.processSearchResult(new flowr_search_1.FlowrSearchElements(searchResult), fullConfig, input);
16
+ const processTime = Date.now() - processStart;
17
+ return {
18
+ ...result,
19
+ '.meta': {
20
+ ...result['.meta'],
21
+ searchTimeMs: searchTime,
22
+ processTimeMs: processTime
23
+ }
24
+ };
25
+ }
26
+ //# sourceMappingURL=linter-executor.js.map
@@ -0,0 +1,65 @@
1
+ import type { FlowrSearchLike } from '../search/flowr-search-builder';
2
+ import type { FlowrSearchElement, FlowrSearchElements } from '../search/flowr-search';
3
+ import type { MergeableRecord } from '../util/objects';
4
+ import type { GeneratorNames } from '../search/search-executor/search-generators';
5
+ import type { TransformerNames } from '../search/search-executor/search-transformer';
6
+ import type { NormalizedAst, ParentInformation } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
7
+ import type { LintingRuleConfig, LintingRuleMetadata, LintingRuleNames, LintingRuleResult } from './linter-rules';
8
+ import type { DataflowInformation } from '../dataflow/info';
9
+ import type { DeepPartial } from 'ts-essentials';
10
+ /**
11
+ * The base interface for a linting rule, which contains all of its relevant settings.
12
+ * The registry of valid linting rules is stored in {@link LintingRules}.
13
+ */
14
+ export interface LintingRule<Result extends LintingResult, Metadata extends MergeableRecord, Config extends MergeableRecord = never, Info = ParentInformation, Elements extends FlowrSearchElement<Info>[] = FlowrSearchElement<Info>[]> {
15
+ /**
16
+ * Creates a flowR search that will then be executed and whose results will be passed to {@link processSearchResult}.
17
+ * In the future, additional optimizations and transformations may be applied to the search between this function and {@link processSearchResult}.
18
+ */
19
+ readonly createSearch: (config: Config, data: {
20
+ normalize: NormalizedAst;
21
+ dataflow: DataflowInformation;
22
+ }) => FlowrSearchLike<Info, GeneratorNames, TransformerNames[], FlowrSearchElements<Info, Elements>>;
23
+ /**
24
+ * Processes the search results of the search created through {@link createSearch}.
25
+ * This function is expected to return the linting results from this rule for the given search, ie usually the given script file.
26
+ */
27
+ readonly processSearchResult: (elements: FlowrSearchElements<Info, Elements>, config: Config, data: {
28
+ normalize: NormalizedAst;
29
+ dataflow: DataflowInformation;
30
+ }) => {
31
+ results: Result[];
32
+ '.meta': Metadata;
33
+ };
34
+ /**
35
+ * A function used to pretty-print the given linting result.
36
+ * By default, the {@link LintingResult#certainty} is automatically printed alongside this information.
37
+ */
38
+ readonly prettyPrint: (result: Result, metadata: Metadata) => string;
39
+ /**
40
+ * The default config for this linting rule.
41
+ * The default config is combined with the user config when executing the rule.
42
+ */
43
+ readonly defaultConfig: NoInfer<Config>;
44
+ }
45
+ /**
46
+ * A linting result for a single linting rule match.
47
+ */
48
+ export interface LintingResult {
49
+ readonly certainty: LintingCertainty;
50
+ }
51
+ export interface ConfiguredLintingRule<Name extends LintingRuleNames = LintingRuleNames> {
52
+ readonly name: Name;
53
+ readonly config: DeepPartial<LintingRuleConfig<Name>>;
54
+ }
55
+ export interface LintingResults<Name extends LintingRuleNames> {
56
+ results: LintingRuleResult<Name>[];
57
+ '.meta': LintingRuleMetadata<Name> & {
58
+ readonly searchTimeMs: number;
59
+ readonly processTimeMs: number;
60
+ };
61
+ }
62
+ export declare enum LintingCertainty {
63
+ Maybe = "maybe",
64
+ Definitely = "definitely"
65
+ }
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LintingCertainty = void 0;
4
+ var LintingCertainty;
5
+ (function (LintingCertainty) {
6
+ LintingCertainty["Maybe"] = "maybe";
7
+ LintingCertainty["Definitely"] = "definitely";
8
+ })(LintingCertainty || (exports.LintingCertainty = LintingCertainty = {}));
9
+ //# sourceMappingURL=linter-format.js.map