Spec Markdown

repository·main·Indexed 19 days ago

https://github.com/leebyron/spec-md

A tool for rendering Markdown into HTML specifically formatted for technical specification documents. Version 3.1.0 provides a CLI and Node.js module that adds support for algorithms, grammar productions, edit annotations via CriticMarkup, and specialized section numbering. It includes features for code syntax highlighting, definition lists, and automatic conversion of smart characters for math and arrows.

Tokens
7.5K
Snippets
40
Records
44
Agent score
64%

What's inside spec-md

  1. What is Spec Markdown?

    main

    Spec Markdown is a tool that renders Markdown with specific additions into an HTML format optimized for technical specification documents.

    Key features include:

    • Code syntax highlighting
    • Edit annotations
    • Definitions for algorithms and grammar productions

    Philosophy: Spec Markdown follows the standard Markdown philosophy of being easy to read and write. It aims for interoperability by using conventions rather than heavy new syntax, meaning documents written for Spec Markdown should still render adequately in standard Markdown renderers. However, some standard Markdown features may be limited or removed to support these specialized rendering additions.

  2. Define grammar productions in Spec Markdown

    main

    Spec Markdown allows you to define context-free grammatical productions using non-terminal rules and terminal characters.

    • Non-terminals: Must follow the regular expression {/[A-Z][_a-zA-Z]*/} (start with an uppercase letter, followed by letters or underscores).
    • Production Syntax: Use the : token to indicate a production. A single definition can follow the colon, or multiple options can be provided as a Markdown list.
    • Production Types: You can distinguish between different types of productions (e.g., lexical vs syntactical) by varying the number of colons used (:, ::, or :::).
    • Terminals: Characters or sequences that do not have further definitions. Use back-ticks (`) to quote terminals to avoid ambiguity with special characters like /, \, ], or }.
    PBJ : Bread PeanutButter Jelly Bread
    
    PBJ : 
      - Bread PeanutButter Jelly Bread
      - Bread Jelly PeanutButter Bread
    
    TypeOne : `type` `one`
    TypeTwo :: `type` `two`
    TypeThree ::: `type` `three`
  3. Apply quantifiers to tokens and non-terminals

    main

    Quantifiers provide shorthand for optionality and repetition:

    • Token? (Optional): Shorthand for a definition that either includes the token or excludes it.
    • Token+ (One or more): Shorthand for a list of one or more tokens. By default, this expands to a recursive _list production (e.g., Page+ becomes Page_list).
    • Token* (Zero or more): Shorthand for an optional list (zero or more tokens).

    Important: When applying quantifiers to terminals that include special characters (like |), always wrap the terminal in back-ticks to prevent the quantifier from being interpreted as part of the terminal itself.

    Sentence : Noun Verb Adverb?
    Book : Cover Page+ Cover
    Sandwich : Bread Topping* Bread
    
    # Correct way to quantify a terminal symbol
    UnionMembers :
      - UnionMembers | NamedType
      - `|`? NamedType
  4. Use Smart Characters (Quotes, Dashes, Math, and Arrows)

    main

    The renderer automatically converts plain-text characters into typographic entities (except within code blocks):

    • Quotes: Standard quotes are converted to "smart quotes".
    • Dashes: Hyphens, en-dashes, and em-dashes are automatically formatted.
    • Math: >= becomes , <= becomes , and ~= becomes .
    • Arrows:
      • -> becomes
      • <- becomes
      • <-> becomes
      • => becomes
      • <== becomes
      • <=> becomes

    To prevent these conversions, escape the characters (e.g., \>=).

  5. Use conditional parameters in grammar productions

    main

    Conditional parameters allow you to define variants of a non-terminal using bracket syntax Token[Param]. This is shorthand for creating multiple related non-terminals (e.g., Example and Example_WithCondition).

    Defining Conditions

    Inside a production definition, use these prefixes to control which variant is included:

    • [if Param] or [+Param]: Include only if the parameter is present.
    • [if not Param] or [~Param]: Include only if the parameter is absent.

    Using Parameters in Rules

    When referencing a non-terminal within a rule, you can control its conditional behavior:

    • Token[Param]: Uses the variant with the parameter.
    • Token[?Param]: Uses the variant only if the parameter is present in the derived production.
    • Token[!Param]: Uses the variant only if the parameter is absent in the derived production.

    Multiple parameters (e.g., [P, Q]) result in a permutation of all possible condition combinations.

    Example[WithCondition] :
      - A
      - [if WithCondition] B
      - [if not WithCondition] C
      - [+WithCondition] D
      - [~WithCondition] E
    
    # Multiple parameters
    Example[P, Q] :
      - [if P] `p`
      - [if Q] `q`
      - Example[!P, ?Q]
  6. Structure a Spec Markdown document with Title, Intro, and Sections

    main

    A Spec Markdown document follows a specific structural hierarchy to enable automatic Table of Contents generation and section numbering:

    1. Title: The document must start with a top-level header (# Title). You may use Setext-style headers (underlined with ===) for the title for backwards compatibility.
    2. Introduction: Any content following the title header but preceding the first section header is treated as the document's introduction.
    3. Sections: Sections are defined using atx-style headers (e.g., #, ##, ###).
      • Spec Markdown only supports atx-style headers for sections. Do not use Setext-style headers for sections.
      • A section ends when a header of similar or greater precedence (e.g., a # header ending a ## section) is encountered.
      • Sections can contain nested sections of lower precedence.
    4. Subsections: These are created using bold text (e.g., **Subsection Title**). Unlike sections, subsections are not numbered and do not appear in the Table of Contents. Subsections cannot contain sections or other subsections.
    # Document Title
    
    This is the introduction.
    
    # First Section
    
    Content of the first section.
    
    ## Subsection
    
    **This is a subsection**
    
    Subsection content.
  7. Define terms using Definition Lists and Paragraphs

    main

    Spec Markdown provides two ways to define technical terms:

    Definition List

    Write the term on one line, followed by one or more definition lines starting with : .

    Definition Paragraph

    Start a line with :: followed by an italicized term. This is useful for defining terms within a sentence.

    Referencing Defined Terms

    Once a term is defined, you can reference it anywhere else in the document by italicizing the term. References are case-insensitive.

    Cookie
    :   A small piece of data.
    :   A delicious snack.
    
    :: The study of *Philosophy* is deep.
    
    After studying *philosophy*, you may eat a *cookie*.
  8. Define grammar semantics using algorithm steps

    main

    You can define the semantics of a grammar by following a grammar definition with a list of algorithm steps. Spec Markdown interprets a single grammar definition followed by a list as a grammar semantic. Within these steps, you can use value literals (wrapped in { }) to reference grammar tokens, which allows the renderer to link the semantic steps to the defined grammar components.

    PBJ : Bread PeanutButter Jelly Bread
    
    * Let {bottomBread} be the result of placing the first {Bread} on the plate.
    * Let {pbSpread} be the result of getting {PeanutButter} from the jar.
    * Spread {pbSpread} onto {bottomBread}.
    * Let {topBread} be the result of placing the last {Bread} on the plate.
    * Let {jamSpread} be the result of getting {Jelly} from the jar.
    * Spread {jamSpread} onto {topBread}.
    * Let {sandwich} be the result of rotating {topBread} 180&deg; and placing on {bottomBread}.
    * Return {sandwich}.
  9. Use spec-md as a CLI tool

    main

    If installed globally, you can use spec-md directly from your shell. The executable accepts a filepath to a Markdown document as input and outputs the resulting HTML to stdout. To save the output to a file, use the > redirection operator.

    npm install -g spec-md
    spec-md ./path/to/markdown.md > ./path/to/output.html
  10. Create code blocks

    main

    You can create a block of code using two methods:

    1. Indent the block by 4 spaces.
    2. Wrap the code with triple backticks (```) on their own lines.

    Additionally, you can use the HTML <pre> tag to produce a simple code block.

    const code = sample();

    
    <pre>
    Line 1
    Line 2
    </pre>
  11. Assign custom section numbers

    main

    Spec Markdown automatically numbers sections (e.g., 1, 1.1, 1.1.1). To reference an existing specification or override the automatic numbering, you can write the desired section number directly after the # and before the header text.

    The renderer will use the last number provided in the string as the official section number.

    #### 3.2.3.8. Custom Numbers