marked 2.0.7 → 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
@@ -141,46 +141,114 @@ marked.defaults = defaults;
141
141
  * Use Extension
142
142
  */
143
143
 
144
- marked.use = function(extension) {
145
- const opts = merge({}, extension);
146
- if (extension.renderer) {
147
- const renderer = marked.defaults.renderer || new Renderer();
148
- for (const prop in extension.renderer) {
149
- const prevRenderer = renderer[prop];
150
- renderer[prop] = (...args) => {
151
- let ret = extension.renderer[prop].apply(renderer, args);
152
- if (ret === false) {
153
- 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');
154
156
  }
155
- return ret;
156
- };
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
+ });
157
201
  }
158
- opts.renderer = renderer;
159
- }
160
- if (extension.tokenizer) {
161
- const tokenizer = marked.defaults.tokenizer || new Tokenizer();
162
- for (const prop in extension.tokenizer) {
163
- const prevTokenizer = tokenizer[prop];
164
- tokenizer[prop] = (...args) => {
165
- let ret = extension.tokenizer[prop].apply(tokenizer, args);
166
- if (ret === false) {
167
- 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);
168
242
  }
169
- return ret;
170
243
  };
171
244
  }
172
- opts.tokenizer = tokenizer;
173
- }
174
- if (extension.walkTokens) {
175
- const walkTokens = marked.defaults.walkTokens;
176
- opts.walkTokens = (token) => {
177
- extension.walkTokens(token);
178
- if (walkTokens) {
179
- walkTokens(token);
180
- }
181
- };
182
- }
183
- marked.setOptions(opts);
245
+
246
+ if (hasExtensions) {
247
+ opts.extensions = extensions;
248
+ }
249
+
250
+ marked.setOptions(opts);
251
+ });
184
252
  };
185
253
 
186
254
  /**
@@ -207,7 +275,12 @@ marked.walkTokens = function(tokens, callback) {
207
275
  break;
208
276
  }
209
277
  default: {
210
- 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]) {
211
284
  marked.walkTokens(token.tokens, callback);
212
285
  }
213
286
  }