markdown-codec 0.0.0 → 1.0.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/LICENSE +21 -0
- package/README.md +215 -0
- package/dist/ast/ast.cjs +25 -0
- package/dist/ast/ast.d.cts +2 -0
- package/dist/ast/ast.d.ts +2 -0
- package/dist/ast/ast.js +23 -0
- package/dist/ast-BXYwy08e.d.cts +160 -0
- package/dist/ast-BXYwy08e.d.ts +160 -0
- package/dist/block/block.cjs +530 -0
- package/dist/block/block.d.cts +18 -0
- package/dist/block/block.d.ts +18 -0
- package/dist/block/block.js +529 -0
- package/dist/block/definitions.cjs +59 -0
- package/dist/block/definitions.d.cts +6 -0
- package/dist/block/definitions.d.ts +6 -0
- package/dist/block/definitions.js +58 -0
- package/dist/block/line.cjs +76 -0
- package/dist/block/line.d.cts +28 -0
- package/dist/block/line.d.ts +28 -0
- package/dist/block/line.js +74 -0
- package/dist/block/list.cjs +110 -0
- package/dist/block/list.d.cts +8 -0
- package/dist/block/list.d.ts +8 -0
- package/dist/block/list.js +107 -0
- package/dist/block/node.cjs +68 -0
- package/dist/block/node.d.cts +45 -0
- package/dist/block/node.d.ts +45 -0
- package/dist/block/node.js +65 -0
- package/dist/block/table.cjs +64 -0
- package/dist/block/table.d.cts +7 -0
- package/dist/block/table.d.ts +7 -0
- package/dist/block/table.js +61 -0
- package/dist/codec.cjs +22 -0
- package/dist/codec.d.cts +361 -0
- package/dist/codec.d.ts +361 -0
- package/dist/codec.js +20 -0
- package/dist/defaults/defaults.cjs +31 -0
- package/dist/defaults/defaults.d.cts +16 -0
- package/dist/defaults/defaults.d.ts +16 -0
- package/dist/defaults/defaults.js +20 -0
- package/dist/diagnostics/diagnostics.cjs +85 -0
- package/dist/diagnostics/diagnostics.d.cts +2 -0
- package/dist/diagnostics/diagnostics.d.ts +2 -0
- package/dist/diagnostics/diagnostics.js +77 -0
- package/dist/diagnostics-DmuWc7d8.d.cts +61 -0
- package/dist/diagnostics-DmuWc7d8.d.ts +61 -0
- package/dist/emit/emit.cjs +228 -0
- package/dist/emit/emit.d.cts +6 -0
- package/dist/emit/emit.d.ts +6 -0
- package/dist/emit/emit.js +227 -0
- package/dist/emit/front-matter.cjs +24 -0
- package/dist/emit/front-matter.d.cts +5 -0
- package/dist/emit/front-matter.d.ts +5 -0
- package/dist/emit/front-matter.js +23 -0
- package/dist/emit/image.cjs +10 -0
- package/dist/emit/image.d.cts +5 -0
- package/dist/emit/image.d.ts +5 -0
- package/dist/emit/image.js +9 -0
- package/dist/emit/inline.cjs +183 -0
- package/dist/emit/inline.d.cts +12 -0
- package/dist/emit/inline.d.ts +12 -0
- package/dist/emit/inline.js +180 -0
- package/dist/emit/table.cjs +73 -0
- package/dist/emit/table.d.cts +10 -0
- package/dist/emit/table.d.ts +10 -0
- package/dist/emit/table.js +72 -0
- package/dist/html/html.cjs +116 -0
- package/dist/html/html.d.cts +2 -0
- package/dist/html/html.d.ts +2 -0
- package/dist/html/html.js +113 -0
- package/dist/html/render.cjs +193 -0
- package/dist/html/render.d.cts +8 -0
- package/dist/html/render.d.ts +8 -0
- package/dist/html/render.js +189 -0
- package/dist/html-bkz2QTuq.d.cts +7 -0
- package/dist/html-bkz2QTuq.d.ts +7 -0
- package/dist/image/image.cjs +129 -0
- package/dist/image/image.d.cts +2 -0
- package/dist/image/image.d.ts +2 -0
- package/dist/image/image.js +125 -0
- package/dist/image-C4KYmz_L.d.cts +19 -0
- package/dist/image-Cm3hT5PS.d.ts +19 -0
- package/dist/image-DescdRgq.d.cts +12 -0
- package/dist/image-DescdRgq.d.ts +12 -0
- package/dist/index.cjs +17 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +5 -0
- package/dist/inline/chars.cjs +50 -0
- package/dist/inline/chars.d.cts +11 -0
- package/dist/inline/chars.d.ts +11 -0
- package/dist/inline/chars.js +42 -0
- package/dist/inline/delimiter.cjs +136 -0
- package/dist/inline/delimiter.d.cts +29 -0
- package/dist/inline/delimiter.d.ts +29 -0
- package/dist/inline/delimiter.js +132 -0
- package/dist/inline/entity.cjs +67 -0
- package/dist/inline/entity.d.cts +9 -0
- package/dist/inline/entity.d.ts +9 -0
- package/dist/inline/entity.js +65 -0
- package/dist/inline/gfm-autolink.cjs +156 -0
- package/dist/inline/gfm-autolink.d.cts +5 -0
- package/dist/inline/gfm-autolink.d.ts +5 -0
- package/dist/inline/gfm-autolink.js +155 -0
- package/dist/inline/inline.cjs +457 -0
- package/dist/inline/inline.d.cts +2 -0
- package/dist/inline/inline.d.ts +2 -0
- package/dist/inline/inline.js +456 -0
- package/dist/inline/link.cjs +130 -0
- package/dist/inline/link.d.cts +2 -0
- package/dist/inline/link.d.ts +2 -0
- package/dist/inline/link.js +124 -0
- package/dist/inline/node.cjs +57 -0
- package/dist/inline/node.d.cts +23 -0
- package/dist/inline/node.d.ts +23 -0
- package/dist/inline/node.js +55 -0
- package/dist/inline-B50cM6cn.d.ts +10 -0
- package/dist/inline-C9YEGDV5.d.cts +10 -0
- package/dist/link-Dv4kxVjk.d.cts +18 -0
- package/dist/link-Dv4kxVjk.d.ts +18 -0
- package/dist/lower/front-matter.cjs +75 -0
- package/dist/lower/front-matter.d.cts +10 -0
- package/dist/lower/front-matter.d.ts +10 -0
- package/dist/lower/front-matter.js +74 -0
- package/dist/lower/image.cjs +29 -0
- package/dist/lower/image.d.cts +2 -0
- package/dist/lower/image.d.ts +2 -0
- package/dist/lower/image.js +28 -0
- package/dist/lower/inline.cjs +96 -0
- package/dist/lower/inline.d.cts +19 -0
- package/dist/lower/inline.d.ts +19 -0
- package/dist/lower/inline.js +93 -0
- package/dist/lower/lower.cjs +293 -0
- package/dist/lower/lower.d.cts +8 -0
- package/dist/lower/lower.d.ts +8 -0
- package/dist/lower/lower.js +291 -0
- package/dist/lower/table.cjs +27 -0
- package/dist/lower/table.d.cts +7 -0
- package/dist/lower/table.d.ts +7 -0
- package/dist/lower/table.js +26 -0
- package/dist/options/options.cjs +0 -0
- package/dist/options/options.d.cts +43 -0
- package/dist/options/options.d.ts +43 -0
- package/dist/options/options.js +0 -0
- package/dist/read.cjs +20 -0
- package/dist/read.d.cts +11 -0
- package/dist/read.d.ts +11 -0
- package/dist/read.js +19 -0
- package/dist/scan/entity-table.cjs +2131 -0
- package/dist/scan/entity-table.d.cts +4 -0
- package/dist/scan/entity-table.d.ts +4 -0
- package/dist/scan/entity-table.js +2130 -0
- package/dist/scan/scan.cjs +80 -0
- package/dist/scan/scan.d.cts +2 -0
- package/dist/scan/scan.d.ts +2 -0
- package/dist/scan/scan.js +78 -0
- package/dist/scan-DeBxgG-r.d.cts +30 -0
- package/dist/scan-DeBxgG-r.d.ts +30 -0
- package/dist/shared/list-id.cjs +36 -0
- package/dist/shared/list-id.d.cts +22 -0
- package/dist/shared/list-id.d.ts +22 -0
- package/dist/shared/list-id.js +32 -0
- package/dist/shared/style-constants.cjs +34 -0
- package/dist/shared/style-constants.d.cts +14 -0
- package/dist/shared/style-constants.d.ts +14 -0
- package/dist/shared/style-constants.js +23 -0
- package/dist/write.cjs +9 -0
- package/dist/write.d.cts +6 -0
- package/dist/write.d.ts +6 -0
- package/dist/write.js +8 -0
- package/package.json +92 -2
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { codePointAt, codePointBefore, isUnicodePunctuation, isUnicodeWhitespace } from "./chars.js";
|
|
2
|
+
//#region src/inline/delimiter.ts
|
|
3
|
+
function isDelimiterChar(char) {
|
|
4
|
+
return char === "*" || char === "_" || char === "~";
|
|
5
|
+
}
|
|
6
|
+
const MAX_STRIKETHROUGH_RUN = 2;
|
|
7
|
+
function scanDelimiterRun(text, start, char) {
|
|
8
|
+
let count = 0;
|
|
9
|
+
while (text.charAt(start + count) === char) count += 1;
|
|
10
|
+
if (count === 0) return;
|
|
11
|
+
if (char === "~" && count > MAX_STRIKETHROUGH_RUN) return;
|
|
12
|
+
const before = codePointBefore(text, start);
|
|
13
|
+
const after = codePointAt(text, start + count);
|
|
14
|
+
const beforeIsWhitespace = isUnicodeWhitespace(before);
|
|
15
|
+
const beforeIsPunctuation = isUnicodePunctuation(before);
|
|
16
|
+
const afterIsWhitespace = isUnicodeWhitespace(after);
|
|
17
|
+
const afterIsPunctuation = isUnicodePunctuation(after);
|
|
18
|
+
const leftFlanking = !afterIsWhitespace && (!afterIsPunctuation || beforeIsWhitespace || beforeIsPunctuation);
|
|
19
|
+
const rightFlanking = !beforeIsWhitespace && (!beforeIsPunctuation || afterIsWhitespace || afterIsPunctuation);
|
|
20
|
+
if (char === "_") return {
|
|
21
|
+
count,
|
|
22
|
+
canOpen: leftFlanking && (!rightFlanking || beforeIsPunctuation),
|
|
23
|
+
canClose: rightFlanking && (!leftFlanking || afterIsPunctuation)
|
|
24
|
+
};
|
|
25
|
+
return {
|
|
26
|
+
count,
|
|
27
|
+
canOpen: leftFlanking,
|
|
28
|
+
canClose: rightFlanking
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
var DelimiterStack = class {
|
|
32
|
+
top;
|
|
33
|
+
push(char, run, node) {
|
|
34
|
+
const delimiter = {
|
|
35
|
+
char,
|
|
36
|
+
count: run.count,
|
|
37
|
+
origCount: run.count,
|
|
38
|
+
canOpen: run.canOpen,
|
|
39
|
+
canClose: run.canClose,
|
|
40
|
+
node,
|
|
41
|
+
previous: this.top,
|
|
42
|
+
next: void 0
|
|
43
|
+
};
|
|
44
|
+
if (this.top !== void 0) this.top.next = delimiter;
|
|
45
|
+
this.top = delimiter;
|
|
46
|
+
}
|
|
47
|
+
remove(delimiter) {
|
|
48
|
+
if (delimiter.previous !== void 0) delimiter.previous.next = delimiter.next;
|
|
49
|
+
if (delimiter.next === void 0) this.top = delimiter.previous;
|
|
50
|
+
else delimiter.next.previous = delimiter.previous;
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
function closerSignature(closer) {
|
|
54
|
+
return `${closer.char}${closer.canOpen ? "1" : "0"}${String(closer.origCount % 3)}`;
|
|
55
|
+
}
|
|
56
|
+
function isRuleOfThreeBlocked(opener, closer) {
|
|
57
|
+
return (closer.canOpen || opener.canClose) && closer.origCount % 3 !== 0 && (opener.origCount + closer.origCount) % 3 === 0;
|
|
58
|
+
}
|
|
59
|
+
function canMatch(opener, closer) {
|
|
60
|
+
if (opener.char !== closer.char || !opener.canOpen) return false;
|
|
61
|
+
if (closer.char === "~") return opener.count === closer.count;
|
|
62
|
+
return !isRuleOfThreeBlocked(opener, closer);
|
|
63
|
+
}
|
|
64
|
+
function delimitersConsumedByMatch(opener, closer) {
|
|
65
|
+
if (closer.char === "~") return closer.count;
|
|
66
|
+
return closer.count >= 2 && opener.count >= 2 ? 2 : 1;
|
|
67
|
+
}
|
|
68
|
+
function wrapperKindFor(closer, used) {
|
|
69
|
+
if (closer.char === "~") return "strikethrough";
|
|
70
|
+
return used === 1 ? "emphasis" : "strong";
|
|
71
|
+
}
|
|
72
|
+
function processEmphasis(stack, stackBottom, createWrapper) {
|
|
73
|
+
const openersFloor = /* @__PURE__ */ new Map();
|
|
74
|
+
let closer = stack.top;
|
|
75
|
+
while (closer !== void 0 && closer.previous !== stackBottom) closer = closer.previous;
|
|
76
|
+
while (closer !== void 0) {
|
|
77
|
+
if (!closer.canClose) {
|
|
78
|
+
closer = closer.next;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
const signature = closerSignature(closer);
|
|
82
|
+
const floor = openersFloor.has(signature) ? openersFloor.get(signature) : stackBottom;
|
|
83
|
+
let opener = closer.previous;
|
|
84
|
+
let matchedOpener;
|
|
85
|
+
while (opener !== void 0 && opener !== stackBottom && opener !== floor) {
|
|
86
|
+
if (canMatch(opener, closer)) {
|
|
87
|
+
matchedOpener = opener;
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
opener = opener.previous;
|
|
91
|
+
}
|
|
92
|
+
const failedCloser = closer;
|
|
93
|
+
if (matchedOpener === void 0) {
|
|
94
|
+
closer = closer.next;
|
|
95
|
+
openersFloor.set(signature, failedCloser.previous);
|
|
96
|
+
if (!failedCloser.canOpen) stack.remove(failedCloser);
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
99
|
+
const used = delimitersConsumedByMatch(matchedOpener, closer);
|
|
100
|
+
const openerNode = matchedOpener.node;
|
|
101
|
+
const closerNode = closer.node;
|
|
102
|
+
matchedOpener.count -= used;
|
|
103
|
+
closer.count -= used;
|
|
104
|
+
openerNode.literal = openerNode.literal.slice(0, openerNode.literal.length - used);
|
|
105
|
+
closerNode.literal = closerNode.literal.slice(0, closerNode.literal.length - used);
|
|
106
|
+
const wrapper = createWrapper(wrapperKindFor(closer, used), closer.char);
|
|
107
|
+
let moving = openerNode.next;
|
|
108
|
+
while (moving !== void 0 && moving !== closerNode) {
|
|
109
|
+
const following = moving.next;
|
|
110
|
+
wrapper.appendChild(moving);
|
|
111
|
+
moving = following;
|
|
112
|
+
}
|
|
113
|
+
openerNode.insertAfter(wrapper);
|
|
114
|
+
if (matchedOpener.next !== closer) {
|
|
115
|
+
matchedOpener.next = closer;
|
|
116
|
+
closer.previous = matchedOpener;
|
|
117
|
+
}
|
|
118
|
+
if (matchedOpener.count === 0) {
|
|
119
|
+
openerNode.unlink();
|
|
120
|
+
stack.remove(matchedOpener);
|
|
121
|
+
}
|
|
122
|
+
if (closer.count === 0) {
|
|
123
|
+
closerNode.unlink();
|
|
124
|
+
const following = closer.next;
|
|
125
|
+
stack.remove(closer);
|
|
126
|
+
closer = following;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
while (stack.top !== void 0 && stack.top !== stackBottom) stack.remove(stack.top);
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
export { DelimiterStack, isDelimiterChar, processEmphasis, scanDelimiterRun };
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_scan_entity_table = require("../scan/entity-table.cjs");
|
|
3
|
+
const require_inline_chars = require("./chars.cjs");
|
|
4
|
+
//#region src/inline/entity.ts
|
|
5
|
+
const REPLACEMENT_CHARACTER = "�";
|
|
6
|
+
const MAX_CODEPOINT = 1114111;
|
|
7
|
+
const SURROGATE_FIRST = 55296;
|
|
8
|
+
const SURROGATE_LAST = 57343;
|
|
9
|
+
const ENTITY_PATTERN = /^&(?:#[Xx]([0-9A-Fa-f]{1,6})|#([0-9]{1,7})|([A-Za-z][A-Za-z0-9]{1,31}));/;
|
|
10
|
+
function codepointToString(codepoint) {
|
|
11
|
+
if (codepoint === 0 || codepoint > MAX_CODEPOINT || codepoint >= SURROGATE_FIRST && codepoint <= SURROGATE_LAST) return REPLACEMENT_CHARACTER;
|
|
12
|
+
return String.fromCodePoint(codepoint);
|
|
13
|
+
}
|
|
14
|
+
function matchEntity(text, start) {
|
|
15
|
+
if (text.charAt(start) !== "&") return;
|
|
16
|
+
const match = ENTITY_PATTERN.exec(text.slice(start));
|
|
17
|
+
if (match === null) return;
|
|
18
|
+
const [raw, hex, decimal, name] = match;
|
|
19
|
+
if (hex !== void 0) return {
|
|
20
|
+
raw,
|
|
21
|
+
value: codepointToString(Number.parseInt(hex, 16))
|
|
22
|
+
};
|
|
23
|
+
if (decimal !== void 0) return {
|
|
24
|
+
raw,
|
|
25
|
+
value: codepointToString(Number.parseInt(decimal, 10))
|
|
26
|
+
};
|
|
27
|
+
if (name === void 0) return;
|
|
28
|
+
const resolved = require_scan_entity_table.HTML_ENTITY_TABLE[name];
|
|
29
|
+
if (resolved === void 0) return;
|
|
30
|
+
return {
|
|
31
|
+
raw,
|
|
32
|
+
value: resolved
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
function unescapeString(text) {
|
|
36
|
+
if (!text.includes("\\") && !text.includes("&")) return text;
|
|
37
|
+
let result = "";
|
|
38
|
+
let index = 0;
|
|
39
|
+
while (index < text.length) {
|
|
40
|
+
const char = text.charAt(index);
|
|
41
|
+
if (char === "\\") {
|
|
42
|
+
const next = text.charAt(index + 1);
|
|
43
|
+
if (require_inline_chars.isAsciiPunctuation(next)) {
|
|
44
|
+
result += next;
|
|
45
|
+
index += 2;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
result += char;
|
|
49
|
+
index += 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
if (char === "&") {
|
|
53
|
+
const entity = matchEntity(text, index);
|
|
54
|
+
if (entity !== void 0) {
|
|
55
|
+
result += entity.value;
|
|
56
|
+
index += entity.raw.length;
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
result += char;
|
|
61
|
+
index += 1;
|
|
62
|
+
}
|
|
63
|
+
return result;
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
exports.matchEntity = matchEntity;
|
|
67
|
+
exports.unescapeString = unescapeString;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/inline/entity.d.ts
|
|
2
|
+
interface EntityMatch {
|
|
3
|
+
readonly raw: string;
|
|
4
|
+
readonly value: string;
|
|
5
|
+
}
|
|
6
|
+
declare function matchEntity(text: string, start: number): EntityMatch | undefined;
|
|
7
|
+
declare function unescapeString(text: string): string;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { EntityMatch, matchEntity, unescapeString };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
//#region src/inline/entity.d.ts
|
|
2
|
+
interface EntityMatch {
|
|
3
|
+
readonly raw: string;
|
|
4
|
+
readonly value: string;
|
|
5
|
+
}
|
|
6
|
+
declare function matchEntity(text: string, start: number): EntityMatch | undefined;
|
|
7
|
+
declare function unescapeString(text: string): string;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { EntityMatch, matchEntity, unescapeString };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { HTML_ENTITY_TABLE } from "../scan/entity-table.js";
|
|
2
|
+
import { isAsciiPunctuation } from "./chars.js";
|
|
3
|
+
//#region src/inline/entity.ts
|
|
4
|
+
const REPLACEMENT_CHARACTER = "�";
|
|
5
|
+
const MAX_CODEPOINT = 1114111;
|
|
6
|
+
const SURROGATE_FIRST = 55296;
|
|
7
|
+
const SURROGATE_LAST = 57343;
|
|
8
|
+
const ENTITY_PATTERN = /^&(?:#[Xx]([0-9A-Fa-f]{1,6})|#([0-9]{1,7})|([A-Za-z][A-Za-z0-9]{1,31}));/;
|
|
9
|
+
function codepointToString(codepoint) {
|
|
10
|
+
if (codepoint === 0 || codepoint > MAX_CODEPOINT || codepoint >= SURROGATE_FIRST && codepoint <= SURROGATE_LAST) return REPLACEMENT_CHARACTER;
|
|
11
|
+
return String.fromCodePoint(codepoint);
|
|
12
|
+
}
|
|
13
|
+
function matchEntity(text, start) {
|
|
14
|
+
if (text.charAt(start) !== "&") return;
|
|
15
|
+
const match = ENTITY_PATTERN.exec(text.slice(start));
|
|
16
|
+
if (match === null) return;
|
|
17
|
+
const [raw, hex, decimal, name] = match;
|
|
18
|
+
if (hex !== void 0) return {
|
|
19
|
+
raw,
|
|
20
|
+
value: codepointToString(Number.parseInt(hex, 16))
|
|
21
|
+
};
|
|
22
|
+
if (decimal !== void 0) return {
|
|
23
|
+
raw,
|
|
24
|
+
value: codepointToString(Number.parseInt(decimal, 10))
|
|
25
|
+
};
|
|
26
|
+
if (name === void 0) return;
|
|
27
|
+
const resolved = HTML_ENTITY_TABLE[name];
|
|
28
|
+
if (resolved === void 0) return;
|
|
29
|
+
return {
|
|
30
|
+
raw,
|
|
31
|
+
value: resolved
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function unescapeString(text) {
|
|
35
|
+
if (!text.includes("\\") && !text.includes("&")) return text;
|
|
36
|
+
let result = "";
|
|
37
|
+
let index = 0;
|
|
38
|
+
while (index < text.length) {
|
|
39
|
+
const char = text.charAt(index);
|
|
40
|
+
if (char === "\\") {
|
|
41
|
+
const next = text.charAt(index + 1);
|
|
42
|
+
if (isAsciiPunctuation(next)) {
|
|
43
|
+
result += next;
|
|
44
|
+
index += 2;
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
result += char;
|
|
48
|
+
index += 1;
|
|
49
|
+
continue;
|
|
50
|
+
}
|
|
51
|
+
if (char === "&") {
|
|
52
|
+
const entity = matchEntity(text, index);
|
|
53
|
+
if (entity !== void 0) {
|
|
54
|
+
result += entity.value;
|
|
55
|
+
index += entity.raw.length;
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
result += char;
|
|
60
|
+
index += 1;
|
|
61
|
+
}
|
|
62
|
+
return result;
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { matchEntity, unescapeString };
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_inline_node = require("./node.cjs");
|
|
3
|
+
//#region src/inline/gfm-autolink.ts
|
|
4
|
+
const DOMAIN_SEGMENT_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
5
|
+
const MIN_DOMAIN_SEGMENTS = 2;
|
|
6
|
+
const VALID_PRECEDING_CHARACTERS = /* @__PURE__ */ new Set([
|
|
7
|
+
"*",
|
|
8
|
+
"_",
|
|
9
|
+
"~",
|
|
10
|
+
"("
|
|
11
|
+
]);
|
|
12
|
+
const TRAILING_PUNCTUATION = /* @__PURE__ */ new Set([
|
|
13
|
+
"?",
|
|
14
|
+
"!",
|
|
15
|
+
".",
|
|
16
|
+
",",
|
|
17
|
+
":",
|
|
18
|
+
"*",
|
|
19
|
+
"_",
|
|
20
|
+
"~"
|
|
21
|
+
]);
|
|
22
|
+
const EMAIL_LOCAL_PART_PATTERN = /[A-Za-z0-9._+-]/;
|
|
23
|
+
const EMAIL_DOMAIN_PATTERN = /[A-Za-z0-9._-]/;
|
|
24
|
+
const ENTITY_TAIL_PATTERN = /&[A-Za-z0-9]+;$/;
|
|
25
|
+
const WWW_PREFIX = "www.";
|
|
26
|
+
const URL_SCHEME_PREFIXES = [
|
|
27
|
+
"http://",
|
|
28
|
+
"https://",
|
|
29
|
+
"ftp://"
|
|
30
|
+
];
|
|
31
|
+
const PROTOCOL_PREFIXES = ["mailto:", "xmpp:"];
|
|
32
|
+
const OPAQUE_KINDS = /* @__PURE__ */ new Set([
|
|
33
|
+
"link",
|
|
34
|
+
"image",
|
|
35
|
+
"codeSpan",
|
|
36
|
+
"rawHtml",
|
|
37
|
+
"autolink"
|
|
38
|
+
]);
|
|
39
|
+
function isWhitespace(char) {
|
|
40
|
+
return char === "" || char === " " || char === " " || char === "\n" || char === "\r" || char === "\f";
|
|
41
|
+
}
|
|
42
|
+
function isValidStartBoundary(text, index) {
|
|
43
|
+
if (index === 0) return true;
|
|
44
|
+
const before = text.charAt(index - 1);
|
|
45
|
+
return isWhitespace(before) || VALID_PRECEDING_CHARACTERS.has(before);
|
|
46
|
+
}
|
|
47
|
+
function isValidDomain(domain) {
|
|
48
|
+
const segments = domain.split(".");
|
|
49
|
+
if (segments.length < MIN_DOMAIN_SEGMENTS) return false;
|
|
50
|
+
if (!segments.every((segment) => DOMAIN_SEGMENT_PATTERN.test(segment))) return false;
|
|
51
|
+
return segments.slice(-2).every((segment) => !segment.includes("_"));
|
|
52
|
+
}
|
|
53
|
+
function trimTrailingPunctuation(candidate) {
|
|
54
|
+
let end = candidate.length;
|
|
55
|
+
for (;;) {
|
|
56
|
+
const before = end;
|
|
57
|
+
while (end > 0 && TRAILING_PUNCTUATION.has(candidate.charAt(end - 1))) end -= 1;
|
|
58
|
+
if (end > 0 && candidate.charAt(end - 1) === ")") {
|
|
59
|
+
const slice = candidate.slice(0, end);
|
|
60
|
+
if (slice.split(")").length > slice.split("(").length) end -= 1;
|
|
61
|
+
}
|
|
62
|
+
if (end > 0 && candidate.charAt(end - 1) === ";") {
|
|
63
|
+
const entityTail = ENTITY_TAIL_PATTERN.exec(candidate.slice(0, end));
|
|
64
|
+
if (entityTail !== null) end -= entityTail[0].length;
|
|
65
|
+
}
|
|
66
|
+
if (end === before) return candidate.slice(0, end);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function scanRawCandidate(text, start) {
|
|
70
|
+
let end = start;
|
|
71
|
+
while (end < text.length && !isWhitespace(text.charAt(end)) && text.charAt(end) !== "<") end += 1;
|
|
72
|
+
return text.slice(start, end);
|
|
73
|
+
}
|
|
74
|
+
function matchPrefixed(text, index, prefixLength, destinationPrefix, requireValidDomain) {
|
|
75
|
+
const trimmed = trimTrailingPunctuation(scanRawCandidate(text, index));
|
|
76
|
+
if (trimmed.length <= prefixLength) return;
|
|
77
|
+
if (requireValidDomain) {
|
|
78
|
+
if (!isValidDomain(trimmed.slice(prefixLength).split(/[/?#]/)[0] ?? "")) return;
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
text: trimmed,
|
|
82
|
+
destination: destinationPrefix + trimmed,
|
|
83
|
+
start: index
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function scanEmailDomain(text, start) {
|
|
87
|
+
let end = start;
|
|
88
|
+
while (end < text.length && EMAIL_DOMAIN_PATTERN.test(text.charAt(end))) end += 1;
|
|
89
|
+
return text.slice(start, end);
|
|
90
|
+
}
|
|
91
|
+
function matchEmailAt(text, atIndex) {
|
|
92
|
+
let start = atIndex;
|
|
93
|
+
while (start > 0 && EMAIL_LOCAL_PART_PATTERN.test(text.charAt(start - 1))) start -= 1;
|
|
94
|
+
if (start === atIndex || !isValidStartBoundary(text, start)) return;
|
|
95
|
+
const local = text.slice(start, atIndex);
|
|
96
|
+
if (local.startsWith(".") || local.endsWith(".")) return;
|
|
97
|
+
const domain = scanEmailDomain(text, atIndex + 1).replace(/\.+$/, "");
|
|
98
|
+
if (domain.endsWith("-") || domain.endsWith("_") || !isValidDomain(domain)) return;
|
|
99
|
+
const address = `${local}@${domain}`;
|
|
100
|
+
return {
|
|
101
|
+
text: address,
|
|
102
|
+
destination: `mailto:${address}`,
|
|
103
|
+
start
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function startsWithIgnoringCase(text, index, prefix) {
|
|
107
|
+
return text.slice(index, index + prefix.length).toLowerCase() === prefix;
|
|
108
|
+
}
|
|
109
|
+
function findAutolinkAt(text, index) {
|
|
110
|
+
if (text.charAt(index) === "@") return matchEmailAt(text, index);
|
|
111
|
+
if (!isValidStartBoundary(text, index)) return;
|
|
112
|
+
if (startsWithIgnoringCase(text, index, WWW_PREFIX)) return matchPrefixed(text, index, 4, "http://", true);
|
|
113
|
+
for (const prefix of URL_SCHEME_PREFIXES) if (startsWithIgnoringCase(text, index, prefix)) return matchPrefixed(text, index, prefix.length, "", true);
|
|
114
|
+
for (const prefix of PROTOCOL_PREFIXES) if (startsWithIgnoringCase(text, index, prefix)) return matchPrefixed(text, index, prefix.length, "", false);
|
|
115
|
+
}
|
|
116
|
+
function expandTextNode(node) {
|
|
117
|
+
const text = node.literal;
|
|
118
|
+
let cursor = 0;
|
|
119
|
+
let anchor = node;
|
|
120
|
+
let matches = 0;
|
|
121
|
+
let index = 0;
|
|
122
|
+
while (index < text.length) {
|
|
123
|
+
const found = findAutolinkAt(text, index);
|
|
124
|
+
if (found === void 0 || found.start < cursor) {
|
|
125
|
+
index += 1;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (found.start > cursor) {
|
|
129
|
+
const before = require_inline_node.createTextNode(text.slice(cursor, found.start));
|
|
130
|
+
anchor.insertAfter(before);
|
|
131
|
+
anchor = before;
|
|
132
|
+
}
|
|
133
|
+
const link = new require_inline_node.InlineNode("link");
|
|
134
|
+
link.destination = found.destination;
|
|
135
|
+
link.appendChild(require_inline_node.createTextNode(found.text));
|
|
136
|
+
anchor.insertAfter(link);
|
|
137
|
+
anchor = link;
|
|
138
|
+
cursor = found.start + found.text.length;
|
|
139
|
+
matches += 1;
|
|
140
|
+
index = cursor;
|
|
141
|
+
}
|
|
142
|
+
if (matches === 0) return;
|
|
143
|
+
if (cursor < text.length) anchor.insertAfter(require_inline_node.createTextNode(text.slice(cursor)));
|
|
144
|
+
node.unlink();
|
|
145
|
+
}
|
|
146
|
+
function applyGfmAutolinks(root) {
|
|
147
|
+
let child = root.firstChild;
|
|
148
|
+
while (child !== void 0) {
|
|
149
|
+
const following = child.next;
|
|
150
|
+
if (child.kind === "text") expandTextNode(child);
|
|
151
|
+
else if (!OPAQUE_KINDS.has(child.kind)) applyGfmAutolinks(child);
|
|
152
|
+
child = following;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
//#endregion
|
|
156
|
+
exports.applyGfmAutolinks = applyGfmAutolinks;
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { InlineNode, createTextNode } from "./node.js";
|
|
2
|
+
//#region src/inline/gfm-autolink.ts
|
|
3
|
+
const DOMAIN_SEGMENT_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
4
|
+
const MIN_DOMAIN_SEGMENTS = 2;
|
|
5
|
+
const VALID_PRECEDING_CHARACTERS = /* @__PURE__ */ new Set([
|
|
6
|
+
"*",
|
|
7
|
+
"_",
|
|
8
|
+
"~",
|
|
9
|
+
"("
|
|
10
|
+
]);
|
|
11
|
+
const TRAILING_PUNCTUATION = /* @__PURE__ */ new Set([
|
|
12
|
+
"?",
|
|
13
|
+
"!",
|
|
14
|
+
".",
|
|
15
|
+
",",
|
|
16
|
+
":",
|
|
17
|
+
"*",
|
|
18
|
+
"_",
|
|
19
|
+
"~"
|
|
20
|
+
]);
|
|
21
|
+
const EMAIL_LOCAL_PART_PATTERN = /[A-Za-z0-9._+-]/;
|
|
22
|
+
const EMAIL_DOMAIN_PATTERN = /[A-Za-z0-9._-]/;
|
|
23
|
+
const ENTITY_TAIL_PATTERN = /&[A-Za-z0-9]+;$/;
|
|
24
|
+
const WWW_PREFIX = "www.";
|
|
25
|
+
const URL_SCHEME_PREFIXES = [
|
|
26
|
+
"http://",
|
|
27
|
+
"https://",
|
|
28
|
+
"ftp://"
|
|
29
|
+
];
|
|
30
|
+
const PROTOCOL_PREFIXES = ["mailto:", "xmpp:"];
|
|
31
|
+
const OPAQUE_KINDS = /* @__PURE__ */ new Set([
|
|
32
|
+
"link",
|
|
33
|
+
"image",
|
|
34
|
+
"codeSpan",
|
|
35
|
+
"rawHtml",
|
|
36
|
+
"autolink"
|
|
37
|
+
]);
|
|
38
|
+
function isWhitespace(char) {
|
|
39
|
+
return char === "" || char === " " || char === " " || char === "\n" || char === "\r" || char === "\f";
|
|
40
|
+
}
|
|
41
|
+
function isValidStartBoundary(text, index) {
|
|
42
|
+
if (index === 0) return true;
|
|
43
|
+
const before = text.charAt(index - 1);
|
|
44
|
+
return isWhitespace(before) || VALID_PRECEDING_CHARACTERS.has(before);
|
|
45
|
+
}
|
|
46
|
+
function isValidDomain(domain) {
|
|
47
|
+
const segments = domain.split(".");
|
|
48
|
+
if (segments.length < MIN_DOMAIN_SEGMENTS) return false;
|
|
49
|
+
if (!segments.every((segment) => DOMAIN_SEGMENT_PATTERN.test(segment))) return false;
|
|
50
|
+
return segments.slice(-2).every((segment) => !segment.includes("_"));
|
|
51
|
+
}
|
|
52
|
+
function trimTrailingPunctuation(candidate) {
|
|
53
|
+
let end = candidate.length;
|
|
54
|
+
for (;;) {
|
|
55
|
+
const before = end;
|
|
56
|
+
while (end > 0 && TRAILING_PUNCTUATION.has(candidate.charAt(end - 1))) end -= 1;
|
|
57
|
+
if (end > 0 && candidate.charAt(end - 1) === ")") {
|
|
58
|
+
const slice = candidate.slice(0, end);
|
|
59
|
+
if (slice.split(")").length > slice.split("(").length) end -= 1;
|
|
60
|
+
}
|
|
61
|
+
if (end > 0 && candidate.charAt(end - 1) === ";") {
|
|
62
|
+
const entityTail = ENTITY_TAIL_PATTERN.exec(candidate.slice(0, end));
|
|
63
|
+
if (entityTail !== null) end -= entityTail[0].length;
|
|
64
|
+
}
|
|
65
|
+
if (end === before) return candidate.slice(0, end);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function scanRawCandidate(text, start) {
|
|
69
|
+
let end = start;
|
|
70
|
+
while (end < text.length && !isWhitespace(text.charAt(end)) && text.charAt(end) !== "<") end += 1;
|
|
71
|
+
return text.slice(start, end);
|
|
72
|
+
}
|
|
73
|
+
function matchPrefixed(text, index, prefixLength, destinationPrefix, requireValidDomain) {
|
|
74
|
+
const trimmed = trimTrailingPunctuation(scanRawCandidate(text, index));
|
|
75
|
+
if (trimmed.length <= prefixLength) return;
|
|
76
|
+
if (requireValidDomain) {
|
|
77
|
+
if (!isValidDomain(trimmed.slice(prefixLength).split(/[/?#]/)[0] ?? "")) return;
|
|
78
|
+
}
|
|
79
|
+
return {
|
|
80
|
+
text: trimmed,
|
|
81
|
+
destination: destinationPrefix + trimmed,
|
|
82
|
+
start: index
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
function scanEmailDomain(text, start) {
|
|
86
|
+
let end = start;
|
|
87
|
+
while (end < text.length && EMAIL_DOMAIN_PATTERN.test(text.charAt(end))) end += 1;
|
|
88
|
+
return text.slice(start, end);
|
|
89
|
+
}
|
|
90
|
+
function matchEmailAt(text, atIndex) {
|
|
91
|
+
let start = atIndex;
|
|
92
|
+
while (start > 0 && EMAIL_LOCAL_PART_PATTERN.test(text.charAt(start - 1))) start -= 1;
|
|
93
|
+
if (start === atIndex || !isValidStartBoundary(text, start)) return;
|
|
94
|
+
const local = text.slice(start, atIndex);
|
|
95
|
+
if (local.startsWith(".") || local.endsWith(".")) return;
|
|
96
|
+
const domain = scanEmailDomain(text, atIndex + 1).replace(/\.+$/, "");
|
|
97
|
+
if (domain.endsWith("-") || domain.endsWith("_") || !isValidDomain(domain)) return;
|
|
98
|
+
const address = `${local}@${domain}`;
|
|
99
|
+
return {
|
|
100
|
+
text: address,
|
|
101
|
+
destination: `mailto:${address}`,
|
|
102
|
+
start
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
function startsWithIgnoringCase(text, index, prefix) {
|
|
106
|
+
return text.slice(index, index + prefix.length).toLowerCase() === prefix;
|
|
107
|
+
}
|
|
108
|
+
function findAutolinkAt(text, index) {
|
|
109
|
+
if (text.charAt(index) === "@") return matchEmailAt(text, index);
|
|
110
|
+
if (!isValidStartBoundary(text, index)) return;
|
|
111
|
+
if (startsWithIgnoringCase(text, index, WWW_PREFIX)) return matchPrefixed(text, index, 4, "http://", true);
|
|
112
|
+
for (const prefix of URL_SCHEME_PREFIXES) if (startsWithIgnoringCase(text, index, prefix)) return matchPrefixed(text, index, prefix.length, "", true);
|
|
113
|
+
for (const prefix of PROTOCOL_PREFIXES) if (startsWithIgnoringCase(text, index, prefix)) return matchPrefixed(text, index, prefix.length, "", false);
|
|
114
|
+
}
|
|
115
|
+
function expandTextNode(node) {
|
|
116
|
+
const text = node.literal;
|
|
117
|
+
let cursor = 0;
|
|
118
|
+
let anchor = node;
|
|
119
|
+
let matches = 0;
|
|
120
|
+
let index = 0;
|
|
121
|
+
while (index < text.length) {
|
|
122
|
+
const found = findAutolinkAt(text, index);
|
|
123
|
+
if (found === void 0 || found.start < cursor) {
|
|
124
|
+
index += 1;
|
|
125
|
+
continue;
|
|
126
|
+
}
|
|
127
|
+
if (found.start > cursor) {
|
|
128
|
+
const before = createTextNode(text.slice(cursor, found.start));
|
|
129
|
+
anchor.insertAfter(before);
|
|
130
|
+
anchor = before;
|
|
131
|
+
}
|
|
132
|
+
const link = new InlineNode("link");
|
|
133
|
+
link.destination = found.destination;
|
|
134
|
+
link.appendChild(createTextNode(found.text));
|
|
135
|
+
anchor.insertAfter(link);
|
|
136
|
+
anchor = link;
|
|
137
|
+
cursor = found.start + found.text.length;
|
|
138
|
+
matches += 1;
|
|
139
|
+
index = cursor;
|
|
140
|
+
}
|
|
141
|
+
if (matches === 0) return;
|
|
142
|
+
if (cursor < text.length) anchor.insertAfter(createTextNode(text.slice(cursor)));
|
|
143
|
+
node.unlink();
|
|
144
|
+
}
|
|
145
|
+
function applyGfmAutolinks(root) {
|
|
146
|
+
let child = root.firstChild;
|
|
147
|
+
while (child !== void 0) {
|
|
148
|
+
const following = child.next;
|
|
149
|
+
if (child.kind === "text") expandTextNode(child);
|
|
150
|
+
else if (!OPAQUE_KINDS.has(child.kind)) applyGfmAutolinks(child);
|
|
151
|
+
child = following;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
//#endregion
|
|
155
|
+
export { applyGfmAutolinks };
|