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.
- package/CHANGELOG.md +71 -0
- package/LICENSE +30 -0
- package/README.md +134 -0
- package/bin/md2org +91 -0
- package/package.json +53 -0
- package/src/md2org.js +82 -0
- package/src/org-escape.js +70 -0
- package/src/org-render.js +500 -0
- package/src/vendor/LICENSE-commonmark +89 -0
- package/src/vendor/commonmark-entities.js +1907 -0
- package/src/vendor/commonmark.js +401 -0
|
@@ -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/>.
|