Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Prettier support #31

Closed
wants to merge 16 commits into from
11 changes: 9 additions & 2 deletions spec/Markdown.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,8 +86,7 @@ Todo: Links do not yet support a title attribute.

### Emphasis

Wrapping asterisks *(\*)* indicate emphasis. Like Github-flavored
Markdown, Spec Markdown does not treat underscore *(_)* as emphasis.
Wrapping asterisks *(\*)* or underscores _(\_)_ indicate emphasis.

```
Example of **bold** and *italic* and ***bold italic***.
Expand All @@ -97,6 +96,14 @@ Produces the following:

Example of **bold** and *italic* and ***bold italic***.

```
Example of **bold** and _italic_ and **_bold italic_**.
```

Produces the following:

Example of **bold** and _italic_ and **_bold italic_**.



### Inline Code
Expand Down
10 changes: 5 additions & 5 deletions spec/Spec Additions.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,15 +24,15 @@ referencing specific parts of your document easy. Try it here!

## Title and Introduction

A Spec Markdown document should start with one Setext style header which will be
used as the title of the document. Any content before the first atx (`#`) style
header will become the introduction to the document.
A Spec Markdown document should start with one bolded atx style header
(`# **Title**`) which will be used as the title of the document. Any content
before the next atx (`#`) style header will become the introduction to the
document.

A Spec Markdown document starts in this form:

```
Spec Markdown
-------------
# **Spec Markdown**

Introductory paragraph.

Expand Down
96 changes: 75 additions & 21 deletions src/grammar.pegjs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
return list;
}

function markdownUnescape(text) {
return text.replace(/\\([$_*])/g, '$1');
}

var htmlBlockName;

var BLOCK_TAGS_RX = /^(?:p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)$/i;
Expand All @@ -27,16 +31,27 @@ document = title:title? contents:documentContent* EOF {
};
}

title = BLOCK !'#' value:$NOT_NL+ NL ('---' '-'* / '===' '='*) &NL {
oldTitle = BLOCK !'#' value:$NOT_NL+ NL ('---' '-'* / '===' '='*) &NL {
return {
type: 'DocumentTitle',
value: value
};
}

newTitle = BLOCK '# **' value:$([^*\r\n]+) '**' &NL {
return {
type: 'DocumentTitle',
value: value
};
}

title = newTitle / oldTitle

SEC_CLOSE = _ '#'* &NL

sectionTitle = $titleChar+
sectionTitle = t:$titleChar+ {
return markdownUnescape(t);
}
titleChar = [^\n\r# ] / [# ] titleChar

sectionID = start:$sectionIDStart rest:('.' $sectionIDPart)* '.' {
Expand Down Expand Up @@ -209,7 +224,7 @@ inlineEntity = inlineEdit / inlineCode / reference / bold / italic / link / imag
content = inlineEntity / text

textChar = escaped
/ [^\n\r+\-{`*[!<]
/ [^\n\r+\-{`*[!<_]
/ '++' !'}'
/ '+' !'+}'
/ '--' !'}'
Expand All @@ -221,7 +236,7 @@ textChar = escaped
text = value:$textChar+ {
return {
type: 'Text',
value: value
value: markdownUnescape(value)
};
}

Expand All @@ -246,13 +261,22 @@ bold = '**' contents:(inlineCode / link / italic / text)+ '**' {
};
}

italic = '*' contents:(inlineCode / link / text)+ '*' {
asteriskItalic = '*' contents:(inlineCode / link / text)+ '*' {
return {
type: 'Italic',
contents: contents
};
}

underscoreItalic = '_' contents:(inlineCode / link / text)+ '_' {
return {
type: 'Italic',
contents: contents
};
}

italic = underscoreItalic / asteriskItalic

inlineEdit = ins / del

ins = '{++' contents:content* '++}' {
Expand All @@ -276,7 +300,7 @@ htmlTag = tag:$('<' '/'? [a-z]+ [^>]* '>') {
};
}

reference = '{' !('++'/'--') _ ref:(call / value / token)? _ close:'}'? {
reference = '{' !('++'/'--') __ ref:(call / value / token)? __ close:'}'? {
if (ref === null || close === null) {
error('Malformed {reference}.');
}
Expand Down Expand Up @@ -344,7 +368,7 @@ linkTextChar = escaped
linkText = value:$linkTextChar+ {
return {
type: 'Text',
value: value
value: markdownUnescape(value)
};
}

Expand Down Expand Up @@ -438,9 +462,16 @@ tableCellText = value:$tableCellTextChar+ {

// Names

localName = $([_a-z][_a-zA-Z0-9]*)
globalName = $([A-Z][_a-zA-Z]*)
paramName = $([_a-zA-Z][_a-zA-Z0-9]*)
localName = text:$($('\\_' / [_a-z]) $('\\_' / [_a-zA-Z0-9])*) {
return markdownUnescape(text);
}

globalName = text:$([A-Z] $('\\_' / [_a-zA-Z])*) {
return markdownUnescape(text);
}
paramName = text:$($('\\_' / [_a-zA-Z]) $('\\_' / [_a-zA-Z0-9])*) {
return markdownUnescape(text);
}


// Algorithm
Expand All @@ -453,15 +484,17 @@ algorithm = BLOCK call:call _ ':' ':'? steps:list {
};
}

call = name:(globalName / localName) '(' _ args:callArg* _ ')' {
call = name:(globalName / localName) '(' __ args:callArg* __ ')' {
return {
type: 'Call',
name: name,
args: args
};
}

callArg = value:value [, ]* {
callSep = __ ',' __ / __

callArg = value:value callSep {
return value;
}

Expand All @@ -473,7 +506,7 @@ stringLiteral = '"' value:$([^"\n\r]/'\\"')* closer:'"'? {
}
return {
type: 'StringLiteral',
value: '"' + value + '"'
value: '"' + markdownUnescape(value) + '"'
};
}

Expand All @@ -494,7 +527,7 @@ variable = name:localName {

// Grammar productions

semantic = BLOCK name:nonTerminal _ defType:(':::'/'::'/':') _ tokens:token+ steps:list {
semantic = BLOCK name:nonTerminal _ defType:(':::'/'::'/':') _ tokens:tokenListMultiline steps:list {
return {
type: 'Semantic',
name: name,
Expand All @@ -516,7 +549,7 @@ production = BLOCK token:nonTerminal _ defType:(':::'/'::'/':') _ rhs:production
};
}

productionRHS = oneOfRHS / singleRHS / listRHS
productionRHS = oneOfRHS / listRHS / singleRHS

oneOfRHS = 'one of' rows:(_ NL? (_ token)+)+ {
return {
Expand All @@ -529,7 +562,7 @@ oneOfRHS = 'one of' rows:(_ NL? (_ token)+)+ {
};
}

singleRHS = condition:condition? _ tokens:token+ {
singleRHS = condition:condition? _ tokens:tokenListMultiline {
return {
type: 'RHS',
condition: condition,
Expand All @@ -545,7 +578,7 @@ indentedRHS = INDENT defs:(listItemRHS+)? DEDENT &{ return defs !== null; } {
return defs;
}

listItemRHS = LINE listBullet _ condition:condition? _ tokens:token+ {
listItemRHS = LINE listBullet _ condition:condition? _ tokens:tokenListMultiline {
return {
type: 'RHS',
condition: condition,
Expand All @@ -561,13 +594,17 @@ condition = '[' condition:$('+' / '~' / 'if' (_ 'not')?) _ param:paramName ']' {
};
}

token = token:unconstrainedToken quantifier:('+' / '?' / '*')? _ constraint:constraint? _ {
constraintAfterGap = _ constraint:constraint {
return constraint;
}

token = token:unconstrainedToken quantifier:('+' / '?' / '*' / '\\*')? constraint:constraintAfterGap? {
if (quantifier) {
token = {
type: 'Quantified',
token: token,
isList: quantifier === '+' || quantifier === '*',
isOptional: quantifier === '?' || quantifier === '*'
isList: quantifier === '+' || quantifier === '*' || quantifier === '\\*',
isOptional: quantifier === '?' || quantifier === '*' || quantifier === '\\*'
};
}
if (constraint) {
Expand All @@ -580,6 +617,22 @@ token = token:unconstrainedToken quantifier:('+' / '?' / '*')? _ constraint:cons
return token;
}

tokenAfterSpace = _ token:token {
return token;
}

tokenAfterSpaceOrNewline = __ !listBullet token:token {
return token;
}

tokenListOneLine = head:token tail:tokenAfterSpace* {
return [head, ...tail];
}

tokenListMultiline = head:token tail:tokenAfterSpaceOrNewline* {
return [head, ...tail];
}

unconstrainedToken = prose / emptyToken / lookahead / nonTerminal / regexp / quotedTerminal / terminal

prose = '"' text:$([^"\n\r]/'\\"')* closer:'"'? {
Expand Down Expand Up @@ -679,7 +732,7 @@ quotedTerminal = '`' value:$(([^`\n] / ('\\`'))+)? closer:'`' {
terminal = value:$(([^ \n"/`] [^ \n"\`,\]\}]*)) {
return {
type: 'Terminal',
value: value
value: markdownUnescape(value)
};
}

Expand Down Expand Up @@ -711,6 +764,7 @@ DEDENT = &lineStart !{ indentStack.length === 0 } {
NL = '\n' / '\r' / '\r\n'
NOT_NL = [^\n\r]
_ = ' '*
__ = ' '* NL ' '* / ' '*
EOF = NL* !.

lineStart = NL+ / & { return offset() === 0 }
Expand Down
7 changes: 7 additions & 0 deletions src/print.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,13 @@ function getPrismLanguage(lang) {
if (!prism.languages[lang]) {
loadAllLanguages();
}
if (!prism.languages[lang] && lang.startsWith("raw")) {
// To prevent 'prettier' formatting code in your markdown, you may prefix
// the language with "raw" and we will still format it as you would expect
// in the output.
// e.g. ```graphql -> ```rawgraphql
return prism.languages[lang.substr(3)];
}
return prism.languages[lang];
}

Expand Down