Skip to content

weavepage/remark-substitute

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

5 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

remark-substitute

A remark plugin for inline substitution syntax using :sub[INITIAL]{REPLACEMENT}.

Why?

Inline substitution allows progressive disclosure of content — show a brief version initially, then reveal the full content on activation.

Install

npm install remark-substitute

Usage

import { unified } from 'unified'
import remarkParse from 'remark-parse'
import remarkSubstitute from 'remark-substitute'
import remarkStringify from 'remark-stringify'

const result = await unified()
  .use(remarkParse)
  .use(remarkSubstitute)
  .use(remarkStringify)
  .process('The :sub[TL;DR]{full explanation here} summarizes the point.')

Syntax

:sub[INITIAL]{REPLACEMENT}
  • INITIAL: Text shown initially
  • REPLACEMENT: Text shown after activation (one-way toggle)

Both sections support inline Markdown:

:sub[**bold**]{_italic_ and `code`}

Nested :sub is allowed in REPLACEMENT:

:sub[outer]{:sub[inner]{deep}}

Escaping

In INITIAL:

  • \] → literal ] (doesn't close)
  • \[ → literal [ (no depth change)
  • \\ → literal \

In REPLACEMENT:

  • \} → literal } (doesn't close)
  • \{ → literal { (no depth change)
  • \\ → literal \

Bracket & Brace Balancing

Unescaped brackets/braces are balanced:

:sub[f(x) = [a, b]]{expanded}   <!-- INITIAL = "f(x) = [a, b]" -->
:sub[x]{{a, b}}                 <!-- REPLACEMENT = "{a, b}" -->

Boundary Rules

  • :sub[ must NOT be preceded by a word character (a-z, A-Z, 0-9, _)
  • Cannot span multiple lines
foo:sub[x]{y}     <!-- Does NOT parse -->
test(:sub[x]{y})  <!-- Parses -->
test :sub[x]{y}   <!-- Parses -->

Packages

This monorepo contains:

Package Purpose
micromark-extension-substitute Tokenizer
mdast-util-substitute AST utilities
remark-substitute Remark plugin

For direct micromark or mdast integration, see the individual package READMEs.

AST Node

interface Sub extends Parent {
  type: 'sub'
  children: PhrasingContent[]      // Parsed INITIAL
  data: {
    replacement: PhrasingContent[] // Parsed REPLACEMENT
  }
}

With remark-directive

If using both plugins, the one registered last wins for :sub[...] syntax:

// Sub wins:
unified()
  .use(remarkDirective)
  .use(remarkSubstitute)  // registered last

// Directive wins:
unified()
  .use(remarkSubstitute)
  .use(remarkDirective)  // registered last

License

MIT

About

Inline substitution syntax for Markdown

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published