quikdown 1.2.10 → 1.2.11
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/README.md +2 -2
- package/dist/quikdown.cjs +96 -3
- package/dist/quikdown.d.ts +12 -0
- package/dist/quikdown.dark.css +1 -1
- package/dist/quikdown.esm.js +96 -3
- package/dist/quikdown.esm.min.js +2 -2
- package/dist/quikdown.esm.min.js.gz +0 -0
- package/dist/quikdown.esm.min.js.map +1 -1
- package/dist/quikdown.light.css +1 -1
- package/dist/quikdown.umd.js +96 -3
- package/dist/quikdown.umd.min.js +2 -2
- package/dist/quikdown.umd.min.js.gz +0 -0
- package/dist/quikdown.umd.min.js.map +1 -1
- package/dist/quikdown_ast.cjs +2 -2
- package/dist/quikdown_ast.esm.js +2 -2
- package/dist/quikdown_ast.esm.min.js +2 -2
- package/dist/quikdown_ast.esm.min.js.gz +0 -0
- package/dist/quikdown_ast.umd.js +2 -2
- package/dist/quikdown_ast.umd.min.js +2 -2
- package/dist/quikdown_ast.umd.min.js.gz +0 -0
- package/dist/quikdown_ast_html.cjs +3 -3
- package/dist/quikdown_ast_html.esm.js +3 -3
- package/dist/quikdown_ast_html.esm.min.js +2 -2
- package/dist/quikdown_ast_html.esm.min.js.gz +0 -0
- package/dist/quikdown_ast_html.umd.js +3 -3
- package/dist/quikdown_ast_html.umd.min.js +2 -2
- package/dist/quikdown_ast_html.umd.min.js.gz +0 -0
- package/dist/quikdown_bd.cjs +96 -3
- package/dist/quikdown_bd.esm.js +96 -3
- package/dist/quikdown_bd.esm.min.js +2 -2
- package/dist/quikdown_bd.esm.min.js.gz +0 -0
- package/dist/quikdown_bd.esm.min.js.map +1 -1
- package/dist/quikdown_bd.umd.js +96 -3
- package/dist/quikdown_bd.umd.min.js +2 -2
- package/dist/quikdown_bd.umd.min.js.gz +0 -0
- package/dist/quikdown_bd.umd.min.js.map +1 -1
- package/dist/quikdown_edit.cjs +232 -6
- package/dist/quikdown_edit.esm.js +232 -6
- package/dist/quikdown_edit.esm.min.js +3 -3
- package/dist/quikdown_edit.esm.min.js.gz +0 -0
- package/dist/quikdown_edit.esm.min.js.map +1 -1
- package/dist/quikdown_edit.umd.js +232 -6
- package/dist/quikdown_edit.umd.min.js +3 -3
- package/dist/quikdown_edit.umd.min.js.gz +0 -0
- package/dist/quikdown_edit.umd.min.js.map +1 -1
- package/dist/quikdown_json.cjs +3 -3
- package/dist/quikdown_json.esm.js +3 -3
- package/dist/quikdown_json.esm.min.js +2 -2
- package/dist/quikdown_json.esm.min.js.gz +0 -0
- package/dist/quikdown_json.umd.js +3 -3
- package/dist/quikdown_json.umd.min.js +2 -2
- package/dist/quikdown_json.umd.min.js.gz +0 -0
- package/dist/quikdown_yaml.cjs +3 -3
- package/dist/quikdown_yaml.esm.js +3 -3
- package/dist/quikdown_yaml.esm.min.js +2 -2
- package/dist/quikdown_yaml.esm.min.js.gz +0 -0
- package/dist/quikdown_yaml.umd.js +3 -3
- package/dist/quikdown_yaml.umd.min.js +2 -2
- package/dist/quikdown_yaml.umd.min.js.gz +0 -0
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
|
|
3
3
|
[](https://github.com/deftio/quikdown/actions/workflows/ci.yml)
|
|
4
4
|
[](https://www.npmjs.com/package/quikdown)
|
|
5
|
-
[](https://github.com/deftio/quikdown)
|
|
6
6
|
[](https://opensource.org/licenses/BSD-2-Clause)
|
|
7
|
-
[](https://bundlephobia.com/package/quikdown)
|
|
8
8
|
|
|
9
9
|
A small, secure markdown parser and editor for browsers and Node.js. Three modules — use only what you need.
|
|
10
10
|
|
package/dist/quikdown.cjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* quikdown - Lightweight Markdown Parser
|
|
3
|
-
* @version 1.2.
|
|
3
|
+
* @version 1.2.11
|
|
4
4
|
* @license BSD-2-Clause
|
|
5
5
|
* @copyright DeftIO 2025
|
|
6
6
|
*/
|
|
@@ -114,7 +114,7 @@ function isDashHRLine(trimmed) {
|
|
|
114
114
|
// ────────────────────────────────────────────────────────────────────
|
|
115
115
|
|
|
116
116
|
/** Build-time version stamp (injected by tools/updateVersion) */
|
|
117
|
-
const quikdownVersion = '1.2.
|
|
117
|
+
const quikdownVersion = '1.2.11';
|
|
118
118
|
|
|
119
119
|
/** CSS class prefix used for all generated elements */
|
|
120
120
|
const CLASS_PREFIX = 'quikdown-';
|
|
@@ -122,6 +122,10 @@ const CLASS_PREFIX = 'quikdown-';
|
|
|
122
122
|
/** Placeholder sigils — chosen to be extremely unlikely in real text */
|
|
123
123
|
const PLACEHOLDER_CB = '§CB'; // fenced code blocks
|
|
124
124
|
const PLACEHOLDER_IC = '§IC'; // inline code spans
|
|
125
|
+
const PLACEHOLDER_HT = '§HT'; // safe HTML tags (limited mode)
|
|
126
|
+
|
|
127
|
+
/** Attributes whose values need URL sanitization */
|
|
128
|
+
const URL_ATTRIBUTES = { href:1, src:1, action:1, formaction:1 };
|
|
125
129
|
|
|
126
130
|
/** HTML entity escape map */
|
|
127
131
|
const ESC_MAP = {'&':'&','<':'<','>':'>','"':'"',"'":'''};
|
|
@@ -256,6 +260,46 @@ function quikdown(markdown, options = {}) {
|
|
|
256
260
|
return trimmedUrl;
|
|
257
261
|
}
|
|
258
262
|
|
|
263
|
+
/**
|
|
264
|
+
* Sanitize attributes on an HTML tag string for limited mode.
|
|
265
|
+
* Strips on* event handlers (case-insensitive) and runs sanitizeUrl()
|
|
266
|
+
* on href/src/action/formaction values.
|
|
267
|
+
*/
|
|
268
|
+
function sanitizeHtmlTagAttrs(tagStr) {
|
|
269
|
+
// Self-closing or void tag without attributes — pass through
|
|
270
|
+
if (!/\s/.test(tagStr.replace(/<\/?[a-zA-Z][a-zA-Z0-9]*/, '').replace(/\/?>$/, ''))) {
|
|
271
|
+
return tagStr;
|
|
272
|
+
}
|
|
273
|
+
// Parse: <tagname ...attrs... > or <tagname ...attrs... />
|
|
274
|
+
const m = tagStr.match(/^(<\/?[a-zA-Z][a-zA-Z0-9]*)([\s\S]*?)(\/?>)$/);
|
|
275
|
+
/* istanbul ignore next - defensive: Phase 1.5 regex guarantees valid tag shape */
|
|
276
|
+
if (!m) return tagStr;
|
|
277
|
+
|
|
278
|
+
const [, open, attrStr, close] = m;
|
|
279
|
+
// Match individual attributes: name="value", name='value', name=value, or bare name
|
|
280
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- linear: no nested quantifiers
|
|
281
|
+
const attrRe = /([a-zA-Z_][\w\-.:]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g;
|
|
282
|
+
const attrs = [];
|
|
283
|
+
let am;
|
|
284
|
+
while ((am = attrRe.exec(attrStr)) !== null) {
|
|
285
|
+
const name = am[1];
|
|
286
|
+
const value = am[2] !== undefined ? am[2] : am[3] !== undefined ? am[3] : am[4];
|
|
287
|
+
// Strip event handlers (on*)
|
|
288
|
+
if (/^on/i.test(name)) continue;
|
|
289
|
+
if (value === undefined) {
|
|
290
|
+
// Boolean attribute (e.g. disabled, checked)
|
|
291
|
+
attrs.push(name);
|
|
292
|
+
} else {
|
|
293
|
+
let sanitized = value;
|
|
294
|
+
if (name.toLowerCase() in URL_ATTRIBUTES) {
|
|
295
|
+
sanitized = sanitizeUrl(value);
|
|
296
|
+
}
|
|
297
|
+
attrs.push(`${name}="${sanitized}"`);
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return open + (attrs.length ? ' ' + attrs.join(' ') : '') + close;
|
|
301
|
+
}
|
|
302
|
+
|
|
259
303
|
// ────────────────────────────────────────────────────────────────
|
|
260
304
|
// Phase 1 — Code Extraction
|
|
261
305
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -307,17 +351,57 @@ function quikdown(markdown, options = {}) {
|
|
|
307
351
|
return placeholder;
|
|
308
352
|
});
|
|
309
353
|
|
|
354
|
+
// ────────────────────────────────────────────────────────────────
|
|
355
|
+
// Phase 1.5 — Safe HTML Extraction (whitelist mode)
|
|
356
|
+
// ────────────────────────────────────────────────────────────────
|
|
357
|
+
// When allow_unsafe_html is an object or array, extract whitelisted
|
|
358
|
+
// HTML tags, sanitize their attributes, and replace with placeholders.
|
|
359
|
+
// Non-whitelisted tags stay in text so Phase 2 will escape them.
|
|
360
|
+
|
|
361
|
+
const safeTags = [];
|
|
362
|
+
// Normalize: array → object for O(1) lookup; object used as-is
|
|
363
|
+
const htmlAllow = Array.isArray(allow_unsafe_html)
|
|
364
|
+
? Object.fromEntries(allow_unsafe_html.map(t => [t, 1]))
|
|
365
|
+
: (allow_unsafe_html && typeof allow_unsafe_html === 'object') ? allow_unsafe_html : null;
|
|
366
|
+
|
|
367
|
+
if (htmlAllow) {
|
|
368
|
+
// Pass through HTML comments — browsers render them as nothing
|
|
369
|
+
html = html.replace(/<!--[\s\S]*?-->/g, (match) => {
|
|
370
|
+
const idx = safeTags.length;
|
|
371
|
+
safeTags.push(match);
|
|
372
|
+
return `${PLACEHOLDER_HT}${idx}§`;
|
|
373
|
+
});
|
|
374
|
+
html = html.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)\b[^>]*\/?>/g, (match, tagName) => {
|
|
375
|
+
if (tagName.toLowerCase() in htmlAllow) {
|
|
376
|
+
const sanitized = sanitizeHtmlTagAttrs(match);
|
|
377
|
+
const idx = safeTags.length;
|
|
378
|
+
safeTags.push(sanitized);
|
|
379
|
+
return `${PLACEHOLDER_HT}${idx}§`;
|
|
380
|
+
}
|
|
381
|
+
// Not whitelisted — leave in text for Phase 2 to escape
|
|
382
|
+
return match;
|
|
383
|
+
});
|
|
384
|
+
}
|
|
385
|
+
|
|
310
386
|
// ────────────────────────────────────────────────────────────────
|
|
311
387
|
// Phase 2 — HTML Escaping
|
|
312
388
|
// ────────────────────────────────────────────────────────────────
|
|
313
389
|
// All remaining text (everything except code placeholders) is escaped
|
|
314
390
|
// to prevent XSS. The `allow_unsafe_html` option skips this for
|
|
315
391
|
// trusted pipelines that intentionally embed raw HTML.
|
|
392
|
+
// For whitelist mode, escaping still runs (only `true` bypasses it).
|
|
316
393
|
|
|
317
|
-
if (
|
|
394
|
+
if (allow_unsafe_html !== true) {
|
|
318
395
|
html = escapeHtml(html);
|
|
319
396
|
}
|
|
320
397
|
|
|
398
|
+
// Restore safe HTML tag placeholders after escaping
|
|
399
|
+
if (htmlAllow) {
|
|
400
|
+
safeTags.forEach((tag, i) => {
|
|
401
|
+
html = html.replace(`${PLACEHOLDER_HT}${i}§`, tag);
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
|
|
321
405
|
// ────────────────────────────────────────────────────────────────
|
|
322
406
|
// Phase 3 — Block Scanning + Inline Formatting + Paragraphs
|
|
323
407
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -559,6 +643,14 @@ function scanLineBlocks(text, getAttr, dataQd) {
|
|
|
559
643
|
while (i < lines.length) {
|
|
560
644
|
const line = lines[i];
|
|
561
645
|
|
|
646
|
+
// ── Markdown comment (reference-link hack) ──
|
|
647
|
+
// [//]: # (comment) or [//]: # "comment" or [//]: #
|
|
648
|
+
// These produce no output — standard markdown comment convention.
|
|
649
|
+
if (/^\[\/\/\]: #/.test(line)) {
|
|
650
|
+
i++;
|
|
651
|
+
continue;
|
|
652
|
+
}
|
|
653
|
+
|
|
562
654
|
// ── Heading ──
|
|
563
655
|
// Count leading '#' characters. Valid heading: 1-6 hashes then a space.
|
|
564
656
|
// Example: "## Hello World ##" → <h2>Hello World</h2>
|
|
@@ -923,6 +1015,7 @@ quikdown.configure = function(options) {
|
|
|
923
1015
|
/** Semantic version (injected at build time) */
|
|
924
1016
|
quikdown.version = quikdownVersion;
|
|
925
1017
|
|
|
1018
|
+
|
|
926
1019
|
// ════════════════════════════════════════════════════════════════════
|
|
927
1020
|
// Exports
|
|
928
1021
|
// ════════════════════════════════════════════════════════════════════
|
package/dist/quikdown.d.ts
CHANGED
|
@@ -52,6 +52,17 @@ declare module 'quikdown' {
|
|
|
52
52
|
*/
|
|
53
53
|
allow_unsafe_urls?: boolean;
|
|
54
54
|
|
|
55
|
+
/**
|
|
56
|
+
* Controls HTML passthrough in parsed output.
|
|
57
|
+
* - false (default): all HTML tags are escaped (secure)
|
|
58
|
+
* - true: all HTML passes through unchanged (unsafe, use with trusted content only)
|
|
59
|
+
* - Record<string, any>: object whose keys are lowercase tag names to allow
|
|
60
|
+
* (e.g. { img: 1, a: 1, div: 1 }). Use quikdown.SAFE_HTML_TAGS for a curated default.
|
|
61
|
+
* - string[]: array of tag names (converted to object internally)
|
|
62
|
+
* @default false
|
|
63
|
+
*/
|
|
64
|
+
allow_unsafe_html?: boolean | Record<string, any> | string[];
|
|
65
|
+
|
|
55
66
|
/**
|
|
56
67
|
* If true, adds data-qd attributes for bidirectional conversion.
|
|
57
68
|
* Enables HTML to Markdown conversion.
|
|
@@ -95,6 +106,7 @@ declare module 'quikdown' {
|
|
|
95
106
|
* The version of quikdown
|
|
96
107
|
*/
|
|
97
108
|
export const version: string;
|
|
109
|
+
|
|
98
110
|
}
|
|
99
111
|
|
|
100
112
|
export = quikdown;
|
package/dist/quikdown.dark.css
CHANGED
package/dist/quikdown.esm.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* quikdown - Lightweight Markdown Parser
|
|
3
|
-
* @version 1.2.
|
|
3
|
+
* @version 1.2.11
|
|
4
4
|
* @license BSD-2-Clause
|
|
5
5
|
* @copyright DeftIO 2025
|
|
6
6
|
*/
|
|
@@ -112,7 +112,7 @@ function isDashHRLine(trimmed) {
|
|
|
112
112
|
// ────────────────────────────────────────────────────────────────────
|
|
113
113
|
|
|
114
114
|
/** Build-time version stamp (injected by tools/updateVersion) */
|
|
115
|
-
const quikdownVersion = '1.2.
|
|
115
|
+
const quikdownVersion = '1.2.11';
|
|
116
116
|
|
|
117
117
|
/** CSS class prefix used for all generated elements */
|
|
118
118
|
const CLASS_PREFIX = 'quikdown-';
|
|
@@ -120,6 +120,10 @@ const CLASS_PREFIX = 'quikdown-';
|
|
|
120
120
|
/** Placeholder sigils — chosen to be extremely unlikely in real text */
|
|
121
121
|
const PLACEHOLDER_CB = '§CB'; // fenced code blocks
|
|
122
122
|
const PLACEHOLDER_IC = '§IC'; // inline code spans
|
|
123
|
+
const PLACEHOLDER_HT = '§HT'; // safe HTML tags (limited mode)
|
|
124
|
+
|
|
125
|
+
/** Attributes whose values need URL sanitization */
|
|
126
|
+
const URL_ATTRIBUTES = { href:1, src:1, action:1, formaction:1 };
|
|
123
127
|
|
|
124
128
|
/** HTML entity escape map */
|
|
125
129
|
const ESC_MAP = {'&':'&','<':'<','>':'>','"':'"',"'":'''};
|
|
@@ -254,6 +258,46 @@ function quikdown(markdown, options = {}) {
|
|
|
254
258
|
return trimmedUrl;
|
|
255
259
|
}
|
|
256
260
|
|
|
261
|
+
/**
|
|
262
|
+
* Sanitize attributes on an HTML tag string for limited mode.
|
|
263
|
+
* Strips on* event handlers (case-insensitive) and runs sanitizeUrl()
|
|
264
|
+
* on href/src/action/formaction values.
|
|
265
|
+
*/
|
|
266
|
+
function sanitizeHtmlTagAttrs(tagStr) {
|
|
267
|
+
// Self-closing or void tag without attributes — pass through
|
|
268
|
+
if (!/\s/.test(tagStr.replace(/<\/?[a-zA-Z][a-zA-Z0-9]*/, '').replace(/\/?>$/, ''))) {
|
|
269
|
+
return tagStr;
|
|
270
|
+
}
|
|
271
|
+
// Parse: <tagname ...attrs... > or <tagname ...attrs... />
|
|
272
|
+
const m = tagStr.match(/^(<\/?[a-zA-Z][a-zA-Z0-9]*)([\s\S]*?)(\/?>)$/);
|
|
273
|
+
/* istanbul ignore next - defensive: Phase 1.5 regex guarantees valid tag shape */
|
|
274
|
+
if (!m) return tagStr;
|
|
275
|
+
|
|
276
|
+
const [, open, attrStr, close] = m;
|
|
277
|
+
// Match individual attributes: name="value", name='value', name=value, or bare name
|
|
278
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- linear: no nested quantifiers
|
|
279
|
+
const attrRe = /([a-zA-Z_][\w\-.:]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g;
|
|
280
|
+
const attrs = [];
|
|
281
|
+
let am;
|
|
282
|
+
while ((am = attrRe.exec(attrStr)) !== null) {
|
|
283
|
+
const name = am[1];
|
|
284
|
+
const value = am[2] !== undefined ? am[2] : am[3] !== undefined ? am[3] : am[4];
|
|
285
|
+
// Strip event handlers (on*)
|
|
286
|
+
if (/^on/i.test(name)) continue;
|
|
287
|
+
if (value === undefined) {
|
|
288
|
+
// Boolean attribute (e.g. disabled, checked)
|
|
289
|
+
attrs.push(name);
|
|
290
|
+
} else {
|
|
291
|
+
let sanitized = value;
|
|
292
|
+
if (name.toLowerCase() in URL_ATTRIBUTES) {
|
|
293
|
+
sanitized = sanitizeUrl(value);
|
|
294
|
+
}
|
|
295
|
+
attrs.push(`${name}="${sanitized}"`);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
return open + (attrs.length ? ' ' + attrs.join(' ') : '') + close;
|
|
299
|
+
}
|
|
300
|
+
|
|
257
301
|
// ────────────────────────────────────────────────────────────────
|
|
258
302
|
// Phase 1 — Code Extraction
|
|
259
303
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -305,17 +349,57 @@ function quikdown(markdown, options = {}) {
|
|
|
305
349
|
return placeholder;
|
|
306
350
|
});
|
|
307
351
|
|
|
352
|
+
// ────────────────────────────────────────────────────────────────
|
|
353
|
+
// Phase 1.5 — Safe HTML Extraction (whitelist mode)
|
|
354
|
+
// ────────────────────────────────────────────────────────────────
|
|
355
|
+
// When allow_unsafe_html is an object or array, extract whitelisted
|
|
356
|
+
// HTML tags, sanitize their attributes, and replace with placeholders.
|
|
357
|
+
// Non-whitelisted tags stay in text so Phase 2 will escape them.
|
|
358
|
+
|
|
359
|
+
const safeTags = [];
|
|
360
|
+
// Normalize: array → object for O(1) lookup; object used as-is
|
|
361
|
+
const htmlAllow = Array.isArray(allow_unsafe_html)
|
|
362
|
+
? Object.fromEntries(allow_unsafe_html.map(t => [t, 1]))
|
|
363
|
+
: (allow_unsafe_html && typeof allow_unsafe_html === 'object') ? allow_unsafe_html : null;
|
|
364
|
+
|
|
365
|
+
if (htmlAllow) {
|
|
366
|
+
// Pass through HTML comments — browsers render them as nothing
|
|
367
|
+
html = html.replace(/<!--[\s\S]*?-->/g, (match) => {
|
|
368
|
+
const idx = safeTags.length;
|
|
369
|
+
safeTags.push(match);
|
|
370
|
+
return `${PLACEHOLDER_HT}${idx}§`;
|
|
371
|
+
});
|
|
372
|
+
html = html.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)\b[^>]*\/?>/g, (match, tagName) => {
|
|
373
|
+
if (tagName.toLowerCase() in htmlAllow) {
|
|
374
|
+
const sanitized = sanitizeHtmlTagAttrs(match);
|
|
375
|
+
const idx = safeTags.length;
|
|
376
|
+
safeTags.push(sanitized);
|
|
377
|
+
return `${PLACEHOLDER_HT}${idx}§`;
|
|
378
|
+
}
|
|
379
|
+
// Not whitelisted — leave in text for Phase 2 to escape
|
|
380
|
+
return match;
|
|
381
|
+
});
|
|
382
|
+
}
|
|
383
|
+
|
|
308
384
|
// ────────────────────────────────────────────────────────────────
|
|
309
385
|
// Phase 2 — HTML Escaping
|
|
310
386
|
// ────────────────────────────────────────────────────────────────
|
|
311
387
|
// All remaining text (everything except code placeholders) is escaped
|
|
312
388
|
// to prevent XSS. The `allow_unsafe_html` option skips this for
|
|
313
389
|
// trusted pipelines that intentionally embed raw HTML.
|
|
390
|
+
// For whitelist mode, escaping still runs (only `true` bypasses it).
|
|
314
391
|
|
|
315
|
-
if (
|
|
392
|
+
if (allow_unsafe_html !== true) {
|
|
316
393
|
html = escapeHtml(html);
|
|
317
394
|
}
|
|
318
395
|
|
|
396
|
+
// Restore safe HTML tag placeholders after escaping
|
|
397
|
+
if (htmlAllow) {
|
|
398
|
+
safeTags.forEach((tag, i) => {
|
|
399
|
+
html = html.replace(`${PLACEHOLDER_HT}${i}§`, tag);
|
|
400
|
+
});
|
|
401
|
+
}
|
|
402
|
+
|
|
319
403
|
// ────────────────────────────────────────────────────────────────
|
|
320
404
|
// Phase 3 — Block Scanning + Inline Formatting + Paragraphs
|
|
321
405
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -557,6 +641,14 @@ function scanLineBlocks(text, getAttr, dataQd) {
|
|
|
557
641
|
while (i < lines.length) {
|
|
558
642
|
const line = lines[i];
|
|
559
643
|
|
|
644
|
+
// ── Markdown comment (reference-link hack) ──
|
|
645
|
+
// [//]: # (comment) or [//]: # "comment" or [//]: #
|
|
646
|
+
// These produce no output — standard markdown comment convention.
|
|
647
|
+
if (/^\[\/\/\]: #/.test(line)) {
|
|
648
|
+
i++;
|
|
649
|
+
continue;
|
|
650
|
+
}
|
|
651
|
+
|
|
560
652
|
// ── Heading ──
|
|
561
653
|
// Count leading '#' characters. Valid heading: 1-6 hashes then a space.
|
|
562
654
|
// Example: "## Hello World ##" → <h2>Hello World</h2>
|
|
@@ -921,6 +1013,7 @@ quikdown.configure = function(options) {
|
|
|
921
1013
|
/** Semantic version (injected at build time) */
|
|
922
1014
|
quikdown.version = quikdownVersion;
|
|
923
1015
|
|
|
1016
|
+
|
|
924
1017
|
// ════════════════════════════════════════════════════════════════════
|
|
925
1018
|
// Exports
|
|
926
1019
|
// ════════════════════════════════════════════════════════════════════
|
package/dist/quikdown.esm.min.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* quikdown - Lightweight Markdown Parser
|
|
3
|
-
* @version 1.2.
|
|
3
|
+
* @version 1.2.11
|
|
4
4
|
* @license BSD-2-Clause
|
|
5
5
|
* @copyright DeftIO 2025
|
|
6
6
|
*/
|
|
7
|
-
function e(e){if(e.length<3)return!1;for(let t=0;t<e.length;t++){const n=e[t];if("-"!==n){if(" "===n||"\t"===n){for(let n=t+1;n<e.length;n++)if(" "!==e[n]&&"\t"!==e[n])return!1;return t>=3}return!1}}return!0}const t="quikdown-",n="§CB",r={"&":"&","<":"<",">":">",'"':""","'":"'"},o={h1:"font-size:2em;font-weight:600;margin:.67em 0;text-align:left",h2:"font-size:1.5em;font-weight:600;margin:.83em 0",h3:"font-size:1.25em;font-weight:600;margin:1em 0",h4:"font-size:1em;font-weight:600;margin:1.33em 0",h5:"font-size:.875em;font-weight:600;margin:1.67em 0",h6:"font-size:.85em;font-weight:600;margin:2em 0",pre:"background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0",code:"background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace",blockquote:"border-left:4px solid #ddd;margin-left:0;padding-left:1em",table:"border-collapse:collapse;width:100%;margin:1em 0",th:"border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left",td:"border:1px solid #ddd;padding:8px;text-align:left",hr:"border:none;border-top:1px solid #ddd;margin:1em 0",img:"max-width:100%;height:auto",a:"color:#06c;text-decoration:underline",strong:"font-weight:bold",em:"font-style:italic",del:"text-decoration:line-through",ul:"margin:.5em 0;padding-left:2em",ol:"margin:.5em 0;padding-left:2em",li:"margin:.25em 0","task-item":"list-style:none","task-checkbox":"margin-right:.5em"};function l(l,a={}){if(!l||"string"!=typeof l)return"";const{fence_plugin:s,inline_styles:i=!1,bidirectional:p=!1,lazy_linefeeds:d=!1,allow_unsafe_html:g=!1}=a,f=function(e,n){return function(r,o=""){if(e){let e=n[r];return e||o?(o&&o.includes("text-align")&&e&&e.includes("text-align")&&(e=e.replace(/text-align:[^;]+;?/,"").trim(),e&&!e.endsWith(";")&&(e+=";")),` style="${o?e?`${e}${o}`:o:e}"`):""}{const e=` class="${t}${r}"`;return o?`${e} style="${o}"`:e}}}(i,o);function $(e){return e.replace(/[&<>"']/g,e=>r[e])}const u=p?e=>` data-qd="${$(e)}"`:()=>"";function h(e,t=!1){if(!e)return"";if(t)return e;const n=e.trim(),r=n.toLowerCase(),o=["javascript:","vbscript:","data:"];for(const e of o)if(r.startsWith(e))return"data:"===e&&r.startsWith("data:image/")?n:"#";return n}let m=l;const b=[],_=[];m=m.replace(/^(```|~~~)([^\n]*)\n([\s\S]*?)^\1$/gm,(e,t,r,o)=>{const l=`${n}${b.length}§`,a=r?r.trim():"";return s&&s.render&&"function"==typeof s.render?b.push({lang:a,code:o.trimEnd(),custom:!0,fence:t,hasReverse:!!s.reverse}):b.push({lang:a,code:$(o.trimEnd()),custom:!1,fence:t}),l}),m=m.replace(/`([^`]+)`/g,(e,t)=>{const n=`§IC${_.length}§`;return _.push($(t)),n}),g||(m=$(m)),m=function(e,t){const n=e.split("\n"),r=[];let o=!1,l=[];for(let e=0;e<n.length;e++){const a=n[e].trim();if(a.includes("|")&&(a.startsWith("|")||/[^\\|]/.test(a)))o||(o=!0,l=[]),l.push(a);else{if(o){const e=c(l,t);e?r.push(e):r.push(...l),o=!1,l=[]}r.push(n[e])}}if(o&&l.length>0){const e=c(l,t);e?r.push(e):r.push(...l)}return r.join("\n")}(m,f),m=function(t,n,r){const o=t.split("\n"),l=[];let a=0;for(;a<o.length;){const t=o[a];let c=0;for(;c<t.length&&c<7&&"#"===t[c];)c++;if(c>=1&&c<=6&&" "===t[c]){const e=t.slice(c+1).replace(/\s*#+\s*$/,""),o="h"+c;l.push(`<${o}${n(o)}${r("#".repeat(c))}>${e}</${o}>`),a++;continue}e(t)?(l.push(`<hr${n("hr")}>`),a++):/^>\s+/.test(t)?(l.push(`<blockquote${n("blockquote")}>${t.replace(/^>\s+/,"")}</blockquote>`),a++):(l.push(t),a++)}let c=l.join("\n");return c=c.replace(/<\/blockquote>\n<blockquote>/g,"\n"),c}(m,f,u),m=function(e,n,r,o){const l=e.split("\n"),a=[],c=[],s=e=>e.replace(/[&<>"']/g,e=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[e])),i=o?e=>` data-qd="${s(e)}"`:()=>"";for(let e=0;e<l.length;e++){const o=l[e],s=o.match(/^(\s*)([*\-+]|\d+\.)\s+(.+)$/);if(s){const[,e,o,l]=s,p=Math.floor(e.length/2),d=/^\d+\./.test(o),g=d?"ol":"ul";let f=l,$="";const u=l.match(/^\[([x ])\]\s+(.*)$/i);if(u&&!d){const[,e,n]=u,o="x"===e.toLowerCase();f=`<input type="checkbox"${r?' style="margin-right:.5em"':` class="${t}task-checkbox"`}${o?" checked":""} disabled> ${n}`,$=r?' style="list-style:none"':` class="${t}task-item"`}for(;c.length>p+1;){const e=c.pop();a.push(`</${e.type}>`)}if(c.length===p)c.push({type:g,level:p}),a.push(`<${g}${n(g)}>`);else if(c.length===p+1){const e=c[c.length-1];e.type!==g&&(a.push(`</${e.type}>`),c.pop(),c.push({type:g,level:p}),a.push(`<${g}${n(g)}>`))}const h=$||n("li");a.push(`<li${h}${i(o)}>${f}</li>`)}else{for(;c.length>0;){const e=c.pop();a.push(`</${e.type}>`)}a.push(o)}}for(;c.length>0;){const e=c.pop();a.push(`</${e.type}>`)}return a.join("\n")}(m,f,i,p),m=m.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(e,t,n)=>{const r=h(n,a.allow_unsafe_urls),o=p&&t?` data-qd-alt="${$(t)}"`:"",l=p?` data-qd-src="${$(n)}"`:"";return`<img${f("img")} src="${r}" alt="${t}"${o}${l}${u("!")}>`}),m=m.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,t,n)=>{const r=h(n,a.allow_unsafe_urls),o=/^https?:\/\//i.test(r)?' rel="noopener noreferrer"':"",l=p?` data-qd-text="${$(t)}"`:"";return`<a${f("a")} href="${r}"${o}${l}${u("[")}>${t}</a>`}),m=m.replace(/(^|\s)(https?:\/\/[^\s<]+)/g,(e,t,n)=>{const r=h(n,a.allow_unsafe_urls);return`${t}<a${f("a")} href="${r}" rel="noopener noreferrer">${n}</a>`});const x=[];m=m.replace(/<[^>]+>/g,e=>(x.push(e),`%%T${x.length-1}%%`));if([[/\*\*(.+?)\*\*/g,"strong","**"],[/__(.+?)__/g,"strong","__"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em","*"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em","_"],[/~~(.+?)~~/g,"del","~~"]].forEach(([e,t,n])=>{m=m.replace(e,`<${t}${f(t)}${u(n)}>$1</${t}>`)}),m=m.replace(/%%T(\d+)%%/g,(e,t)=>x[t]),d){const e=[];let t=0;m=m.replace(/<(table|[uo]l)[^>]*>[\s\S]*?<\/\1>/g,n=>(e[t]=n,`§B${t++}§`)),m=m.replace(/\n\n+/g,"§P§").replace(/(<\/(?:h[1-6]|blockquote|pre)>)\n/g,"$1§N§").replace(/(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)\n/g,"$1§N§").replace(/\n(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)/g,"§N§$1").replace(/\n(§B\d+§)/g,"§N§$1").replace(/(§B\d+§)\n/g,"$1§N§").replace(/\n/g,`<br${f("br")}>`).replace(/§N§/g,"\n").replace(/§P§/g,"</p><p>"),e.forEach((e,t)=>m=m.replace(`§B${t}§`,e)),m="<p>"+m+"</p>"}else m=m.replace(/ {2}$/gm,`<br${f("br")}>`),m=m.replace(/\n\n+/g,(e,t)=>m.substring(0,t).match(/<\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)?"<p>":"</p><p>"),m="<p>"+m+"</p>";return[[/<p><\/p>/g,""],[/<p>(<h[1-6][^>]*>)/g,"$1"],[/(<\/h[1-6]>)<\/p>/g,"$1"],[/<p>(<blockquote[^>]*>)/g,"$1"],[/(<\/blockquote>)<\/p>/g,"$1"],[/<p>(<ul[^>]*>|<ol[^>]*>)/g,"$1"],[/(<\/ul>|<\/ol>)<\/p>/g,"$1"],[/<p>(<hr[^>]*>)<\/p>/g,"$1"],[/<p>(<table[^>]*>)/g,"$1"],[/(<\/table>)<\/p>/g,"$1"],[/<p>(<pre[^>]*>)/g,"$1"],[/(<\/pre>)<\/p>/g,"$1"],[new RegExp(`<p>(${n}\\d+§)</p>`,"g"),"$1"]].forEach(([e,t])=>{m=m.replace(e,t)}),m=m.replace(/(<\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\n([^<])/g,"$1\n<p>$2"),b.forEach((e,t)=>{let r;if(e.custom&&s&&s.render)if(r=s.render(e.code,e.lang),void 0===r){const t=!i&&e.lang?` class="language-${e.lang}"`:"",n=i?f("code"):t,o=p&&e.lang?` data-qd-lang="${$(e.lang)}"`:"",l=p?` data-qd-fence="${$(e.fence)}"`:"";r=`<pre${f("pre")}${l}${o}><code${n}>${$(e.code)}</code></pre>`}else p&&(r=r.replace(/^<(\w+)/,`<$1 data-qd-fence="${$(e.fence)}" data-qd-lang="${$(e.lang)}" data-qd-source="${$(e.code)}"`));else{const t=!i&&e.lang?` class="language-${e.lang}"`:"",n=i?f("code"):t,o=p&&e.lang?` data-qd-lang="${$(e.lang)}"`:"",l=p?` data-qd-fence="${$(e.fence)}"`:"";r=`<pre${f("pre")}${l}${o}><code${n}>${e.code}</code></pre>`}const o=`${n}${t}§`;m=m.replace(o,r)}),_.forEach((e,t)=>{const n=`§IC${t}§`;m=m.replace(n,`<code${f("code")}${u("`")}>${e}</code>`)}),m.trim()}function a(e,t){return[[/\*\*(.+?)\*\*/g,"strong"],[/__(.+?)__/g,"strong"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em"],[/~~(.+?)~~/g,"del"],[/`([^`]+)`/g,"code"]].forEach(([n,r])=>{e=e.replace(n,`<${r}${t(r)}>$1</${r}>`)}),e}function c(e,t){if(e.length<2)return null;let n=-1;for(let t=1;t<e.length;t++)if(/^\|?[\s\-:|]+\|?$/.test(e[t])&&e[t].includes("-")){n=t;break}if(-1===n)return null;const r=e.slice(0,n),o=e.slice(n+1),l=e[n].trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"});let c=`<table${t("table")}>\n`;return c+=`<thead${t("thead")}>\n`,r.forEach(e=>{c+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=l[n]&&"left"!==l[n]?`text-align:${l[n]}`:"",o=a(e.trim(),t);c+=`<th${t("th",r)}>${o}</th>\n`}),c+="</tr>\n"}),c+="</thead>\n",o.length>0&&(c+=`<tbody${t("tbody")}>\n`,o.forEach(e=>{c+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=l[n]&&"left"!==l[n]?`text-align:${l[n]}`:"",o=a(e.trim(),t);c+=`<td${t("td",r)}>${o}</td>\n`}),c+="</tr>\n"}),c+="</tbody>\n"),c+="</table>",c}l.emitStyles=function(e="quikdown-",t="light"){const n=o,r={"#f4f4f4":"#2a2a2a","#f0f0f0":"#2a2a2a","#f2f2f2":"#2a2a2a","#ddd":"#3a3a3a","#06c":"#6db3f2",_textColor:"#e0e0e0"},l={_textColor:"#333"};let a="";for(const[o,c]of Object.entries(n)){let n=c;if("dark"===t&&r){for(const[e,t]of Object.entries(r))e.startsWith("_")||(n=n.replaceAll(e,t));["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(o)&&(n+=`;color:${r._textColor}`)}else if("light"===t&&l){["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(o)&&(n+=`;color:${l._textColor}`)}a+=`.${e}${o} { ${n} }\n`}return a},l.configure=function(e){return function(t){return l(t,e)}},l.version="1.2.10","undefined"!=typeof module&&module.exports&&(module.exports=l),"undefined"!=typeof window&&(window.quikdown=l);export{l as default};
|
|
7
|
+
function e(e){if(e.length<3)return!1;for(let t=0;t<e.length;t++){const n=e[t];if("-"!==n){if(" "===n||"\t"===n){for(let n=t+1;n<e.length;n++)if(" "!==e[n]&&"\t"!==e[n])return!1;return t>=3}return!1}}return!0}const t="quikdown-",n="§CB",r="§HT",o={href:1,src:1,action:1,formaction:1},l={"&":"&","<":"<",">":">",'"':""","'":"'"},a={h1:"font-size:2em;font-weight:600;margin:.67em 0;text-align:left",h2:"font-size:1.5em;font-weight:600;margin:.83em 0",h3:"font-size:1.25em;font-weight:600;margin:1em 0",h4:"font-size:1em;font-weight:600;margin:1.33em 0",h5:"font-size:.875em;font-weight:600;margin:1.67em 0",h6:"font-size:.85em;font-weight:600;margin:2em 0",pre:"background:#f4f4f4;padding:10px;border-radius:4px;overflow-x:auto;margin:1em 0",code:"background:#f0f0f0;padding:2px 4px;border-radius:3px;font-family:monospace",blockquote:"border-left:4px solid #ddd;margin-left:0;padding-left:1em",table:"border-collapse:collapse;width:100%;margin:1em 0",th:"border:1px solid #ddd;padding:8px;background-color:#f2f2f2;font-weight:bold;text-align:left",td:"border:1px solid #ddd;padding:8px;text-align:left",hr:"border:none;border-top:1px solid #ddd;margin:1em 0",img:"max-width:100%;height:auto",a:"color:#06c;text-decoration:underline",strong:"font-weight:bold",em:"font-style:italic",del:"text-decoration:line-through",ul:"margin:.5em 0;padding-left:2em",ol:"margin:.5em 0;padding-left:2em",li:"margin:.25em 0","task-item":"list-style:none","task-checkbox":"margin-right:.5em"};function c(c,s={}){if(!c||"string"!=typeof c)return"";const{fence_plugin:p,inline_styles:g=!1,bidirectional:d=!1,lazy_linefeeds:f=!1,allow_unsafe_html:u=!1}=s,$=function(e,n){return function(r,o=""){if(e){let e=n[r];return e||o?(o&&o.includes("text-align")&&e&&e.includes("text-align")&&(e=e.replace(/text-align:[^;]+;?/,"").trim(),e&&!e.endsWith(";")&&(e+=";")),` style="${o?e?`${e}${o}`:o:e}"`):""}{const e=` class="${t}${r}"`;return o?`${e} style="${o}"`:e}}}(g,a);function h(e){return e.replace(/[&<>"']/g,e=>l[e])}const m=d?e=>` data-qd="${h(e)}"`:()=>"";function b(e,t=!1){if(!e)return"";if(t)return e;const n=e.trim(),r=n.toLowerCase(),o=["javascript:","vbscript:","data:"];for(const e of o)if(r.startsWith(e))return"data:"===e&&r.startsWith("data:image/")?n:"#";return n}let _=c;const x=[],q=[];_=_.replace(/^(```|~~~)([^\n]*)\n([\s\S]*?)^\1$/gm,(e,t,r,o)=>{const l=`${n}${x.length}§`,a=r?r.trim():"";return p&&p.render&&"function"==typeof p.render?x.push({lang:a,code:o.trimEnd(),custom:!0,fence:t,hasReverse:!!p.reverse}):x.push({lang:a,code:h(o.trimEnd()),custom:!1,fence:t}),l}),_=_.replace(/`([^`]+)`/g,(e,t)=>{const n=`§IC${q.length}§`;return q.push(h(t)),n});const k=[],w=Array.isArray(u)?Object.fromEntries(u.map(e=>[e,1])):u&&"object"==typeof u?u:null;w&&(_=_.replace(/<!--[\s\S]*?-->/g,e=>{const t=k.length;return k.push(e),`${r}${t}§`}),_=_.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)\b[^>]*\/?>/g,(e,t)=>{if(t.toLowerCase()in w){const t=function(e){if(!/\s/.test(e.replace(/<\/?[a-zA-Z][a-zA-Z0-9]*/,"").replace(/\/?>$/,"")))return e;const t=e.match(/^(<\/?[a-zA-Z][a-zA-Z0-9]*)([\s\S]*?)(\/?>)$/);if(!t)return e;const[,n,r,l]=t,a=/([a-zA-Z_][\w\-.:]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g,c=[];let s;for(;null!==(s=a.exec(r));){const e=s[1],t=void 0!==s[2]?s[2]:void 0!==s[3]?s[3]:s[4];if(!/^on/i.test(e))if(void 0===t)c.push(e);else{let n=t;e.toLowerCase()in o&&(n=b(t)),c.push(`${e}="${n}"`)}}return n+(c.length?" "+c.join(" "):"")+l}(e),n=k.length;return k.push(t),`${r}${n}§`}return e})),!0!==u&&(_=h(_)),w&&k.forEach((e,t)=>{_=_.replace(`${r}${t}§`,e)}),_=function(e,t){const n=e.split("\n"),r=[];let o=!1,l=[];for(let e=0;e<n.length;e++){const a=n[e].trim();if(a.includes("|")&&(a.startsWith("|")||/[^\\|]/.test(a)))o||(o=!0,l=[]),l.push(a);else{if(o){const e=i(l,t);e?r.push(e):r.push(...l),o=!1,l=[]}r.push(n[e])}}if(o&&l.length>0){const e=i(l,t);e?r.push(e):r.push(...l)}return r.join("\n")}(_,$),_=function(t,n,r){const o=t.split("\n"),l=[];let a=0;for(;a<o.length;){const t=o[a];if(/^\[\/\/\]: #/.test(t)){a++;continue}let c=0;for(;c<t.length&&c<7&&"#"===t[c];)c++;if(c>=1&&c<=6&&" "===t[c]){const e=t.slice(c+1).replace(/\s*#+\s*$/,""),o="h"+c;l.push(`<${o}${n(o)}${r("#".repeat(c))}>${e}</${o}>`),a++;continue}e(t)?(l.push(`<hr${n("hr")}>`),a++):/^>\s+/.test(t)?(l.push(`<blockquote${n("blockquote")}>${t.replace(/^>\s+/,"")}</blockquote>`),a++):(l.push(t),a++)}let c=l.join("\n");return c=c.replace(/<\/blockquote>\n<blockquote>/g,"\n"),c}(_,$,m),_=function(e,n,r,o){const l=e.split("\n"),a=[],c=[],s=e=>e.replace(/[&<>"']/g,e=>({"&":"&","<":"<",">":">",'"':""","'":"'"}[e])),i=o?e=>` data-qd="${s(e)}"`:()=>"";for(let e=0;e<l.length;e++){const o=l[e],s=o.match(/^(\s*)([*\-+]|\d+\.)\s+(.+)$/);if(s){const[,e,o,l]=s,p=Math.floor(e.length/2),g=/^\d+\./.test(o),d=g?"ol":"ul";let f=l,u="";const $=l.match(/^\[([x ])\]\s+(.*)$/i);if($&&!g){const[,e,n]=$,o="x"===e.toLowerCase();f=`<input type="checkbox"${r?' style="margin-right:.5em"':` class="${t}task-checkbox"`}${o?" checked":""} disabled> ${n}`,u=r?' style="list-style:none"':` class="${t}task-item"`}for(;c.length>p+1;){const e=c.pop();a.push(`</${e.type}>`)}if(c.length===p)c.push({type:d,level:p}),a.push(`<${d}${n(d)}>`);else if(c.length===p+1){const e=c[c.length-1];e.type!==d&&(a.push(`</${e.type}>`),c.pop(),c.push({type:d,level:p}),a.push(`<${d}${n(d)}>`))}const h=u||n("li");a.push(`<li${h}${i(o)}>${f}</li>`)}else{for(;c.length>0;){const e=c.pop();a.push(`</${e.type}>`)}a.push(o)}}for(;c.length>0;){const e=c.pop();a.push(`</${e.type}>`)}return a.join("\n")}(_,$,g,d),_=_.replace(/!\[([^\]]*)\]\(([^)]+)\)/g,(e,t,n)=>{const r=b(n,s.allow_unsafe_urls),o=d&&t?` data-qd-alt="${h(t)}"`:"",l=d?` data-qd-src="${h(n)}"`:"";return`<img${$("img")} src="${r}" alt="${t}"${o}${l}${m("!")}>`}),_=_.replace(/\[([^\]]+)\]\(([^)]+)\)/g,(e,t,n)=>{const r=b(n,s.allow_unsafe_urls),o=/^https?:\/\//i.test(r)?' rel="noopener noreferrer"':"",l=d?` data-qd-text="${h(t)}"`:"";return`<a${$("a")} href="${r}"${o}${l}${m("[")}>${t}</a>`}),_=_.replace(/(^|\s)(https?:\/\/[^\s<]+)/g,(e,t,n)=>{const r=b(n,s.allow_unsafe_urls);return`${t}<a${$("a")} href="${r}" rel="noopener noreferrer">${n}</a>`});const y=[];_=_.replace(/<[^>]+>/g,e=>(y.push(e),`%%T${y.length-1}%%`));if([[/\*\*(.+?)\*\*/g,"strong","**"],[/__(.+?)__/g,"strong","__"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em","*"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em","_"],[/~~(.+?)~~/g,"del","~~"]].forEach(([e,t,n])=>{_=_.replace(e,`<${t}${$(t)}${m(n)}>$1</${t}>`)}),_=_.replace(/%%T(\d+)%%/g,(e,t)=>y[t]),f){const e=[];let t=0;_=_.replace(/<(table|[uo]l)[^>]*>[\s\S]*?<\/\1>/g,n=>(e[t]=n,`§B${t++}§`)),_=_.replace(/\n\n+/g,"§P§").replace(/(<\/(?:h[1-6]|blockquote|pre)>)\n/g,"$1§N§").replace(/(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)\n/g,"$1§N§").replace(/\n(<(?:h[1-6]|blockquote|pre|hr)[^>]*>)/g,"§N§$1").replace(/\n(§B\d+§)/g,"§N§$1").replace(/(§B\d+§)\n/g,"$1§N§").replace(/\n/g,`<br${$("br")}>`).replace(/§N§/g,"\n").replace(/§P§/g,"</p><p>"),e.forEach((e,t)=>_=_.replace(`§B${t}§`,e)),_="<p>"+_+"</p>"}else _=_.replace(/ {2}$/gm,`<br${$("br")}>`),_=_.replace(/\n\n+/g,(e,t)=>_.substring(0,t).match(/<\/(h[1-6]|blockquote|ul|ol|table|pre|hr)>$/)?"<p>":"</p><p>"),_="<p>"+_+"</p>";return[[/<p><\/p>/g,""],[/<p>(<h[1-6][^>]*>)/g,"$1"],[/(<\/h[1-6]>)<\/p>/g,"$1"],[/<p>(<blockquote[^>]*>)/g,"$1"],[/(<\/blockquote>)<\/p>/g,"$1"],[/<p>(<ul[^>]*>|<ol[^>]*>)/g,"$1"],[/(<\/ul>|<\/ol>)<\/p>/g,"$1"],[/<p>(<hr[^>]*>)<\/p>/g,"$1"],[/<p>(<table[^>]*>)/g,"$1"],[/(<\/table>)<\/p>/g,"$1"],[/<p>(<pre[^>]*>)/g,"$1"],[/(<\/pre>)<\/p>/g,"$1"],[new RegExp(`<p>(${n}\\d+§)</p>`,"g"),"$1"]].forEach(([e,t])=>{_=_.replace(e,t)}),_=_.replace(/(<\/(?:h[1-6]|blockquote|ul|ol|table|pre|hr)>)\n([^<])/g,"$1\n<p>$2"),x.forEach((e,t)=>{let r;if(e.custom&&p&&p.render)if(r=p.render(e.code,e.lang),void 0===r){const t=!g&&e.lang?` class="language-${e.lang}"`:"",n=g?$("code"):t,o=d&&e.lang?` data-qd-lang="${h(e.lang)}"`:"",l=d?` data-qd-fence="${h(e.fence)}"`:"";r=`<pre${$("pre")}${l}${o}><code${n}>${h(e.code)}</code></pre>`}else d&&(r=r.replace(/^<(\w+)/,`<$1 data-qd-fence="${h(e.fence)}" data-qd-lang="${h(e.lang)}" data-qd-source="${h(e.code)}"`));else{const t=!g&&e.lang?` class="language-${e.lang}"`:"",n=g?$("code"):t,o=d&&e.lang?` data-qd-lang="${h(e.lang)}"`:"",l=d?` data-qd-fence="${h(e.fence)}"`:"";r=`<pre${$("pre")}${l}${o}><code${n}>${e.code}</code></pre>`}const o=`${n}${t}§`;_=_.replace(o,r)}),q.forEach((e,t)=>{const n=`§IC${t}§`;_=_.replace(n,`<code${$("code")}${m("`")}>${e}</code>`)}),_.trim()}function s(e,t){return[[/\*\*(.+?)\*\*/g,"strong"],[/__(.+?)__/g,"strong"],[/(?<!\*)\*(?!\*)(.+?)(?<!\*)\*(?!\*)/g,"em"],[/(?<!_)_(?!_)(.+?)(?<!_)_(?!_)/g,"em"],[/~~(.+?)~~/g,"del"],[/`([^`]+)`/g,"code"]].forEach(([n,r])=>{e=e.replace(n,`<${r}${t(r)}>$1</${r}>`)}),e}function i(e,t){if(e.length<2)return null;let n=-1;for(let t=1;t<e.length;t++)if(/^\|?[\s\-:|]+\|?$/.test(e[t])&&e[t].includes("-")){n=t;break}if(-1===n)return null;const r=e.slice(0,n),o=e.slice(n+1),l=e[n].trim().replace(/^\|/,"").replace(/\|$/,"").split("|").map(e=>{const t=e.trim();return t.startsWith(":")&&t.endsWith(":")?"center":t.endsWith(":")?"right":"left"});let a=`<table${t("table")}>\n`;return a+=`<thead${t("thead")}>\n`,r.forEach(e=>{a+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=l[n]&&"left"!==l[n]?`text-align:${l[n]}`:"",o=s(e.trim(),t);a+=`<th${t("th",r)}>${o}</th>\n`}),a+="</tr>\n"}),a+="</thead>\n",o.length>0&&(a+=`<tbody${t("tbody")}>\n`,o.forEach(e=>{a+=`<tr${t("tr")}>\n`;e.trim().replace(/^\|/,"").replace(/\|$/,"").split("|").forEach((e,n)=>{const r=l[n]&&"left"!==l[n]?`text-align:${l[n]}`:"",o=s(e.trim(),t);a+=`<td${t("td",r)}>${o}</td>\n`}),a+="</tr>\n"}),a+="</tbody>\n"),a+="</table>",a}c.emitStyles=function(e="quikdown-",t="light"){const n=a,r={"#f4f4f4":"#2a2a2a","#f0f0f0":"#2a2a2a","#f2f2f2":"#2a2a2a","#ddd":"#3a3a3a","#06c":"#6db3f2",_textColor:"#e0e0e0"},o={_textColor:"#333"};let l="";for(const[a,c]of Object.entries(n)){let n=c;if("dark"===t&&r){for(const[e,t]of Object.entries(r))e.startsWith("_")||(n=n.replaceAll(e,t));["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(a)&&(n+=`;color:${r._textColor}`)}else if("light"===t&&o){["h1","h2","h3","h4","h5","h6","td","li","blockquote"].includes(a)&&(n+=`;color:${o._textColor}`)}l+=`.${e}${a} { ${n} }\n`}return l},c.configure=function(e){return function(t){return c(t,e)}},c.version="1.2.11","undefined"!=typeof module&&module.exports&&(module.exports=c),"undefined"!=typeof window&&(window.quikdown=c);export{c as default};
|
|
8
8
|
//# sourceMappingURL=quikdown.esm.min.js.map
|
|
Binary file
|