chrome-cdp-cli 2.0.4 → 2.1.0

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.
@@ -5,19 +5,20 @@ const fs_1 = require("fs");
5
5
  const path_1 = require("path");
6
6
  class TakeSnapshotHandler {
7
7
  constructor() {
8
- this.name = 'snapshot';
8
+ this.name = "dom";
9
+ this.aliases = ["snapshot"];
9
10
  this.colors = {
10
- reset: '\x1b[0m',
11
- bright: '\x1b[1m',
12
- dim: '\x1b[2m',
13
- red: '\x1b[31m',
14
- green: '\x1b[32m',
15
- yellow: '\x1b[33m',
16
- blue: '\x1b[34m',
17
- magenta: '\x1b[35m',
18
- cyan: '\x1b[36m',
19
- white: '\x1b[37m',
20
- gray: '\x1b[90m',
11
+ reset: "\x1b[0m",
12
+ bright: "\x1b[1m",
13
+ dim: "\x1b[2m",
14
+ red: "\x1b[31m",
15
+ green: "\x1b[32m",
16
+ yellow: "\x1b[33m",
17
+ blue: "\x1b[34m",
18
+ magenta: "\x1b[35m",
19
+ cyan: "\x1b[36m",
20
+ white: "\x1b[37m",
21
+ gray: "\x1b[90m",
21
22
  };
22
23
  }
23
24
  shouldUseColors(args) {
@@ -30,10 +31,10 @@ class TakeSnapshotHandler {
30
31
  if (process.env.NO_COLOR) {
31
32
  return false;
32
33
  }
33
- if (process.env.FORCE_COLOR === '0') {
34
+ if (process.env.FORCE_COLOR === "0") {
34
35
  return false;
35
36
  }
36
- if (process.env.FORCE_COLOR === '1' || process.env.FORCE_COLOR === 'true') {
37
+ if (process.env.FORCE_COLOR === "1" || process.env.FORCE_COLOR === "true") {
37
38
  return true;
38
39
  }
39
40
  if (args.filename) {
@@ -47,13 +48,13 @@ class TakeSnapshotHandler {
47
48
  return `${color}${text}${this.colors.reset}`;
48
49
  }
49
50
  colorTag(tagName, useColors) {
50
- if (['button', 'a', 'input', 'textarea', 'select'].includes(tagName.toLowerCase())) {
51
+ if (["button", "a", "input", "textarea", "select"].includes(tagName.toLowerCase())) {
51
52
  return this.colorize(tagName.toUpperCase(), this.colors.green + this.colors.bright, useColors);
52
53
  }
53
- if (['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(tagName.toLowerCase())) {
54
+ if (["h1", "h2", "h3", "h4", "h5", "h6"].includes(tagName.toLowerCase())) {
54
55
  return this.colorize(tagName.toUpperCase(), this.colors.cyan + this.colors.bright, useColors);
55
56
  }
56
- if (tagName.toLowerCase() === 'img') {
57
+ if (tagName.toLowerCase() === "img") {
57
58
  return this.colorize(tagName.toUpperCase(), this.colors.magenta, useColors);
58
59
  }
59
60
  return this.colorize(tagName.toUpperCase(), this.colors.cyan, useColors);
@@ -65,10 +66,10 @@ class TakeSnapshotHandler {
65
66
  return this.colorize(`.${className}`, this.colors.yellow, useColors);
66
67
  }
67
68
  colorAttribute(name, value, useColors) {
68
- if (name === 'type') {
69
+ if (name === "type") {
69
70
  return this.colorize(`[${value}]`, this.colors.magenta, useColors);
70
71
  }
71
- if (name === 'name') {
72
+ if (name === "name") {
72
73
  return this.colorize(`name="${value}"`, this.colors.magenta, useColors);
73
74
  }
74
75
  return `[${name}="${value}"]`;
@@ -90,12 +91,12 @@ class TakeSnapshotHandler {
90
91
  }
91
92
  async execute(client, args) {
92
93
  const snapshotArgs = args;
93
- if (snapshotArgs['no-color']) {
94
+ if (snapshotArgs["no-color"]) {
94
95
  snapshotArgs.color = false;
95
96
  }
96
97
  try {
97
- await client.send('DOM.enable');
98
- await client.send('CSS.enable');
98
+ await client.send("DOM.enable");
99
+ await client.send("CSS.enable");
99
100
  try {
100
101
  return await this.captureWithDOMSnapshot(client, snapshotArgs);
101
102
  }
@@ -106,16 +107,16 @@ class TakeSnapshotHandler {
106
107
  catch (error) {
107
108
  return {
108
109
  success: false,
109
- error: error instanceof Error ? error.message : String(error)
110
+ error: error instanceof Error ? error.message : String(error),
110
111
  };
111
112
  }
112
113
  }
113
114
  async captureWithDOMSnapshot(client, snapshotArgs) {
114
- await client.send('DOMSnapshot.enable');
115
+ await client.send("DOMSnapshot.enable");
115
116
  const params = this.buildSnapshotParams(snapshotArgs);
116
- const response = await client.send('DOMSnapshot.captureSnapshot', params);
117
+ const response = (await client.send("DOMSnapshot.captureSnapshot", params));
117
118
  if (!response || !response.documents || response.documents.length === 0) {
118
- throw new Error('Failed to capture DOM snapshot: empty response');
119
+ throw new Error("Failed to capture DOM snapshot: empty response");
119
120
  }
120
121
  const processedSnapshot = this.processSnapshot(response, snapshotArgs);
121
122
  if (snapshotArgs.filename) {
@@ -125,23 +126,25 @@ class TakeSnapshotHandler {
125
126
  data: {
126
127
  message: `DOM snapshot saved to ${snapshotArgs.filename}`,
127
128
  filename: snapshotArgs.filename,
128
- format: snapshotArgs.format || 'text',
129
+ format: snapshotArgs.format || "text",
129
130
  documentsCount: response.documents.length,
130
- nodesCount: response.documents[0]?.nodes?.nodeName?.length || 0
131
- }
131
+ nodesCount: response.documents[0]?.nodes?.nodeName?.length || 0,
132
+ },
132
133
  };
133
134
  }
134
- if (snapshotArgs.format !== 'html' && typeof processedSnapshot === 'object' && processedSnapshot !== null) {
135
+ if (snapshotArgs.format !== "html" &&
136
+ typeof processedSnapshot === "object" &&
137
+ processedSnapshot !== null) {
135
138
  const snapshotObj = processedSnapshot;
136
- if (snapshotObj.snapshot && typeof snapshotObj.snapshot === 'string') {
139
+ if (snapshotObj.snapshot && typeof snapshotObj.snapshot === "string") {
137
140
  return {
138
141
  success: true,
139
142
  data: {
140
143
  snapshot: snapshotObj.snapshot,
141
- format: 'text',
144
+ format: "text",
142
145
  documentsCount: response.documents.length,
143
- nodesCount: response.documents[0]?.nodes?.nodeName?.length || 0
144
- }
146
+ nodesCount: response.documents[0]?.nodes?.nodeName?.length || 0,
147
+ },
145
148
  };
146
149
  }
147
150
  }
@@ -149,26 +152,28 @@ class TakeSnapshotHandler {
149
152
  success: true,
150
153
  data: {
151
154
  snapshot: processedSnapshot,
152
- format: snapshotArgs.format || 'text',
155
+ format: snapshotArgs.format || "text",
153
156
  documentsCount: response.documents.length,
154
- nodesCount: response.documents[0]?.nodes?.nodeName?.length || 0
155
- }
157
+ nodesCount: response.documents[0]?.nodes?.nodeName?.length || 0,
158
+ },
156
159
  };
157
160
  }
158
161
  async captureWithDOM(client, snapshotArgs) {
159
- const docResponse = await client.send('DOM.getDocument', { depth: -1 });
162
+ const docResponse = (await client.send("DOM.getDocument", {
163
+ depth: -1,
164
+ }));
160
165
  if (!docResponse || !docResponse.root) {
161
- throw new Error('Failed to get document root');
166
+ throw new Error("Failed to get document root");
162
167
  }
163
168
  const url = await this.getCurrentURL(client);
164
169
  const title = await this.getCurrentTitle(client);
165
170
  let processedSnapshot;
166
- if (snapshotArgs.format === 'html') {
167
- const htmlResponse = await client.send('DOM.getOuterHTML', {
168
- nodeId: docResponse.root.nodeId
169
- });
171
+ if (snapshotArgs.format === "html") {
172
+ const htmlResponse = (await client.send("DOM.getOuterHTML", {
173
+ nodeId: docResponse.root.nodeId,
174
+ }));
170
175
  if (!htmlResponse || !htmlResponse.outerHTML) {
171
- throw new Error('Failed to get document HTML');
176
+ throw new Error("Failed to get document HTML");
172
177
  }
173
178
  processedSnapshot = htmlResponse.outerHTML;
174
179
  }
@@ -178,7 +183,7 @@ class TakeSnapshotHandler {
178
183
  processedSnapshot = {
179
184
  url,
180
185
  title,
181
- snapshot: textSnapshot
186
+ snapshot: textSnapshot,
182
187
  };
183
188
  }
184
189
  if (snapshotArgs.filename) {
@@ -188,19 +193,21 @@ class TakeSnapshotHandler {
188
193
  data: {
189
194
  message: `DOM snapshot saved to ${snapshotArgs.filename}`,
190
195
  filename: snapshotArgs.filename,
191
- format: snapshotArgs.format || 'text'
192
- }
196
+ format: snapshotArgs.format || "text",
197
+ },
193
198
  };
194
199
  }
195
- if (snapshotArgs.format !== 'html' && typeof processedSnapshot === 'object' && processedSnapshot !== null) {
200
+ if (snapshotArgs.format !== "html" &&
201
+ typeof processedSnapshot === "object" &&
202
+ processedSnapshot !== null) {
196
203
  const snapshotObj = processedSnapshot;
197
- if (snapshotObj.snapshot && typeof snapshotObj.snapshot === 'string') {
204
+ if (snapshotObj.snapshot && typeof snapshotObj.snapshot === "string") {
198
205
  return {
199
206
  success: true,
200
207
  data: {
201
208
  snapshot: snapshotObj.snapshot,
202
- format: 'text'
203
- }
209
+ format: "text",
210
+ },
204
211
  };
205
212
  }
206
213
  }
@@ -208,49 +215,49 @@ class TakeSnapshotHandler {
208
215
  success: true,
209
216
  data: {
210
217
  snapshot: processedSnapshot,
211
- format: snapshotArgs.format || 'text'
212
- }
218
+ format: snapshotArgs.format || "text",
219
+ },
213
220
  };
214
221
  }
215
222
  async getCurrentURL(client) {
216
223
  try {
217
- const result = await client.send('Runtime.evaluate', {
218
- expression: 'window.location.href',
219
- returnByValue: true
220
- });
221
- return result.result?.value || 'unknown';
224
+ const result = (await client.send("Runtime.evaluate", {
225
+ expression: "window.location.href",
226
+ returnByValue: true,
227
+ }));
228
+ return result.result?.value || "unknown";
222
229
  }
223
230
  catch {
224
- return 'unknown';
231
+ return "unknown";
225
232
  }
226
233
  }
227
234
  async getCurrentTitle(client) {
228
235
  try {
229
- const result = await client.send('Runtime.evaluate', {
230
- expression: 'document.title',
231
- returnByValue: true
232
- });
233
- return result.result?.value || 'unknown';
236
+ const result = (await client.send("Runtime.evaluate", {
237
+ expression: "document.title",
238
+ returnByValue: true,
239
+ }));
240
+ return result.result?.value || "unknown";
234
241
  }
235
242
  catch {
236
- return 'unknown';
243
+ return "unknown";
237
244
  }
238
245
  }
239
246
  buildSnapshotParams(args) {
240
247
  const params = {};
241
248
  if (args.includePaintOrder) {
242
- console.log('Paint order requested but not yet supported');
249
+ console.log("Paint order requested but not yet supported");
243
250
  }
244
251
  return params;
245
252
  }
246
253
  processSnapshot(response, args) {
247
- if (args.format === 'html') {
254
+ if (args.format === "html") {
248
255
  return this.convertToHTML(response);
249
256
  }
250
257
  const doc = response.documents[0];
251
258
  if (!doc) {
252
259
  return {
253
- error: 'No documents found'
260
+ error: "No documents found",
254
261
  };
255
262
  }
256
263
  const useColors = this.shouldUseColors(args);
@@ -258,17 +265,17 @@ class TakeSnapshotHandler {
258
265
  const result = {
259
266
  url: doc.documentURL,
260
267
  title: doc.title,
261
- snapshot: textSnapshot
268
+ snapshot: textSnapshot,
262
269
  };
263
270
  return result;
264
271
  }
265
272
  createTextSnapshot(doc, strings, useColors = true) {
266
273
  const nodes = doc.nodes;
267
274
  if (!nodes.nodeName || !nodes.nodeType) {
268
- return 'Empty document';
275
+ return "Empty document";
269
276
  }
270
277
  const nodeTree = this.buildNodeTree(doc, strings);
271
- let output = this.colorPageTitle(doc.title || 'Untitled', useColors) + '\n';
278
+ let output = this.colorPageTitle(doc.title || "Untitled", useColors) + "\n";
272
279
  const bodyNode = this.findBodyNode(nodeTree);
273
280
  if (bodyNode) {
274
281
  output += this.renderNodeAsText(bodyNode, 0, false, [], useColors);
@@ -292,8 +299,8 @@ class TakeSnapshotHandler {
292
299
  nodeType: nodes.nodeType[i],
293
300
  nodeName: nodes.nodeName[i].toLowerCase(),
294
301
  children: [],
295
- textContent: '',
296
- attributes: {}
302
+ textContent: "",
303
+ attributes: {},
297
304
  };
298
305
  if (nodes.nodeValue?.[i]) {
299
306
  node.textContent = nodes.nodeValue[i].trim();
@@ -301,7 +308,7 @@ class TakeSnapshotHandler {
301
308
  if (nodes.textValue?.index.includes(i)) {
302
309
  const textIndex = nodes.textValue.index.indexOf(i);
303
310
  const stringIndex = nodes.textValue.value[textIndex];
304
- if (typeof stringIndex === 'number' && strings[stringIndex]) {
311
+ if (typeof stringIndex === "number" && strings[stringIndex]) {
305
312
  node.textContent = strings[stringIndex].trim();
306
313
  }
307
314
  }
@@ -310,7 +317,18 @@ class TakeSnapshotHandler {
310
317
  for (let j = 0; j < attrs.length; j += 2) {
311
318
  const name = strings[parseInt(attrs[j])];
312
319
  const value = strings[parseInt(attrs[j + 1])];
313
- if (['id', 'class', 'type', 'name', 'href', 'src', 'alt', 'placeholder', 'value', 'title'].includes(name)) {
320
+ if ([
321
+ "id",
322
+ "class",
323
+ "type",
324
+ "name",
325
+ "href",
326
+ "src",
327
+ "alt",
328
+ "placeholder",
329
+ "value",
330
+ "title",
331
+ ].includes(name)) {
314
332
  node.attributes[name] = value;
315
333
  }
316
334
  }
@@ -318,7 +336,7 @@ class TakeSnapshotHandler {
318
336
  if (nodes.inputValue?.index.includes(i)) {
319
337
  const inputIndex = nodes.inputValue.index.indexOf(i);
320
338
  const stringIndex = nodes.inputValue.value[inputIndex];
321
- if (typeof stringIndex === 'number') {
339
+ if (typeof stringIndex === "number") {
322
340
  node.inputValue = strings[stringIndex];
323
341
  }
324
342
  }
@@ -361,31 +379,31 @@ class TakeSnapshotHandler {
361
379
  }
362
380
  return null;
363
381
  };
364
- return findNode(nodeTree, 'body') || findNode(nodeTree, 'main') || null;
382
+ return findNode(nodeTree, "body") || findNode(nodeTree, "main") || null;
365
383
  }
366
384
  shouldIncludeNode(node) {
367
- const skipTags = ['script', 'style', 'meta', 'link', 'head', 'noscript'];
385
+ const skipTags = ["script", "style", "meta", "link", "head", "noscript"];
368
386
  if (skipTags.includes(node.nodeName)) {
369
387
  return false;
370
388
  }
371
389
  if (node.nodeType === 3) {
372
- const text = (node.textContent || '').trim();
390
+ const text = (node.textContent || "").trim();
373
391
  return text.length > 0;
374
392
  }
375
393
  return true;
376
394
  }
377
395
  renderNodeAsText(node, depth, isLast = false, parentIsLast = [], useColors = true) {
378
396
  if (!this.shouldIncludeNode(node)) {
379
- return '';
397
+ return "";
380
398
  }
381
- let indent = '';
399
+ let indent = "";
382
400
  for (let i = 0; i < parentIsLast.length; i++) {
383
- const symbol = parentIsLast[i] ? ' ' : '';
401
+ const symbol = parentIsLast[i] ? " " : "";
384
402
  indent += this.colorTreeSymbol(symbol, useColors);
385
403
  }
386
- const prefixSymbol = depth > 0 ? (isLast ? '└── ' : '├── ') : '';
404
+ const prefixSymbol = depth > 0 ? (isLast ? "└── " : "├── ") : "";
387
405
  const prefix = this.colorTreeSymbol(prefixSymbol, useColors);
388
- let output = '';
406
+ let output = "";
389
407
  if (node.nodeType === 3) {
390
408
  if (node.textContent) {
391
409
  const truncatedText = this.truncateText(node.textContent.trim(), 40);
@@ -400,28 +418,30 @@ class TakeSnapshotHandler {
400
418
  attrs.push(this.colorId(node.attributes.id, useColors));
401
419
  }
402
420
  if (node.attributes.class) {
403
- const classes = node.attributes.class.split(/\s+/).filter((c) => c.trim().length > 0);
421
+ const classes = node.attributes.class
422
+ .split(/\s+/)
423
+ .filter((c) => c.trim().length > 0);
404
424
  classes.forEach((cls) => {
405
425
  attrs.push(this.colorClass(cls.trim(), useColors));
406
426
  });
407
427
  }
408
428
  if (node.attributes.type) {
409
- attrs.push(this.colorAttribute('type', node.attributes.type, useColors));
429
+ attrs.push(this.colorAttribute("type", node.attributes.type, useColors));
410
430
  }
411
431
  if (node.attributes.name) {
412
- attrs.push(this.colorAttribute('name', node.attributes.name, useColors));
432
+ attrs.push(this.colorAttribute("name", node.attributes.name, useColors));
413
433
  }
414
434
  if (attrs.length > 0) {
415
- description += `(${attrs.join(' ')})`;
435
+ description += `(${attrs.join(" ")})`;
416
436
  }
417
- if (node.nodeName === 'img' && node.attributes.alt) {
437
+ if (node.nodeName === "img" && node.attributes.alt) {
418
438
  const altText = this.truncateText(node.attributes.alt, 40);
419
439
  description += `: ${this.colorText(altText, useColors)}`;
420
440
  }
421
- else if (node.nodeName === 'a' && node.attributes.href) {
441
+ else if (node.nodeName === "a" && node.attributes.href) {
422
442
  description += `: ${this.colorUrl(node.attributes.href, useColors)}`;
423
443
  }
424
- else if (['input', 'textarea'].includes(node.nodeName)) {
444
+ else if (["input", "textarea"].includes(node.nodeName)) {
425
445
  if (node.attributes.placeholder) {
426
446
  const placeholderText = this.truncateText(node.attributes.placeholder, 40);
427
447
  description += `: ${this.colorText(placeholderText, useColors)}`;
@@ -430,7 +450,7 @@ class TakeSnapshotHandler {
430
450
  const inputText = this.truncateText(node.inputValue, 40);
431
451
  description += `: ${this.colorText(inputText, useColors)}`;
432
452
  }
433
- else if (node.nodeName === 'textarea') {
453
+ else if (node.nodeName === "textarea") {
434
454
  const textContent = this.extractTextContent(node);
435
455
  if (textContent) {
436
456
  const truncatedText = this.truncateText(textContent, 40);
@@ -438,10 +458,11 @@ class TakeSnapshotHandler {
438
458
  }
439
459
  }
440
460
  if (node.checked) {
441
- description += ` ${this.colorSpecial('[checked]', useColors)}`;
461
+ description += ` ${this.colorSpecial("[checked]", useColors)}`;
442
462
  }
443
463
  }
444
- else if (node.nodeName === 'button' || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(node.nodeName)) {
464
+ else if (node.nodeName === "button" ||
465
+ ["h1", "h2", "h3", "h4", "h5", "h6"].includes(node.nodeName)) {
445
466
  const textContent = this.extractTextContent(node);
446
467
  if (textContent) {
447
468
  const truncatedText = this.truncateText(textContent, 40);
@@ -449,7 +470,7 @@ class TakeSnapshotHandler {
449
470
  }
450
471
  }
451
472
  output += `${indent}${prefix}${description}\n`;
452
- if (node.nodeName === 'textarea') {
473
+ if (node.nodeName === "textarea") {
453
474
  return output;
454
475
  }
455
476
  const meaningfulChildren = node.children.filter((child) => this.shouldIncludeNode(child));
@@ -457,7 +478,7 @@ class TakeSnapshotHandler {
457
478
  const textContent = this.extractTextContent(node);
458
479
  if (textContent && textContent.trim().length > 0) {
459
480
  const truncatedText = this.truncateText(textContent.trim(), 40);
460
- const treeSymbol = this.colorTreeSymbol('│ └── ', useColors);
481
+ const treeSymbol = this.colorTreeSymbol("│ └── ", useColors);
461
482
  output += `${indent}${treeSymbol}${this.colorText(truncatedText, useColors)}\n`;
462
483
  return output;
463
484
  }
@@ -475,27 +496,27 @@ class TakeSnapshotHandler {
475
496
  return output;
476
497
  }
477
498
  extractTextContent(node) {
478
- let text = '';
499
+ let text = "";
479
500
  if (node.nodeType === 3) {
480
- return node.textContent || '';
501
+ return node.textContent || "";
481
502
  }
482
503
  if (node.textContent) {
483
- text += node.textContent + ' ';
504
+ text += node.textContent + " ";
484
505
  }
485
506
  for (const child of node.children) {
486
- text += this.extractTextContent(child) + ' ';
507
+ text += this.extractTextContent(child) + " ";
487
508
  }
488
- return text.trim().replace(/\s+/g, ' ');
509
+ return text.trim().replace(/\s+/g, " ");
489
510
  }
490
511
  truncateText(text, maxLength) {
491
512
  if (!text)
492
- return '';
513
+ return "";
493
514
  if (text.length <= maxLength)
494
515
  return text;
495
- return text.substring(0, maxLength) + '...';
516
+ return text.substring(0, maxLength) + "...";
496
517
  }
497
518
  buildTextFromDOMNode(root, _url, title, useColors = true) {
498
- let output = this.colorPageTitle(title || 'Untitled', useColors) + '\n';
519
+ let output = this.colorPageTitle(title || "Untitled", useColors) + "\n";
499
520
  const bodyNode = this.findBodyInDOMTree(root);
500
521
  if (bodyNode) {
501
522
  output += this.renderDOMNodeAsText(bodyNode, 0, false, [], useColors);
@@ -512,10 +533,10 @@ class TakeSnapshotHandler {
512
533
  return output;
513
534
  }
514
535
  findBodyInDOMTree(node) {
515
- if (node.nodeName && node.nodeName.toLowerCase() === 'body') {
536
+ if (node.nodeName && node.nodeName.toLowerCase() === "body") {
516
537
  return node;
517
538
  }
518
- if (node.nodeName && node.nodeName.toLowerCase() === 'main') {
539
+ if (node.nodeName && node.nodeName.toLowerCase() === "main") {
519
540
  return node;
520
541
  }
521
542
  if (node.children) {
@@ -530,38 +551,38 @@ class TakeSnapshotHandler {
530
551
  shouldIncludeDOMNode(node) {
531
552
  if (!node)
532
553
  return false;
533
- const nodeName = node.nodeName ? node.nodeName.toLowerCase() : '';
534
- const skipTags = ['script', 'style', 'meta', 'link', 'head', 'noscript'];
554
+ const nodeName = node.nodeName ? node.nodeName.toLowerCase() : "";
555
+ const skipTags = ["script", "style", "meta", "link", "head", "noscript"];
535
556
  if (skipTags.includes(nodeName)) {
536
557
  return false;
537
558
  }
538
559
  if (node.nodeType === 3) {
539
- const text = node.nodeValue || '';
560
+ const text = node.nodeValue || "";
540
561
  return text.trim().length > 0;
541
562
  }
542
563
  return true;
543
564
  }
544
565
  renderDOMNodeAsText(node, depth, isLast = false, parentIsLast = [], useColors = true) {
545
566
  if (!this.shouldIncludeDOMNode(node)) {
546
- return '';
567
+ return "";
547
568
  }
548
- let indent = '';
569
+ let indent = "";
549
570
  for (let i = 0; i < parentIsLast.length; i++) {
550
- const symbol = parentIsLast[i] ? ' ' : '';
571
+ const symbol = parentIsLast[i] ? " " : "";
551
572
  indent += this.colorTreeSymbol(symbol, useColors);
552
573
  }
553
- const prefixSymbol = depth > 0 ? (isLast ? '└── ' : '├── ') : '';
574
+ const prefixSymbol = depth > 0 ? (isLast ? "└── " : "├── ") : "";
554
575
  const prefix = this.colorTreeSymbol(prefixSymbol, useColors);
555
- let output = '';
576
+ let output = "";
556
577
  if (node.nodeType === 3) {
557
- const text = (node.nodeValue || '').trim();
578
+ const text = (node.nodeValue || "").trim();
558
579
  if (text) {
559
580
  const truncatedText = this.truncateText(text, 40);
560
581
  output += `${indent}${prefix}${this.colorText(truncatedText, useColors)}\n`;
561
582
  }
562
583
  }
563
584
  else if (node.nodeType === 1) {
564
- const nodeName = (node.nodeName || '').toLowerCase();
585
+ const nodeName = (node.nodeName || "").toLowerCase();
565
586
  const tag = this.colorTag(nodeName, useColors);
566
587
  let description = tag;
567
588
  const attrs = [];
@@ -569,18 +590,31 @@ class TakeSnapshotHandler {
569
590
  for (let i = 0; i < node.attributes.length; i += 2) {
570
591
  const name = node.attributes[i];
571
592
  const value = node.attributes[i + 1];
572
- if (['id', 'class', 'type', 'name', 'href', 'src', 'alt', 'placeholder', 'value', 'title'].includes(name)) {
573
- if (name === 'id') {
593
+ if ([
594
+ "id",
595
+ "class",
596
+ "type",
597
+ "name",
598
+ "href",
599
+ "src",
600
+ "alt",
601
+ "placeholder",
602
+ "value",
603
+ "title",
604
+ ].includes(name)) {
605
+ if (name === "id") {
574
606
  attrs.push(this.colorId(value, useColors));
575
607
  }
576
- else if (name === 'class') {
577
- const classes = value.split(/\s+/).filter((c) => c.trim().length > 0);
608
+ else if (name === "class") {
609
+ const classes = value
610
+ .split(/\s+/)
611
+ .filter((c) => c.trim().length > 0);
578
612
  classes.forEach((cls) => {
579
613
  attrs.push(this.colorClass(cls.trim(), useColors));
580
614
  });
581
615
  }
582
- else if (name === 'type') {
583
- attrs.push(this.colorAttribute('type', value, useColors));
616
+ else if (name === "type") {
617
+ attrs.push(this.colorAttribute("type", value, useColors));
584
618
  }
585
619
  else {
586
620
  attrs.push(this.colorAttribute(name, value, useColors));
@@ -589,30 +623,31 @@ class TakeSnapshotHandler {
589
623
  }
590
624
  }
591
625
  if (attrs.length > 0) {
592
- description += `(${attrs.join(' ')})`;
626
+ description += `(${attrs.join(" ")})`;
593
627
  }
594
- if (nodeName === 'img' && node.attributes) {
595
- const altIndex = node.attributes.indexOf('alt');
628
+ if (nodeName === "img" && node.attributes) {
629
+ const altIndex = node.attributes.indexOf("alt");
596
630
  if (altIndex >= 0 && altIndex + 1 < node.attributes.length) {
597
631
  const altText = this.truncateText(node.attributes[altIndex + 1], 40);
598
632
  description += `: ${this.colorText(altText, useColors)}`;
599
633
  }
600
634
  }
601
- else if (nodeName === 'a' && node.attributes) {
602
- const hrefIndex = node.attributes.indexOf('href');
635
+ else if (nodeName === "a" && node.attributes) {
636
+ const hrefIndex = node.attributes.indexOf("href");
603
637
  if (hrefIndex >= 0 && hrefIndex + 1 < node.attributes.length) {
604
638
  description += `: ${this.colorUrl(node.attributes[hrefIndex + 1], useColors)}`;
605
639
  }
606
640
  }
607
- else if (['input', 'textarea'].includes(nodeName)) {
641
+ else if (["input", "textarea"].includes(nodeName)) {
608
642
  if (node.attributes) {
609
- const placeholderIndex = node.attributes.indexOf('placeholder');
610
- if (placeholderIndex >= 0 && placeholderIndex + 1 < node.attributes.length) {
643
+ const placeholderIndex = node.attributes.indexOf("placeholder");
644
+ if (placeholderIndex >= 0 &&
645
+ placeholderIndex + 1 < node.attributes.length) {
611
646
  const placeholderText = this.truncateText(node.attributes[placeholderIndex + 1], 40);
612
647
  description += `: ${this.colorText(placeholderText, useColors)}`;
613
648
  }
614
649
  }
615
- if (nodeName === 'textarea') {
650
+ if (nodeName === "textarea") {
616
651
  const textContent = this.extractTextFromDOMNode(node);
617
652
  if (textContent) {
618
653
  const truncatedText = this.truncateText(textContent, 40);
@@ -620,7 +655,8 @@ class TakeSnapshotHandler {
620
655
  }
621
656
  }
622
657
  }
623
- else if (nodeName === 'button' || ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'].includes(nodeName)) {
658
+ else if (nodeName === "button" ||
659
+ ["h1", "h2", "h3", "h4", "h5", "h6"].includes(nodeName)) {
624
660
  const textContent = this.extractTextFromDOMNode(node);
625
661
  if (textContent) {
626
662
  const truncatedText = this.truncateText(textContent, 40);
@@ -628,7 +664,7 @@ class TakeSnapshotHandler {
628
664
  }
629
665
  }
630
666
  output += `${indent}${prefix}${description}\n`;
631
- if (nodeName === 'textarea') {
667
+ if (nodeName === "textarea") {
632
668
  return output;
633
669
  }
634
670
  if (node.children) {
@@ -637,7 +673,7 @@ class TakeSnapshotHandler {
637
673
  const textContent = this.extractTextFromDOMNode(node);
638
674
  if (textContent && textContent.trim().length > 0) {
639
675
  const truncatedText = this.truncateText(textContent.trim(), 40);
640
- const treeSymbol = this.colorTreeSymbol('│ └── ', useColors);
676
+ const treeSymbol = this.colorTreeSymbol("│ └── ", useColors);
641
677
  output += `${indent}${treeSymbol}${this.colorText(truncatedText, useColors)}\n`;
642
678
  return output;
643
679
  }
@@ -657,20 +693,20 @@ class TakeSnapshotHandler {
657
693
  }
658
694
  extractTextFromDOMNode(node) {
659
695
  if (node.nodeType === 3) {
660
- return (node.nodeValue || '').trim();
696
+ return (node.nodeValue || "").trim();
661
697
  }
662
- let text = '';
698
+ let text = "";
663
699
  if (node.children) {
664
700
  for (const child of node.children) {
665
- text += this.extractTextFromDOMNode(child) + ' ';
701
+ text += this.extractTextFromDOMNode(child) + " ";
666
702
  }
667
703
  }
668
- return text.trim().replace(/\s+/g, ' ');
704
+ return text.trim().replace(/\s+/g, " ");
669
705
  }
670
706
  convertToHTML(response) {
671
707
  const doc = response.documents[0];
672
708
  if (!doc)
673
- return '';
709
+ return "";
674
710
  const tree = this.buildDOMTree(doc, response.strings);
675
711
  return this.renderNodeAsHTML(tree[0], 0);
676
712
  }
@@ -689,7 +725,7 @@ class TakeSnapshotHandler {
689
725
  nodeName: nodes.nodeName[i],
690
726
  nodeValue: nodes.nodeValue?.[i],
691
727
  backendNodeId: nodes.backendNodeId?.[i],
692
- children: []
728
+ children: [],
693
729
  };
694
730
  if (nodes.attributes?.[i]) {
695
731
  const attrs = nodes.attributes[i];
@@ -703,14 +739,14 @@ class TakeSnapshotHandler {
703
739
  if (nodes.textValue?.index.includes(i)) {
704
740
  const textIndex = nodes.textValue.index.indexOf(i);
705
741
  const stringIndex = nodes.textValue.value[textIndex];
706
- if (typeof stringIndex === 'number') {
742
+ if (typeof stringIndex === "number") {
707
743
  node.textValue = strings[stringIndex];
708
744
  }
709
745
  }
710
746
  if (nodes.inputValue?.index.includes(i)) {
711
747
  const inputIndex = nodes.inputValue.index.indexOf(i);
712
748
  const stringIndex = nodes.inputValue.value[inputIndex];
713
- if (typeof stringIndex === 'number') {
749
+ if (typeof stringIndex === "number") {
714
750
  node.inputValue = strings[stringIndex];
715
751
  }
716
752
  }
@@ -742,14 +778,14 @@ class TakeSnapshotHandler {
742
778
  }
743
779
  renderNodeAsHTML(node, depth) {
744
780
  if (!node)
745
- return '';
746
- const indent = ' '.repeat(depth);
781
+ return "";
782
+ const indent = " ".repeat(depth);
747
783
  if (node.nodeType === 3) {
748
- const text = node.nodeValue || node.textValue || '';
749
- return text.trim() ? `${indent}${text.trim()}\n` : '';
784
+ const text = node.nodeValue || node.textValue || "";
785
+ return text.trim() ? `${indent}${text.trim()}\n` : "";
750
786
  }
751
787
  if (node.nodeType === 8) {
752
- return `${indent}<!-- ${node.nodeValue || ''} -->\n`;
788
+ return `${indent}<!-- ${node.nodeValue || ""} -->\n`;
753
789
  }
754
790
  if (node.nodeType === 1) {
755
791
  const tagName = node.nodeName.toLowerCase();
@@ -759,14 +795,29 @@ class TakeSnapshotHandler {
759
795
  html += ` ${name}="${value}"`;
760
796
  }
761
797
  }
762
- const selfClosing = ['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr'];
798
+ const selfClosing = [
799
+ "area",
800
+ "base",
801
+ "br",
802
+ "col",
803
+ "embed",
804
+ "hr",
805
+ "img",
806
+ "input",
807
+ "link",
808
+ "meta",
809
+ "param",
810
+ "source",
811
+ "track",
812
+ "wbr",
813
+ ];
763
814
  if (selfClosing.includes(tagName)) {
764
- html += ' />\n';
815
+ html += " />\n";
765
816
  return html;
766
817
  }
767
- html += '>';
818
+ html += ">";
768
819
  if (node.children && node.children.length > 0) {
769
- html += '\n';
820
+ html += "\n";
770
821
  for (const child of node.children) {
771
822
  html += this.renderNodeAsHTML(child, depth + 1);
772
823
  }
@@ -777,27 +828,28 @@ class TakeSnapshotHandler {
777
828
  }
778
829
  return html;
779
830
  }
780
- return '';
831
+ return "";
781
832
  }
782
833
  async saveSnapshot(snapshotData, filename, format) {
783
834
  try {
784
835
  const dir = (0, path_1.dirname)(filename);
785
836
  await fs_1.promises.mkdir(dir, { recursive: true });
786
837
  let content;
787
- if (format === 'html') {
838
+ if (format === "html") {
788
839
  content = snapshotData;
789
840
  }
790
- else if (format === 'text' || !format) {
791
- if (typeof snapshotData === 'object' && snapshotData !== null) {
841
+ else if (format === "text" || !format) {
842
+ if (typeof snapshotData === "object" && snapshotData !== null) {
792
843
  const snapshotObj = snapshotData;
793
- if (snapshotObj.snapshot && typeof snapshotObj.snapshot === 'string') {
844
+ if (snapshotObj.snapshot &&
845
+ typeof snapshotObj.snapshot === "string") {
794
846
  content = snapshotObj.snapshot;
795
847
  }
796
848
  else {
797
849
  content = JSON.stringify(snapshotData, null, 2);
798
850
  }
799
851
  }
800
- else if (typeof snapshotData === 'string') {
852
+ else if (typeof snapshotData === "string") {
801
853
  content = snapshotData;
802
854
  }
803
855
  else {
@@ -807,33 +859,39 @@ class TakeSnapshotHandler {
807
859
  else {
808
860
  content = JSON.stringify(snapshotData, null, 2);
809
861
  }
810
- await fs_1.promises.writeFile(filename, content, 'utf-8');
862
+ await fs_1.promises.writeFile(filename, content, "utf-8");
811
863
  }
812
864
  catch (error) {
813
865
  throw new Error(`Failed to save DOM snapshot to "${filename}": ${error instanceof Error ? error.message : String(error)}`);
814
866
  }
815
867
  }
816
868
  validateArgs(args) {
817
- if (typeof args !== 'object' || args === null) {
869
+ if (typeof args !== "object" || args === null) {
818
870
  return false;
819
871
  }
820
872
  const snapshotArgs = args;
821
- if (snapshotArgs.filename !== undefined && typeof snapshotArgs.filename !== 'string') {
873
+ if (snapshotArgs.filename !== undefined &&
874
+ typeof snapshotArgs.filename !== "string") {
822
875
  return false;
823
876
  }
824
- if (snapshotArgs.format !== undefined && !['json', 'html', 'text'].includes(snapshotArgs.format)) {
877
+ if (snapshotArgs.format !== undefined &&
878
+ !["json", "html", "text"].includes(snapshotArgs.format)) {
825
879
  return false;
826
880
  }
827
- if (snapshotArgs.includeStyles !== undefined && typeof snapshotArgs.includeStyles !== 'boolean') {
881
+ if (snapshotArgs.includeStyles !== undefined &&
882
+ typeof snapshotArgs.includeStyles !== "boolean") {
828
883
  return false;
829
884
  }
830
- if (snapshotArgs.includeAttributes !== undefined && typeof snapshotArgs.includeAttributes !== 'boolean') {
885
+ if (snapshotArgs.includeAttributes !== undefined &&
886
+ typeof snapshotArgs.includeAttributes !== "boolean") {
831
887
  return false;
832
888
  }
833
- if (snapshotArgs.includePaintOrder !== undefined && typeof snapshotArgs.includePaintOrder !== 'boolean') {
889
+ if (snapshotArgs.includePaintOrder !== undefined &&
890
+ typeof snapshotArgs.includePaintOrder !== "boolean") {
834
891
  return false;
835
892
  }
836
- if (snapshotArgs.includeTextIndex !== undefined && typeof snapshotArgs.includeTextIndex !== 'boolean') {
893
+ if (snapshotArgs.includeTextIndex !== undefined &&
894
+ typeof snapshotArgs.includeTextIndex !== "boolean") {
837
895
  return false;
838
896
  }
839
897
  return true;