Skip to content

Commit b5706aa

Browse files
bartvenemanclaude
andauthored
Add child_count getter to CSSNode for efficient child counting (#197)
## Summary Added a new `child_count` getter to the `CSSNode` class that efficiently counts children without allocating an intermediate array, along with comprehensive test coverage. ## Key Changes - **New `child_count` getter**: Implements an efficient child counting mechanism by iterating through siblings using the arena's internal methods rather than materializing the full children array - **Test coverage**: Added three test cases covering: - Counting children in a block declaration (3 properties) - Returning 0 for nodes with no children - Verifying consistency with the existing `children.length` property ## Implementation Details The `child_count` getter uses a simple loop that traverses the sibling chain starting from the first child, incrementing a counter until reaching the end (index 0). This approach avoids the memory overhead of creating an intermediate array when only the count is needed, making it more efficient for performance-sensitive code paths. https://claude.ai/code/session_01JZ7KyHoubj42U8DN2GRv7n Co-authored-by: Claude <noreply@anthropic.com>
1 parent f01c6fa commit b5706aa

File tree

2 files changed

+31
-0
lines changed

2 files changed

+31
-0
lines changed

src/api.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,26 @@ describe('CSSNode', () => {
7474
})
7575
})
7676

77+
describe('child_count', () => {
78+
test('should return the number of children', () => {
79+
const source = 'body { color: red; margin: 0; padding: 10px; }'
80+
const root = parse(source, { parse_selectors: false, parse_values: false })
81+
const block = root.first_child!.block!
82+
expect(block.child_count).toBe(3)
83+
})
84+
85+
test('should return 0 for a node with no children', () => {
86+
const root = parse('', { parse_selectors: false, parse_values: false })
87+
expect(root.child_count).toBe(0)
88+
})
89+
90+
test('should match children.length', () => {
91+
const source = 'body { color: red; } div { margin: 0; }'
92+
const root = parse(source, { parse_selectors: false, parse_values: false })
93+
expect(root.child_count).toBe(root.children.length)
94+
})
95+
})
96+
7797
describe('has_prelude', () => {
7898
test('should return true for @media with prelude', () => {
7999
const source = '@media (min-width: 768px) { body { color: red; } }'

src/css-node.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -584,6 +584,17 @@ export class CSSNode {
584584
return this.arena.has_children(this.index)
585585
}
586586

587+
/** Count children without allocating an intermediate array */
588+
get child_count(): number {
589+
let count = 0
590+
let child_index = this.arena.get_first_child(this.index)
591+
while (child_index !== 0) {
592+
count++
593+
child_index = this.arena.get_next_sibling(child_index)
594+
}
595+
return count
596+
}
597+
587598
/** Get all children as an array */
588599
get children(): CSSNode[] {
589600
let result: CSSNode[] = []

0 commit comments

Comments
 (0)