0
# Type Guards
1
2
Runtime type checking functions for identifying and validating AST node types. Essential for safely working with the parsed AST and implementing type-specific logic.
3
4
## Capabilities
5
6
### General Node Validation
7
8
Core functions for validating nodes and their capabilities.
9
10
```javascript { .api }
11
/**
12
* Check if value is a valid AST node
13
* @param node - Value to check
14
* @returns True if value is a node
15
*/
16
function isNode(node: any): boolean;
17
18
/**
19
* Check if node is a container (can have children)
20
* @param node - Node to check
21
* @returns True if node is Root, Selector, or Pseudo
22
*/
23
function isContainer(node: any): boolean;
24
25
/**
26
* Check if node supports namespaces
27
* @param node - Node to check
28
* @returns True if node is Attribute or Tag
29
*/
30
function isNamespace(node: any): boolean;
31
```
32
33
**Usage Examples:**
34
35
```javascript
36
const parser = require('postcss-selector-parser');
37
38
const ast = parser().astSync('.class, #id');
39
const node = ast.first.first;
40
41
// Check if it's a valid node
42
if (parser.isNode(node)) {
43
console.log('Valid node:', node.type);
44
}
45
46
// Check if it can contain children
47
if (parser.isContainer(node)) {
48
console.log('Can contain children');
49
node.walk(child => {
50
console.log('Child:', child.type);
51
});
52
}
53
54
// Check if it supports namespaces
55
if (parser.isNamespace(node)) {
56
console.log('Supports namespaces');
57
console.log('Namespace:', node.namespace);
58
}
59
```
60
61
### Container Type Guards
62
63
Functions for identifying specific container node types.
64
65
```javascript { .api }
66
/**
67
* Check if node is a Root container
68
* @param node - Node to check
69
* @returns True if node is Root
70
*/
71
function isRoot(node: any): boolean;
72
73
/**
74
* Check if node is a Selector container
75
* @param node - Node to check
76
* @returns True if node is Selector
77
*/
78
function isSelector(node: any): boolean;
79
80
/**
81
* Check if node is a Pseudo container
82
* @param node - Node to check
83
* @returns True if node is Pseudo
84
*/
85
function isPseudo(node: any): boolean;
86
```
87
88
**Usage Examples:**
89
90
```javascript
91
const parser = require('postcss-selector-parser');
92
93
const ast = parser().astSync('.class:hover');
94
95
// Check root
96
if (parser.isRoot(ast)) {
97
console.log('This is the root container');
98
console.log('Selectors:', ast.nodes.length);
99
}
100
101
// Check selector
102
const firstChild = ast.first;
103
if (parser.isSelector(firstChild)) {
104
console.log('This is a selector');
105
console.log('Components:', firstChild.nodes.length);
106
}
107
108
// Check pseudo
109
const pseudo = firstChild.last;
110
if (parser.isPseudo(pseudo)) {
111
console.log('This is a pseudo selector');
112
console.log('Value:', pseudo.value);
113
}
114
```
115
116
### Leaf Node Type Guards
117
118
Functions for identifying specific leaf node types that cannot contain children.
119
120
```javascript { .api }
121
/**
122
* Check if node is an Attribute selector
123
* @param node - Node to check
124
* @returns True if node is Attribute
125
*/
126
function isAttribute(node: any): boolean;
127
128
/**
129
* Check if node is a ClassName selector
130
* @param node - Node to check
131
* @returns True if node is ClassName
132
*/
133
function isClassName(node: any): boolean;
134
135
/**
136
* Check if node is a Combinator
137
* @param node - Node to check
138
* @returns True if node is Combinator
139
*/
140
function isCombinator(node: any): boolean;
141
142
/**
143
* Check if node is a Comment
144
* @param node - Node to check
145
* @returns True if node is Comment
146
*/
147
function isComment(node: any): boolean;
148
149
/**
150
* Check if node is an Identifier (ID selector)
151
* @param node - Node to check
152
* @returns True if node is Identifier
153
*/
154
function isIdentifier(node: any): boolean;
155
156
/**
157
* Check if node is a Nesting selector
158
* @param node - Node to check
159
* @returns True if node is Nesting
160
*/
161
function isNesting(node: any): boolean;
162
163
/**
164
* Check if node is a String literal
165
* @param node - Node to check
166
* @returns True if node is String
167
*/
168
function isString(node: any): boolean;
169
170
/**
171
* Check if node is a Tag selector
172
* @param node - Node to check
173
* @returns True if node is Tag
174
*/
175
function isTag(node: any): boolean;
176
177
/**
178
* Check if node is a Universal selector
179
* @param node - Node to check
180
* @returns True if node is Universal
181
*/
182
function isUniversal(node: any): boolean;
183
```
184
185
**Usage Examples:**
186
187
```javascript
188
const parser = require('postcss-selector-parser');
189
190
const ast = parser().astSync('div.class#id[href] > * + /* comment */');
191
const selector = ast.first;
192
193
// Walk through nodes and identify types
194
selector.walk(node => {
195
if (parser.isTag(node)) {
196
console.log('Tag:', node.value);
197
} else if (parser.isClassName(node)) {
198
console.log('Class:', node.value);
199
} else if (parser.isIdentifier(node)) {
200
console.log('ID:', node.value);
201
} else if (parser.isAttribute(node)) {
202
console.log('Attribute:', node.attribute);
203
} else if (parser.isCombinator(node)) {
204
console.log('Combinator:', node.value);
205
} else if (parser.isUniversal(node)) {
206
console.log('Universal selector');
207
} else if (parser.isComment(node)) {
208
console.log('Comment:', node.value);
209
}
210
});
211
```
212
213
### Pseudo Type Guards
214
215
Specialized functions for distinguishing between pseudo-classes and pseudo-elements.
216
217
```javascript { .api }
218
/**
219
* Check if node is specifically a pseudo-element
220
* @param node - Node to check
221
* @returns True if node is a pseudo-element
222
*/
223
function isPseudoElement(node: any): boolean;
224
225
/**
226
* Check if node is specifically a pseudo-class
227
* @param node - Node to check
228
* @returns True if node is a pseudo-class
229
*/
230
function isPseudoClass(node: any): boolean;
231
```
232
233
**Usage Examples:**
234
235
```javascript
236
const parser = require('postcss-selector-parser');
237
238
const ast = parser().astSync('.btn:hover::before:first-letter');
239
const selector = ast.first;
240
241
selector.walkPseudos(pseudo => {
242
if (parser.isPseudoElement(pseudo)) {
243
console.log('Pseudo-element:', pseudo.value);
244
// Outputs: ::before, :first-letter
245
} else if (parser.isPseudoClass(pseudo)) {
246
console.log('Pseudo-class:', pseudo.value);
247
// Outputs: :hover
248
}
249
});
250
251
// Specific pseudo-element detection
252
const pseudos = [':before', ':after', '::before', '::after', ':first-letter', ':first-line'];
253
pseudos.forEach(pseudoValue => {
254
const node = parser.pseudo({ value: pseudoValue });
255
console.log(`${pseudoValue} is pseudo-element:`, parser.isPseudoElement(node));
256
});
257
```
258
259
### Type-Safe Processing
260
261
Using type guards for safe node processing and transformation.
262
263
**Usage Examples:**
264
265
```javascript
266
const parser = require('postcss-selector-parser');
267
268
// Transform function using type guards
269
const transform = selectors => {
270
selectors.walk(node => {
271
// Remove universal selectors
272
if (parser.isUniversal(node)) {
273
node.remove();
274
return;
275
}
276
277
// Convert all IDs to classes
278
if (parser.isIdentifier(node)) {
279
const className = parser.className({ value: node.value });
280
node.replaceWith(className);
281
return;
282
}
283
284
// Add namespace to tags
285
if (parser.isTag(node)) {
286
node.namespace = 'app';
287
return;
288
}
289
290
// Process attributes
291
if (parser.isAttribute(node)) {
292
if (node.attribute === 'class') {
293
// Convert [class="value"] to .value
294
if (node.operator === '=' && node.value) {
295
const className = parser.className({ value: node.value });
296
node.replaceWith(className);
297
}
298
}
299
return;
300
}
301
});
302
};
303
304
const processor = parser(transform);
305
const result = processor.processSync('*#header.nav[class="btn"]');
306
// Result: app|#header.nav.btn
307
```
308
309
### Advanced Type Guard Usage
310
311
Combining type guards for complex logic and validation.
312
313
**Usage Examples:**
314
315
```javascript
316
const parser = require('postcss-selector-parser');
317
318
// Function to analyze selector complexity
319
function analyzeSelector(selectorString) {
320
const ast = parser().astSync(selectorString);
321
const stats = {
322
selectors: 0,
323
tags: 0,
324
classes: 0,
325
ids: 0,
326
attributes: 0,
327
pseudoClasses: 0,
328
pseudoElements: 0,
329
combinators: 0,
330
hasNamespaces: false,
331
hasComments: false
332
};
333
334
ast.walk(node => {
335
if (parser.isSelector(node)) {
336
stats.selectors++;
337
} else if (parser.isTag(node)) {
338
stats.tags++;
339
if (parser.isNamespace(node) && node.namespace) {
340
stats.hasNamespaces = true;
341
}
342
} else if (parser.isClassName(node)) {
343
stats.classes++;
344
} else if (parser.isIdentifier(node)) {
345
stats.ids++;
346
} else if (parser.isAttribute(node)) {
347
stats.attributes++;
348
} else if (parser.isPseudoClass(node)) {
349
stats.pseudoClasses++;
350
} else if (parser.isPseudoElement(node)) {
351
stats.pseudoElements++;
352
} else if (parser.isCombinator(node)) {
353
stats.combinators++;
354
} else if (parser.isComment(node)) {
355
stats.hasComments = true;
356
}
357
});
358
359
return stats;
360
}
361
362
// Usage
363
const stats = analyzeSelector('div.nav#main[data-id] > .item:hover::before');
364
console.log(stats);
365
// { selectors: 1, tags: 1, classes: 2, ids: 1, attributes: 1,
366
// pseudoClasses: 1, pseudoElements: 1, combinators: 1, ... }
367
```