Skip to content

Commit

Permalink
Add support for separate open and close markers, custom fences
Browse files Browse the repository at this point in the history
Closes GH-3.
Closes GH-2.

Amended-by: Titus Wormer <tituswormer@gmail.com>
  • Loading branch information
maxkueng authored and wooorm committed Dec 4, 2017
1 parent fb88571 commit ecc5096
Show file tree
Hide file tree
Showing 27 changed files with 709 additions and 53 deletions.
8 changes: 5 additions & 3 deletions lib/compile.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
'use strict';

var fence = require('./fence');

module.exports = create;

function create(matter) {
var type = matter.type;
var marker = matter.marker;
var fence = marker + marker + marker;
var open = fence(matter, 'open');
var close = fence(matter, 'close');

frontmatter.displayName = type + 'FrontMatter';

return [type, frontmatter];

function frontmatter(node) {
return fence + (node.value ? '\n' + node.value : '') + '\n' + fence;
return open + (node.value ? '\n' + node.value : '') + '\n' + close;
}
}
18 changes: 18 additions & 0 deletions lib/fence.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
'use strict';

module.exports = fence;

function fence(matter, prop) {
var marker;

if (matter.marker) {
marker = pick(matter.marker, prop);
return marker + marker + marker;
}

return pick(matter.fence, prop);
}

function pick(schema, prop) {
return typeof schema === 'string' ? schema : schema[prop];
}
4 changes: 2 additions & 2 deletions lib/matters.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ function matter(option) {
throw fault('Missing `type` in matter `%j`', result);
}

if (!own.call(result, 'marker')) {
throw fault('Missing `marker` in matter `%j`', result);
if (!own.call(result, 'fence') && !own.call(result, 'marker')) {
throw fault('Missing `marker` or `fence` in matter `%j`', result);
}

return result;
Expand Down
62 changes: 20 additions & 42 deletions lib/parse.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
'use strict';

var fence = require('./fence');

module.exports = create;

function create(matter) {
var name = matter.type + 'FrontMatter';
var marker = matter.marker;
var fence = marker + marker + marker;
var open = fence(matter, 'open');
var close = fence(matter, 'close');
var newline = '\n';

frontmatter.displayName = name;
Expand All @@ -14,54 +16,30 @@ function create(matter) {
return [name, frontmatter];

function frontmatter(eat, value, silent) {
var subvalue;
var content;
var index;
var length;
var character;
var queue;
var index = open.length;
var offset;

if (
value.charAt(0) !== marker ||
value.charAt(1) !== marker ||
value.charAt(2) !== marker ||
value.charAt(3) !== newline
) {
if (value.slice(0, index) !== open || value.charAt(index) !== newline) {
return;
}

subvalue = fence + newline;
content = '';
queue = '';
index = 3;
length = value.length;

while (++index < length) {
character = value.charAt(index);

if (
character === marker &&
(queue || !content) &&
value.charAt(index + 1) === marker &&
value.charAt(index + 2) === marker
) {
/* istanbul ignore if - never used (yet) */
if (silent) {
return true;
}
offset = value.indexOf(close, index);

subvalue += queue + fence;
while (offset !== -1 && value.charAt(offset - 1) !== newline) {
index = offset + close.length;
offset = value.indexOf(close, index);
}

return eat(subvalue)({type: matter.type, value: content});
if (offset !== -1) {
/* istanbul ignore if - never used (yet) */
if (silent) {
return true;
}

if (character === newline) {
queue += character;
} else {
subvalue += queue + character;
content += queue + character;
queue = '';
}
return eat(value.slice(0, offset + close.length))({
type: matter.type,
value: value.slice(open.length + 1, offset - 1)
});
}
}
}
93 changes: 88 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,24 +82,107 @@ Adds [tokenizers][] if the [processor][] is configured with
If you are parsing from a different syntax, or compiling to a different syntax
(e.g., [`remark-man`][man]) your custom nodes may not be supported.

###### `options`
##### `options`

One [`preset`][preset] or [`Matter`][matter], or an array of them, defining all
the supported frontmatters (default: `'yaml'`).

###### `preset`
##### `preset`

Either `'yaml'` or `'toml'`:

* `'yaml'`[`matter`][matter] defined as `{type: 'yaml', marker: '-'}`
* `'toml'`[`matter`][matter] defined as `{type: 'toml', marker: '+'}`

###### `Matter`
##### `Matter`

An object with a `type` and a `marker`:
An object with a `type` and either a `marker` or a `fence`:

* `type` (`string`) — Node type to parse to in [mdast][] and compile from
* `marker` (`string`) — Character used for fences
* `marker` (`string` or `{open: string, close: string}`) — Character used
to construct fences. By providing an object with `open` and `close`.
different characters can be used for opening and closing fences. For
example the character `'-'` will result in `'---'` being used as the fence
* `fence` (`string` or `{open: string, close: string}`) — String used as
the complete fence. By providing an object with `open` and `close`
different values can be used for opening and closing fences. This can be
used too if fences contain different characters or lengths other than 3

###### Example

For `{type: 'yaml', marker: '-'}`:

```yaml
---
key: value
---
```

Yields:

```json
{
"type": "yaml",
"value": "key: value"
}
```

###### Example

For `{type: 'custom', marker: {open: '<', close: '>'}}`:

```text
<<<
data
>>>
```

Yields:

```json
{
"type": "custom",
"value": "data"
}
```

###### Example

For `{type: 'custom', fence: '+=+=+=+'}`:

```text
+=+=+=+
data
+=+=+=+
```

Yields:

```json
{
"type": "custom",
"value": "dats"
}
```

###### Example

For `{type: 'json', fence: {open: '{', close: '}'}}`:

```json
{
"key": "value"
}
```

Yields:

```json
{
"type": "json",
"value": "\"key\": \"value\""
}
```

## Related

Expand Down
1 change: 1 addition & 0 deletions test/fixtures/custom-fence-long/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"type": "jsonml", "fence": "=f-e*n_c$e"}]
8 changes: 8 additions & 0 deletions test/fixtures/custom-fence-long/input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
=f-e*n_c$e
{
title: "Custom",
// A comment ***
}
=f-e*n_c$e

# Deep
76 changes: 76 additions & 0 deletions test/fixtures/custom-fence-long/tree.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
{
"type": "root",
"children": [
{
"type": "jsonml",
"value": "{\n title: \"Custom\",\n // A comment ***\n}",
"position": {
"start": {
"line": 1,
"column": 1,
"offset": 0
},
"end": {
"line": 6,
"column": 11,
"offset": 63
},
"indent": [
1,
1,
1,
1,
1
]
}
},
{
"type": "heading",
"depth": 1,
"children": [
{
"type": "text",
"value": "Deep",
"position": {
"start": {
"line": 8,
"column": 3,
"offset": 67
},
"end": {
"line": 8,
"column": 7,
"offset": 71
},
"indent": []
}
}
],
"position": {
"start": {
"line": 8,
"column": 1,
"offset": 65
},
"end": {
"line": 8,
"column": 7,
"offset": 71
},
"indent": []
}
}
],
"position": {
"start": {
"line": 1,
"column": 1,
"offset": 0
},
"end": {
"line": 9,
"column": 1,
"offset": 72
}
}
}
1 change: 1 addition & 0 deletions test/fixtures/custom-fence-openclose/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"type": "jsonml", "fence": {"open": "$$OPEN", "close": "CLOSE##"}}]
8 changes: 8 additions & 0 deletions test/fixtures/custom-fence-openclose/input.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
$$OPEN
{
title: "Custom",
// A comment ***
}
CLOSE##
# Deep
Loading

0 comments on commit ecc5096

Please sign in to comment.