motion-markdown-it 0.4.0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|