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