1 |
|
2 |
|
3 |
|
4 | const escapeTest = /[&<>"']/;
|
5 | const escapeReplace = /[&<>"']/g;
|
6 | const escapeTestNoEncode = /[<>"']|&(?!#?\w+;)/;
|
7 | const escapeReplaceNoEncode = /[<>"']|&(?!#?\w+;)/g;
|
8 | const escapeReplacements = {
|
9 | '&': '&',
|
10 | '<': '<',
|
11 | '>': '>',
|
12 | '"': '"',
|
13 | "'": '''
|
14 | };
|
15 | const getEscapeReplacement = (ch) => escapeReplacements[ch];
|
16 | export function escape(html, encode) {
|
17 | if (encode) {
|
18 | if (escapeTest.test(html)) {
|
19 | return html.replace(escapeReplace, getEscapeReplacement);
|
20 | }
|
21 | } else {
|
22 | if (escapeTestNoEncode.test(html)) {
|
23 | return html.replace(escapeReplaceNoEncode, getEscapeReplacement);
|
24 | }
|
25 | }
|
26 |
|
27 | return html;
|
28 | }
|
29 |
|
30 | const unescapeTest = /&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/ig;
|
31 |
|
32 |
|
33 |
|
34 |
|
35 | export function unescape(html) {
|
36 |
|
37 | return html.replace(unescapeTest, (_, n) => {
|
38 | n = n.toLowerCase();
|
39 | if (n === 'colon') return ':';
|
40 | if (n.charAt(0) === '#') {
|
41 | return n.charAt(1) === 'x'
|
42 | ? String.fromCharCode(parseInt(n.substring(2), 16))
|
43 | : String.fromCharCode(+n.substring(1));
|
44 | }
|
45 | return '';
|
46 | });
|
47 | }
|
48 |
|
49 | const caret = /(^|[^\[])\^/g;
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 | export function edit(regex, opt) {
|
56 | regex = typeof regex === 'string' ? regex : regex.source;
|
57 | opt = opt || '';
|
58 | const obj = {
|
59 | replace: (name, val) => {
|
60 | val = val.source || val;
|
61 | val = val.replace(caret, '$1');
|
62 | regex = regex.replace(name, val);
|
63 | return obj;
|
64 | },
|
65 | getRegex: () => {
|
66 | return new RegExp(regex, opt);
|
67 | }
|
68 | };
|
69 | return obj;
|
70 | }
|
71 |
|
72 | const nonWordAndColonTest = /[^\w:]/g;
|
73 | const originIndependentUrl = /^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;
|
74 |
|
75 |
|
76 |
|
77 |
|
78 |
|
79 |
|
80 | export function cleanUrl(sanitize, base, href) {
|
81 | if (sanitize) {
|
82 | let prot;
|
83 | try {
|
84 | prot = decodeURIComponent(unescape(href))
|
85 | .replace(nonWordAndColonTest, '')
|
86 | .toLowerCase();
|
87 | } catch (e) {
|
88 | return null;
|
89 | }
|
90 | if (prot.indexOf('javascript:') === 0 || prot.indexOf('vbscript:') === 0 || prot.indexOf('data:') === 0) {
|
91 | return null;
|
92 | }
|
93 | }
|
94 | if (base && !originIndependentUrl.test(href)) {
|
95 | href = resolveUrl(base, href);
|
96 | }
|
97 | try {
|
98 | href = encodeURI(href).replace(/%25/g, '%');
|
99 | } catch (e) {
|
100 | return null;
|
101 | }
|
102 | return href;
|
103 | }
|
104 |
|
105 | const baseUrls = {};
|
106 | const justDomain = /^[^:]+:\/*[^/]*$/;
|
107 | const protocol = /^([^:]+:)[\s\S]*$/;
|
108 | const domain = /^([^:]+:\/*[^/]*)[\s\S]*$/;
|
109 |
|
110 |
|
111 |
|
112 |
|
113 |
|
114 | export function resolveUrl(base, href) {
|
115 | if (!baseUrls[' ' + base]) {
|
116 |
|
117 |
|
118 |
|
119 | if (justDomain.test(base)) {
|
120 | baseUrls[' ' + base] = base + '/';
|
121 | } else {
|
122 | baseUrls[' ' + base] = rtrim(base, '/', true);
|
123 | }
|
124 | }
|
125 | base = baseUrls[' ' + base];
|
126 | const relativeBase = base.indexOf(':') === -1;
|
127 |
|
128 | if (href.substring(0, 2) === '//') {
|
129 | if (relativeBase) {
|
130 | return href;
|
131 | }
|
132 | return base.replace(protocol, '$1') + href;
|
133 | } else if (href.charAt(0) === '/') {
|
134 | if (relativeBase) {
|
135 | return href;
|
136 | }
|
137 | return base.replace(domain, '$1') + href;
|
138 | } else {
|
139 | return base + href;
|
140 | }
|
141 | }
|
142 |
|
143 | export const noopTest = { exec: function noopTest() {} };
|
144 |
|
145 | export function merge(obj) {
|
146 | let i = 1,
|
147 | target,
|
148 | key;
|
149 |
|
150 | for (; i < arguments.length; i++) {
|
151 | target = arguments[i];
|
152 | for (key in target) {
|
153 | if (Object.prototype.hasOwnProperty.call(target, key)) {
|
154 | obj[key] = target[key];
|
155 | }
|
156 | }
|
157 | }
|
158 |
|
159 | return obj;
|
160 | }
|
161 |
|
162 | export function splitCells(tableRow, count) {
|
163 |
|
164 |
|
165 | const row = tableRow.replace(/\|/g, (match, offset, str) => {
|
166 | let escaped = false,
|
167 | curr = offset;
|
168 | while (--curr >= 0 && str[curr] === '\\') escaped = !escaped;
|
169 | if (escaped) {
|
170 |
|
171 |
|
172 | return '|';
|
173 | } else {
|
174 |
|
175 | return ' |';
|
176 | }
|
177 | }),
|
178 | cells = row.split(/ \|/);
|
179 | let i = 0;
|
180 |
|
181 |
|
182 | if (!cells[0].trim()) { cells.shift(); }
|
183 | if (cells.length > 0 && !cells[cells.length - 1].trim()) { cells.pop(); }
|
184 |
|
185 | if (cells.length > count) {
|
186 | cells.splice(count);
|
187 | } else {
|
188 | while (cells.length < count) cells.push('');
|
189 | }
|
190 |
|
191 | for (; i < cells.length; i++) {
|
192 |
|
193 | cells[i] = cells[i].trim().replace(/\\\|/g, '|');
|
194 | }
|
195 | return cells;
|
196 | }
|
197 |
|
198 |
|
199 |
|
200 |
|
201 |
|
202 |
|
203 |
|
204 |
|
205 |
|
206 | export function rtrim(str, c, invert) {
|
207 | const l = str.length;
|
208 | if (l === 0) {
|
209 | return '';
|
210 | }
|
211 |
|
212 |
|
213 | let suffLen = 0;
|
214 |
|
215 |
|
216 | while (suffLen < l) {
|
217 | const currChar = str.charAt(l - suffLen - 1);
|
218 | if (currChar === c && !invert) {
|
219 | suffLen++;
|
220 | } else if (currChar !== c && invert) {
|
221 | suffLen++;
|
222 | } else {
|
223 | break;
|
224 | }
|
225 | }
|
226 |
|
227 | return str.slice(0, l - suffLen);
|
228 | }
|
229 |
|
230 | export function findClosingBracket(str, b) {
|
231 | if (str.indexOf(b[1]) === -1) {
|
232 | return -1;
|
233 | }
|
234 | const l = str.length;
|
235 | let level = 0,
|
236 | i = 0;
|
237 | for (; i < l; i++) {
|
238 | if (str[i] === '\\') {
|
239 | i++;
|
240 | } else if (str[i] === b[0]) {
|
241 | level++;
|
242 | } else if (str[i] === b[1]) {
|
243 | level--;
|
244 | if (level < 0) {
|
245 | return i;
|
246 | }
|
247 | }
|
248 | }
|
249 | return -1;
|
250 | }
|
251 |
|
252 | export function checkSanitizeDeprecation(opt) {
|
253 | if (opt && opt.sanitize && !opt.silent) {
|
254 | console.warn('marked(): sanitize and sanitizer parameters are deprecated since version 0.7.0, should not be used and will be removed in the future. Read more here: https://marked.js.org/#/USING_ADVANCED.md#options');
|
255 | }
|
256 | }
|
257 |
|
258 |
|
259 |
|
260 |
|
261 |
|
262 |
|
263 | export function repeatString(pattern, count) {
|
264 | if (count < 1) {
|
265 | return '';
|
266 | }
|
267 | let result = '';
|
268 | while (count > 1) {
|
269 | if (count & 1) {
|
270 | result += pattern;
|
271 | }
|
272 | count >>= 1;
|
273 | pattern += pattern;
|
274 | }
|
275 | return result + pattern;
|
276 | }
|