@jsenv/terminal-recorder 1.1.6 → 1.1.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/package.json +2 -2
- package/src/svg/parse_ansi.js +1 -0
- package/src/svg/render_terminal_svg.js +10 -11
- package/src/svg/xml_generator.js +22 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/terminal-recorder",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.9",
|
|
4
4
|
"description": "Record terminal output as .svg, .gif, .webm, .mp4",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"prepublishOnly": "npm run build"
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
|
-
"@jsenv/server": "15.2.
|
|
35
|
+
"@jsenv/server": "15.2.10",
|
|
36
36
|
"@playwright/browser-webkit": "1.45.1",
|
|
37
37
|
"ansi-regex": "6.0.1",
|
|
38
38
|
"he": "1.2.0",
|
package/src/svg/parse_ansi.js
CHANGED
|
@@ -206,10 +206,9 @@ export const renderTerminalSvg = async (
|
|
|
206
206
|
if (type !== "text") {
|
|
207
207
|
continue;
|
|
208
208
|
}
|
|
209
|
-
|
|
210
209
|
const { position } = chunk;
|
|
211
210
|
const x =
|
|
212
|
-
offsetLeft +
|
|
211
|
+
offsetLeft + (position.x + leadingWhitespaceWidth(value)) * font.width;
|
|
213
212
|
const y = offsetTop + position.y + font.lineHeight * position.y;
|
|
214
213
|
const w = font.width * value.length;
|
|
215
214
|
const attrs = {};
|
|
@@ -244,7 +243,7 @@ export const renderTerminalSvg = async (
|
|
|
244
243
|
}
|
|
245
244
|
|
|
246
245
|
// Underline & Strikethrough:
|
|
247
|
-
// Some SVG
|
|
246
|
+
// Some SVG implementations do not support underline and
|
|
248
247
|
// strikethrough for <text> elements (see Sketch 49.2)
|
|
249
248
|
if (style.underline) {
|
|
250
249
|
const yOffset = font.height * 0.14;
|
|
@@ -267,14 +266,10 @@ export const renderTerminalSvg = async (
|
|
|
267
266
|
textContainer.appendChild(path);
|
|
268
267
|
}
|
|
269
268
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
value.replace(/ /g, "").length === 0 &&
|
|
273
|
-
Object.keys(attrs).length === 0
|
|
274
|
-
) {
|
|
269
|
+
if (value.trim() === "") {
|
|
270
|
+
// Do not output elements containing only whitespace
|
|
275
271
|
continue;
|
|
276
272
|
}
|
|
277
|
-
|
|
278
273
|
const text = svg.createNode("text", {
|
|
279
274
|
x,
|
|
280
275
|
y,
|
|
@@ -294,7 +289,11 @@ export const renderTerminalSvg = async (
|
|
|
294
289
|
|
|
295
290
|
// Some SVG Implementations drop whitespaces
|
|
296
291
|
// https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/xml:space
|
|
297
|
-
|
|
292
|
+
// and https://codepen.io/dmail/pen/wvLvbbP
|
|
293
|
+
const leadingWhitespaceWidth = (text) => {
|
|
294
|
+
if (text.trim() === "") {
|
|
295
|
+
return 0;
|
|
296
|
+
}
|
|
298
297
|
const leadingSpace = text.match(/^\s*/g);
|
|
299
|
-
return
|
|
298
|
+
return leadingSpace[0].length;
|
|
300
299
|
};
|
package/src/svg/xml_generator.js
CHANGED
|
@@ -1,21 +1,31 @@
|
|
|
1
1
|
import he from "he";
|
|
2
2
|
|
|
3
|
+
export const encodeTextContent = (content) => {
|
|
4
|
+
return he.encode(content, {
|
|
5
|
+
decimal: false,
|
|
6
|
+
});
|
|
7
|
+
};
|
|
8
|
+
|
|
3
9
|
export const createXmlGenerator = ({
|
|
4
10
|
rootNodeName,
|
|
5
11
|
canSelfCloseNames = [],
|
|
6
12
|
canReceiveChildNames = [],
|
|
7
13
|
canReceiveContentNames = [],
|
|
14
|
+
canInjectWhitespacesAroundContentNames = [],
|
|
8
15
|
}) => {
|
|
9
16
|
const createNode = (name, attributes = {}) => {
|
|
10
17
|
const canSelfClose = canSelfCloseNames.includes(name);
|
|
11
18
|
const canReceiveChild = canReceiveChildNames.includes(name);
|
|
12
19
|
const canReceiveContent = canReceiveContentNames.includes(name);
|
|
20
|
+
const canInjectWhitespacesAroundContent =
|
|
21
|
+
canInjectWhitespacesAroundContentNames.includes(name);
|
|
13
22
|
|
|
14
23
|
const children = [];
|
|
15
24
|
|
|
16
25
|
const node = {
|
|
17
26
|
name,
|
|
18
27
|
content: "",
|
|
28
|
+
contentIsSafe: false,
|
|
19
29
|
children,
|
|
20
30
|
attributes,
|
|
21
31
|
canSelfClose,
|
|
@@ -27,11 +37,12 @@ export const createXmlGenerator = ({
|
|
|
27
37
|
children.push(childNode);
|
|
28
38
|
return childNode;
|
|
29
39
|
},
|
|
30
|
-
setContent: (value) => {
|
|
40
|
+
setContent: (value, isSafe = false) => {
|
|
31
41
|
if (!canReceiveContent) {
|
|
32
42
|
throw new Error(`cannot setContent on ${name}`);
|
|
33
43
|
}
|
|
34
44
|
node.content = value;
|
|
45
|
+
node.contentIsSafe = isSafe;
|
|
35
46
|
},
|
|
36
47
|
renderAsString: () => {
|
|
37
48
|
const renderNode = (node, { depth }) => {
|
|
@@ -73,13 +84,17 @@ export const createXmlGenerator = ({
|
|
|
73
84
|
|
|
74
85
|
let innerHTML = "";
|
|
75
86
|
if (node.content) {
|
|
76
|
-
if (
|
|
87
|
+
if (canInjectWhitespacesAroundContent) {
|
|
77
88
|
innerHTML += "\n ";
|
|
78
89
|
innerHTML += " ".repeat(depth);
|
|
79
90
|
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
91
|
+
if (node.contentIsSafe) {
|
|
92
|
+
innerHTML += node.content;
|
|
93
|
+
} else {
|
|
94
|
+
const contentEncoded = encodeTextContent(node.content);
|
|
95
|
+
innerHTML += contentEncoded;
|
|
96
|
+
}
|
|
97
|
+
if (canInjectWhitespacesAroundContent) {
|
|
83
98
|
innerHTML += "\n";
|
|
84
99
|
innerHTML += " ".repeat(depth);
|
|
85
100
|
}
|
|
@@ -127,7 +142,8 @@ export const createSvgRootNode = createXmlGenerator({
|
|
|
127
142
|
rootNodeName: "svg",
|
|
128
143
|
canSelfCloseNames: ["path", "rect", "circle"],
|
|
129
144
|
canReceiveChildNames: ["svg", "foreignObject", "g"],
|
|
130
|
-
canReceiveContentNames: ["text", "style"],
|
|
145
|
+
canReceiveContentNames: ["text", "tspan", "style"],
|
|
146
|
+
canInjectWhitespacesAroundContentNames: ["style"],
|
|
131
147
|
});
|
|
132
148
|
|
|
133
149
|
// not used for now and needs to configure canReceiveChildNames and so on...
|