quikchat 1.2.6 → 1.2.7
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 +7 -2
- package/dist/build-manifest.json +57 -57
- package/dist/quikchat-md-full.cjs.js +98 -5
- package/dist/quikchat-md-full.cjs.js.map +1 -1
- package/dist/quikchat-md-full.cjs.min.js +3 -3
- package/dist/quikchat-md-full.cjs.min.js.map +1 -1
- package/dist/quikchat-md-full.esm.js +98 -5
- package/dist/quikchat-md-full.esm.js.map +1 -1
- package/dist/quikchat-md-full.esm.min.js +3 -3
- package/dist/quikchat-md-full.esm.min.js.map +1 -1
- package/dist/quikchat-md-full.umd.js +98 -5
- package/dist/quikchat-md-full.umd.js.map +1 -1
- package/dist/quikchat-md-full.umd.min.js +3 -3
- package/dist/quikchat-md-full.umd.min.js.map +1 -1
- package/dist/quikchat-md.cjs.js +98 -5
- package/dist/quikchat-md.cjs.js.map +1 -1
- package/dist/quikchat-md.cjs.min.js +3 -3
- package/dist/quikchat-md.cjs.min.js.map +1 -1
- package/dist/quikchat-md.esm.js +98 -5
- package/dist/quikchat-md.esm.js.map +1 -1
- package/dist/quikchat-md.esm.min.js +3 -3
- package/dist/quikchat-md.esm.min.js.map +1 -1
- package/dist/quikchat-md.umd.js +98 -5
- package/dist/quikchat-md.umd.js.map +1 -1
- package/dist/quikchat-md.umd.min.js +3 -3
- package/dist/quikchat-md.umd.min.js.map +1 -1
- package/dist/quikchat.cjs.js +2 -2
- package/dist/quikchat.cjs.js.map +1 -1
- package/dist/quikchat.cjs.min.js +1 -1
- package/dist/quikchat.cjs.min.js.map +1 -1
- package/dist/quikchat.esm.js +2 -2
- package/dist/quikchat.esm.js.map +1 -1
- package/dist/quikchat.esm.min.js +1 -1
- package/dist/quikchat.esm.min.js.map +1 -1
- package/dist/quikchat.umd.js +2 -2
- package/dist/quikchat.umd.js.map +1 -1
- package/dist/quikchat.umd.min.js +1 -1
- package/dist/quikchat.umd.min.js.map +1 -1
- package/package.json +2 -2
package/dist/quikchat-md.cjs.js
CHANGED
|
@@ -900,9 +900,9 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
900
900
|
key: "version",
|
|
901
901
|
value: function version() {
|
|
902
902
|
return {
|
|
903
|
-
"version": "1.2.
|
|
903
|
+
"version": "1.2.7",
|
|
904
904
|
"license": "BSD-2",
|
|
905
|
-
"url": "https://github/deftio/quikchat"
|
|
905
|
+
"url": "https://github.com/deftio/quikchat"
|
|
906
906
|
};
|
|
907
907
|
}
|
|
908
908
|
|
|
@@ -960,7 +960,7 @@ var quikchat = /*#__PURE__*/function () {
|
|
|
960
960
|
|
|
961
961
|
/**
|
|
962
962
|
* quikdown - Lightweight Markdown Parser
|
|
963
|
-
* @version 1.2.
|
|
963
|
+
* @version 1.2.12
|
|
964
964
|
* @license BSD-2-Clause
|
|
965
965
|
* @copyright DeftIO 2025
|
|
966
966
|
*/
|
|
@@ -1072,7 +1072,7 @@ function isDashHRLine(trimmed) {
|
|
|
1072
1072
|
// ────────────────────────────────────────────────────────────────────
|
|
1073
1073
|
|
|
1074
1074
|
/** Build-time version stamp (injected by tools/updateVersion) */
|
|
1075
|
-
const quikdownVersion = '1.2.
|
|
1075
|
+
const quikdownVersion = '1.2.12';
|
|
1076
1076
|
|
|
1077
1077
|
/** CSS class prefix used for all generated elements */
|
|
1078
1078
|
const CLASS_PREFIX = 'quikdown-';
|
|
@@ -1080,6 +1080,10 @@ const CLASS_PREFIX = 'quikdown-';
|
|
|
1080
1080
|
/** Placeholder sigils — chosen to be extremely unlikely in real text */
|
|
1081
1081
|
const PLACEHOLDER_CB = '§CB'; // fenced code blocks
|
|
1082
1082
|
const PLACEHOLDER_IC = '§IC'; // inline code spans
|
|
1083
|
+
const PLACEHOLDER_HT = '§HT'; // safe HTML tags (limited mode)
|
|
1084
|
+
|
|
1085
|
+
/** Attributes whose values need URL sanitization */
|
|
1086
|
+
const URL_ATTRIBUTES = { href:1, src:1, action:1, formaction:1 };
|
|
1083
1087
|
|
|
1084
1088
|
/** HTML entity escape map */
|
|
1085
1089
|
const ESC_MAP = {'&':'&','<':'<','>':'>','"':'"',"'":'''};
|
|
@@ -1214,6 +1218,46 @@ function quikdown(markdown, options = {}) {
|
|
|
1214
1218
|
return trimmedUrl;
|
|
1215
1219
|
}
|
|
1216
1220
|
|
|
1221
|
+
/**
|
|
1222
|
+
* Sanitize attributes on an HTML tag string for limited mode.
|
|
1223
|
+
* Strips on* event handlers (case-insensitive) and runs sanitizeUrl()
|
|
1224
|
+
* on href/src/action/formaction values.
|
|
1225
|
+
*/
|
|
1226
|
+
function sanitizeHtmlTagAttrs(tagStr) {
|
|
1227
|
+
// Self-closing or void tag without attributes — pass through
|
|
1228
|
+
if (!/\s/.test(tagStr.replace(/<\/?[a-zA-Z][a-zA-Z0-9]*/, '').replace(/\/?>$/, ''))) {
|
|
1229
|
+
return tagStr;
|
|
1230
|
+
}
|
|
1231
|
+
// Parse: <tagname ...attrs... > or <tagname ...attrs... />
|
|
1232
|
+
const m = tagStr.match(/^(<\/?[a-zA-Z][a-zA-Z0-9]*)([\s\S]*?)(\/?>)$/);
|
|
1233
|
+
/* istanbul ignore next - defensive: Phase 1.5 regex guarantees valid tag shape */
|
|
1234
|
+
if (!m) return tagStr;
|
|
1235
|
+
|
|
1236
|
+
const [, open, attrStr, close] = m;
|
|
1237
|
+
// Match individual attributes: name="value", name='value', name=value, or bare name
|
|
1238
|
+
// eslint-disable-next-line security/detect-unsafe-regex -- linear: no nested quantifiers
|
|
1239
|
+
const attrRe = /([a-zA-Z_][\w\-.:]*)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|(\S+)))?/g;
|
|
1240
|
+
const attrs = [];
|
|
1241
|
+
let am;
|
|
1242
|
+
while ((am = attrRe.exec(attrStr)) !== null) {
|
|
1243
|
+
const name = am[1];
|
|
1244
|
+
const value = am[2] !== undefined ? am[2] : am[3] !== undefined ? am[3] : am[4];
|
|
1245
|
+
// Strip event handlers (on*)
|
|
1246
|
+
if (/^on/i.test(name)) continue;
|
|
1247
|
+
if (value === undefined) {
|
|
1248
|
+
// Boolean attribute (e.g. disabled, checked)
|
|
1249
|
+
attrs.push(name);
|
|
1250
|
+
} else {
|
|
1251
|
+
let sanitized = value;
|
|
1252
|
+
if (name.toLowerCase() in URL_ATTRIBUTES) {
|
|
1253
|
+
sanitized = sanitizeUrl(value);
|
|
1254
|
+
}
|
|
1255
|
+
attrs.push(`${name}="${sanitized}"`);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
return open + (attrs.length ? ' ' + attrs.join(' ') : '') + close;
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1217
1261
|
// ────────────────────────────────────────────────────────────────
|
|
1218
1262
|
// Phase 1 — Code Extraction
|
|
1219
1263
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -1265,17 +1309,57 @@ function quikdown(markdown, options = {}) {
|
|
|
1265
1309
|
return placeholder;
|
|
1266
1310
|
});
|
|
1267
1311
|
|
|
1312
|
+
// ────────────────────────────────────────────────────────────────
|
|
1313
|
+
// Phase 1.5 — Safe HTML Extraction (whitelist mode)
|
|
1314
|
+
// ────────────────────────────────────────────────────────────────
|
|
1315
|
+
// When allow_unsafe_html is an object or array, extract whitelisted
|
|
1316
|
+
// HTML tags, sanitize their attributes, and replace with placeholders.
|
|
1317
|
+
// Non-whitelisted tags stay in text so Phase 2 will escape them.
|
|
1318
|
+
|
|
1319
|
+
const safeTags = [];
|
|
1320
|
+
// Normalize: array → object for O(1) lookup; object used as-is
|
|
1321
|
+
const htmlAllow = Array.isArray(allow_unsafe_html)
|
|
1322
|
+
? Object.fromEntries(allow_unsafe_html.map(t => [t, 1]))
|
|
1323
|
+
: (allow_unsafe_html && typeof allow_unsafe_html === 'object') ? allow_unsafe_html : null;
|
|
1324
|
+
|
|
1325
|
+
if (htmlAllow) {
|
|
1326
|
+
// Pass through HTML comments — browsers render them as nothing
|
|
1327
|
+
html = html.replace(/<!--[\s\S]*?-->/g, (match) => {
|
|
1328
|
+
const idx = safeTags.length;
|
|
1329
|
+
safeTags.push(match);
|
|
1330
|
+
return `${PLACEHOLDER_HT}${idx}§`;
|
|
1331
|
+
});
|
|
1332
|
+
html = html.replace(/<\/?([a-zA-Z][a-zA-Z0-9]*)\b[^>]*\/?>/g, (match, tagName) => {
|
|
1333
|
+
if (tagName.toLowerCase() in htmlAllow) {
|
|
1334
|
+
const sanitized = sanitizeHtmlTagAttrs(match);
|
|
1335
|
+
const idx = safeTags.length;
|
|
1336
|
+
safeTags.push(sanitized);
|
|
1337
|
+
return `${PLACEHOLDER_HT}${idx}§`;
|
|
1338
|
+
}
|
|
1339
|
+
// Not whitelisted — leave in text for Phase 2 to escape
|
|
1340
|
+
return match;
|
|
1341
|
+
});
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1268
1344
|
// ────────────────────────────────────────────────────────────────
|
|
1269
1345
|
// Phase 2 — HTML Escaping
|
|
1270
1346
|
// ────────────────────────────────────────────────────────────────
|
|
1271
1347
|
// All remaining text (everything except code placeholders) is escaped
|
|
1272
1348
|
// to prevent XSS. The `allow_unsafe_html` option skips this for
|
|
1273
1349
|
// trusted pipelines that intentionally embed raw HTML.
|
|
1350
|
+
// For whitelist mode, escaping still runs (only `true` bypasses it).
|
|
1274
1351
|
|
|
1275
|
-
if (
|
|
1352
|
+
if (allow_unsafe_html !== true) {
|
|
1276
1353
|
html = escapeHtml(html);
|
|
1277
1354
|
}
|
|
1278
1355
|
|
|
1356
|
+
// Restore safe HTML tag placeholders after escaping
|
|
1357
|
+
if (htmlAllow) {
|
|
1358
|
+
safeTags.forEach((tag, i) => {
|
|
1359
|
+
html = html.replace(`${PLACEHOLDER_HT}${i}§`, tag);
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1279
1363
|
// ────────────────────────────────────────────────────────────────
|
|
1280
1364
|
// Phase 3 — Block Scanning + Inline Formatting + Paragraphs
|
|
1281
1365
|
// ────────────────────────────────────────────────────────────────
|
|
@@ -1517,6 +1601,14 @@ function scanLineBlocks(text, getAttr, dataQd) {
|
|
|
1517
1601
|
while (i < lines.length) {
|
|
1518
1602
|
const line = lines[i];
|
|
1519
1603
|
|
|
1604
|
+
// ── Markdown comment (reference-link hack) ──
|
|
1605
|
+
// [//]: # (comment) or [//]: # "comment" or [//]: #
|
|
1606
|
+
// These produce no output — standard markdown comment convention.
|
|
1607
|
+
if (/^\[\/\/\]: #/.test(line)) {
|
|
1608
|
+
i++;
|
|
1609
|
+
continue;
|
|
1610
|
+
}
|
|
1611
|
+
|
|
1520
1612
|
// ── Heading ──
|
|
1521
1613
|
// Count leading '#' characters. Valid heading: 1-6 hashes then a space.
|
|
1522
1614
|
// Example: "## Hello World ##" → <h2>Hello World</h2>
|
|
@@ -1881,6 +1973,7 @@ quikdown.configure = function(options) {
|
|
|
1881
1973
|
/** Semantic version (injected at build time) */
|
|
1882
1974
|
quikdown.version = quikdownVersion;
|
|
1883
1975
|
|
|
1976
|
+
|
|
1884
1977
|
// ════════════════════════════════════════════════════════════════════
|
|
1885
1978
|
// Exports
|
|
1886
1979
|
// ════════════════════════════════════════════════════════════════════
|