Skip to content

Commit c4313fb

Browse files
committed
Add support for options in extensions
1 parent 6e08182 commit c4313fb

File tree

5 files changed

+113
-49
lines changed

5 files changed

+113
-49
lines changed

lib/index.js

Lines changed: 46 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -2,27 +2,39 @@ module.exports = toMarkdown
22

33
var zwitch = require('zwitch')
44
var defaultHandlers = require('./handle')
5-
var defaultUnsafePatterns = require('./unsafe')
5+
var defaultUnsafe = require('./unsafe')
66
var defaultJoin = require('./join')
77

88
function toMarkdown(tree, options) {
99
var settings = options || {}
10-
var extensions = configure(settings)
11-
var stack = []
12-
var handle = zwitch('type', {
13-
invalid: invalid,
14-
unknown: unknown,
15-
handlers: extensions.handlers
16-
})
1710
var context = {
18-
handle: handle,
19-
stack: stack,
2011
enter: enter,
21-
options: settings,
22-
unsafePatterns: extensions.unsafe,
23-
join: extensions.join
12+
stack: [],
13+
unsafe: [],
14+
join: [],
15+
handlers: {},
16+
options: {}
17+
}
18+
var result
19+
20+
configure(context, {
21+
unsafe: defaultUnsafe,
22+
join: defaultJoin,
23+
handlers: defaultHandlers
24+
})
25+
configure(context, settings)
26+
27+
if (context.options.tightDefinitions) {
28+
context.join = [joinDefinition].concat(context.join)
2429
}
25-
var result = handle(tree, null, context, {before: '\n', after: '\n'})
30+
31+
context.handle = zwitch('type', {
32+
invalid: invalid,
33+
unknown: unknown,
34+
handlers: context.handlers
35+
})
36+
37+
result = context.handle(tree, null, context, {before: '\n', after: '\n'})
2638

2739
if (
2840
result &&
@@ -35,11 +47,11 @@ function toMarkdown(tree, options) {
3547
return result
3648

3749
function enter(name) {
38-
stack.push(name)
50+
context.stack.push(name)
3951
return exit
4052

4153
function exit() {
42-
stack.pop()
54+
context.stack.pop()
4355
}
4456
}
4557
}
@@ -52,26 +64,30 @@ function unknown(node) {
5264
throw new Error('Cannot handle unknown node `' + node.type + '`')
5365
}
5466

55-
function configure(settings) {
56-
var extensions = [
57-
{unsafe: settings.unsafe, handlers: settings.handlers, join: settings.join}
58-
].concat(settings.extensions || [])
59-
var unsafe = defaultUnsafePatterns
60-
var join = defaultJoin
61-
var handlers = Object.assign({}, defaultHandlers)
67+
function configure(base, extension) {
6268
var index = -1
69+
var key
6370

64-
if (settings.tightDefinitions) {
65-
join = [joinDefinition].concat(join)
71+
// First do subextensions.
72+
if (extension.extensions) {
73+
while (++index < extension.extensions.length) {
74+
configure(base, extension.extensions[index])
75+
}
6676
}
6777

68-
while (++index < extensions.length) {
69-
unsafe = unsafe.concat(extensions[index].unsafe || [])
70-
join = join.concat(extensions[index].join || [])
71-
Object.assign(handlers, extensions[index].handlers || {})
78+
for (key in extension) {
79+
if (key === 'extensions') {
80+
// Empty.
81+
} else if (key === 'unsafe' || key === 'join') {
82+
base[key] = base[key].concat(extension[key] || [])
83+
} else if (key === 'handlers') {
84+
base[key] = Object.assign(base[key], extension[key] || {})
85+
} else {
86+
base.options[key] = extension[key]
87+
}
7288
}
7389

74-
return {unsafe: unsafe, join: join, handlers: handlers}
90+
return base
7591
}
7692

7793
function joinDefinition(left, right) {

lib/util/safe.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ function safe(context, input, config) {
1515
var start
1616
var end
1717

18-
while (++index < context.unsafePatterns.length) {
19-
pattern = context.unsafePatterns[index]
18+
while (++index < context.unsafe.length) {
19+
pattern = context.unsafe[index]
2020

2121
if (
2222
!inScope(context.stack, pattern.inConstruct, true) ||

readme.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -146,15 +146,6 @@ function (left, right) {
146146
}
147147
```
148148

149-
##### Extension options
150-
151-
###### `options.extensions`
152-
153-
List of extensions (`Array.<ToMarkdownExtension>`).
154-
Each `ToMarkdownExtension` is an object with optional `handlers`, `join`, and
155-
`unsafe` keys, mapping to the values which can also be passed in directly,
156-
documented below.
157-
158149
###### `options.handlers`
159150

160151
Object mapping node types to custom handlers.
@@ -188,6 +179,14 @@ List of patterns to escape.
188179
Useful for syntax extensions.
189180
Take a look at [`lib/unsafe.js`][unsafe] for examples.
190181

182+
##### Extension options
183+
184+
###### `options.extensions`
185+
186+
List of extensions (`Array.<ToMarkdownExtension>`).
187+
Each `ToMarkdownExtension` is an object with the same interface as `options`
188+
here.
189+
191190
##### Returns
192191

193192
`string` — Serialized markdown.

test.js

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2530,6 +2530,61 @@ test('escape', function (t) {
25302530
'should not escape what can’t be a list (dot)'
25312531
)
25322532

2533+
t.equal(
2534+
to(
2535+
{
2536+
type: 'root',
2537+
children: [
2538+
{type: 'definition', label: 'a'},
2539+
{type: 'definition', label: 'b'}
2540+
]
2541+
},
2542+
{extensions: [{tightDefinitions: true}]}
2543+
),
2544+
'[a]: <>\n[b]: <>\n',
2545+
'should support options in extensions'
2546+
)
2547+
2548+
t.equal(
2549+
to(
2550+
{
2551+
type: 'root',
2552+
children: [{type: 'strong', children: [{type: 'text', value: 'a'}]}]
2553+
},
2554+
{
2555+
extensions: [
2556+
{strong: '_', join: null, handlers: null, extensions: null}
2557+
]
2558+
}
2559+
),
2560+
'__a__\n',
2561+
'should support empty `join`, `handlers`, `extensions` in an extension (coverage)'
2562+
)
2563+
2564+
t.equal(
2565+
to(
2566+
{
2567+
type: 'root',
2568+
children: [{type: 'strong', children: [{type: 'text', value: 'a'}]}]
2569+
},
2570+
{strong: '*', extensions: [{strong: '_'}]}
2571+
),
2572+
'**a**\n',
2573+
'should prefer main options over extension options'
2574+
)
2575+
2576+
t.equal(
2577+
to(
2578+
{
2579+
type: 'root',
2580+
children: [{type: 'strong', children: [{type: 'text', value: 'a'}]}]
2581+
},
2582+
{extensions: [{strong: '*', extensions: [{strong: '_'}]}]}
2583+
),
2584+
'**a**\n',
2585+
'should prefer extension options over subextension options'
2586+
)
2587+
25332588
t.end()
25342589
})
25352590

types/index.d.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ declare namespace toMarkdown {
2020
stack: string[]
2121
enter: (type: string) => () => void
2222
options: Options
23-
unsafePatterns: Unsafe[]
23+
unsafe: Unsafe[]
2424
join: Join[]
2525
handle: Handle
2626
}
@@ -55,12 +55,6 @@ declare namespace toMarkdown {
5555
context: Context
5656
) => boolean | null | void
5757

58-
interface Extension {
59-
handlers?: Handlers
60-
join?: Join[]
61-
unsafe?: Unsafe[]
62-
}
63-
6458
interface Options {
6559
bullet?: '-' | '*' | '+'
6660
closeAtx?: boolean
@@ -77,7 +71,7 @@ declare namespace toMarkdown {
7771
strong?: '_' | '*'
7872
tightDefinitions?: boolean
7973

80-
extensions?: Extension[]
74+
extensions?: Options[]
8175
handlers?: Handlers
8276
join?: Join[]
8377
unsafe?: Unsafe[]

0 commit comments

Comments
 (0)