CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-prism-react-renderer

Renders highlighted Prism output using React with render props pattern for syntax highlighting

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

utilities.mddocs/

Utilities

Utility functions and the bundled Prism instance for advanced usage, custom implementations, and direct access to tokenization functionality.

Capabilities

Bundled Prism Instance

Pre-configured Prism.js instance with common programming languages bundled for optimal performance and no global namespace pollution.

/**
 * Pre-configured Prism.js instance with bundled language definitions
 * Includes common programming languages without polluting global namespace
 */
declare const Prism: PrismLib;

interface PrismLib {
  /** Object containing grammar definitions for supported languages */
  languages: Record<string, PrismGrammar>;
  /** Tokenize text using a specific grammar */
  tokenize(text: string, grammar: PrismGrammar): (string | PrismToken)[];
  /** Hook system for extending Prism functionality */
  hooks: {
    /** Run hooks for specific events */
    run(name: string, env: EnvConfig): void;
  };
}

type PrismGrammar = import("prismjs").Grammar;

Supported Languages:

  • Web: markup (HTML), jsx, tsx, javascript (via js-extras)
  • Systems: rust, go, cpp, swift, kotlin, objectivec
  • Functional: reason
  • Scripting: python
  • Data: json, yaml, graphql
  • Documentation: markdown

Usage Examples:

import { Prism } from "prism-react-renderer";

// Check if a language is supported
function isLanguageSupported(language: string): boolean {
  return language.toLowerCase() in Prism.languages;
}

// Get available languages
const availableLanguages = Object.keys(Prism.languages);
console.log("Supported languages:", availableLanguages);

// Direct tokenization
const code = "const greeting = 'Hello, World!';";
const grammar = Prism.languages.javascript;
const tokens = Prism.tokenize(code, grammar);

// Use with custom hook implementations
function useCustomTokenizer(code: string, language: string) {
  const grammar = Prism.languages[language.toLowerCase()];
  
  if (!grammar) {
    console.warn(`Grammar not found for language: ${language}`);
    return [code]; // Return as plain text
  }
  
  return Prism.tokenize(code, grammar);
}

// Language fallback handling
function getGrammarWithFallback(language: string): PrismGrammar | null {
  const normalizedLang = language.toLowerCase();
  
  // Direct match
  if (Prism.languages[normalizedLang]) {
    return Prism.languages[normalizedLang];
  }
  
  // Common aliases
  const aliases: Record<string, string> = {
    'js': 'javascript',
    'ts': 'typescript',  
    'py': 'python',
    'md': 'markdown',
    'yml': 'yaml'
  };
  
  const aliasTarget = aliases[normalizedLang];
  if (aliasTarget && Prism.languages[aliasTarget]) {
    return Prism.languages[aliasTarget];
  }
  
  return null;
}

normalizeTokens Function

Utility function that converts Prism's raw token output into a normalized 2D array structure organized by lines.

/**
 * Converts Prism tokens into normalized Token structure grouped by lines
 * Handles nested tokens, newlines, and empty lines consistently
 * @param tokens - Raw tokens from Prism.tokenize()
 * @returns 2D array of normalized tokens organized by lines
 */
declare function normalizeTokens(tokens: (PrismToken | string)[]): Token[][];

interface Token {
  /** Array of token type classifications */
  types: string[];
  /** Token content/text */
  content: string;
  /** Whether this token represents an empty line */
  empty?: boolean;
}

Usage Examples:

import { normalizeTokens, Prism } from "prism-react-renderer";

// Basic normalization
const code = `function greet(name) {
  console.log('Hello, ' + name);
}`;

const grammar = Prism.languages.javascript;
const rawTokens = Prism.tokenize(code, grammar);
const normalizedTokens = normalizeTokens(rawTokens);

console.log(normalizedTokens);
// [
//   [{ types: ['keyword'], content: 'function' }, { types: ['plain'], content: ' ' }, ...],
//   [{ types: ['plain'], content: '  ' }, { types: ['builtin'], content: 'console' }, ...],
//   [{ types: ['punctuation'], content: '}' }]
// ]

// Handle empty lines
const codeWithEmptyLines = `const a = 1;

const b = 2;`;

const tokensWithEmpty = normalizeTokens(Prism.tokenize(codeWithEmptyLines, grammar));
// Second array will contain: [{ types: ['plain'], content: '\n', empty: true }]

// Custom rendering with normalized tokens
function renderTokens(tokens: Token[][]) {
  return tokens.map((line, lineIndex) => (
    <div key={lineIndex} className="code-line">
      {line.map((token, tokenIndex) => (
        <span
          key={tokenIndex}
          className={token.types.join(' ')}
          data-empty={token.empty || undefined}
        >
          {token.content}
        </span>
      ))}
    </div>
  ));
}

Advanced Usage Patterns

Custom Language Support

For languages not included in the bundle, you can extend Prism:

import { Prism } from "prism-react-renderer";

// Note: This requires additional Prism language definitions
// You would need to import and register the language manually

// Example of how to check and handle unsupported languages
function highlightWithFallback(code: string, language: string) {
  const grammar = Prism.languages[language.toLowerCase()];
  
  if (!grammar) {
    // Fallback to plain text
    return normalizeTokens([code]);
  }
  
  const tokens = Prism.tokenize(code, grammar);
  return normalizeTokens(tokens);
}

Performance Optimization

import { useTokenize, Prism } from "prism-react-renderer";
import { useMemo } from "react";

function OptimizedHighlighter({ code, language }) {
  // Grammar lookup is memoized
  const grammar = useMemo(() => {
    return Prism.languages[language.toLowerCase()];
  }, [language]);
  
  // useTokenize already includes memoization
  const tokens = useTokenize({
    prism: Prism,
    code,
    language,
    grammar
  });
  
  return (
    <div>
      {tokens.map((line, i) => (
        <div key={i}>
          {line.map((token, j) => (
            <span key={j} className={token.types.join(' ')}>
              {token.content}
            </span>
          ))}
        </div>
      ))}
    </div>
  );
}

Supporting Types

type Language = string;
type PrismGrammar = import("prismjs").Grammar;
type PrismLib = typeof import("prismjs");

Install with Tessl CLI

npx tessl i tessl/npm-prism-react-renderer

docs

component-hooks.md

index.md

themes.md

utilities.md

tile.json