or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

index.mdnode-constructors.mdnode-manipulation.mdparser-processor.mdtype-guards.md

node-manipulation.mddocs/

0

# Node Manipulation

1

2

Base methods available on all AST nodes for manipulation, navigation, and tree modification. Includes specialized container methods for nodes that can have children.

3

4

## Capabilities

5

6

### Base Node Interface

7

8

Common properties and methods available on all AST nodes.

9

10

```javascript { .api }

11

/**

12

* Base interface for all AST nodes

13

*/

14

interface Base {

15

/** Node type identifier */

16

type: string;

17

/** Parent container node */

18

parent: Container;

19

/** Node value/content */

20

value: string;

21

/** Whitespace configuration */

22

spaces: Spaces;

23

/** Source location information */

24

source?: NodeSource;

25

/** Index in source string */

26

sourceIndex: number;

27

/** Raw whitespace before node */

28

rawSpaceBefore: string;

29

/** Raw whitespace after node */

30

rawSpaceAfter: string;

31

/** Raw values for precise output control */

32

raws?: NodeRaws;

33

34

/**

35

* Remove this node from its parent

36

* @returns The removed node

37

*/

38

remove(): Node;

39

40

/**

41

* Replace this node with other nodes

42

* @param nodes - Nodes to replace with

43

* @returns This node

44

*/

45

replaceWith(...nodes: Node[]): Node;

46

47

/**

48

* Get the next sibling node

49

* @returns Next sibling or undefined

50

*/

51

next(): Node | undefined;

52

53

/**

54

* Get the previous sibling node

55

* @returns Previous sibling or undefined

56

*/

57

prev(): Node | undefined;

58

59

/**

60

* Clone this node

61

* @param opts - Override options

62

* @returns Cloned node

63

*/

64

clone(opts?: {[key: string]: any}): this;

65

66

/**

67

* Check if node includes character at given position

68

* @param line - 1-based line number

69

* @param column - 1-based column number

70

* @returns Whether node is at position

71

*/

72

isAtPosition(line: number, column: number): boolean | undefined;

73

74

/**

75

* Set property with escaped value

76

* @param name - Property name

77

* @param value - Unescaped value

78

* @param valueEscaped - Escaped value

79

*/

80

setPropertyAndEscape(name: string, value: any, valueEscaped: string): void;

81

82

/**

83

* Set property without escaping

84

* @param name - Property name

85

* @param value - Value (both escaped and unescaped)

86

*/

87

setPropertyWithoutEscape(name: string, value: any): void;

88

89

/**

90

* Append to property with escaped value

91

* @param name - Property name

92

* @param value - Unescaped value

93

* @param valueEscaped - Escaped value

94

*/

95

appendToPropertyAndEscape(name: string, value: any, valueEscaped: string): void;

96

97

/**

98

* Convert node to string representation

99

* @returns String representation

100

*/

101

toString(): string;

102

}

103

104

interface NodeRaws {

105

/** Raw value as it appeared in source */

106

value?: string;

107

/** Raw spacing information */

108

spaces?: {

109

before?: string;

110

after?: string;

111

};

112

}

113

```

114

115

**Usage Examples:**

116

117

```javascript

118

const parser = require('postcss-selector-parser');

119

120

const ast = parser().astSync('.class1, .class2');

121

const firstSelector = ast.first;

122

const classNode = firstSelector.first;

123

124

// Navigate nodes

125

const nextNode = classNode.next();

126

const prevNode = classNode.prev();

127

128

// Clone node

129

const clonedNode = classNode.clone();

130

131

// Remove node

132

classNode.remove();

133

134

// Replace node

135

const newClass = parser.className({ value: 'new-class' });

136

classNode.replaceWith(newClass);

137

```

138

139

### Container Interface

140

141

Methods available on nodes that can contain children (Root, Selector, Pseudo).

142

143

```javascript { .api }

144

/**

145

* Interface for nodes that can contain children

146

*/

147

interface Container extends Base {

148

/** Array of child nodes */

149

nodes: Node[];

150

151

/**

152

* Append a child node

153

* @param node - Node to append

154

* @returns This container

155

*/

156

append(node: Node): this;

157

158

/**

159

* Prepend a child node

160

* @param node - Node to prepend

161

* @returns This container

162

*/

163

prepend(node: Node): this;

164

165

/**

166

* Get child node at index

167

* @param index - Child index

168

* @returns Child node

169

*/

170

at(index: number): Node;

171

172

/**

173

* Get most specific node at line/column position

174

* @param line - 1-based line number

175

* @param column - 1-based column number

176

* @returns Node at position

177

*/

178

atPosition(line: number, column: number): Node;

179

180

/**

181

* Get index of child node

182

* @param child - Child node

183

* @returns Index of child

184

*/

185

index(child: Node): number;

186

187

/** First child node */

188

readonly first: Node;

189

190

/** Last child node */

191

readonly last: Node;

192

193

/** Number of child nodes */

194

readonly length: number;

195

196

/**

197

* Remove specific child node

198

* @param child - Child to remove

199

* @returns This container

200

*/

201

removeChild(child: Node): this;

202

203

/**

204

* Remove all child nodes

205

* @returns This container

206

*/

207

removeAll(): this;

208

209

/**

210

* Remove all child nodes (alias for removeAll)

211

* @returns This container

212

*/

213

empty(): this;

214

215

/**

216

* Insert nodes after existing node

217

* @param oldNode - Reference node

218

* @param newNode - Node to insert

219

* @param restNodes - Additional nodes to insert

220

* @returns This container

221

*/

222

insertAfter(oldNode: Node, newNode: Node, ...restNodes: Node[]): this;

223

224

/**

225

* Insert nodes before existing node

226

* @param oldNode - Reference node

227

* @param newNode - Node to insert

228

* @param restNodes - Additional nodes to insert

229

* @returns This container

230

*/

231

insertBefore(oldNode: Node, newNode: Node, ...restNodes: Node[]): this;

232

}

233

```

234

235

**Usage Examples:**

236

237

```javascript

238

const parser = require('postcss-selector-parser');

239

240

const root = parser.root();

241

const selector = parser.selector();

242

243

// Append children

244

selector.append(parser.tag({ value: 'div' }));

245

selector.append(parser.className({ value: 'container' }));

246

root.append(selector);

247

248

// Access children

249

const firstChild = selector.first; // div

250

const lastChild = selector.last; // .container

251

const childCount = selector.length; // 2

252

253

// Insert nodes

254

const id = parser.id({ value: 'main' });

255

selector.insertBefore(selector.first, id);

256

// Result: #main div.container

257

258

// Remove children

259

selector.removeChild(selector.last);

260

selector.empty(); // Remove all children

261

```

262

263

### Container Iteration Methods

264

265

Methods for iterating over and traversing container nodes.

266

267

```javascript { .api }

268

interface Container {

269

/**

270

* Iterate over direct children

271

* @param callback - Function called for each child

272

* @returns False if iteration was stopped

273

*/

274

each(callback: (node: Node, index: number) => boolean | void): boolean | undefined;

275

276

/**

277

* Walk all descendant nodes

278

* @param callback - Function called for each descendant

279

* @returns False if traversal was stopped

280

*/

281

walk(callback: (node: Node, index: number) => boolean | void): boolean | undefined;

282

283

/**

284

* Walk all attribute nodes

285

* @param callback - Function called for each attribute

286

* @returns False if traversal was stopped

287

*/

288

walkAttributes(callback: (node: Attribute) => boolean | void): boolean | undefined;

289

290

/**

291

* Walk all class nodes

292

* @param callback - Function called for each class

293

* @returns False if traversal was stopped

294

*/

295

walkClasses(callback: (node: ClassName) => boolean | void): boolean | undefined;

296

297

/**

298

* Walk all combinator nodes

299

* @param callback - Function called for each combinator

300

* @returns False if traversal was stopped

301

*/

302

walkCombinators(callback: (node: Combinator) => boolean | void): boolean | undefined;

303

304

/**

305

* Walk all comment nodes

306

* @param callback - Function called for each comment

307

* @returns False if traversal was stopped

308

*/

309

walkComments(callback: (node: Comment) => boolean | void): boolean | undefined;

310

311

/**

312

* Walk all ID nodes

313

* @param callback - Function called for each ID

314

* @returns False if traversal was stopped

315

*/

316

walkIds(callback: (node: Identifier) => boolean | void): boolean | undefined;

317

318

/**

319

* Walk all nesting nodes

320

* @param callback - Function called for each nesting node

321

* @returns False if traversal was stopped

322

*/

323

walkNesting(callback: (node: Nesting) => boolean | void): boolean | undefined;

324

325

/**

326

* Walk all pseudo nodes

327

* @param callback - Function called for each pseudo

328

* @returns False if traversal was stopped

329

*/

330

walkPseudos(callback: (node: Pseudo) => boolean | void): boolean | undefined;

331

332

/**

333

* Walk all tag nodes

334

* @param callback - Function called for each tag

335

* @returns False if traversal was stopped

336

*/

337

walkTags(callback: (node: Tag) => boolean | void): boolean | undefined;

338

339

/**

340

* Walk all universal nodes

341

* @param callback - Function called for each universal

342

* @returns False if traversal was stopped

343

*/

344

walkUniversals(callback: (node: Universal) => boolean | void): boolean | undefined;

345

}

346

```

347

348

**Usage Examples:**

349

350

```javascript

351

const parser = require('postcss-selector-parser');

352

353

const ast = parser().astSync('.btn, #header > .nav .item');

354

355

// Iterate over selectors

356

ast.each((selector, index) => {

357

console.log(`Selector ${index}:`, selector.toString());

358

});

359

360

// Walk all nodes

361

ast.walk((node, index) => {

362

console.log(`Node ${index}:`, node.type, node.value);

363

});

364

365

// Walk specific node types

366

ast.walkClasses(classNode => {

367

console.log('Class:', classNode.value);

368

// Outputs: btn, nav, item

369

});

370

371

ast.walkIds(idNode => {

372

console.log('ID:', idNode.value);

373

// Outputs: header

374

});

375

376

// Stop traversal early

377

ast.walkUniversals(universalNode => {

378

console.log('Universal selector found');

379

universalNode.remove(); // Remove all * selectors

380

});

381

382

ast.walkTags(tagNode => {

383

if (tagNode.value === 'div') {

384

return false; // Stop walking

385

}

386

});

387

```

388

389

### Container Array Methods

390

391

Array-like methods for working with child nodes.

392

393

```javascript { .api }

394

interface Container {

395

/**

396

* Split children based on predicate

397

* @param callback - Predicate function

398

* @returns Tuple of [matching, non-matching] nodes

399

*/

400

split(callback: (node: Node) => boolean): [Node[], Node[]];

401

402

/**

403

* Map over children

404

* @param callback - Mapping function

405

* @returns Array of mapped values

406

*/

407

map<T>(callback: (node: Node) => T): T[];

408

409

/**

410

* Reduce children to single value

411

* @param callback - Reducer function

412

* @param initialValue - Initial value

413

* @returns Reduced value

414

*/

415

reduce<T>(

416

callback: (

417

previousValue: T,

418

currentValue: Node,

419

currentIndex: number,

420

array: readonly Node[]

421

) => T,

422

initialValue?: T

423

): T;

424

425

/**

426

* Test if all children match predicate

427

* @param callback - Test function

428

* @returns True if all children match

429

*/

430

every(callback: (node: Node) => boolean): boolean;

431

432

/**

433

* Test if some children match predicate

434

* @param callback - Test function

435

* @returns True if any children match

436

*/

437

some(callback: (node: Node) => boolean): boolean;

438

439

/**

440

* Filter children by predicate

441

* @param callback - Filter function

442

* @returns Array of matching children

443

*/

444

filter(callback: (node: Node) => boolean): Node[];

445

446

/**

447

* Sort children by comparison function

448

* @param callback - Comparison function

449

* @returns Array of sorted children

450

*/

451

sort(callback: (nodeA: Node, nodeB: Node) => number): Node[];

452

}

453

```

454

455

**Usage Examples:**

456

457

```javascript

458

const parser = require('postcss-selector-parser');

459

460

const selector = parser().astSync('div.btn#main').first;

461

462

// Map node values

463

const values = selector.map(node => node.value);

464

// Result: ['div', 'btn', 'main']

465

466

// Filter by type

467

const classes = selector.filter(node => node.type === 'class');

468

469

// Check conditions

470

const hasId = selector.some(node => node.type === 'id');

471

const allHaveValues = selector.every(node => node.value);

472

473

// Split by type

474

const [tags, others] = selector.split(node => node.type === 'tag');

475

476

// Sort by value

477

const sorted = selector.sort((a, b) => a.value.localeCompare(b.value));

478

```

479

480

## Types

481

482

```javascript { .api }

483

interface Spaces {

484

before: string;

485

after: string;

486

[spaceType: string]: string | Partial<SpaceAround> | undefined;

487

}

488

489

interface SpaceAround {

490

before: string;

491

after: string;

492

}

493

494

interface NodeSource {

495

start?: { line: number; column: number };

496

end?: { line: number; column: number };

497

}

498

```