@@ -22,32 +22,13 @@ const Allocator = std.mem.Allocator;
2222
2323pub const Id = u32 ;
2424
25+ const log = std .log .scoped (.cdp_node );
26+
2527const Node = @This ();
2628
2729id : 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 ,
4130_node : * parser.Node ,
4231
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-
5132// Whenever we send a node to the client, we register it here for future lookup.
5233// We maintain a node -> id and id -> node lookup.
5334pub const Registry = struct {
@@ -94,66 +75,21 @@ pub const Registry = struct {
9475 // but, just in case, let's try to keep things tidy.
9576 errdefer _ = self .lookup_by_node .remove (n );
9677
97- const id = self .node_id ;
98- self .node_id = id + 1 ;
99-
100- const child_nodes = try self .registerChildNodes (n );
101-
10278 const node = try self .node_pool .create ();
10379 errdefer self .node_pool .destroy (node );
10480
81+ const id = self .node_id ;
82+ self .node_id = id + 1 ;
83+
10584 node .* = .{
10685 ._node = n ,
10786 .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 ,
12187 };
12288
123- // if (try parser.nodeParentNode(n)) |pn| {
124- // _ = pn;
125- // // TODO
126- // }
127-
12889 node_lookup_gop .value_ptr .* = node ;
12990 try self .lookup_by_id .putNoClobber (self .allocator , id , node );
13091 return node ;
13192 }
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 ,
15793};
15894
15995const NodeContext = struct {
@@ -261,67 +197,98 @@ pub const Search = struct {
261197// Sometimes we want to serializ the node without chidren, sometimes with just
262198// its direct children, and sometimes the entire tree.
263199// (For now, we only support direct children)
200+
264201pub const Writer = struct {
265202 opts : Opts ,
266203 node : * const Node ,
204+ registry : * Registry ,
267205
268206 pub const Opts = struct {};
269207
270208 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 {
271219 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 );
279242 }
280- try w . endArray ();
243+
281244 try w .endObject ();
282245 }
283246
284- fn writeCommon (node : * const Node , w : anytype ) ! void {
247+ fn writeCommon (node : * const Node , include_child_count : bool , w : anytype ) ! void {
285248 try w .objectField ("nodeId" );
286249 try w .write (node .id );
287250
288- if (node .parent_id ) | pid | {
289- try w .objectField ("parentId" );
290- try w .write (pid );
291- }
292-
293251 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);
295259
296260 try w .objectField ("nodeType" );
297- try w .write (node . node_type );
261+ try w .write (@intFromEnum ( try parser . nodeType ( n )) );
298262
299263 try w .objectField ("nodeName" );
300- try w .write (node . node_name );
264+ try w .write (try parser . nodeName ( n ) );
301265
302266 try w .objectField ("localName" );
303- try w .write (node . local_name );
267+ try w .write (try parser . nodeLocalName ( n ) );
304268
305269 try w .objectField ("nodeValue" );
306- try w .write (node . node_value );
270+ try w .write (( try parser . nodeValue ( n )) orelse "" );
307271
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+ }
310277
311278 try w .objectField ("documentURL" );
312- try w .write (node . document_url );
279+ try w .write (null );
313280
314281 try w .objectField ("baseURL" );
315- try w .write (node . base_url );
282+ try w .write (null );
316283
317284 try w .objectField ("xmlVersion" );
318- try w .write (node . xml_version );
285+ try w .write ("" );
319286
320287 try w .objectField ("compatibilityMode" );
321- try w .write (node . compatibility_mode );
288+ try w .write ("NoQuirksMode" );
322289
323290 try w .objectField ("isScrollable" );
324- try w .write (node . is_scrollable );
291+ try w .write (false );
325292 }
326293};
327294
@@ -345,46 +312,18 @@ test "cdp Node: Registry register" {
345312 try testing .expectEqual (node , n1c );
346313
347314 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 );
362315 try testing .expectEqual (n , node ._node );
363316 }
364317
365318 {
366319 const n = (try doc .querySelector ("p" )).? ;
367320 const node = try registry .register (n );
368- const n1b = registry .lookup_by_id .get (2 ).? ;
321+ const n1b = registry .lookup_by_id .get (1 ).? ;
369322 const n1c = registry .lookup_by_node .get (node ._node ).? ;
370323 try testing .expectEqual (node , n1b );
371324 try testing .expectEqual (node , n1c );
372325
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 );
388327 try testing .expectEqual (n , node ._node );
389328 }
390329}
@@ -449,17 +388,92 @@ test "cdp Node: Writer" {
449388
450389 {
451390 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+ }, .{});
453396 defer testing .allocator .free (json );
454397
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 );
456426 }
457427
458428 {
459429 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+ }, .{});
461435 defer testing .allocator .free (json );
462436
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 );
464478 }
465479}
0 commit comments