367 lines
6.3 KiB
Markdown
367 lines
6.3 KiB
Markdown
# Abstract Syntax Tree (AST)
|
|
|
|
## Overview
|
|
|
|
The AST represents CSS as a tree structure where each node has a specific type and properties. All nodes share common properties and have type-specific properties.
|
|
|
|
## Common Properties
|
|
|
|
All AST nodes have these properties:
|
|
|
|
### `type`
|
|
|
|
The node type as a string. See [Node Types](#node-types) for all possible values.
|
|
|
|
### `position` (optional)
|
|
|
|
Position information for the node in the source code:
|
|
|
|
```typescript
|
|
{
|
|
start: { line: number; column: number };
|
|
end: { line: number; column: number };
|
|
source?: string;
|
|
}
|
|
```
|
|
|
|
### `parent` (optional)
|
|
|
|
Reference to the parent node in the AST.
|
|
|
|
## Node Types
|
|
|
|
### `stylesheet`
|
|
|
|
The root node representing an entire CSS document.
|
|
|
|
**Properties:**
|
|
- `stylesheet.source` (optional): Source file path
|
|
- `stylesheet.rules`: Array of top-level rules
|
|
- `stylesheet.parsingErrors` (optional): Array of parse errors when `silent` option is used
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "stylesheet",
|
|
"stylesheet": {
|
|
"rules": [
|
|
// ... other nodes
|
|
]
|
|
}
|
|
}
|
|
```
|
|
|
|
### `rule`
|
|
|
|
A CSS rule with selectors and declarations.
|
|
|
|
**Properties:**
|
|
- `selectors`: Array of CSS selectors as strings
|
|
- `declarations`: Array of declarations and comments
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "rule",
|
|
"selectors": ["body", "html"],
|
|
"declarations": [
|
|
{
|
|
"type": "declaration",
|
|
"property": "color",
|
|
"value": "red"
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### `declaration`
|
|
|
|
A CSS property declaration.
|
|
|
|
**Properties:**
|
|
- `property`: The CSS property name
|
|
- `value`: The CSS property value as a string
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "declaration",
|
|
"property": "background-color",
|
|
"value": "#ffffff"
|
|
}
|
|
```
|
|
|
|
### `comment`
|
|
|
|
A CSS comment.
|
|
|
|
**Properties:**
|
|
- `comment`: The comment text (without `/*` and `*/`)
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "comment",
|
|
"comment": " This is a comment "
|
|
}
|
|
```
|
|
|
|
### `media`
|
|
|
|
A `@media` rule.
|
|
|
|
**Properties:**
|
|
- `media`: The media query string
|
|
- `rules`: Array of rules within the media block
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "media",
|
|
"media": "screen and (max-width: 768px)",
|
|
"rules": [
|
|
// ... nested rules
|
|
]
|
|
}
|
|
```
|
|
|
|
### `keyframes`
|
|
|
|
A `@keyframes` rule.
|
|
|
|
**Properties:**
|
|
- `name`: The keyframes name
|
|
- `vendor` (optional): Vendor prefix (e.g., "-webkit-")
|
|
- `keyframes`: Array of keyframe rules and comments
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "keyframes",
|
|
"name": "fade",
|
|
"keyframes": [
|
|
{
|
|
"type": "keyframe",
|
|
"values": ["from"],
|
|
"declarations": [
|
|
{
|
|
"type": "declaration",
|
|
"property": "opacity",
|
|
"value": "0"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### `keyframe`
|
|
|
|
A keyframe within a `@keyframes` rule.
|
|
|
|
**Properties:**
|
|
- `values`: Array of keyframe selectors (e.g., `["from"]`, `["to"]`, `["50%"]`)
|
|
- `declarations`: Array of declarations and comments
|
|
|
|
### `import`
|
|
|
|
An `@import` rule.
|
|
|
|
**Properties:**
|
|
- `import`: The import string (URL or media query)
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "import",
|
|
"import": "url('styles.css')"
|
|
}
|
|
```
|
|
|
|
### `charset`
|
|
|
|
A `@charset` rule.
|
|
|
|
**Properties:**
|
|
- `charset`: The character encoding
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "charset",
|
|
"charset": "utf-8"
|
|
}
|
|
```
|
|
|
|
### `namespace`
|
|
|
|
A `@namespace` rule.
|
|
|
|
**Properties:**
|
|
- `namespace`: The namespace declaration
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "namespace",
|
|
"namespace": "url(http://www.w3.org/1999/xhtml)"
|
|
}
|
|
```
|
|
|
|
### `supports`
|
|
|
|
A `@supports` rule.
|
|
|
|
**Properties:**
|
|
- `supports`: The supports condition
|
|
- `rules`: Array of rules within the supports block
|
|
|
|
**Example:**
|
|
```json
|
|
{
|
|
"type": "supports",
|
|
"supports": "(display: grid)",
|
|
"rules": [
|
|
// ... nested rules
|
|
]
|
|
}
|
|
```
|
|
|
|
### `document`
|
|
|
|
A `@document` rule.
|
|
|
|
**Properties:**
|
|
- `document`: The document condition
|
|
- `vendor` (optional): Vendor prefix
|
|
- `rules`: Array of rules within the document block
|
|
|
|
### `page`
|
|
|
|
A `@page` rule.
|
|
|
|
**Properties:**
|
|
- `selectors`: Array of page selectors
|
|
- `declarations`: Array of declarations and comments
|
|
|
|
### `font-face`
|
|
|
|
A `@font-face` rule.
|
|
|
|
**Properties:**
|
|
- `declarations`: Array of font declarations and comments
|
|
|
|
### `host`
|
|
|
|
A `:host` rule.
|
|
|
|
**Properties:**
|
|
- `rules`: Array of rules within the host block
|
|
|
|
### `container`
|
|
|
|
A `@container` rule.
|
|
|
|
**Properties:**
|
|
- `container`: The container query
|
|
- `rules`: Array of rules within the container block
|
|
|
|
### `layer`
|
|
|
|
A `@layer` rule.
|
|
|
|
**Properties:**
|
|
- `layer`: The layer name
|
|
- `rules` (optional): Array of rules within the layer block
|
|
|
|
### `custom-media`
|
|
|
|
A `@custom-media` rule.
|
|
|
|
**Properties:**
|
|
- `name`: The custom media query name
|
|
- `media`: The media query definition
|
|
|
|
### `starting-style`
|
|
|
|
A `@starting-style` rule.
|
|
|
|
**Properties:**
|
|
- `rules`: Array of rules within the starting-style block
|
|
|
|
## Type Hierarchy
|
|
|
|
The AST nodes are organized in the following hierarchy:
|
|
|
|
- `CssStylesheetAST` - Root node
|
|
- `CssAtRuleAST` - Union of all at-rule and rule nodes
|
|
- `CssAllNodesAST` - Union of all possible node types
|
|
|
|
## Working with the AST
|
|
|
|
### Traversing Nodes
|
|
|
|
```typescript
|
|
import { parse, CssStylesheetAST } from '@adobe/css-tools';
|
|
|
|
const ast: CssStylesheetAST = parse('body { color: red; }');
|
|
|
|
// Access top-level rules
|
|
ast.stylesheet.rules.forEach(rule => {
|
|
if (rule.type === 'rule') {
|
|
console.log('Selectors:', rule.selectors);
|
|
rule.declarations.forEach(decl => {
|
|
if (decl.type === 'declaration') {
|
|
console.log(`${decl.property}: ${decl.value}`);
|
|
}
|
|
});
|
|
}
|
|
});
|
|
```
|
|
|
|
### Modifying Nodes
|
|
|
|
```typescript
|
|
// Add a new declaration
|
|
const newDecl = {
|
|
type: 'declaration' as const,
|
|
property: 'font-size',
|
|
value: '16px'
|
|
};
|
|
|
|
// Find a rule and add the declaration
|
|
ast.stylesheet.rules.forEach(rule => {
|
|
if (rule.type === 'rule' && rule.selectors.includes('body')) {
|
|
rule.declarations.push(newDecl);
|
|
}
|
|
});
|
|
```
|
|
|
|
### Error Handling
|
|
|
|
When parsing with the `silent` option, errors are collected in the AST:
|
|
|
|
```typescript
|
|
const ast = parse('invalid css {', { silent: true });
|
|
|
|
if (ast.stylesheet.parsingErrors) {
|
|
ast.stylesheet.parsingErrors.forEach(error => {
|
|
console.error('Parse error:', error.message);
|
|
});
|
|
}
|
|
```
|
|
|
|
## Position Information
|
|
|
|
Position information is available on most nodes and includes:
|
|
|
|
- `start.line` and `start.column`: Beginning of the node
|
|
- `end.line` and `end.column`: End of the node
|
|
- `source`: Source file path (if provided during parsing)
|
|
|
|
This is useful for:
|
|
- Error reporting
|
|
- Source mapping
|
|
- Code analysis tools
|
|
- IDE integration
|