@eagleoutice/flowr 2.7.4 → 2.7.5
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 +15 -15
- package/cli/repl/commands/repl-commands.d.ts +2 -0
- package/cli/repl/commands/repl-commands.js +2 -0
- package/cli/repl/commands/repl-dataflow.d.ts +2 -0
- package/cli/repl/commands/repl-dataflow.js +38 -1
- package/cli/repl/core.js +22 -0
- package/config.d.ts +5 -0
- package/config.js +6 -0
- package/dataflow/graph/graph.js +2 -0
- package/documentation/wiki-analyzer.js +12 -0
- package/documentation/wiki-interface.js +3 -0
- package/documentation/wiki-query.js +1 -1
- package/package.json +5 -1
- package/project/context/flowr-analyzer-dependencies-context.d.ts +5 -1
- package/project/context/flowr-analyzer-functions-context.d.ts +16 -0
- package/project/context/flowr-analyzer-functions-context.js +6 -0
- package/project/context/flowr-analyzer-loading-order-context.d.ts +4 -4
- package/project/context/flowr-analyzer-loading-order-context.js +4 -0
- package/project/plugins/file-plugins/files/flowr-description-file.d.ts +18 -1
- package/project/plugins/file-plugins/files/flowr-description-file.js +70 -13
- package/project/plugins/loading-order-plugins/flowr-analyzer-loading-order-description-file-plugin.js +8 -3
- package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-description-file-plugin.js +5 -2
- package/project/plugins/package-version-plugins/flowr-analyzer-package-versions-namespace-file-plugin.js +6 -1
- package/project/plugins/package-version-plugins/package.js +1 -1
- package/project/plugins/project-discovery/flowr-analyzer-project-discovery-plugin.js +12 -2
- package/queries/catalog/project-query/project-query-executor.js +12 -2
- package/queries/catalog/project-query/project-query-format.d.ts +13 -0
- package/queries/catalog/project-query/project-query-format.js +25 -2
- package/queries/query-print.js +8 -3
- package/util/mermaid/cfg.d.ts +3 -0
- package/util/mermaid/cfg.js +25 -0
- package/util/r-author.d.ts +39 -0
- package/util/r-author.js +194 -0
- package/util/simple-df/dfg-ascii.d.ts +5 -0
- package/util/simple-df/dfg-ascii.js +272 -0
- package/util/version.js +1 -1
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.dfgToAscii = dfgToAscii;
|
|
4
|
+
const dagre_1 = require("dagre");
|
|
5
|
+
const edge_1 = require("../../dataflow/graph/edge");
|
|
6
|
+
const node_id_1 = require("../../r-bridge/lang-4.x/ast/model/processing/node-id");
|
|
7
|
+
const vertex_1 = require("../../dataflow/graph/vertex");
|
|
8
|
+
function combineAscii(has, add) {
|
|
9
|
+
if (has === ' ' || has === add) {
|
|
10
|
+
return add;
|
|
11
|
+
}
|
|
12
|
+
const [a, b] = [has, add].sort();
|
|
13
|
+
let res = add;
|
|
14
|
+
if (b === edgesChar.vertical && a === edgesChar.horizontal) {
|
|
15
|
+
res = '┼';
|
|
16
|
+
}
|
|
17
|
+
else if ((b === edgesChar.topRight || b === edgesChar.topLeft || b === '┬') && a === edgesChar.horizontal) {
|
|
18
|
+
res = '┬';
|
|
19
|
+
}
|
|
20
|
+
else if ((b === edgesChar.bottomRight || b === edgesChar.bottomLeft || b === '┴') && a === edgesChar.horizontal) {
|
|
21
|
+
res = '┴';
|
|
22
|
+
}
|
|
23
|
+
else if ((b === edgesChar.topRight || b === edgesChar.bottomRight || b === '┤') && a === edgesChar.vertical) {
|
|
24
|
+
res = '┤';
|
|
25
|
+
}
|
|
26
|
+
else if ((b === edgesChar.topLeft || b === edgesChar.bottomLeft || b === '├') && a === edgesChar.vertical) {
|
|
27
|
+
res = '├';
|
|
28
|
+
}
|
|
29
|
+
else if ((b === '┤' || b === '├') && a === edgesChar.horizontal) {
|
|
30
|
+
res = '┼';
|
|
31
|
+
}
|
|
32
|
+
else if ((b === '┬' || b === '┴') && a === edgesChar.vertical) {
|
|
33
|
+
res = '┼';
|
|
34
|
+
}
|
|
35
|
+
return res;
|
|
36
|
+
}
|
|
37
|
+
class AsciiCanvas {
|
|
38
|
+
filler;
|
|
39
|
+
grid;
|
|
40
|
+
shiftX;
|
|
41
|
+
shiftY;
|
|
42
|
+
constructor(filler = ' ', shiftX = 0, shiftY = 0) {
|
|
43
|
+
this.grid = [];
|
|
44
|
+
this.filler = filler;
|
|
45
|
+
this.shiftX = shiftX;
|
|
46
|
+
this.shiftY = shiftY;
|
|
47
|
+
}
|
|
48
|
+
set(x, y, char, overwrite = false) {
|
|
49
|
+
x += this.shiftX;
|
|
50
|
+
y += this.shiftY;
|
|
51
|
+
if (x < 0 || y < 0 || isNaN(x) || isNaN(y)) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
while (this.grid.length <= y) {
|
|
55
|
+
this.grid.push([]);
|
|
56
|
+
}
|
|
57
|
+
while (this.grid[y].length <= x) {
|
|
58
|
+
this.grid[y].push(this.filler);
|
|
59
|
+
}
|
|
60
|
+
this.grid[y][x] = overwrite ? char : combineAscii(this.grid[y][x], char);
|
|
61
|
+
}
|
|
62
|
+
drawText(x, y, text) {
|
|
63
|
+
for (let i = 0; i < text.length; i++) {
|
|
64
|
+
this.set(x + i, y, text[i]);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
toString() {
|
|
68
|
+
return this.grid.map(r => r.join('')).join('\n');
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Converts the given dataflow graph to an ASCII representation.
|
|
73
|
+
*/
|
|
74
|
+
function dfgToAscii(dfg) {
|
|
75
|
+
const g = new dagre_1.graphlib.Graph();
|
|
76
|
+
const verts = Array.from(dfg.vertices(true));
|
|
77
|
+
g.setGraph({
|
|
78
|
+
nodesep: 1,
|
|
79
|
+
ranksep: 4,
|
|
80
|
+
edgesep: 0,
|
|
81
|
+
rankdir: verts.length < 15 ? 'LR' : 'TB',
|
|
82
|
+
ranker: 'longest-path',
|
|
83
|
+
});
|
|
84
|
+
for (const [id, v] of verts) {
|
|
85
|
+
let label = (0, node_id_1.recoverName)(id, dfg.idMap) ?? v.tag;
|
|
86
|
+
if (label.length < 3) {
|
|
87
|
+
label = label.padStart(2, ' ').padEnd(3, ' ');
|
|
88
|
+
}
|
|
89
|
+
g.setNode(String(id), {
|
|
90
|
+
label,
|
|
91
|
+
width: Math.max(3, label.length * 2),
|
|
92
|
+
height: 3,
|
|
93
|
+
shape: 'rectangle'
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
const edgesDone = new Set();
|
|
97
|
+
let longestId = 0;
|
|
98
|
+
for (const [from, edges] of dfg.edges()) {
|
|
99
|
+
longestId = Math.max(longestId, String(from).length);
|
|
100
|
+
for (const [to, { types }] of edges) {
|
|
101
|
+
if (!g.hasNode(String(from)) || !g.hasNode(String(to)) || edgesDone.has(`${to}-${from}`)) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
longestId = Math.max(longestId, String(to).length);
|
|
105
|
+
g.setEdge(String(from), String(to), (0, edge_1.edgeTypesToNames)(types));
|
|
106
|
+
edgesDone.add(`${from}-${to}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
(0, dagre_1.layout)(g, {
|
|
110
|
+
minlen: 2
|
|
111
|
+
});
|
|
112
|
+
const canvas = new AsciiCanvas();
|
|
113
|
+
renderEdges(g, canvas);
|
|
114
|
+
renderVertices(dfg, g, canvas);
|
|
115
|
+
const lines = canvas.toString().split('\n').filter(line => line.trim() !== '');
|
|
116
|
+
const edgeLines = [];
|
|
117
|
+
// add all edges
|
|
118
|
+
for (const [from, edges] of dfg.edges()) {
|
|
119
|
+
for (const [to, { types }] of edges) {
|
|
120
|
+
if (!g.hasNode(String(from)) || !g.hasNode(String(to))) {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
edgeLines.push(`${from.toString().padStart(longestId, ' ')} -> ${to.toString().padStart(longestId, ' ')}: ${Array.from((0, edge_1.edgeTypesToNames)(types)).join(', ')}`);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// always merge two edgelines with padding
|
|
127
|
+
if (edgeLines.length > 0) {
|
|
128
|
+
lines.push('Edges:');
|
|
129
|
+
}
|
|
130
|
+
const longestFirstLine = Math.max(...edgeLines.map(l => l.length));
|
|
131
|
+
for (let i = 0; i < edgeLines.length; i += 2) {
|
|
132
|
+
const line1 = edgeLines[i];
|
|
133
|
+
const line2 = edgeLines[i + 1];
|
|
134
|
+
if (line2) {
|
|
135
|
+
lines.push(line1.padEnd(Math.min(50, longestFirstLine), ' ') + line2);
|
|
136
|
+
}
|
|
137
|
+
else {
|
|
138
|
+
lines.push(line1);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return lines.join('\n');
|
|
142
|
+
}
|
|
143
|
+
const type2Edge = {
|
|
144
|
+
[vertex_1.VertexType.FunctionCall]: 'c',
|
|
145
|
+
[vertex_1.VertexType.Use]: 'u',
|
|
146
|
+
[vertex_1.VertexType.FunctionDefinition]: 'f',
|
|
147
|
+
[vertex_1.VertexType.VariableDefinition]: 'v',
|
|
148
|
+
[vertex_1.VertexType.Value]: '0'
|
|
149
|
+
};
|
|
150
|
+
function renderVertices(dfg, g, canvas) {
|
|
151
|
+
for (const nodeId of g.nodes()) {
|
|
152
|
+
const node = g.node(nodeId);
|
|
153
|
+
if (!node) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
const label = node.label;
|
|
157
|
+
const x = Math.round(node.x);
|
|
158
|
+
const y = Math.round(node.y);
|
|
159
|
+
const tag = dfg.getVertex((0, node_id_1.normalizeIdToNumberIfPossible)(nodeId))?.tag;
|
|
160
|
+
let e = '+';
|
|
161
|
+
if (tag && tag in type2Edge) {
|
|
162
|
+
e = type2Edge[tag];
|
|
163
|
+
}
|
|
164
|
+
canvas.drawText(x - 1, y - 1, `${e}${'-'.repeat(label.length)}${e}`);
|
|
165
|
+
canvas.drawText(x - 1 + Math.round(label.length / 2 - nodeId.length / 2), y - 1, `<${nodeId}>`);
|
|
166
|
+
canvas.drawText(x - 1, y, `|${label}|`);
|
|
167
|
+
canvas.drawText(x - 1, y + 1, `${e}${'-'.repeat(label.length)}${e}`);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const edgesChar = {
|
|
171
|
+
vertical: '│',
|
|
172
|
+
horizontal: '─',
|
|
173
|
+
topLeft: '┌',
|
|
174
|
+
topRight: '┐',
|
|
175
|
+
bottomLeft: '└',
|
|
176
|
+
bottomRight: '┘',
|
|
177
|
+
};
|
|
178
|
+
function determineCornerChar(lastDirection, px, py, tx, ty) {
|
|
179
|
+
if (px === tx) {
|
|
180
|
+
return edgesChar.vertical;
|
|
181
|
+
}
|
|
182
|
+
else if (py === ty) {
|
|
183
|
+
return edgesChar.horizontal;
|
|
184
|
+
}
|
|
185
|
+
else if (px < tx) {
|
|
186
|
+
if (py < ty) {
|
|
187
|
+
return lastDirection === 'horizontal' ? edgesChar.topRight : edgesChar.bottomLeft;
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
return lastDirection === 'horizontal' ? edgesChar.bottomRight : edgesChar.topLeft;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
if (py < ty) {
|
|
195
|
+
return lastDirection === 'horizontal' ? edgesChar.topLeft : edgesChar.bottomRight;
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
return lastDirection === 'horizontal' ? edgesChar.bottomLeft : edgesChar.topRight;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
function renderEdges(g, canvas) {
|
|
203
|
+
const otherEdges = new Set();
|
|
204
|
+
for (const e of g.edges()) {
|
|
205
|
+
const edge = g.edge(e);
|
|
206
|
+
let points = edge.points;
|
|
207
|
+
// we rework edges into sequences of straight lines only, adding intermediate points as needed
|
|
208
|
+
const newPoints = [points[0]];
|
|
209
|
+
for (let i = 1; i < points.length; i++) {
|
|
210
|
+
const prev = points[i - 1];
|
|
211
|
+
const curr = points[i];
|
|
212
|
+
if (prev.x !== curr.x && prev.y !== curr.y) {
|
|
213
|
+
const intermediate = { x: prev.x, y: curr.y };
|
|
214
|
+
newPoints.push(intermediate);
|
|
215
|
+
}
|
|
216
|
+
newPoints.push(curr);
|
|
217
|
+
}
|
|
218
|
+
points = newPoints;
|
|
219
|
+
let lastDirection = null;
|
|
220
|
+
// let single edges overwrite themselves
|
|
221
|
+
const writtenPoints = new Set();
|
|
222
|
+
for (let i = 0; i < points.length - 1; i++) {
|
|
223
|
+
const p = points[i - 1] ?? points[i];
|
|
224
|
+
const a = points[i];
|
|
225
|
+
const b = points[i + 1];
|
|
226
|
+
const px = Math.round(p.x);
|
|
227
|
+
const py = Math.round(p.y);
|
|
228
|
+
const x1 = Math.round(a.x);
|
|
229
|
+
const y1 = Math.round(a.y);
|
|
230
|
+
const x2 = Math.round(b.x);
|
|
231
|
+
const y2 = Math.round(b.y);
|
|
232
|
+
if (x1 === x2) {
|
|
233
|
+
// vertical
|
|
234
|
+
const [start, end] = y1 < y2 ? [y1, y2] : [y2, y1];
|
|
235
|
+
for (let y = start; y <= end; y++) {
|
|
236
|
+
const key = `${x1},${y}`;
|
|
237
|
+
const overwrite = writtenPoints.has(key) && !otherEdges.has(key);
|
|
238
|
+
if (y === (y1 < y2 ? start : end)) {
|
|
239
|
+
const cornerChar = determineCornerChar(lastDirection, px, py, x2, y2);
|
|
240
|
+
canvas.set(x1, y, cornerChar, overwrite);
|
|
241
|
+
}
|
|
242
|
+
else {
|
|
243
|
+
canvas.set(x1, y, edgesChar.vertical, overwrite);
|
|
244
|
+
}
|
|
245
|
+
writtenPoints.add(`${x1},${y}`);
|
|
246
|
+
}
|
|
247
|
+
lastDirection = 'vertical';
|
|
248
|
+
}
|
|
249
|
+
else if (y1 === y2) {
|
|
250
|
+
// horizontal
|
|
251
|
+
const [start, end] = x1 < x2 ? [x1, x2] : [x2, x1];
|
|
252
|
+
for (let x = start; x <= end; x++) {
|
|
253
|
+
const key = `${x},${y1}`;
|
|
254
|
+
const overwrite = writtenPoints.has(key) && !otherEdges.has(key);
|
|
255
|
+
if (x === (x1 < x2 ? start : end)) {
|
|
256
|
+
const cornerChar = determineCornerChar(lastDirection, px, py, x2, y2);
|
|
257
|
+
canvas.set(x, y1, cornerChar, overwrite);
|
|
258
|
+
}
|
|
259
|
+
else {
|
|
260
|
+
canvas.set(x, y1, edgesChar.horizontal, overwrite);
|
|
261
|
+
}
|
|
262
|
+
writtenPoints.add(`${x},${y1}`);
|
|
263
|
+
}
|
|
264
|
+
lastDirection = 'horizontal';
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
for (const p of writtenPoints) {
|
|
268
|
+
otherEdges.add(p);
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
//# sourceMappingURL=dfg-ascii.js.map
|
package/util/version.js
CHANGED
|
@@ -6,7 +6,7 @@ exports.printVersionInformation = printVersionInformation;
|
|
|
6
6
|
const semver_1 = require("semver");
|
|
7
7
|
const assert_1 = require("./assert");
|
|
8
8
|
// this is automatically replaced with the current version by release-it
|
|
9
|
-
const version = '2.7.
|
|
9
|
+
const version = '2.7.5';
|
|
10
10
|
/**
|
|
11
11
|
* Retrieves the current flowR version as a new {@link SemVer} object.
|
|
12
12
|
*/
|