or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

ast-nodes.mddocument-processing.mderror-handling.mdindex.mdparse-stringify.mdparser-infrastructure.mdschema-configuration.mdtree-traversal.mdtype-guards.mdutilities.md

utilities.mddocs/

0

# Utilities

1

2

Helper functions for node creation, type conversion, string formatting, and advanced YAML operations exposed through the util export. These utilities provide convenient access to lower-level functionality for specialized use cases.

3

4

## Capabilities

5

6

### Node Creation Utilities

7

8

Functions for creating and manipulating YAML AST nodes from JavaScript values.

9

10

```typescript { .api }

11

/**

12

* Create YAML node from JavaScript value

13

* @param value - Value to convert to node

14

* @param options - Node creation options

15

* @returns Created YAML node

16

*/

17

function createNode(value: unknown, options?: CreateNodeOptions): Node;

18

19

/**

20

* Create key-value pair node

21

* @param key - Key for the pair

22

* @param value - Value for the pair

23

* @param options - Node creation options

24

* @returns Pair node

25

*/

26

function createPair(key: any, value: any, options?: CreateNodeOptions): Pair;

27

28

interface CreateNodeContext {

29

/** Document schema */

30

schema: Schema;

31

/** Creation options */

32

options: CreateNodeOptions;

33

/** Anchor map for deduplication */

34

anchors?: Map<unknown, string>;

35

/** Current creation path */

36

path?: (string | number)[];

37

}

38

```

39

40

**Usage Examples:**

41

42

```typescript

43

import { createNode, createPair } from "yaml/util";

44

import { Schema } from "yaml";

45

46

const schema = new Schema({ version: '1.2' });

47

48

// Create scalar nodes

49

const stringNode = createNode('Hello World', { schema });

50

const numberNode = createNode(42, { schema });

51

const booleanNode = createNode(true, { schema });

52

53

// Create collection nodes

54

const arrayNode = createNode(['item1', 'item2', 'item3'], {

55

schema,

56

flow: true // Use flow style: [item1, item2, item3]

57

});

58

59

const objectNode = createNode({

60

name: 'John Doe',

61

age: 30,

62

active: true

63

}, {

64

schema,

65

sortMapEntries: true // Sort keys alphabetically

66

});

67

68

// Create pair nodes

69

const keyValuePair = createPair('config', { timeout: 30, retries: 3 }, { schema });

70

71

// Advanced node creation with anchors

72

const sharedConfig = { host: 'localhost', port: 5432 };

73

const node1 = createNode(sharedConfig, {

74

schema,

75

anchorPrefix: 'config'

76

});

77

78

const node2 = createNode(sharedConfig, {

79

schema,

80

anchorPrefix: 'config' // Will reuse anchor

81

});

82

83

console.log(stringNode.toString()); // "Hello World"

84

console.log(arrayNode.toString()); // [item1, item2, item3]

85

console.log(keyValuePair.toString()); // config: {timeout: 30, retries: 3}

86

```

87

88

### Type Conversion Utilities

89

90

Functions for converting between YAML nodes and JavaScript values.

91

92

```typescript { .api }

93

/**

94

* Convert YAML node to JavaScript value

95

* @param value - YAML node or value to convert

96

* @param arg - Conversion options or context

97

* @returns JavaScript representation

98

*/

99

function toJS(value: unknown, arg?: string | ToJSOptions): any;

100

101

interface ToJSContext {

102

/** Document being processed */

103

doc: Document;

104

/** Current conversion path */

105

path: (string | number)[];

106

/** Anchors encountered during conversion */

107

anchors: Map<Node, unknown>;

108

/** Maximum alias count */

109

maxAliasCount: number;

110

/** Keep scalar wrapper objects */

111

keepScalar?: boolean;

112

/** Map representation preference */

113

mapAsMap?: boolean;

114

}

115

```

116

117

**Usage Examples:**

118

119

```typescript

120

import { toJS } from "yaml/util";

121

import { parseDocument } from "yaml";

122

123

const doc = parseDocument(`

124

config:

125

database: &db

126

host: localhost

127

port: 5432

128

ssl: true

129

130

development:

131

<<: *db

132

name: dev_database

133

134

production:

135

<<: *db

136

name: prod_database

137

host: prod.example.com

138

`);

139

140

// Basic conversion

141

const basicJS = toJS(doc.contents);

142

console.log(basicJS);

143

144

// Conversion with options

145

const jsWithMaps = toJS(doc.contents, {

146

mapAsMap: true, // Use Map objects instead of plain objects

147

keepScalar: false, // Don't keep Scalar wrapper objects

148

maxAliasCount: 100 // Prevent infinite recursion

149

});

150

151

// Custom reviver function

152

const jsWithReviver = toJS(doc.contents, {

153

reviver: (key, value) => {

154

// Transform date strings to Date objects

155

if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(value)) {

156

return new Date(value);

157

}

158

return value;

159

}

160

});

161

162

// Convert individual nodes

163

const configNode = doc.get(['config'], true);

164

if (configNode) {

165

const configJS = toJS(configNode, { mapAsMap: false });

166

console.log('Config as plain object:', configJS);

167

}

168

```

169

170

### Collection Utilities

171

172

Helper functions for working with YAML collections (maps and sequences).

173

174

```typescript { .api }

175

/**

176

* Find pair in map items by key

177

* @param items - Map items to search

178

* @param key - Key to find

179

* @returns Matching pair or undefined

180

*/

181

function findPair(items: Iterable<unknown>, key: unknown): Pair | undefined;

182

```

183

184

**Usage Examples:**

185

186

```typescript

187

import { findPair } from "yaml/util";

188

import { parseDocument, isPair, isSeq, isMap } from "yaml";

189

190

const doc = parseDocument(`

191

users:

192

- name: Alice

193

email: alice@example.com

194

role: admin

195

- name: Bob

196

email: bob@example.com

197

role: user

198

- name: Charlie

199

email: charlie@example.com

200

role: user

201

`);

202

203

const usersNode = doc.get(['users'], true);

204

if (isSeq(usersNode)) {

205

usersNode.items.forEach((userNode, index) => {

206

if (isMap(userNode)) {

207

// Find specific fields

208

const namePair = findPair(userNode.items, 'name');

209

const emailPair = findPair(userNode.items, 'email');

210

const rolePair = findPair(userNode.items, 'role');

211

212

if (namePair && emailPair && rolePair) {

213

console.log(`User ${index + 1}:`);

214

console.log(` Name: ${namePair.value}`);

215

console.log(` Email: ${emailPair.value}`);

216

console.log(` Role: ${rolePair.value}`);

217

}

218

}

219

});

220

}

221

222

// Modify found pairs

223

const configDoc = parseDocument(`

224

database:

225

host: localhost

226

port: 5432

227

ssl: false

228

`);

229

230

const dbNode = configDoc.get(['database'], true);

231

if (isMap(dbNode)) {

232

const sslPair = findPair(dbNode.items, 'ssl');

233

if (sslPair && isPair(sslPair)) {

234

sslPair.value = new Scalar(true); // Enable SSL

235

console.log('Updated config:', configDoc.toString());

236

}

237

}

238

```

239

240

### Schema Tag Utilities

241

242

Access to built-in schema tags for custom schema creation and manipulation.

243

244

```typescript { .api }

245

/**

246

* Built-in map tag definition

247

*/

248

declare const mapTag: ScalarTag;

249

250

/**

251

* Built-in sequence tag definition

252

*/

253

declare const seqTag: ScalarTag;

254

255

/**

256

* Built-in string tag definition

257

*/

258

declare const stringTag: ScalarTag;

259

```

260

261

**Usage Examples:**

262

263

```typescript

264

import { mapTag, seqTag, stringTag } from "yaml/util";

265

import { Schema } from "yaml";

266

267

// Create custom schema with built-in tags

268

const customSchema = new Schema({

269

version: '1.2',

270

tags: [

271

mapTag,

272

seqTag,

273

stringTag,

274

// Add custom tags

275

{

276

tag: '!date',

277

resolve: (str) => new Date(str),

278

stringify: (date) => date.toISOString().split('T')[0],

279

test: /^\d{4}-\d{2}-\d{2}$/

280

}

281

]

282

});

283

284

// Use tags directly

285

console.log('Map tag:', mapTag.tag); // !!map

286

console.log('Seq tag:', seqTag.tag); // !!seq

287

console.log('String tag:', stringTag.tag); // !!str

288

289

// Custom tag behavior

290

const testValue = "2023-12-01";

291

const customTag = customSchema.tags.find(tag => tag.tag === '!date');

292

if (customTag && customTag.test && customTag.resolve) {

293

if (customTag.test.test(testValue)) {

294

const resolved = customTag.resolve(testValue);

295

console.log('Resolved date:', resolved); // Date object

296

}

297

}

298

```

299

300

### String Processing Utilities

301

302

Advanced string formatting and processing functions for YAML output.

303

304

```typescript { .api }

305

/**

306

* Fold long lines in flow scalars

307

* @param text - Text to fold

308

* @param options - Folding options

309

* @returns Folded text

310

*/

311

function foldFlowLines(text: string, options?: FoldOptions): string;

312

313

interface FoldOptions {

314

/** Maximum line width */

315

lineWidth?: number;

316

/** Minimum content width */

317

minContentWidth?: number;

318

/** Handle lines with indicators */

319

indicatorWidth?: number;

320

/** More aggressive folding */

321

onFold?: () => void;

322

}

323

324

/**

325

* Convert number to YAML string representation

326

* @param value - Number to stringify

327

* @returns YAML string representation

328

*/

329

function stringifyNumber(value: number): string;

330

331

/**

332

* Convert string to YAML string representation

333

* @param value - String to convert

334

* @param ctx - Stringify context

335

* @param onComment - Comment handler

336

* @param onChompKeep - Chomp keep handler

337

* @returns YAML string representation

338

*/

339

function stringifyString(

340

value: string,

341

ctx?: StringifyContext,

342

onComment?: () => void,

343

onChompKeep?: () => void

344

): string;

345

346

interface StringifyContext {

347

/** Document being stringified */

348

doc: Document;

349

/** Indentation string */

350

indent: string;

351

/** Current indentation level */

352

indentStep: string;

353

/** Stringify options */

354

options: ToStringOptions;

355

/** Type of container */

356

type?: Scalar.Type;

357

}

358

```

359

360

**Usage Examples:**

361

362

```typescript

363

import {

364

foldFlowLines,

365

stringifyNumber,

366

stringifyString

367

} from "yaml/util";

368

369

// Fold long text

370

const longText = "This is a very long line of text that should be folded across multiple lines to improve readability and conform to line width constraints in YAML documents.";

371

372

const folded = foldFlowLines(longText, {

373

lineWidth: 60,

374

minContentWidth: 20

375

});

376

377

console.log('Folded text:');

378

console.log(folded);

379

// Output:

380

// This is a very long line of text that should be folded

381

// across multiple lines to improve readability and conform to

382

// line width constraints in YAML documents.

383

384

// Number stringification

385

console.log(stringifyNumber(42)); // "42"

386

console.log(stringifyNumber(3.14159)); // "3.14159"

387

console.log(stringifyNumber(Infinity)); // ".inf"

388

console.log(stringifyNumber(-Infinity)); // "-.inf"

389

console.log(stringifyNumber(NaN)); // ".nan"

390

391

// String stringification with context

392

const ctx = {

393

doc: new Document(),

394

indent: '',

395

indentStep: ' ',

396

options: {

397

lineWidth: 80,

398

singleQuote: false,

399

blockQuote: false

400

}

401

};

402

403

// Simple string

404

console.log(stringifyString('Hello World', ctx)); // Hello World

405

406

// String requiring quotes

407

console.log(stringifyString('Hello: World', ctx)); // "Hello: World"

408

409

// Multiline string

410

const multiline = 'Line 1\nLine 2\nLine 3';

411

console.log(stringifyString(multiline, {

412

...ctx,

413

options: { ...ctx.options, blockQuote: 'literal' }

414

}));

415

// Output:

416

// |

417

// Line 1

418

// Line 2

419

// Line 3

420

```

421

422

### Logging Utilities

423

424

Logging functions for debugging and development.

425

426

```typescript { .api }

427

type LogLevelId = 'silent' | 'error' | 'warn' | 'debug';

428

429

/**

430

* Debug logging function

431

* @param logLevel - Current log level

432

* @param messages - Messages to log

433

*/

434

function debug(logLevel: LogLevelId, ...messages: any[]): void;

435

436

/**

437

* Warning logging function

438

* @param logLevel - Current log level

439

* @param messages - Messages to log

440

*/

441

function warn(logLevel: LogLevelId, ...messages: any[]): void;

442

```

443

444

**Usage Examples:**

445

446

```typescript

447

import { debug, warn } from "yaml/util";

448

449

// Configure logging level

450

const logLevel = 'debug';

451

452

// Debug messages (only shown when logLevel is 'debug')

453

debug(logLevel, 'Processing YAML document');

454

debug(logLevel, 'Found', 5, 'top-level keys');

455

456

// Warning messages (shown when logLevel is 'warn' or 'debug')

457

warn(logLevel, 'Deprecated YAML 1.1 syntax detected');

458

warn(logLevel, 'Duplicate key found:', 'database.host');

459

460

// Silent mode (nothing logged)

461

const silentLevel = 'silent';

462

debug(silentLevel, 'This will not be logged');

463

warn(silentLevel, 'This will also not be logged');

464

465

// Conditional logging

466

function processConfig(config: any, logLevel: LogLevelId) {

467

debug(logLevel, 'Starting config processing');

468

469

if (!config.database) {

470

warn(logLevel, 'No database configuration found');

471

}

472

473

debug(logLevel, 'Config processing completed');

474

}

475

476

processConfig({ app: 'MyApp' }, 'debug');

477

```

478

479

### Advanced Utility Patterns

480

481

Combine utilities for complex YAML processing workflows.

482

483

```typescript

484

import {

485

createNode,

486

createPair,

487

toJS,

488

findPair,

489

stringifyString

490

} from "yaml/util";

491

import {

492

Schema,

493

Document,

494

isMap,

495

isPair,

496

YAMLMap,

497

Scalar

498

} from "yaml";

499

500

class YAMLConfigManager {

501

private schema: Schema;

502

503

constructor() {

504

this.schema = new Schema({

505

version: '1.2',

506

sortMapEntries: true

507

});

508

}

509

510

// Merge configurations with proper YAML structure

511

mergeConfigs(base: any, override: any): Document {

512

const doc = new Document();

513

514

// Create base structure

515

const baseNode = createNode(base, {

516

schema: this.schema,

517

sortMapEntries: true

518

});

519

520

// Apply overrides

521

const overrideNode = createNode(override, {

522

schema: this.schema,

523

sortMapEntries: true

524

});

525

526

// Merge logic

527

const merged = this.deepMergeNodes(baseNode, overrideNode);

528

doc.contents = merged;

529

530

return doc;

531

}

532

533

private deepMergeNodes(base: any, override: any): any {

534

if (isMap(base) && isMap(override)) {

535

const result = new YAMLMap(this.schema);

536

537

// Add all base pairs

538

base.items.forEach(pair => {

539

if (isPair(pair)) {

540

result.items.push(createPair(pair.key, pair.value, {

541

schema: this.schema

542

}));

543

}

544

});

545

546

// Override/merge with override pairs

547

override.items.forEach(overridePair => {

548

if (isPair(overridePair)) {

549

const existingPair = findPair(result.items, overridePair.key);

550

551

if (existingPair && isPair(existingPair)) {

552

// Merge nested objects

553

existingPair.value = this.deepMergeNodes(

554

existingPair.value,

555

overridePair.value

556

);

557

} else {

558

// Add new pair

559

result.items.push(createPair(

560

overridePair.key,

561

overridePair.value,

562

{ schema: this.schema }

563

));

564

}

565

}

566

});

567

568

return result;

569

}

570

571

// For non-objects, override takes precedence

572

return override;

573

}

574

575

// Extract configuration section

576

extractSection(doc: Document, path: string[]): any {

577

let current = doc.contents;

578

579

for (const key of path) {

580

if (isMap(current)) {

581

const pair = findPair(current.items, key);

582

if (pair && isPair(pair)) {

583

current = pair.value;

584

} else {

585

return null;

586

}

587

} else {

588

return null;

589

}

590

}

591

592

return toJS(current);

593

}

594

595

// Validate configuration structure

596

validateConfig(doc: Document, requiredKeys: string[]): string[] {

597

const errors: string[] = [];

598

599

if (!isMap(doc.contents)) {

600

errors.push('Root must be a mapping');

601

return errors;

602

}

603

604

for (const key of requiredKeys) {

605

const pair = findPair(doc.contents.items, key);

606

if (!pair) {

607

errors.push(`Missing required key: ${key}`);

608

}

609

}

610

611

return errors;

612

}

613

}

614

615

// Usage example

616

const manager = new YAMLConfigManager();

617

618

const baseConfig = {

619

app: {

620

name: 'MyApp',

621

version: '1.0.0',

622

debug: false

623

},

624

database: {

625

host: 'localhost',

626

port: 5432,

627

ssl: false

628

}

629

};

630

631

const prodOverride = {

632

app: {

633

debug: false // Ensure debug is off

634

},

635

database: {

636

host: 'prod.example.com',

637

ssl: true

638

}

639

};

640

641

// Merge configurations

642

const prodConfig = manager.mergeConfigs(baseConfig, prodOverride);

643

console.log('Production config:');

644

console.log(prodConfig.toString());

645

646

// Extract and validate

647

const dbConfig = manager.extractSection(prodConfig, ['database']);

648

console.log('Database config:', dbConfig);

649

650

const errors = manager.validateConfig(prodConfig, ['app', 'database']);

651

if (errors.length > 0) {

652

console.log('Validation errors:', errors);

653

} else {

654

console.log('Configuration is valid');

655

}

656

```