marked 2.0.4 → 2.1.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.
package/src/marked.js CHANGED
@@ -51,6 +51,9 @@ function marked(src, opt, callback) {
51
51
 
52
52
  if (!err) {
53
53
  try {
54
+ if (opt.walkTokens) {
55
+ marked.walkTokens(tokens, opt.walkTokens);
56
+ }
54
57
  out = Parser.parse(tokens, opt);
55
58
  } catch (e) {
56
59
  err = e;
@@ -138,46 +141,114 @@ marked.defaults = defaults;
138
141
  * Use Extension
139
142
  */
140
143
 
141
- marked.use = function(extension) {
142
- const opts = merge({}, extension);
143
- if (extension.renderer) {
144
- const renderer = marked.defaults.renderer || new Renderer();
145
- for (const prop in extension.renderer) {
146
- const prevRenderer = renderer[prop];
147
- renderer[prop] = (...args) => {
148
- let ret = extension.renderer[prop].apply(renderer, args);
149
- if (ret === false) {
150
- ret = prevRenderer.apply(renderer, args);
144
+ marked.use = function(...args) {
145
+ const opts = merge({}, ...args);
146
+ const extensions = marked.defaults.extensions || { renderers: {}, childTokens: {} };
147
+ let hasExtensions;
148
+
149
+ args.forEach((pack) => {
150
+ // ==-- Parse "addon" extensions --== //
151
+ if (pack.extensions) {
152
+ hasExtensions = true;
153
+ pack.extensions.forEach((ext) => {
154
+ if (!ext.name) {
155
+ throw new Error('extension name required');
151
156
  }
152
- return ret;
153
- };
157
+ if (ext.renderer) { // Renderer extensions
158
+ const prevRenderer = extensions.renderers?.[ext.name];
159
+ if (prevRenderer) {
160
+ // Replace extension with func to run new extension but fall back if false
161
+ extensions.renderers[ext.name] = function(...args) {
162
+ let ret = ext.renderer.apply(this, args);
163
+ if (ret === false) {
164
+ ret = prevRenderer.apply(this, args);
165
+ }
166
+ return ret;
167
+ };
168
+ } else {
169
+ extensions.renderers[ext.name] = ext.renderer;
170
+ }
171
+ }
172
+ if (ext.tokenizer) { // Tokenizer Extensions
173
+ if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {
174
+ throw new Error("extension level must be 'block' or 'inline'");
175
+ }
176
+ if (extensions[ext.level]) {
177
+ extensions[ext.level].unshift(ext.tokenizer);
178
+ } else {
179
+ extensions[ext.level] = [ext.tokenizer];
180
+ }
181
+ if (ext.start) { // Function to check for start of token
182
+ if (ext.level === 'block') {
183
+ if (extensions.startBlock) {
184
+ extensions.startBlock.push(ext.start);
185
+ } else {
186
+ extensions.startBlock = [ext.start];
187
+ }
188
+ } else if (ext.level === 'inline') {
189
+ if (extensions.startInline) {
190
+ extensions.startInline.push(ext.start);
191
+ } else {
192
+ extensions.startInline = [ext.start];
193
+ }
194
+ }
195
+ }
196
+ }
197
+ if (ext.childTokens) { // Child tokens to be visited by walkTokens
198
+ extensions.childTokens[ext.name] = ext.childTokens;
199
+ }
200
+ });
154
201
  }
155
- opts.renderer = renderer;
156
- }
157
- if (extension.tokenizer) {
158
- const tokenizer = marked.defaults.tokenizer || new Tokenizer();
159
- for (const prop in extension.tokenizer) {
160
- const prevTokenizer = tokenizer[prop];
161
- tokenizer[prop] = (...args) => {
162
- let ret = extension.tokenizer[prop].apply(tokenizer, args);
163
- if (ret === false) {
164
- ret = prevTokenizer.apply(tokenizer, args);
202
+
203
+ // ==-- Parse "overwrite" extensions --== //
204
+ if (pack.renderer) {
205
+ const renderer = marked.defaults.renderer || new Renderer();
206
+ for (const prop in pack.renderer) {
207
+ const prevRenderer = renderer[prop];
208
+ // Replace renderer with func to run extension, but fall back if false
209
+ renderer[prop] = (...args) => {
210
+ let ret = pack.renderer[prop].apply(renderer, args);
211
+ if (ret === false) {
212
+ ret = prevRenderer.apply(renderer, args);
213
+ }
214
+ return ret;
215
+ };
216
+ }
217
+ opts.renderer = renderer;
218
+ }
219
+ if (pack.tokenizer) {
220
+ const tokenizer = marked.defaults.tokenizer || new Tokenizer();
221
+ for (const prop in pack.tokenizer) {
222
+ const prevTokenizer = tokenizer[prop];
223
+ // Replace tokenizer with func to run extension, but fall back if false
224
+ tokenizer[prop] = (...args) => {
225
+ let ret = pack.tokenizer[prop].apply(tokenizer, args);
226
+ if (ret === false) {
227
+ ret = prevTokenizer.apply(tokenizer, args);
228
+ }
229
+ return ret;
230
+ };
231
+ }
232
+ opts.tokenizer = tokenizer;
233
+ }
234
+
235
+ // ==-- Parse WalkTokens extensions --== //
236
+ if (pack.walkTokens) {
237
+ const walkTokens = marked.defaults.walkTokens;
238
+ opts.walkTokens = (token) => {
239
+ pack.walkTokens.call(this, token);
240
+ if (walkTokens) {
241
+ walkTokens(token);
165
242
  }
166
- return ret;
167
243
  };
168
244
  }
169
- opts.tokenizer = tokenizer;
170
- }
171
- if (extension.walkTokens) {
172
- const walkTokens = marked.defaults.walkTokens;
173
- opts.walkTokens = (token) => {
174
- extension.walkTokens(token);
175
- if (walkTokens) {
176
- walkTokens(token);
177
- }
178
- };
179
- }
180
- marked.setOptions(opts);
245
+
246
+ if (hasExtensions) {
247
+ opts.extensions = extensions;
248
+ }
249
+
250
+ marked.setOptions(opts);
251
+ });
181
252
  };
182
253
 
183
254
  /**
@@ -204,7 +275,12 @@ marked.walkTokens = function(tokens, callback) {
204
275
  break;
205
276
  }
206
277
  default: {
207
- if (token.tokens) {
278
+ if (marked.defaults?.extensions?.childTokens?.[token.type]) { // Walk any extensions
279
+ marked.defaults?.extensions.childTokens[token.type].forEach(function(childTokens) {
280
+ marked.walkTokens(token[childTokens], callback);
281
+ });
282
+ }
283
+ if (token.tokens && !marked.defaults?.extensions?.childTokens[token.type]) {
208
284
  marked.walkTokens(token.tokens, callback);
209
285
  }
210
286
  }
package/src/rules.js CHANGED
@@ -176,9 +176,9 @@ const inline = {
176
176
  emStrong: {
177
177
  lDelim: /^(?:\*+(?:([punct_])|[^\s*]))|^_+(?:([punct*])|([^\s_]))/,
178
178
  // (1) and (2) can only be a Right Delimiter. (3) and (4) can only be Left. (5) and (6) can be either Left or Right.
179
- // () Skip other delimiter (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
180
- rDelimAst: /\_\_[^_]*?\*[^_]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
181
- rDelimUnd: /\*\*[^*]*?\_[^*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
179
+ // () Skip other delimiter (1) #*** (2) a***#, a*** (3) #***a, ***a (4) ***# (5) #***# (6) a***a
180
+ rDelimAst: /\_\_[^_*]*?\*[^_*]*?\_\_|[punct_](\*+)(?=[\s]|$)|[^punct*_\s](\*+)(?=[punct_\s]|$)|[punct_\s](\*+)(?=[^punct*_\s])|[\s](\*+)(?=[punct_])|[punct_](\*+)(?=[punct_])|[^punct*_\s](\*+)(?=[^punct*_\s])/,
181
+ rDelimUnd: /\*\*[^_*]*?\_[^_*]*?\*\*|[punct*](\_+)(?=[\s]|$)|[^punct*_\s](\_+)(?=[punct*\s]|$)|[punct*\s](\_+)(?=[^punct*_\s])|[\s](\_+)(?=[punct*])|[punct*](\_+)(?=[punct*])/ // ^- Not allowed for _
182
182
  },
183
183
  code: /^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,
184
184
  br: /^( {2,}|\\)\n(?!\s*$)/,
@@ -286,7 +286,7 @@ inline.gfm = merge({}, inline.normal, {
286
286
  url: /^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,
287
287
  _backpedal: /(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,
288
288
  del: /^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,
289
- text: /^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@))/
289
+ text: /^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/
290
290
  });
291
291
 
292
292
  inline.gfm.url = edit(inline.gfm.url, 'i')