@@ -22,32 +22,13 @@ const Allocator = std.mem.Allocator;
22
22
23
23
pub const Id = u32 ;
24
24
25
+ const log = std .log .scoped (.cdp_node );
26
+
25
27
const Node = @This ();
26
28
27
29
id : Id ,
28
- parent_id : ? Id = null ,
29
- node_type : u32 ,
30
- backend_node_id : Id ,
31
- node_name : []const u8 ,
32
- local_name : []const u8 ,
33
- node_value : []const u8 ,
34
- child_node_count : u32 ,
35
- children : []const * Node ,
36
- document_url : ? []const u8 ,
37
- base_url : ? []const u8 ,
38
- xml_version : []const u8 ,
39
- compatibility_mode : CompatibilityMode ,
40
- is_scrollable : bool ,
41
30
_node : * parser.Node ,
42
31
43
- const CompatibilityMode = enum {
44
- NoQuirksMode ,
45
- };
46
-
47
- pub fn writer (self : * const Node , opts : Writer.Opts ) Writer {
48
- return .{ .node = self , .opts = opts };
49
- }
50
-
51
32
// Whenever we send a node to the client, we register it here for future lookup.
52
33
// We maintain a node -> id and id -> node lookup.
53
34
pub const Registry = struct {
@@ -94,66 +75,21 @@ pub const Registry = struct {
94
75
// but, just in case, let's try to keep things tidy.
95
76
errdefer _ = self .lookup_by_node .remove (n );
96
77
97
- const id = self .node_id ;
98
- self .node_id = id + 1 ;
99
-
100
- const child_nodes = try self .registerChildNodes (n );
101
-
102
78
const node = try self .node_pool .create ();
103
79
errdefer self .node_pool .destroy (node );
104
80
81
+ const id = self .node_id ;
82
+ self .node_id = id + 1 ;
83
+
105
84
node .* = .{
106
85
._node = n ,
107
86
.id = id ,
108
- .parent_id = null , // TODO
109
- .backend_node_id = id , // ??
110
- .node_name = parser .nodeName (n ) catch return error .NodeNameError ,
111
- .local_name = parser .nodeLocalName (n ) catch return error .NodeLocalNameError ,
112
- .node_value = (parser .nodeValue (n ) catch return error .NameValueError ) orelse "" ,
113
- .node_type = @intFromEnum (parser .nodeType (n ) catch return error .NodeTypeError ),
114
- .child_node_count = @intCast (child_nodes .len ),
115
- .children = child_nodes ,
116
- .document_url = null ,
117
- .base_url = null ,
118
- .xml_version = "" ,
119
- .compatibility_mode = .NoQuirksMode ,
120
- .is_scrollable = false ,
121
87
};
122
88
123
- // if (try parser.nodeParentNode(n)) |pn| {
124
- // _ = pn;
125
- // // TODO
126
- // }
127
-
128
89
node_lookup_gop .value_ptr .* = node ;
129
90
try self .lookup_by_id .putNoClobber (self .allocator , id , node );
130
91
return node ;
131
92
}
132
-
133
- pub fn registerChildNodes (self : * Registry , n : * parser.Node ) RegisterError ! []* Node {
134
- const node_list = parser .nodeGetChildNodes (n ) catch return error .GetChildNodeError ;
135
- const count = parser .nodeListLength (node_list ) catch return error .NodeListLengthError ;
136
-
137
- var arr = try self .arena .allocator ().alloc (* Node , count );
138
- var i : usize = 0 ;
139
- for (0.. count ) | _ | {
140
- const child = (parser .nodeListItem (node_list , @intCast (i )) catch return error .NodeListItemError ) orelse continue ;
141
- arr [i ] = try self .register (child );
142
- i += 1 ;
143
- }
144
- return arr [0.. i ];
145
- }
146
- };
147
-
148
- const RegisterError = error {
149
- OutOfMemory ,
150
- GetChildNodeError ,
151
- NodeListLengthError ,
152
- NodeListItemError ,
153
- NodeNameError ,
154
- NodeLocalNameError ,
155
- NameValueError ,
156
- NodeTypeError ,
157
93
};
158
94
159
95
const NodeContext = struct {
@@ -261,67 +197,98 @@ pub const Search = struct {
261
197
// Sometimes we want to serializ the node without chidren, sometimes with just
262
198
// its direct children, and sometimes the entire tree.
263
199
// (For now, we only support direct children)
200
+
264
201
pub const Writer = struct {
265
202
opts : Opts ,
266
203
node : * const Node ,
204
+ registry : * Registry ,
267
205
268
206
pub const Opts = struct {};
269
207
270
208
pub fn jsonStringify (self : * const Writer , w : anytype ) ! void {
209
+ self .toJSON (w ) catch | err | {
210
+ // The only error our jsonStringify method can return is
211
+ // @TypeOf(w).Error. In other words, our code can't return its own
212
+ // error, we can only return a writer error. Kinda sucks.
213
+ log .err ("json stringify: {}" , .{err });
214
+ return error .OutOfMemory ;
215
+ };
216
+ }
217
+
218
+ fn toJSON (self : * const Writer , w : anytype ) ! void {
271
219
try w .beginObject ();
272
- try writeCommon (self .node , w );
273
- try w .objectField ("children" );
274
- try w .beginArray ();
275
- for (self .node .children ) | node | {
276
- try w .beginObject ();
277
- try writeCommon (node , w );
278
- try w .endObject ();
220
+ try writeCommon (self .node , false , w );
221
+
222
+ {
223
+ var registry = self .registry ;
224
+ const child_nodes = try parser .nodeGetChildNodes (self .node ._node );
225
+ const child_count = try parser .nodeListLength (child_nodes );
226
+
227
+ var i : usize = 0 ;
228
+ try w .objectField ("children" );
229
+ try w .beginArray ();
230
+ for (0.. child_count ) | _ | {
231
+ const child = (try parser .nodeListItem (child_nodes , @intCast (i ))) orelse continue ;
232
+ const child_node = try registry .register (child );
233
+ try w .beginObject ();
234
+ try writeCommon (child_node , true , w );
235
+ try w .endObject ();
236
+ i += 1 ;
237
+ }
238
+ try w .endArray ();
239
+
240
+ try w .objectField ("childNodeCount" );
241
+ try w .write (i );
279
242
}
280
- try w . endArray ();
243
+
281
244
try w .endObject ();
282
245
}
283
246
284
- fn writeCommon (node : * const Node , w : anytype ) ! void {
247
+ fn writeCommon (node : * const Node , include_child_count : bool , w : anytype ) ! void {
285
248
try w .objectField ("nodeId" );
286
249
try w .write (node .id );
287
250
288
- if (node .parent_id ) | pid | {
289
- try w .objectField ("parentId" );
290
- try w .write (pid );
291
- }
292
-
293
251
try w .objectField ("backendNodeId" );
294
- try w .write (node .backend_node_id );
252
+ try w .write (node .id );
253
+
254
+ const n = node ._node ;
255
+
256
+ // TODO:
257
+ // try w.objectField("parentId");
258
+ // try w.write(pid);
295
259
296
260
try w .objectField ("nodeType" );
297
- try w .write (node . node_type );
261
+ try w .write (@intFromEnum ( try parser . nodeType ( n )) );
298
262
299
263
try w .objectField ("nodeName" );
300
- try w .write (node . node_name );
264
+ try w .write (try parser . nodeName ( n ) );
301
265
302
266
try w .objectField ("localName" );
303
- try w .write (node . local_name );
267
+ try w .write (try parser . nodeLocalName ( n ) );
304
268
305
269
try w .objectField ("nodeValue" );
306
- try w .write (node . node_value );
270
+ try w .write (( try parser . nodeValue ( n )) orelse "" );
307
271
308
- try w .objectField ("childNodeCount" );
309
- try w .write (node .child_node_count );
272
+ if (include_child_count ) {
273
+ try w .objectField ("childNodeCount" );
274
+ const child_nodes = try parser .nodeGetChildNodes (n );
275
+ try w .write (try parser .nodeListLength (child_nodes ));
276
+ }
310
277
311
278
try w .objectField ("documentURL" );
312
- try w .write (node . document_url );
279
+ try w .write (null );
313
280
314
281
try w .objectField ("baseURL" );
315
- try w .write (node . base_url );
282
+ try w .write (null );
316
283
317
284
try w .objectField ("xmlVersion" );
318
- try w .write (node . xml_version );
285
+ try w .write ("" );
319
286
320
287
try w .objectField ("compatibilityMode" );
321
- try w .write (node . compatibility_mode );
288
+ try w .write ("NoQuirksMode" );
322
289
323
290
try w .objectField ("isScrollable" );
324
- try w .write (node . is_scrollable );
291
+ try w .write (false );
325
292
}
326
293
};
327
294
@@ -345,46 +312,18 @@ test "cdp Node: Registry register" {
345
312
try testing .expectEqual (node , n1c );
346
313
347
314
try testing .expectEqual (0 , node .id );
348
- try testing .expectEqual (null , node .parent_id );
349
- try testing .expectEqual (1 , node .node_type );
350
- try testing .expectEqual (0 , node .backend_node_id );
351
- try testing .expectEqual ("A" , node .node_name );
352
- try testing .expectEqual ("a" , node .local_name );
353
- try testing .expectEqual ("" , node .node_value );
354
- try testing .expectEqual (1 , node .child_node_count );
355
- try testing .expectEqual (1 , node .children .len );
356
- try testing .expectEqual (1 , node .children [0 ].id );
357
- try testing .expectEqual (null , node .document_url );
358
- try testing .expectEqual (null , node .base_url );
359
- try testing .expectEqual ("" , node .xml_version );
360
- try testing .expectEqual (.NoQuirksMode , node .compatibility_mode );
361
- try testing .expectEqual (false , node .is_scrollable );
362
315
try testing .expectEqual (n , node ._node );
363
316
}
364
317
365
318
{
366
319
const n = (try doc .querySelector ("p" )).? ;
367
320
const node = try registry .register (n );
368
- const n1b = registry .lookup_by_id .get (2 ).? ;
321
+ const n1b = registry .lookup_by_id .get (1 ).? ;
369
322
const n1c = registry .lookup_by_node .get (node ._node ).? ;
370
323
try testing .expectEqual (node , n1b );
371
324
try testing .expectEqual (node , n1c );
372
325
373
- try testing .expectEqual (2 , node .id );
374
- try testing .expectEqual (null , node .parent_id );
375
- try testing .expectEqual (1 , node .node_type );
376
- try testing .expectEqual (2 , node .backend_node_id );
377
- try testing .expectEqual ("P" , node .node_name );
378
- try testing .expectEqual ("p" , node .local_name );
379
- try testing .expectEqual ("" , node .node_value );
380
- try testing .expectEqual (1 , node .child_node_count );
381
- try testing .expectEqual (1 , node .children .len );
382
- try testing .expectEqual (3 , node .children [0 ].id );
383
- try testing .expectEqual (null , node .document_url );
384
- try testing .expectEqual (null , node .base_url );
385
- try testing .expectEqual ("" , node .xml_version );
386
- try testing .expectEqual (.NoQuirksMode , node .compatibility_mode );
387
- try testing .expectEqual (false , node .is_scrollable );
326
+ try testing .expectEqual (1 , node .id );
388
327
try testing .expectEqual (n , node ._node );
389
328
}
390
329
}
@@ -449,17 +388,92 @@ test "cdp Node: Writer" {
449
388
450
389
{
451
390
const node = try registry .register (doc .asNode ());
452
- const json = try std .json .stringifyAlloc (testing .allocator , node .writer (.{}), .{});
391
+ const json = try std .json .stringifyAlloc (testing .allocator , Writer {
392
+ .node = node ,
393
+ .opts = .{},
394
+ .registry = & registry ,
395
+ }, .{});
453
396
defer testing .allocator .free (json );
454
397
455
- try testing .expectJson (.{ .nodeId = 0 , .backendNodeId = 0 , .nodeType = 9 , .nodeName = "#document" , .localName = "" , .nodeValue = "" , .documentURL = null , .baseURL = null , .xmlVersion = "" , .isScrollable = false , .compatibilityMode = "NoQuirksMode" , .childNodeCount = 1 , .children = &.{.{ .nodeId = 1 , .backendNodeId = 1 , .nodeType = 1 , .nodeName = "HTML" , .localName = "html" , .nodeValue = "" , .childNodeCount = 2 , .documentURL = null , .baseURL = null , .xmlVersion = "" , .compatibilityMode = "NoQuirksMode" , .isScrollable = false }} }, json );
398
+ try testing .expectJson (.{
399
+ .nodeId = 0 ,
400
+ .backendNodeId = 0 ,
401
+ .nodeType = 9 ,
402
+ .nodeName = "#document" ,
403
+ .localName = "" ,
404
+ .nodeValue = "" ,
405
+ .documentURL = null ,
406
+ .baseURL = null ,
407
+ .xmlVersion = "" ,
408
+ .isScrollable = false ,
409
+ .compatibilityMode = "NoQuirksMode" ,
410
+ .childNodeCount = 1 ,
411
+ .children = &.{.{
412
+ .nodeId = 1 ,
413
+ .backendNodeId = 1 ,
414
+ .nodeType = 1 ,
415
+ .nodeName = "HTML" ,
416
+ .localName = "html" ,
417
+ .nodeValue = "" ,
418
+ .childNodeCount = 2 ,
419
+ .documentURL = null ,
420
+ .baseURL = null ,
421
+ .xmlVersion = "" ,
422
+ .compatibilityMode = "NoQuirksMode" ,
423
+ .isScrollable = false ,
424
+ }},
425
+ }, json );
456
426
}
457
427
458
428
{
459
429
const node = registry .lookup_by_id .get (1 ).? ;
460
- const json = try std .json .stringifyAlloc (testing .allocator , node .writer (.{}), .{});
430
+ const json = try std .json .stringifyAlloc (testing .allocator , Writer {
431
+ .node = node ,
432
+ .opts = .{},
433
+ .registry = & registry ,
434
+ }, .{});
461
435
defer testing .allocator .free (json );
462
436
463
- try testing .expectJson (.{ .nodeId = 1 , .backendNodeId = 1 , .nodeType = 1 , .nodeName = "HTML" , .localName = "html" , .nodeValue = "" , .childNodeCount = 2 , .documentURL = null , .baseURL = null , .xmlVersion = "" , .compatibilityMode = "NoQuirksMode" , .isScrollable = false , .children = &.{ .{ .nodeId = 2 , .backendNodeId = 2 , .nodeType = 1 , .nodeName = "HEAD" , .localName = "head" , .nodeValue = "" , .childNodeCount = 0 , .documentURL = null , .baseURL = null , .xmlVersion = "" , .compatibilityMode = "NoQuirksMode" , .isScrollable = false }, .{ .nodeId = 3 , .backendNodeId = 3 , .nodeType = 1 , .nodeName = "BODY" , .localName = "body" , .nodeValue = "" , .childNodeCount = 2 , .documentURL = null , .baseURL = null , .xmlVersion = "" , .compatibilityMode = "NoQuirksMode" , .isScrollable = false } } }, json );
437
+ try testing .expectJson (.{
438
+ .nodeId = 1 ,
439
+ .backendNodeId = 1 ,
440
+ .nodeType = 1 ,
441
+ .nodeName = "HTML" ,
442
+ .localName = "html" ,
443
+ .nodeValue = "" ,
444
+ .childNodeCount = 2 ,
445
+ .documentURL = null ,
446
+ .baseURL = null ,
447
+ .xmlVersion = "" ,
448
+ .compatibilityMode = "NoQuirksMode" ,
449
+ .isScrollable = false ,
450
+ .children = &.{ .{
451
+ .nodeId = 2 ,
452
+ .backendNodeId = 2 ,
453
+ .nodeType = 1 ,
454
+ .nodeName = "HEAD" ,
455
+ .localName = "head" ,
456
+ .nodeValue = "" ,
457
+ .childNodeCount = 0 ,
458
+ .documentURL = null ,
459
+ .baseURL = null ,
460
+ .xmlVersion = "" ,
461
+ .compatibilityMode = "NoQuirksMode" ,
462
+ .isScrollable = false ,
463
+ }, .{
464
+ .nodeId = 3 ,
465
+ .backendNodeId = 3 ,
466
+ .nodeType = 1 ,
467
+ .nodeName = "BODY" ,
468
+ .localName = "body" ,
469
+ .nodeValue = "" ,
470
+ .childNodeCount = 2 ,
471
+ .documentURL = null ,
472
+ .baseURL = null ,
473
+ .xmlVersion = "" ,
474
+ .compatibilityMode = "NoQuirksMode" ,
475
+ .isScrollable = false ,
476
+ } },
477
+ }, json );
464
478
}
465
479
}
0 commit comments