Spec Markdown
Renders Markdown with some additions into an HTML format commonly used for writing technical specification documents. Markdown additions include code syntax highlighting, edit annotations, and the definition of algorithms and grammar productions.
Philosophy
Spec Markdown is first and foremost Markdown. As such, it follows Markdown’s philosophy of intending to be as easy to read and easy to write as is feasible.
In order to interoperate with other tools which use Markdown, Spec Markdown tries to add as little additional syntax as possible, instead preferring conventions. This means any documents written with Spec Markdown in mind should render adequately by other Markdown renderers.
To support the rendering additions of Spec Markdown, some features of Markdown may be limited or removed. As an example, Spec Markdown is strict about the order and locations of headers in a document.
1Getting Started
To use Spec Markdown, just write Markdown files. There are some conventions used by Spec Markdown which you can read about in Spec additions.
To convert your Markdown files into an HTML spec document, use the spec-md
utility.
npm install -g spec-md
spec-md ./path/to/markdown.md > ./path/to/output.html
You can also require spec-md
as a node module.
npm install --save-dev spec-md
const fs = require('fs');
const specMarkdown = require('spec-md');
specMarkdown.html('./path/to/markdown.md').then(html => {
fs.writeFile('./path/to/output.html', html);
});
Spec Markdown also provides utilities for generating and operating on an intermediate representation of the markdown, which you can explore in Using Spec Markdown.
2JTF-LD Format specification
JTF-LD is a linked data-compatible JSON-based format for storing and processing textual cuneiform tablet data and metadata about cuneiform artifacts. This specification document describes the structure and usage of the JTF format and its relations to other formats describing cuneiform tablet contents.
2.1Introduction
JTF-LD is a format for encoding various features on cuneiform artifacts and linking elements found on said cuneiform tablets to existing data in the linked open data cloud. In doing so, JTF-LD defines a vocabulary for describing elements of a cuneiform tablet and can act as an exchange format between different databases providing cuneiform artifact data. This specification builds on work by Ilya Khait, who defined the format JTF as an alternative format to the format ATF, which is commonly used to describe transliterations of cuneiform tablets.
2.1.1Requirements Language
The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “NOT RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in [RFC2119]
2.1.2Conventions Used in This Document
The ordering of the members of any JSON object defined in this document MUST be considered irrelevant, as specified by [RFC7159].
Some examples use the combination of a JavaScript single-line comment (//) followed by an ellipsis (...) as placeholder notation for content deemed irrelevant by the authors. These placeholders must of course be deleted or otherwise replaced before attempting to validate the corresponding JSON code example.
Whitespace is used in the examples inside this document to help illustrate the data structures, but it is not required. Unquoted whitespace is not significant in JSON.
2.1.3Definitions
- JavaScript Object Notation (JSON), and the terms object, member, name, value, array, number, true, false, and null, are to be interpreted as defined in [RFC7159].
2.2Format structure
This section describes the structure of a JTF-LD document. JTF-LD is a hierarchical representation of the contents of a cuneiform artifact. The contents JTF-LD can describe are introduced in the following sections.
2.2.1Medium
JTF includes predefined classifications of cuneiform artefact types. This section introduces the keywords used in JTF to describe the different types of cuneiform artifacts. These types are consistent with types used in major cuneiform artifact repositories such as the Cuneiform Digital Library Initiative (CDLI) and ORACC
2.2.1.1Cuneiform artifact types
- Tablet
- An artifact in the shape of a tablet with one or many impressions
- Envelope
- An artifact in the shape of an envelope that may encompass another cuneiform artifact, e.g., a tablet
2.2.2Layout
A cuneiform tablet may include
- A set of surfaces (typically obverse, reverse, left, right, top, bottom)
- A set of cuneiform sign inscriptions on each of the aforementioned surfaces
2.2.2.1Surfaces
Surfaces of cuneiform artifacts commonly contain textual information, seal impressions, or other areas of interest that may need further detailed examination and description by scholars. This specification assumes that an agreement to classify surfaces on the cuneiform artifact has been reached before encoding in JTF-LD is attempted. In particular, this involves researchers’ agreement concerning the orientation of the cuneiform tablet and, hence, the identification of its different surfaces. Therefore, the following definitions of surfaces are the results of scholarly work and may be applied to areas on the cuneiform tablet:
Top : One or many surfaces located at the top of a cuneiform artifact as defined by one or many scholars interpreting the contents of the artifact
Bottom : One or many surfaces located at the bottom of a cuneiform artifact as defined by one or many scholars interpreting the contents of the artifact
Left : One or many surfaces located on the left side of a cuneiform artifact as defined by one or many scholars interpreting the contents of the artifact
Right : One or many surfaces located on the right side of a cuneiform artifact as defined by one or many scholars interpreting the contents of the artifact
Obverse : One or many surfaces located on the obverse or front side of a cuneiform artifact as defined by one or many scholars interpreting the contents of the artifact
Reverse : One or many surfaces located on the obverse or back side of a cuneiform artifact as defined by one or many scholars interpreting the contents of the artifact
2.3Metadata
Metadata associated with cuneiform artifacts may include:
Width : Width of the cuneiform artifact
Height : Height of the cuneiform artifact
Depth : Depth of the cuneiform artifact
2.4Text Content
JTF-LD is able to express textual contents present on surfaces of cuneiform tablets. A text content always belongs to a To express textual contents, the following definitions apply:
Line : A line in a text block on a surface of a cuneiform tablet A line usually occurs within a given surface. Hence, a surface may contain an arbitrary amount of lines. Lines are ordered by their occurrence on the surface, usually from top to bottom.
Word : A word consists of a list of characters which have been identified as a semantic entity A line consists of several words in the order of their writing, usually from left to right.
Character : A character forms the basic means of writing cuneiform texts
CharacterPaleography : The paleographic description of a cuneiform character used on a cuneiform artifact
2.5Annotations
2.6JTF as linked data: JTF-LD
3Spec Additions
Spec Markdown makes some additions to Markdown to support cases relevant to writing technical specs and documentation. It attempts to be as minimally invasive as possible, leveraging existing Markdown formatting features whenever possible so Spec Markdown documents may render adequately as regular Markdown.
Spec Markdown also makes restrictions to the overall format of the Markdown document in order to derive a structure to the entire document.
3.1Link Anything
Everything unique in a Spec Markdown file has a link created for it. Sections each have a link, as do named Algorithms and Grammar. You’ll find that Notes and Examples are also given stable links based on their contents, just in case things move around.
However, you can also link anything in a Spec Markdown file. Just highlight any bit of text and a link will be created just for that selection, making referencing specific parts of your document easy. Try it here!
3.2Title and Introduction
A Spec Markdown document must start with a header which will be used as the title of the document. Any content between this and the next header will become the introduction to the document.
A Spec Markdown document starts in this form:
# Spec Markdown
Introductory paragraph.
# First Section Header
3.3Sections
A Spec Markdown document is separated into a sequence and hierarchy of sections. Those sections can then be used as navigation points and can be used to create a table of contents. A section is started by a header and ends at either the next header of similar or greater precedence or the end of the document. A section can contain other sections if their headers are of lower precedence.
3.3.1Section Headers
Regular Markdown supports two styles of headers, Setext and atx, however Spec Markdown only supports atx style headers as section headers.
# Header
Only use Setext style headers for the title of the document.
Counter Example № 1Header
------
3.3.2Subsection Headers
While sections are numbered and appear in the table of contents, a subsection is similar but not numbered or in the table of contents.
This is a subsection
The subsection’s content appears below the subsection header.
Another subsection
Sections may contain multiple subsections, but subsections cannot contain sections or subsections.
3.3.3Table of Contents
A table of contents is automatically generated from the hierarchy of sections in the Spec Markdown document.
3.3.4Section Numbers
A number is associated with each section, starting with 1. In a hierarchy of sections, the parent sections are joined with dots. This provides an unambiguous location identifier for a given section in a document.
You can specify these section numbers directly in your Markdown documents if you wish by writing them directly after the #
and before the text of the header.
3.3.4.8Custom Numbers
If the section number is written in the document, the last number will be used as the number for that section. This is useful when writing a proposal against an existing spec and wish to reference a particular section.
The header for this section was written as
#### 3.2.3.8. Custom Numbers
3.3.4.9Appendix / Annex Sections
If a top level section is written with a letter, such as A
instead of a number, that will begin an Appendix section.
# A. Appendix: Grammar
3.4Smart Characters
The Spec Markdown renderer will replace easy to type characters like quotes and dashes with their appropriate typographic entities. These replacements will not occur within blocks of code.
3.4.1Quotes and Dashes
Prose text has “smart quotes”, hyphens, en-dashes and em-dashes—you shouldn’t have to think about it, they’ll just work.
For example, a quote of a quote (with an inner apostrophe and emphasis for flair):
"She told me that 'he isn't here right *now*' - so I left."
Will render as:
“She told me that ‘he isn’t here right now’ – so I left.”
Escaped \"quotes \'and single\-quotes\'\"
becomes: \“quotes \‘and single-quotes'".
3.4.2Math
Math operators like ≥, ≤, and ≈ can be written as >=
, <=
, and ~=
.
Escaped \>= \<= \~=
becomes: >= <= ~=.
3.4.3Arrows
Smart arrows → and ← and ↔ can be written as ->
, <-
and <->
.
Fat smart arrows ⇒ and ⇐ and ⇔ can be written as =>
, <==
and <=>
.
Escaped \-> \<- \<-> \=> \<== \<=>
becomes: -> <- <-> => <== <=>.
3.5Tables
Similar to Github flavored Markdown
| This | is a | table |
| ---- | ---: | :---: |
| key | val | etc |
Produces the following:
This | is a | table |
---|---|---|
key | val | etc |
Table cells can contain any content that a paragraph can contain.
3.6Definitions
Spec Markdown provides two forms for defining terms, definition lists and definition paragraphs.
3.6.1Definition List
A definition list is written as a defined term on a single line followed by one or more definition lines, each starting with a :
.
Cookie
: A small piece of data that a server sends to the user's web browser. The
browser may store it and send it back with later requests to the same server.
: A delicious snack, often containing chocolate chips.
Produces the following:
- Cookie
- A small piece of data that a server sends to the user’s web browser. The browser may store it and send it back with later requests to the same server.
- A delicious snack, often containing chocolate chips.
3.6.2Definition Paragraph
A definition paragraph starts with a ::
and contains an italicized term. This is useful when it is easier to define a term in a sentence containing that term.
:: The study of *Philosophy* investigates general and fundamental questions.
Produces the following:
The study of Philosophy investigates general and fundamental questions.
3.6.3Definition References
A defined term can be later referenced by italicizing that term. Referenced terms are case insensitive.
After studying *philosophy*, you may eat a *cookie*.
Produces the following:
After studying philosophy, you may eat a cookie.
3.7Note
Notes can be written inline with a spec document, and are often helpful to supply non-normative explanatory text or caveats in a differently formatted style. Case insensitive, the :
is optional.
Notes automatically have short links generated for them. If the contents of the note changes, so will the link URL. However if a note moves around, or content around the note changes the existing links will still point to the right place, very useful for consistently evolving specifications!
Note: Notes are awesome.
Produces the following:
3.8Todo
It’s often helpful to write a draft of a document and leave “to-do” comments in not-yet-completed sections. Case insensitive, the :
is optional.
TODO: finish this section
Produces the following:
3.9Syntax Highlighting
Spec Markdown will apply syntax highlighting to blocks of code if a github-flavored-markdown style language is supplied.
You may provide a highlight
function as an option to customize this behavior.
To render this highlighted javascript:
```js
const baz = foo("bar");
```
Produces the following:
const baz = foo("bar");
You may also prefix your highlight function with “raw” if you want to avoid other tools, such as Prettier, from interpreting a code block.
```raw js
const baz = foo("bar");
```
Produces the following:
const baz = foo("bar");
3.9.1Examples
Spec Markdown helps you write examples, visually indicaticating the difference from normative code blocks, and generating permalinks to those examples. Just write example
after the ```
.
```example
const great = useOf.example("code");
```
Produces the following:
Example № 2const great = useOf.example("code");
Examples can also be syntax highlighted, by placing the language directly before writing example
:
```js example
const great = useOf.example("code");
```
Produces the following:
Example № 3const great = useOf.example("code");
3.9.2Counter Examples
In addition to examples, Spec Markdown helps you write counter-examples, which are examples of things you should not do. These are visually indicated as different from normative code blocks and other examples. Just write counter-example
after the ```
(and optional language).
```js counter-example
const shit = dontSwear();
```
Produces the following:
Counter Example № 4const shit = dontSwear();
3.10Imports
When compiled, an import reference will be inlined into the same document. An import reference looks like a link to a “.md” file as a single paragraph.
[AnythingGoesHere](SomeName.md)
You can optionally prefix the import reference with #
characters to describe at what section level the import should apply. By default an import reference will be imported as a child of the current section.
3.11Inline editing
A portion of the CriticMarkup spec is supported.
For example, we can add or remove text with the {++add++}
or {--remove--}
syntax.
3.12Block editing
We can also add and remove entire blocks of content, by using {++
or {--
on their own line with empty lines on either side:
These paragraphs
have been added.
And
These paragraphs
have been removed.
By typing:
{++
These paragraphs
have been *added*.
++}
And
{--
These paragraphs
have been *removed*.
--}
3.13Algorithms
Specifications for procedures or algorithms can be defined in terms of nested markdown lists. These lists can be of any kind, but will always have ordered formatting. The bullet labeling for algorithms is specific will cycle between decimal, lower-alpha, and lower-roman.
An algorithm definition also describes its arguments in terms of variables.
Algorithm(arg) :
1. first
1. then
* substep
* deeper substep
* another deep substep
* another step
1. okay
Produces the following:
- first
- then
- substep
- deeper substep
- another deep substep
- another step
- substep
- okay
3.14Grammar
Spec Markdown makes it easier to describe context-free grammatical productions.
Grammars are defined by a sequence of terminal characters or sequence of characters, which are then referenced by non-terminal rules. The definition of a non-terminal is referred to as a production.
3.14.1Grammar Production
The :
token indicates an “is defined as” production for a non-terminal, where a single definition can be written directly after the :
.
PBJ : Bread PeanutButter Jelly Bread
Produces the following:
Or if PBJ has definition options, they are written immediately after as a Markdown list.
PBJ :
- Bread PeanutButter Jelly Bread
- Bread Jelly PeanutButter Bread
Produces the following:
Each definition is a space seperated list of terminal or non-terminal tokens, and may also include conditionals and constraints.
Definition lists aren’t required to be indented:
PBJ :
- Bread PeanutButter Jelly Bread
- Bread Jelly PeanutButter Bread
Produces the following:
3.14.2Production types
Often languages wish to specify different types of grammar productions, such as lexical or syntactical, or if certain characters line whitespace or newlines are permitted between symbols in the right-hand-side. Spec-md allows this this distinction based on the number of colons:
TypeOne : `type` `one`
TypeTwo :: `type` `two`
TypeThree ::: `type` `three`
Produces the following:
3.14.3One of
If each definition option is a single token, it can be expressed as a “one of” expression instead of a markdown list.
AssignmentOperator : one of *= `/=` %= += -= <<= >>= >>>= &= ^= |=
Produces the following:
*= | /= | %= | += | -= | <<= | >>= | >>>= | &= | ^= | |= |
“one of” can also be followed by a line break and multiple lines of tokens. To improve legibility in other tools, each line may optionally begin with a bullet.
Keyword : one of
- break do in typeof
- case else instanceof var
- catch export new void
- class extends return while
- const finally super with
- continue for switch yield
- debugger function this
- default if throw
- delete import try
Produces the following:
break | do | in | typeof |
case | else | instanceof | var |
catch | export | new | void |
class | extends | return | while |
const | finally | super | with |
continue | for | switch | yield |
debugger | function | this | |
default | if | throw | |
delete | import | try |
3.14.4Non Terminal Token
Non-terminal tokens with a defined as a grammar production can be referred to in other grammar productions. Non-terminals must match the regular expression /[A-Z][_a-zA-Z]*/. That is, they must start with an uppercase letter, followed by any number of letters or underscores.
3.14.5Prose
Grammars can describe arbitrary rules by using prose within a grammar definition by using "quotes"
.
Sandwich : Bread "Any kind of topping" Bread
Produces the following:
3.14.6Terminal Token
Terminal tokens refer to a character or sequence of characters. They can be written unadorned in the grammar definition.
BalancedParens : ( BalancedParens )
Produces the following:
Any sequence of characters can be written to indicate a terminal token:
WhileStatement : while ( Expression ) { Statements }
Produces
Terminals can also be quoted with back-ticks `
to remove any ambiguity from other meanings, for example to allow a terminal token to start with an uppercase letter, or a slash /
or backslash \
, or later contain a ]
or }
.
DivisionExpression : Expression `/` Expression
Produces
3.14.7Regular Expression
When a grammar is intended to be interpretted as a single token and can be clearly written as a regular expression, you can do so directly.
UppercaseWord : /[A-Z][a-z]*/
Produces the following:
3.14.8Quantifiers
Tokens can be followed by quantifiers to alter their meaning and as a short-hand for common patterns of optionality and repetition.
Optional Tokens
A subscript suffix Token?
renders as Tokenopt and is a shorthand for two possible definitions, one including that token and one excluding it.
Sentence : Noun Verb Adverb?
Produces the following:
Which is shorthand for:
Token Lists
A subscript suffix Token+
renders as Tokenlist and is shorthand for a list of one or more of that token.
Book : Cover Page+ Cover
Produces the following:
Which, unless your specification document declares otherwise, is shorthand for:
Some specifications may wish to declare Tokenlist as a shorthand for a comma-separated list, in which case the previous example would be shorthand for:
Optional Lists
A subscript suffix Token*
renders as Tokenlistopt and is shorthand for an optional list, which describes zero or more of that token.
Sandwich : Bread Topping* Bread
Produces the following:
Which is shorthand for:
Use with Non-Terminals
Quantifiers also apply to non-terminal tokens with the same rules. For example:
UnionMembers :
- UnionMembers | NamedType
- `|`? NamedType
Produces the following:
However, unquoted non-terminals may use the *
, ?
and +
characters, so always quote the terminal if the intent is to apply a quantifer.
Counter Example № 5UnionMembers :
- UnionMembers | NamedType
- |? NamedType
Produces the terminal |?
, not an optional |
:
3.14.9Conditional Parameters
It can be a useful short-hand to provide conditional parameters when defining a non-terminal token rather than defining two very similar non-terminals.
A conditional parameter is written in braces Token[Param]
and renders as TokenParam. When used in definitions is shorthand for two symbol definitions: one appended with that parameter name, the other without.
Example[WithCondition] : "Definition TBD"
Produces the following:
Which is shorthand for:
The conditions are applied at the beginning of a definition for the non-terminal by prefixing with [if Param]
(alternatively [+Param]
) or [if not Param]
(alternatively [~Param]
) to only include the definition when the variant with the conditional parameter is or is not used, respectively.
Example[WithCondition] :
- A
- [if WithCondition] B
- [if not WithCondition] C
- [+WithCondition] D
- [~WithCondition] E
Produces the following:
Which is shorthand for:
The same bracket suffix on a non-terminal within a rule is shorthand for using that variant of the rule. If the parameter starts with ?
, that form of the symbol is conditionally used only in the derived production with the same parameter. If the parameter starts with !
, that form of the symbol is only used when in the derived production without that parameter.
Example[WithCondition] :
- Example
- Example[WithCondition]
- Example[?WithCondition]
- Example[!WithCondition]
Produces the following:
Which is shorthand for:
Multiple conditional parameters can be used on both the production definition and on non-terminals within a rule, in which case it is short form for the permutation of all conditions:
Example[P, Q] :
- [if P] `p`
- [if Q] `q`
- Example[!P, ?Q]
Produces the following:
Which is shorthand for:
Conditional parameters on a usage can be followed by a quantifier.
Example[P, ?Q]*
Produces the following:
ExamplePQlistopt
3.14.10Constraints
Any token can be followed by “but not” or “but not one of” to place a further constraint on the previous token:
Example : A B but not foo or bar
Produces the following:
Optionally can mention “one of”, this will be omitted when rendered. Commas can be used instead of “or”.
Example : A B but not one of foo, bar
Produces the following:
3.14.11Meta Tokens
Spec Markdown can specify some tokens which do not consume any characters.
The empty set, written [empty]
appears as [empty] can be used to define a non-terminal as matching no terminal or non-terminal tokens.
Example : [empty]
Produces the following:
Lookaheads can appear anywhere in a sequence of tokens, and describe additional constraints on the following token.
Example :
- [lookahead token] Token
- [lookahead ! token] Token
- [lookahead != token] Token
- [lookahead NonTerminal] Token
- [lookahead ! NonTerminal] Token
- [lookahead != NonTerminal] Token
- [lookahead {token, set}] Token
- [lookahead ! {token, set}] Token
- [lookahead != {token, set}] Token
Produces the following:
3.15Grammar Semantics
Once grammar is defined, it can be useful to define the semantics of the grammar in terms of algorithm steps. A single grammar definition followed by a list is interpretted as a grammar semantic:
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° and placing on {bottomBread}.
* Return {sandwich}.
Produces the following:
- Let bottomBread be the result of placing the first Bread on the plate.
- Let pbSpread be the result of PeanutButter.
- Spread pbSpread onto bottomBread.
- Let topBread be the result of placing the last Bread on the plate.
- Let jamSpread be the result of Jelly.
- Spread jamSpread onto topBread.
- Let sandwich be the result of rotating topBread 180° and placing on bottomBread.
- Return sandwich.
3.16Value Literals
Value literals allow any text to refer to a value which has semantic meaning in the specification by wrapping it in { }
curly brace characters.
I can reference {foo}, {"foo"}, {null}, {true}.
Produces the following:
I can reference foo, "foo", null, true.
Variables
Write {foo}
to produce a variable (represented by a <var> tag) like foo.
Keywords
Some known keywords like null, undefined, true and false are rendered as constants instead of variables.
String literal
Write {"foo"}
to produce a string literal like "foo".
Grammar tokens
Any grammar token can be written inline, like {Example}
to represent the non-terminal token Example, {`terminal`}
to represent the terminal token terminal. Even meta tokens like {[empty]}
for [empty] and {[lookahead !{ x, y }]}
for xy.
Algorithm calls
A call to an algorithm can be expressed as a value literal:
{Algorithm(foo, "string", null)}
Produces the following:
Algorithm(foo, "string", null)
3.17Biblio
By supplying a "biblio"
key in a metadata file, you can have Algorithm calls and Non-terminal tokens which are not defined in this spec to link to where they are defined.
spec-md -m metadata.json myspec.md
Where metadata.json includes:
{
"biblio": {
"http://people.mozilla.org/~jorendorff/es6-draft.html": {
"Identifier": "#sec-names-and-keywords",
"PrimaryExpression": "#sec-primary-expression",
"ReturnIfAbrupt()": "#sec-returnifabrupt",
"Get()": "#sec-get-o-p"
}
}
}
Then referring to these tokens will link out to that page.
MemberExpression : PrimaryExpression . Identifier
* Let {reference} be the result of evaluating {PrimaryExpression}.
* Let {propName} be the string value of {Identifier}.
* Let {value} be {Get(reference, propName)}.
* {ReturnIfAbrupt(value)}.
* Return {value}.
Produces the following:
- Let reference be the result of evaluating PrimaryExpression.
- Let propName be the string value of Identifier.
- Let value be Get(reference, propName).
- ReturnIfAbrupt(value).
- Return value.
AUsing Spec Markdown
If installed globally, using spec-md
as a shell executable is the easiest way to use Spec Markdown. The spec-md
executable expects a filepath to a Markdown document as input and outputs HTML on stdout. Use >
to write stdout to a file.
npm install -g spec-md
spec-md ./path/to/markdown.md > ./path/to/output.html
You can also require spec-md
as a node module, after which you might add the spec-md
command as a node script.
npm install --save-dev spec-md
const fs = require('fs');
const specMarkdown = require('spec-md');
const html = specMarkdown.html('./path/to/markdown.md');
fs.writeFileSync('./path/to/output.html', html);
The spec-md
node module provides a few functions:
- html(filePath, options) takes a filepath to a Markdown file and returns an HTML string. This function is the primary usage of the
spec-md
module. - parse(filePath) takes a filepath and returns an AST (Abstract Syntax Tree) representing the contents of the Spec Markdown file, with all imports already inlined.
- print(ast, options) takes an ast produced by parse() and returns an HTML string.
- visit(ast, visitor) takes an ast and a visitor. It walks over the ast in a depth-first-traversal calling the visitor along the way.
A.1Print Options
The html(filePath, options) and print(filePath) functions both take options as an optional second argument. These options allow for customization control over the returned HTML, more options may be added in the future.
- githubSource - a base URL, that if provided will be used to construct Github source links to the original Markdown files throughout the returned HTML. (example: “https://github.com/leebyron/spec-md/blame/main/”)
- highlight - a function which is called when blocks of code are encountered, with the first argument as the string of code, the second argument being the language specified. This function should return well formed HTML, complete with escaped special characters.
- head - a string which is inserted in the
<head>
tag in the returned HTML. Use this to introduce additional meta tags and scripts.
A.2Hot rebuilding with nodemon
The spec-md
shell executable follows the Unix Philosophy of doing one thing and doing it well. Try out nodemon
to continuously rebuild the HTML output as you edit the markdown specification:
npm install -g nodemon
nodemon --exec "spec-md > ./path/to/output.html" ./path/to/markdown.md
BContributing to Spec Markdown
We want to make contributing to this project as easy and transparent as possible. Hopefully this document makes the process for contributing clear and answers any questions you may have. If not, feel free to open an Issue.
B.1Pull Requests
All active development of Spec Markdown happens on GitHub. We actively welcome your pull requests.
- Fork the repo and create your branch from
main
. - Install all dependencies. (
npm install
) - If you’ve added code, add tests.
- If you’ve changed APIs, update the documentation.
- Run tests and ensure your code passes lint. (
npm test
)
B.2`main` is unsafe
We will do our best to keep main
in good shape, with tests passing at all times. But in order to move fast, we might make API changes that your application might not be compatible with. We will do our best to communicate these changes and always version appropriately so you can lock into a specific version if need be. If any of this is worrysome to you, just use npm.
B.3Issues
We use GitHub issues to track public bugs and requests. Please ensure your bug description is clear and has sufficient instructions to be able to reproduce the issue. The best way is to provide a reduced test case on jsFiddle or jsBin.
B.4Coding Style
- 2 spaces for indentation (no tabs)
- 80 character line length strongly preferred.
- Prefer
'
over"
- Use semicolons;
- Trailing commas,
- Avd abbr wrds.
B.5License
By contributing to Spec Markdown, you agree that your contributions will be licensed under its MIT license.