@jsenv/terminal-recorder 1.1.7 → 1.1.10

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/terminal-recorder",
3
- "version": "1.1.7",
3
+ "version": "1.1.10",
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.10",
35
+ "@jsenv/server": "15.2.11",
36
36
  "@playwright/browser-webkit": "1.45.1",
37
37
  "ansi-regex": "6.0.1",
38
38
  "he": "1.2.0",
@@ -143,6 +143,7 @@ export const parseAnsi = (ansi) => {
143
143
  styleState.strikethrough = false;
144
144
  },
145
145
  reset: () => {
146
+ styleState.underline = false;
146
147
  styleState.strikethrough = false;
147
148
  styleState.inverse = false;
148
149
  styleState.italic = false;
@@ -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 + adjustXforWhitespace(value, position.x) * font.width;
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 implmentations do not support underline and
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
- // Do not output elements containing whitespace with no style
271
- if (
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
- const adjustXforWhitespace = (text, x) => {
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 x + leadingSpace[0].length;
298
+ return leadingSpace[0].length;
300
299
  };
@@ -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 (node.name !== "text") {
87
+ if (canInjectWhitespacesAroundContent) {
77
88
  innerHTML += "\n ";
78
89
  innerHTML += " ".repeat(depth);
79
90
  }
80
- const contentEncoded = he.encode(node.content, { decimal: false });
81
- innerHTML += contentEncoded;
82
- if (node.name !== "text") {
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...