@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.
Files changed (55) hide show
  1. package/README.md +7 -5
  2. package/cli/repl/server/compact.d.ts +2 -0
  3. package/cli/repl/server/compact.js +13 -0
  4. package/cli/repl/server/connection.js +10 -0
  5. package/cli/repl/server/messages/message-analysis.d.ts +21 -5
  6. package/cli/repl/server/messages/message-analysis.js +9 -2
  7. package/config.d.ts +49 -1
  8. package/config.js +43 -4
  9. package/dataflow/environments/built-in.js +1 -1
  10. package/dataflow/environments/environment.d.ts +4 -0
  11. package/dataflow/environments/environment.js +3 -3
  12. package/dataflow/environments/resolve-by-name.js +1 -1
  13. package/dataflow/extractor.js +12 -10
  14. package/dataflow/graph/dataflowgraph-builder.js +7 -7
  15. package/dataflow/graph/diff.js +1 -1
  16. package/dataflow/graph/graph.d.ts +3 -3
  17. package/dataflow/graph/graph.js +4 -4
  18. package/dataflow/graph/vertex.d.ts +1 -1
  19. package/dataflow/internal/process/functions/call/built-in/built-in-access.js +1 -1
  20. package/dataflow/internal/process/functions/call/built-in/built-in-apply.js +1 -1
  21. package/dataflow/internal/process/functions/call/built-in/built-in-expression-list.js +1 -1
  22. package/dataflow/internal/process/functions/call/built-in/built-in-function-definition.js +2 -2
  23. package/dataflow/internal/process/functions/call/built-in/built-in-pipe.js +10 -3
  24. package/dataflow/internal/process/functions/call/built-in/built-in-source.d.ts +11 -1
  25. package/dataflow/internal/process/functions/call/built-in/built-in-source.js +94 -16
  26. package/dataflow/internal/process/functions/call/common.js +1 -1
  27. package/dataflow/internal/process/functions/call/known-call-handling.js +1 -1
  28. package/dataflow/internal/process/functions/call/unnamed-call-handling.js +2 -3
  29. package/dataflow/internal/process/functions/process-argument.js +1 -1
  30. package/dataflow/internal/process/process-symbol.js +1 -1
  31. package/dataflow/internal/process/process-value.d.ts +1 -1
  32. package/dataflow/internal/process/process-value.js +6 -6
  33. package/dataflow/processor.d.ts +2 -2
  34. package/documentation/data/server/doc-data-server-messages.js +31 -0
  35. package/documentation/doc-util/doc-dfg.js +4 -7
  36. package/documentation/print-interface-wiki.js +7 -1
  37. package/documentation/print-normalized-ast-wiki.js +3 -3
  38. package/documentation/print-readme.js +1 -1
  39. package/package.json +4 -3
  40. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.d.ts +3 -0
  41. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-executor.js +29 -0
  42. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.d.ts +72 -0
  43. package/queries/catalog/dataflow-lens-query/dataflow-lens-query-format.js +24 -0
  44. package/queries/query.d.ts +60 -1
  45. package/queries/query.js +2 -0
  46. package/r-bridge/retriever.d.ts +3 -2
  47. package/r-bridge/retriever.js +26 -7
  48. package/slicing/static/static-slicer.js +2 -2
  49. package/util/mermaid/cfg.js +1 -1
  50. package/util/mermaid/dfg.d.ts +4 -3
  51. package/util/mermaid/dfg.js +13 -10
  52. package/util/objects.d.ts +2 -2
  53. package/util/simple-df/dfg-view.d.ts +16 -0
  54. package/util/simple-df/dfg-view.js +64 -0
  55. package/util/version.js +1 -1
@@ -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
- export type Query = CallContextQuery | ConfigQuery | SearchQuery | DataflowQuery | NormalizedAstQuery | IdMapQuery | DataflowClusterQuery | StaticSliceQuery | LineageQuery | DependenciesQuery | LocationMapQuery | HappensBeforeQuery | ResolveValueQuery;
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,
@@ -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* {@link retrieveParseDataFromRCode} (or {@link retrieveNormalizedAstFromRCode})
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>;
@@ -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* {@link retrieveParseDataFromRCode} (or {@link retrieveNormalizedAstFromRCode})
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.controlDependencies && currentVertex.controlDependencies.length > 0) {
63
+ if (currentVertex.cds && currentVertex.cds.length > 0) {
64
64
  const topLevel = graph.isRoot(id) || sliceSeedIds.has(id);
65
- for (const cd of currentVertex.controlDependencies.filter(({ id }) => !queue.hasId(id))) {
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
  }
@@ -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 TD\n';
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);
@@ -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 - The graph to convert
47
+ * @param graph - The graph to convert
48
48
  * @param includeEnvironments - Whether to include the environments in the mermaid graph code
49
- * @param mark - Special nodes to mark (e.g., those included in the slice)
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>): string;
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;
@@ -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
- mermaid.nodeLines.push(`\nsubgraph "${subflowId}" ["${(0, mermaid_1.escapeMarkdown)(nodeLexeme ?? 'function')}"]`);
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 escapedName = '**' + (0, mermaid_1.escapeMarkdown)(node ? `${lexeme}` : '??') + '**' + (node ? `\n*${node.type}*` : '');
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.controlDependencies ? ', :may:' + info.controlDependencies.map(c => c.id + (c.when ? '+' : '-')).join(',') : '';
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.controlDependencies ?? []).map(x => [x.id, { types: new Set([x.when ? 'CD-True' : 'CD-False']) }]);
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 TD', 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' } }) {
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 - The graph to convert
213
+ * @param graph - The graph to convert
212
214
  * @param includeEnvironments - Whether to include the environments in the mermaid graph code
213
- * @param mark - Special nodes to mark (e.g., those included in the slice)
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 TD\nsubgraph "${left.label}"\n${leftGraph}\nend\nsubgraph "${right.label}"\n${rightGraph}\nend`;
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.8';
6
+ const version = '2.2.9';
7
7
  function flowrVersion() {
8
8
  return new semver_1.SemVer(version);
9
9
  }