@eagleoutice/flowr 2.7.3 → 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 +17 -17
- 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/extractor.js +13 -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/call-context-query/call-context-query-executor.js +2 -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
package/util/r-author.js
ADDED
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.AuthorRole = void 0;
|
|
4
|
+
exports.rAuthorInfoToReadable = rAuthorInfoToReadable;
|
|
5
|
+
exports.parseRAuthorString = parseRAuthorString;
|
|
6
|
+
const args_1 = require("./text/args");
|
|
7
|
+
const assert_1 = require("./assert");
|
|
8
|
+
const objects_1 = require("./objects");
|
|
9
|
+
const retriever_1 = require("../r-bridge/retriever");
|
|
10
|
+
/** https://r-pkgs.org/description.html#sec-description-authors-at-r */
|
|
11
|
+
var AuthorRole;
|
|
12
|
+
(function (AuthorRole) {
|
|
13
|
+
/** the creator or maintainer, the person you should bother if you have problems. Despite being short for “creator”, this is the correct role to use for the current maintainer, even if they are not the initial creator of the package. */
|
|
14
|
+
AuthorRole["Creator"] = "cre";
|
|
15
|
+
/** authors, those who have made significant contributions to the package. */
|
|
16
|
+
AuthorRole["Author"] = "aut";
|
|
17
|
+
/** contributors, those who have made smaller contributions, like patches. */
|
|
18
|
+
AuthorRole["Contributor"] = "ctb";
|
|
19
|
+
/** copyright holder. This is used to list additional copyright holders who are not authors, typically companies, like an employer of one or more of the authors. */
|
|
20
|
+
AuthorRole["CopyrightHolder"] = "cph";
|
|
21
|
+
/** funder, the people or organizations that have provided financial support for the development of the package. */
|
|
22
|
+
AuthorRole["Funder"] = "fnd";
|
|
23
|
+
})(AuthorRole || (exports.AuthorRole = AuthorRole = {}));
|
|
24
|
+
/**
|
|
25
|
+
* Convert structured R author information into an R `Authors@R` string.
|
|
26
|
+
*/
|
|
27
|
+
function rAuthorInfoToReadable(author) {
|
|
28
|
+
const nameStr = author.name.join(' ');
|
|
29
|
+
const emailStr = author.email ? ` <${author.email}>` : '';
|
|
30
|
+
const rolesStr = author.roles.length > 0 ? ` [${author.roles.join(', ')}]` : '';
|
|
31
|
+
const orcidStr = author.orcid ? ` (ORCID: ${author.orcid})` : '';
|
|
32
|
+
const commentStr = author.comment && author.comment.length > 0 ? ` {${author.comment.join('; ')}}` : '';
|
|
33
|
+
return `${nameStr}${emailStr}${rolesStr}${orcidStr}${commentStr}`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse an R `Authors@R` string into structured author information.
|
|
37
|
+
* These are mostly found in `R` DESCRIPTION files and are a vector of `person()` calls.
|
|
38
|
+
* For now, this works *without* the full dataflow engine, so complex cases may not be parsed correctly.
|
|
39
|
+
*/
|
|
40
|
+
function parseRAuthorString(authorString) {
|
|
41
|
+
const str = authorString.trim();
|
|
42
|
+
if (str.startsWith('c(') && str.endsWith(')')) {
|
|
43
|
+
const inner = str.slice(2, -1).trim();
|
|
44
|
+
const parts = joinPartsWithVectors((0, args_1.splitAtEscapeSensitive)(inner, false, ','));
|
|
45
|
+
const authors = [];
|
|
46
|
+
for (const part of parts) {
|
|
47
|
+
const author = parseRPersonCall(part);
|
|
48
|
+
if (author) {
|
|
49
|
+
authors.push(author);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return authors;
|
|
53
|
+
}
|
|
54
|
+
else if (str.startsWith('person(') && str.endsWith(')')) {
|
|
55
|
+
const author = parseRPersonCall(str);
|
|
56
|
+
return author ? [author] : [];
|
|
57
|
+
}
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
function splitArgNameValue(arg) {
|
|
61
|
+
const eqIndex = arg.indexOf('=');
|
|
62
|
+
if (eqIndex === -1) {
|
|
63
|
+
const trimmedArg = arg.trim();
|
|
64
|
+
return { value: trimmedArg.length === 0 ? undefined : trimmedArg };
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
const name = arg.slice(0, eqIndex).trim();
|
|
68
|
+
const value = arg.slice(eqIndex + 1).trim();
|
|
69
|
+
return { name, value };
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
// Joins parts that may be split by c(...) vectors back together, ...
|
|
73
|
+
function joinPartsWithVectors(parts) {
|
|
74
|
+
const result = [];
|
|
75
|
+
let buffer = [];
|
|
76
|
+
let parenthesisLevel = 0;
|
|
77
|
+
for (const part of parts) {
|
|
78
|
+
const trimmed = part.trim();
|
|
79
|
+
// check whether parenthesis are balanced
|
|
80
|
+
for (const char of trimmed) {
|
|
81
|
+
if (char === '(') {
|
|
82
|
+
parenthesisLevel++;
|
|
83
|
+
}
|
|
84
|
+
else if (char === ')') {
|
|
85
|
+
parenthesisLevel--;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
if (parenthesisLevel === 0) {
|
|
89
|
+
buffer.push(trimmed);
|
|
90
|
+
result.push(buffer.join(', '));
|
|
91
|
+
buffer = [];
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
buffer.push(trimmed);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
if (buffer.length > 0) {
|
|
98
|
+
result.push(buffer.join(', '));
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
const defaultPosArgNames = ['given', 'family', 'middle', 'email', 'role', 'comment', 'first', 'last'];
|
|
103
|
+
function splitVector(roleStr) {
|
|
104
|
+
if (roleStr.startsWith('c(') && roleStr.endsWith(')')) {
|
|
105
|
+
const inner = roleStr.slice(2, -1).trim();
|
|
106
|
+
return joinPartsWithVectors((0, args_1.splitAtEscapeSensitive)(inner, false, ','));
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
return [roleStr.trim()];
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function parseRoles(roleStr) {
|
|
113
|
+
if (!roleStr) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
const roles = [];
|
|
117
|
+
const parts = splitVector(roleStr);
|
|
118
|
+
for (const part of parts) {
|
|
119
|
+
const trimmed = part.trim();
|
|
120
|
+
const roleValue = (0, retriever_1.removeRQuotes)(trimmed);
|
|
121
|
+
if (Object.values(AuthorRole).includes(roleValue)) {
|
|
122
|
+
roles.push(roleValue);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
return roles;
|
|
126
|
+
}
|
|
127
|
+
function parseComments(commentStr) {
|
|
128
|
+
if (!commentStr) {
|
|
129
|
+
return undefined;
|
|
130
|
+
}
|
|
131
|
+
const comments = [];
|
|
132
|
+
const parts = splitVector(commentStr);
|
|
133
|
+
let orcid = undefined;
|
|
134
|
+
for (const part of parts) {
|
|
135
|
+
const trimmed = part.trim();
|
|
136
|
+
const commentValue = (0, retriever_1.removeRQuotes)(trimmed);
|
|
137
|
+
if (/ORCID\s*=/ig.test(commentValue)) {
|
|
138
|
+
const orcidIndex = commentValue.indexOf('=');
|
|
139
|
+
if (orcidIndex !== -1) {
|
|
140
|
+
orcid = (0, retriever_1.removeRQuotes)(commentValue.slice(orcidIndex + 1).trim());
|
|
141
|
+
}
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
comments.push(commentValue);
|
|
145
|
+
}
|
|
146
|
+
return comments.length > 0 || orcid ? { contents: comments, orcid: orcid } : undefined;
|
|
147
|
+
}
|
|
148
|
+
function assignArg(argMap, split) {
|
|
149
|
+
argMap.set(split.name, split.value === undefined || split.value?.length === 0 ? undefined : (0, retriever_1.removeRQuotes)(split.value));
|
|
150
|
+
}
|
|
151
|
+
function parseRPersonCall(personCall) {
|
|
152
|
+
/* function(given = NULL, family = NULL, middle = NULL,
|
|
153
|
+
email = NULL, role = NULL, comment = NULL,
|
|
154
|
+
first = NULL, last = NULL), but we neither use nor support full R semantics here for now */
|
|
155
|
+
personCall = personCall.trim();
|
|
156
|
+
if (!personCall.startsWith('person(') || !personCall.endsWith(')')) {
|
|
157
|
+
return undefined;
|
|
158
|
+
}
|
|
159
|
+
const inner = personCall.slice(7, -1).trim();
|
|
160
|
+
// these may also split unescaped commas inside c(...)
|
|
161
|
+
const parArgs = joinPartsWithVectors((0, args_1.splitAtEscapeSensitive)(inner, false, ','));
|
|
162
|
+
const argMap = new Map();
|
|
163
|
+
const unnamed = [];
|
|
164
|
+
for (const arg of parArgs) {
|
|
165
|
+
const split = splitArgNameValue(arg.trim());
|
|
166
|
+
if (!split.name) {
|
|
167
|
+
unnamed.push(arg.trim());
|
|
168
|
+
continue;
|
|
169
|
+
}
|
|
170
|
+
assignArg(argMap, split);
|
|
171
|
+
}
|
|
172
|
+
// assign unnamed args in order
|
|
173
|
+
for (let i = 0; i < unnamed.length; i++) {
|
|
174
|
+
if (i >= defaultPosArgNames.length) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
const argIdx = defaultPosArgNames.findIndex(x => !argMap.has(x));
|
|
178
|
+
if (argIdx === -1) {
|
|
179
|
+
break;
|
|
180
|
+
}
|
|
181
|
+
const argName = defaultPosArgNames[argIdx];
|
|
182
|
+
const value = unnamed[i];
|
|
183
|
+
assignArg(argMap, { name: argName, value });
|
|
184
|
+
}
|
|
185
|
+
const comments = parseComments(argMap.get('comment'));
|
|
186
|
+
return (0, objects_1.compactRecord)({
|
|
187
|
+
name: [argMap.get('given') ?? argMap.get('first'), argMap.get('middle'), argMap.get('family') ?? argMap.get('last')].filter(assert_1.isNotUndefined),
|
|
188
|
+
email: argMap.get('email'),
|
|
189
|
+
roles: parseRoles(argMap.get('role')),
|
|
190
|
+
comment: comments?.contents,
|
|
191
|
+
orcid: comments?.orcid
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
//# sourceMappingURL=r-author.js.map
|
|
@@ -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
|
*/
|