@eagleoutice/flowr 2.2.8 → 2.2.9
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/README.md +7 -5
- package/cli/repl/server/compact.d.ts +2 -0
- package/cli/repl/server/compact.js +13 -0
- package/cli/repl/server/connection.js +10 -0
- package/cli/repl/server/messages/message-analysis.d.ts +21 -5
- package/cli/repl/server/messages/message-analysis.js +9 -2
- package/config.d.ts +49 -1
- package/config.js +43 -4
- package/dataflow/environments/built-in.js +1 -1
- package/dataflow/environments/environment.d.ts +4 -0
- package/dataflow/environments/environment.js +3 -3
- package/dataflow/environments/resolve-by-name.js +1 -1
- package/dataflow/extractor.js +12 -10
- package/dataflow/graph/dataflowgraph-builder.js +7 -7
- package/dataflow/graph/diff.js +1 -1
- package/dataflow/graph/graph.d.ts +3 -3
- package/dataflow/graph/graph.js +4 -4
- package/dataflow/graph/vertex.d.ts +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-access.js +1 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +1 -1
- 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-function-definition.js +2 -2
- package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +10 -3
- package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +11 -1
- package/dataflow/internal/process/functions/call/built-in/built-in-source.js +94 -16
- package/dataflow/internal/process/functions/call/common.js +1 -1
- package/dataflow/internal/process/functions/call/known-call-handling.js +1 -1
- package/dataflow/internal/process/functions/call/unnamed-call-handling.js +2 -3
- package/dataflow/internal/process/functions/process-argument.js +1 -1
- package/dataflow/internal/process/process-symbol.js +1 -1
- package/dataflow/internal/process/process-value.d.ts +1 -1
- package/dataflow/internal/process/process-value.js +6 -6
- package/dataflow/processor.d.ts +2 -2
- package/documentation/data/server/doc-data-server-messages.js +31 -0
- package/documentation/doc-util/doc-dfg.js +4 -7
- package/documentation/print-interface-wiki.js +7 -1
- package/documentation/print-normalized-ast-wiki.js +3 -3
- package/documentation/print-readme.js +1 -1
- package/package.json +4 -3
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.d.ts +3 -0
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.js +29 -0
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +72 -0
- package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +24 -0
- package/queries/query.d.ts +60 -1
- package/queries/query.js +2 -0
- package/r-bridge/retriever.d.ts +3 -2
- package/r-bridge/retriever.js +26 -7
- package/slicing/static/static-slicer.js +2 -2
- package/util/mermaid/cfg.js +1 -1
- package/util/mermaid/dfg.d.ts +4 -3
- package/util/mermaid/dfg.js +13 -10
- package/util/objects.d.ts +2 -2
- package/util/simple-df/dfg-view.d.ts +16 -0
- package/util/simple-df/dfg-view.js +64 -0
- package/util/version.js +1 -1
package/queries/query.d.ts
CHANGED
|
@@ -18,7 +18,8 @@ import type { ConfigQuery } from './catalog/config-query/config-query-format';
|
|
|
18
18
|
import type { SearchQuery } from './catalog/search-query/search-query-format';
|
|
19
19
|
import type { HappensBeforeQuery } from './catalog/happens-before-query/happens-before-query-format';
|
|
20
20
|
import type { ResolveValueQuery } from './catalog/resolve-value-query/resolve-value-query-format';
|
|
21
|
-
|
|
21
|
+
import type { DataflowLensQuery } from './catalog/dataflow-lens-query/dataflow-lens-query-format';
|
|
22
|
+
export type Query = CallContextQuery | ConfigQuery | SearchQuery | DataflowQuery | DataflowLensQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery | StaticSliceQuery | LineageQuery | DependenciesQuery | LocationMapQuery | HappensBeforeQuery | ResolveValueQuery;
|
|
22
23
|
export type QueryArgumentsWithType<QueryType extends BaseQueryFormat['type']> = Query & {
|
|
23
24
|
type: QueryType;
|
|
24
25
|
};
|
|
@@ -100,6 +101,64 @@ export declare const SupportedQueries: {
|
|
|
100
101
|
}>>, queryResults: BaseQueryResult, result: string[]) => true;
|
|
101
102
|
readonly schema: Joi.ObjectSchema<any>;
|
|
102
103
|
};
|
|
104
|
+
readonly 'dataflow-lens': {
|
|
105
|
+
readonly executor: typeof import("./catalog/dataflow-lens-query/dataflow-lens-query-executor").executeDataflowLensQuery;
|
|
106
|
+
readonly asciiSummarizer: (formatter: OutputFormatter, _processed: PipelineOutput<import("../core/steps/pipeline/pipeline").Pipeline<{
|
|
107
|
+
readonly name: "parse";
|
|
108
|
+
readonly humanReadableName: "parse with R shell";
|
|
109
|
+
readonly description: "Parse the given R code into an AST";
|
|
110
|
+
readonly processor: (_results: unknown, input: Partial<import("../r-bridge/parser").ParseRequiredInput<string>>) => Promise<import("../r-bridge/parser").ParseStepOutput<string>>;
|
|
111
|
+
readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
112
|
+
readonly printer: {
|
|
113
|
+
readonly 0: typeof import("../core/print/print").internalPrinter;
|
|
114
|
+
readonly 2: {
|
|
115
|
+
(value: any, replacer?: (this: any, key: string, value: any) => any, space?: string | number): string;
|
|
116
|
+
(value: any, replacer?: (number | string)[] | null, space?: string | number): string;
|
|
117
|
+
};
|
|
118
|
+
readonly 5: ({ parsed }: import("../r-bridge/parser").ParseStepOutput<string>, config: import("../util/quads").QuadSerializationConfiguration) => string;
|
|
119
|
+
};
|
|
120
|
+
readonly dependencies: readonly [];
|
|
121
|
+
readonly requiredInput: import("../r-bridge/parser").ParseRequiredInput<string>;
|
|
122
|
+
} | {
|
|
123
|
+
readonly name: "normalize";
|
|
124
|
+
readonly humanReadableName: "normalize";
|
|
125
|
+
readonly description: "Normalize the AST to flowR's AST";
|
|
126
|
+
readonly processor: (results: {
|
|
127
|
+
parse?: import("../r-bridge/parser").ParseStepOutput<string>;
|
|
128
|
+
}, input: Partial<import("../core/steps/all/core/10-normalize").NormalizeRequiredInput>) => import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation, import("../r-bridge/lang-4.x/ast/model/model").RNode<import("../r-bridge/lang-4.x/ast/model/processing/decorate").ParentInformation>>;
|
|
129
|
+
readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
130
|
+
readonly printer: {
|
|
131
|
+
readonly 0: typeof import("../core/print/print").internalPrinter;
|
|
132
|
+
readonly 2: typeof import("../core/print/normalize-printer").normalizedAstToJson;
|
|
133
|
+
readonly 5: typeof import("../core/print/normalize-printer").normalizedAstToQuads;
|
|
134
|
+
readonly 3: typeof import("../core/print/normalize-printer").printNormalizedAstToMermaid;
|
|
135
|
+
readonly 4: typeof import("../core/print/normalize-printer").printNormalizedAstToMermaidUrl;
|
|
136
|
+
};
|
|
137
|
+
readonly dependencies: readonly ["parse"];
|
|
138
|
+
readonly requiredInput: import("../core/steps/all/core/10-normalize").NormalizeRequiredInput;
|
|
139
|
+
} | {
|
|
140
|
+
readonly humanReadableName: "dataflow";
|
|
141
|
+
readonly processor: (results: {
|
|
142
|
+
normalize?: import("../r-bridge/lang-4.x/ast/model/processing/decorate").NormalizedAst;
|
|
143
|
+
}, input: {
|
|
144
|
+
request?: import("../r-bridge/retriever").RParseRequests;
|
|
145
|
+
parser?: import("../r-bridge/parser").Parser<import("../r-bridge/parser").KnownParserType>;
|
|
146
|
+
}) => import("../dataflow/info").DataflowInformation;
|
|
147
|
+
readonly requiredInput: {};
|
|
148
|
+
readonly name: "dataflow";
|
|
149
|
+
readonly description: "Construct the dataflow graph";
|
|
150
|
+
readonly executed: import("../core/steps/pipeline-step").PipelineStepStage.OncePerFile;
|
|
151
|
+
readonly printer: {
|
|
152
|
+
readonly 0: typeof import("../core/print/print").internalPrinter;
|
|
153
|
+
readonly 2: typeof import("../core/print/dataflow-printer").dataflowGraphToJson;
|
|
154
|
+
readonly 5: typeof import("../core/print/dataflow-printer").dataflowGraphToQuads;
|
|
155
|
+
readonly 3: typeof import("../core/print/dataflow-printer").dataflowGraphToMermaid;
|
|
156
|
+
readonly 4: typeof import("../core/print/dataflow-printer").dataflowGraphToMermaidUrl;
|
|
157
|
+
};
|
|
158
|
+
readonly dependencies: readonly ["normalize"];
|
|
159
|
+
}>>, queryResults: BaseQueryResult, result: string[]) => true;
|
|
160
|
+
readonly schema: Joi.ObjectSchema<any>;
|
|
161
|
+
};
|
|
103
162
|
readonly 'id-map': {
|
|
104
163
|
readonly executor: typeof import("./catalog/id-map-query/id-map-query-executor").executeIdMapQuery;
|
|
105
164
|
readonly asciiSummarizer: (formatter: OutputFormatter, _processed: PipelineOutput<import("../core/steps/pipeline/pipeline").Pipeline<{
|
package/queries/query.js
CHANGED
|
@@ -26,10 +26,12 @@ const config_query_format_1 = require("./catalog/config-query/config-query-forma
|
|
|
26
26
|
const search_query_format_1 = require("./catalog/search-query/search-query-format");
|
|
27
27
|
const happens_before_query_format_1 = require("./catalog/happens-before-query/happens-before-query-format");
|
|
28
28
|
const resolve_value_query_format_1 = require("./catalog/resolve-value-query/resolve-value-query-format");
|
|
29
|
+
const dataflow_lens_query_format_1 = require("./catalog/dataflow-lens-query/dataflow-lens-query-format");
|
|
29
30
|
exports.SupportedQueries = {
|
|
30
31
|
'call-context': call_context_query_format_1.CallContextQueryDefinition,
|
|
31
32
|
'config': config_query_format_1.ConfigQueryDefinition,
|
|
32
33
|
'dataflow': dataflow_query_format_1.DataflowQueryDefinition,
|
|
34
|
+
'dataflow-lens': dataflow_lens_query_format_1.DataflowLensQueryDefinition,
|
|
33
35
|
'id-map': id_map_query_format_1.IdMapQueryDefinition,
|
|
34
36
|
'normalized-ast': normalized_ast_query_format_1.NormalizedAstQueryDefinition,
|
|
35
37
|
'dataflow-cluster': cluster_query_format_1.ClusterQueryDefinition,
|
package/r-bridge/retriever.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ export interface RParseRequestFromText {
|
|
|
25
25
|
* A provider for an {@link RParseRequests} that can be used, for example, to override source file parsing behavior in tests
|
|
26
26
|
*/
|
|
27
27
|
export interface RParseRequestProvider {
|
|
28
|
+
/** returns the path if it exists, otherwise undefined */
|
|
29
|
+
exists(path: string, ignoreCase: boolean): string | undefined;
|
|
28
30
|
createRequest(path: string): RParseRequest;
|
|
29
31
|
}
|
|
30
32
|
export type RParseRequest = RParseRequestFromFile | RParseRequestFromText;
|
|
@@ -40,7 +42,6 @@ export declare function requestProviderFromFile(): RParseRequestProvider;
|
|
|
40
42
|
export declare function requestProviderFromText(text: Readonly<{
|
|
41
43
|
[path: string]: string;
|
|
42
44
|
}>): RParseRequestProvider;
|
|
43
|
-
export declare function requestFingerprint(request: RParseRequest): string;
|
|
44
45
|
export declare function isEmptyRequest(request: RParseRequest): boolean;
|
|
45
46
|
export declare function retrieveParseDataFromRCode(request: RParseRequest, shell: RShell): Promise<string>;
|
|
46
47
|
export declare function retrieveParseDataFromRCode(request: RParseRequest, shell: RShellExecutor): string;
|
|
@@ -55,6 +56,6 @@ export declare function retrieveNormalizedAstFromRCode(request: RParseRequest, s
|
|
|
55
56
|
*/
|
|
56
57
|
export declare function removeRQuotes(str: string): string;
|
|
57
58
|
/**
|
|
58
|
-
* Needs to be called *after*
|
|
59
|
+
* Needs to be called *after* {@link retrieveParseDataFromRCode} (or {@link retrieveNormalizedAstFromRCode})
|
|
59
60
|
*/
|
|
60
61
|
export declare function retrieveNumberOfRTokensOfLastParse(shell: RShell, ignoreComments?: boolean): Promise<number>;
|
package/r-bridge/retriever.js
CHANGED
|
@@ -7,7 +7,6 @@ exports.fileProtocol = void 0;
|
|
|
7
7
|
exports.requestFromInput = requestFromInput;
|
|
8
8
|
exports.requestProviderFromFile = requestProviderFromFile;
|
|
9
9
|
exports.requestProviderFromText = requestProviderFromText;
|
|
10
|
-
exports.requestFingerprint = requestFingerprint;
|
|
11
10
|
exports.isEmptyRequest = isEmptyRequest;
|
|
12
11
|
exports.retrieveParseDataFromRCode = retrieveParseDataFromRCode;
|
|
13
12
|
exports.retrieveNormalizedAstFromRCode = retrieveNormalizedAstFromRCode;
|
|
@@ -16,12 +15,13 @@ exports.retrieveNumberOfRTokensOfLastParse = retrieveNumberOfRTokensOfLastParse;
|
|
|
16
15
|
const strings_1 = require("../util/strings");
|
|
17
16
|
const assert_1 = require("../util/assert");
|
|
18
17
|
const shell_executor_1 = require("./shell-executor");
|
|
19
|
-
const object_hash_1 = __importDefault(require("object-hash"));
|
|
20
18
|
const parser_1 = require("./lang-4.x/ast/parser/json/parser");
|
|
21
19
|
const init_1 = require("./init");
|
|
22
20
|
const convert_values_1 = require("./lang-4.x/convert-values");
|
|
23
21
|
const decorate_1 = require("./lang-4.x/ast/model/processing/decorate");
|
|
24
22
|
const type_1 = require("./lang-4.x/ast/model/type");
|
|
23
|
+
const fs_1 = __importDefault(require("fs"));
|
|
24
|
+
const path_1 = __importDefault(require("path"));
|
|
25
25
|
exports.fileProtocol = 'file://';
|
|
26
26
|
/**
|
|
27
27
|
* Creates a {@link RParseRequests} from a given input.
|
|
@@ -42,6 +42,22 @@ function requestFromInput(input) {
|
|
|
42
42
|
}
|
|
43
43
|
function requestProviderFromFile() {
|
|
44
44
|
return {
|
|
45
|
+
exists(p, ignoreCase) {
|
|
46
|
+
try {
|
|
47
|
+
if (!ignoreCase) {
|
|
48
|
+
return fs_1.default.existsSync(p) ? p : undefined;
|
|
49
|
+
}
|
|
50
|
+
// walk the directory and find the first match
|
|
51
|
+
const dir = path_1.default.dirname(p);
|
|
52
|
+
const file = path_1.default.basename(p);
|
|
53
|
+
const files = fs_1.default.readdirSync(dir);
|
|
54
|
+
const found = files.find(f => f.toLowerCase() === file.toLowerCase());
|
|
55
|
+
return found ? path_1.default.join(dir, found) : undefined;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
},
|
|
45
61
|
createRequest(path) {
|
|
46
62
|
return {
|
|
47
63
|
request: 'file',
|
|
@@ -52,17 +68,20 @@ function requestProviderFromFile() {
|
|
|
52
68
|
}
|
|
53
69
|
function requestProviderFromText(text) {
|
|
54
70
|
return {
|
|
71
|
+
exists(path, ignoreCase) {
|
|
72
|
+
if (ignoreCase) {
|
|
73
|
+
return Object.keys(text).find(p => p.toLowerCase() === path.toLowerCase());
|
|
74
|
+
}
|
|
75
|
+
return text[path] ? path : undefined;
|
|
76
|
+
},
|
|
55
77
|
createRequest(path) {
|
|
56
78
|
return {
|
|
57
79
|
request: 'text',
|
|
58
|
-
content: text[path]
|
|
80
|
+
content: text[path] ?? ''
|
|
59
81
|
};
|
|
60
82
|
}
|
|
61
83
|
};
|
|
62
84
|
}
|
|
63
|
-
function requestFingerprint(request) {
|
|
64
|
-
return (0, object_hash_1.default)(request);
|
|
65
|
-
}
|
|
66
85
|
function isEmptyRequest(request) {
|
|
67
86
|
return request.content.trim().length === 0;
|
|
68
87
|
}
|
|
@@ -107,7 +126,7 @@ function removeRQuotes(str) {
|
|
|
107
126
|
}
|
|
108
127
|
}
|
|
109
128
|
/**
|
|
110
|
-
* Needs to be called *after*
|
|
129
|
+
* Needs to be called *after* {@link retrieveParseDataFromRCode} (or {@link retrieveNormalizedAstFromRCode})
|
|
111
130
|
*/
|
|
112
131
|
async function retrieveNumberOfRTokensOfLastParse(shell, ignoreComments = false) {
|
|
113
132
|
const rows = ignoreComments ? `flowr_output[flowr_output$token != "${type_1.RawRType.Comment}", ]` : 'flowr_output';
|
|
@@ -60,9 +60,9 @@ function staticSlicing(graph, { idMap }, criteria, threshold = 75) {
|
|
|
60
60
|
}
|
|
61
61
|
const [currentVertex, currentEdges] = currentInfo;
|
|
62
62
|
// we only add control dependencies iff 1) we are in different function call or 2) they have, at least, the same nesting as the slicing seed
|
|
63
|
-
if (currentVertex.
|
|
63
|
+
if (currentVertex.cds && currentVertex.cds.length > 0) {
|
|
64
64
|
const topLevel = graph.isRoot(id) || sliceSeedIds.has(id);
|
|
65
|
-
for (const cd of currentVertex.
|
|
65
|
+
for (const cd of currentVertex.cds.filter(({ id }) => !queue.hasId(id))) {
|
|
66
66
|
if (!topLevel || (idMap.get(cd.id)?.info.nesting ?? 0) >= minNesting) {
|
|
67
67
|
queue.add(cd.id, baseEnvironment, baseEnvFingerprint, false);
|
|
68
68
|
}
|
package/util/mermaid/cfg.js
CHANGED
|
@@ -7,7 +7,7 @@ function getLexeme(n) {
|
|
|
7
7
|
return n ? n.info.fullLexeme ?? n.lexeme ?? '<unknown>' : '';
|
|
8
8
|
}
|
|
9
9
|
function cfgToMermaid(cfg, normalizedAst, prefix = '') {
|
|
10
|
-
let output = prefix + 'flowchart
|
|
10
|
+
let output = prefix + 'flowchart BT\n';
|
|
11
11
|
for (const [id, vertex] of cfg.graph.vertices()) {
|
|
12
12
|
const normalizedVertex = normalizedAst.idMap.get(id);
|
|
13
13
|
const content = getLexeme(normalizedVertex);
|
package/util/mermaid/dfg.d.ts
CHANGED
|
@@ -44,11 +44,12 @@ export declare function graphToMermaid(config: MermaidGraphConfiguration): {
|
|
|
44
44
|
/**
|
|
45
45
|
* Converts a dataflow graph to a mermaid url that visualizes the graph.
|
|
46
46
|
*
|
|
47
|
-
* @param graph
|
|
47
|
+
* @param graph - The graph to convert
|
|
48
48
|
* @param includeEnvironments - Whether to include the environments in the mermaid graph code
|
|
49
|
-
* @param mark
|
|
49
|
+
* @param mark - Special nodes to mark (e.g., those included in the slice)
|
|
50
|
+
* @param simplified - Whether to simplify the graph
|
|
50
51
|
*/
|
|
51
|
-
export declare function graphToMermaidUrl(graph: DataflowGraph, includeEnvironments?: boolean, mark?: ReadonlySet<NodeId
|
|
52
|
+
export declare function graphToMermaidUrl(graph: DataflowGraph, includeEnvironments?: boolean, mark?: ReadonlySet<NodeId>, simplified?: boolean): string;
|
|
52
53
|
export interface LabeledDiffGraph {
|
|
53
54
|
label: string;
|
|
54
55
|
graph: DataflowGraph;
|
package/util/mermaid/dfg.js
CHANGED
|
@@ -42,7 +42,8 @@ function subflowToMermaid(nodeId, exitPoints, subflow, mermaid, idPrefix = '') {
|
|
|
42
42
|
const idMap = mermaid.rootGraph.idMap;
|
|
43
43
|
const node = idMap?.get(nodeId);
|
|
44
44
|
const nodeLexeme = node?.info.fullLexeme ?? node?.lexeme ?? '??';
|
|
45
|
-
|
|
45
|
+
const location = node?.location?.[0] ? ` (L. ${node?.location?.[0]})` : '';
|
|
46
|
+
mermaid.nodeLines.push(`\nsubgraph "${subflowId}" ["${(0, mermaid_1.escapeMarkdown)(nodeLexeme ?? 'function')}${location}"]`);
|
|
46
47
|
}
|
|
47
48
|
else {
|
|
48
49
|
mermaid.nodeLines.push(`\nsubgraph "${subflowId}" [function ${nodeId}]`);
|
|
@@ -154,12 +155,13 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
|
|
|
154
155
|
const node = mermaid.rootGraph.idMap?.get(info.id);
|
|
155
156
|
const lexeme = node?.lexeme ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0]?.lexeme : '') ?? '??';
|
|
156
157
|
if (mermaid.simplified) {
|
|
157
|
-
const
|
|
158
|
+
const location = node?.location?.[0] ? ` (L. ${node?.location?.[0]})` : '';
|
|
159
|
+
const escapedName = '**' + (0, mermaid_1.escapeMarkdown)(node ? `${lexeme}` : '??') + '**' + location + (node ? `\n*${node.type}*` : '');
|
|
158
160
|
mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}\`"${close}`);
|
|
159
161
|
}
|
|
160
162
|
else {
|
|
161
163
|
const escapedName = (0, mermaid_1.escapeMarkdown)(node ? `[${node.type}] ${lexeme}` : '??');
|
|
162
|
-
const deps = info.
|
|
164
|
+
const deps = info.cds ? ', :may:' + info.cds.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
|
|
163
165
|
const n = node?.info.fullRange ?? node?.location ?? (node?.type === type_1.RType.ExpressionList ? node?.grouping?.[0].location : undefined);
|
|
164
166
|
mermaid.nodeLines.push(` ${idPrefix}${id}${open}"\`${escapedName}${escapedName.length > 10 ? '\n ' : ' '}(${id}${deps})\n *${formatRange(n)}*${fCall ? displayFunctionArgMapping(info.args) : ''}\`"${close}`);
|
|
165
167
|
}
|
|
@@ -171,7 +173,7 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
|
|
|
171
173
|
}
|
|
172
174
|
const edges = mermaid.rootGraph.get(id, true);
|
|
173
175
|
(0, assert_1.guard)(edges !== undefined, `node ${id} must be found`);
|
|
174
|
-
const artificialCdEdges = (info.
|
|
176
|
+
const artificialCdEdges = (info.cds ?? []).map(x => [x.id, { types: new Set([x.when ? 'CD-True' : 'CD-False']) }]);
|
|
175
177
|
for (const [target, edge] of [...edges[1], ...artificialCdEdges]) {
|
|
176
178
|
const edgeTypes = typeof edge.types == 'number' ? new Set((0, edge_1.splitEdgeTypes)(edge.types)) : edge.types;
|
|
177
179
|
const edgeId = encodeEdge(idPrefix + id, idPrefix + target, edgeTypes);
|
|
@@ -192,7 +194,7 @@ function vertexToMermaid(info, mermaid, id, idPrefix, mark) {
|
|
|
192
194
|
}
|
|
193
195
|
}
|
|
194
196
|
// make the passing of root ids more performant again
|
|
195
|
-
function graphToMermaidGraph(rootIds, { simplified, graph, prefix = 'flowchart
|
|
197
|
+
function graphToMermaidGraph(rootIds, { simplified, graph, prefix = 'flowchart BT', idPrefix = '', includeEnvironments = !simplified, mark, rootGraph, presentEdges = new Set(), markStyle = { vertex: 'stroke:teal,stroke-width:7px,stroke-opacity:.8;', edge: 'stroke:teal,stroke-width:4.2px,stroke-opacity:.8' } }) {
|
|
196
198
|
const mermaid = { nodeLines: prefix === null ? [] : [prefix], edgeLines: [], presentEdges, mark, rootGraph: rootGraph ?? graph, includeEnvironments, markStyle, simplified };
|
|
197
199
|
for (const [id, info] of graph.vertices(true)) {
|
|
198
200
|
if (rootIds.has(id)) {
|
|
@@ -208,19 +210,20 @@ function graphToMermaid(config) {
|
|
|
208
210
|
/**
|
|
209
211
|
* Converts a dataflow graph to a mermaid url that visualizes the graph.
|
|
210
212
|
*
|
|
211
|
-
* @param graph
|
|
213
|
+
* @param graph - The graph to convert
|
|
212
214
|
* @param includeEnvironments - Whether to include the environments in the mermaid graph code
|
|
213
|
-
* @param mark
|
|
215
|
+
* @param mark - Special nodes to mark (e.g., those included in the slice)
|
|
216
|
+
* @param simplified - Whether to simplify the graph
|
|
214
217
|
*/
|
|
215
|
-
function graphToMermaidUrl(graph, includeEnvironments, mark) {
|
|
216
|
-
return (0, mermaid_1.mermaidCodeToUrl)(graphToMermaid({ graph, includeEnvironments, mark }).string);
|
|
218
|
+
function graphToMermaidUrl(graph, includeEnvironments, mark, simplified = false) {
|
|
219
|
+
return (0, mermaid_1.mermaidCodeToUrl)(graphToMermaid({ graph, includeEnvironments, mark, simplified }).string);
|
|
217
220
|
}
|
|
218
221
|
/** uses same id map but ensures, it is different from the rhs so that mermaid can work with that */
|
|
219
222
|
function diffGraphsToMermaid(left, right, prefix) {
|
|
220
223
|
// we add the prefix ourselves
|
|
221
224
|
const { string: leftGraph, mermaid } = graphToMermaid({ graph: left.graph, prefix: '', idPrefix: `l-${left.label}`, includeEnvironments: true, mark: left.mark });
|
|
222
225
|
const { string: rightGraph } = graphToMermaid({ graph: right.graph, prefix: '', idPrefix: `r-${right.label}`, includeEnvironments: true, mark: right.mark, presentEdges: mermaid.presentEdges });
|
|
223
|
-
return `${prefix}flowchart
|
|
226
|
+
return `${prefix}flowchart BT\nsubgraph "${left.label}"\n${leftGraph}\nend\nsubgraph "${right.label}"\n${rightGraph}\nend`;
|
|
224
227
|
}
|
|
225
228
|
function diffGraphsToMermaidUrl(left, right, prefix) {
|
|
226
229
|
return (0, mermaid_1.mermaidCodeToUrl)(diffGraphsToMermaid(left, right, prefix));
|
package/util/objects.d.ts
CHANGED
|
@@ -10,8 +10,8 @@ export type Mergeable = MergeableRecord | MergeableArray;
|
|
|
10
10
|
* Given two objects deeply merges them, if an object is an array it will merge the array values!
|
|
11
11
|
* Guarantees some type safety by requiring objects to merge to be from the same type (allows undefined)
|
|
12
12
|
*/
|
|
13
|
-
export declare function deepMergeObject<T extends Mergeable>(base: Required<T>, addon?: T): Required<T>;
|
|
14
|
-
export declare function deepMergeObject<T extends Mergeable>(base: DeepRequired<T>, addon?: T): DeepRequired<T>;
|
|
13
|
+
export declare function deepMergeObject<T extends Mergeable>(base: Required<T>, addon?: T | DeepPartial<T> | Partial<T>): Required<T>;
|
|
14
|
+
export declare function deepMergeObject<T extends Mergeable>(base: DeepRequired<T>, addon?: T | DeepPartial<T> | Partial<T>): DeepRequired<T>;
|
|
15
15
|
export declare function deepMergeObject<T extends Mergeable>(base: T, addon?: DeepPartial<T> | Partial<T>): T;
|
|
16
16
|
export declare function deepMergeObject(base: Mergeable, addon: Mergeable): Mergeable;
|
|
17
17
|
export declare function deepMergeObject(base?: Mergeable, addon?: Mergeable): Mergeable | undefined;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { DataflowGraph } from '../../dataflow/graph/graph';
|
|
2
|
+
import { VertexType } from '../../dataflow/graph/vertex';
|
|
3
|
+
import type { MergeableRecord } from '../objects';
|
|
4
|
+
import type { DeepPartial } from 'ts-essentials';
|
|
5
|
+
export interface ReduceVertexOptions extends MergeableRecord {
|
|
6
|
+
tags: VertexType[];
|
|
7
|
+
nameRegex: string;
|
|
8
|
+
blacklistWithName: boolean;
|
|
9
|
+
keepEnv: boolean;
|
|
10
|
+
keepCd: boolean;
|
|
11
|
+
compactFunctions: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface ReduceOptions extends MergeableRecord {
|
|
14
|
+
vertices: ReduceVertexOptions;
|
|
15
|
+
}
|
|
16
|
+
export declare function reduceDfg(dfg: DataflowGraph, options: DeepPartial<ReduceOptions>): DataflowGraph;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.reduceDfg = reduceDfg;
|
|
4
|
+
const graph_1 = require("../../dataflow/graph/graph");
|
|
5
|
+
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
6
|
+
const objects_1 = require("../objects");
|
|
7
|
+
const assert_1 = require("../assert");
|
|
8
|
+
const defaultReduceOptions = {
|
|
9
|
+
vertices: {
|
|
10
|
+
tags: [...Object.values(vertex_1.VertexType)],
|
|
11
|
+
nameRegex: '.*',
|
|
12
|
+
blacklistWithName: false,
|
|
13
|
+
keepEnv: false,
|
|
14
|
+
keepCd: true,
|
|
15
|
+
compactFunctions: true
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function makeFilter(options, idMap) {
|
|
19
|
+
const nameRegex = new RegExp(options.nameRegex);
|
|
20
|
+
return (arg) => {
|
|
21
|
+
if (!options.tags.includes(arg.tag)) {
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
const lexeme = idMap?.get(arg.id)?.lexeme;
|
|
25
|
+
if (lexeme && (nameRegex.test(lexeme) === options.blacklistWithName)) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
...arg,
|
|
30
|
+
environment: options.keepEnv ? arg.environment : undefined,
|
|
31
|
+
controlDependencies: options.keepCd ? arg.controlDependencies : undefined,
|
|
32
|
+
functionInformation: options.compactFunctions ? arg.functionInformation : undefined
|
|
33
|
+
};
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
function reduceDfg(dfg, options) {
|
|
37
|
+
const newDfg = new graph_1.DataflowGraph(dfg.idMap);
|
|
38
|
+
const applyOptions = (0, objects_1.deepMergeObject)(defaultReduceOptions, options);
|
|
39
|
+
// overwrite the tag set if possible
|
|
40
|
+
if (options.vertices?.tags) {
|
|
41
|
+
applyOptions.vertices.tags = options.vertices.tags.filter(assert_1.isNotUndefined);
|
|
42
|
+
}
|
|
43
|
+
const applyFilter = makeFilter(applyOptions.vertices, dfg.idMap);
|
|
44
|
+
// go over the vertices
|
|
45
|
+
for (const [id, info] of dfg.vertices(!applyOptions)) {
|
|
46
|
+
const result = applyFilter(info);
|
|
47
|
+
if (result) {
|
|
48
|
+
newDfg.addVertex(result, dfg.isRoot(id));
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
for (const [from, out] of dfg.edges()) {
|
|
52
|
+
if (!newDfg.hasVertex(from)) {
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
for (const [to, { types }] of out) {
|
|
56
|
+
if (!newDfg.hasVertex(to)) {
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
newDfg.addEdge(from, to, types);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return newDfg;
|
|
63
|
+
}
|
|
64
|
+
//# sourceMappingURL=dfg-view.js.map
|
package/util/version.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.flowrVersion = flowrVersion;
|
|
4
4
|
const semver_1 = require("semver");
|
|
5
5
|
// this is automatically replaced with the current version by release-it
|
|
6
|
-
const version = '2.2.
|
|
6
|
+
const version = '2.2.9';
|
|
7
7
|
function flowrVersion() {
|
|
8
8
|
return new semver_1.SemVer(version);
|
|
9
9
|
}
|