or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

core-highlighting.mdindex.mdlanguage-system.mdplugin-system.mdtoken-system.mdutilities.md

utilities.mddocs/

0

# Utilities

1

2

The utility system provides helper functions for DOM manipulation, language detection, object operations, and other common tasks needed throughout the PrismJS ecosystem. These utilities support both internal operations and external plugin development.

3

4

## Capabilities

5

6

### Utility Namespace

7

8

The main container for all utility functions and helper methods.

9

10

```javascript { .api }

11

/**

12

* Utility methods namespace containing helper functions

13

*/

14

Prism.util;

15

```

16

17

### DOM and Language Utilities

18

19

#### getLanguage

20

21

Extract language identifier from element's CSS classes.

22

23

```javascript { .api }

24

/**

25

* Extract language identifier from element's CSS classes

26

* @param {Element} element - DOM element to examine

27

* @returns {string} Language identifier or 'none' if not found

28

*/

29

Prism.util.getLanguage(element);

30

```

31

32

**Usage Examples:**

33

34

```javascript

35

// Extract language from various class patterns

36

const jsElement = document.querySelector('.language-javascript');

37

console.log(Prism.util.getLanguage(jsElement)); // 'javascript'

38

39

const pyElement = document.querySelector('.lang-python');

40

console.log(Prism.util.getLanguage(pyElement)); // 'python'

41

42

const noLangElement = document.querySelector('.no-language');

43

console.log(Prism.util.getLanguage(noLangElement)); // 'none'

44

45

// Works with multiple classes

46

const multiElement = document.createElement('code');

47

multiElement.className = 'line-numbers language-typescript highlight';

48

console.log(Prism.util.getLanguage(multiElement)); // 'typescript'

49

50

// Dynamic language detection

51

function highlightDynamicCode(element, fallbackLang = 'text') {

52

const detectedLang = Prism.util.getLanguage(element);

53

const language = detectedLang !== 'none' ? detectedLang : fallbackLang;

54

55

if (Prism.languages[language]) {

56

Prism.highlightElement(element);

57

} else {

58

console.warn(`Language '${language}' not available`);

59

}

60

}

61

```

62

63

#### setLanguage

64

65

Set language classes on DOM elements.

66

67

```javascript { .api }

68

/**

69

* Set language classes on DOM element

70

* @param {Element} element - DOM element to modify

71

* @param {string} language - Language identifier to set

72

*/

73

Prism.util.setLanguage(element, language);

74

```

75

76

**Usage Examples:**

77

78

```javascript

79

// Set language on code element

80

const codeElement = document.createElement('code');

81

Prism.util.setLanguage(codeElement, 'javascript');

82

console.log(codeElement.className); // 'language-javascript'

83

84

// Change language dynamically

85

const existingElement = document.querySelector('code.language-python');

86

Prism.util.setLanguage(existingElement, 'typescript');

87

console.log(existingElement.className); // 'language-typescript'

88

89

// Set language on parent and child

90

const preElement = document.createElement('pre');

91

const codeChild = document.createElement('code');

92

preElement.appendChild(codeChild);

93

94

Prism.util.setLanguage(preElement, 'css');

95

Prism.util.setLanguage(codeChild, 'css');

96

97

// Dynamic language switching

98

function switchLanguage(element, newLanguage) {

99

const oldLanguage = Prism.util.getLanguage(element);

100

console.log(`Switching from ${oldLanguage} to ${newLanguage}`);

101

102

Prism.util.setLanguage(element, newLanguage);

103

104

// Re-highlight with new language

105

if (Prism.languages[newLanguage]) {

106

Prism.highlightElement(element);

107

}

108

}

109

```

110

111

#### currentScript

112

113

Get reference to currently executing script element.

114

115

```javascript { .api }

116

/**

117

* Get reference to currently executing script element

118

* @returns {Element|null} Current script element or null

119

*/

120

Prism.util.currentScript();

121

```

122

123

**Usage Examples:**

124

125

```javascript

126

// Get current script for path resolution

127

const currentScript = Prism.util.currentScript();

128

if (currentScript) {

129

const scriptPath = currentScript.src;

130

const basePath = scriptPath.substring(0, scriptPath.lastIndexOf('/'));

131

console.log('Script base path:', basePath);

132

}

133

134

// Plugin initialization with script detection

135

(function() {

136

const script = Prism.util.currentScript();

137

const pluginConfig = {

138

scriptSrc: script ? script.src : 'unknown',

139

loadTime: Date.now()

140

};

141

142

Prism.plugins.myPlugin = pluginConfig;

143

})();

144

145

// Conditional loading based on script location

146

const script = Prism.util.currentScript();

147

if (script && script.hasAttribute('data-manual')) {

148

Prism.manual = true;

149

}

150

```

151

152

### Object Utilities

153

154

#### clone

155

156

Deep clone objects with circular reference handling.

157

158

```javascript { .api }

159

/**

160

* Deep clone object with circular reference handling

161

* @param {*} o - Object to clone

162

* @param {WeakMap} [visited] - Map of visited objects for circular reference detection

163

* @returns {*} Cloned object

164

*/

165

Prism.util.clone(o, visited);

166

```

167

168

**Usage Examples:**

169

170

```javascript

171

// Clone simple objects

172

const original = { a: 1, b: { c: 2 } };

173

const cloned = Prism.util.clone(original);

174

cloned.b.c = 3;

175

console.log(original.b.c); // 2 (unchanged)

176

console.log(cloned.b.c); // 3

177

178

// Clone language grammars

179

const baseGrammar = Prism.languages.javascript;

180

const customGrammar = Prism.util.clone(baseGrammar);

181

customGrammar.keyword = /\b(?:const|let|var|custom)\b/;

182

183

// Clone with circular references

184

const circular = { name: 'test' };

185

circular.self = circular;

186

const clonedCircular = Prism.util.clone(circular);

187

console.log(clonedCircular.self === clonedCircular); // true

188

189

// Clone arrays and complex structures

190

const complexObject = {

191

array: [1, 2, { nested: true }],

192

func: function() { return 'test'; },

193

regex: /pattern/gi,

194

date: new Date()

195

};

196

const clonedComplex = Prism.util.clone(complexObject);

197

198

// Safe grammar extension

199

function extendGrammar(baseId, extensions) {

200

const base = Prism.languages[baseId];

201

if (!base) {

202

throw new Error(`Base language '${baseId}' not found`);

203

}

204

205

const extended = Prism.util.clone(base);

206

Object.assign(extended, extensions);

207

return extended;

208

}

209

```

210

211

#### type

212

213

Get detailed type information for objects.

214

215

```javascript { .api }

216

/**

217

* Get detailed type information for any value

218

* @param {*} o - Value to examine

219

* @returns {string} Type string (Object, Array, String, etc.)

220

*/

221

Prism.util.type(o);

222

```

223

224

**Usage Examples:**

225

226

```javascript

227

// Type detection for various values

228

console.log(Prism.util.type({})); // 'Object'

229

console.log(Prism.util.type([])); // 'Array'

230

console.log(Prism.util.type('string')); // 'String'

231

console.log(Prism.util.type(42)); // 'Number'

232

console.log(Prism.util.type(true)); // 'Boolean'

233

console.log(Prism.util.type(/regex/)); // 'RegExp'

234

console.log(Prism.util.type(null)); // 'Null'

235

console.log(Prism.util.type(undefined)); // 'Undefined'

236

237

// Type-based processing

238

function processGrammarRule(rule) {

239

const ruleType = Prism.util.type(rule);

240

241

switch (ruleType) {

242

case 'RegExp':

243

return { pattern: rule };

244

case 'Object':

245

return rule;

246

case 'Array':

247

return rule.map(processGrammarRule);

248

default:

249

console.warn('Unexpected rule type:', ruleType);

250

return rule;

251

}

252

}

253

254

// Safe property access based on type

255

function safeAccess(obj, property, expectedType) {

256

if (Prism.util.type(obj) === 'Object' && property in obj) {

257

const value = obj[property];

258

return Prism.util.type(value) === expectedType ? value : null;

259

}

260

return null;

261

}

262

```

263

264

#### objId

265

266

Generate unique identifiers for objects (circular reference handling).

267

268

```javascript { .api }

269

/**

270

* Get or generate unique identifier for object

271

* @param {Object} obj - Object to get ID for

272

* @returns {string} Unique object identifier

273

*/

274

Prism.util.objId(obj);

275

```

276

277

**Usage Examples:**

278

279

```javascript

280

// Generate unique IDs for objects

281

const obj1 = { name: 'first' };

282

const obj2 = { name: 'second' };

283

284

console.log(Prism.util.objId(obj1)); // 'O_1' (or similar)

285

console.log(Prism.util.objId(obj2)); // 'O_2' (or similar)

286

console.log(Prism.util.objId(obj1)); // Same as first call

287

288

// Track object references

289

const objectTracker = new Map();

290

291

function trackObject(obj, metadata) {

292

const id = Prism.util.objId(obj);

293

objectTracker.set(id, { object: obj, metadata, accessed: Date.now() });

294

return id;

295

}

296

297

// Use in grammar processing

298

function processGrammarWithTracking(grammar) {

299

const grammarId = Prism.util.objId(grammar);

300

console.log(`Processing grammar ${grammarId}`);

301

302

// Process grammar rules...

303

return grammarId;

304

}

305

```

306

307

### Token and Content Utilities

308

309

#### encode

310

311

HTML encode tokens and content for safe output.

312

313

```javascript { .api }

314

/**

315

* HTML encode tokens and content for safe output

316

* @param {*} tokens - Tokens, strings, or mixed content to encode

317

* @returns {*} Encoded content with same structure

318

*/

319

Prism.util.encode(tokens);

320

```

321

322

**Usage Examples:**

323

324

```javascript

325

// Encode simple strings

326

const htmlString = '<script>alert("XSS")</script>';

327

const encoded = Prism.util.encode(htmlString);

328

console.log(encoded); // '&lt;script&gt;alert("XSS")&lt;/script&gt;'

329

330

// Encode token content

331

const token = new Prism.Token('string', '"<html>"');

332

const encodedToken = Prism.util.encode(token);

333

console.log(encodedToken.content); // '"&lt;html&gt;"'

334

335

// Encode token arrays

336

const tokens = [

337

'const html = ',

338

new Prism.Token('string', '"<div>content</div>"'),

339

';'

340

];

341

const encodedTokens = Prism.util.encode(tokens);

342

343

// Recursive encoding of nested structures

344

const nestedToken = new Prism.Token('tag', [

345

'<',

346

new Prism.Token('tag-name', 'script'),

347

'>'

348

]);

349

const encodedNested = Prism.util.encode(nestedToken);

350

351

// Safe content processing

352

function safeHighlight(code, grammar, language) {

353

const tokens = Prism.tokenize(code, grammar);

354

const encodedTokens = Prism.util.encode(tokens);

355

return Prism.Token.stringify(encodedTokens, language);

356

}

357

```

358

359

#### isActive

360

361

Check element state based on CSS classes and configuration.

362

363

```javascript { .api }

364

/**

365

* Check if element has active state based on classes and configuration

366

* @param {Element} element - Element to check

367

* @param {string} className - CSS class name to look for

368

* @param {boolean} [defaultActivation=false] - Default state if class not found

369

* @returns {boolean} Whether element is active for the given class

370

*/

371

Prism.util.isActive(element, className, defaultActivation);

372

```

373

374

**Usage Examples:**

375

376

```javascript

377

// Check plugin activation

378

const codeElement = document.querySelector('code.language-js');

379

380

// Check if line numbers should be shown

381

const hasLineNumbers = Prism.util.isActive(codeElement, 'line-numbers', false);

382

if (hasLineNumbers) {

383

console.log('Line numbers enabled');

384

}

385

386

// Check with default activation

387

const shouldShowToolbar = Prism.util.isActive(codeElement, 'toolbar', true);

388

389

// Plugin conditional activation

390

function conditionalPluginInit(element, pluginClass, pluginHandler) {

391

if (Prism.util.isActive(element, pluginClass)) {

392

pluginHandler(element);

393

}

394

}

395

396

// Usage in plugin development

397

Prism.hooks.add('complete', function(env) {

398

conditionalPluginInit(env.element, 'show-language', function(el) {

399

const language = Prism.util.getLanguage(el);

400

const label = document.createElement('span');

401

label.textContent = language.toUpperCase();

402

label.className = 'language-label';

403

el.parentNode.insertBefore(label, el);

404

});

405

});

406

```

407

408

## Advanced Utility Patterns

409

410

### Utility Combinations

411

412

```javascript

413

// Combine utilities for complex operations

414

function smartLanguageDetection(element) {

415

const detectedLang = Prism.util.getLanguage(element);

416

417

if (detectedLang === 'none') {

418

// Try to detect from content or context

419

const content = element.textContent;

420

if (content.includes('function') && content.includes('{')) {

421

Prism.util.setLanguage(element, 'javascript');

422

return 'javascript';

423

}

424

}

425

426

return detectedLang;

427

}

428

429

// Safe grammar operations

430

function safeGrammarOperation(grammarId, operation) {

431

const grammar = Prism.languages[grammarId];

432

if (!grammar) {

433

console.error(`Grammar '${grammarId}' not found`);

434

return null;

435

}

436

437

const grammarType = Prism.util.type(grammar);

438

if (grammarType !== 'Object') {

439

console.error(`Invalid grammar type: ${grammarType}`);

440

return null;

441

}

442

443

try {

444

const cloned = Prism.util.clone(grammar);

445

return operation(cloned);

446

} catch (error) {

447

console.error('Grammar operation failed:', error);

448

return null;

449

}

450

}

451

```

452

453

### Performance Utilities

454

455

```javascript

456

// Efficient type checking

457

const typeCache = new Map();

458

459

function cachedType(obj) {

460

const id = Prism.util.objId(obj);

461

if (typeCache.has(id)) {

462

return typeCache.get(id);

463

}

464

465

const type = Prism.util.type(obj);

466

typeCache.set(id, type);

467

return type;

468

}

469

470

// Batch language operations

471

function batchSetLanguage(elements, language) {

472

elements.forEach(element => {

473

Prism.util.setLanguage(element, language);

474

});

475

}

476

477

// Memory-conscious cloning

478

function shallowCloneIfNeeded(obj, deep = false) {

479

const objType = Prism.util.type(obj);

480

481

if (objType === 'Object' || objType === 'Array') {

482

return deep ? Prism.util.clone(obj) : Object.assign({}, obj);

483

}

484

485

return obj; // Primitives don't need cloning

486

}

487

```

488

489

### Error Handling Utilities

490

491

```javascript

492

// Safe utility calls with fallbacks

493

function safeGetLanguage(element, fallback = 'text') {

494

try {

495

const language = Prism.util.getLanguage(element);

496

return language !== 'none' ? language : fallback;

497

} catch (error) {

498

console.warn('Language detection failed:', error);

499

return fallback;

500

}

501

}

502

503

function safeClone(obj, fallback = null) {

504

try {

505

return Prism.util.clone(obj);

506

} catch (error) {

507

console.error('Cloning failed:', error);

508

return fallback;

509

}

510

}

511

512

// Validation utilities

513

function validateElement(element, requiredClasses = []) {

514

if (!element || Prism.util.type(element) !== 'Object') {

515

return false;

516

}

517

518

return requiredClasses.every(className =>

519

Prism.util.isActive(element, className)

520

);

521

}

522

```