@eagleoutice/flowr 2.1.2 → 2.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/benchmark/slicer.js +1 -1
- package/cli/repl/commands/repl-parse.js +1 -1
- package/cli/repl/commands/repl-query.d.ts +0 -5
- package/cli/repl/commands/repl-query.js +4 -145
- package/cli/repl/server/connection.js +6 -1
- package/cli/repl/server/messages/message-query.js +2 -2
- package/cli/repl/server/net.js +1 -1
- package/cli/repl/server/send.js +3 -6
- package/cli/repl/server/server.d.ts +2 -2
- package/cli/repl/server/server.js +1 -1
- package/config.js +1 -1
- package/core/pipeline-executor.js +2 -1
- package/core/steps/all/core/00-parse.d.ts +11 -4
- package/core/steps/all/core/00-parse.js +5 -5
- package/core/steps/all/core/10-normalize.d.ts +2 -1
- package/core/steps/all/core/20-dataflow.d.ts +2 -2
- package/core/steps/all/core/20-dataflow.js +2 -2
- package/core/steps/pipeline/default-pipelines.d.ts +41 -23
- package/core/steps/pipeline/pipeline.d.ts +15 -3
- package/core/steps/pipeline/pipeline.js +2 -2
- package/dataflow/environments/built-in.d.ts +8 -6
- package/dataflow/environments/built-in.js +6 -1
- package/dataflow/environments/default-builtin-config.js +21 -5
- package/dataflow/environments/environment.d.ts +1 -0
- package/dataflow/environments/environment.js +5 -5
- package/dataflow/extractor.js +23 -0
- package/dataflow/graph/dataflowgraph-builder.d.ts +2 -0
- package/dataflow/graph/dataflowgraph-builder.js +9 -0
- package/dataflow/graph/diff.js +1 -1
- package/dataflow/graph/graph.d.ts +7 -2
- package/dataflow/graph/graph.js +10 -2
- package/dataflow/internal/process/functions/call/argument/unpack-argument.d.ts +1 -1
- package/dataflow/internal/process/functions/call/argument/unpack-argument.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-assignment.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-for-loop.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-if-then-else.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +13 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-while-loop.js +1 -1
- package/dataflow/internal/process/functions/call/named-call-handling.js +1 -1
- package/dataflow/processor.d.ts +3 -3
- package/documentation/data/server/doc-data-server-messages.js +9 -10
- package/documentation/doc-util/doc-cli-option.js +4 -4
- package/documentation/doc-util/doc-query.d.ts +3 -1
- package/documentation/doc-util/doc-query.js +16 -9
- package/documentation/doc-util/doc-repl.js +2 -2
- package/documentation/print-dataflow-graph-wiki.js +2 -1
- package/documentation/print-interface-wiki.js +8 -3
- package/documentation/print-query-wiki.js +139 -16
- package/package.json +3 -2
- package/queries/base-query-format.d.ts +6 -0
- package/queries/catalog/call-context-query/call-context-query-executor.d.ts +1 -1
- package/queries/catalog/call-context-query/call-context-query-executor.js +27 -81
- package/queries/catalog/call-context-query/call-context-query-format.d.ts +14 -13
- package/queries/catalog/call-context-query/call-context-query-format.js +32 -14
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.d.ts +17 -0
- package/queries/catalog/call-context-query/identify-link-to-last-call-relation.js +99 -0
- package/queries/catalog/cluster-query/cluster-query-executor.d.ts +1 -1
- package/queries/catalog/cluster-query/cluster-query-format.d.ts +59 -0
- package/queries/catalog/cluster-query/cluster-query-format.js +29 -0
- package/queries/catalog/dataflow-query/dataflow-query-executor.d.ts +1 -1
- package/queries/catalog/dataflow-query/dataflow-query-format.d.ts +59 -0
- package/queries/catalog/dataflow-query/dataflow-query-format.js +21 -0
- package/queries/catalog/dependencies-query/dependencies-query-executor.d.ts +3 -0
- package/queries/catalog/dependencies-query/dependencies-query-executor.js +144 -0
- package/queries/catalog/dependencies-query/dependencies-query-format.d.ts +102 -0
- package/queries/catalog/dependencies-query/dependencies-query-format.js +187 -0
- package/queries/catalog/id-map-query/id-map-query-executor.d.ts +1 -1
- package/queries/catalog/id-map-query/id-map-query-format.d.ts +59 -0
- package/queries/catalog/id-map-query/id-map-query-format.js +21 -0
- package/queries/catalog/lineage-query/lineage-query-executor.d.ts +3 -0
- package/queries/catalog/lineage-query/lineage-query-executor.js +22 -0
- package/queries/catalog/lineage-query/lineage-query-format.d.ts +73 -0
- package/queries/catalog/lineage-query/lineage-query-format.js +27 -0
- package/queries/catalog/location-map-query/location-map-query-executor.d.ts +3 -0
- package/queries/catalog/location-map-query/location-map-query-executor.js +21 -0
- package/queries/catalog/location-map-query/location-map-query-format.d.ts +17 -0
- package/queries/catalog/location-map-query/location-map-query-format.js +24 -0
- package/queries/catalog/normalized-ast-query/normalized-ast-query-executor.d.ts +1 -1
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.d.ts +59 -0
- package/queries/catalog/normalized-ast-query/normalized-ast-query-format.js +21 -0
- package/queries/catalog/static-slice-query/static-slice-query-executor.d.ts +1 -1
- package/queries/catalog/static-slice-query/static-slice-query-executor.js +8 -3
- package/queries/catalog/static-slice-query/static-slice-query-format.d.ts +59 -0
- package/queries/catalog/static-slice-query/static-slice-query-format.js +40 -0
- package/queries/query-print.d.ts +8 -0
- package/queries/query-print.js +94 -0
- package/queries/query.d.ts +431 -23
- package/queries/query.js +36 -16
- package/r-bridge/lang-4.x/ast/parser/json/parser.d.ts +2 -1
- package/r-bridge/lang-4.x/ast/parser/json/parser.js +2 -2
- package/r-bridge/lang-4.x/ast/parser/main/internal/functions/normalize-argument.js +2 -1
- package/r-bridge/retriever.js +1 -1
- package/r-bridge/shell-executor.js +1 -1
- package/r-bridge/shell.d.ts +1 -2
- package/r-bridge/shell.js +22 -18
- package/slicing/static/static-slicer.js +3 -1
- package/statistics/features/supported/used-functions/used-functions.js +1 -1
- package/{documentation/doc-util/doc-hover-over.js → util/html-hover-over.js} +1 -1
- package/util/json.d.ts +2 -1
- package/util/json.js +101 -3
- package/util/objects.d.ts +2 -1
- package/util/objects.js +3 -0
- package/util/version.js +1 -1
- package/queries/query-schema.d.ts +0 -12
- package/queries/query-schema.js +0 -50
- /package/{documentation/doc-util/doc-hover-over.d.ts → util/html-hover-over.d.ts} +0 -0
|
@@ -5,8 +5,9 @@ import type { VirtualCompoundConstraint } from '../../queries/virtual-query/comp
|
|
|
5
5
|
export interface ShowQueryOptions {
|
|
6
6
|
readonly showCode?: boolean;
|
|
7
7
|
readonly collapseResult?: boolean;
|
|
8
|
+
readonly collapseQuery?: boolean;
|
|
8
9
|
}
|
|
9
|
-
export declare function showQuery<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(shell: RShell, code: string, queries: Queries<Base, VirtualArguments>, { showCode, collapseResult }?: ShowQueryOptions): Promise<string>;
|
|
10
|
+
export declare function showQuery<Base extends SupportedQueryTypes, VirtualArguments extends VirtualCompoundConstraint<Base> = VirtualCompoundConstraint<Base>>(shell: RShell, code: string, queries: Queries<Base, VirtualArguments>, { showCode, collapseResult, collapseQuery }?: ShowQueryOptions): Promise<string>;
|
|
10
11
|
export interface QueryDocumentation {
|
|
11
12
|
readonly name: string;
|
|
12
13
|
readonly type: 'virtual' | 'active';
|
|
@@ -20,5 +21,6 @@ export declare const RegisteredQueries: {
|
|
|
20
21
|
virtual: Map<string, QueryDocumentation>;
|
|
21
22
|
};
|
|
22
23
|
export declare function registerQueryDocumentation(query: SupportedQueryTypes | SupportedVirtualQueryTypes, doc: QueryDocumentation): void;
|
|
24
|
+
export declare function linkToQueryOfName(id: SupportedQueryTypes | SupportedVirtualQueryTypes): string;
|
|
23
25
|
export declare function tocForQueryType(type: 'active' | 'virtual'): string;
|
|
24
26
|
export declare function explainQueries(shell: RShell, type: 'active' | 'virtual'): Promise<string>;
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.RegisteredQueries = void 0;
|
|
4
4
|
exports.showQuery = showQuery;
|
|
5
5
|
exports.registerQueryDocumentation = registerQueryDocumentation;
|
|
6
|
+
exports.linkToQueryOfName = linkToQueryOfName;
|
|
6
7
|
exports.tocForQueryType = tocForQueryType;
|
|
7
8
|
exports.explainQueries = explainQueries;
|
|
8
9
|
const query_1 = require("../../queries/query");
|
|
@@ -11,12 +12,12 @@ const default_pipelines_1 = require("../../core/steps/pipeline/default-pipelines
|
|
|
11
12
|
const retriever_1 = require("../../r-bridge/retriever");
|
|
12
13
|
const json_1 = require("../../util/json");
|
|
13
14
|
const ansi_1 = require("../../util/ansi");
|
|
14
|
-
const repl_query_1 = require("../../cli/repl/commands/repl-query");
|
|
15
15
|
const doc_files_1 = require("./doc-files");
|
|
16
16
|
const doc_dfg_1 = require("./doc-dfg");
|
|
17
17
|
const doc_code_1 = require("./doc-code");
|
|
18
18
|
const time_1 = require("../../util/time");
|
|
19
|
-
|
|
19
|
+
const query_print_1 = require("../../queries/query-print");
|
|
20
|
+
async function showQuery(shell, code, queries, { showCode, collapseResult, collapseQuery } = {}) {
|
|
20
21
|
const now = performance.now();
|
|
21
22
|
const analysis = await new pipeline_executor_1.PipelineExecutor(default_pipelines_1.DEFAULT_DATAFLOW_PIPELINE, {
|
|
22
23
|
shell,
|
|
@@ -27,17 +28,16 @@ async function showQuery(shell, code, queries, { showCode, collapseResult } = {}
|
|
|
27
28
|
const metaInfo = `
|
|
28
29
|
The analysis required _${(0, time_1.printAsMs)(duration)}_ (including parsing and normalization and the query) within the generation environment.
|
|
29
30
|
`.trim();
|
|
31
|
+
const str = JSON.stringify(queries, json_1.jsonReplacer, collapseQuery ? ' ' : 2);
|
|
30
32
|
return `
|
|
31
33
|
|
|
32
|
-
|
|
33
|
-
${JSON.stringify(queries, json_1.jsonReplacer, 2)}
|
|
34
|
-
\`\`\`
|
|
34
|
+
${(0, doc_code_1.codeBlock)('json', collapseQuery ? str.split('\n').join(' ').replace(/([{[])\s{2,}/g, '$1 ').replace(/\s{2,}([\]}])/g, ' $1') : str)}
|
|
35
35
|
|
|
36
36
|
${collapseResult ? ' <details> <summary style="color:gray">Show Results</summary>' : ''}
|
|
37
37
|
|
|
38
38
|
_Results (prettified and summarized):_
|
|
39
39
|
|
|
40
|
-
${(0,
|
|
40
|
+
${(0, query_print_1.asciiSummaryOfQueryResult)(ansi_1.markdownFormatter, duration, results, analysis)}
|
|
41
41
|
|
|
42
42
|
<details> <summary style="color:gray">Show Detailed Results as Json</summary>
|
|
43
43
|
|
|
@@ -76,6 +76,13 @@ function registerQueryDocumentation(query, doc) {
|
|
|
76
76
|
function linkify(name) {
|
|
77
77
|
return name.toLowerCase().replace(/ /g, '-');
|
|
78
78
|
}
|
|
79
|
+
function linkToQueryOfName(id) {
|
|
80
|
+
const query = exports.RegisteredQueries.active.get(id) ?? exports.RegisteredQueries.virtual.get(id);
|
|
81
|
+
if (!query) {
|
|
82
|
+
throw new Error(`Query ${id} not found`);
|
|
83
|
+
}
|
|
84
|
+
return `[${query.name}](#${linkify(query.name)})`;
|
|
85
|
+
}
|
|
79
86
|
function tocForQueryType(type) {
|
|
80
87
|
const queries = [...exports.RegisteredQueries[type].entries()].sort(([, { name: a }], [, { name: b }]) => a.localeCompare(b));
|
|
81
88
|
const result = [];
|
|
@@ -101,11 +108,11 @@ Responsible for the execution of the ${name} query is \`${functionName}\` in ${(
|
|
|
101
108
|
`;
|
|
102
109
|
}
|
|
103
110
|
async function explainQueries(shell, type) {
|
|
104
|
-
const queries = exports.RegisteredQueries[type];
|
|
111
|
+
const queries = [...exports.RegisteredQueries[type].entries()].sort(([, { name: a }], [, { name: b }]) => a.localeCompare(b));
|
|
105
112
|
const result = [];
|
|
106
|
-
for (const doc of queries
|
|
113
|
+
for (const [, doc] of queries) {
|
|
107
114
|
result.push(await explainQuery(shell, doc));
|
|
108
115
|
}
|
|
109
|
-
return result.join('\n\n
|
|
116
|
+
return result.join(`\n${'-'.repeat(5)}\n\n`);
|
|
110
117
|
}
|
|
111
118
|
//# sourceMappingURL=doc-query.js.map
|
|
@@ -4,7 +4,7 @@ exports.printReplHelpAsMarkdownTable = printReplHelpAsMarkdownTable;
|
|
|
4
4
|
exports.documentReplSession = documentReplSession;
|
|
5
5
|
const repl_commands_1 = require("../../cli/repl/commands/repl-commands");
|
|
6
6
|
const doc_cli_option_1 = require("./doc-cli-option");
|
|
7
|
-
const
|
|
7
|
+
const html_hover_over_1 = require("../../util/html-hover-over");
|
|
8
8
|
const core_1 = require("../../cli/repl/core");
|
|
9
9
|
const ansi_1 = require("../../util/ansi");
|
|
10
10
|
const doc_docker_1 = require("./doc-docker");
|
|
@@ -19,7 +19,7 @@ function printHelpForScript(script, starredVersion) {
|
|
|
19
19
|
return base;
|
|
20
20
|
}
|
|
21
21
|
const aliases = script[1].aliases;
|
|
22
|
-
return `${base} (alias${aliases.length > 1 ? 'es' : ''}: ${aliases.map(a => '**:' + (0,
|
|
22
|
+
return `${base} (alias${aliases.length > 1 ? 'es' : ''}: ${aliases.map(a => '**:' + (0, html_hover_over_1.textWithTooltip)(a, `Alias of ':${script[0]}'. ${script[1].description}`) + '**').join(', ')}) |`;
|
|
23
23
|
}
|
|
24
24
|
function printReplHelpAsMarkdownTable() {
|
|
25
25
|
const scriptHelp = [];
|
|
@@ -807,7 +807,8 @@ ${(0, doc_types_1.printHierarchy)({ program: vertexType.program, hierarchy: vert
|
|
|
807
807
|
Let's start by looking at the properties of the dataflow information object: ${Object.keys(result.dataflow).map(k => `\`${k}\``).join(', ')}.
|
|
808
808
|
|
|
809
809
|
${(() => {
|
|
810
|
-
|
|
810
|
+
/* this includes the meta field for timing */
|
|
811
|
+
(0, assert_1.guard)(Object.keys(result.dataflow).length === 8, () => 'Update Dataflow Documentation!');
|
|
811
812
|
return '';
|
|
812
813
|
})()}
|
|
813
814
|
|
|
@@ -18,6 +18,7 @@ const ansi_1 = require("../util/ansi");
|
|
|
18
18
|
const flowr_main_options_1 = require("../cli/flowr-main-options");
|
|
19
19
|
const doc_issue_1 = require("./doc-util/doc-issue");
|
|
20
20
|
const pipeline_executor_1 = require("../core/pipeline-executor");
|
|
21
|
+
const doc_structure_1 = require("./doc-util/doc-structure");
|
|
21
22
|
async function explainServer(shell) {
|
|
22
23
|
(0, doc_data_server_messages_1.documentAllServerMessages)();
|
|
23
24
|
return `
|
|
@@ -27,9 +28,13 @@ Additionally, the server is not well guarded against attacks (e.g., you can theo
|
|
|
27
28
|
|
|
28
29
|
Every message has to be given in a single line (i.e., without a newline in-between) and end with a newline character. Nevertheless, we will pretty-print example given in the following segments for the ease of reading.
|
|
29
30
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
${(0, doc_structure_1.block)({
|
|
32
|
+
type: 'NOTE',
|
|
33
|
+
content: `
|
|
34
|
+
The default ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'server', false)} uses a simple [TCP](https://de.wikipedia.org/wiki/Transmission_Control_Protocol)
|
|
35
|
+
connection. If you want _flowR_ to expose a [WebSocket](https://de.wikipedia.org/wiki/WebSocket) server instead, add the ${(0, doc_cli_option_1.getCliLongOptionOf)('flowr', 'ws', false)} flag (i.e., ${(0, doc_cli_option_1.multipleCliOptions)('flowr', 'server', 'ws')}) when starting _flowR_ from the command line.
|
|
36
|
+
`
|
|
37
|
+
})}
|
|
33
38
|
|
|
34
39
|
${await (0, doc_server_message_1.printServerMessages)(shell)}
|
|
35
40
|
|
|
@@ -6,9 +6,7 @@ const log_1 = require("../../test/functionality/_helper/log");
|
|
|
6
6
|
const query_1 = require("../queries/query");
|
|
7
7
|
const doc_files_1 = require("./doc-util/doc-files");
|
|
8
8
|
const doc_query_1 = require("./doc-util/doc-query");
|
|
9
|
-
const call_context_query_format_1 = require("../queries/catalog/call-context-query/call-context-query-format");
|
|
10
9
|
const schema_1 = require("../util/schema");
|
|
11
|
-
const query_schema_1 = require("../queries/query-schema");
|
|
12
10
|
const ansi_1 = require("../util/ansi");
|
|
13
11
|
const call_context_query_executor_1 = require("../queries/catalog/call-context-query/call-context-query-executor");
|
|
14
12
|
const compound_query_1 = require("../queries/virtual-query/compound-query");
|
|
@@ -21,6 +19,12 @@ const id_map_query_executor_1 = require("../queries/catalog/id-map-query/id-map-
|
|
|
21
19
|
const normalized_ast_query_executor_1 = require("../queries/catalog/normalized-ast-query/normalized-ast-query-executor");
|
|
22
20
|
const cluster_query_executor_1 = require("../queries/catalog/cluster-query/cluster-query-executor");
|
|
23
21
|
const static_slice_query_executor_1 = require("../queries/catalog/static-slice-query/static-slice-query-executor");
|
|
22
|
+
const lineage_query_executor_1 = require("../queries/catalog/lineage-query/lineage-query-executor");
|
|
23
|
+
const dependencies_query_executor_1 = require("../queries/catalog/dependencies-query/dependencies-query-executor");
|
|
24
|
+
const doc_cli_option_1 = require("./doc-util/doc-cli-option");
|
|
25
|
+
const doc_issue_1 = require("./doc-util/doc-issue");
|
|
26
|
+
const location_map_query_executor_1 = require("../queries/catalog/location-map-query/location-map-query-executor");
|
|
27
|
+
const identify_link_to_last_call_relation_1 = require("../queries/catalog/call-context-query/identify-link-to-last-call-relation");
|
|
24
28
|
(0, doc_query_1.registerQueryDocumentation)('call-context', {
|
|
25
29
|
name: 'Call-Context Query',
|
|
26
30
|
type: 'active',
|
|
@@ -53,7 +57,7 @@ ${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode,
|
|
|
53
57
|
callName: '^read_',
|
|
54
58
|
kind: 'input',
|
|
55
59
|
subkind: 'csv-file',
|
|
56
|
-
callTargets:
|
|
60
|
+
callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyGlobal
|
|
57
61
|
},
|
|
58
62
|
{
|
|
59
63
|
type: 'call-context',
|
|
@@ -66,7 +70,7 @@ ${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode,
|
|
|
66
70
|
|
|
67
71
|
As you can see, all kinds and subkinds with the same name are grouped together.
|
|
68
72
|
Yet, re-stating common arguments and kinds may be cumbersome (although you can already use clever regex patterns).
|
|
69
|
-
See the
|
|
73
|
+
See the ${(0, doc_query_1.linkToQueryOfName)('compound')} for a way to structure your queries more compactly if you think it gets too verbose.
|
|
70
74
|
|
|
71
75
|
${await (async () => {
|
|
72
76
|
const code = `
|
|
@@ -98,7 +102,7 @@ This query type does exactly that!
|
|
|
98
102
|
Using the example code \`${exampleCode}\`, the following query returns the dataflow graph of the code:
|
|
99
103
|
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
100
104
|
type: 'dataflow'
|
|
101
|
-
}], { showCode: true })}
|
|
105
|
+
}], { showCode: true, collapseQuery: true })}
|
|
102
106
|
`;
|
|
103
107
|
}
|
|
104
108
|
});
|
|
@@ -117,7 +121,38 @@ This query type does exactly that!
|
|
|
117
121
|
Using the example code \`${exampleCode}\`, the following query returns the normalized AST of the code:
|
|
118
122
|
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
119
123
|
type: 'normalized-ast'
|
|
120
|
-
}], { showCode: true })}
|
|
124
|
+
}], { showCode: true, collapseQuery: true })}
|
|
125
|
+
`;
|
|
126
|
+
}
|
|
127
|
+
});
|
|
128
|
+
(0, doc_query_1.registerQueryDocumentation)('lineage', {
|
|
129
|
+
name: 'Lineage Query',
|
|
130
|
+
type: 'active',
|
|
131
|
+
shortDescription: 'Returns lineage of a criteria.',
|
|
132
|
+
functionName: lineage_query_executor_1.executeLineageQuery.name,
|
|
133
|
+
functionFile: '../queries/catalog/lineage-query/lineage-query-executor.ts',
|
|
134
|
+
buildExplanation: async (shell) => {
|
|
135
|
+
const exampleCode = 'x <- 1\nx';
|
|
136
|
+
return `
|
|
137
|
+
This query calculates the _lineage_ of a given slicing criterion. The lineage traces back all parts that the
|
|
138
|
+
respective variables stems from given the reads, definitions, and returns in the dataflow graph.
|
|
139
|
+
|
|
140
|
+
To understand this, let's start with a simple example query, to get the lineage of the second use of \`x\` in the following code:
|
|
141
|
+
${(0, doc_code_1.codeBlock)('r', exampleCode)}
|
|
142
|
+
|
|
143
|
+
For this, we use the criterion \`2@x\` (which is the first use of \`x\` in the second line).
|
|
144
|
+
|
|
145
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
146
|
+
type: 'lineage',
|
|
147
|
+
criterion: '2@x'
|
|
148
|
+
}], { showCode: false })}
|
|
149
|
+
|
|
150
|
+
In this simple scenario, the _lineage_ is equivalent to the slice (and in-fact the complete code).
|
|
151
|
+
In general the lineage is smaller and makes no executability guarantees.
|
|
152
|
+
It is just a quick and neither complete nor sound way to get information on where the variable originates from.
|
|
153
|
+
|
|
154
|
+
This query replaces the old [\`request-lineage\`](${doc_files_1.FlowrWikiBaseRef}/Interface#message-request-lineage) message.
|
|
155
|
+
|
|
121
156
|
`;
|
|
122
157
|
}
|
|
123
158
|
});
|
|
@@ -144,7 +179,7 @@ ${(0, doc_structure_1.details)('Example <code>' + exampleB + '</code>', await (0
|
|
|
144
179
|
Using the example code from above, the following query returns all clusters:
|
|
145
180
|
${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{
|
|
146
181
|
type: 'dataflow-cluster'
|
|
147
|
-
}], { showCode: false })}
|
|
182
|
+
}], { showCode: false, collapseQuery: true })}
|
|
148
183
|
`;
|
|
149
184
|
}
|
|
150
185
|
});
|
|
@@ -162,7 +197,7 @@ This query provides access to all nodes in the [normalized AST](${doc_files_1.Fl
|
|
|
162
197
|
Using the example code \`${exampleCode}\`, the following query returns all nodes from the code:
|
|
163
198
|
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
164
199
|
type: 'id-map'
|
|
165
|
-
}], { showCode: true })}
|
|
200
|
+
}], { showCode: true, collapseQuery: true })}
|
|
166
201
|
`;
|
|
167
202
|
}
|
|
168
203
|
});
|
|
@@ -208,10 +243,10 @@ want to resolve to a local definition:
|
|
|
208
243
|
${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{
|
|
209
244
|
type: 'compound',
|
|
210
245
|
query: 'call-context',
|
|
211
|
-
commonArguments: { kind: 'visualize', subkind: 'text', callTargets:
|
|
246
|
+
commonArguments: { kind: 'visualize', subkind: 'text', callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyGlobal },
|
|
212
247
|
arguments: [
|
|
213
248
|
{ callName: '^mean$' },
|
|
214
|
-
{ callName: '^print$', callTargets:
|
|
249
|
+
{ callName: '^print$', callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyLocal }
|
|
215
250
|
]
|
|
216
251
|
}], { showCode: false })}
|
|
217
252
|
|
|
@@ -257,6 +292,85 @@ This query replaces the old [\`request-slice\`](${doc_files_1.FlowrWikiBaseRef}/
|
|
|
257
292
|
`;
|
|
258
293
|
}
|
|
259
294
|
});
|
|
295
|
+
(0, doc_query_1.registerQueryDocumentation)('dependencies', {
|
|
296
|
+
name: 'Dependencies Query',
|
|
297
|
+
type: 'active',
|
|
298
|
+
shortDescription: 'Returns all direct dependencies (in- and outputs) of a given R script',
|
|
299
|
+
functionName: dependencies_query_executor_1.executeDependenciesQuery.name,
|
|
300
|
+
functionFile: '../queries/catalog/dependencies-query/dependencies-query-executor.ts',
|
|
301
|
+
buildExplanation: async (shell) => {
|
|
302
|
+
const exampleCode = 'library(x)';
|
|
303
|
+
const longerCode = `
|
|
304
|
+
source("sample.R")
|
|
305
|
+
foo <- loadNamespace("bar")
|
|
306
|
+
|
|
307
|
+
data <- read.csv("data.csv")
|
|
308
|
+
|
|
309
|
+
#' @importFrom ggplot2 ggplot geom_point aes
|
|
310
|
+
ggplot(data, aes(x=x, y=y)) + geom_point()
|
|
311
|
+
|
|
312
|
+
better::write.csv(data, "data2.csv")
|
|
313
|
+
print("hello world!")
|
|
314
|
+
`;
|
|
315
|
+
return `
|
|
316
|
+
This query extracts all dependencies from an R script, using a combination of a ${(0, doc_query_1.linkToQueryOfName)('call-context')}
|
|
317
|
+
and more advanced tracking in the [Dataflow Graph](${doc_files_1.FlowrWikiBaseRef}/Dataflow%20Graph).
|
|
318
|
+
|
|
319
|
+
In other words, if you have a script simply reading: \`${exampleCode}\`, the following query returns the loaded library:
|
|
320
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
321
|
+
type: 'dependencies'
|
|
322
|
+
}], { showCode: false, collapseQuery: true })}
|
|
323
|
+
|
|
324
|
+
Of course, this works for more complicated scripts too. The query offers information on the loaded _libraries_, _sourced_ files, data which is _read_ and data which is _written_.
|
|
325
|
+
For example, consider the following script:
|
|
326
|
+
${(0, doc_code_1.codeBlock)('r', longerCode)}
|
|
327
|
+
The following query returns the dependencies of the script.
|
|
328
|
+
${await (0, doc_query_1.showQuery)(shell, longerCode, [{
|
|
329
|
+
type: 'dependencies'
|
|
330
|
+
}], { showCode: false, collapseQuery: true, collapseResult: true })}
|
|
331
|
+
|
|
332
|
+
Currently the dependency extraction may fail as it is essentially a set of heuristics guessing the dependencies.
|
|
333
|
+
We welcome any feedback on this (consider opening a [new issue](${doc_issue_1.NewIssueUrl})).
|
|
334
|
+
|
|
335
|
+
In the meantime we offer several properties to overwrite the default behavior (e.g., function names that should be collected)
|
|
336
|
+
|
|
337
|
+
${await (0, doc_query_1.showQuery)(shell, longerCode, [{
|
|
338
|
+
type: 'dependencies',
|
|
339
|
+
ignoreDefaultFunctions: true,
|
|
340
|
+
libraryFunctions: [{ name: 'print', argIdx: 0, argName: 'library' }],
|
|
341
|
+
sourceFunctions: [],
|
|
342
|
+
readFunctions: [],
|
|
343
|
+
writeFunctions: []
|
|
344
|
+
}], { showCode: false, collapseQuery: false, collapseResult: true })}
|
|
345
|
+
|
|
346
|
+
`;
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
(0, doc_query_1.registerQueryDocumentation)('location-map', {
|
|
350
|
+
name: 'Location Map Query',
|
|
351
|
+
type: 'active',
|
|
352
|
+
shortDescription: 'Returns a simple mapping of ids to their location in the source file',
|
|
353
|
+
functionName: location_map_query_executor_1.executeLocationMapQuery.name,
|
|
354
|
+
functionFile: '../queries/catalog/location-map-query/location-map-query-executor.ts',
|
|
355
|
+
buildExplanation: async (shell) => {
|
|
356
|
+
const exampleCode = 'x + 1\nx * 2';
|
|
357
|
+
return `
|
|
358
|
+
A query like the ${(0, doc_query_1.linkToQueryOfName)('id-map')} query can return a really big result, especially for larger scripts.
|
|
359
|
+
If you are not interested in all of the information contained within the full map, you can use the location map query to get a simple mapping of ids to their location in the source file.
|
|
360
|
+
|
|
361
|
+
Consider you have the following code:
|
|
362
|
+
|
|
363
|
+
${(0, doc_code_1.codeBlock)('r', exampleCode)}
|
|
364
|
+
|
|
365
|
+
The following query then gives you the aforementioned mapping:
|
|
366
|
+
|
|
367
|
+
${await (0, doc_query_1.showQuery)(shell, exampleCode, [{
|
|
368
|
+
type: 'location-map'
|
|
369
|
+
}], { showCode: false, collapseQuery: true })}
|
|
370
|
+
|
|
371
|
+
`;
|
|
372
|
+
}
|
|
373
|
+
});
|
|
260
374
|
async function getText(shell) {
|
|
261
375
|
const rversion = (await shell.usedRVersion())?.format() ?? 'unknown';
|
|
262
376
|
return `${(0, doc_auto_gen_1.autoGenHeader)({ filename: module.filename, purpose: 'query API', rVersion: rversion })}
|
|
@@ -264,13 +378,22 @@ async function getText(shell) {
|
|
|
264
378
|
This page briefly summarizes flowR's query API, represented by the ${query_1.executeQueries.name} function in ${(0, doc_files_1.getFilePathMd)('../queries/query.ts')}.
|
|
265
379
|
Please see the [Interface](${doc_files_1.FlowrWikiBaseRef}/Interface) wiki page for more information on how to access this API.
|
|
266
380
|
|
|
381
|
+
${(0, doc_structure_1.block)({
|
|
382
|
+
type: 'NOTE',
|
|
383
|
+
content: `
|
|
384
|
+
There are many ways to query a dataflow graph created by flowR.
|
|
385
|
+
For example, you can use the [\`request-query\`](${doc_files_1.FlowrWikiBaseRef}/Interface#message-request-query) message
|
|
386
|
+
with a running flowR server, or the ${(0, doc_cli_option_1.getReplCommand)('query')} command in the flowR [REPL](${doc_files_1.FlowrWikiBaseRef}/Interface#repl).
|
|
387
|
+
`.trim()
|
|
388
|
+
})}
|
|
389
|
+
|
|
267
390
|
## The Query Format
|
|
268
391
|
|
|
269
392
|
Queries are JSON arrays of query objects, each of which uses a \`type\` property to specify the query type.
|
|
270
393
|
In general, we separate two types of queries:
|
|
271
394
|
|
|
272
|
-
1. **Active Queries**: Are exactly what you would expect from a query (e.g., the
|
|
273
|
-
2. **Virtual Queries**: Are used to structure your queries (e.g., the
|
|
395
|
+
1. **Active Queries**: Are exactly what you would expect from a query (e.g., the ${(0, doc_query_1.linkToQueryOfName)('call-context')}). They fetch information from the dataflow graph.
|
|
396
|
+
2. **Virtual Queries**: Are used to structure your queries (e.g., the ${(0, doc_query_1.linkToQueryOfName)('compound')}).
|
|
274
397
|
|
|
275
398
|
We separate these from a concept perspective.
|
|
276
399
|
For now, we support the following **active** queries (which we will refer to simply as a \`query\`):
|
|
@@ -288,7 +411,7 @@ ${(0, doc_query_1.tocForQueryType)('virtual')}
|
|
|
288
411
|
|
|
289
412
|
Although it is probably better to consult the detailed explanations below, if you want to have a look at the scehma, here is its description:
|
|
290
413
|
|
|
291
|
-
${(0, schema_1.describeSchema)(
|
|
414
|
+
${(0, schema_1.describeSchema)(query_1.QueriesSchema, ansi_1.markdownFormatter)}
|
|
292
415
|
|
|
293
416
|
</details>
|
|
294
417
|
|
|
@@ -317,11 +440,11 @@ However, this fails to incorporate
|
|
|
317
440
|
3. Context information (e.g., calls like \`points\` may link to the current plot)
|
|
318
441
|
|
|
319
442
|
To solve this, flowR provides a query API which allows you to specify queries on the dataflow graph.
|
|
320
|
-
For the specific use-case stated, you could use the
|
|
443
|
+
For the specific use-case stated, you could use the ${(0, doc_query_1.linkToQueryOfName)('call-context')} to find all calls to \`read_csv\` which refer functions that are not overwritten.
|
|
321
444
|
|
|
322
|
-
Just as an example, the following
|
|
445
|
+
Just as an example, the following ${(0, doc_query_1.linkToQueryOfName)('call-context')} finds all calls to \`read_csv\` that are not overwritten:
|
|
323
446
|
|
|
324
|
-
${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{ type: 'call-context', callName: '^read_csv$', callTargets:
|
|
447
|
+
${await (0, doc_query_1.showQuery)(shell, example_query_code_1.exampleQueryCode, [{ type: 'call-context', callName: '^read_csv$', callTargets: identify_link_to_last_call_relation_1.CallTargets.OnlyGlobal, kind: 'input', subkind: 'csv-file' }], { showCode: false })}
|
|
325
448
|
|
|
326
449
|
${await (0, doc_query_1.explainQueries)(shell, 'active')}
|
|
327
450
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eagleoutice/flowr",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.4",
|
|
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": {
|
|
@@ -38,7 +38,8 @@
|
|
|
38
38
|
"test": "nyc --no-clean mocha",
|
|
39
39
|
"performance-test": "func() { cd test/performance/ && bash run-all-suites.sh $1 $2 $3; cd ../../; }; func",
|
|
40
40
|
"test-full": "npm run test -- --test-installation",
|
|
41
|
-
"detect-circular-deps": "npx madge --extensions ts,tsx --circular src/"
|
|
41
|
+
"detect-circular-deps": "npx madge --extensions ts,tsx --circular src/",
|
|
42
|
+
"checkup": "npm run flowr -- --execute \":version\" && npm run lint && npm run test-full -- --forbid-only && docker build -t test-flowr -f scripts/Dockerfile . && npm run doc && npm-run-all wiki:*"
|
|
42
43
|
},
|
|
43
44
|
"keywords": [
|
|
44
45
|
"static code analysis",
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { NormalizedAst } from '../r-bridge/lang-4.x/ast/model/processing/decorate';
|
|
2
|
+
import type { DataflowGraph } from '../dataflow/graph/graph';
|
|
1
3
|
export interface BaseQueryFormat {
|
|
2
4
|
/** used to select the query type :) */
|
|
3
5
|
readonly type: string;
|
|
@@ -9,3 +11,7 @@ export interface BaseQueryMeta {
|
|
|
9
11
|
export interface BaseQueryResult {
|
|
10
12
|
readonly '.meta': BaseQueryMeta;
|
|
11
13
|
}
|
|
14
|
+
export interface BasicQueryData {
|
|
15
|
+
readonly ast: NormalizedAst;
|
|
16
|
+
readonly graph: DataflowGraph;
|
|
17
|
+
}
|
|
@@ -1,69 +1,13 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.executeCallContextQueries = executeCallContextQueries;
|
|
4
|
-
const call_context_query_format_1 = require("./call-context-query-format");
|
|
5
4
|
const node_id_1 = require("../../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
6
5
|
const vertex_1 = require("../../../dataflow/graph/vertex");
|
|
7
|
-
const assert_1 = require("../../../util/assert");
|
|
8
6
|
const edge_1 = require("../../../dataflow/graph/edge");
|
|
9
|
-
const resolve_by_name_1 = require("../../../dataflow/environments/resolve-by-name");
|
|
10
|
-
const built_in_1 = require("../../../dataflow/environments/built-in");
|
|
11
7
|
const cfg_1 = require("../../../util/cfg/cfg");
|
|
12
8
|
const two_layer_collector_1 = require("../../two-layer-collector");
|
|
13
9
|
const objects_1 = require("../../../util/objects");
|
|
14
|
-
const
|
|
15
|
-
const identifier_1 = require("../../../dataflow/environments/identifier");
|
|
16
|
-
function satisfiesCallTargets(id, graph, callTarget) {
|
|
17
|
-
const callVertex = graph.get(id);
|
|
18
|
-
if (callVertex === undefined || callVertex[0].tag !== vertex_1.VertexType.FunctionCall) {
|
|
19
|
-
return 'no';
|
|
20
|
-
}
|
|
21
|
-
const [info, outgoing] = callVertex;
|
|
22
|
-
const callTargets = [...outgoing]
|
|
23
|
-
.filter(([, e]) => (0, edge_1.edgeIncludesType)(e.types, edge_1.EdgeType.Calls))
|
|
24
|
-
.map(([t]) => t);
|
|
25
|
-
let builtIn = false;
|
|
26
|
-
if (info.environment === undefined) {
|
|
27
|
-
/* if we have a call with an unbound environment,
|
|
28
|
-
* this only happens if we are sure of built-in relations and want to save references
|
|
29
|
-
*/
|
|
30
|
-
builtIn = true;
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
/*
|
|
34
|
-
* for performance and scoping reasons, flowR will not identify the global linkage,
|
|
35
|
-
* including any potential built-in mapping.
|
|
36
|
-
*/
|
|
37
|
-
const reResolved = (0, resolve_by_name_1.resolveByName)(info.name, info.environment, identifier_1.ReferenceType.Unknown);
|
|
38
|
-
if (reResolved?.some(t => t.definedAt === built_in_1.BuiltIn)) {
|
|
39
|
-
builtIn = true;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
switch (callTarget) {
|
|
43
|
-
case call_context_query_format_1.CallTargets.Any:
|
|
44
|
-
return callTargets;
|
|
45
|
-
case call_context_query_format_1.CallTargets.OnlyGlobal:
|
|
46
|
-
if (callTargets.length === 0) {
|
|
47
|
-
return builtIn ? [built_in_1.BuiltIn] : [];
|
|
48
|
-
}
|
|
49
|
-
else {
|
|
50
|
-
return 'no';
|
|
51
|
-
}
|
|
52
|
-
case call_context_query_format_1.CallTargets.MustIncludeGlobal:
|
|
53
|
-
return builtIn || callTargets.length === 0 ? [...callTargets, built_in_1.BuiltIn] : 'no';
|
|
54
|
-
case call_context_query_format_1.CallTargets.OnlyLocal:
|
|
55
|
-
return !builtIn && callTargets.length > 0 ? callTargets : 'no';
|
|
56
|
-
case call_context_query_format_1.CallTargets.MustIncludeLocal:
|
|
57
|
-
if (callTargets.length > 0) {
|
|
58
|
-
return builtIn ? [...callTargets, built_in_1.BuiltIn] : callTargets;
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
return 'no';
|
|
62
|
-
}
|
|
63
|
-
default:
|
|
64
|
-
(0, assert_1.assertUnreachable)(callTarget);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
10
|
+
const identify_link_to_last_call_relation_1 = require("./identify-link-to-last-call-relation");
|
|
67
11
|
/* if the node is effected by nse, we have an ingoing nse edge */
|
|
68
12
|
function isQuoted(node, graph) {
|
|
69
13
|
const vertex = graph.ingoingEdges(node);
|
|
@@ -77,6 +21,9 @@ function makeReport(collector) {
|
|
|
77
21
|
for (const [kind, collected] of collector.store) {
|
|
78
22
|
const subkinds = {};
|
|
79
23
|
for (const [subkind, values] of collected) {
|
|
24
|
+
if (!Array.isArray(subkinds[subkind])) {
|
|
25
|
+
subkinds[subkind] = [];
|
|
26
|
+
}
|
|
80
27
|
subkinds[subkind] ??= [];
|
|
81
28
|
const collectIn = subkinds[subkind];
|
|
82
29
|
for (const value of values) {
|
|
@@ -90,10 +37,10 @@ function makeReport(collector) {
|
|
|
90
37
|
return result;
|
|
91
38
|
}
|
|
92
39
|
function isSubCallQuery(query) {
|
|
93
|
-
return 'linkTo' in query;
|
|
40
|
+
return 'linkTo' in query && query.linkTo !== undefined;
|
|
94
41
|
}
|
|
95
42
|
function exactCallNameRegex(name) {
|
|
96
|
-
return new RegExp(
|
|
43
|
+
return new RegExp(`^(${name})$`);
|
|
97
44
|
}
|
|
98
45
|
function promoteQueryCallNames(queries) {
|
|
99
46
|
let requiresCfg = false;
|
|
@@ -121,24 +68,6 @@ function promoteQueryCallNames(queries) {
|
|
|
121
68
|
});
|
|
122
69
|
return { promotedQueries, requiresCfg };
|
|
123
70
|
}
|
|
124
|
-
function identifyLinkToLastCallRelation(from, cfg, graph, linkTo) {
|
|
125
|
-
const found = [];
|
|
126
|
-
(0, visitor_1.visitInReverseOrder)(cfg, from, node => {
|
|
127
|
-
/* we ignore the start id as it cannot be the last call */
|
|
128
|
-
if (node === from) {
|
|
129
|
-
return;
|
|
130
|
-
}
|
|
131
|
-
const vertex = graph.getVertex(node);
|
|
132
|
-
if (vertex === undefined || vertex.tag !== vertex_1.VertexType.FunctionCall) {
|
|
133
|
-
return;
|
|
134
|
-
}
|
|
135
|
-
if (linkTo.test(vertex.name)) {
|
|
136
|
-
found.push(node);
|
|
137
|
-
return true;
|
|
138
|
-
}
|
|
139
|
-
});
|
|
140
|
-
return found;
|
|
141
|
-
}
|
|
142
71
|
/* maybe we want to add caches to this */
|
|
143
72
|
function retrieveAllCallAliases(nodeId, graph) {
|
|
144
73
|
/* we want the names of all functions called at the source id, including synonyms and returns */
|
|
@@ -187,6 +116,22 @@ function retrieveAllCallAliases(nodeId, graph) {
|
|
|
187
116
|
}
|
|
188
117
|
return aliases;
|
|
189
118
|
}
|
|
119
|
+
function removeIdenticalDuplicates(collector) {
|
|
120
|
+
for (const [, collected] of collector.store) {
|
|
121
|
+
for (const [subkind, values] of collected) {
|
|
122
|
+
const seen = new Set();
|
|
123
|
+
const newValues = values.filter(v => {
|
|
124
|
+
const str = JSON.stringify(v);
|
|
125
|
+
if (seen.has(str)) {
|
|
126
|
+
return false;
|
|
127
|
+
}
|
|
128
|
+
seen.add(str);
|
|
129
|
+
return true;
|
|
130
|
+
});
|
|
131
|
+
collected.set(subkind, newValues);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
190
135
|
/**
|
|
191
136
|
* Multi-stage call context query resolve.
|
|
192
137
|
*
|
|
@@ -223,7 +168,7 @@ function executeCallContextQueries({ graph, ast }, queries) {
|
|
|
223
168
|
for (const [l, ids] of targets.entries()) {
|
|
224
169
|
for (const query of queriesWhichWantAliases) {
|
|
225
170
|
if (query.callName.test(l)) {
|
|
226
|
-
initialIdCollector.add(query.kind ?? '.', query.subkind ?? '.', (0, objects_1.compactRecord)({ id: nodeId, aliasRoots: ids }));
|
|
171
|
+
initialIdCollector.add(query.kind ?? '.', query.subkind ?? '.', (0, objects_1.compactRecord)({ id: nodeId, name: info.name, aliasRoots: ids }));
|
|
227
172
|
}
|
|
228
173
|
}
|
|
229
174
|
}
|
|
@@ -231,7 +176,7 @@ function executeCallContextQueries({ graph, ast }, queries) {
|
|
|
231
176
|
for (const query of promotedQueries.filter(q => q.callName.test(info.name))) {
|
|
232
177
|
let targets = undefined;
|
|
233
178
|
if (query.callTargets) {
|
|
234
|
-
targets = satisfiesCallTargets(nodeId, graph, query.callTargets);
|
|
179
|
+
targets = (0, identify_link_to_last_call_relation_1.satisfiesCallTargets)(nodeId, graph, query.callTargets);
|
|
235
180
|
if (targets === 'no') {
|
|
236
181
|
continue;
|
|
237
182
|
}
|
|
@@ -243,14 +188,15 @@ function executeCallContextQueries({ graph, ast }, queries) {
|
|
|
243
188
|
let linkedIds = undefined;
|
|
244
189
|
if (cfg && isSubCallQuery(query)) {
|
|
245
190
|
/* if we have a linkTo query, we have to find the last call */
|
|
246
|
-
const lastCall = identifyLinkToLastCallRelation(nodeId, cfg.graph, graph, query.linkTo.callName);
|
|
191
|
+
const lastCall = (0, identify_link_to_last_call_relation_1.identifyLinkToLastCallRelation)(nodeId, cfg.graph, graph, query.linkTo.callName);
|
|
247
192
|
if (lastCall) {
|
|
248
193
|
linkedIds = lastCall;
|
|
249
194
|
}
|
|
250
195
|
}
|
|
251
|
-
initialIdCollector.add(query.kind ?? '.', query.subkind ?? '.', (0, objects_1.compactRecord)({ id: nodeId, calls: targets, linkedIds }));
|
|
196
|
+
initialIdCollector.add(query.kind ?? '.', query.subkind ?? '.', (0, objects_1.compactRecord)({ id: nodeId, name: info.name, calls: targets, linkedIds }));
|
|
252
197
|
}
|
|
253
198
|
}
|
|
199
|
+
removeIdenticalDuplicates(initialIdCollector);
|
|
254
200
|
return {
|
|
255
201
|
'.meta': {
|
|
256
202
|
timing: Date.now() - now,
|