sdocs-dev 1.1.0 → 1.1.2
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/bin/sdocs-dev.js +81 -14
- package/package.json +1 -1
- package/public/css/layout.css +4 -1
- package/public/css/mobile.css +1 -1
- package/public/css/rendered.css +12 -1
- package/public/css/tokens.css +5 -2
- package/public/default.md +125 -96
- package/public/fonts/inter-400.woff2 +0 -0
- package/public/fonts/inter-500.woff2 +0 -0
- package/public/fonts/inter-600.woff2 +0 -0
- package/public/images/examples.png +0 -0
- package/public/index.html +20 -7
- package/public/sdocs-app.js +62 -12
- package/public/sdocs-controls.js +26 -39
- package/public/sdocs-export.js +2 -1
- package/public/sdocs-styles.js +85 -1
- package/public/sdocs-theme.js +7 -1
- package/public/sw.js +106 -0
- package/public/vendor/marked.min.js +6 -0
- package/server.js +65 -3
package/public/sdocs-controls.js
CHANGED
|
@@ -51,7 +51,7 @@ var STANDALONE_COLOR_IDS = new Set(SDocStyles.STANDALONE_COLOR_IDS);
|
|
|
51
51
|
'ctrl-h1-weight','ctrl-h2-weight','ctrl-h3-weight','ctrl-h4-weight',
|
|
52
52
|
'ctrl-bg-color','ctrl-link-color','ctrl-link-decoration',
|
|
53
53
|
'ctrl-code-font','ctrl-code-bg','ctrl-code-color',
|
|
54
|
-
'ctrl-bq-border-color','ctrl-bq-color',
|
|
54
|
+
'ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-color',
|
|
55
55
|
].forEach(function(id) {
|
|
56
56
|
var handler = function() { if (STANDALONE_COLOR_IDS.has(id)) S.overriddenColors.add(id); applyCtrl(id); };
|
|
57
57
|
document.getElementById(id).addEventListener('input', handler);
|
|
@@ -97,7 +97,7 @@ document.getElementById('reset-h4-color').addEventListener('click', function()
|
|
|
97
97
|
document.getElementById('reset-p-color').addEventListener('click', function() { resetColorValue('ctrl-p-color'); S.syncAll('controls'); });
|
|
98
98
|
document.getElementById('reset-list-color').addEventListener('click', function() { resetColorValue('ctrl-list-color'); S.syncAll('controls'); });
|
|
99
99
|
|
|
100
|
-
['ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color'].forEach(function(ctrlId) {
|
|
100
|
+
['ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-color'].forEach(function(ctrlId) {
|
|
101
101
|
var btnId = 'reset-' + ctrlId.replace('ctrl-', '');
|
|
102
102
|
document.getElementById(btnId).addEventListener('click', function() {
|
|
103
103
|
var defaultVal = S.getStandaloneDefault(ctrlId);
|
|
@@ -165,54 +165,41 @@ function applyStylesFromMeta(s) {
|
|
|
165
165
|
return;
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
-
// Legacy single-theme path: top-level colors go to light theme
|
|
168
|
+
// Legacy single-theme path: top-level colors go to light theme only,
|
|
169
|
+
// then loadThemeColors applies the correct theme's colors.
|
|
170
|
+
var lightOverridden = S.themeOverridden.light;
|
|
171
|
+
var lightColors = S.themeColors.light;
|
|
169
172
|
var newOverridden = result.overriddenColors;
|
|
170
173
|
|
|
171
|
-
|
|
172
|
-
|
|
174
|
+
lightOverridden.clear();
|
|
175
|
+
S.themeOverridden.dark.clear();
|
|
173
176
|
|
|
174
177
|
newOverridden.forEach(function(id) {
|
|
175
|
-
|
|
176
|
-
|
|
178
|
+
lightOverridden.add(id);
|
|
179
|
+
lightColors[id] = controls[id];
|
|
177
180
|
});
|
|
178
181
|
|
|
179
|
-
// Also
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
if (elBg) { elBg.value = s.background; applyCtrl('ctrl-bg-color'); }
|
|
184
|
-
}
|
|
185
|
-
if (s.link && s.link.color) {
|
|
186
|
-
S.overriddenColors.add('ctrl-link-color');
|
|
187
|
-
var el = document.getElementById('ctrl-link-color');
|
|
188
|
-
if (el) { el.value = s.link.color; applyCtrl('ctrl-link-color'); }
|
|
189
|
-
}
|
|
182
|
+
// Also store standalone colors from legacy format into light theme
|
|
183
|
+
var legacyStandalone = [];
|
|
184
|
+
if (s.background) legacyStandalone.push(['ctrl-bg-color', s.background]);
|
|
185
|
+
if (s.link && s.link.color) legacyStandalone.push(['ctrl-link-color', s.link.color]);
|
|
190
186
|
if (s.code) {
|
|
191
|
-
if (s.code.background)
|
|
192
|
-
|
|
193
|
-
var el2 = document.getElementById('ctrl-code-bg');
|
|
194
|
-
if (el2) { el2.value = s.code.background; applyCtrl('ctrl-code-bg'); }
|
|
195
|
-
}
|
|
196
|
-
if (s.code.color) {
|
|
197
|
-
S.overriddenColors.add('ctrl-code-color');
|
|
198
|
-
var el3 = document.getElementById('ctrl-code-color');
|
|
199
|
-
if (el3) { el3.value = s.code.color; applyCtrl('ctrl-code-color'); }
|
|
200
|
-
}
|
|
187
|
+
if (s.code.background) legacyStandalone.push(['ctrl-code-bg', s.code.background]);
|
|
188
|
+
if (s.code.color) legacyStandalone.push(['ctrl-code-color', s.code.color]);
|
|
201
189
|
}
|
|
202
190
|
if (s.blockquote) {
|
|
203
|
-
if (s.blockquote.borderColor)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
if (el4) { el4.value = s.blockquote.borderColor; applyCtrl('ctrl-bq-border-color'); }
|
|
207
|
-
}
|
|
208
|
-
if (s.blockquote.color) {
|
|
209
|
-
S.overriddenColors.add('ctrl-bq-color');
|
|
210
|
-
var el5 = document.getElementById('ctrl-bq-color');
|
|
211
|
-
if (el5) { el5.value = s.blockquote.color; applyCtrl('ctrl-bq-color'); }
|
|
212
|
-
}
|
|
191
|
+
if (s.blockquote.borderColor) legacyStandalone.push(['ctrl-bq-border-color', s.blockquote.borderColor]);
|
|
192
|
+
if (s.blockquote.background) legacyStandalone.push(['ctrl-bq-bg', s.blockquote.background]);
|
|
193
|
+
if (s.blockquote.color) legacyStandalone.push(['ctrl-bq-color', s.blockquote.color]);
|
|
213
194
|
}
|
|
195
|
+
legacyStandalone.forEach(function(pair) {
|
|
196
|
+
lightOverridden.add(pair[0]);
|
|
197
|
+
lightColors[pair[0]] = pair[1];
|
|
198
|
+
});
|
|
214
199
|
|
|
200
|
+
// Now apply the active theme's colors (light overrides or dark defaults)
|
|
215
201
|
S._syncing = wasSyncing;
|
|
202
|
+
S.loadThemeColors(S.activeTheme);
|
|
216
203
|
}
|
|
217
204
|
|
|
218
205
|
function collectStyles() {
|
|
@@ -257,7 +244,7 @@ function resetAllStyles() {
|
|
|
257
244
|
'ctrl-p-lh-num','ctrl-p-mb-num',
|
|
258
245
|
'ctrl-link-color','ctrl-link-decoration',
|
|
259
246
|
'ctrl-code-font','ctrl-code-bg','ctrl-code-color',
|
|
260
|
-
'ctrl-bq-border-color','ctrl-bq-bw-num','ctrl-bq-size-num','ctrl-bq-color',
|
|
247
|
+
'ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-bw-num','ctrl-bq-size-num','ctrl-bq-color',
|
|
261
248
|
'ctrl-list-spacing-num','ctrl-list-indent-num',
|
|
262
249
|
].forEach(function(id) { applyCtrl(id); });
|
|
263
250
|
}
|
package/public/sdocs-export.js
CHANGED
|
@@ -47,11 +47,12 @@ function buildExportCSS() {
|
|
|
47
47
|
var preBG = cv('--md-pre-bg') || codeBG;
|
|
48
48
|
|
|
49
49
|
var bqBorder = cv('--md-bq-border') || '3px solid #2563eb';
|
|
50
|
+
var bqBg = cv('--md-bq-bg') || '#f7f5f2';
|
|
50
51
|
var bqColor = cv('--md-bq-color') || '#6b6560';
|
|
51
52
|
var bqPad = cv('--md-bq-padding') || '0.5em 1em';
|
|
52
53
|
var bqMargin = cv('--md-bq-margin') || '1.2em 0';
|
|
53
54
|
|
|
54
|
-
return '\nbody {\n font-family: ' + fontFamily + ';\n font-size: ' + baseSize + ';\n color: ' + color + ';\n line-height: ' + lineHeight + ';\n background-color: ' + bgColor + ';\n max-width: 720px;\n margin: 0 auto;\n padding: 40px 48px 60px;\n -webkit-font-smoothing: antialiased;\n}\nh1 { font-family: ' + hFontFamily + '; font-size: ' + h1Size + '; color: ' + h1Color + '; font-weight: ' + h1Weight + '; letter-spacing: -0.02em; line-height: 1.2; margin: 0 0 ' + hMB + '; }\nh2 { font-family: ' + hFontFamily + '; font-size: ' + h2Size + '; color: ' + h2Color + '; font-weight: ' + h2Weight + '; letter-spacing: -0.015em; line-height: 1.3; margin: 1.4em 0 ' + hMB + '; padding-bottom: 0.3em; border-bottom: 1px solid #ede8e2; }\nh3 { font-family: ' + hFontFamily + '; font-size: ' + h3Size + '; color: ' + h3Color + '; font-weight: ' + h3Weight + '; letter-spacing: -0.01em; line-height: 1.4; margin: 1.2em 0 ' + hMB + '; }\nh4 { font-family: ' + hFontFamily + '; font-size: ' + h4Size + '; color: ' + h4Color + '; font-weight: ' + h4Weight + '; line-height: 1.5; margin: 1em 0 ' + hMB + '; }\np { color: ' + pColor + '; line-height: ' + pLH + '; margin: ' + pMargin + '; }\na { color: ' + linkColor + '; text-decoration: ' + linkDec + '; text-underline-offset: 2px; }\ncode { background: ' + codeBG + '; color: ' + codeColor + '; padding: 0.15em 0.45em; border-radius: 4px; font-family: ' + codeFont + '; font-size: 0.85em; }\npre { background: ' + preBG + '; padding: 1.1em 1.25em; border-radius: 8px; overflow-x: auto; margin: 1.2em 0; border: 1px solid #e7e2db; }\npre code { background: none; padding: 0; color: #3c3733; font-size: 0.88em; }\nblockquote { border-left: ' + bqBorder + '; color: ' + bqColor + '; padding: ' + bqPad + '; margin: ' + bqMargin + '; background:
|
|
55
|
+
return '\nbody {\n font-family: ' + fontFamily + ';\n font-size: ' + baseSize + ';\n color: ' + color + ';\n line-height: ' + lineHeight + ';\n background-color: ' + bgColor + ';\n max-width: 720px;\n margin: 0 auto;\n padding: 40px 48px 60px;\n -webkit-font-smoothing: antialiased;\n}\nh1 { font-family: ' + hFontFamily + '; font-size: ' + h1Size + '; color: ' + h1Color + '; font-weight: ' + h1Weight + '; letter-spacing: -0.02em; line-height: 1.2; margin: 0 0 ' + hMB + '; }\nh2 { font-family: ' + hFontFamily + '; font-size: ' + h2Size + '; color: ' + h2Color + '; font-weight: ' + h2Weight + '; letter-spacing: -0.015em; line-height: 1.3; margin: 1.4em 0 ' + hMB + '; padding-bottom: 0.3em; border-bottom: 1px solid #ede8e2; }\nh3 { font-family: ' + hFontFamily + '; font-size: ' + h3Size + '; color: ' + h3Color + '; font-weight: ' + h3Weight + '; letter-spacing: -0.01em; line-height: 1.4; margin: 1.2em 0 ' + hMB + '; }\nh4 { font-family: ' + hFontFamily + '; font-size: ' + h4Size + '; color: ' + h4Color + '; font-weight: ' + h4Weight + '; line-height: 1.5; margin: 1em 0 ' + hMB + '; }\np { color: ' + pColor + '; line-height: ' + pLH + '; margin: ' + pMargin + '; }\na { color: ' + linkColor + '; text-decoration: ' + linkDec + '; text-underline-offset: 2px; }\ncode { background: ' + codeBG + '; color: ' + codeColor + '; padding: 0.15em 0.45em; border-radius: 4px; font-family: ' + codeFont + '; font-size: 0.85em; }\npre { background: ' + preBG + '; padding: 1.1em 1.25em; border-radius: 8px; overflow-x: auto; margin: 1.2em 0; border: 1px solid #e7e2db; }\npre code { background: none; padding: 0; color: #3c3733; font-size: 0.88em; }\nblockquote { border-left: ' + bqBorder + '; color: ' + bqColor + '; padding: ' + bqPad + '; margin: ' + bqMargin + '; background: ' + bqBg + '; border-radius: 0 6px 6px 0; }\nblockquote p { margin: 0; color: inherit; }\nul, ol { padding-left: 1.6em; margin: 0.5em 0 1.1em; }\nli { margin-bottom: 0.3em; }\nhr { border: none; border-top: 1px solid #ede8e2; margin: 2em 0; }\ntable { border-collapse: collapse; width: 100%; margin: 1.2em 0; font-size: 0.92em; }\nth, td { border: 1px solid #e2ddd6; padding: 7px 12px; text-align: left; }\nth { background: #f4f1ed; font-weight: 600; }\ntr:nth-child(even) td { background: #fafaf8; }\nimg { max-width: 100%; border-radius: 8px; }\n';
|
|
55
56
|
}
|
|
56
57
|
|
|
57
58
|
function buildExportHTML() {
|
package/public/sdocs-styles.js
CHANGED
|
@@ -55,6 +55,7 @@ const CTRL_CSS_MAP = {
|
|
|
55
55
|
'ctrl-code-color': { cssVar: '--md-code-color' },
|
|
56
56
|
'ctrl-bq-border-color': { cssVar: '--md-bq-border', compound: 'bq-border' },
|
|
57
57
|
'ctrl-bq-bw-num': { cssVar: '--md-bq-border', compound: 'bq-border' },
|
|
58
|
+
'ctrl-bq-bg': { cssVar: '--md-bq-bg' },
|
|
58
59
|
'ctrl-bq-size-num': { cssVar: '--md-bq-size', suffix: 'em' },
|
|
59
60
|
'ctrl-bq-color': { cssVar: '--md-bq-color' },
|
|
60
61
|
'ctrl-list-spacing-num': { cssVar: '--md-list-spacing', suffix: 'em' },
|
|
@@ -170,6 +171,7 @@ function collectStyles(values, overriddenColors) {
|
|
|
170
171
|
blockquote: {
|
|
171
172
|
borderColor: gv('ctrl-bq-border-color'),
|
|
172
173
|
borderWidth: gn('ctrl-bq-bw-num'),
|
|
174
|
+
background: gv('ctrl-bq-bg'),
|
|
173
175
|
fontSize: gn('ctrl-bq-size-num'),
|
|
174
176
|
color: gv('ctrl-bq-color'),
|
|
175
177
|
},
|
|
@@ -257,6 +259,7 @@ function stylesToControls(styles) {
|
|
|
257
259
|
const bq = styles.blockquote || {};
|
|
258
260
|
if (bq.borderColor) controls['ctrl-bq-border-color'] = bq.borderColor;
|
|
259
261
|
if (bq.borderWidth) controls['ctrl-bq-bw-num'] = bq.borderWidth;
|
|
262
|
+
if (bq.background) controls['ctrl-bq-bg'] = bq.background;
|
|
260
263
|
if (bq.fontSize) controls['ctrl-bq-size-num'] = bq.fontSize;
|
|
261
264
|
if (bq.color) controls['ctrl-bq-color'] = bq.color;
|
|
262
265
|
|
|
@@ -276,7 +279,7 @@ function stylesToControls(styles) {
|
|
|
276
279
|
// ═══════════════════════════════════════════════════════
|
|
277
280
|
|
|
278
281
|
var STANDALONE_COLOR_IDS = [
|
|
279
|
-
'ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-color',
|
|
282
|
+
'ctrl-bg-color','ctrl-link-color','ctrl-code-bg','ctrl-code-color','ctrl-bq-border-color','ctrl-bq-bg','ctrl-bq-color',
|
|
280
283
|
];
|
|
281
284
|
|
|
282
285
|
var CASCADE_COLOR_IDS = Object.keys(COLOR_VAR_MAP);
|
|
@@ -341,6 +344,7 @@ function parseThemeColorBlock(block) {
|
|
|
341
344
|
}
|
|
342
345
|
if (block.blockquote) {
|
|
343
346
|
if (block.blockquote.borderColor) { colors['ctrl-bq-border-color'] = block.blockquote.borderColor; overridden.add('ctrl-bq-border-color'); }
|
|
347
|
+
if (block.blockquote.background) { colors['ctrl-bq-bg'] = block.blockquote.background; overridden.add('ctrl-bq-bg'); }
|
|
344
348
|
if (block.blockquote.color) { colors['ctrl-bq-color'] = block.blockquote.color; overridden.add('ctrl-bq-color'); }
|
|
345
349
|
}
|
|
346
350
|
|
|
@@ -397,6 +401,10 @@ function collectThemeColors(colorValues, overriddenSet) {
|
|
|
397
401
|
if (!block.blockquote) block.blockquote = {};
|
|
398
402
|
block.blockquote.borderColor = colorValues['ctrl-bq-border-color'];
|
|
399
403
|
}
|
|
404
|
+
if (overriddenSet.has('ctrl-bq-bg')) {
|
|
405
|
+
if (!block.blockquote) block.blockquote = {};
|
|
406
|
+
block.blockquote.background = colorValues['ctrl-bq-bg'];
|
|
407
|
+
}
|
|
400
408
|
if (overriddenSet.has('ctrl-bq-color')) {
|
|
401
409
|
if (!block.blockquote) block.blockquote = {};
|
|
402
410
|
block.blockquote.color = colorValues['ctrl-bq-color'];
|
|
@@ -438,6 +446,7 @@ function collectStylesDual(values, lightOverridden, darkOverridden, lightColors,
|
|
|
438
446
|
borderWidth: gn('ctrl-bq-bw-num'),
|
|
439
447
|
fontSize: gn('ctrl-bq-size-num'),
|
|
440
448
|
},
|
|
449
|
+
|
|
441
450
|
};
|
|
442
451
|
|
|
443
452
|
styles.list = {
|
|
@@ -525,6 +534,79 @@ stylesToControls = function(styles) {
|
|
|
525
534
|
};
|
|
526
535
|
};
|
|
527
536
|
|
|
537
|
+
// ═══════════════════════════════════════════════════════
|
|
538
|
+
// STRIP STYLE DEFAULTS (for shorter URLs)
|
|
539
|
+
// ═══════════════════════════════════════════════════════
|
|
540
|
+
|
|
541
|
+
// Default values matching HTML control defaults in index.html.
|
|
542
|
+
// When a style value equals its default, it can be omitted from serialization
|
|
543
|
+
// because stylesToControls / the browser already falls back to these defaults.
|
|
544
|
+
var STYLE_DEFAULTS = {
|
|
545
|
+
fontFamily: 'Inter',
|
|
546
|
+
baseFontSize: 16,
|
|
547
|
+
lineHeight: 1.75,
|
|
548
|
+
headers: {
|
|
549
|
+
fontFamily: 'inherit',
|
|
550
|
+
scale: 1.0,
|
|
551
|
+
marginBottom: 0.4,
|
|
552
|
+
},
|
|
553
|
+
h1: { fontSize: 2.1, fontWeight: 700 },
|
|
554
|
+
h2: { fontSize: 1.55, fontWeight: 600 },
|
|
555
|
+
h3: { fontSize: 1.2, fontWeight: 600 },
|
|
556
|
+
h4: { fontSize: 1.0, fontWeight: 600 },
|
|
557
|
+
p: { lineHeight: 1.75, marginBottom: 1.1 },
|
|
558
|
+
link: { decoration: 'underline' },
|
|
559
|
+
code: { font: 'JetBrains Mono' },
|
|
560
|
+
blockquote: { borderWidth: 3, fontSize: 1.0 },
|
|
561
|
+
list: { spacing: 0.3, indent: 1.6 },
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
function numEq(a, b) {
|
|
565
|
+
var na = typeof a === 'number' ? a : parseFloat(a);
|
|
566
|
+
var nb = typeof b === 'number' ? b : parseFloat(b);
|
|
567
|
+
if (isNaN(na) || isNaN(nb)) return false;
|
|
568
|
+
return Math.abs(na - nb) < 0.001;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
/**
|
|
572
|
+
* stripStyleDefaults(styles)
|
|
573
|
+
* Returns a new styles object with default-valued properties removed.
|
|
574
|
+
* light/dark color blocks are preserved as-is (they have no static defaults).
|
|
575
|
+
* Empty sub-objects are removed entirely.
|
|
576
|
+
*/
|
|
577
|
+
function stripStyleDefaults(styles) {
|
|
578
|
+
if (!styles || typeof styles !== 'object') return styles;
|
|
579
|
+
var result = {};
|
|
580
|
+
for (var key in styles) {
|
|
581
|
+
if (!styles.hasOwnProperty(key)) continue;
|
|
582
|
+
var val = styles[key];
|
|
583
|
+
var def = STYLE_DEFAULTS[key];
|
|
584
|
+
|
|
585
|
+
// light/dark theme color blocks — always keep
|
|
586
|
+
if (key === 'light' || key === 'dark') {
|
|
587
|
+
result[key] = val;
|
|
588
|
+
continue;
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
if (typeof val === 'object' && val !== null) {
|
|
592
|
+
var sub = {};
|
|
593
|
+
var defObj = (typeof def === 'object' && def !== null) ? def : {};
|
|
594
|
+
for (var sk in val) {
|
|
595
|
+
if (!val.hasOwnProperty(sk)) continue;
|
|
596
|
+
var sv = val[sk];
|
|
597
|
+
var sd = defObj[sk];
|
|
598
|
+
if (sd !== undefined && (sv === sd || String(sv) === String(sd) || numEq(sv, sd))) continue;
|
|
599
|
+
sub[sk] = sv;
|
|
600
|
+
}
|
|
601
|
+
if (Object.keys(sub).length > 0) result[key] = sub;
|
|
602
|
+
} else {
|
|
603
|
+
if (def !== undefined && (val === def || String(val) === String(def) || numEq(val, def))) continue;
|
|
604
|
+
result[key] = val;
|
|
605
|
+
}
|
|
606
|
+
}
|
|
607
|
+
return result;
|
|
608
|
+
}
|
|
609
|
+
|
|
528
610
|
// ═══════════════════════════════════════════════════════
|
|
529
611
|
// EXPORTS
|
|
530
612
|
// ═══════════════════════════════════════════════════════
|
|
@@ -544,6 +626,8 @@ exports.collectStylesDual = collectStylesDual;
|
|
|
544
626
|
exports.collectThemeColors = collectThemeColors;
|
|
545
627
|
exports.parseThemeColorBlock = parseThemeColorBlock;
|
|
546
628
|
exports.stylesToControls = stylesToControls;
|
|
629
|
+
exports.STYLE_DEFAULTS = STYLE_DEFAULTS;
|
|
630
|
+
exports.stripStyleDefaults = stripStyleDefaults;
|
|
547
631
|
|
|
548
632
|
// UMD tail: in Node (tests) this writes to module.exports; in the browser
|
|
549
633
|
// it creates window.SDocStyles. We use this pattern instead of ES modules
|
package/public/sdocs-theme.js
CHANGED
|
@@ -55,16 +55,18 @@ const LIGHT_DEFAULTS = {
|
|
|
55
55
|
codeColor: '#6b21a8',
|
|
56
56
|
linkColor: '#2563eb',
|
|
57
57
|
bqBorderColor: '#2563eb',
|
|
58
|
+
bqBg: '#f7f5f2',
|
|
58
59
|
bqColor: '#6b6560',
|
|
59
60
|
};
|
|
60
61
|
|
|
61
62
|
const DARK_DEFAULTS = {
|
|
62
|
-
bgColor: '#
|
|
63
|
+
bgColor: '#2c2a26',
|
|
63
64
|
colorDefault: '#e7e5e2',
|
|
64
65
|
codeBg: '#1a1816',
|
|
65
66
|
codeColor: '#b8a99a',
|
|
66
67
|
linkColor: '#60a5fa',
|
|
67
68
|
bqBorderColor: '#60a5fa',
|
|
69
|
+
bqBg: '#252320',
|
|
68
70
|
bqColor: '#a8a29e',
|
|
69
71
|
};
|
|
70
72
|
|
|
@@ -142,6 +144,7 @@ function loadThemeColors(theme) {
|
|
|
142
144
|
'ctrl-code-bg': defaults.codeBg,
|
|
143
145
|
'ctrl-code-color': defaults.codeColor,
|
|
144
146
|
'ctrl-bq-border-color': defaults.bqBorderColor,
|
|
147
|
+
'ctrl-bq-bg': defaults.bqBg,
|
|
145
148
|
'ctrl-bq-color': defaults.bqColor,
|
|
146
149
|
};
|
|
147
150
|
for (var ctrlId in standaloneMap) {
|
|
@@ -192,6 +195,7 @@ function updateDefaultColors() {
|
|
|
192
195
|
'ctrl-code-bg': defaults.codeBg,
|
|
193
196
|
'ctrl-code-color': defaults.codeColor,
|
|
194
197
|
'ctrl-bq-border-color': defaults.bqBorderColor,
|
|
198
|
+
'ctrl-bq-bg': defaults.bqBg,
|
|
195
199
|
'ctrl-bq-color': defaults.bqColor,
|
|
196
200
|
};
|
|
197
201
|
for (const [ctrlId, val] of Object.entries(standaloneMap)) {
|
|
@@ -216,6 +220,7 @@ function getStandaloneDefault(ctrlId) {
|
|
|
216
220
|
'ctrl-code-bg': d.codeBg,
|
|
217
221
|
'ctrl-code-color': d.codeColor,
|
|
218
222
|
'ctrl-bq-border-color': d.bqBorderColor,
|
|
223
|
+
'ctrl-bq-bg': d.bqBg,
|
|
219
224
|
'ctrl-bq-color': d.bqColor,
|
|
220
225
|
};
|
|
221
226
|
return map[ctrlId];
|
|
@@ -247,6 +252,7 @@ S.getStandaloneDefault = getStandaloneDefault;
|
|
|
247
252
|
S.updateDefaultColors = updateDefaultColors;
|
|
248
253
|
S.toggleTheme = toggleTheme;
|
|
249
254
|
S.switchThemeAndUpdate = switchThemeAndUpdate;
|
|
255
|
+
S.getPreferredTheme = getPreferredTheme;
|
|
250
256
|
S.saveCurrentThemeColors = saveCurrentThemeColors;
|
|
251
257
|
S.loadThemeColors = loadThemeColors;
|
|
252
258
|
S.updateThemeTabs = updateThemeTabs;
|
package/public/sw.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// Service worker — stale-while-revalidate + version-gated cache bust
|
|
2
|
+
var CACHE_NAME = 'sdocs-cache';
|
|
3
|
+
|
|
4
|
+
var APP_SHELL = [
|
|
5
|
+
'/',
|
|
6
|
+
'/public/css/tokens.css',
|
|
7
|
+
'/public/css/layout.css',
|
|
8
|
+
'/public/css/rendered.css',
|
|
9
|
+
'/public/css/panel.css',
|
|
10
|
+
'/public/css/write.css',
|
|
11
|
+
'/public/css/mobile.css',
|
|
12
|
+
'/public/sdocs-yaml.js',
|
|
13
|
+
'/public/sdocs-styles.js',
|
|
14
|
+
'/public/sdocs-state.js',
|
|
15
|
+
'/public/sdocs-theme.js',
|
|
16
|
+
'/public/sdocs-controls.js',
|
|
17
|
+
'/public/sdocs-export.js',
|
|
18
|
+
'/public/sdocs-write.js',
|
|
19
|
+
'/public/sdocs-app.js',
|
|
20
|
+
'/public/vendor/marked.min.js',
|
|
21
|
+
'/public/fonts/inter-400.woff2',
|
|
22
|
+
'/public/fonts/inter-500.woff2',
|
|
23
|
+
'/public/fonts/inter-600.woff2',
|
|
24
|
+
'/public/default.md',
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
// Pre-cache app shell on install
|
|
28
|
+
self.addEventListener('install', function (e) {
|
|
29
|
+
e.waitUntil(
|
|
30
|
+
caches.open(CACHE_NAME).then(function (cache) {
|
|
31
|
+
return cache.addAll(APP_SHELL);
|
|
32
|
+
}).then(function () {
|
|
33
|
+
return self.skipWaiting();
|
|
34
|
+
})
|
|
35
|
+
);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
// Claim clients on activate
|
|
39
|
+
self.addEventListener('activate', function (e) {
|
|
40
|
+
e.waitUntil(self.clients.claim());
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Stale-while-revalidate for same-origin, cache-first for fonts
|
|
44
|
+
self.addEventListener('fetch', function (e) {
|
|
45
|
+
var url = new URL(e.request.url);
|
|
46
|
+
|
|
47
|
+
if (e.request.method !== 'GET') return;
|
|
48
|
+
|
|
49
|
+
// Version-check always hits network
|
|
50
|
+
if (url.pathname === '/version-check') return;
|
|
51
|
+
|
|
52
|
+
// Google Fonts: cache-first (they're immutable)
|
|
53
|
+
if (url.hostname === 'fonts.googleapis.com' || url.hostname === 'fonts.gstatic.com') {
|
|
54
|
+
e.respondWith(
|
|
55
|
+
caches.match(e.request).then(function (cached) {
|
|
56
|
+
if (cached) return cached;
|
|
57
|
+
return fetch(e.request).then(function (response) {
|
|
58
|
+
var clone = response.clone();
|
|
59
|
+
caches.open(CACHE_NAME).then(function (cache) { cache.put(e.request, clone); });
|
|
60
|
+
return response;
|
|
61
|
+
});
|
|
62
|
+
})
|
|
63
|
+
);
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Same-origin: stale-while-revalidate
|
|
68
|
+
// Return cached immediately, fetch in background to update cache
|
|
69
|
+
if (url.origin === self.location.origin) {
|
|
70
|
+
e.respondWith(
|
|
71
|
+
caches.open(CACHE_NAME).then(function (cache) {
|
|
72
|
+
return cache.match(e.request).then(function (cached) {
|
|
73
|
+
var networkFetch = fetch(e.request).then(function (response) {
|
|
74
|
+
if (response.ok) {
|
|
75
|
+
cache.put(e.request, response.clone());
|
|
76
|
+
}
|
|
77
|
+
return response;
|
|
78
|
+
}).catch(function () {
|
|
79
|
+
return cached; // offline fallback
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
return cached || networkFetch;
|
|
83
|
+
});
|
|
84
|
+
})
|
|
85
|
+
);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// Version check: if server version differs, purge and re-cache.
|
|
91
|
+
// No reload — stale-while-revalidate ensures next navigation gets fresh content.
|
|
92
|
+
self.addEventListener('message', function (e) {
|
|
93
|
+
if (e.data && e.data.type === 'check-update' && e.data.version) {
|
|
94
|
+
fetch('/version-check').then(function (res) {
|
|
95
|
+
return res.json();
|
|
96
|
+
}).then(function (data) {
|
|
97
|
+
if (data.version !== e.data.version) {
|
|
98
|
+
caches.delete(CACHE_NAME).then(function () {
|
|
99
|
+
return caches.open(CACHE_NAME).then(function (cache) {
|
|
100
|
+
return cache.addAll(APP_SHELL);
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}).catch(function () { /* offline — ignore */ });
|
|
105
|
+
}
|
|
106
|
+
});
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* marked v11.2.0 - a markdown parser
|
|
3
|
+
* Copyright (c) 2011-2024, Christopher Jeffrey. (MIT Licensed)
|
|
4
|
+
* https://github.com/markedjs/marked
|
|
5
|
+
*/
|
|
6
|
+
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).marked={})}(this,(function(e){"use strict";function t(){return{async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null}}function n(t){e.defaults=t}e.defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};const s=/[&<>"']/,r=new RegExp(s.source,"g"),i=/[<>"']|&(?!(#\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\w+);)/,l=new RegExp(i.source,"g"),o={"&":"&","<":"<",">":">",'"':""","'":"'"},a=e=>o[e];function c(e,t){if(t){if(s.test(e))return e.replace(r,a)}else if(i.test(e))return e.replace(l,a);return e}const h=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function p(e){return e.replace(h,((e,t)=>"colon"===(t=t.toLowerCase())?":":"#"===t.charAt(0)?"x"===t.charAt(1)?String.fromCharCode(parseInt(t.substring(2),16)):String.fromCharCode(+t.substring(1)):""))}const u=/(^|[^\[])\^/g;function k(e,t){let n="string"==typeof e?e:e.source;t=t||"";const s={replace:(e,t)=>{let r="string"==typeof t?t:t.source;return r=r.replace(u,"$1"),n=n.replace(e,r),s},getRegex:()=>new RegExp(n,t)};return s}function g(e){try{e=encodeURI(e).replace(/%25/g,"%")}catch(e){return null}return e}const f={exec:()=>null};function d(e,t){const n=e.replace(/\|/g,((e,t,n)=>{let s=!1,r=t;for(;--r>=0&&"\\"===n[r];)s=!s;return s?"|":" |"})).split(/ \|/);let s=0;if(n[0].trim()||n.shift(),n.length>0&&!n[n.length-1].trim()&&n.pop(),t)if(n.length>t)n.splice(t);else for(;n.length<t;)n.push("");for(;s<n.length;s++)n[s]=n[s].trim().replace(/\\\|/g,"|");return n}function x(e,t,n){const s=e.length;if(0===s)return"";let r=0;for(;r<s;){const i=e.charAt(s-r-1);if(i!==t||n){if(i===t||!n)break;r++}else r++}return e.slice(0,s-r)}function b(e,t,n,s){const r=t.href,i=t.title?c(t.title):null,l=e[1].replace(/\\([\[\]])/g,"$1");if("!"!==e[0].charAt(0)){s.state.inLink=!0;const e={type:"link",raw:n,href:r,title:i,text:l,tokens:s.inlineTokens(l)};return s.state.inLink=!1,e}return{type:"image",raw:n,href:r,title:i,text:c(l)}}class w{options;rules;lexer;constructor(t){this.options=t||e.defaults}space(e){const t=this.rules.block.newline.exec(e);if(t&&t[0].length>0)return{type:"space",raw:t[0]}}code(e){const t=this.rules.block.code.exec(e);if(t){const e=t[0].replace(/^ {1,4}/gm,"");return{type:"code",raw:t[0],codeBlockStyle:"indented",text:this.options.pedantic?e:x(e,"\n")}}}fences(e){const t=this.rules.block.fences.exec(e);if(t){const e=t[0],n=function(e,t){const n=e.match(/^(\s+)(?:```)/);if(null===n)return t;const s=n[1];return t.split("\n").map((e=>{const t=e.match(/^\s+/);if(null===t)return e;const[n]=t;return n.length>=s.length?e.slice(s.length):e})).join("\n")}(e,t[3]||"");return{type:"code",raw:e,lang:t[2]?t[2].trim().replace(this.rules.inline.anyPunctuation,"$1"):t[2],text:n}}}heading(e){const t=this.rules.block.heading.exec(e);if(t){let e=t[2].trim();if(/#$/.test(e)){const t=x(e,"#");this.options.pedantic?e=t.trim():t&&!/ $/.test(t)||(e=t.trim())}return{type:"heading",raw:t[0],depth:t[1].length,text:e,tokens:this.lexer.inline(e)}}}hr(e){const t=this.rules.block.hr.exec(e);if(t)return{type:"hr",raw:t[0]}}blockquote(e){const t=this.rules.block.blockquote.exec(e);if(t){const e=x(t[0].replace(/^ *>[ \t]?/gm,""),"\n"),n=this.lexer.state.top;this.lexer.state.top=!0;const s=this.lexer.blockTokens(e);return this.lexer.state.top=n,{type:"blockquote",raw:t[0],tokens:s,text:e}}}list(e){let t=this.rules.block.list.exec(e);if(t){let n=t[1].trim();const s=n.length>1,r={type:"list",raw:"",ordered:s,start:s?+n.slice(0,-1):"",loose:!1,items:[]};n=s?`\\d{1,9}\\${n.slice(-1)}`:`\\${n}`,this.options.pedantic&&(n=s?n:"[*+-]");const i=new RegExp(`^( {0,3}${n})((?:[\t ][^\\n]*)?(?:\\n|$))`);let l="",o="",a=!1;for(;e;){let n=!1;if(!(t=i.exec(e)))break;if(this.rules.block.hr.test(e))break;l=t[0],e=e.substring(l.length);let s=t[2].split("\n",1)[0].replace(/^\t+/,(e=>" ".repeat(3*e.length))),c=e.split("\n",1)[0],h=0;this.options.pedantic?(h=2,o=s.trimStart()):(h=t[2].search(/[^ ]/),h=h>4?1:h,o=s.slice(h),h+=t[1].length);let p=!1;if(!s&&/^ *$/.test(c)&&(l+=c+"\n",e=e.substring(c.length+1),n=!0),!n){const t=new RegExp(`^ {0,${Math.min(3,h-1)}}(?:[*+-]|\\d{1,9}[.)])((?:[ \t][^\\n]*)?(?:\\n|$))`),n=new RegExp(`^ {0,${Math.min(3,h-1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$)`),r=new RegExp(`^ {0,${Math.min(3,h-1)}}(?:\`\`\`|~~~)`),i=new RegExp(`^ {0,${Math.min(3,h-1)}}#`);for(;e;){const a=e.split("\n",1)[0];if(c=a,this.options.pedantic&&(c=c.replace(/^ {1,4}(?=( {4})*[^ ])/g," ")),r.test(c))break;if(i.test(c))break;if(t.test(c))break;if(n.test(e))break;if(c.search(/[^ ]/)>=h||!c.trim())o+="\n"+c.slice(h);else{if(p)break;if(s.search(/[^ ]/)>=4)break;if(r.test(s))break;if(i.test(s))break;if(n.test(s))break;o+="\n"+c}p||c.trim()||(p=!0),l+=a+"\n",e=e.substring(a.length+1),s=c.slice(h)}}r.loose||(a?r.loose=!0:/\n *\n *$/.test(l)&&(a=!0));let u,k=null;this.options.gfm&&(k=/^\[[ xX]\] /.exec(o),k&&(u="[ ] "!==k[0],o=o.replace(/^\[[ xX]\] +/,""))),r.items.push({type:"list_item",raw:l,task:!!k,checked:u,loose:!1,text:o,tokens:[]}),r.raw+=l}r.items[r.items.length-1].raw=l.trimEnd(),r.items[r.items.length-1].text=o.trimEnd(),r.raw=r.raw.trimEnd();for(let e=0;e<r.items.length;e++)if(this.lexer.state.top=!1,r.items[e].tokens=this.lexer.blockTokens(r.items[e].text,[]),!r.loose){const t=r.items[e].tokens.filter((e=>"space"===e.type)),n=t.length>0&&t.some((e=>/\n.*\n/.test(e.raw)));r.loose=n}if(r.loose)for(let e=0;e<r.items.length;e++)r.items[e].loose=!0;return r}}html(e){const t=this.rules.block.html.exec(e);if(t){return{type:"html",block:!0,raw:t[0],pre:"pre"===t[1]||"script"===t[1]||"style"===t[1],text:t[0]}}}def(e){const t=this.rules.block.def.exec(e);if(t){const e=t[1].toLowerCase().replace(/\s+/g," "),n=t[2]?t[2].replace(/^<(.*)>$/,"$1").replace(this.rules.inline.anyPunctuation,"$1"):"",s=t[3]?t[3].substring(1,t[3].length-1).replace(this.rules.inline.anyPunctuation,"$1"):t[3];return{type:"def",tag:e,raw:t[0],href:n,title:s}}}table(e){const t=this.rules.block.table.exec(e);if(!t)return;if(!/[:|]/.test(t[2]))return;const n=d(t[1]),s=t[2].replace(/^\||\| *$/g,"").split("|"),r=t[3]&&t[3].trim()?t[3].replace(/\n[ \t]*$/,"").split("\n"):[],i={type:"table",raw:t[0],header:[],align:[],rows:[]};if(n.length===s.length){for(const e of s)/^ *-+: *$/.test(e)?i.align.push("right"):/^ *:-+: *$/.test(e)?i.align.push("center"):/^ *:-+ *$/.test(e)?i.align.push("left"):i.align.push(null);for(const e of n)i.header.push({text:e,tokens:this.lexer.inline(e)});for(const e of r)i.rows.push(d(e,i.header.length).map((e=>({text:e,tokens:this.lexer.inline(e)}))));return i}}lheading(e){const t=this.rules.block.lheading.exec(e);if(t)return{type:"heading",raw:t[0],depth:"="===t[2].charAt(0)?1:2,text:t[1],tokens:this.lexer.inline(t[1])}}paragraph(e){const t=this.rules.block.paragraph.exec(e);if(t){const e="\n"===t[1].charAt(t[1].length-1)?t[1].slice(0,-1):t[1];return{type:"paragraph",raw:t[0],text:e,tokens:this.lexer.inline(e)}}}text(e){const t=this.rules.block.text.exec(e);if(t)return{type:"text",raw:t[0],text:t[0],tokens:this.lexer.inline(t[0])}}escape(e){const t=this.rules.inline.escape.exec(e);if(t)return{type:"escape",raw:t[0],text:c(t[1])}}tag(e){const t=this.rules.inline.tag.exec(e);if(t)return!this.lexer.state.inLink&&/^<a /i.test(t[0])?this.lexer.state.inLink=!0:this.lexer.state.inLink&&/^<\/a>/i.test(t[0])&&(this.lexer.state.inLink=!1),!this.lexer.state.inRawBlock&&/^<(pre|code|kbd|script)(\s|>)/i.test(t[0])?this.lexer.state.inRawBlock=!0:this.lexer.state.inRawBlock&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(t[0])&&(this.lexer.state.inRawBlock=!1),{type:"html",raw:t[0],inLink:this.lexer.state.inLink,inRawBlock:this.lexer.state.inRawBlock,block:!1,text:t[0]}}link(e){const t=this.rules.inline.link.exec(e);if(t){const e=t[2].trim();if(!this.options.pedantic&&/^</.test(e)){if(!/>$/.test(e))return;const t=x(e.slice(0,-1),"\\");if((e.length-t.length)%2==0)return}else{const e=function(e,t){if(-1===e.indexOf(t[1]))return-1;let n=0;for(let s=0;s<e.length;s++)if("\\"===e[s])s++;else if(e[s]===t[0])n++;else if(e[s]===t[1]&&(n--,n<0))return s;return-1}(t[2],"()");if(e>-1){const n=(0===t[0].indexOf("!")?5:4)+t[1].length+e;t[2]=t[2].substring(0,e),t[0]=t[0].substring(0,n).trim(),t[3]=""}}let n=t[2],s="";if(this.options.pedantic){const e=/^([^'"]*[^\s])\s+(['"])(.*)\2/.exec(n);e&&(n=e[1],s=e[3])}else s=t[3]?t[3].slice(1,-1):"";return n=n.trim(),/^</.test(n)&&(n=this.options.pedantic&&!/>$/.test(e)?n.slice(1):n.slice(1,-1)),b(t,{href:n?n.replace(this.rules.inline.anyPunctuation,"$1"):n,title:s?s.replace(this.rules.inline.anyPunctuation,"$1"):s},t[0],this.lexer)}}reflink(e,t){let n;if((n=this.rules.inline.reflink.exec(e))||(n=this.rules.inline.nolink.exec(e))){const e=t[(n[2]||n[1]).replace(/\s+/g," ").toLowerCase()];if(!e){const e=n[0].charAt(0);return{type:"text",raw:e,text:e}}return b(n,e,n[0],this.lexer)}}emStrong(e,t,n=""){let s=this.rules.inline.emStrongLDelim.exec(e);if(!s)return;if(s[3]&&n.match(/[\p{L}\p{N}]/u))return;if(!(s[1]||s[2]||"")||!n||this.rules.inline.punctuation.exec(n)){const n=[...s[0]].length-1;let r,i,l=n,o=0;const a="*"===s[0][0]?this.rules.inline.emStrongRDelimAst:this.rules.inline.emStrongRDelimUnd;for(a.lastIndex=0,t=t.slice(-1*e.length+n);null!=(s=a.exec(t));){if(r=s[1]||s[2]||s[3]||s[4]||s[5]||s[6],!r)continue;if(i=[...r].length,s[3]||s[4]){l+=i;continue}if((s[5]||s[6])&&n%3&&!((n+i)%3)){o+=i;continue}if(l-=i,l>0)continue;i=Math.min(i,i+l+o);const t=[...s[0]][0].length,a=e.slice(0,n+s.index+t+i);if(Math.min(n,i)%2){const e=a.slice(1,-1);return{type:"em",raw:a,text:e,tokens:this.lexer.inlineTokens(e)}}const c=a.slice(2,-2);return{type:"strong",raw:a,text:c,tokens:this.lexer.inlineTokens(c)}}}}codespan(e){const t=this.rules.inline.code.exec(e);if(t){let e=t[2].replace(/\n/g," ");const n=/[^ ]/.test(e),s=/^ /.test(e)&&/ $/.test(e);return n&&s&&(e=e.substring(1,e.length-1)),e=c(e,!0),{type:"codespan",raw:t[0],text:e}}}br(e){const t=this.rules.inline.br.exec(e);if(t)return{type:"br",raw:t[0]}}del(e){const t=this.rules.inline.del.exec(e);if(t)return{type:"del",raw:t[0],text:t[2],tokens:this.lexer.inlineTokens(t[2])}}autolink(e){const t=this.rules.inline.autolink.exec(e);if(t){let e,n;return"@"===t[2]?(e=c(t[1]),n="mailto:"+e):(e=c(t[1]),n=e),{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}url(e){let t;if(t=this.rules.inline.url.exec(e)){let e,n;if("@"===t[2])e=c(t[0]),n="mailto:"+e;else{let s;do{s=t[0],t[0]=this.rules.inline._backpedal.exec(t[0])?.[0]??""}while(s!==t[0]);e=c(t[0]),n="www."===t[1]?"http://"+t[0]:t[0]}return{type:"link",raw:t[0],text:e,href:n,tokens:[{type:"text",raw:e,text:e}]}}}inlineText(e){const t=this.rules.inline.text.exec(e);if(t){let e;return e=this.lexer.state.inRawBlock?t[0]:c(t[0]),{type:"text",raw:t[0],text:e}}}}const m=/^ {0,3}((?:-[\t ]*){3,}|(?:_[ \t]*){3,}|(?:\*[ \t]*){3,})(?:\n+|$)/,y=/(?:[*+-]|\d{1,9}[.)])/,$=k(/^(?!bull )((?:.|\n(?!\s*?\n|bull ))+?)\n {0,3}(=+|-+) *(?:\n+|$)/).replace(/bull/g,y).getRegex(),z=/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\n)[^\n]+)*)/,T=/(?!\s*\])(?:\\.|[^\[\]\\])+/,R=k(/^ {0,3}\[(label)\]: *(?:\n *)?([^<\s][^\s]*|<.*?>)(?:(?: +(?:\n *)?| *\n *)(title))? *(?:\n+|$)/).replace("label",T).replace("title",/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/).getRegex(),_=k(/^( {0,3}bull)([ \t][^\n]+?)?(?:\n|$)/).replace(/bull/g,y).getRegex(),A="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",S=/<!--(?!-?>)[\s\S]*?(?:-->|$)/,I=k("^ {0,3}(?:<(script|pre|style|textarea)[\\s>][\\s\\S]*?(?:</\\1>[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|<![A-Z][\\s\\S]*?(?:>\\n*|$)|<!\\[CDATA\\[[\\s\\S]*?(?:\\]\\]>\\n*|$)|</?(tag)(?: +|\\n|/?>)[\\s\\S]*?(?:(?:\\n *)+\\n|$)|<(?!script|pre|style|textarea)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$)|</(?!script|pre|style|textarea)[a-z][\\w-]*\\s*>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:(?:\\n *)+\\n|$))","i").replace("comment",S).replace("tag",A).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),E=k(z).replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("|table","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex(),Z={blockquote:k(/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/).replace("paragraph",E).getRegex(),code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,def:R,fences:/^ {0,3}(`{3,}(?=[^`\n]*(?:\n|$))|~{3,})([^\n]*)(?:\n|$)(?:|([\s\S]*?)(?:\n|$))(?: {0,3}\1[~`]* *(?=\n|$)|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,hr:m,html:I,lheading:$,list:_,newline:/^(?: *(?:\n|$))+/,paragraph:E,table:f,text:/^[^\n]+/},q=k("^ *([^\\n ].*)\\n {0,3}((?:\\| *)?:?-+:? *(?:\\| *:?-+:? *)*(?:\\| *)?)(?:\\n((?:(?! *\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)").replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex(),L={...Z,table:q,paragraph:k(z).replace("hr",m).replace("heading"," {0,3}#{1,6}(?:\\s|$)").replace("|lheading","").replace("table",q).replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html","</?(?:tag)(?: +|\\n|/?>)|<(?:script|pre|style|textarea|!--)").replace("tag",A).getRegex()},P={...Z,html:k("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+?</\\1> *(?:\\n{2,}|\\s*$)|<tag(?:\"[^\"]*\"|'[^']*'|\\s[^'\"/>\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",S).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *<?([^\s>]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:f,lheading:/^(.+?)\n {0,3}(=+|-+) *(?:\n+|$)/,paragraph:k(z).replace("hr",m).replace("heading"," *#{1,6} *[^\n]").replace("lheading",$).replace("|table","").replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").replace("|tag","").getRegex()},Q=/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,v=/^( {2,}|\\)\n(?!\s*$)/,B="\\p{P}$+<=>`^|~",M=k(/^((?![*_])[\spunctuation])/,"u").replace(/punctuation/g,B).getRegex(),O=k(/^(?:\*+(?:((?!\*)[punct])|[^\s*]))|^_+(?:((?!_)[punct])|([^\s_]))/,"u").replace(/punct/g,B).getRegex(),C=k("^[^_*]*?__[^_*]*?\\*[^_*]*?(?=__)|[^*]+(?=[^*])|(?!\\*)[punct](\\*+)(?=[\\s]|$)|[^punct\\s](\\*+)(?!\\*)(?=[punct\\s]|$)|(?!\\*)[punct\\s](\\*+)(?=[^punct\\s])|[\\s](\\*+)(?!\\*)(?=[punct])|(?!\\*)[punct](\\*+)(?!\\*)(?=[punct])|[^punct\\s](\\*+)(?=[^punct\\s])","gu").replace(/punct/g,B).getRegex(),D=k("^[^_*]*?\\*\\*[^_*]*?_[^_*]*?(?=\\*\\*)|[^_]+(?=[^_])|(?!_)[punct](_+)(?=[\\s]|$)|[^punct\\s](_+)(?!_)(?=[punct\\s]|$)|(?!_)[punct\\s](_+)(?=[^punct\\s])|[\\s](_+)(?!_)(?=[punct])|(?!_)[punct](_+)(?!_)(?=[punct])","gu").replace(/punct/g,B).getRegex(),j=k(/\\([punct])/,"gu").replace(/punct/g,B).getRegex(),H=k(/^<(scheme:[^\s\x00-\x1f<>]*|email)>/).replace("scheme",/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/).replace("email",/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/).getRegex(),U=k(S).replace("(?:--\x3e|$)","--\x3e").getRegex(),X=k("^comment|^</[a-zA-Z][\\w:-]*\\s*>|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^<![a-zA-Z]+\\s[\\s\\S]*?>|^<!\\[CDATA\\[[\\s\\S]*?\\]\\]>").replace("comment",U).replace("attribute",/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/).getRegex(),F=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,N=k(/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/).replace("label",F).replace("href",/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/).replace("title",/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/).getRegex(),G=k(/^!?\[(label)\]\[(ref)\]/).replace("label",F).replace("ref",T).getRegex(),J=k(/^!?\[(ref)\](?:\[\])?/).replace("ref",T).getRegex(),K={_backpedal:f,anyPunctuation:j,autolink:H,blockSkip:/\[[^[\]]*?\]\([^\(\)]*?\)|`[^`]*?`|<[^<>]*?>/g,br:v,code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,del:f,emStrongLDelim:O,emStrongRDelimAst:C,emStrongRDelimUnd:D,escape:Q,link:N,nolink:J,punctuation:M,reflink:G,reflinkSearch:k("reflink|nolink(?!\\()","g").replace("reflink",G).replace("nolink",J).getRegex(),tag:X,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\<!\[`*_]|\b_|$)|[^ ](?= {2,}\n)))/,url:f},V={...K,link:k(/^!?\[(label)\]\((.*?)\)/).replace("label",F).getRegex(),reflink:k(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",F).getRegex()},W={...K,escape:k(Q).replace("])","~|])").getRegex(),url:k(/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,"i").replace("email",/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/).getRegex(),_backpedal:/(?:[^?!.,:;*_'"~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'"~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|(?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)|[\s\S]*?(?:(?=[\\<!\[`*~_]|\b_|https?:\/\/|ftp:\/\/|www\.|$)|[^ ](?= {2,}\n)|[^a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-](?=[a-zA-Z0-9.!#$%&'*+\/=?_`{\|}~-]+@)))/},Y={...W,br:k(v).replace("{2,}","*").getRegex(),text:k(W.text).replace("\\b_","\\b_| {2,}\\n").replace(/\{2,\}/g,"*").getRegex()},ee={normal:Z,gfm:L,pedantic:P},te={normal:K,gfm:W,breaks:Y,pedantic:V};class ne{tokens;options;state;tokenizer;inlineQueue;constructor(t){this.tokens=[],this.tokens.links=Object.create(null),this.options=t||e.defaults,this.options.tokenizer=this.options.tokenizer||new w,this.tokenizer=this.options.tokenizer,this.tokenizer.options=this.options,this.tokenizer.lexer=this,this.inlineQueue=[],this.state={inLink:!1,inRawBlock:!1,top:!0};const n={block:ee.normal,inline:te.normal};this.options.pedantic?(n.block=ee.pedantic,n.inline=te.pedantic):this.options.gfm&&(n.block=ee.gfm,this.options.breaks?n.inline=te.breaks:n.inline=te.gfm),this.tokenizer.rules=n}static get rules(){return{block:ee,inline:te}}static lex(e,t){return new ne(t).lex(e)}static lexInline(e,t){return new ne(t).inlineTokens(e)}lex(e){e=e.replace(/\r\n|\r/g,"\n"),this.blockTokens(e,this.tokens);for(let e=0;e<this.inlineQueue.length;e++){const t=this.inlineQueue[e];this.inlineTokens(t.src,t.tokens)}return this.inlineQueue=[],this.tokens}blockTokens(e,t=[]){let n,s,r,i;for(e=this.options.pedantic?e.replace(/\t/g," ").replace(/^ +$/gm,""):e.replace(/^( *)(\t+)/gm,((e,t,n)=>t+" ".repeat(n.length)));e;)if(!(this.options.extensions&&this.options.extensions.block&&this.options.extensions.block.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.space(e))e=e.substring(n.raw.length),1===n.raw.length&&t.length>0?t[t.length-1].raw+="\n":t.push(n);else if(n=this.tokenizer.code(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?t.push(n):(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.fences(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.heading(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.hr(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.blockquote(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.list(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.html(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.def(e))e=e.substring(n.raw.length),s=t[t.length-1],!s||"paragraph"!==s.type&&"text"!==s.type?this.tokens.links[n.tag]||(this.tokens.links[n.tag]={href:n.href,title:n.title}):(s.raw+="\n"+n.raw,s.text+="\n"+n.raw,this.inlineQueue[this.inlineQueue.length-1].src=s.text);else if(n=this.tokenizer.table(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.lheading(e))e=e.substring(n.raw.length),t.push(n);else{if(r=e,this.options.extensions&&this.options.extensions.startBlock){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startBlock.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(this.state.top&&(n=this.tokenizer.paragraph(r)))s=t[t.length-1],i&&"paragraph"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n),i=r.length!==e.length,e=e.substring(n.raw.length);else if(n=this.tokenizer.text(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===s.type?(s.raw+="\n"+n.raw,s.text+="\n"+n.text,this.inlineQueue.pop(),this.inlineQueue[this.inlineQueue.length-1].src=s.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}return this.state.top=!0,t}inline(e,t=[]){return this.inlineQueue.push({src:e,tokens:t}),t}inlineTokens(e,t=[]){let n,s,r,i,l,o,a=e;if(this.tokens.links){const e=Object.keys(this.tokens.links);if(e.length>0)for(;null!=(i=this.tokenizer.rules.inline.reflinkSearch.exec(a));)e.includes(i[0].slice(i[0].lastIndexOf("[")+1,-1))&&(a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex))}for(;null!=(i=this.tokenizer.rules.inline.blockSkip.exec(a));)a=a.slice(0,i.index)+"["+"a".repeat(i[0].length-2)+"]"+a.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);for(;null!=(i=this.tokenizer.rules.inline.anyPunctuation.exec(a));)a=a.slice(0,i.index)+"++"+a.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);for(;e;)if(l||(o=""),l=!1,!(this.options.extensions&&this.options.extensions.inline&&this.options.extensions.inline.some((s=>!!(n=s.call({lexer:this},e,t))&&(e=e.substring(n.raw.length),t.push(n),!0)))))if(n=this.tokenizer.escape(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.tag(e))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.link(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.reflink(e,this.tokens.links))e=e.substring(n.raw.length),s=t[t.length-1],s&&"text"===n.type&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(n=this.tokenizer.emStrong(e,a,o))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.codespan(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.br(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.del(e))e=e.substring(n.raw.length),t.push(n);else if(n=this.tokenizer.autolink(e))e=e.substring(n.raw.length),t.push(n);else if(this.state.inLink||!(n=this.tokenizer.url(e))){if(r=e,this.options.extensions&&this.options.extensions.startInline){let t=1/0;const n=e.slice(1);let s;this.options.extensions.startInline.forEach((e=>{s=e.call({lexer:this},n),"number"==typeof s&&s>=0&&(t=Math.min(t,s))})),t<1/0&&t>=0&&(r=e.substring(0,t+1))}if(n=this.tokenizer.inlineText(r))e=e.substring(n.raw.length),"_"!==n.raw.slice(-1)&&(o=n.raw.slice(-1)),l=!0,s=t[t.length-1],s&&"text"===s.type?(s.raw+=n.raw,s.text+=n.text):t.push(n);else if(e){const t="Infinite loop on byte: "+e.charCodeAt(0);if(this.options.silent){console.error(t);break}throw new Error(t)}}else e=e.substring(n.raw.length),t.push(n);return t}}class se{options;constructor(t){this.options=t||e.defaults}code(e,t,n){const s=(t||"").match(/^\S*/)?.[0];return e=e.replace(/\n$/,"")+"\n",s?'<pre><code class="language-'+c(s)+'">'+(n?e:c(e,!0))+"</code></pre>\n":"<pre><code>"+(n?e:c(e,!0))+"</code></pre>\n"}blockquote(e){return`<blockquote>\n${e}</blockquote>\n`}html(e,t){return e}heading(e,t,n){return`<h${t}>${e}</h${t}>\n`}hr(){return"<hr>\n"}list(e,t,n){const s=t?"ol":"ul";return"<"+s+(t&&1!==n?' start="'+n+'"':"")+">\n"+e+"</"+s+">\n"}listitem(e,t,n){return`<li>${e}</li>\n`}checkbox(e){return"<input "+(e?'checked="" ':"")+'disabled="" type="checkbox">'}paragraph(e){return`<p>${e}</p>\n`}table(e,t){return t&&(t=`<tbody>${t}</tbody>`),"<table>\n<thead>\n"+e+"</thead>\n"+t+"</table>\n"}tablerow(e){return`<tr>\n${e}</tr>\n`}tablecell(e,t){const n=t.header?"th":"td";return(t.align?`<${n} align="${t.align}">`:`<${n}>`)+e+`</${n}>\n`}strong(e){return`<strong>${e}</strong>`}em(e){return`<em>${e}</em>`}codespan(e){return`<code>${e}</code>`}br(){return"<br>"}del(e){return`<del>${e}</del>`}link(e,t,n){const s=g(e);if(null===s)return n;let r='<a href="'+(e=s)+'"';return t&&(r+=' title="'+t+'"'),r+=">"+n+"</a>",r}image(e,t,n){const s=g(e);if(null===s)return n;let r=`<img src="${e=s}" alt="${n}"`;return t&&(r+=` title="${t}"`),r+=">",r}text(e){return e}}class re{strong(e){return e}em(e){return e}codespan(e){return e}del(e){return e}html(e){return e}text(e){return e}link(e,t,n){return""+n}image(e,t,n){return""+n}br(){return""}}class ie{options;renderer;textRenderer;constructor(t){this.options=t||e.defaults,this.options.renderer=this.options.renderer||new se,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new re}static parse(e,t){return new ie(t).parse(e)}static parseInline(e,t){return new ie(t).parseInline(e)}parse(e,t=!0){let n="";for(let s=0;s<e.length;s++){const r=e[s];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[r.type]){const e=r,t=this.options.extensions.renderers[e.type].call({parser:this},e);if(!1!==t||!["space","hr","heading","code","table","blockquote","list","html","paragraph","text"].includes(e.type)){n+=t||"";continue}}switch(r.type){case"space":continue;case"hr":n+=this.renderer.hr();continue;case"heading":{const e=r;n+=this.renderer.heading(this.parseInline(e.tokens),e.depth,p(this.parseInline(e.tokens,this.textRenderer)));continue}case"code":{const e=r;n+=this.renderer.code(e.text,e.lang,!!e.escaped);continue}case"table":{const e=r;let t="",s="";for(let t=0;t<e.header.length;t++)s+=this.renderer.tablecell(this.parseInline(e.header[t].tokens),{header:!0,align:e.align[t]});t+=this.renderer.tablerow(s);let i="";for(let t=0;t<e.rows.length;t++){const n=e.rows[t];s="";for(let t=0;t<n.length;t++)s+=this.renderer.tablecell(this.parseInline(n[t].tokens),{header:!1,align:e.align[t]});i+=this.renderer.tablerow(s)}n+=this.renderer.table(t,i);continue}case"blockquote":{const e=r,t=this.parse(e.tokens);n+=this.renderer.blockquote(t);continue}case"list":{const e=r,t=e.ordered,s=e.start,i=e.loose;let l="";for(let t=0;t<e.items.length;t++){const n=e.items[t],s=n.checked,r=n.task;let o="";if(n.task){const e=this.renderer.checkbox(!!s);i?n.tokens.length>0&&"paragraph"===n.tokens[0].type?(n.tokens[0].text=e+" "+n.tokens[0].text,n.tokens[0].tokens&&n.tokens[0].tokens.length>0&&"text"===n.tokens[0].tokens[0].type&&(n.tokens[0].tokens[0].text=e+" "+n.tokens[0].tokens[0].text)):n.tokens.unshift({type:"text",text:e+" "}):o+=e+" "}o+=this.parse(n.tokens,i),l+=this.renderer.listitem(o,r,!!s)}n+=this.renderer.list(l,t,s);continue}case"html":{const e=r;n+=this.renderer.html(e.text,e.block);continue}case"paragraph":{const e=r;n+=this.renderer.paragraph(this.parseInline(e.tokens));continue}case"text":{let i=r,l=i.tokens?this.parseInline(i.tokens):i.text;for(;s+1<e.length&&"text"===e[s+1].type;)i=e[++s],l+="\n"+(i.tokens?this.parseInline(i.tokens):i.text);n+=t?this.renderer.paragraph(l):l;continue}default:{const e='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(e),"";throw new Error(e)}}}return n}parseInline(e,t){t=t||this.renderer;let n="";for(let s=0;s<e.length;s++){const r=e[s];if(this.options.extensions&&this.options.extensions.renderers&&this.options.extensions.renderers[r.type]){const e=this.options.extensions.renderers[r.type].call({parser:this},r);if(!1!==e||!["escape","html","link","image","strong","em","codespan","br","del","text"].includes(r.type)){n+=e||"";continue}}switch(r.type){case"escape":{const e=r;n+=t.text(e.text);break}case"html":{const e=r;n+=t.html(e.text);break}case"link":{const e=r;n+=t.link(e.href,e.title,this.parseInline(e.tokens,t));break}case"image":{const e=r;n+=t.image(e.href,e.title,e.text);break}case"strong":{const e=r;n+=t.strong(this.parseInline(e.tokens,t));break}case"em":{const e=r;n+=t.em(this.parseInline(e.tokens,t));break}case"codespan":{const e=r;n+=t.codespan(e.text);break}case"br":n+=t.br();break;case"del":{const e=r;n+=t.del(this.parseInline(e.tokens,t));break}case"text":{const e=r;n+=t.text(e.text);break}default:{const e='Token with "'+r.type+'" type was not found.';if(this.options.silent)return console.error(e),"";throw new Error(e)}}}return n}}class le{options;constructor(t){this.options=t||e.defaults}static passThroughHooks=new Set(["preprocess","postprocess","processAllTokens"]);preprocess(e){return e}postprocess(e){return e}processAllTokens(e){return e}}class oe{defaults={async:!1,breaks:!1,extensions:null,gfm:!0,hooks:null,pedantic:!1,renderer:null,silent:!1,tokenizer:null,walkTokens:null};options=this.setOptions;parse=this.#e(ne.lex,ie.parse);parseInline=this.#e(ne.lexInline,ie.parseInline);Parser=ie;Renderer=se;TextRenderer=re;Lexer=ne;Tokenizer=w;Hooks=le;constructor(...e){this.use(...e)}walkTokens(e,t){let n=[];for(const s of e)switch(n=n.concat(t.call(this,s)),s.type){case"table":{const e=s;for(const s of e.header)n=n.concat(this.walkTokens(s.tokens,t));for(const s of e.rows)for(const e of s)n=n.concat(this.walkTokens(e.tokens,t));break}case"list":{const e=s;n=n.concat(this.walkTokens(e.items,t));break}default:{const e=s;this.defaults.extensions?.childTokens?.[e.type]?this.defaults.extensions.childTokens[e.type].forEach((s=>{const r=e[s].flat(1/0);n=n.concat(this.walkTokens(r,t))})):e.tokens&&(n=n.concat(this.walkTokens(e.tokens,t)))}}return n}use(...e){const t=this.defaults.extensions||{renderers:{},childTokens:{}};return e.forEach((e=>{const n={...e};if(n.async=this.defaults.async||n.async||!1,e.extensions&&(e.extensions.forEach((e=>{if(!e.name)throw new Error("extension name required");if("renderer"in e){const n=t.renderers[e.name];t.renderers[e.name]=n?function(...t){let s=e.renderer.apply(this,t);return!1===s&&(s=n.apply(this,t)),s}:e.renderer}if("tokenizer"in e){if(!e.level||"block"!==e.level&&"inline"!==e.level)throw new Error("extension level must be 'block' or 'inline'");const n=t[e.level];n?n.unshift(e.tokenizer):t[e.level]=[e.tokenizer],e.start&&("block"===e.level?t.startBlock?t.startBlock.push(e.start):t.startBlock=[e.start]:"inline"===e.level&&(t.startInline?t.startInline.push(e.start):t.startInline=[e.start]))}"childTokens"in e&&e.childTokens&&(t.childTokens[e.name]=e.childTokens)})),n.extensions=t),e.renderer){const t=this.defaults.renderer||new se(this.defaults);for(const n in e.renderer){if(!(n in t))throw new Error(`renderer '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.renderer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n||""}}n.renderer=t}if(e.tokenizer){const t=this.defaults.tokenizer||new w(this.defaults);for(const n in e.tokenizer){if(!(n in t))throw new Error(`tokenizer '${n}' does not exist`);if(["options","rules","lexer"].includes(n))continue;const s=n,r=e.tokenizer[s],i=t[s];t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.tokenizer=t}if(e.hooks){const t=this.defaults.hooks||new le;for(const n in e.hooks){if(!(n in t))throw new Error(`hook '${n}' does not exist`);if("options"===n)continue;const s=n,r=e.hooks[s],i=t[s];le.passThroughHooks.has(n)?t[s]=e=>{if(this.defaults.async)return Promise.resolve(r.call(t,e)).then((e=>i.call(t,e)));const n=r.call(t,e);return i.call(t,n)}:t[s]=(...e)=>{let n=r.apply(t,e);return!1===n&&(n=i.apply(t,e)),n}}n.hooks=t}if(e.walkTokens){const t=this.defaults.walkTokens,s=e.walkTokens;n.walkTokens=function(e){let n=[];return n.push(s.call(this,e)),t&&(n=n.concat(t.call(this,e))),n}}this.defaults={...this.defaults,...n}})),this}setOptions(e){return this.defaults={...this.defaults,...e},this}lexer(e,t){return ne.lex(e,t??this.defaults)}parser(e,t){return ie.parse(e,t??this.defaults)}#e(e,t){return(n,s)=>{const r={...s},i={...this.defaults,...r};!0===this.defaults.async&&!1===r.async&&(i.silent||console.warn("marked(): The async option was set to true by an extension. The async: false option sent to parse will be ignored."),i.async=!0);const l=this.#t(!!i.silent,!!i.async);if(null==n)return l(new Error("marked(): input parameter is undefined or null"));if("string"!=typeof n)return l(new Error("marked(): input parameter is of type "+Object.prototype.toString.call(n)+", string expected"));if(i.hooks&&(i.hooks.options=i),i.async)return Promise.resolve(i.hooks?i.hooks.preprocess(n):n).then((t=>e(t,i))).then((e=>i.hooks?i.hooks.processAllTokens(e):e)).then((e=>i.walkTokens?Promise.all(this.walkTokens(e,i.walkTokens)).then((()=>e)):e)).then((e=>t(e,i))).then((e=>i.hooks?i.hooks.postprocess(e):e)).catch(l);try{i.hooks&&(n=i.hooks.preprocess(n));let s=e(n,i);i.hooks&&(s=i.hooks.processAllTokens(s)),i.walkTokens&&this.walkTokens(s,i.walkTokens);let r=t(s,i);return i.hooks&&(r=i.hooks.postprocess(r)),r}catch(e){return l(e)}}}#t(e,t){return n=>{if(n.message+="\nPlease report this to https://github.com/markedjs/marked.",e){const e="<p>An error occurred:</p><pre>"+c(n.message+"",!0)+"</pre>";return t?Promise.resolve(e):e}if(t)return Promise.reject(n);throw n}}}const ae=new oe;function ce(e,t){return ae.parse(e,t)}ce.options=ce.setOptions=function(e){return ae.setOptions(e),ce.defaults=ae.defaults,n(ce.defaults),ce},ce.getDefaults=t,ce.defaults=e.defaults,ce.use=function(...e){return ae.use(...e),ce.defaults=ae.defaults,n(ce.defaults),ce},ce.walkTokens=function(e,t){return ae.walkTokens(e,t)},ce.parseInline=ae.parseInline,ce.Parser=ie,ce.parser=ie.parse,ce.Renderer=se,ce.TextRenderer=re,ce.Lexer=ne,ce.lexer=ne.lex,ce.Tokenizer=w,ce.Hooks=le,ce.parse=ce;const he=ce.options,pe=ce.setOptions,ue=ce.use,ke=ce.walkTokens,ge=ce.parseInline,fe=ce,de=ie.parse,xe=ne.lex;e.Hooks=le,e.Lexer=ne,e.Marked=oe,e.Parser=ie,e.Renderer=se,e.TextRenderer=re,e.Tokenizer=w,e.getDefaults=t,e.lexer=xe,e.marked=ce,e.options=he,e.parse=fe,e.parseInline=ge,e.parser=de,e.setOptions=pe,e.use=ue,e.walkTokens=ke}));
|
package/server.js
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
const http = require('http');
|
|
2
2
|
const fs = require('fs');
|
|
3
3
|
const path = require('path');
|
|
4
|
+
const crypto = require('crypto');
|
|
4
5
|
|
|
5
6
|
const PORT = process.env.PORT || 3000;
|
|
6
7
|
|
|
8
|
+
// Auto-version: hash all non-font files in public/ at startup.
|
|
9
|
+
// Any file change = new hash = clients purge their SW cache.
|
|
10
|
+
const appHash = crypto.createHash('md5');
|
|
11
|
+
(function walkDir(dir) {
|
|
12
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
13
|
+
for (const entry of entries) {
|
|
14
|
+
if (entry.isDirectory()) {
|
|
15
|
+
if (entry.name === 'fonts') continue;
|
|
16
|
+
walkDir(path.join(dir, entry.name));
|
|
17
|
+
} else {
|
|
18
|
+
appHash.update(entry.name);
|
|
19
|
+
appHash.update(fs.readFileSync(path.join(dir, entry.name)));
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})(path.join(__dirname, 'public'));
|
|
23
|
+
const APP_VERSION = appHash.digest('hex').slice(0, 10);
|
|
24
|
+
|
|
7
25
|
const MIME = {
|
|
8
26
|
'.html': 'text/html; charset=utf-8',
|
|
9
27
|
'.css': 'text/css',
|
|
@@ -11,9 +29,17 @@ const MIME = {
|
|
|
11
29
|
'.json': 'application/json',
|
|
12
30
|
'.md': 'text/plain',
|
|
13
31
|
'.smd': 'text/plain',
|
|
32
|
+
'.woff2': 'font/woff2',
|
|
14
33
|
};
|
|
15
34
|
|
|
16
|
-
function
|
|
35
|
+
function cacheHeader(ext) {
|
|
36
|
+
if (ext === '.html') return 'no-cache';
|
|
37
|
+
if (ext === '.woff2') return 'public, max-age=31536000, immutable';
|
|
38
|
+
if (ext === '.css' || ext === '.js') return 'public, max-age=86400';
|
|
39
|
+
return 'no-cache';
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function serveFile(res, filePath, extraHeaders) {
|
|
17
43
|
fs.readFile(filePath, (err, data) => {
|
|
18
44
|
if (err) {
|
|
19
45
|
res.writeHead(404, { 'Content-Type': 'text/plain' });
|
|
@@ -21,7 +47,12 @@ function serveFile(res, filePath) {
|
|
|
21
47
|
return;
|
|
22
48
|
}
|
|
23
49
|
const ext = path.extname(filePath);
|
|
24
|
-
|
|
50
|
+
const headers = {
|
|
51
|
+
'Content-Type': MIME[ext] || 'application/octet-stream',
|
|
52
|
+
'Cache-Control': cacheHeader(ext),
|
|
53
|
+
};
|
|
54
|
+
Object.assign(headers, extraHeaders);
|
|
55
|
+
res.writeHead(200, headers);
|
|
25
56
|
res.end(data);
|
|
26
57
|
});
|
|
27
58
|
}
|
|
@@ -36,8 +67,39 @@ const server = http.createServer((req, res) => {
|
|
|
36
67
|
return;
|
|
37
68
|
}
|
|
38
69
|
|
|
70
|
+
// Version check — used by service worker to detect updates
|
|
71
|
+
if (pathname === '/version-check') {
|
|
72
|
+
const v = url.searchParams.get('v') || '';
|
|
73
|
+
console.log([
|
|
74
|
+
new Date().toISOString(),
|
|
75
|
+
req.headers['x-forwarded-for'] || req.socket.remoteAddress,
|
|
76
|
+
req.headers['user-agent'] || '',
|
|
77
|
+
req.headers['referer'] || '',
|
|
78
|
+
req.headers['accept-language'] || '',
|
|
79
|
+
v ? 'cached:' + v : 'no-cache',
|
|
80
|
+
].join(' | '));
|
|
81
|
+
res.writeHead(200, {
|
|
82
|
+
'Content-Type': 'application/json',
|
|
83
|
+
'Cache-Control': 'no-cache',
|
|
84
|
+
});
|
|
85
|
+
res.end(JSON.stringify({ version: APP_VERSION }));
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
|
|
39
89
|
if (pathname === '/' || pathname === '/new') {
|
|
40
|
-
|
|
90
|
+
const htmlPath = path.join(__dirname, 'public', 'index.html');
|
|
91
|
+
fs.readFile(htmlPath, 'utf8', (err, html) => {
|
|
92
|
+
if (err) { res.writeHead(500); res.end('Error'); return; }
|
|
93
|
+
html = html.replace('__APP_VERSION__', APP_VERSION);
|
|
94
|
+
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8', 'Cache-Control': 'no-cache' });
|
|
95
|
+
res.end(html);
|
|
96
|
+
});
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Service worker must be served from root scope
|
|
101
|
+
if (pathname === '/sw.js') {
|
|
102
|
+
serveFile(res, path.join(__dirname, 'public', 'sw.js'), { 'Cache-Control': 'no-cache' });
|
|
41
103
|
return;
|
|
42
104
|
}
|
|
43
105
|
|