motion-markdown-it 0.4.0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +243 -0
- data/lib/motion-markdown-it.rb +71 -0
- data/lib/motion-markdown-it/common/entities.rb +1084 -0
- data/lib/motion-markdown-it/common/html_blocks.rb +60 -0
- data/lib/motion-markdown-it/common/html_re.rb +28 -0
- data/lib/motion-markdown-it/common/string.rb +14 -0
- data/lib/motion-markdown-it/common/url_schemas.rb +173 -0
- data/lib/motion-markdown-it/common/utils.rb +216 -0
- data/lib/motion-markdown-it/helpers/parse_link_destination.rb +75 -0
- data/lib/motion-markdown-it/helpers/parse_link_label.rb +51 -0
- data/lib/motion-markdown-it/helpers/parse_link_title.rb +48 -0
- data/lib/motion-markdown-it/index.rb +507 -0
- data/lib/motion-markdown-it/parser_block.rb +113 -0
- data/lib/motion-markdown-it/parser_core.rb +46 -0
- data/lib/motion-markdown-it/parser_inline.rb +121 -0
- data/lib/motion-markdown-it/presets/commonmark.rb +76 -0
- data/lib/motion-markdown-it/presets/default.rb +42 -0
- data/lib/motion-markdown-it/presets/zero.rb +59 -0
- data/lib/motion-markdown-it/renderer.rb +286 -0
- data/lib/motion-markdown-it/ruler.rb +327 -0
- data/lib/motion-markdown-it/rules_block/blockquote.rb +138 -0
- data/lib/motion-markdown-it/rules_block/code.rb +35 -0
- data/lib/motion-markdown-it/rules_block/fence.rb +94 -0
- data/lib/motion-markdown-it/rules_block/heading.rb +56 -0
- data/lib/motion-markdown-it/rules_block/hr.rb +45 -0
- data/lib/motion-markdown-it/rules_block/html_block.rb +73 -0
- data/lib/motion-markdown-it/rules_block/lheading.rb +54 -0
- data/lib/motion-markdown-it/rules_block/list.rb +242 -0
- data/lib/motion-markdown-it/rules_block/paragraph.rb +51 -0
- data/lib/motion-markdown-it/rules_block/reference.rb +161 -0
- data/lib/motion-markdown-it/rules_block/state_block.rb +184 -0
- data/lib/motion-markdown-it/rules_block/table.rb +161 -0
- data/lib/motion-markdown-it/rules_core/block.rb +20 -0
- data/lib/motion-markdown-it/rules_core/inline.rb +20 -0
- data/lib/motion-markdown-it/rules_core/linkify.rb +138 -0
- data/lib/motion-markdown-it/rules_core/normalize.rb +44 -0
- data/lib/motion-markdown-it/rules_core/replacements.rb +90 -0
- data/lib/motion-markdown-it/rules_core/smartquotes.rb +158 -0
- data/lib/motion-markdown-it/rules_core/state_core.rb +20 -0
- data/lib/motion-markdown-it/rules_inline/autolink.rb +74 -0
- data/lib/motion-markdown-it/rules_inline/backticks.rb +51 -0
- data/lib/motion-markdown-it/rules_inline/emphasis.rb +172 -0
- data/lib/motion-markdown-it/rules_inline/entity.rb +51 -0
- data/lib/motion-markdown-it/rules_inline/escape.rb +55 -0
- data/lib/motion-markdown-it/rules_inline/html_inline.rb +49 -0
- data/lib/motion-markdown-it/rules_inline/image.rb +158 -0
- data/lib/motion-markdown-it/rules_inline/link.rb +153 -0
- data/lib/motion-markdown-it/rules_inline/newline.rb +47 -0
- data/lib/motion-markdown-it/rules_inline/state_inline.rb +57 -0
- data/lib/motion-markdown-it/rules_inline/strikethrough.rb +130 -0
- data/lib/motion-markdown-it/rules_inline/text.rb +94 -0
- data/lib/motion-markdown-it/token.rb +134 -0
- data/lib/motion-markdown-it/version.rb +5 -0
- data/spec/motion-markdown-it/bench_mark_spec.rb +44 -0
- data/spec/motion-markdown-it/commonmark_spec.rb +16 -0
- data/spec/motion-markdown-it/markdown_it_spec.rb +18 -0
- data/spec/motion-markdown-it/misc_spec.rb +277 -0
- data/spec/motion-markdown-it/ruler_spec.rb +153 -0
- data/spec/motion-markdown-it/testgen_helper.rb +68 -0
- data/spec/motion-markdown-it/token_spec.rb +17 -0
- data/spec/motion-markdown-it/utils_spec.rb +82 -0
- data/spec/spec_helper.rb +6 -0
- metadata +158 -0
@@ -0,0 +1,286 @@
|
|
1
|
+
# class Renderer
|
2
|
+
#
|
3
|
+
# Generates HTML from parsed token stream. Each instance has independent
|
4
|
+
# copy of rules. Those can be rewritten with ease. Also, you can add new
|
5
|
+
# rules if you create plugin and adds new token types.
|
6
|
+
#------------------------------------------------------------------------------
|
7
|
+
module MarkdownIt
|
8
|
+
class Renderer
|
9
|
+
include MarkdownIt::Common::Utils
|
10
|
+
extend MarkdownIt::Common::Utils
|
11
|
+
|
12
|
+
# Default Rules
|
13
|
+
#------------------------------------------------------------------------------
|
14
|
+
def self.code_inline(tokens, idx)
|
15
|
+
return '<code>' + escapeHtml(tokens[idx].content) + '</code>'
|
16
|
+
end
|
17
|
+
|
18
|
+
#------------------------------------------------------------------------------
|
19
|
+
def self.code_block(tokens, idx)
|
20
|
+
return '<pre><code>' + escapeHtml(tokens[idx].content) + "</code></pre>\n"
|
21
|
+
end
|
22
|
+
|
23
|
+
#------------------------------------------------------------------------------
|
24
|
+
def self.fence(tokens, idx, options, env, renderer)
|
25
|
+
token = tokens[idx]
|
26
|
+
langName = ''
|
27
|
+
|
28
|
+
if !token.info.empty?
|
29
|
+
langName = unescapeAll(token.info.strip.split(/\s+/)[0])
|
30
|
+
token.attrPush([ 'class', options[:langPrefix] + langName ])
|
31
|
+
end
|
32
|
+
|
33
|
+
if options[:highlight]
|
34
|
+
highlighted = options[:highlight].call(token.content, langName) || escapeHtml(token.content)
|
35
|
+
else
|
36
|
+
highlighted = escapeHtml(token.content)
|
37
|
+
end
|
38
|
+
|
39
|
+
return '<pre><code' + renderer.renderAttrs(token) + '>' + highlighted + "</code></pre>\n"
|
40
|
+
end
|
41
|
+
|
42
|
+
#------------------------------------------------------------------------------
|
43
|
+
def self.image(tokens, idx, options, env, renderer)
|
44
|
+
token = tokens[idx]
|
45
|
+
|
46
|
+
# "alt" attr MUST be set, even if empty. Because it's mandatory and
|
47
|
+
# should be placed on proper position for tests.
|
48
|
+
#
|
49
|
+
# Replace content with actual value
|
50
|
+
|
51
|
+
token.attrs[token.attrIndex('alt')][1] = renderer.renderInlineAsText(token.children, options, env)
|
52
|
+
|
53
|
+
return renderer.renderToken(tokens, idx, options);
|
54
|
+
end
|
55
|
+
|
56
|
+
#------------------------------------------------------------------------------
|
57
|
+
def self.hardbreak(tokens, idx, options)
|
58
|
+
return options[:xhtmlOut] ? "<br />\n" : "<br>\n"
|
59
|
+
end
|
60
|
+
def self.softbreak(tokens, idx, options)
|
61
|
+
return options[:breaks] ? (options[:xhtmlOut] ? "<br />\n" : "<br>\n") : "\n"
|
62
|
+
end
|
63
|
+
|
64
|
+
#------------------------------------------------------------------------------
|
65
|
+
def self.text(tokens, idx)
|
66
|
+
return escapeHtml(tokens[idx].content)
|
67
|
+
end
|
68
|
+
|
69
|
+
#------------------------------------------------------------------------------
|
70
|
+
def self.html_block(tokens, idx)
|
71
|
+
return tokens[idx].content
|
72
|
+
end
|
73
|
+
def self.html_inline(tokens, idx)
|
74
|
+
return tokens[idx].content
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
# new Renderer()
|
79
|
+
#
|
80
|
+
# Creates new [[Renderer]] instance and fill [[Renderer#rules]] with defaults.
|
81
|
+
#------------------------------------------------------------------------------
|
82
|
+
def initialize
|
83
|
+
@default_rules = {
|
84
|
+
'code_inline' => lambda {|tokens, idx, options, env, renderer| Renderer.code_inline(tokens, idx)},
|
85
|
+
'code_block' => lambda {|tokens, idx, options, env, renderer| Renderer.code_block(tokens, idx)},
|
86
|
+
'fence' => lambda {|tokens, idx, options, env, renderer| Renderer.fence(tokens, idx, options, env, renderer)},
|
87
|
+
'image' => lambda {|tokens, idx, options, env, renderer| Renderer.image(tokens, idx, options, env, renderer)},
|
88
|
+
'hardbreak' => lambda {|tokens, idx, options, env, renderer| Renderer.hardbreak(tokens, idx, options)},
|
89
|
+
'softbreak' => lambda {|tokens, idx, options, env, renderer| Renderer.softbreak(tokens, idx, options)},
|
90
|
+
'text' => lambda {|tokens, idx, options, env, renderer| Renderer.text(tokens, idx)},
|
91
|
+
'html_block' => lambda {|tokens, idx, options, env, renderer| Renderer.html_block(tokens, idx)},
|
92
|
+
'html_inline' => lambda {|tokens, idx, options, env, renderer| Renderer.html_inline(tokens, idx)}
|
93
|
+
}
|
94
|
+
|
95
|
+
# Renderer#rules -> Object
|
96
|
+
#
|
97
|
+
# Contains render rules for tokens. Can be updated and extended.
|
98
|
+
#
|
99
|
+
# ##### Example
|
100
|
+
#
|
101
|
+
# ```javascript
|
102
|
+
# var md = require('markdown-it')();
|
103
|
+
#
|
104
|
+
# md.renderer.rules.strong_open = function () { return '<b>'; };
|
105
|
+
# md.renderer.rules.strong_close = function () { return '</b>'; };
|
106
|
+
#
|
107
|
+
# var result = md.renderInline(...);
|
108
|
+
# ```
|
109
|
+
#
|
110
|
+
# Each rule is called as independed static function with fixed signature:
|
111
|
+
#
|
112
|
+
# ```javascript
|
113
|
+
# function my_token_render(tokens, idx, options, env, renderer) {
|
114
|
+
# // ...
|
115
|
+
# return renderedHTML;
|
116
|
+
# }
|
117
|
+
# ```
|
118
|
+
#
|
119
|
+
# See [source code](https://github.com/markdown-it/markdown-it/blob/master/lib/renderer.js)
|
120
|
+
# for more details and examples.
|
121
|
+
@rules = assign({}, @default_rules)
|
122
|
+
end
|
123
|
+
|
124
|
+
|
125
|
+
# Renderer.renderAttrs(token) -> String
|
126
|
+
#
|
127
|
+
# Render token attributes to string.
|
128
|
+
#------------------------------------------------------------------------------
|
129
|
+
def renderAttrs(token)
|
130
|
+
return '' if !token.attrs
|
131
|
+
|
132
|
+
result = ''
|
133
|
+
0.upto(token.attrs.length - 1) do |i|
|
134
|
+
result += ' ' + escapeHtml(token.attrs[i][0]) + '="' + escapeHtml(token.attrs[i][1].to_s) + '"'
|
135
|
+
end
|
136
|
+
|
137
|
+
return result
|
138
|
+
end
|
139
|
+
|
140
|
+
|
141
|
+
# Renderer.renderToken(tokens, idx, options) -> String
|
142
|
+
# - tokens (Array): list of tokens
|
143
|
+
# - idx (Numbed): token index to render
|
144
|
+
# - options (Object): params of parser instance
|
145
|
+
#
|
146
|
+
# Default token renderer. Can be overriden by custom function
|
147
|
+
# in [[Renderer#rules]].
|
148
|
+
#------------------------------------------------------------------------------
|
149
|
+
def renderToken(tokens, idx, options, env = nil, renderer = nil)
|
150
|
+
result = ''
|
151
|
+
needLf = false
|
152
|
+
token = tokens[idx]
|
153
|
+
|
154
|
+
# Tight list paragraphs
|
155
|
+
return '' if token.hidden
|
156
|
+
|
157
|
+
# Insert a newline between hidden paragraph and subsequent opening
|
158
|
+
# block-level tag.
|
159
|
+
#
|
160
|
+
# For example, here we should insert a newline before blockquote:
|
161
|
+
# - a
|
162
|
+
# >
|
163
|
+
#
|
164
|
+
if token.block && token.nesting != -1 && idx && tokens[idx - 1].hidden
|
165
|
+
result += "\n"
|
166
|
+
end
|
167
|
+
|
168
|
+
# Add token name, e.g. `<img`
|
169
|
+
result += (token.nesting == -1 ? '</' : '<') + token.tag
|
170
|
+
|
171
|
+
# Encode attributes, e.g. `<img src="foo"`
|
172
|
+
result += renderAttrs(token)
|
173
|
+
|
174
|
+
# Add a slash for self-closing tags, e.g. `<img src="foo" /`
|
175
|
+
if token.nesting == 0 && options[:xhtmlOut]
|
176
|
+
result += ' /'
|
177
|
+
end
|
178
|
+
|
179
|
+
# Check if we need to add a newline after this tag
|
180
|
+
if token.block
|
181
|
+
needLf = true
|
182
|
+
|
183
|
+
if token.nesting == 1
|
184
|
+
if idx + 1 < tokens.length
|
185
|
+
nextToken = tokens[idx + 1]
|
186
|
+
|
187
|
+
if nextToken.type == 'inline' || nextToken.hidden
|
188
|
+
# Block-level tag containing an inline tag.
|
189
|
+
#
|
190
|
+
needLf = false
|
191
|
+
|
192
|
+
elsif nextToken.nesting == -1 && nextToken.tag == token.tag
|
193
|
+
# Opening tag + closing tag of the same type. E.g. `<li></li>`.
|
194
|
+
#
|
195
|
+
needLf = false
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
|
201
|
+
result += needLf ? ">\n" : '>'
|
202
|
+
|
203
|
+
return result
|
204
|
+
end
|
205
|
+
|
206
|
+
|
207
|
+
# Renderer.renderInline(tokens, options, env) -> String
|
208
|
+
# - tokens (Array): list on block tokens to renter
|
209
|
+
# - options (Object): params of parser instance
|
210
|
+
# - env (Object): additional data from parsed input (references, for example)
|
211
|
+
#
|
212
|
+
# The same as [[Renderer.render]], but for single token of `inline` type.
|
213
|
+
#------------------------------------------------------------------------------
|
214
|
+
def renderInline(tokens, options, env)
|
215
|
+
result = ''
|
216
|
+
rules = @rules
|
217
|
+
|
218
|
+
0.upto(tokens.length - 1) do |i|
|
219
|
+
type = tokens[i].type
|
220
|
+
|
221
|
+
if rules[type] != nil
|
222
|
+
result += rules[type].call(tokens, i, options, env, self)
|
223
|
+
else
|
224
|
+
result += renderToken(tokens, i, options)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
return result;
|
229
|
+
end
|
230
|
+
|
231
|
+
|
232
|
+
# internal
|
233
|
+
# Renderer.renderInlineAsText(tokens, options, env) -> String
|
234
|
+
# - tokens (Array): list on block tokens to renter
|
235
|
+
# - options (Object): params of parser instance
|
236
|
+
# - env (Object): additional data from parsed input (references, for example)
|
237
|
+
#
|
238
|
+
# Special kludge for image `alt` attributes to conform CommonMark spec.
|
239
|
+
# Don't try to use it! Spec requires to show `alt` content with stripped markup,
|
240
|
+
# instead of simple escaping.
|
241
|
+
#------------------------------------------------------------------------------
|
242
|
+
def renderInlineAsText(tokens, options, env)
|
243
|
+
result = ''
|
244
|
+
rules = @rules
|
245
|
+
|
246
|
+
0.upto(tokens.length - 1) do |i|
|
247
|
+
if tokens[i].type == 'text'
|
248
|
+
result += rules['text'].call(tokens, i, options, env, self)
|
249
|
+
elsif tokens[i].type == 'image'
|
250
|
+
result += renderInlineAsText(tokens[i].children, options, env)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
return result
|
255
|
+
end
|
256
|
+
|
257
|
+
|
258
|
+
# Renderer.render(tokens, options, env) -> String
|
259
|
+
# - tokens (Array): list on block tokens to renter
|
260
|
+
# - options (Object): params of parser instance
|
261
|
+
# - env (Object): additional data from parsed input (references, for example)
|
262
|
+
#
|
263
|
+
# Takes token stream and generates HTML. Probably, you will never need to call
|
264
|
+
# this method directly.
|
265
|
+
#------------------------------------------------------------------------------
|
266
|
+
def render(tokens, options, env)
|
267
|
+
result = ''
|
268
|
+
rules = @rules
|
269
|
+
|
270
|
+
0.upto(tokens.length - 1) do |i|
|
271
|
+
type = tokens[i].type
|
272
|
+
|
273
|
+
if type == 'inline'
|
274
|
+
result += renderInline(tokens[i].children, options, env)
|
275
|
+
elsif rules[type] != nil
|
276
|
+
result += rules[tokens[i].type].call(tokens, i, options, env, self)
|
277
|
+
else
|
278
|
+
result += renderToken(tokens, i, options)
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
return result
|
283
|
+
end
|
284
|
+
|
285
|
+
end
|
286
|
+
end
|
@@ -0,0 +1,327 @@
|
|
1
|
+
# * class Ruler
|
2
|
+
# *
|
3
|
+
# * Helper class, used by [[MarkdownIt#core]], [[MarkdownIt#block]] and
|
4
|
+
# * [[MarkdownIt#inline]] to manage sequences of functions (rules):
|
5
|
+
# *
|
6
|
+
# * - keep rules in defined order
|
7
|
+
# * - assign the name to each rule
|
8
|
+
# * - enable/disable rules
|
9
|
+
# * - add/replace rules
|
10
|
+
# * - allow assign rules to additional named chains (in the same)
|
11
|
+
# * - cacheing lists of active rules
|
12
|
+
# *
|
13
|
+
# * You will not need use this class directly until write plugins. For simple
|
14
|
+
# * rules control use [[MarkdownIt.disable]], [[MarkdownIt.enable]] and
|
15
|
+
# * [[MarkdownIt.use]].
|
16
|
+
#------------------------------------------------------------------------------
|
17
|
+
|
18
|
+
module MarkdownIt
|
19
|
+
class Ruler
|
20
|
+
|
21
|
+
def initialize
|
22
|
+
# // List of added rules. Each element is:
|
23
|
+
# //
|
24
|
+
# // {
|
25
|
+
# // name: XXX,
|
26
|
+
# // enabled: Boolean,
|
27
|
+
# // fn: Function(),
|
28
|
+
# // alt: [ name2, name3 ]
|
29
|
+
# // }
|
30
|
+
@__rules__ = []
|
31
|
+
|
32
|
+
# // Cached rule chains.
|
33
|
+
# //
|
34
|
+
# // First level - chain name, '' for default.
|
35
|
+
# // Second level - diginal anchor for fast filtering by charcodes.
|
36
|
+
@__cache__ = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
#------------------------------------------------------------------------------
|
40
|
+
# // Helper methods, should not be used directly
|
41
|
+
|
42
|
+
|
43
|
+
# // Find rule index by name
|
44
|
+
#------------------------------------------------------------------------------
|
45
|
+
def __find__(name)
|
46
|
+
@__rules__.each_with_index do |rule, index|
|
47
|
+
return index if (rule[:name] == name)
|
48
|
+
end
|
49
|
+
return -1
|
50
|
+
end
|
51
|
+
|
52
|
+
|
53
|
+
# // Build rules lookup cache
|
54
|
+
#------------------------------------------------------------------------------
|
55
|
+
def __compile__
|
56
|
+
chains = [ '' ]
|
57
|
+
|
58
|
+
# // collect unique names
|
59
|
+
@__rules__.each do |rule|
|
60
|
+
next if !rule[:enabled]
|
61
|
+
|
62
|
+
rule[:alt].each do |altName|
|
63
|
+
if !chains.include?(altName)
|
64
|
+
chains.push(altName)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
@__cache__ = {}
|
70
|
+
|
71
|
+
chains.each do |chain|
|
72
|
+
@__cache__[chain] = []
|
73
|
+
@__rules__.each do |rule|
|
74
|
+
next if !rule[:enabled]
|
75
|
+
next if (chain && !rule[:alt].include?(chain))
|
76
|
+
|
77
|
+
@__cache__[chain].push(rule[:fn])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
# * Ruler.at(name, fn [, options])
|
84
|
+
# * - name (String): rule name to replace.
|
85
|
+
# * - fn (Function): new rule function.
|
86
|
+
# * - options (Object): new rule options (not mandatory).
|
87
|
+
# *
|
88
|
+
# * Replace rule by name with new function & options. Throws error if name not
|
89
|
+
# * found.
|
90
|
+
# *
|
91
|
+
# * ##### Options:
|
92
|
+
# *
|
93
|
+
# * - __alt__ - array with names of "alternate" chains.
|
94
|
+
# *
|
95
|
+
# * ##### Example
|
96
|
+
# *
|
97
|
+
# * Replace existing typorgapher replacement rule with new one:
|
98
|
+
# *
|
99
|
+
# * ```javascript
|
100
|
+
# * var md = require('markdown-it')();
|
101
|
+
# *
|
102
|
+
# * md.core.ruler.at('replacements', function replace(state) {
|
103
|
+
# * //...
|
104
|
+
# * });
|
105
|
+
# * ```
|
106
|
+
#------------------------------------------------------------------------------
|
107
|
+
def at(name, fn, opt = {})
|
108
|
+
index = __find__(name)
|
109
|
+
|
110
|
+
raise(StandardError, "Parser rule not found: #{name}") if index == -1
|
111
|
+
|
112
|
+
@__rules__[index][:fn] = fn
|
113
|
+
@__rules__[index][:alt] = opt[:alt] || ['']
|
114
|
+
@__cache__ = nil
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
# * Ruler.before(beforeName, ruleName, fn [, options])
|
119
|
+
# * - beforeName (String): new rule will be added before this one.
|
120
|
+
# * - ruleName (String): name of added rule.
|
121
|
+
# * - fn (Function): rule function.
|
122
|
+
# * - options (Object): rule options (not mandatory).
|
123
|
+
# *
|
124
|
+
# * Add new rule to chain before one with given name. See also
|
125
|
+
# * [[Ruler.after]], [[Ruler.push]].
|
126
|
+
# *
|
127
|
+
# * ##### Options:
|
128
|
+
# *
|
129
|
+
# * - __alt__ - array with names of "alternate" chains.
|
130
|
+
# *
|
131
|
+
# * ##### Example
|
132
|
+
# *
|
133
|
+
# * ```javascript
|
134
|
+
# * var md = require('markdown-it')();
|
135
|
+
# *
|
136
|
+
# * md.block.ruler.before('paragraph', 'my_rule', function replace(state) {
|
137
|
+
# * //...
|
138
|
+
# * });
|
139
|
+
# * ```
|
140
|
+
#------------------------------------------------------------------------------
|
141
|
+
def before(beforeName, ruleName, fn, opt = {})
|
142
|
+
index = __find__(beforeName)
|
143
|
+
|
144
|
+
raise(StandardError, "Parser rule not found: #{beforeName}") if index == -1
|
145
|
+
|
146
|
+
@__rules__.insert(index, {
|
147
|
+
name: ruleName,
|
148
|
+
enabled: true,
|
149
|
+
fn: fn,
|
150
|
+
alt: (opt[:alt] || [''])
|
151
|
+
})
|
152
|
+
|
153
|
+
@__cache__ = nil
|
154
|
+
end
|
155
|
+
|
156
|
+
|
157
|
+
# * Ruler.after(afterName, ruleName, fn [, options])
|
158
|
+
# * - afterName (String): new rule will be added after this one.
|
159
|
+
# * - ruleName (String): name of added rule.
|
160
|
+
# * - fn (Function): rule function.
|
161
|
+
# * - options (Object): rule options (not mandatory).
|
162
|
+
# *
|
163
|
+
# * Add new rule to chain after one with given name. See also
|
164
|
+
# * [[Ruler.before]], [[Ruler.push]].
|
165
|
+
# *
|
166
|
+
# * ##### Options:
|
167
|
+
# *
|
168
|
+
# * - __alt__ - array with names of "alternate" chains.
|
169
|
+
# *
|
170
|
+
# * ##### Example
|
171
|
+
# *
|
172
|
+
# * ```javascript
|
173
|
+
# * var md = require('markdown-it')();
|
174
|
+
# *
|
175
|
+
# * md.inline.ruler.after('text', 'my_rule', function replace(state) {
|
176
|
+
# * //...
|
177
|
+
# * });
|
178
|
+
# * ```
|
179
|
+
#------------------------------------------------------------------------------
|
180
|
+
def after(afterName, ruleName, fn, opt = {})
|
181
|
+
index = __find__(afterName)
|
182
|
+
|
183
|
+
raise(StandardError, "Parser rule not found: #{afterName}") if index == -1
|
184
|
+
|
185
|
+
@__rules__.insert(index + 1, {
|
186
|
+
name: ruleName,
|
187
|
+
enabled: true,
|
188
|
+
fn: fn,
|
189
|
+
alt: (opt[:alt] || [''])
|
190
|
+
})
|
191
|
+
|
192
|
+
@__cache__ = nil
|
193
|
+
end
|
194
|
+
|
195
|
+
# * Ruler.push(ruleName, fn [, options])
|
196
|
+
# * - ruleName (String): name of added rule.
|
197
|
+
# * - fn (Function): rule function.
|
198
|
+
# * - options (Object): rule options (not mandatory).
|
199
|
+
# *
|
200
|
+
# * Push new rule to the end of chain. See also
|
201
|
+
# * [[Ruler.before]], [[Ruler.after]].
|
202
|
+
# *
|
203
|
+
# * ##### Options:
|
204
|
+
# *
|
205
|
+
# * - __alt__ - array with names of "alternate" chains.
|
206
|
+
# *
|
207
|
+
# * ##### Example
|
208
|
+
# *
|
209
|
+
# * ```javascript
|
210
|
+
# * var md = require('markdown-it')();
|
211
|
+
# *
|
212
|
+
# * md.core.ruler.push('emphasis', 'my_rule', function replace(state) {
|
213
|
+
# * //...
|
214
|
+
# * });
|
215
|
+
# * ```
|
216
|
+
#------------------------------------------------------------------------------
|
217
|
+
def push(ruleName, fn, opt = {})
|
218
|
+
@__rules__.push({
|
219
|
+
name: ruleName,
|
220
|
+
enabled: true,
|
221
|
+
fn: fn,
|
222
|
+
alt: (opt[:alt] ? [''] + opt[:alt] : [''])
|
223
|
+
})
|
224
|
+
@__cache__ = nil
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
# * Ruler.enable(list [, ignoreInvalid]) -> Array
|
229
|
+
# * - list (String|Array): list of rule names to enable.
|
230
|
+
# * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
|
231
|
+
# *
|
232
|
+
# * Enable rules with given names. If any rule name not found - throw Error.
|
233
|
+
# * Errors can be disabled by second param.
|
234
|
+
# *
|
235
|
+
# * Returns list of found rule names (if no exception happened).
|
236
|
+
# *
|
237
|
+
# * See also [[Ruler.disable]], [[Ruler.enableOnly]].
|
238
|
+
#------------------------------------------------------------------------------
|
239
|
+
def enable(list, ignoreInvalid = false)
|
240
|
+
list = [ list ] if !list.is_a?(Array)
|
241
|
+
result = []
|
242
|
+
|
243
|
+
# // Search by name and enable
|
244
|
+
list.each do |name|
|
245
|
+
idx = __find__(name)
|
246
|
+
|
247
|
+
if idx < 0
|
248
|
+
next if ignoreInvalid
|
249
|
+
raise(StandardError, "Rules manager: invalid rule name #{name}")
|
250
|
+
end
|
251
|
+
@__rules__[idx][:enabled] = true
|
252
|
+
result.push(name)
|
253
|
+
end
|
254
|
+
|
255
|
+
@__cache__ = nil
|
256
|
+
return result
|
257
|
+
end
|
258
|
+
|
259
|
+
|
260
|
+
# * Ruler.enableOnly(list [, ignoreInvalid])
|
261
|
+
# * - list (String|Array): list of rule names to enable (whitelist).
|
262
|
+
# * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
|
263
|
+
# *
|
264
|
+
# * Enable rules with given names, and disable everything else. If any rule name
|
265
|
+
# * not found - throw Error. Errors can be disabled by second param.
|
266
|
+
# *
|
267
|
+
# * See also [[Ruler.disable]], [[Ruler.enable]].
|
268
|
+
#------------------------------------------------------------------------------
|
269
|
+
def enableOnly(list, ignoreInvalid = false)
|
270
|
+
list = [ list ] if !list.is_a?(Array)
|
271
|
+
|
272
|
+
@__rules__.each { |rule| rule[:enabled] = false }
|
273
|
+
|
274
|
+
enable(list, ignoreInvalid)
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
# * Ruler.disable(list [, ignoreInvalid]) -> Array
|
279
|
+
# * - list (String|Array): list of rule names to disable.
|
280
|
+
# * - ignoreInvalid (Boolean): set `true` to ignore errors when rule not found.
|
281
|
+
# *
|
282
|
+
# * Disable rules with given names. If any rule name not found - throw Error.
|
283
|
+
# * Errors can be disabled by second param.
|
284
|
+
# *
|
285
|
+
# * Returns list of found rule names (if no exception happened).
|
286
|
+
# *
|
287
|
+
# * See also [[Ruler.enable]], [[Ruler.enableOnly]].
|
288
|
+
#------------------------------------------------------------------------------
|
289
|
+
def disable(list, ignoreInvalid = false)
|
290
|
+
list = [ list ] if !list.is_a?(Array)
|
291
|
+
result = []
|
292
|
+
|
293
|
+
# // Search by name and disable
|
294
|
+
list.each do |name|
|
295
|
+
idx = __find__(name)
|
296
|
+
|
297
|
+
if idx < 0
|
298
|
+
next if ignoreInvalid
|
299
|
+
raise(StandardError, "Rules manager: invalid rule name #{name}")
|
300
|
+
end
|
301
|
+
@__rules__[idx][:enabled] = false
|
302
|
+
result.push(name)
|
303
|
+
end
|
304
|
+
|
305
|
+
@__cache__ = nil
|
306
|
+
return result
|
307
|
+
end
|
308
|
+
|
309
|
+
|
310
|
+
# * Ruler.getRules(chainName) -> Array
|
311
|
+
# *
|
312
|
+
# * Return array of active functions (rules) for given chain name. It analyzes
|
313
|
+
# * rules configuration, compiles caches if not exists and returns result.
|
314
|
+
# *
|
315
|
+
# * Default chain name is `''` (empty string). It can't be skipped. That's
|
316
|
+
# * done intentionally, to keep signature monomorphic for high speed.
|
317
|
+
#------------------------------------------------------------------------------
|
318
|
+
def getRules(chainName)
|
319
|
+
if @__cache__ == nil
|
320
|
+
__compile__
|
321
|
+
end
|
322
|
+
|
323
|
+
# // Chain can be empty, if rules disabled. But we still have to return Array.
|
324
|
+
return @__cache__[chainName] || []
|
325
|
+
end
|
326
|
+
end
|
327
|
+
end
|