@jsenv/terminal-recorder 1.2.2 → 1.3.1
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 +6 -7
- package/src/main.js +4 -3
- package/src/svg/render_terminal_svg.js +63 -54
- package/src/terminal_recording.js +7 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/terminal-recorder",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "Record terminal output as .svg, .gif, .webm, .mp4",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -10,8 +10,7 @@
|
|
|
10
10
|
},
|
|
11
11
|
"author": {
|
|
12
12
|
"name": "dmail",
|
|
13
|
-
"email": "dmaillard06@gmail.com"
|
|
14
|
-
"url": "https://twitter.com/damienmaillard"
|
|
13
|
+
"email": "dmaillard06@gmail.com"
|
|
15
14
|
},
|
|
16
15
|
"publishConfig": {
|
|
17
16
|
"access": "public"
|
|
@@ -32,12 +31,12 @@
|
|
|
32
31
|
"prepublishOnly": "npm run build"
|
|
33
32
|
},
|
|
34
33
|
"dependencies": {
|
|
35
|
-
"@jsenv/humanize": "1.2.
|
|
36
|
-
"@jsenv/server": "15.2.
|
|
37
|
-
"@playwright/browser-chromium": "1.45.
|
|
34
|
+
"@jsenv/humanize": "1.2.4",
|
|
35
|
+
"@jsenv/server": "15.2.13",
|
|
36
|
+
"@playwright/browser-chromium": "1.45.2",
|
|
38
37
|
"ansi-regex": "6.0.1",
|
|
39
38
|
"he": "1.2.0",
|
|
40
|
-
"playwright": "1.45.
|
|
39
|
+
"playwright": "1.45.2",
|
|
41
40
|
"string-width": "5.1.2",
|
|
42
41
|
"strip-ansi": "7.1.0",
|
|
43
42
|
"webm-to-mp4": "1.0.0"
|
package/src/main.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
// not yet available
|
|
2
|
-
// export { renderTerminalHtml } from "./render_terminal_html.js";
|
|
3
|
-
|
|
4
1
|
export { startTerminalRecording } from "./terminal_recording.js";
|
|
5
2
|
export { recordCommandToSvg } from "./command_recording.js";
|
|
3
|
+
|
|
4
|
+
export { renderTerminalSvg } from "./svg/render_terminal_svg.js";
|
|
5
|
+
// not yet available
|
|
6
|
+
// export { renderTerminalHtml } from "./render_terminal_html.js";
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import prettier from "prettier";
|
|
2
1
|
import { parseAnsi } from "./parse_ansi.js";
|
|
3
2
|
import { createSvgRootNode } from "./xml_generator.js";
|
|
4
3
|
|
|
@@ -36,8 +35,11 @@ const colorsDefault = {
|
|
|
36
35
|
bgCyanBright: "#00FFFF",
|
|
37
36
|
bgWhiteBright: "#FFFFFF",
|
|
38
37
|
};
|
|
38
|
+
const headDefault = {
|
|
39
|
+
height: 40,
|
|
40
|
+
};
|
|
39
41
|
|
|
40
|
-
export const renderTerminalSvg =
|
|
42
|
+
export const renderTerminalSvg = (
|
|
41
43
|
ansi,
|
|
42
44
|
{
|
|
43
45
|
title = "ansi to terminal",
|
|
@@ -61,9 +63,10 @@ export const renderTerminalSvg = async (
|
|
|
61
63
|
height,
|
|
62
64
|
maxWidth,
|
|
63
65
|
maxHeight,
|
|
66
|
+
|
|
67
|
+
head = true,
|
|
64
68
|
} = {},
|
|
65
69
|
) => {
|
|
66
|
-
const { rows, columns, chunks } = parseAnsi(ansi);
|
|
67
70
|
const font = {
|
|
68
71
|
size: fontSize,
|
|
69
72
|
width: 8.4013671875,
|
|
@@ -75,13 +78,20 @@ export const renderTerminalSvg = async (
|
|
|
75
78
|
emHeightDescent: 3.4453125,
|
|
76
79
|
};
|
|
77
80
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
81
|
+
let headerHeight = 0;
|
|
82
|
+
if (head) {
|
|
83
|
+
if (head === true) head = {};
|
|
84
|
+
const headOptions = { ...headDefault, ...head };
|
|
85
|
+
headerHeight = headOptions.height;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const { rows, columns, chunks } = parseAnsi(ansi);
|
|
89
|
+
const bodyTextWidth = columns * font.width;
|
|
90
|
+
const bodyTextHeight = rows * (font.lineHeight + 1) + font.emHeightDescent;
|
|
91
|
+
const bodyContentWidth = paddingLeft + bodyTextWidth + paddingRight;
|
|
92
|
+
const bodyContentHeight = paddingTop + bodyTextHeight + paddingBottom;
|
|
93
|
+
let contentWidth = bodyContentWidth;
|
|
94
|
+
let contentHeight = headerHeight + bodyContentHeight;
|
|
85
95
|
|
|
86
96
|
let computedWidth;
|
|
87
97
|
if (typeof width === "number") {
|
|
@@ -111,7 +121,7 @@ export const renderTerminalSvg = async (
|
|
|
111
121
|
backgroundColor,
|
|
112
122
|
});
|
|
113
123
|
|
|
114
|
-
|
|
124
|
+
render_background: {
|
|
115
125
|
const backgroundGroup = svg.createNode("g", {
|
|
116
126
|
id: "background",
|
|
117
127
|
});
|
|
@@ -129,48 +139,50 @@ export const renderTerminalSvg = async (
|
|
|
129
139
|
svg.appendChild(backgroundGroup);
|
|
130
140
|
}
|
|
131
141
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
142
|
+
if (head) {
|
|
143
|
+
render_head: {
|
|
144
|
+
const headerGroup = svg.createNode("g", {
|
|
145
|
+
id: "header",
|
|
146
|
+
});
|
|
147
|
+
const iconsGroup = svg.createNode("g", {
|
|
148
|
+
transform: `translate(20,${headerHeight / 2})`,
|
|
149
|
+
});
|
|
150
|
+
const circleA = svg.createNode("circle", {
|
|
151
|
+
cx: 0,
|
|
152
|
+
cy: 0,
|
|
153
|
+
r: 6,
|
|
154
|
+
fill: "#ff5f57",
|
|
155
|
+
});
|
|
156
|
+
iconsGroup.appendChild(circleA);
|
|
157
|
+
const circleB = svg.createNode("circle", {
|
|
158
|
+
cx: 20,
|
|
159
|
+
cy: 0,
|
|
160
|
+
r: 6,
|
|
161
|
+
fill: "#febc2e",
|
|
162
|
+
});
|
|
163
|
+
iconsGroup.appendChild(circleB);
|
|
164
|
+
const circleC = svg.createNode("circle", {
|
|
165
|
+
cx: 40,
|
|
166
|
+
cy: 0,
|
|
167
|
+
r: 6,
|
|
168
|
+
fill: "#28c840",
|
|
169
|
+
});
|
|
170
|
+
iconsGroup.appendChild(circleC);
|
|
171
|
+
headerGroup.appendChild(iconsGroup);
|
|
161
172
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
173
|
+
const text = svg.createNode("text", {
|
|
174
|
+
"fill": "#abb2bf",
|
|
175
|
+
"text-anchor": "middle",
|
|
176
|
+
"x": computedWidth / 2,
|
|
177
|
+
"y": headerHeight / 2,
|
|
178
|
+
});
|
|
179
|
+
text.setContent(title);
|
|
180
|
+
headerGroup.appendChild(text);
|
|
181
|
+
svg.appendChild(headerGroup);
|
|
182
|
+
}
|
|
171
183
|
}
|
|
172
184
|
|
|
173
|
-
|
|
185
|
+
render_body: {
|
|
174
186
|
const bodyComputedHeight = computedHeight - headerHeight + paddingBottom;
|
|
175
187
|
const foreignObject = svg.createNode("foreignObject", {
|
|
176
188
|
id: "body",
|
|
@@ -281,10 +293,7 @@ export const renderTerminalSvg = async (
|
|
|
281
293
|
}
|
|
282
294
|
|
|
283
295
|
const svgString = svg.renderAsString();
|
|
284
|
-
|
|
285
|
-
parser: "html",
|
|
286
|
-
});
|
|
287
|
-
return formatted;
|
|
296
|
+
return svgString;
|
|
288
297
|
};
|
|
289
298
|
|
|
290
299
|
// Some SVG Implementations drop whitespaces
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
- we should have a webm video
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import prettier from "prettier";
|
|
13
|
+
|
|
12
14
|
import { renderTerminalSvg } from "./svg/render_terminal_svg.js";
|
|
13
15
|
|
|
14
16
|
const isDev = process.execArgv.includes("--conditions=development");
|
|
@@ -155,8 +157,11 @@ export const startTerminalRecording = async ({
|
|
|
155
157
|
}
|
|
156
158
|
terminalRecords.svg = async () => {
|
|
157
159
|
const ansi = recordedFormats.textInViewport;
|
|
158
|
-
const terminalSvg =
|
|
159
|
-
|
|
160
|
+
const terminalSvg = renderTerminalSvg(ansi, svg);
|
|
161
|
+
const terminalSvgFormatted = await prettier.format(terminalSvg, {
|
|
162
|
+
parser: "html",
|
|
163
|
+
});
|
|
164
|
+
return terminalSvgFormatted;
|
|
160
165
|
};
|
|
161
166
|
terminalRecords.gif = () => {
|
|
162
167
|
const terminalGifBuffer = Buffer.from(recordedFormats.gif, "binary");
|