@eagleoutice/flowr 2.8.11 → 2.8.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 (44) hide show
  1. package/README.md +23 -22
  2. package/control-flow/simple-visitor.js +3 -1
  3. package/dataflow/environments/default-builtin-config.d.ts +1 -1
  4. package/dataflow/environments/default-builtin-config.js +1 -1
  5. package/dataflow/extractor.js +1 -1
  6. package/dataflow/graph/graph.d.ts +1 -14
  7. package/dataflow/graph/graph.js +1 -10
  8. package/dataflow/internal/linker.d.ts +12 -0
  9. package/dataflow/internal/linker.js +24 -11
  10. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +5 -4
  11. package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +3 -2
  12. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +7 -4
  13. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +16 -10
  14. package/dataflow/internal/process/functions/call/built-in/built-in-get.js +1 -1
  15. package/dataflow/internal/process/functions/call/built-in/built-in-try-catch.js +3 -2
  16. package/dataflow/internal/process/functions/process-argument.js +2 -1
  17. package/dataflow/internal/process/functions/process-parameter.js +4 -3
  18. package/documentation/wiki-query.js +2 -3
  19. package/package.json +1 -1
  20. package/project/plugins/file-plugins/files/flowr-description-file.d.ts +19 -0
  21. package/project/plugins/file-plugins/files/flowr-description-file.js +43 -12
  22. package/project/plugins/loading-order-plugins/flowr-analyzer-loading-order-description-file-plugin.js +2 -5
  23. package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-description-file-plugin.js +5 -6
  24. package/queries/catalog/call-context-query/call-context-query-executor.d.ts +1 -1
  25. package/queries/catalog/call-context-query/call-context-query-executor.js +4 -3
  26. package/queries/catalog/call-context-query/call-context-query-format.d.ts +21 -1
  27. package/queries/catalog/call-context-query/call-context-query-format.js +15 -7
  28. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +11 -3
  29. package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +14 -1
  30. package/queries/catalog/call-context-query/identify-link-to-nested-call-relation.d.ts +12 -0
  31. package/queries/catalog/call-context-query/identify-link-to-nested-call-relation.js +30 -0
  32. package/queries/catalog/call-context-query/identify-link-to-relation.d.ts +10 -0
  33. package/queries/catalog/call-context-query/identify-link-to-relation.js +21 -0
  34. package/queries/catalog/dependencies-query/dependencies-query-executor.js +2 -1
  35. package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +11 -2
  36. package/queries/catalog/dependencies-query/dependencies-query-format.js +1 -1
  37. package/queries/catalog/dependencies-query/function-info/test-functions.js +146 -12
  38. package/queries/query.js +1 -1
  39. package/search/search-executor/search-enrichers.d.ts +8 -40
  40. package/search/search-executor/search-enrichers.js +17 -13
  41. package/search/search-executor/search-generators.js +5 -7
  42. package/search/search-executor/search-transformer.js +1 -7
  43. package/util/schema.js +6 -8
  44. package/util/version.js +1 -1
@@ -8,8 +8,13 @@ const r_author_1 = require("../../../../util/r-author");
8
8
  const args_1 = require("../../../../util/text/args");
9
9
  const r_license_1 = require("../../../../util/r-license");
10
10
  const package_1 = require("../../package-version-plugins/package");
11
+ const retriever_1 = require("../../../../r-bridge/retriever");
11
12
  /**
12
13
  * This decorates a text file and provides access to its content as a DCF (Debian Control File)-like structure.
14
+ * Please use the static {@link FlowrDescriptionFile.from} method to create instances of this class.
15
+ * To access description specific fields, use the provided methods like {@link license}, {@link authors}, {@link suggests}, and {@link collate}.
16
+ * These methods parse and return the relevant information in structured formats.
17
+ * To access raw fields, use the {@link content} method inherited from {@link FlowrFile}.
13
18
  */
14
19
  class FlowrDescriptionFile extends flowr_file_1.FlowrFile {
15
20
  wrapped;
@@ -59,10 +64,35 @@ class FlowrDescriptionFile extends flowr_file_1.FlowrFile {
59
64
  const parsedAuthors = authors?.flatMap(a => (0, r_author_1.parseTextualAuthorString)(a, [r_author_1.AuthorRole.Author])) ?? [];
60
65
  return parsedAuthors.concat(this.content().get('Maintainer')?.flatMap(m => (0, r_author_1.parseTextualAuthorString)(m, [r_author_1.AuthorRole.Creator])) ?? []);
61
66
  }
67
+ /**
68
+ * Returns the parsed suggested packages from the 'Suggests' field in the DESCRIPTION file.
69
+ */
62
70
  suggests() {
63
71
  const suggests = this.content().get('Suggests');
64
72
  return suggests ? parsePackagesWithVersions(suggests, 'package') : undefined;
65
73
  }
74
+ /**
75
+ * Returns the 'Collate' field from the DESCRIPTION file.
76
+ */
77
+ collate() {
78
+ const c = this.content().get('Collate');
79
+ // we join newlines, and then split quote sensitive:
80
+ return c ? (0, args_1.splitAtEscapeSensitive)(c.join(' '), true, ' ').map(s => (0, retriever_1.removeRQuotes)(s).trim()).filter(s => s.length > 0) : undefined;
81
+ }
82
+ /**
83
+ * Returns the parsed dependencies from the 'Depends' field in the DESCRIPTION file.
84
+ */
85
+ depends() {
86
+ const deps = this.content().get('Depends');
87
+ return deps ? parsePackagesWithVersions(deps, 'r') : undefined;
88
+ }
89
+ /**
90
+ * Returns the parsed imports from the 'Imports' field in the DESCRIPTION file.
91
+ */
92
+ imports() {
93
+ const imps = this.content().get('Imports');
94
+ return imps ? parsePackagesWithVersions(imps, 'package') : undefined;
95
+ }
66
96
  }
67
97
  exports.FlowrDescriptionFile = FlowrDescriptionFile;
68
98
  /**
@@ -117,25 +147,26 @@ function cleanValues(values) {
117
147
  .map(s => s.trim())
118
148
  .filter(s => s.length > 0);
119
149
  }
120
- const VersionRegex = /^([a-zA-Z0-9.]+)(?:\s*\(([><=~!]+)\s*([^)]+)\))?$/;
150
+ const VersionRegex = /([a-zA-Z0-9.]+)(?:\s*\(([><=~!]+)\s*([^)]+)\))?\s*/;
121
151
  /**
122
152
  * Parses package strings with optional version constraints into Package objects.
123
153
  * @param packageStrings - The package strings to parse
124
154
  * @param type - The type of the packages (e.g., 'r' or 'package')
125
155
  */
126
156
  function parsePackagesWithVersions(packageStrings, type) {
157
+ let str = packageStrings.join(' ');
158
+ let match;
127
159
  const packages = [];
128
- for (const entry of packageStrings) {
129
- const match = VersionRegex.exec(entry);
130
- if (match) {
131
- const [, name, operator, version] = match;
132
- const range = package_1.Package.parsePackageVersionRange(operator, version);
133
- packages.push(new package_1.Package({
134
- name: name,
135
- type: type,
136
- versionConstraints: range ? [range] : undefined
137
- }));
138
- }
160
+ // match until exhaustion
161
+ while ((match = VersionRegex.exec(str)) !== null) {
162
+ const [, name, operator, version] = match;
163
+ const range = package_1.Package.parsePackageVersionRange(operator, version);
164
+ packages.push(new package_1.Package({
165
+ name: name,
166
+ type: type,
167
+ versionConstraints: range ? [range] : undefined
168
+ }));
169
+ str = str.slice(match.index + match[0].length);
139
170
  }
140
171
  return packages;
141
172
  }
@@ -5,7 +5,6 @@ const flowr_analyzer_description_file_plugin_1 = require("../file-plugins/flowr-
5
5
  const semver_1 = require("semver");
6
6
  const flowr_analyzer_loading_order_plugin_1 = require("./flowr-analyzer-loading-order-plugin");
7
7
  const flowr_file_1 = require("../../context/flowr-file");
8
- const retriever_1 = require("../../../r-bridge/retriever");
9
8
  /**
10
9
  * This plugin extracts loading order information from R `DESCRIPTION` files.
11
10
  * It looks at the `Collate` field to determine the order in which files should be loaded.
@@ -25,10 +24,8 @@ class FlowrAnalyzerLoadingOrderDescriptionFilePlugin extends flowr_analyzer_load
25
24
  flowr_analyzer_description_file_plugin_1.descriptionFileLog.warn(`Found ${descFiles.length} description files, expected exactly one.`);
26
25
  }
27
26
  /** this will do the caching etc. for me */
28
- const deps = descFiles[0].content();
29
- if (deps.has('Collate')) {
30
- const collate = deps.get('Collate')?.map(f => (0, retriever_1.removeRQuotes)(f))
31
- ?? [];
27
+ const collate = descFiles[0].collate();
28
+ if (collate) {
32
29
  /* we probably have to do some more guesswork here */
33
30
  const unordered = ctx.files.loadingOrder.getUnorderedRequests();
34
31
  // sort them by their path index in the Collate field
@@ -5,7 +5,6 @@ const flowr_analyzer_package_versions_plugin_1 = require("./flowr-analyzer-packa
5
5
  const flowr_analyzer_description_file_plugin_1 = require("../file-plugins/flowr-analyzer-description-file-plugin");
6
6
  const semver_1 = require("semver");
7
7
  const flowr_file_1 = require("../../context/flowr-file");
8
- const flowr_description_file_1 = require("../file-plugins/files/flowr-description-file");
9
8
  /**
10
9
  * This plugin extracts package versions from R `DESCRIPTION` files.
11
10
  * It looks at the `Depends` and `Imports` fields to find package names and their version constraints.
@@ -24,12 +23,12 @@ class FlowrAnalyzerPackageVersionsDescriptionFilePlugin extends flowr_analyzer_p
24
23
  flowr_analyzer_description_file_plugin_1.descriptionFileLog.warn(`Found ${descFiles.length} description files, expected exactly one.`);
25
24
  }
26
25
  /** this will do the caching etc. for me */
27
- const deps = descFiles[0].content();
28
- this.retrieveVersionsFromField(ctx, deps, 'Depends', 'r');
29
- this.retrieveVersionsFromField(ctx, deps, 'Imports', 'package');
26
+ const deps = descFiles[0];
27
+ this.retrieveVersionsFromField(ctx, deps.depends() ?? []);
28
+ this.retrieveVersionsFromField(ctx, deps.imports() ?? []);
30
29
  }
31
- retrieveVersionsFromField(ctx, file, field, type) {
32
- for (const pkg of (0, flowr_description_file_1.parsePackagesWithVersions)(file.get(field) ?? [], type)) {
30
+ retrieveVersionsFromField(ctx, pkgs) {
31
+ for (const pkg of pkgs) {
33
32
  ctx.deps.addDependency(pkg);
34
33
  }
35
34
  }
@@ -4,7 +4,7 @@ import type { BasicQueryData } from '../../base-query-format';
4
4
  *
5
5
  */
6
6
  export declare function promoteCallName(callName: CallNameTypes, exact?: boolean): RegExp | Set<string>;
7
- export type PromotedLinkTo = Omit<LinkTo, 'callName'> & {
7
+ export type PromotedLinkTo<LT = LinkTo> = Omit<LT, 'callName'> & {
8
8
  callName: RegExp | Set<string>;
9
9
  };
10
10
  /**
@@ -10,6 +10,7 @@ const objects_1 = require("../../../util/objects");
10
10
  const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
11
11
  const cfg_kind_1 = require("../../../project/cfg-kind");
12
12
  const extract_cfg_1 = require("../../../control-flow/extract-cfg");
13
+ const identify_link_to_relation_1 = require("./identify-link-to-relation");
13
14
  /* if the node is effected by nse, we have an ingoing nse edge */
14
15
  function isQuoted(node, graph) {
15
16
  const vertex = graph.ingoingEdges(node);
@@ -239,10 +240,10 @@ async function executeCallContextQueries({ analyzer }, queries) {
239
240
  const linked = Array.isArray(query.linkTo) ? query.linkTo : [query.linkTo];
240
241
  for (const link of linked) {
241
242
  /* if we have a linkTo query, we have to find the last call */
242
- const lastCall = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(nodeId, cfg.graph, dataflow.graph, link, calls);
243
- if (lastCall) {
243
+ const linkTos = await (0, identify_link_to_relation_1.identifyLinkToRelation)(nodeId, analyzer, link, calls);
244
+ if (linkTos) {
244
245
  linkedIds ??= new Set();
245
- for (const l of lastCall) {
246
+ for (const l of linkTos) {
246
247
  if (link.attachLinkInfo) {
247
248
  linkedIds.add({ id: l, info: link.attachLinkInfo });
248
249
  }
@@ -47,6 +47,7 @@ export type CallNameTypes = RegExp | string | string[];
47
47
  * This way, you can link a call like `points` to the latest graphics plot etc.
48
48
  * For now, this uses the static Control-Flow-Graph produced by flowR as the FD over-approximation is still not stable (see #1005).
49
49
  * In short, this means that we are unable to detect origins over function call boundaries but plan on being more precise in the future.
50
+ * @see LinkToNestedCall
50
51
  */
51
52
  export interface LinkToLastCall<CallName extends CallNameTypes = CallNameTypes> extends BaseQueryFormat {
52
53
  readonly type: 'link-to-last-call';
@@ -63,7 +64,26 @@ export interface LinkToLastCall<CallName extends CallNameTypes = CallNameTypes>
63
64
  */
64
65
  readonly cascadeIf?: (target: DataflowGraphVertexInfo, from: NodeId, graph: DataflowGraph) => CascadeAction;
65
66
  }
66
- export type LinkTo<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> = (LinkToLastCall<CallName>) & {
67
+ /**
68
+ * Allows to link nested calls to their parent calls.
69
+ * This way, you can link an `assert_equal` call to the parent `test_that` call etc:
70
+ * ```r
71
+ * test_that("my test", {
72
+ * assert_equal(1 + 1, 2)
73
+ * })
74
+ * ```
75
+ */
76
+ export interface LinkToNestedCall<CallName extends CallNameTypes = CallNameTypes> extends BaseQueryFormat {
77
+ readonly type: 'link-to-nested-call';
78
+ /** Regex regarding the function name of the last call. Similar to {@link DefaultCallContextQueryFormat#callName}, strings are interpreted as a `RegExp`. */
79
+ readonly callName: CallName;
80
+ /**
81
+ * Should we ignore this (source) call?
82
+ * Currently, there is no well working serialization for this.
83
+ */
84
+ readonly ignoreIf?: (id: NodeId, graph: DataflowGraph) => boolean;
85
+ }
86
+ export type LinkTo<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> = (LinkToLastCall<CallName> | LinkToNestedCall<CallName>) & {
67
87
  attachLinkInfo?: AttachLinkInfo;
68
88
  };
69
89
  export interface SubCallContextQueryFormat<CallName extends CallNameTypes = CallNameTypes, AttachLinkInfo = NoInfo> extends DefaultCallContextQueryFormat<CallName> {
@@ -10,13 +10,21 @@ const time_1 = require("../../../util/text/time");
10
10
  const joi_1 = __importDefault(require("joi"));
11
11
  const query_print_1 = require("../../query-print");
12
12
  const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
13
- const CallContextQueryLinkTo = joi_1.default.object({
14
- type: joi_1.default.string().valid('link-to-last-call').required().description('The type of the linkTo sub-query.'),
15
- callName: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).required().description('Test regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression, and string arrays are checked for containment.'),
16
- ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
17
- 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.'),
18
- attachLinkInfo: joi_1.default.object().optional().description('Additional information to attach to the link.')
19
- });
13
+ const CallContextQueryLinkTo = joi_1.default.alternatives([
14
+ joi_1.default.object({
15
+ type: joi_1.default.string().valid('link-to-last-call').required().description('The type of the linkTo sub-query.'),
16
+ callName: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).required().description('Test regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression, and string arrays are checked for containment.'),
17
+ ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
18
+ 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.'),
19
+ attachLinkInfo: joi_1.default.object().optional().description('Additional information to attach to the link.')
20
+ }).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.'),
21
+ joi_1.default.object({
22
+ type: joi_1.default.string().valid('link-to-nested-call').required().description('The type of the linkTo sub-query.'),
23
+ callName: joi_1.default.alternatives(joi_1.default.string(), joi_1.default.array().items(joi_1.default.string())).required().description('Test regarding the function name of the last call. Similar to `callName`, strings are interpreted as a regular expression, and string arrays are checked for containment.'),
24
+ ignoreIf: joi_1.default.function().optional().description('Should we ignore this (source) call? Currently, there is no well working serialization for this.'),
25
+ attachLinkInfo: joi_1.default.object().optional().description('Additional information to attach to the link.')
26
+ }).description('Allows to link nested calls to their parent calls. This way, you can link an `assert_equal` call to the parent `test_that` call etc.')
27
+ ]);
20
28
  exports.CallContextQueryDefinition = {
21
29
  executor: call_context_query_executor_1.executeCallContextQueries,
22
30
  asciiSummarizer: async (formatter, analyzer, queryResults, result) => {
@@ -3,9 +3,10 @@ import { type DataflowGraph } from '../../../dataflow/graph/graph';
3
3
  import { type DataflowGraphVertexFunctionCall } from '../../../dataflow/graph/vertex';
4
4
  import { RType } from '../../../r-bridge/lang-4.x/ast/model/type';
5
5
  import type { RNodeWithParent } from '../../../r-bridge/lang-4.x/ast/model/processing/decorate';
6
- import type { LinkTo } from './call-context-query-format';
7
- import type { ControlFlowGraph } from '../../../control-flow/control-flow-graph';
6
+ import type { LinkToLastCall } from './call-context-query-format';
8
7
  import type { PromotedLinkTo } from './call-context-query-executor';
8
+ import type { ReadonlyFlowrAnalysisProvider } from '../../../project/flowr-analyzer';
9
+ import type { ControlFlowGraph } from '../../../control-flow/control-flow-graph';
9
10
  export declare enum CallTargets {
10
11
  /** call targets a function that is not defined locally in the script (e.g., the call targets a library function) */
11
12
  OnlyGlobal = "global",
@@ -32,9 +33,16 @@ export declare function getValueOfArgument<Types extends readonly RType[] = read
32
33
  type: Types[number];
33
34
  }) | undefined;
34
35
  /**
36
+ * **Please refer to {@link identifyLinkToRelation}.**
37
+ *
35
38
  * Identifies nodes that link to the last call of a specified function from a given starting node in the control flow graph.
36
39
  * If you pass on `knownCalls` (e.g., produced by {@link getCallsInCfg}), this will only respect the functions
37
40
  * listed there and ignore any other calls. This can be also used to speed up the process if you already have
38
41
  * the known calls available.
42
+ * @see {@link identifyLinkToLastCallRelationSync} for the synchronous version.
43
+ */
44
+ export declare function identifyLinkToLastCallRelation(from: NodeId, analyzer: ReadonlyFlowrAnalysisProvider, l: LinkToLastCall<RegExp> | PromotedLinkTo<LinkToLastCall<RegExp>>, knownCalls?: Map<NodeId, Required<DataflowGraphVertexFunctionCall>>): Promise<NodeId[]>;
45
+ /**
46
+ * Synchronous version of {@link identifyLinkToLastCallRelation}.
39
47
  */
40
- export declare function identifyLinkToLastCallRelation(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, { callName, ignoreIf, cascadeIf }: LinkTo<RegExp> | PromotedLinkTo, knownCalls?: Map<NodeId, Required<DataflowGraphVertexFunctionCall>>): NodeId[];
48
+ export declare function identifyLinkToLastCallRelationSync(from: NodeId, cfg: ControlFlowGraph, graph: DataflowGraph, { callName, cascadeIf, ignoreIf }: LinkToLastCall<RegExp> | PromotedLinkTo<LinkToLastCall<RegExp>>, knownCalls?: Map<NodeId, Required<DataflowGraphVertexFunctionCall>>): NodeId[];
@@ -4,6 +4,7 @@ exports.CallTargets = void 0;
4
4
  exports.satisfiesCallTargets = satisfiesCallTargets;
5
5
  exports.getValueOfArgument = getValueOfArgument;
6
6
  exports.identifyLinkToLastCallRelation = identifyLinkToLastCallRelation;
7
+ exports.identifyLinkToLastCallRelationSync = identifyLinkToLastCallRelationSync;
7
8
  const graph_1 = require("../../../dataflow/graph/graph");
8
9
  const simple_visitor_1 = require("../../../control-flow/simple-visitor");
9
10
  const vertex_1 = require("../../../dataflow/graph/vertex");
@@ -15,6 +16,7 @@ const assert_1 = require("../../../util/assert");
15
16
  const type_1 = require("../../../r-bridge/lang-4.x/ast/model/type");
16
17
  const r_function_call_1 = require("../../../r-bridge/lang-4.x/ast/model/nodes/r-function-call");
17
18
  const cascade_action_1 = require("./cascade-action");
19
+ const cfg_kind_1 = require("../../../project/cfg-kind");
18
20
  var CallTargets;
19
21
  (function (CallTargets) {
20
22
  /** call targets a function that is not defined locally in the script (e.g., the call targets a library function) */
@@ -111,12 +113,23 @@ function getValueOfArgument(graph, call, argument, additionalAllowedTypes) {
111
113
  }
112
114
  }
113
115
  /**
116
+ * **Please refer to {@link identifyLinkToRelation}.**
117
+ *
114
118
  * Identifies nodes that link to the last call of a specified function from a given starting node in the control flow graph.
115
119
  * If you pass on `knownCalls` (e.g., produced by {@link getCallsInCfg}), this will only respect the functions
116
120
  * listed there and ignore any other calls. This can be also used to speed up the process if you already have
117
121
  * the known calls available.
122
+ * @see {@link identifyLinkToLastCallRelationSync} for the synchronous version.
118
123
  */
119
- function identifyLinkToLastCallRelation(from, cfg, graph, { callName, ignoreIf, cascadeIf }, knownCalls) {
124
+ async function identifyLinkToLastCallRelation(from, analyzer, l, knownCalls) {
125
+ const graph = (await analyzer.dataflow()).graph;
126
+ const cfg = (await analyzer.controlflow([], cfg_kind_1.CfgKind.WithDataflow)).graph;
127
+ return identifyLinkToLastCallRelationSync(from, cfg, graph, l, knownCalls);
128
+ }
129
+ /**
130
+ * Synchronous version of {@link identifyLinkToLastCallRelation}.
131
+ */
132
+ function identifyLinkToLastCallRelationSync(from, cfg, graph, { callName, cascadeIf, ignoreIf }, knownCalls) {
120
133
  if (ignoreIf?.(from, graph)) {
121
134
  return [];
122
135
  }
@@ -0,0 +1,12 @@
1
+ import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
2
+ import type { LinkToNestedCall } from './call-context-query-format';
3
+ import type { PromotedLinkTo } from './call-context-query-executor';
4
+ import type { ReadonlyFlowrAnalysisProvider } from '../../../project/flowr-analyzer';
5
+ /**
6
+ * **Please refer to {@link identifyLinkToRelation}.**
7
+ *
8
+ * Links to the nested call context of the current function call.
9
+ * This is useful for identifying calls made within nested functions
10
+ * that should be associated with their parent function's call context.
11
+ */
12
+ export declare function identifyLinkToNestedRelation(from: NodeId, analyzer: ReadonlyFlowrAnalysisProvider, { callName, ignoreIf }: LinkToNestedCall<RegExp> | PromotedLinkTo<LinkToNestedCall<RegExp>>): Promise<NodeId[]>;
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.identifyLinkToNestedRelation = identifyLinkToNestedRelation;
4
+ const call_graph_1 = require("../../../dataflow/graph/call-graph");
5
+ /**
6
+ * **Please refer to {@link identifyLinkToRelation}.**
7
+ *
8
+ * Links to the nested call context of the current function call.
9
+ * This is useful for identifying calls made within nested functions
10
+ * that should be associated with their parent function's call context.
11
+ */
12
+ async function identifyLinkToNestedRelation(from, analyzer, { callName, ignoreIf }) {
13
+ const df = await analyzer.dataflow();
14
+ if (ignoreIf?.(from, df.graph)) {
15
+ return [];
16
+ }
17
+ const found = [];
18
+ const cg = await analyzer.callGraph();
19
+ const subCg = (0, call_graph_1.getSubCallGraph)(cg, new Set([from]));
20
+ for (const [, { id, name }] of subCg.vertices(true)) {
21
+ if (typeof name !== 'string') {
22
+ continue;
23
+ }
24
+ if (callName instanceof RegExp ? callName.test(name) : callName.has(name)) {
25
+ found.push(id);
26
+ }
27
+ }
28
+ return found;
29
+ }
30
+ //# sourceMappingURL=identify-link-to-nested-call-relation.js.map
@@ -0,0 +1,10 @@
1
+ import type { NodeId } from '../../../r-bridge/lang-4.x/ast/model/processing/node-id';
2
+ import type { LinkTo } from './call-context-query-format';
3
+ import type { PromotedLinkTo } from './call-context-query-executor';
4
+ import type { DataflowGraphVertexFunctionCall } from '../../../dataflow/graph/vertex';
5
+ import type { ReadonlyFlowrAnalysisProvider } from '../../../project/flowr-analyzer';
6
+ /**
7
+ * This facade selects the appropriate link-to relation identification function
8
+ * based on the type of link-to relation specified.
9
+ */
10
+ export declare function identifyLinkToRelation(from: NodeId, analyzer: ReadonlyFlowrAnalysisProvider, l: LinkTo | PromotedLinkTo, knownCalls?: Map<NodeId, Required<DataflowGraphVertexFunctionCall>>): Promise<NodeId[]>;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.identifyLinkToRelation = identifyLinkToRelation;
4
+ const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
5
+ const identify_link_to_nested_call_relation_1 = require("./identify-link-to-nested-call-relation");
6
+ const assert_1 = require("../../../util/assert");
7
+ /**
8
+ * This facade selects the appropriate link-to relation identification function
9
+ * based on the type of link-to relation specified.
10
+ */
11
+ async function identifyLinkToRelation(from, analyzer, l, knownCalls) {
12
+ switch (l.type) {
13
+ case 'link-to-last-call':
14
+ return (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(from, analyzer, l, knownCalls);
15
+ case 'link-to-nested-call':
16
+ return (0, identify_link_to_nested_call_relation_1.identifyLinkToNestedRelation)(from, analyzer, l);
17
+ default:
18
+ (0, assert_1.assertUnreachable)(l);
19
+ }
20
+ }
21
+ //# sourceMappingURL=identify-link-to-relation.js.map
@@ -36,12 +36,13 @@ async function executeDependenciesQuery({ analyzer, }, queries) {
36
36
  }
37
37
  const queryResults = functions.values().toArray().flat().length === 0 ? { kinds: {}, '.meta': { timing: 0 } } :
38
38
  await (0, query_1.executeQueriesOfSameType)(data, functions.entries().map(([c, f]) => makeCallContextQuery(f, c)).toArray().flat());
39
+ const g = (0, dependencies_query_format_1.getAllCategories)(queries);
39
40
  const results = Object.fromEntries(await Promise.all(functions.entries().map(async ([c, f]) => {
40
41
  const results = getResults(queries, { dataflow, config, normalize }, queryResults, c, f, data);
41
42
  // only default categories allow additional analyses, so we null-coalesce here!
42
43
  const enabled = query.enabledCategories;
43
44
  if (enabled === undefined || (enabled?.length > 0 && enabled.includes(c))) {
44
- await dependencies_query_format_1.DefaultDependencyCategories[c]?.additionalAnalysis?.(data, ignoreDefault, f, queryResults, results);
45
+ await g[c]?.additionalAnalysis?.(data, ignoreDefault, f, queryResults, results);
45
46
  }
46
47
  return [c, results];
47
48
  })));
@@ -5,7 +5,7 @@ import { executeDependenciesQuery } from './dependencies-query-executor';
5
5
  import type { FunctionInfo } from './function-info/function-info';
6
6
  import type { CallContextQueryResult } from '../call-context-query/call-context-query-format';
7
7
  import type { Range } from 'semver';
8
- import type { AsyncOrSync } from 'ts-essentials';
8
+ import type { AsyncOrSync, MarkOptional } from 'ts-essentials';
9
9
  import type { NamespaceInfo } from '../../../project/plugins/file-plugins/files/flowr-namespace-file';
10
10
  export declare const Unknown = "unknown";
11
11
  export interface DependencyCategorySettings {
@@ -13,6 +13,15 @@ export interface DependencyCategorySettings {
13
13
  functions: FunctionInfo[];
14
14
  /** this describes the global default value for this category, e.g., 'stdout' for write operations, please be aware, that this can be overwritten by a by-function default value */
15
15
  defaultValue?: string;
16
+ /**
17
+ * An optional additional analysis step that is executed after the main function-based analysis has been performed.
18
+ * To add or modify dependency info entries, simply modify the `result` array.
19
+ * @param data - The basic query data.
20
+ * @param ignoreDefault - Whether the default functions were ignored.
21
+ * @param functions - The functions used for this category.
22
+ * @param queryResults - The results of the call context query.
23
+ * @param result - The current result array to which additional dependency info can be added.
24
+ */
16
25
  additionalAnalysis?: (data: BasicQueryData, ignoreDefault: boolean, functions: FunctionInfo[], queryResults: CallContextQueryResult, result: DependencyInfo[]) => AsyncOrSync<void>;
17
26
  }
18
27
  export declare const DefaultDependencyCategories: {
@@ -52,7 +61,7 @@ export interface DependenciesQuery extends BaseQueryFormat, Partial<Record<`${De
52
61
  readonly type: 'dependencies';
53
62
  readonly enabledCategories?: DependencyCategoryName[];
54
63
  readonly ignoreDefaultFunctions?: boolean;
55
- readonly additionalCategories?: Record<string, Omit<DependencyCategorySettings, 'additionalAnalysis'>>;
64
+ readonly additionalCategories?: Record<string, MarkOptional<DependencyCategorySettings, 'additionalAnalysis'>>;
56
65
  }
57
66
  export type DependenciesQueryResult = BaseQueryResult & {
58
67
  [C in DefaultDependencyCategoryName]: DependencyInfo[];
@@ -84,7 +84,7 @@ function printResultSection(title, infos, result) {
84
84
  }, new Map());
85
85
  for (const [functionName, infos] of grouped) {
86
86
  result.push(` ╰ \`${functionName}\``);
87
- result.push(infos.map(i => ` ╰ Node Id: ${i.nodeId}${i.value !== undefined ? `, \`${i.value}\`` : ''}${i.derivedVersion !== undefined ? `, Version: \`${i.derivedVersion.format()}\`` : ''}`).join('\n'));
87
+ result.push(infos.map(i => ` ╰ Node Id: ${i.nodeId}${i.value !== undefined ? `, \`${i.value}\`` : ''}${i.derivedVersion !== undefined ? `, Version: \`${i.derivedVersion.format()}\`` : ''}${i.linkedIds ? `, linked: [${i.linkedIds.join(', ')}]` : ''}`).join('\n'));
88
88
  }
89
89
  }
90
90
  /**