Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,14 +215,14 @@ for (const token of tokenize('a { color: red }')) {

### Node types, type guards and `clone()`

Node type constants (`STYLE_RULE`, `DECLARATION`, `DIMENSION`, …), `TYPE_NAMES` and `NODE_TYPES` are exported from the root, as are type guards such as `is_declaration()` and `is_dimension()` that narrow a node to its specific type. `node.clone({ deep?, locations? })` returns a mutable plain-object copy of a node.
Node type constants (`STYLE_RULE`, `DECLARATION`, `DIMENSION`, …) and `NODE_TYPES` are exported from the root, as are type guards such as `is_declaration()` and `is_dimension()` that narrow a node to its specific type. `node.clone({ deep?, locations? })` returns a mutable plain-object copy of a node.

```typescript
import { parse, is_declaration, TYPE_NAMES, DECLARATION } from '@projectwallace/css-parser'
import { parse, is_declaration } from '@projectwallace/css-parser'

const decl = parse('a { color: red }').first_child.block.first_child
is_declaration(decl) // true
TYPE_NAMES[DECLARATION] // "Declaration"
decl.type_name // "Declaration"
decl.clone({ deep: false }).property // "color"
```

Expand Down
197 changes: 145 additions & 52 deletions src/css-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,57 +72,54 @@ import {
} from './string-utils'
import { dimension_number_end } from './parse-dimension'

// Type name lookup table - maps numeric type to CSSTree-compatible strings
export const TYPE_NAMES = {
[STYLESHEET]: 'StyleSheet',
[STYLE_RULE]: 'Rule',
[AT_RULE]: 'Atrule',
[DECLARATION]: 'Declaration',
[SELECTOR]: 'Selector',
[COMMENT]: 'Comment',
[BLOCK]: 'Block',
[RAW]: 'Raw',
[IDENTIFIER]: 'Identifier',
[NUMBER]: 'Number',
[DIMENSION]: 'Dimension',
[STRING]: 'String',
[HASH]: 'Hash',
[FUNCTION]: 'Function',
[OPERATOR]: 'Operator',
[PARENTHESIS]: 'Parentheses',
[URL]: 'Url',
[UNICODE_RANGE]: 'UnicodeRange',
[VALUE]: 'Value',
[SELECTOR_LIST]: 'SelectorList',
[TYPE_SELECTOR]: 'TypeSelector',
[CLASS_SELECTOR]: 'ClassSelector',
[ID_SELECTOR]: 'IdSelector',
[ATTRIBUTE_SELECTOR]: 'AttributeSelector',
[PSEUDO_CLASS_SELECTOR]: 'PseudoClassSelector',
[PSEUDO_ELEMENT_SELECTOR]: 'PseudoElementSelector',
[COMBINATOR]: 'Combinator',
[UNIVERSAL_SELECTOR]: 'UniversalSelector',
[NESTING_SELECTOR]: 'NestingSelector',
[NTH_SELECTOR]: 'Nth',
[NTH_OF_SELECTOR]: 'NthOf',
[LANG_SELECTOR]: 'Lang',
[MEDIA_QUERY]: 'MediaQuery',
[MEDIA_FEATURE]: 'Feature',
[MEDIA_TYPE]: 'MediaType',
[CONTAINER_QUERY]: 'ContainerQuery',
[SUPPORTS_QUERY]: 'SupportsQuery',
[SUPPORTS_DECLARATION]: 'SupportsDeclaration',
[LAYER_NAME]: 'Layer',
[PRELUDE_OPERATOR]: 'Operator',
[FEATURE_RANGE]: 'MediaFeatureRange',
[AT_RULE_PRELUDE]: 'AtrulePrelude',
[PRELUDE_SELECTORLIST]: 'PreludeSelectorList',
[RATIO]: 'Ratio',
[IF_BRANCH]: 'IfBranch',
[IF_CONDITION]: 'IfCondition',
} as const

export type TypeName = (typeof TYPE_NAMES)[keyof typeof TYPE_NAMES] | 'unknown'
// CSSTree-compatible node type names
export type TypeName =
| 'StyleSheet'
| 'Rule'
| 'Atrule'
| 'Declaration'
| 'Selector'
| 'Comment'
| 'Block'
| 'Raw'
| 'Identifier'
| 'Number'
| 'Dimension'
| 'String'
| 'Hash'
| 'Function'
| 'Operator'
| 'Parentheses'
| 'Url'
| 'UnicodeRange'
| 'Value'
| 'SelectorList'
| 'TypeSelector'
| 'ClassSelector'
| 'IdSelector'
| 'AttributeSelector'
| 'PseudoClassSelector'
| 'PseudoElementSelector'
| 'Combinator'
| 'UniversalSelector'
| 'NestingSelector'
| 'Nth'
| 'NthOf'
| 'Lang'
| 'MediaQuery'
| 'Feature'
| 'MediaType'
| 'ContainerQuery'
| 'SupportsQuery'
| 'SupportsDeclaration'
| 'Layer'
| 'MediaFeatureRange'
| 'AtrulePrelude'
| 'PreludeSelectorList'
| 'Ratio'
| 'IfBranch'
| 'IfCondition'
| 'unknown'

// Node type constants (numeric for performance)
export type CSSNodeType =
Expand Down Expand Up @@ -327,7 +324,103 @@ export class CSSNode {

/** Get node type as human-readable string */
get type_name(): TypeName {
return TYPE_NAMES[this.type] || 'unknown'
// A switch compiles to a jump table, which is faster than an object lookup
switch (this.type) {
case STYLESHEET:
return 'StyleSheet'
case STYLE_RULE:
return 'Rule'
case AT_RULE:
return 'Atrule'
case DECLARATION:
return 'Declaration'
case SELECTOR:
return 'Selector'
case COMMENT:
return 'Comment'
case BLOCK:
return 'Block'
case RAW:
return 'Raw'
case IDENTIFIER:
return 'Identifier'
case NUMBER:
return 'Number'
case DIMENSION:
return 'Dimension'
case STRING:
return 'String'
case HASH:
return 'Hash'
case FUNCTION:
return 'Function'
case OPERATOR:
return 'Operator'
case PARENTHESIS:
return 'Parentheses'
case URL:
return 'Url'
case UNICODE_RANGE:
return 'UnicodeRange'
case VALUE:
return 'Value'
case SELECTOR_LIST:
return 'SelectorList'
case TYPE_SELECTOR:
return 'TypeSelector'
case CLASS_SELECTOR:
return 'ClassSelector'
case ID_SELECTOR:
return 'IdSelector'
case ATTRIBUTE_SELECTOR:
return 'AttributeSelector'
case PSEUDO_CLASS_SELECTOR:
return 'PseudoClassSelector'
case PSEUDO_ELEMENT_SELECTOR:
return 'PseudoElementSelector'
case COMBINATOR:
return 'Combinator'
case UNIVERSAL_SELECTOR:
return 'UniversalSelector'
case NESTING_SELECTOR:
return 'NestingSelector'
case NTH_SELECTOR:
return 'Nth'
case NTH_OF_SELECTOR:
return 'NthOf'
case LANG_SELECTOR:
return 'Lang'
case MEDIA_QUERY:
return 'MediaQuery'
case MEDIA_FEATURE:
return 'Feature'
case MEDIA_TYPE:
return 'MediaType'
case CONTAINER_QUERY:
return 'ContainerQuery'
case SUPPORTS_QUERY:
return 'SupportsQuery'
case SUPPORTS_DECLARATION:
return 'SupportsDeclaration'
case LAYER_NAME:
return 'Layer'
case PRELUDE_OPERATOR:
return 'Operator'
case FEATURE_RANGE:
return 'MediaFeatureRange'
case AT_RULE_PRELUDE:
return 'AtrulePrelude'
case PRELUDE_SELECTORLIST:
return 'PreludeSelectorList'
case RATIO:
return 'Ratio'
case IF_BRANCH:
return 'IfBranch'
case IF_CONDITION:
return 'IfCondition'
default:
return 'unknown'
}
}

/** Get the full text of this node from source */
Expand Down
2 changes: 1 addition & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export {
export { type ParserOptions } from './parse'

// Types
export { TYPE_NAMES, type CloneOptions, type PlainCSSNode } from './css-node'
export { type CloneOptions, type PlainCSSNode } from './css-node'
export type { LexerPosition, CommentInfo } from './tokenize'

// Constants - imported from dedicated constants file
Expand Down
Loading