@eagleoutice/flowr 2.9.11 → 2.9.13

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 (95) hide show
  1. package/README.md +31 -31
  2. package/benchmark/slicer.d.ts +4 -2
  3. package/benchmark/slicer.js +20 -6
  4. package/benchmark/stats/print.js +12 -0
  5. package/benchmark/stats/stats.d.ts +3 -2
  6. package/benchmark/stats/stats.js +1 -1
  7. package/benchmark/summarizer/data.d.ts +1 -0
  8. package/benchmark/summarizer/second-phase/process.js +5 -0
  9. package/cli/benchmark-app.d.ts +1 -0
  10. package/cli/benchmark-app.js +1 -0
  11. package/cli/benchmark-helper-app.d.ts +2 -1
  12. package/cli/benchmark-helper-app.js +6 -3
  13. package/cli/common/options.d.ts +8 -0
  14. package/cli/common/options.js +3 -1
  15. package/cli/common/scripts-info.d.ts +8 -0
  16. package/cli/export-quads-app.js +1 -1
  17. package/cli/flowr.js +3 -3
  18. package/cli/repl/core.d.ts +3 -3
  19. package/cli/repl/server/connection.d.ts +2 -2
  20. package/cli/repl/server/server.d.ts +2 -2
  21. package/cli/script-core/statistics-core.d.ts +2 -2
  22. package/cli/script-core/statistics-helper-core.d.ts +2 -2
  23. package/cli/script-core/statistics-helper-core.js +1 -1
  24. package/cli/slicer-app.js +2 -2
  25. package/cli/statistics-app.js +1 -1
  26. package/cli/statistics-helper-app.js +1 -1
  27. package/cli/wiki.js +2 -2
  28. package/config.d.ts +65 -24
  29. package/config.js +197 -161
  30. package/control-flow/extract-cfg.js +5 -8
  31. package/core/steps/pipeline-step.d.ts +2 -2
  32. package/dataflow/cluster.js +12 -8
  33. package/dataflow/eval/resolve/alias-tracking.js +12 -15
  34. package/dataflow/graph/graph.js +8 -8
  35. package/dataflow/graph/quads.js +4 -7
  36. package/dataflow/internal/linker.js +5 -5
  37. package/dataflow/internal/process/functions/call/built-in/built-in-eval.js +2 -2
  38. package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +1 -1
  39. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +20 -9
  40. package/documentation/doc-readme.js +2 -2
  41. package/documentation/wiki-analyzer.js +7 -5
  42. package/documentation/wiki-core.js +1 -3
  43. package/documentation/wiki-dataflow-graph.js +87 -32
  44. package/documentation/wiki-engine.js +18 -0
  45. package/documentation/wiki-interface.js +5 -3
  46. package/documentation/wiki-linter.js +5 -5
  47. package/documentation/wiki-mk/doc-context.d.ts +44 -11
  48. package/documentation/wiki-mk/doc-context.js +19 -17
  49. package/engines.d.ts +2 -2
  50. package/engines.js +4 -4
  51. package/linter/rules/dataframe-access-validation.js +5 -5
  52. package/linter/rules/naming-convention.d.ts +1 -1
  53. package/linter/rules/naming-convention.js +7 -3
  54. package/package.json +3 -1
  55. package/project/context/flowr-analyzer-context.d.ts +6 -6
  56. package/project/context/flowr-analyzer-context.js +2 -2
  57. package/project/context/flowr-analyzer-files-context.d.ts +2 -2
  58. package/project/context/flowr-analyzer-files-context.js +28 -8
  59. package/project/flowr-analyzer-builder.d.ts +10 -6
  60. package/project/flowr-analyzer-builder.js +12 -3
  61. package/project/flowr-analyzer.d.ts +3 -3
  62. package/queries/catalog/config-query/config-query-format.d.ts +5 -5
  63. package/queries/catalog/dependencies-query/function-info/library-functions.js +2 -1
  64. package/queries/catalog/dependencies-query/function-info/read-functions.js +1 -1
  65. package/queries/catalog/dependencies-query/function-info/visualize-functions.js +9 -1
  66. package/queries/catalog/dependencies-query/function-info/write-functions.js +1 -0
  67. package/queries/catalog/df-shape-query/df-shape-query-format.d.ts +2 -2
  68. package/queries/catalog/does-call-query/does-call-query-format.d.ts +2 -2
  69. package/queries/catalog/files-query/files-query-format.d.ts +3 -3
  70. package/queries/catalog/inspect-exceptions-query/inspect-exception-query-format.d.ts +2 -2
  71. package/queries/catalog/inspect-higher-order-query/inspect-higher-order-query-format.d.ts +2 -2
  72. package/queries/catalog/inspect-recursion-query/inspect-recursion-query-format.d.ts +2 -2
  73. package/queries/catalog/linter-query/linter-query-format.d.ts +3 -3
  74. package/queries/catalog/location-map-query/location-map-query-format.d.ts +2 -2
  75. package/queries/catalog/origin-query/origin-query-format.d.ts +2 -2
  76. package/queries/catalog/resolve-value-query/resolve-value-query-executor.js +3 -3
  77. package/queries/catalog/resolve-value-query/resolve-value-query-format.d.ts +2 -2
  78. package/queries/catalog/resolve-value-query/resolve-value-query-format.js +4 -0
  79. package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +2 -2
  80. package/queries/query.d.ts +18 -18
  81. package/r-bridge/lang-4.x/ast/model/model.d.ts +7 -2
  82. package/r-bridge/lang-4.x/ast/model/model.js +13 -0
  83. package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +2 -2
  84. package/r-bridge/lang-4.x/ast/parser/json/parser.js +2 -2
  85. package/r-bridge/lang-4.x/tree-sitter/tree-sitter-normalize.js +6 -2
  86. package/statistics/statistics.d.ts +2 -2
  87. package/util/mermaid/dfg.d.ts +8 -0
  88. package/util/mermaid/dfg.js +4 -0
  89. package/util/objects.d.ts +12 -0
  90. package/util/objects.js +28 -0
  91. package/util/quads.js +14 -6
  92. package/util/range.d.ts +3 -0
  93. package/util/range.js +3 -0
  94. package/util/summarizer.js +1 -1
  95. package/util/version.js +1 -1
@@ -37,6 +37,19 @@ are exposed with some command line options (e.g., when using the docker image of
37
37
  - ${ctx.cliOption('flowr', 'engine.tree-sitter.tree-sitter-wasm-path', false)} pass the path to the wasm of tree-sitter (see [below](#tree-sitter))
38
38
  - ${ctx.cliOption('flowr', 'default-engine', false)} to set the default engine to use
39
39
 
40
+ <a id="r-shell"></a>
41
+ ## Dealing with the R Shell Engine
42
+
43
+ The ${ctx.link(shell_1.RShell)} engine is the original engine of flowR and is still available today.
44
+ It provides a powerful interface to the R interpreter, allowing for complex interactions and the execution of R code.
45
+ There are two interfaces available:
46
+
47
+ * The ${ctx.link(shell_1.RShell)} which is asynchronous and allows for non-blocking interactions with the R interpreter. This is the default engine.
48
+ * The ${ctx.link(shell_executor_1.RShellExecutor)} which is synchronous and blocks the execution until the R code is executed. This can be useful for certain use cases where you want to ensure that the R code is executed before proceeding with the analysis.
49
+
50
+ Please note, that these classes are available to you even if you do not use/enable the R shell engine.
51
+ The selection and preparation of the engine just reflects what the flowR analysis will use.
52
+
40
53
  <a id="tree-sitter"></a>
41
54
  ## Dealing with the Tree-Sitter Engine
42
55
 
@@ -59,6 +72,11 @@ you first must build the new wasm file. For this you have to:
59
72
  3. Pass the \`tree-sitter-r.wasm\` to flowR.
60
73
 
61
74
  For tree-sitter, please rely on the [releases](https://github.com/tree-sitter/tree-sitter/releases).
75
+
76
+ ${(0, doc_structure_1.block)({
77
+ type: 'NOTE',
78
+ content: 'The tree-sitter grammar may not be able to parse all valid R code due to some bugs in the parser grammar. In that case, please report these to the [tree-sitter-r repository](https://github.com/r-lib/tree-sitter-r).'
79
+ })}
62
80
  `;
63
81
  }
64
82
  }
@@ -200,7 +200,7 @@ ${await (0, doc_repl_1.documentReplSession)(parser, [{
200
200
  For more information on the available queries, please check out the ${ctx.linkPage('wiki/Query API', 'Query API')}.
201
201
  `;
202
202
  }
203
- function explainConfigFile() {
203
+ function explainConfigFile(ctx) {
204
204
  return `
205
205
 
206
206
  When running _flowR_, you may want to specify some behaviors with a dedicated configuration file.
@@ -211,6 +211,8 @@ Within the REPL this works by running the following:
211
211
 
212
212
  ${(0, doc_code_1.codeBlock)('shell', ':query @config')}
213
213
 
214
+ To work with the ${ctx.link(config_1.FlowrConfig)} you can use the provided helper objects alongside its methods like
215
+ ${ctx.linkO(config_1.FlowrConfig, 'amend')}.
214
216
  The following summarizes the configuration options:
215
217
 
216
218
  - \`ignoreSourceCalls\`: If set to \`true\`, _flowR_ will ignore source calls when analyzing the code, i.e., ignoring the inclusion of other files.
@@ -298,7 +300,7 @@ ${(0, doc_code_1.codeBlock)('json', JSON.stringify({
298
300
 
299
301
  <summary style='color:gray'>Full Configuration-File Schema</summary>
300
302
 
301
- ${(0, schema_1.describeSchema)(config_1.flowrConfigFileSchema, ansi_1.markdownFormatter)}
303
+ ${(0, schema_1.describeSchema)(config_1.FlowrConfig.Schema, ansi_1.markdownFormatter)}
302
304
 
303
305
  </details>
304
306
 
@@ -331,7 +333,7 @@ ${await explainRepl(treeSitter, ctx)}
331
333
  <a id='configuring-flowr'></a>
332
334
  ## ⚙️ Configuring FlowR
333
335
 
334
- ${explainConfigFile()}
336
+ ${explainConfigFile(ctx)}
335
337
 
336
338
  <a id='writing-code'></a>
337
339
  ## ⚒️ Writing Code
@@ -46,12 +46,12 @@ function prettyPrintExpectedOutput(expected) {
46
46
  //
47
47
  lines = expected.trim().replace(/^\s*\[+\s*{*/m, '').replace(/\s*}*\s*]+\s*$/, '').split('\n').filter(l => l.trim() !== '');
48
48
  /* take the indentation of the last line and remove it from all but the first: */
49
- const indentation = lines[lines.length - 1].match(/^\s*/)?.[0] ?? '';
49
+ const indentation = lines.at(-1)?.match(/^\s*/)?.[0] ?? '';
50
50
  return lines.map((line, i) => {
51
51
  if (i === 0) {
52
52
  return line;
53
53
  }
54
- return line.replace(new RegExp('^' + indentation, 'g'), '');
54
+ return line.replaceAll(new RegExp('^' + indentation, 'g'), '');
55
55
  }).join('\n');
56
56
  }
57
57
  function buildSamplesFromLinterTestCases(_parser, testFile) {
@@ -236,7 +236,7 @@ We use tags to categorize linting rules for users. The following tags are availa
236
236
  | Tag/Badge&emsp;&emsp; | Description |
237
237
  | --- | :-- |
238
238
  ${Object.entries(linter_tags_1.LintingRuleTag).map(([name, tag]) => {
239
- return `| <a id="${tag}"></a> ${(makeTagBadge(tag, tagTypes.info))} | ${(0, doc_types_1.getDocumentationForType)('LintingRuleTag::' + name, tagTypes.info).replaceAll(/\n/g, ' ')} (rule${getAllLintingRulesWithTag(tag).length === 1 ? '' : 's'}: ${(0, strings_1.joinWithLast)(getAllLintingRulesWithTag(tag).map(l => linkToRule(l))) || '_none_'}) | `;
239
+ return `| <a id="${tag}"></a> ${(makeTagBadge(tag, tagTypes.info))} | ${(0, doc_types_1.getDocumentationForType)('LintingRuleTag::' + name, tagTypes.info).replaceAll('\n', ' ')} (rule${getAllLintingRulesWithTag(tag).length === 1 ? '' : 's'}: ${(0, strings_1.joinWithLast)(getAllLintingRulesWithTag(tag).map(l => linkToRule(l))) || '_none_'}) | `;
240
240
  }).join('\n')}
241
241
 
242
242
  ${(0, doc_structure_1.section)('Certainty', 2, 'certainty')}
@@ -248,14 +248,14 @@ ${(0, doc_structure_1.section)('Rule Certainty', 3, 'rule-certainty')}
248
248
  | Rule Certainty | Description |
249
249
  | -------------- | :---------- |
250
250
  ${Object.entries(linter_format_1.LintingRuleCertainty).map(([name, certainty]) => {
251
- return `| <a id="${certainty}"></a> \`${certainty}\` | ${(0, doc_types_1.getDocumentationForType)('LintingRuleCertainty::' + name, tagTypes.info).replaceAll(/\n/g, ' ')} (rule${getAllLintingRulesWitCertainty(certainty).length === 1 ? '' : 's'}: ${(0, strings_1.joinWithLast)(getAllLintingRulesWitCertainty(certainty).map(l => linkToRule(l))) || '_none_'}) |`;
251
+ return `| <a id="${certainty}"></a> \`${certainty}\` | ${(0, doc_types_1.getDocumentationForType)('LintingRuleCertainty::' + name, tagTypes.info).replaceAll('\n', ' ')} (rule${getAllLintingRulesWitCertainty(certainty).length === 1 ? '' : 's'}: ${(0, strings_1.joinWithLast)(getAllLintingRulesWitCertainty(certainty).map(l => linkToRule(l))) || '_none_'}) |`;
252
252
  }).join('\n')}
253
253
 
254
254
  ${(0, doc_structure_1.section)('Result Certainty', 3, 'result-certainty')}
255
255
 
256
256
  | Result Certainty | Description |
257
257
  | ---------------- | :---------- |
258
- ${Object.entries(linter_format_1.LintingResultCertainty).map(([name, certainty]) => `| <a id="${certainty}"></a> \`${certainty}\` | ${(0, doc_types_1.getDocumentationForType)('LintingResultCertainty::' + name, tagTypes.info).replaceAll(/\n/g, ' ')} |`).join('\n')}
258
+ ${Object.entries(linter_format_1.LintingResultCertainty).map(([name, certainty]) => `| <a id="${certainty}"></a> \`${certainty}\` | ${(0, doc_types_1.getDocumentationForType)('LintingResultCertainty::' + name, tagTypes.info).replaceAll('\n', ' ')} |`).join('\n')}
259
259
 
260
260
  `.trim();
261
261
  }
@@ -47,17 +47,50 @@ type StaticKeys<T> = T extends {
47
47
  prototype: infer P;
48
48
  } ? Exclude<keyof T, keyof P> : never;
49
49
  export declare const ConstantWikiLinkInfo: {
50
- readonly 'flowr:npm': "https://www.npmjs.com/package/@eagleoutice/flowr";
51
- readonly 'flowr:github': string;
52
- readonly 'flowr:wiki': "https://github.com/flowr-analysis/flowr/wiki";
53
- readonly 'flowr:docker': "https://hub.docker.com/r/eagleoutice/flowr";
54
- readonly 'flowr:vscode': "https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr";
55
- readonly 'flowr:positron': "https://open-vsx.org/extension/code-inspect/vscode-flowr";
56
- readonly 'flowr:rstudio-addin': "https://github.com/flowr-analysis/rstudio-addin-flowr";
57
- readonly 'flowr:radapter': "https://github.com/flowr-analysis/flowr-r-adapter";
58
- readonly 'flowr:benchmarks': "https://flowr-analysis.github.io/flowr/wiki/stats/benchmark";
59
- readonly 'flowr:docs': "https://flowr-analysis.github.io/flowr/docs";
60
- readonly 'flowr:zenodo': "https://zenodo.org/doi/10.5281/zenodo.13319290";
50
+ readonly 'flowr:npm': {
51
+ readonly url: "https://www.npmjs.com/package/@eagleoutice/flowr";
52
+ readonly name: "flowR on npm";
53
+ };
54
+ readonly 'flowr:github': {
55
+ readonly url: string;
56
+ readonly name: "flowR's GitHub";
57
+ };
58
+ readonly 'flowr:wiki': {
59
+ readonly url: "https://github.com/flowr-analysis/flowr/wiki";
60
+ readonly name: "flowR's wiki";
61
+ };
62
+ readonly 'flowr:docker': {
63
+ readonly url: "https://hub.docker.com/r/eagleoutice/flowr";
64
+ readonly name: "flowR's Docker Image";
65
+ };
66
+ readonly 'flowr:vscode': {
67
+ readonly url: "https://marketplace.visualstudio.com/items?itemName=code-inspect.vscode-flowr";
68
+ readonly name: "flowR extension for VS Code";
69
+ };
70
+ readonly 'flowr:positron': {
71
+ readonly url: "https://open-vsx.org/extension/code-inspect/vscode-flowr";
72
+ readonly name: "flowR extension for Positron";
73
+ };
74
+ readonly 'flowr:rstudio-addin': {
75
+ readonly url: "https://github.com/flowr-analysis/rstudio-addin-flowr";
76
+ readonly name: "flowR RStudio Addin";
77
+ };
78
+ readonly 'flowr:radapter': {
79
+ readonly url: "https://github.com/flowr-analysis/flowr-r-adapter";
80
+ readonly name: "flowR R Adapter";
81
+ };
82
+ readonly 'flowr:benchmarks': {
83
+ readonly url: "https://flowr-analysis.github.io/flowr/wiki/stats/benchmark";
84
+ readonly name: "flowR benchmark page";
85
+ };
86
+ readonly 'flowr:docs': {
87
+ readonly url: "https://flowr-analysis.github.io/flowr/docs";
88
+ readonly name: "flowR code docs";
89
+ };
90
+ readonly 'flowr:zenodo': {
91
+ readonly url: "https://zenodo.org/doi/10.5281/zenodo.13319290";
92
+ readonly name: "flowR on Zenodo";
93
+ };
61
94
  };
62
95
  /**
63
96
  * Provides methods to generate links, code snippets, and documentation for code elements.
@@ -23,17 +23,17 @@ function getNameFromElementIdOrRef(element) {
23
23
  }
24
24
  }
25
25
  exports.ConstantWikiLinkInfo = {
26
- 'flowr:npm': doc_files_1.FlowrNpmRef,
27
- 'flowr:github': doc_files_1.FlowrGithubRef,
28
- 'flowr:wiki': doc_files_1.FlowrWikiBaseRef,
29
- 'flowr:docker': doc_files_1.FlowrDockerRef,
30
- 'flowr:vscode': doc_files_1.FlowrVsCode,
31
- 'flowr:positron': doc_files_1.FlowrPositron,
32
- 'flowr:rstudio-addin': doc_files_1.FlowrRStudioAddin,
33
- 'flowr:radapter': doc_files_1.FlowrRAdapter,
34
- 'flowr:benchmarks': 'https://flowr-analysis.github.io/flowr/wiki/stats/benchmark',
35
- 'flowr:docs': 'https://flowr-analysis.github.io/flowr/docs',
36
- 'flowr:zenodo': 'https://zenodo.org/doi/10.5281/zenodo.13319290'
26
+ 'flowr:npm': { url: doc_files_1.FlowrNpmRef, name: 'flowR on npm' },
27
+ 'flowr:github': { url: doc_files_1.FlowrGithubRef, name: 'flowR\'s GitHub' },
28
+ 'flowr:wiki': { url: doc_files_1.FlowrWikiBaseRef, name: 'flowR\'s wiki' },
29
+ 'flowr:docker': { url: doc_files_1.FlowrDockerRef, name: 'flowR\'s Docker Image' },
30
+ 'flowr:vscode': { url: doc_files_1.FlowrVsCode, name: 'flowR extension for VS Code' },
31
+ 'flowr:positron': { url: doc_files_1.FlowrPositron, name: 'flowR extension for Positron' },
32
+ 'flowr:rstudio-addin': { url: doc_files_1.FlowrRStudioAddin, name: 'flowR RStudio Addin' },
33
+ 'flowr:radapter': { url: doc_files_1.FlowrRAdapter, name: 'flowR R Adapter' },
34
+ 'flowr:benchmarks': { url: 'https://flowr-analysis.github.io/flowr/wiki/stats/benchmark', name: 'flowR benchmark page' },
35
+ 'flowr:docs': { url: 'https://flowr-analysis.github.io/flowr/docs', name: 'flowR code docs' },
36
+ 'flowr:zenodo': { url: 'https://zenodo.org/doi/10.5281/zenodo.13319290', name: 'flowR on Zenodo' },
37
37
  };
38
38
  /**
39
39
  * Creates a wiki context for generating documentation for code elements.
@@ -49,8 +49,7 @@ exports.ConstantWikiLinkInfo = {
49
49
  */
50
50
  function makeDocContextForTypes(shell, ...rootFolders) {
51
51
  if (rootFolders.length === 0) {
52
- rootFolders.push(path_1.default.resolve(__dirname, '../../../src'));
53
- rootFolders.push(path_1.default.resolve(__dirname, '../../../test/functionality'));
52
+ rootFolders.push(path_1.default.resolve(__dirname, '../../../src'), path_1.default.resolve(__dirname, '../../../test/functionality'));
54
53
  }
55
54
  const { info, program } = (0, doc_types_1.getTypesFromFolder)({ rootFolder: rootFolders, typeNameForMermaid: undefined });
56
55
  return {
@@ -100,15 +99,18 @@ function makeDocContextForTypes(shell, ...rootFolders) {
100
99
  });
101
100
  },
102
101
  linkPage(pageName, linkText, segment) {
103
- const text = linkText ?? pageName.split('/').pop() ?? pageName;
104
102
  let link;
103
+ let text = linkText;
105
104
  if (pageName in exports.ConstantWikiLinkInfo) {
106
- link = exports.ConstantWikiLinkInfo[pageName];
105
+ const i = exports.ConstantWikiLinkInfo[pageName];
106
+ link = i.url;
107
+ text ??= i.name;
107
108
  }
108
109
  else {
109
- link = `${doc_files_1.FlowrWikiBaseRef}/${pageName.toLowerCase().replace(/ /g, '-')}`;
110
+ link = `${doc_files_1.FlowrGithubRef}/${pageName.toLowerCase().replaceAll(' ', '-')}`;
110
111
  }
111
- return `[${text}](${link}${segment ? `#${segment}` : ''})`;
112
+ text ??= pageName.split('/').pop() ?? pageName;
113
+ return `[${text}](${link}${segment ? '#' + segment : ''})`;
112
114
  },
113
115
  linkCode(path, lineNumber) {
114
116
  const lnk = lineNumber ? `${path.toString()}#L${lineNumber}` : path.toString();
package/engines.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { type FlowrConfigOptions, type KnownEngines } from './config';
1
+ import { FlowrConfig, type KnownEngines } from './config';
2
2
  /**
3
3
  * Retrieve all requested engine instance.
4
4
  * Please make sure that if this includes the R engine, that you properly shut it down again!
5
5
  */
6
- export declare function retrieveEngineInstances(config: FlowrConfigOptions, defaultOnly?: boolean): Promise<{
6
+ export declare function retrieveEngineInstances(config: FlowrConfig, defaultOnly?: boolean): Promise<{
7
7
  engines: KnownEngines;
8
8
  default: keyof KnownEngines;
9
9
  }>;
package/engines.js CHANGED
@@ -12,9 +12,9 @@ const log_1 = require("./util/log");
12
12
  */
13
13
  async function retrieveEngineInstances(config, defaultOnly = false) {
14
14
  const engines = {};
15
- if ((0, config_1.getEngineConfig)(config, 'r-shell') && (!defaultOnly || config.defaultEngine === 'r-shell')) {
15
+ if (config_1.FlowrConfig.getForEngine(config, 'r-shell') && (!defaultOnly || config.defaultEngine === 'r-shell')) {
16
16
  // we keep an active shell session to allow other parse investigations :)
17
- engines['r-shell'] = new shell_1.RShell((0, config_1.getEngineConfig)(config, 'r-shell'), {
17
+ engines['r-shell'] = new shell_1.RShell(config_1.FlowrConfig.getForEngine(config, 'r-shell'), {
18
18
  revive: 2 /* RShellReviveOptions.Always */,
19
19
  onRevive: (code, signal) => {
20
20
  const signalText = signal == null ? '' : ` and signal ${signal}`;
@@ -23,8 +23,8 @@ async function retrieveEngineInstances(config, defaultOnly = false) {
23
23
  }
24
24
  });
25
25
  }
26
- if ((0, config_1.getEngineConfig)(config, 'tree-sitter') && (!defaultOnly || config.defaultEngine === 'tree-sitter')) {
27
- await tree_sitter_executor_1.TreeSitterExecutor.initTreeSitter((0, config_1.getEngineConfig)(config, 'tree-sitter'));
26
+ if (config_1.FlowrConfig.getForEngine(config, 'tree-sitter') && (!defaultOnly || config.defaultEngine === 'tree-sitter')) {
27
+ await tree_sitter_executor_1.TreeSitterExecutor.initTreeSitter(config_1.FlowrConfig.getForEngine(config, 'tree-sitter'));
28
28
  engines['tree-sitter'] = new tree_sitter_executor_1.TreeSitterExecutor();
29
29
  }
30
30
  let defaultEngine = config.defaultEngine;
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DATA_FRAME_ACCESS_VALIDATION = void 0;
4
4
  const shape_inference_1 = require("../../abstract-interpretation/data-frame/shape-inference");
5
5
  const satisfiable_domain_1 = require("../../abstract-interpretation/domains/satisfiable-domain");
6
- const config_1 = require("../../config");
7
6
  const cfg_kind_1 = require("../../project/cfg-kind");
8
7
  const type_1 = require("../../r-bridge/lang-4.x/ast/model/type");
9
8
  const flowr_search_builder_1 = require("../../search/flowr-search-builder");
@@ -13,13 +12,14 @@ const range_1 = require("../../util/range");
13
12
  const linter_format_1 = require("../linter-format");
14
13
  const linter_tags_1 = require("../linter-tags");
15
14
  const identifier_1 = require("../../dataflow/environments/identifier");
15
+ const config_1 = require("../../config");
16
16
  exports.DATA_FRAME_ACCESS_VALIDATION = {
17
17
  createSearch: () => flowr_search_builder_1.Q.all().with(search_enrichers_1.Enrichment.CallTargets, { onlyBuiltin: true }),
18
18
  processSearchResult: async (elements, config, data) => {
19
19
  let ctx = data.analyzer.inspectContext();
20
20
  ctx = {
21
21
  ...ctx,
22
- config: (0, config_1.amendConfig)(data.analyzer.flowrConfig, flowrConfig => {
22
+ config: config_1.FlowrConfig.amend(data.analyzer.flowrConfig, flowrConfig => {
23
23
  if (config.readLoadedData !== undefined) {
24
24
  flowrConfig.abstractInterpretation.dataFrame.readLoadedData.readExternalFiles = config.readLoadedData;
25
25
  }
@@ -61,7 +61,7 @@ exports.DATA_FRAME_ACCESS_VALIDATION = {
61
61
  .map(({ nodeId, operand, ...accessed }) => ({
62
62
  ...accessed,
63
63
  node: data.normalize.idMap.get(nodeId),
64
- operand: operand !== undefined ? data.normalize.idMap.get(operand) : undefined,
64
+ operand: operand === undefined ? undefined : data.normalize.idMap.get(operand),
65
65
  }))
66
66
  .map(({ node, operand, ...accessed }) => ({
67
67
  ...accessed,
@@ -76,10 +76,10 @@ exports.DATA_FRAME_ACCESS_VALIDATION = {
76
76
  prettyPrint: {
77
77
  [linter_format_1.LintingPrettyPrintContext.Query]: result => `Access of ${result.type} ` +
78
78
  (typeof result.accessed === 'string' ? `"${result.accessed}"` : result.accessed) + ' ' +
79
- (result.operand !== undefined ? `of \`${result.operand}\`` : `at \`${result.access}\``) + ` at ${range_1.SourceRange.format(result.range)}`,
79
+ (result.operand === undefined ? `at \`${result.access}\`` : `of \`${result.operand}\``) + ` at ${range_1.SourceRange.format(result.range)}`,
80
80
  [linter_format_1.LintingPrettyPrintContext.Full]: result => `Accessed ${result.type} ` +
81
81
  (typeof result.accessed === 'string' ? `"${result.accessed}"` : result.accessed) + ' does not exist ' +
82
- (result.operand !== undefined ? `in \`${result.operand}\`` : `at \`${result.access}\``) + ` at ${range_1.SourceRange.format(result.range)}`
82
+ (result.operand === undefined ? `at \`${result.access}\`` : `in \`${result.operand}\``) + ` at ${range_1.SourceRange.format(result.range)}`
83
83
  },
84
84
  info: {
85
85
  name: 'Dataframe Access Validation',
@@ -53,7 +53,7 @@ export declare function getMostUsedCasing(symbols: {
53
53
  /**
54
54
  * Attempts to fix the casing of the given identifier to match the provided convention.
55
55
  */
56
- export declare function fixCasing(identifier: string, convention: CasingConvention): string | undefined;
56
+ export declare function fixCasing(identifier: string, convention: CasingConvention, ignorePrefix?: string): string | undefined;
57
57
  /**
58
58
  * Creates quick fixes for renaming all references to the given node to match the provided replacement.
59
59
  */
@@ -91,11 +91,15 @@ function getMostUsedCasing(symbols) {
91
91
  /**
92
92
  * Attempts to fix the casing of the given identifier to match the provided convention.
93
93
  */
94
- function fixCasing(identifier, convention) {
94
+ function fixCasing(identifier, convention, ignorePrefix) {
95
95
  if (!containsAlpha(identifier)) {
96
96
  return undefined;
97
97
  }
98
- const tokens = identifier.split(/(?=[A-Z])|_/).map(s => s.toLowerCase());
98
+ if (ignorePrefix) {
99
+ identifier = identifier.replace(new RegExp(`^(${ignorePrefix})`), '');
100
+ }
101
+ const splitOn = identifier.includes('_') ? /_/ : /(?=[A-Z])/;
102
+ const tokens = identifier.split(splitOn).map(s => s.toLowerCase());
99
103
  const firstUp = (s) => {
100
104
  if (s.length < 1) {
101
105
  return s.toUpperCase();
@@ -167,7 +171,7 @@ exports.NAMING_CONVENTION = {
167
171
  const results = symbols
168
172
  .filter(m => (m.detectedCasing !== casing) && (!config.ignoreNonAlpha || containsAlpha(m.name)))
169
173
  .map(({ id, ...m }) => {
170
- const fix = fixCasing(m.name, casing);
174
+ const fix = fixCasing(m.name, casing, config.ignorePrefix);
171
175
  return {
172
176
  ...m,
173
177
  involvedId: id,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eagleoutice/flowr",
3
- "version": "2.9.11",
3
+ "version": "2.9.13",
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": {
@@ -178,6 +178,7 @@
178
178
  "@types/n-readlines": "^1.0.6",
179
179
  "@types/n3": "^1.26.0",
180
180
  "@types/object-hash": "^3.0.6",
181
+ "@types/object-path": "^0.11.4",
181
182
  "@types/seedrandom": "^3.0.8",
182
183
  "@types/semver": "^7.7.0",
183
184
  "@types/tmp": "^0.2.6",
@@ -212,6 +213,7 @@
212
213
  "n-readlines": "^1.0.3",
213
214
  "n3": "^1.26.0",
214
215
  "object-hash": "^3.0.0",
216
+ "object-path": "^0.11.8",
215
217
  "object-sizeof": "^2.6.5",
216
218
  "rotating-file-stream": "^3.2.8",
217
219
  "seedrandom": "^3.0.5",
@@ -2,7 +2,7 @@ import { FlowrAnalyzerFilesContext, type RAnalysisRequest, type ReadOnlyFlowrAna
2
2
  import { FlowrAnalyzerDependenciesContext, type ReadOnlyFlowrAnalyzerDependenciesContext } from './flowr-analyzer-dependencies-context';
3
3
  import { type FlowrAnalyzerPlugin, PluginType } from '../plugins/flowr-analyzer-plugin';
4
4
  import type { fileProtocol, RParseRequestFromFile, RParseRequests } from '../../r-bridge/retriever';
5
- import type { FlowrConfigOptions } from '../../config';
5
+ import { FlowrConfig } from '../../config';
6
6
  import type { FlowrFileProvider } from './flowr-file';
7
7
  import type { ReadOnlyFlowrAnalyzerEnvironmentContext } from './flowr-analyzer-environment-context';
8
8
  import { FlowrAnalyzerEnvironmentContext } from './flowr-analyzer-environment-context';
@@ -34,7 +34,7 @@ export interface ReadOnlyFlowrAnalyzerContext {
34
34
  /**
35
35
  * The configuration options used by the analyzer.
36
36
  */
37
- readonly config: FlowrConfigOptions;
37
+ readonly config: FlowrConfig;
38
38
  /**
39
39
  * Run all resolution steps that can be done before the main analysis run.
40
40
  */
@@ -58,8 +58,8 @@ export declare class FlowrAnalyzerContext implements ReadOnlyFlowrAnalyzerContex
58
58
  readonly deps: FlowrAnalyzerDependenciesContext;
59
59
  readonly env: FlowrAnalyzerEnvironmentContext;
60
60
  private _analyzer;
61
- readonly config: FlowrConfigOptions;
62
- constructor(config: FlowrConfigOptions, plugins: ReadonlyMap<PluginType, readonly FlowrAnalyzerPlugin[]>);
61
+ readonly config: FlowrConfig;
62
+ constructor(config: FlowrConfig, plugins: ReadonlyMap<PluginType, readonly FlowrAnalyzerPlugin[]>);
63
63
  /**
64
64
  * Provides the analyzer associated with this context, if any.
65
65
  * This is usually set when the context is used within an analyzer instance.
@@ -91,7 +91,7 @@ export declare class FlowrAnalyzerContext implements ReadOnlyFlowrAnalyzerContex
91
91
  * @see {@link requestFromInput} - for details on how inputs are processed into requests.
92
92
  * @see {@link contextFromSources} - to create a context from source code strings directly.
93
93
  */
94
- export declare function contextFromInput(input: `${typeof fileProtocol}${string}` | string | readonly string[] | RParseRequests, config?: FlowrConfigOptions, plugins?: FlowrAnalyzerPlugin[]): FlowrAnalyzerContext;
94
+ export declare function contextFromInput(input: `${typeof fileProtocol}${string}` | string | readonly string[] | RParseRequests, config?: FlowrConfig, plugins?: FlowrAnalyzerPlugin[]): FlowrAnalyzerContext;
95
95
  /**
96
96
  * Create a {@link FlowrAnalyzerContext} from a set of source code strings.
97
97
  * @param sources - A record mapping file paths to their source code content.
@@ -100,4 +100,4 @@ export declare function contextFromInput(input: `${typeof fileProtocol}${string}
100
100
  * @see {@link contextFromInput} - to create a context from input requests.
101
101
  * @see {@link FlowrInlineTextFile} - to create inline text files for the sources.
102
102
  */
103
- export declare function contextFromSources(sources: Record<string, string>, config?: FlowrConfigOptions, plugins?: FlowrAnalyzerPlugin[]): FlowrAnalyzerContext;
103
+ export declare function contextFromSources(sources: Record<string, string>, config?: FlowrConfig, plugins?: FlowrAnalyzerPlugin[]): FlowrAnalyzerContext;
@@ -93,7 +93,7 @@ exports.FlowrAnalyzerContext = FlowrAnalyzerContext;
93
93
  * @see {@link requestFromInput} - for details on how inputs are processed into requests.
94
94
  * @see {@link contextFromSources} - to create a context from source code strings directly.
95
95
  */
96
- function contextFromInput(input, config = config_1.defaultConfigOptions, plugins) {
96
+ function contextFromInput(input, config = config_1.FlowrConfig.default(), plugins) {
97
97
  const context = new FlowrAnalyzerContext(config, (0, arrays_1.arraysGroupBy)(plugins ?? [], (p) => p.type));
98
98
  if (typeof input === 'string' || Array.isArray(input) && input.every(i => typeof i === 'string')) {
99
99
  const requests = (0, retriever_1.requestFromInput)(input);
@@ -113,7 +113,7 @@ function contextFromInput(input, config = config_1.defaultConfigOptions, plugins
113
113
  * @see {@link contextFromInput} - to create a context from input requests.
114
114
  * @see {@link FlowrInlineTextFile} - to create inline text files for the sources.
115
115
  */
116
- function contextFromSources(sources, config = config_1.defaultConfigOptions, plugins) {
116
+ function contextFromSources(sources, config = config_1.FlowrConfig.default(), plugins) {
117
117
  const context = new FlowrAnalyzerContext(config, (0, arrays_1.arraysGroupBy)(plugins ?? [], (p) => p.type));
118
118
  for (const [p, c] of Object.entries(sources)) {
119
119
  context.addFile(new flowr_file_1.FlowrInlineTextFile(p, c));
@@ -59,7 +59,7 @@ export interface ReadOnlyFlowrAnalyzerFilesContext {
59
59
  /**
60
60
  * Check if the context has a file with the given path.
61
61
  * Please note, that this may also check the file system, depending on the configuration
62
- * (see {@link FlowrConfigOptions.project.resolveUnknownPathsOnDisk}).
62
+ * (see {@link FlowrConfig.project.resolveUnknownPathsOnDisk}).
63
63
  * @param path - The path to the file.
64
64
  *
65
65
  * If you do not know the exact path or, e.g., casing of the file, use {@link exists} instead.
@@ -70,7 +70,7 @@ export interface ReadOnlyFlowrAnalyzerFilesContext {
70
70
  * @param path - The path to the file.
71
71
  * @param ignoreCase - Whether to ignore case when checking for the file.
72
72
  *
73
- * Please note that this method checks the file system based on the configuration (see {@link FlowrConfigOptions.project.resolveUnknownPathsOnDisk}).
73
+ * Please note that this method checks the file system based on the configuration (see {@link FlowrConfig.project.resolveUnknownPathsOnDisk}).
74
74
  * @returns The actual path of the file if it exists, otherwise `undefined`.
75
75
  */
76
76
  exists(path: string, ignoreCase: boolean): string | undefined;
@@ -129,19 +129,39 @@ class FlowrAnalyzerFilesContext extends abstract_flowr_analyzer_context_1.Abstra
129
129
  if (!ignoreCase) {
130
130
  return this.hasFile(p) ? p : undefined;
131
131
  }
132
+ if (this.hasFile(p)) {
133
+ return p;
134
+ }
132
135
  // walk the directory and find the first match
133
136
  const dir = path_1.default.dirname(p);
134
- const file = path_1.default.basename(p);
137
+ const file = path_1.default.basename(p).toLowerCase();
135
138
  // try to find in local known files first
136
- const localFound = Array.from(this.files.keys()).find(f => {
137
- return path_1.default.dirname(f) === dir && path_1.default.basename(f).toLowerCase() === file.toLowerCase();
138
- });
139
- if (localFound) {
140
- return localFound;
139
+ for (const f of this.files.keys()) {
140
+ if (path_1.default.dirname(f).toLowerCase() !== dir.toLowerCase()) {
141
+ continue;
142
+ }
143
+ const lf = path_1.default.basename(f).toLowerCase();
144
+ if (file === lf) {
145
+ return f;
146
+ }
141
147
  }
142
148
  if (this.ctx.config.project.resolveUnknownPathsOnDisk) {
143
- const files = fs_1.default.readdirSync(dir);
144
- const found = files.find(f => f.toLowerCase() === file.toLowerCase());
149
+ let files;
150
+ if (fs_1.default.existsSync(dir)) {
151
+ files = fs_1.default.readdirSync(dir);
152
+ }
153
+ else {
154
+ // try to find a dir in parent
155
+ const parentDir = path_1.default.dirname(dir);
156
+ if (fs_1.default.existsSync(parentDir)) {
157
+ const parentFiles = fs_1.default.readdirSync(parentDir);
158
+ const foundDir = parentFiles.find(f => f.toLowerCase() === path_1.default.basename(dir).toLowerCase());
159
+ if (foundDir) {
160
+ files = fs_1.default.readdirSync(path_1.default.join(parentDir, foundDir));
161
+ }
162
+ }
163
+ }
164
+ const found = files?.find(f => f.toLowerCase() === file);
145
165
  return found ? path_1.default.join(dir, found) : undefined;
146
166
  }
147
167
  return undefined;
@@ -1,10 +1,11 @@
1
- import { type EngineConfig, type FlowrConfigOptions } from '../config';
2
- import type { DeepWritable } from 'ts-essentials';
1
+ import { type EngineConfig, FlowrConfig } from '../config';
2
+ import type { DeepWritable, PathValue } from 'ts-essentials';
3
3
  import { FlowrAnalyzer } from './flowr-analyzer';
4
4
  import type { KnownParser } from '../r-bridge/parser';
5
5
  import type { FlowrAnalyzerPlugin } from './plugins/flowr-analyzer-plugin';
6
6
  import type { NormalizeRequiredInput } from '../core/steps/all/core/10-normalize';
7
7
  import type { BuiltInFlowrPluginName, PluginToRegister } from './plugins/plugin-registry';
8
+ import type { AutocompletablePaths } from '../util/objects';
8
9
  /**
9
10
  * Builder for the {@link FlowrAnalyzer}, use it to configure all analysis aspects before creating the analyzer instance
10
11
  * with {@link FlowrAnalyzerBuilder#build|`.build()`} or {@link FlowrAnalyzerBuilder#buildSync|`.buildSync()`}.
@@ -32,7 +33,7 @@ export declare class FlowrAnalyzerBuilder {
32
33
  private flowrConfig;
33
34
  private parser?;
34
35
  private input?;
35
- private plugins;
36
+ private readonly plugins;
36
37
  /**
37
38
  * Creates a new builder for the {@link FlowrAnalyzer}.
38
39
  * By default, the standard set of plugins as returned by {@link FlowrAnalyzerPluginDefaults} are registered.
@@ -44,15 +45,18 @@ export declare class FlowrAnalyzerBuilder {
44
45
  constructor(withDefaultPlugins?: boolean);
45
46
  /**
46
47
  * Apply an amendment to the configuration the builder currently holds.
47
- * Per default, the {@link defaultConfigOptions} are used.
48
+ * This is mostly intended for more complex logic to transform the config.
49
+ * Please consider using {@link FlowrAnalyzerBuilder.configure} to set/amend individual values
50
+ * Per default, the value returned by {@link FlowrConfig.default} is used.
48
51
  * @param func - Receives the current configuration of the builder and allows for amendment.
49
52
  */
50
- amendConfig(func: (config: DeepWritable<FlowrConfigOptions>) => FlowrConfigOptions | void): this;
53
+ amendConfig(func: (config: DeepWritable<FlowrConfig>) => FlowrConfig | void): this;
51
54
  /**
52
55
  * Overwrite the configuration used by the resulting analyzer.
53
56
  * @param config - The new configuration.
54
57
  */
55
- setConfig(config: FlowrConfigOptions): this;
58
+ setConfig(config: FlowrConfig): this;
59
+ configure<K extends AutocompletablePaths<FlowrConfig>>(key: K, value: PathValue<FlowrConfig, K>): this;
56
60
  /**
57
61
  * Set the parser instance used by the analyzer.
58
62
  * This is an alternative to {@link FlowrAnalyzerBuilder#setEngine} if you already have a parser instance.
@@ -33,7 +33,7 @@ const plugin_registry_1 = require("./plugins/plugin-registry");
33
33
  * @see https://github.com/flowr-analysis/flowr/wiki/Analyzer
34
34
  */
35
35
  class FlowrAnalyzerBuilder {
36
- flowrConfig = (0, config_1.cloneConfig)(config_1.defaultConfigOptions);
36
+ flowrConfig = config_1.FlowrConfig.default();
37
37
  parser;
38
38
  input;
39
39
  plugins = new Map();
@@ -52,12 +52,14 @@ class FlowrAnalyzerBuilder {
52
52
  }
53
53
  /**
54
54
  * Apply an amendment to the configuration the builder currently holds.
55
- * Per default, the {@link defaultConfigOptions} are used.
55
+ * This is mostly intended for more complex logic to transform the config.
56
+ * Please consider using {@link FlowrAnalyzerBuilder.configure} to set/amend individual values
57
+ * Per default, the value returned by {@link FlowrConfig.default} is used.
56
58
  * @param func - Receives the current configuration of the builder and allows for amendment.
57
59
  */
58
60
  // eslint-disable-next-line @typescript-eslint/no-invalid-void-type
59
61
  amendConfig(func) {
60
- this.flowrConfig = (0, config_1.amendConfig)(this.flowrConfig, func);
62
+ this.flowrConfig = config_1.FlowrConfig.amend(this.flowrConfig, func);
61
63
  return this;
62
64
  }
63
65
  /**
@@ -68,6 +70,13 @@ class FlowrAnalyzerBuilder {
68
70
  this.flowrConfig = config;
69
71
  return this;
70
72
  }
73
+ /**
74
+ * Set a specific value in the configuration used by the resulting analyzer.
75
+ */
76
+ configure(key, value) {
77
+ config_1.FlowrConfig.setInConfigInPlace(this.flowrConfig, key, value);
78
+ return this;
79
+ }
71
80
  /**
72
81
  * Set the parser instance used by the analyzer.
73
82
  * This is an alternative to {@link FlowrAnalyzerBuilder#setEngine} if you already have a parser instance.
@@ -1,4 +1,4 @@
1
- import type { FlowrConfigOptions } from '../config';
1
+ import type { FlowrConfig } from '../config';
2
2
  import type { KnownParser, KnownParserInformation } from '../r-bridge/parser';
3
3
  import { type Queries, type QueryResults, type SupportedQueryTypes } from '../queries/query';
4
4
  import type { ControlFlowInformation } from '../control-flow/control-flow-graph';
@@ -139,7 +139,7 @@ export interface ReadonlyFlowrAnalysisProvider<Parser extends KnownParser = Know
139
139
  */
140
140
  runFull(force?: boolean): Promise<void>;
141
141
  /** This is the config used for the analyzer */
142
- flowrConfig: FlowrConfigOptions;
142
+ flowrConfig: FlowrConfig;
143
143
  }
144
144
  /**
145
145
  * Central class for conducting analyses with FlowR.
@@ -165,7 +165,7 @@ export declare class FlowrAnalyzer<Parser extends KnownParser = KnownParser> imp
165
165
  * @param cache - The caching layer to use for storing analysis results.
166
166
  */
167
167
  constructor(parser: Parser, ctx: FlowrAnalyzerContext, cache: FlowrAnalyzerCache<Parser>);
168
- get flowrConfig(): FlowrConfigOptions;
168
+ get flowrConfig(): FlowrConfig;
169
169
  context(): FlowrAnalyzerContext;
170
170
  parserInformation(): KnownParserInformation;
171
171
  inspectContext(): ReadOnlyFlowrAnalyzerContext;