md2org 1.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.
@@ -0,0 +1,500 @@
1
+ /*
2
+ * org-render: walks a CommonMark AST and emits Org.
3
+ *
4
+ * Literal text is copied; the few escapes live in org-escape. This file handles
5
+ * structure: the block-context stack, indentation and blank lines. Blank lines
6
+ * follow the source, using sourcepos, rather than being emitted at every block
7
+ * boundary.
8
+ */
9
+
10
+ /* --8<-- core start */
11
+
12
+ function fnLabel(s) {
13
+ return String(s).trim().toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "") || "fn";
14
+ }
15
+
16
+ function renderOrg(ast, esc) {
17
+ // A reference converts only if a matching definition exists, so definitions
18
+ // are collected first. Labels that sanitise to the same Org label ("x y" and
19
+ // "x-y") get a counter to keep them distinct.
20
+ var defined = {}, taken = {}, w0 = ast.walker(), e0, raw, lab, n;
21
+ while ((e0 = w0.next())) {
22
+ if (!e0.entering || e0.node.type !== "footnote_definition") continue;
23
+ raw = e0.node._label;
24
+ if (defined[raw] !== undefined) continue;
25
+ lab = fnLabel(raw); n = 1;
26
+ while (taken[lab]) { n++; lab = fnLabel(raw) + "-" + n; }
27
+ taken[lab] = 1;
28
+ defined[raw] = lab;
29
+ }
30
+ function fnRef(r) { return defined[r] !== undefined ? defined[r] : null; }
31
+
32
+ if (!renderOrg.warn) renderOrg.warn = {};
33
+ var out = [];
34
+ var line = "";
35
+ var indent = [];
36
+ var listStack = [];
37
+ var linkDepth = 0; // inside a link description
38
+ var nestedSkip = 0; // inside a nested link or image whose children are suppressed
39
+ var bareDesc = 0; // inside a link emitted as its description text only
40
+ var emptyDesc = 0; // inside a link with no description
41
+ var atLineStart = true; // nothing but indentation emitted on this line yet
42
+ var inPara = false; // inside a paragraph, where footnotes are recognised
43
+ var lastEnd = 0; // source line on which the previous block ended
44
+ var inCell = false;
45
+ var inFnDef = false;
46
+ var quoteDepth = 0; // inside a quote block
47
+ var boldHeading = 0; // current heading is being written as bold text
48
+ var inHeading = 0; // inside a heading node
49
+ var authored = false; // this line carries text the author wrote
50
+ var authoredLine = ""; // just the authored part of it
51
+ var declaredHeadline = false; // md2org emitted a headline on this line, on purpose
52
+ var declaredComment = false; // md2org emitted an Org comment on this line, on purpose
53
+ var inVerbatim = false; // emitting the body of a block Org does not parse
54
+ var descStart = -1; // index in the current line where the description begins
55
+ function warnAt(k) {
56
+ var a = renderOrg.warn[k] || (renderOrg.warn[k] = []), n = out.length + 1;
57
+ if (a[a.length - 1] !== n) a.push(n);
58
+ }
59
+
60
+ function pad() { return indent.join(""); }
61
+
62
+ // Invariant 4. Warns when an escape changed its input, which attributes the
63
+ // finding to the construct that caused it rather than to the finished line.
64
+ function ent(before, after, name) {
65
+ if (before !== after) warnAt(name);
66
+ return after;
67
+ }
68
+ function push(s) { if (s) { line += s; atLineStart = false; } }
69
+
70
+ function endLine() {
71
+ // GFM task list. The parser does not recognise the box, so it is corrected
72
+ // on the assembled line. Org recognises "[X]" but not "[x]".
73
+ if (listStack.length) line = line.replace(/^(\s*(?:-|\d+\.) )\[x\] /, "$1[X] ");
74
+ // Warn on any line Org reads as a headline, unless md2org declared it. The
75
+ // test is on the output line because only the line determines what Org does:
76
+ // generated emphasis markup can also produce leading asterisks ("__** * **__").
77
+ if (!declaredHeadline && /^\*+\s/.test(line)) warnAt("heading");
78
+ // Warn on any line Org reads as a comment, which drops it from every export.
79
+ // The usual source is "\#", CommonMark's escape for a literal hash: the parser
80
+ // consumes the backslash and leaves a bare "#". Org requires "#" followed by
81
+ // whitespace or end of line, so "#1" and "#+TITLE:" do not match. Exempt:
82
+ // comments md2org emitted, and verbatim block bodies, where Org parses none.
83
+ if (!declaredComment && !inVerbatim && /^[ \t]*#(\s|$)/.test(line)) warnAt("comment");
84
+ // An authored block delimiter can pair with one md2org emitted. Block bodies
85
+ // are comma-quoted, so only authored text can reach this.
86
+ if (authored && /^[ \t]*#\+(BEGIN|END)_/i.test(line)) warnAt("stray block delimiter");
87
+ // Org reads "[[…]]" as a link. Tested against authored text only, because
88
+ // every link md2org emits has that form.
89
+ if (/\[\[[^\]]*\]\]/.test(authoredLine)) warnAt("[[ ]] read as an Org link");
90
+ authored = false;
91
+ authoredLine = "";
92
+ declaredHeadline = false;
93
+ declaredComment = false;
94
+ out.push(line);
95
+ line = "";
96
+ atLineStart = true;
97
+ }
98
+
99
+ // Close any open line before a block starts, so that a heading after an empty
100
+ // list item is not emitted as "- * H".
101
+ function flush() { if (line !== "") endLine(); }
102
+
103
+ function blank() {
104
+ if (out.length && out[out.length - 1] !== "") out.push("");
105
+ }
106
+
107
+ // Emit the blank line separating this block from the previous one, but only if
108
+ // the source had one.
109
+ function spaceBefore(node) {
110
+ var sp = node.sourcepos;
111
+ if (!sp) { blank(); return; }
112
+ if (lastEnd && sp[0][0] > lastEnd + 1) blank();
113
+ }
114
+ function noteEnd(node) {
115
+ if (node.sourcepos) lastEnd = node.sourcepos[1][0];
116
+ }
117
+
118
+ // Literal text is copied unchanged (DESIGN.md, Invariant 1).
119
+ function text(s) {
120
+ var t = inCell ? ent(s, esc.escapeCell(s), "\\| in a table cell") : s;
121
+ // Accumulated across nodes: a backslash escape is its own text node, so
122
+ // "[a\\]\\]b](/u)" arrives as "a", "]", "]", "b" and no node holds "]]".
123
+ authored = true;
124
+ authoredLine += t;
125
+ push(t);
126
+ }
127
+
128
+ // Close a bracket link. A description that contains "]]", or ends in "]" and so
129
+ // forms "]]" with the closer, ends the link early. Org has no escape for this,
130
+ // so it is reported.
131
+ function closeLink() {
132
+ var desc = descStart >= 0 ? line.slice(descStart) : "";
133
+ if (desc.indexOf("]]") !== -1 || desc.slice(-1) === "]")
134
+ warnAt("]] in a link description");
135
+ descStart = -1;
136
+ push("]]");
137
+ }
138
+
139
+ // Emits the body of a block Org does not parse: an export, src or example
140
+ // block. Quote block contents are walked instead, which lets the comment check
141
+ // in endLine tell the two apart.
142
+ function emitBlockLines(str) {
143
+ inVerbatim = true;
144
+ str.replace(/\n$/, "").split("\n").forEach(function (l) {
145
+ push(pad() + l);
146
+ endLine();
147
+ });
148
+ inVerbatim = false;
149
+ }
150
+
151
+ // An HTML comment block becomes Org comment lines rather than an export block.
152
+ function htmlComment(literal) {
153
+ var raw = literal.replace(/\n$/, "");
154
+ // An HTML block may be indented up to three spaces; the literal keeps them.
155
+ var open = /^ {0,3}<!--/.exec(raw);
156
+ if (!open) return false;
157
+ // The block ends on the line containing "-->", so any text after it is part
158
+ // of the literal. A comment would drop that text, so it goes to an export
159
+ // block instead.
160
+ var cut = raw.indexOf("-->");
161
+ if (cut !== -1 && !/^\s*$/.test(raw.slice(cut + 3))) return false;
162
+ var body = raw.slice(open[0].length, cut === -1 ? undefined : cut);
163
+ // A run of comment lines, not a comment block. Org strips "#" and one space
164
+ // on read, so the body survives exactly without comma-quoting, which Org does
165
+ // not reverse in a comment block. No body line can start another construct.
166
+ body.split("\n").forEach(function (l) {
167
+ push(pad() + (l ? "# " + l : "#"));
168
+ declaredComment = true;
169
+ endLine();
170
+ });
171
+ return true;
172
+ }
173
+
174
+ var walker = ast.walker(), ev, node, type;
175
+
176
+ while ((ev = walker.next())) {
177
+ node = ev.node;
178
+ type = node.type;
179
+
180
+ switch (type) {
181
+ case "text":
182
+ if (nestedSkip === 0) text(node.literal, node);
183
+ break;
184
+
185
+ case "softbreak":
186
+ // Footnote definitions and headlines (§Headings) are single lines, so a
187
+ // soft break inside one becomes a space. Otherwise a multi-line setext
188
+ // heading ("foo\nbar\n===") would be truncated.
189
+ if (inFnDef) { push(" "); break; }
190
+ if (inHeading) { push(" "); break; }
191
+ endLine();
192
+ push(pad());
193
+ atLineStart = true;
194
+ break;
195
+
196
+ case "linebreak":
197
+ push("\\\\");
198
+ endLine();
199
+ push(pad());
200
+ atLineStart = true;
201
+ break;
202
+
203
+ case "code":
204
+ // A code span holding "|" in a table cell loses its monospace: CONTENTS
205
+ // is a literal string (§Text Markup), so no escape works inside the
206
+ // delimiters. The characters are emitted bare and warned.
207
+ var lit = node.literal, span, bare;
208
+ if (inCell && lit.indexOf("|") !== -1) {
209
+ span = ent(lit, esc.escapeCell(lit), "\\| in a table cell");
210
+ bare = true;
211
+ } else {
212
+ span = esc.codeSpan(lit);
213
+ // codeSpan returns the text unchanged when it holds both "=" and "~".
214
+ bare = span === lit;
215
+ }
216
+ authored = true;
217
+ // Only a span emitted without delimiters can be read as Org markup;
218
+ // "=[[Some Page]]=" is not a link.
219
+ if (bare) authoredLine += span;
220
+ push(span);
221
+ break;
222
+
223
+ case "math":
224
+ // LaTeX math is copied verbatim; Org reads "\(…\)" and "\[…\]" as LaTeX
225
+ // fragments. Line breaks follow softbreak's rules. In a table cell the
226
+ // text goes through escapeCell like any other.
227
+ var ml = node.literal.split("\n"), mi;
228
+ authored = true;
229
+ for (mi = 0; mi < ml.length; mi++) {
230
+ if (mi) {
231
+ if (inFnDef || inHeading) push(" ");
232
+ else { endLine(); push(pad()); }
233
+ }
234
+ push(inCell ? ent(ml[mi], esc.escapeCell(ml[mi]), "\\| in a table cell") : ml[mi]);
235
+ }
236
+ break;
237
+
238
+ case "emph":
239
+ push("/");
240
+ break;
241
+
242
+ case "footnote_definition":
243
+ if (ev.entering) {
244
+ // Consecutive definitions are separated by a blank line for readability.
245
+ flush();
246
+ if (node.prev && node.prev.type === "footnote_definition") blank();
247
+ else spaceBefore(node);
248
+ push(pad() + "[fn:" + fnRef(node._label) + "] ");
249
+ inFnDef = true;
250
+ } else {
251
+ inFnDef = false;
252
+ line = line.replace(/[ \t]+$/, "");
253
+ // Org ends a definition at a blank line; without one the next
254
+ // paragraph is absorbed into the footnote.
255
+ endLine(); blank(); noteEnd(node);
256
+ }
257
+ break;
258
+
259
+ case "footnote_reference":
260
+ push(fnRef(node._label)
261
+ ? "[fn:" + fnRef(node._label) + "]" : "[^" + node._label + "]");
262
+ break;
263
+
264
+ case "table":
265
+ if (ev.entering) { flush(); spaceBefore(node); } else { noteEnd(node); }
266
+ break;
267
+
268
+ case "table_row":
269
+ if (ev.entering) {
270
+ push(pad() + "|");
271
+ } else {
272
+ endLine();
273
+ // Org's rule row goes under the heading, and carries the column count.
274
+ if (node._isHeading) {
275
+ var segs = [], cookies = [], any = false, cell = node.firstChild;
276
+ while (cell) {
277
+ segs.push("----");
278
+ cookies.push(cell._align === "center" ? " <c> "
279
+ : cell._align === "right" ? " <r> "
280
+ : cell._align === "left" ? " <l> " : " ");
281
+ if (cell._align) any = true;
282
+ cell = cell.next;
283
+ }
284
+ push(pad() + "|" + segs.join("+") + "|"); endLine();
285
+ if (any) { push(pad() + "|" + cookies.join("|") + "|"); endLine(); }
286
+ }
287
+ }
288
+ break;
289
+
290
+ case "table_cell":
291
+ // Text inside a cell goes through escapeCell (see text()).
292
+ inCell = ev.entering;
293
+ if (ev.entering) push(" "); else push(" |");
294
+ break;
295
+
296
+ case "strikethrough":
297
+ push("+");
298
+ break;
299
+
300
+ case "strong":
301
+ push("*");
302
+ break;
303
+
304
+ // Links and images share one path: an Org image is a link to a displayable
305
+ // file. Alt text becomes the description; a Markdown title is dropped.
306
+ case "link":
307
+ case "image":
308
+ if (ev.entering) {
309
+ if (linkDepth > 0) {
310
+ // A description may contain another link only as a plain or angle
311
+ // link (§Regular Link). A nested link or image, typically a badge,
312
+ // contributes its destination as the description; its own text is
313
+ // dropped.
314
+ push(esc.escapeLinkPath(node.destination));
315
+ nestedSkip++;
316
+ } else if (node.destination && !node.firstChild) {
317
+ // A description must hold at least one object, so an empty one uses
318
+ // the path-only form.
319
+ push("[[" + esc.escapeLinkPath(node.destination));
320
+ emptyDesc++;
321
+ } else if (!node.destination || node.destination[0] === "#") {
322
+ // No link is possible, so the description is emitted as text. An
323
+ // empty PATHREG is not a link (§Regular Link), and a "#anchor" needs a
324
+ // CUSTOM_ID property that Markdown does not declare; an unresolvable
325
+ // link makes the whole export fail.
326
+ bareDesc++;
327
+ } else {
328
+ push("[[" + esc.escapeLinkPath(node.destination) + "][");
329
+ if (linkDepth === 0) descStart = line.length;
330
+ }
331
+ linkDepth++;
332
+ } else {
333
+ linkDepth--;
334
+ if (linkDepth > 0) nestedSkip--;
335
+ else if (bareDesc) bareDesc--;
336
+ else if (emptyDesc) { emptyDesc--; push("]]"); }
337
+ else closeLink();
338
+ }
339
+ break;
340
+
341
+ case "html_inline":
342
+ // No Org object corresponds to raw inline HTML; an export snippet keeps it
343
+ // for HTML export and hides it elsewhere.
344
+ push("@@html:" + node.literal + "@@");
345
+ break;
346
+
347
+ case "html_block":
348
+ flush();
349
+ spaceBefore(node);
350
+ if (!htmlComment(node.literal)) {
351
+ push(pad() + "#+BEGIN_EXPORT html"); endLine();
352
+ // Export block contents are raw text, so "*" and "#+" lines are
353
+ // comma-quoted.
354
+ emitBlockLines(esc.protectBlockBody(node.literal));
355
+ push(pad() + "#+END_EXPORT"); endLine();
356
+ }
357
+ noteEnd(node);
358
+ break;
359
+
360
+ case "paragraph":
361
+ if (ev.entering) {
362
+ // Blank lines follow the source, which keeps loose lists loose.
363
+ if (!inFnDef) spaceBefore(node);
364
+ // A list item or footnote definition has already written its marker
365
+ // onto this line.
366
+ if (line === "") line += pad();
367
+ atLineStart = true;
368
+ inPara = true;
369
+ } else {
370
+ // Footnote definition paragraphs are joined, because a blank line
371
+ // would end the definition.
372
+ if (inFnDef) push(" "); else endLine();
373
+ inPara = false;
374
+ noteEnd(node);
375
+ }
376
+ break;
377
+
378
+ case "heading":
379
+ if (ev.entering) {
380
+ inHeading++;
381
+ // A headline must start at column 0 (§Headings), so a heading inside a
382
+ // quote or list item would end the enclosing block. It is emitted as
383
+ // bold text instead, and its level is lost.
384
+ boldHeading = quoteDepth || listStack.length;
385
+ if (boldHeading) {
386
+ if (!listStack.length) spaceBefore(node);
387
+ if (line === "") line += pad();
388
+ push("*");
389
+ } else {
390
+ flush();
391
+ spaceBefore(node);
392
+ push("*".repeat(node.level) + " ");
393
+ declaredHeadline = true;
394
+ }
395
+ } else {
396
+ if (boldHeading) {
397
+ // An empty heading would leave "**": neither markup nor text.
398
+ if (line.slice(-1) === "*") line = line.slice(0, -1); else push("*");
399
+ }
400
+ inHeading--;
401
+ endLine();
402
+ noteEnd(node);
403
+ }
404
+ break;
405
+
406
+ case "code_block":
407
+ flush();
408
+ spaceBefore(node);
409
+ // Only the first word is the language; Org reads the rest of the line as
410
+ // switches and header arguments. "{r setup}" gives "r".
411
+ var info = (node.info || "").trim().split(/[\s{}]+/).filter(Boolean)[0] || "";
412
+ // Org requires a LANGUAGE on a source block (§Lesser Elements), so a bare
413
+ // fence becomes an example block rather than an empty #+BEGIN_SRC.
414
+ push(pad() + (info ? "#+BEGIN_SRC " + info : "#+BEGIN_EXAMPLE"));
415
+ endLine();
416
+ emitBlockLines(esc.protectBlockBody(node.literal));
417
+ push(pad() + (info ? "#+END_SRC" : "#+END_EXAMPLE"));
418
+ endLine();
419
+ noteEnd(node);
420
+ break;
421
+
422
+ case "thematic_break":
423
+ flush();
424
+ spaceBefore(node);
425
+ push(pad() + "-----"); endLine();
426
+ noteEnd(node);
427
+ break;
428
+
429
+ case "block_quote":
430
+ if (ev.entering) {
431
+ flush();
432
+ spaceBefore(node);
433
+ push(pad() + "#+BEGIN_QUOTE"); endLine();
434
+ quoteDepth++;
435
+ // Measure the first inner paragraph's gap from the quote's opening line.
436
+ if (node.sourcepos) lastEnd = node.sourcepos[0][0];
437
+ } else {
438
+ quoteDepth--;
439
+ // An empty list item can leave its bullet on an open line; flush it so
440
+ // the delimiter starts a line of its own.
441
+ flush();
442
+ push(pad() + "#+END_QUOTE"); endLine();
443
+ noteEnd(node);
444
+ }
445
+ break;
446
+
447
+ case "list":
448
+ if (ev.entering) {
449
+ if (!listStack.length) spaceBefore(node);
450
+ listStack.push({
451
+ ordered: node.listType === "ordered",
452
+ n: (node.listStart === null || node.listStart === undefined) ? 1 : node.listStart,
453
+ first: true
454
+ });
455
+ } else {
456
+ listStack.pop();
457
+ noteEnd(node);
458
+ }
459
+ break;
460
+
461
+ case "item":
462
+ if (ev.entering) {
463
+ flush();
464
+ var st = listStack[listStack.length - 1];
465
+ var bullet;
466
+ if (st.ordered) {
467
+ // Org takes a non-1 start via the [@n] counter cookie.
468
+ bullet = st.n + ". ";
469
+ if (st.first && st.n !== 1) bullet += "[@" + st.n + "] ";
470
+ st.n++;
471
+ } else {
472
+ bullet = "- ";
473
+ }
474
+ st.first = false;
475
+ line += pad() + bullet;
476
+ indent.push(" ".repeat(bullet.length));
477
+ atLineStart = true;
478
+ } else {
479
+ indent.pop();
480
+ }
481
+ break;
482
+
483
+ default:
484
+ break;
485
+ }
486
+ }
487
+
488
+ if (line !== "") endLine();
489
+
490
+ while (out.length && out[0] === "") out.shift();
491
+ while (out.length && out[out.length - 1] === "") out.pop();
492
+
493
+ return out.join("\n");
494
+ }
495
+
496
+ /* --8<-- core end */
497
+
498
+ if (typeof module !== "undefined" && module.exports) {
499
+ module.exports = renderOrg;
500
+ }
@@ -0,0 +1,89 @@
1
+ Copyright (c) 2014, John MacFarlane
2
+
3
+ All rights reserved.
4
+
5
+ Redistribution and use in source and binary forms, with or without
6
+ modification, are permitted provided that the following conditions are met:
7
+
8
+ * Redistributions of source code must retain the above copyright
9
+ notice, this list of conditions and the following disclaimer.
10
+
11
+ * Redistributions in binary form must reproduce the above
12
+ copyright notice, this list of conditions and the following
13
+ disclaimer in the documentation and/or other materials provided
14
+ with the distribution.
15
+
16
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27
+
28
+ ---
29
+
30
+ lib/from-code-point.js is derived from a polyfill
31
+ Copyright Mathias Bynens <http://mathiasbynens.be/>
32
+
33
+ Permission is hereby granted, free of charge, to any person obtaining
34
+ a copy of this software and associated documentation files (the
35
+ "Software"), to deal in the Software without restriction, including
36
+ without limitation the rights to use, copy, modify, merge, publish,
37
+ distribute, sublicense, and/or sell copies of the Software, and to
38
+ permit persons to whom the Software is furnished to do so, subject to
39
+ the following conditions:
40
+
41
+ The above copyright notice and this permission notice shall be
42
+ included in all copies or substantial portions of the Software.
43
+
44
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
45
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
46
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
47
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
48
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
49
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
50
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
51
+
52
+ ---
53
+
54
+ bench/samples/*.md:
55
+
56
+ With the exception of `bench/samples/README.md`, the samples in
57
+ `bench/samples` are taken from https://github.com/markdown-it/markdown-it.
58
+
59
+ Copyright (c) 2014 Vitaly Puzrin, Alex Kocharin.
60
+
61
+ Permission is hereby granted, free of charge, to any person
62
+ obtaining a copy of this software and associated documentation
63
+ files (the "Software"), to deal in the Software without
64
+ restriction, including without limitation the rights to use,
65
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
66
+ copies of the Software, and to permit persons to whom the
67
+ Software is furnished to do so, subject to the following
68
+ conditions:
69
+
70
+ The above copyright notice and this permission notice shall be
71
+ included in all copies or substantial portions of the Software.
72
+
73
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
74
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
75
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
76
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
77
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
78
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
79
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
80
+ OTHER DEALINGS IN THE SOFTWARE.
81
+
82
+ ---
83
+
84
+ The CommonMark spec (spec.txt) in test/ is
85
+
86
+ Copyright (C) 2014-15 John MacFarlane
87
+
88
+ Released under the Creative Commons CC-BY-SA 4.0 license:
89
+ <http://creativecommons.org/licenses/by-sa/4.0/>.