Skip to content

Commit 064616b

Browse files
authored
breaking: remove .name property from Declaration nodes (#138)
closes #135
1 parent 217f887 commit 064616b

File tree

6 files changed

+86
-79
lines changed

6 files changed

+86
-79
lines changed

src/api.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -768,7 +768,7 @@ describe('CSSNode', () => {
768768
expect(clone.type).toBe(DECLARATION)
769769
expect(clone.type_name).toBe('Declaration')
770770
expect(clone.text).toBe('color: red;')
771-
expect(clone.name).toBe('color')
771+
expect(clone.name).toBe(undefined)
772772
expect(clone.property).toBe('color')
773773
expect(clone.value).toBe('red')
774774
expect(clone.children).toEqual([])
@@ -838,7 +838,7 @@ describe('CSSNode', () => {
838838
expect(clone.type).toBe(DECLARATION)
839839
expect(clone.type_name).toBe('Declaration')
840840
expect(clone.property).toBe('color')
841-
expect(clone.name).toBe('color')
841+
expect(clone.name).toBe(undefined)
842842
expect(clone.value).toBe('red')
843843
expect(clone.is_important).toBe(true)
844844
})

src/css-node.ts

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,13 @@ export class CSSNode {
208208
return this.arena
209209
}
210210

211+
private get_content(): string {
212+
let start = this.arena.get_content_start(this.index)
213+
let length = this.arena.get_content_length(this.index)
214+
if (length === 0) return ''
215+
return this.source.substring(start, start + length)
216+
}
217+
211218
/** Get node type as number (for performance) */
212219
get type(): CSSNodeType {
213220
return this.arena.get_type(this.index) as CSSNodeType
@@ -225,20 +232,20 @@ export class CSSNode {
225232
return this.source.substring(start, start + length)
226233
}
227234

228-
/** Get the "content" text (property name for declarations, at-rule name for at-rules, layer name for import layers) */
229-
get name(): string {
230-
let start = this.arena.get_content_start(this.index)
231-
let length = this.arena.get_content_length(this.index)
232-
if (length === 0) return ''
233-
return this.source.substring(start, start + length)
235+
/** Get the "content" text (at-rule name for at-rules, layer name for import layers) */
236+
get name(): string | undefined {
237+
if (this.type === DECLARATION) return
238+
return this.get_content()
234239
}
235240

236241
/**
237242
* Alias for name (for declarations: "color" in "color: blue")
238243
* More semantic than `name` for declaration nodes
239244
*/
240-
get property(): string {
241-
return this.name
245+
get property(): string | undefined {
246+
let { type } = this
247+
if (type !== DECLARATION && type !== MEDIA_FEATURE) return
248+
return this.get_content()
242249
}
243250

244251
/**
@@ -370,17 +377,17 @@ export class CSSNode {
370377
switch (this.type) {
371378
case DECLARATION:
372379
// Check property name (e.g., -webkit-transform)
373-
return is_vendor_prefixed(this.name)
380+
return is_vendor_prefixed(this.get_content())
374381
case PSEUDO_CLASS_SELECTOR:
375382
case PSEUDO_ELEMENT_SELECTOR:
376383
// Check pseudo-class/element name without colons (e.g., -webkit-autofill, -webkit-scrollbar)
377-
return is_vendor_prefixed(this.name)
384+
return is_vendor_prefixed(this.get_content())
378385
case AT_RULE:
379386
// Check at-rule name (e.g., -webkit-keyframes from @-webkit-keyframes)
380-
return is_vendor_prefixed(this.name)
387+
return is_vendor_prefixed(this.get_content())
381388
case FUNCTION:
382389
// Check function name (e.g., -webkit-gradient from -webkit-gradient())
383-
return is_vendor_prefixed(this.name)
390+
return is_vendor_prefixed(this.get_content())
384391
case IDENTIFIER:
385392
// Check identifier value (e.g., -webkit-sticky)
386393
return is_vendor_prefixed(this.text)
@@ -654,7 +661,7 @@ export class CSSNode {
654661

655662
// 2. Extract type-specific properties (only if meaningful)
656663
if (this.name) plain.name = this.name
657-
if (this.type === DECLARATION) plain.property = this.name
664+
if (this.property) plain.property = this.property
658665

659666
// 3. Handle value types
660667
if (this.value !== undefined && this.value !== null) {

src/parse-declaration.test.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -62,48 +62,48 @@ describe('parse_declaration', () => {
6262
test('simple declaration', () => {
6363
const node = parse_declaration('color: red')
6464
expect(node.type).toBe(DECLARATION)
65-
expect(node.name).toBe('color')
65+
expect(node.property).toBe('color')
6666
expect(node.first_child!.text).toBe('red')
6767
expect(node.is_important).toBe(false)
6868
})
6969

7070
test('declaration with semicolon', () => {
7171
const node = parse_declaration('color: red;')
7272
expect(node.type).toBe(DECLARATION)
73-
expect(node.name).toBe('color')
73+
expect(node.property).toBe('color')
7474
expect(node.first_child!.text).toBe('red')
7575
})
7676

7777
test('declaration without semicolon', () => {
7878
const node = parse_declaration('color: red')
7979
expect(node.type).toBe(DECLARATION)
80-
expect(node.name).toBe('color')
80+
expect(node.property).toBe('color')
8181
expect(node.first_child!.text).toBe('red')
8282
})
8383

8484
test('declaration with whitespace variations', () => {
8585
const node = parse_declaration('color : red')
86-
expect(node.name).toBe('color')
86+
expect(node.property).toBe('color')
8787
expect(node.first_child!.text).toBe('red')
8888
})
8989

9090
test('declaration with leading and trailing whitespace', () => {
9191
const node = parse_declaration(' color: red ')
92-
expect(node.name).toBe('color')
92+
expect(node.property).toBe('color')
9393
expect(node.first_child!.text).toBe('red')
9494
})
9595

9696
test('empty value', () => {
9797
const node = parse_declaration('color:')
98-
expect(node.name).toBe('color')
98+
expect(node.property).toBe('color')
9999
// Empty values return null (consistent with main parser)
100100
expect(node.first_child!.text).toBe('')
101101
expect(node.first_child!.children).toHaveLength(0)
102102
})
103103

104104
test('empty value with semicolon', () => {
105105
const node = parse_declaration('color:;')
106-
expect(node.name).toBe('color')
106+
expect(node.property).toBe('color')
107107
// Empty values return null (consistent with main parser)
108108
expect(node.first_child!.text).toBe('')
109109
})
@@ -112,28 +112,28 @@ describe('parse_declaration', () => {
112112
describe('!important Flag', () => {
113113
test('declaration with !important', () => {
114114
const node = parse_declaration('color: red !important')
115-
expect(node.name).toBe('color')
115+
expect(node.property).toBe('color')
116116
expect(node.first_child!.text).toBe('red')
117117
expect(node.is_important).toBe(true)
118118
})
119119

120120
test('declaration with !important and semicolon', () => {
121121
const node = parse_declaration('color: red !important;')
122-
expect(node.name).toBe('color')
122+
expect(node.property).toBe('color')
123123
expect(node.first_child!.text).toBe('red')
124124
expect(node.is_important).toBe(true)
125125
})
126126

127127
test('historic !ie variant', () => {
128128
const node = parse_declaration('color: red !ie')
129-
expect(node.name).toBe('color')
129+
expect(node.property).toBe('color')
130130
expect(node.first_child!.text).toBe('red')
131131
expect(node.is_important).toBe(true)
132132
})
133133

134134
test('any identifier after ! is treated as important', () => {
135135
const node = parse_declaration('color: red !foo')
136-
expect(node.name).toBe('color')
136+
expect(node.property).toBe('color')
137137
expect(node.first_child!.text).toBe('red')
138138
expect(node.is_important).toBe(true)
139139
})
@@ -147,37 +147,37 @@ describe('parse_declaration', () => {
147147
describe('Vendor Prefixes', () => {
148148
test('-webkit- vendor prefix', () => {
149149
const node = parse_declaration('-webkit-transform: rotate(45deg)')
150-
expect(node.name).toBe('-webkit-transform')
150+
expect(node.property).toBe('-webkit-transform')
151151
expect(node.is_vendor_prefixed).toBe(true)
152152
})
153153

154154
test('-moz- vendor prefix', () => {
155155
const node = parse_declaration('-moz-appearance: none')
156-
expect(node.name).toBe('-moz-appearance')
156+
expect(node.property).toBe('-moz-appearance')
157157
expect(node.is_vendor_prefixed).toBe(true)
158158
})
159159

160160
test('-ms- vendor prefix', () => {
161161
const node = parse_declaration('-ms-filter: blur(5px)')
162-
expect(node.name).toBe('-ms-filter')
162+
expect(node.property).toBe('-ms-filter')
163163
expect(node.is_vendor_prefixed).toBe(true)
164164
})
165165

166166
test('-o- vendor prefix', () => {
167167
const node = parse_declaration('-o-transition: all 0.3s')
168-
expect(node.name).toBe('-o-transition')
168+
expect(node.property).toBe('-o-transition')
169169
expect(node.is_vendor_prefixed).toBe(true)
170170
})
171171

172172
test('non-prefixed property', () => {
173173
const node = parse_declaration('transform: rotate(45deg)')
174-
expect(node.name).toBe('transform')
174+
expect(node.property).toBe('transform')
175175
expect(node.is_vendor_prefixed).toBe(false)
176176
})
177177

178178
test('custom property is not vendor prefixed', () => {
179179
const node = parse_declaration('--custom-color: blue')
180-
expect(node.name).toBe('--custom-color')
180+
expect(node.property).toBe('--custom-color')
181181
expect(node.is_vendor_prefixed).toBe(false)
182182
})
183183
})
@@ -301,7 +301,7 @@ describe('parse_declaration', () => {
301301

302302
test('property with colon but value with invalid token', () => {
303303
const node = parse_declaration('color: red')
304-
expect(node.name).toBe('color')
304+
expect(node.property).toBe('color')
305305
expect(node.first_child!.text).toBe('red')
306306
})
307307
})
@@ -312,9 +312,9 @@ describe('parse_declaration', () => {
312312
expect(node.type).toBe(DECLARATION)
313313
})
314314

315-
test('node.name returns property name', () => {
315+
test('node.property returns property name', () => {
316316
const node = parse_declaration('background-color: blue')
317-
expect(node.name).toBe('background-color')
317+
expect(node.property).toBe('background-color')
318318
})
319319

320320
test('node.value returns raw value string', () => {

src/parse-selector.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,7 +1023,7 @@ describe('Selector Nodes', () => {
10231023
const attr_selector = root.first_child?.first_child
10241024
expect(attr_selector?.type_name).toBe('AttributeSelector')
10251025
expect(attr_selector?.value).toBe('"value"')
1026-
expect(attr_selector?.property).toBe('data-test')
1026+
expect(attr_selector?.name).toBe('data-test')
10271027
expect(attr_selector?.attr_operator).toBe(ATTR_OPERATOR_EQUAL)
10281028
expect(attr_selector?.attr_flags).toBe(ATTR_FLAG_NONE)
10291029
})
@@ -1035,7 +1035,7 @@ describe('Selector Nodes', () => {
10351035
const attr_selector = root.first_child?.first_child
10361036
expect(attr_selector?.type_name).toBe('AttributeSelector')
10371037
expect(attr_selector?.value).toBe('"value"')
1038-
expect(attr_selector?.property).toBe('data-test')
1038+
expect(attr_selector?.name).toBe('data-test')
10391039
expect(attr_selector?.attr_operator).toBe(ATTR_OPERATOR_EQUAL)
10401040
expect(attr_selector?.attr_flags).toBe(ATTR_FLAG_NONE)
10411041
expect(attr_selector?.text).toBe(input)

0 commit comments

Comments
 (0)