diff --git a/copyparty/web/util.js b/copyparty/web/util.js
index 2f56553b..76b9c1ff 100644
--- a/copyparty/web/util.js
+++ b/copyparty/web/util.js
@@ -194,36 +194,40 @@ function ev(e) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith
-if (!String.prototype.endsWith) {
+if (!String.prototype.endsWith)
String.prototype.endsWith = function (search, this_len) {
if (this_len === undefined || this_len > this.length) {
this_len = this.length;
}
return this.substring(this_len - search.length, this_len) === search;
};
-}
-if (!String.startsWith) {
+
+if (!String.startsWith)
String.prototype.startsWith = function (s, i) {
i = i > 0 ? i | 0 : 0;
return this.substring(i, i + s.length) === s;
};
-}
-if (!Element.prototype.matches) {
+
+if (!String.trimEnd)
+ String.prototype.trimEnd = String.prototype.trimRight = function () {
+ return this.replace(/[ \t\r\n]+$/m, '');
+ };
+
+if (!Element.prototype.matches)
Element.prototype.matches =
Element.prototype.oMatchesSelector ||
Element.prototype.msMatchesSelector ||
Element.prototype.mozMatchesSelector ||
Element.prototype.webkitMatchesSelector;
-}
-if (!Element.prototype.closest) {
+
+if (!Element.prototype.closest)
Element.prototype.closest = function (s) {
var el = this;
do {
if (el.matches(s)) return el;
el = el.parentElement || el.parentNode;
} while (el !== null && el.nodeType === 1);
- }
-}
+ };
// https://stackoverflow.com/a/950146
diff --git a/scripts/deps-docker/Dockerfile b/scripts/deps-docker/Dockerfile
index 1feacec2..f55075f4 100644
--- a/scripts/deps-docker/Dockerfile
+++ b/scripts/deps-docker/Dockerfile
@@ -2,10 +2,10 @@ FROM alpine:3.14
WORKDIR /z
ENV ver_asmcrypto=5b994303a9d3e27e0915f72a10b6c2c51535a4dc \
ver_hashwasm=4.9.0 \
- ver_marked=1.1.0 \
+ ver_marked=3.0.4 \
ver_ogvjs=1.8.4 \
- ver_mde=2.14.0 \
- ver_codemirror=5.59.3 \
+ ver_mde=2.15.0 \
+ ver_codemirror=5.62.3 \
ver_fontawesome=5.13.0 \
ver_zopfli=1.0.3
@@ -113,7 +113,7 @@ RUN cd CodeMirror-$ver_codemirror \
COPY easymde.patch /z/
RUN cd easy-markdown-editor-$ver_mde \
&& patch -p1 < /z/easymde.patch \
- && sed -ri 's`https://registry.npmjs.org/marked/-/marked-0.8.2.tgz`file:/z/nodepkgs/marked`' package-lock.json \
+ && sed -ri 's`https://registry.npmjs.org/marked/-/marked-[0-9\.]+.tgz`file:/z/nodepkgs/marked`' package-lock.json \
&& sed -ri 's`("marked": ")[^"]+`\1file:/z/nodepkgs/marked`' ./package.json \
&& sed -ri 's`("codemirror": ")[^"]+`\1file:/z/nodepkgs/codemirror`' ./package.json \
&& npm install
diff --git a/scripts/deps-docker/marked-ln.patch b/scripts/deps-docker/marked-ln.patch
index 42066b06..552457fd 100644
--- a/scripts/deps-docker/marked-ln.patch
+++ b/scripts/deps-docker/marked-ln.patch
@@ -1,15 +1,15 @@
diff --git a/src/Lexer.js b/src/Lexer.js
-adds linetracking to marked.js v1.0.0 +git;
+adds linetracking to marked.js v3.0.4;
add data-ln="%d" to most tags, %d is the source markdown line
--- a/src/Lexer.js
+++ b/src/Lexer.js
-@@ -49,4 +49,5 @@ function mangle(text) {
+@@ -50,4 +50,5 @@ function mangle(text) {
module.exports = class Lexer {
constructor(options) {
+ this.ln = 1; // like most editors, start couting from 1
this.tokens = [];
this.tokens.links = Object.create(null);
-@@ -108,4 +109,15 @@ module.exports = class Lexer {
+@@ -127,4 +128,15 @@ module.exports = class Lexer {
}
+ set_ln(token, ln = this.ln) {
@@ -25,122 +25,123 @@ add data-ln="%d" to most tags, %d is the source markdown line
+
/**
* Lexing
-@@ -113,10 +125,15 @@ module.exports = class Lexer {
- blockTokens(src, tokens = [], top = true) {
- src = src.replace(/^ +$/gm, '');
-- let token, i, l, lastToken;
-+ let token, i, l, lastToken, ln;
+@@ -134,7 +146,11 @@ module.exports = class Lexer {
+ src = src.replace(/^ +$/gm, '');
+ }
+- let token, lastToken, cutSrc, lastParagraphClipped;
++ let token, lastToken, cutSrc, lastParagraphClipped, ln;
while (src) {
+ // this.ln will be bumped by recursive calls into this func;
+ // reset the count and rely on the outermost token's raw only
+ ln = this.ln;
+
- // newline
+ if (this.options.extensions
+ && this.options.extensions.block
+@@ -142,4 +158,5 @@ module.exports = class Lexer {
+ if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
+ src = src.substring(token.raw.length);
++ this.set_ln(token, ln);
+ tokens.push(token);
+ return true;
+@@ -153,4 +170,5 @@ module.exports = class Lexer {
if (token = this.tokenizer.space(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token); // is \n if not type
++ this.set_ln(token, ln); // is \n if not type
if (token.type) {
tokens.push(token);
-@@ -128,4 +145,5 @@ module.exports = class Lexer {
- if (token = this.tokenizer.code(src, tokens)) {
+@@ -162,4 +180,5 @@ module.exports = class Lexer {
+ if (token = this.tokenizer.code(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
- if (token.type) {
- tokens.push(token);
-@@ -141,4 +159,5 @@ module.exports = class Lexer {
++ this.set_ln(token, ln);
+ lastToken = tokens[tokens.length - 1];
+ // An indented code block cannot interrupt a paragraph.
+@@ -177,4 +196,5 @@ module.exports = class Lexer {
if (token = this.tokenizer.fences(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
++ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -148,4 +167,5 @@ module.exports = class Lexer {
+@@ -184,4 +204,5 @@ module.exports = class Lexer {
if (token = this.tokenizer.heading(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
++ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -155,4 +175,5 @@ module.exports = class Lexer {
- if (token = this.tokenizer.nptable(src)) {
- src = src.substring(token.raw.length);
-+ this.set_ln(token);
- tokens.push(token);
- continue;
-@@ -162,4 +183,5 @@ module.exports = class Lexer {
+@@ -191,4 +212,5 @@ module.exports = class Lexer {
if (token = this.tokenizer.hr(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
++ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -170,4 +192,7 @@ module.exports = class Lexer {
+@@ -198,4 +220,5 @@ module.exports = class Lexer {
+ if (token = this.tokenizer.blockquote(src)) {
src = src.substring(token.raw.length);
- token.tokens = this.blockTokens(token.text, [], top);
-+ // recursive call to blockTokens probably bumped this.ln,
-+ // token.raw is more reliable so reset this.ln and use that
+ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -180,5 +205,9 @@ module.exports = class Lexer {
- for (i = 0; i < l; i++) {
- token.items[i].tokens = this.blockTokens(token.items[i].text, [], false);
-+ // list entries don't bump the linecounter, so let's
-+ this.ln++;
- }
-+ // then reset like blockquote
+@@ -205,4 +228,5 @@ module.exports = class Lexer {
+ if (token = this.tokenizer.list(src)) {
+ src = src.substring(token.raw.length);
+ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -188,4 +217,5 @@ module.exports = class Lexer {
+@@ -212,4 +236,5 @@ module.exports = class Lexer {
if (token = this.tokenizer.html(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
++ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -195,4 +225,5 @@ module.exports = class Lexer {
- if (top && (token = this.tokenizer.def(src))) {
+@@ -219,4 +244,5 @@ module.exports = class Lexer {
+ if (token = this.tokenizer.def(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
- if (!this.tokens.links[token.tag]) {
- this.tokens.links[token.tag] = {
-@@ -207,4 +238,5 @@ module.exports = class Lexer {
++ this.set_ln(token, ln);
+ lastToken = tokens[tokens.length - 1];
+ if (lastToken && (lastToken.type === 'paragraph' || lastToken.type === 'text')) {
+@@ -236,4 +262,5 @@ module.exports = class Lexer {
if (token = this.tokenizer.table(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
++ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -214,4 +246,5 @@ module.exports = class Lexer {
+@@ -243,4 +270,5 @@ module.exports = class Lexer {
if (token = this.tokenizer.lheading(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
++ this.set_ln(token, ln);
tokens.push(token);
continue;
-@@ -221,4 +254,5 @@ module.exports = class Lexer {
- if (top && (token = this.tokenizer.paragraph(src))) {
+@@ -263,4 +291,5 @@ module.exports = class Lexer {
+ }
+ if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {
++ this.set_ln(token, ln);
+ lastToken = tokens[tokens.length - 1];
+ if (lastParagraphClipped && lastToken.type === 'paragraph') {
+@@ -280,4 +309,6 @@ module.exports = class Lexer {
+ if (token = this.tokenizer.text(src)) {
src = src.substring(token.raw.length);
-+ this.set_ln(token);
- tokens.push(token);
- continue;
-@@ -228,4 +262,5 @@ module.exports = class Lexer {
- if (token = this.tokenizer.text(src, tokens)) {
- src = src.substring(token.raw.length);
-+ this.set_ln(token);
- if (token.type) {
- tokens.push(token);
-@@ -263,4 +298,7 @@ module.exports = class Lexer {
- for (i = 0; i < l; i++) {
- token = tokens[i];
-+ // this.ln is at EOF when inline() is invoked;
-+ // all this affects
tags only so no biggie if it breaks
-+ this.ln = token.ln || this.ln;
- switch (token.type) {
- case 'paragraph':
-@@ -386,4 +424,6 @@ module.exports = class Lexer {
++ this.set_ln(token, ln);
++ this.ln++;
+ lastToken = tokens[tokens.length - 1];
+ if (lastToken && lastToken.type === 'text') {
+@@ -355,4 +386,5 @@ module.exports = class Lexer {
+ if (token = extTokenizer.call({ lexer: this }, src, tokens)) {
+ src = src.substring(token.raw.length);
++ this.ln = token.ln || this.ln;
+ tokens.push(token);
+ return true;
+@@ -420,4 +452,6 @@ module.exports = class Lexer {
if (token = this.tokenizer.br(src)) {
src = src.substring(token.raw.length);
+ // no need to reset (no more blockTokens anyways)
+ token.ln = this.ln++;
tokens.push(token);
continue;
+@@ -462,4 +496,5 @@ module.exports = class Lexer {
+ if (token = this.tokenizer.inlineText(cutSrc, smartypants)) {
+ src = src.substring(token.raw.length);
++ this.ln = token.ln || this.ln;
+ if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started
+ prevChar = token.raw.slice(-1);
diff --git a/src/Parser.js b/src/Parser.js
--- a/src/Parser.js
+++ b/src/Parser.js
@@ -150,17 +151,16 @@ diff --git a/src/Parser.js b/src/Parser.js
+ this.ln = 0; // error indicator; should always be set >=1 from tokens
}
-@@ -55,4 +56,9 @@ module.exports = class Parser {
+@@ -64,4 +65,8 @@ module.exports = class Parser {
for (i = 0; i < l; i++) {
token = tokens[i];
+ // take line-numbers from tokens whenever possible
+ // and update the renderer's html attribute with the new value
+ this.ln = token.ln || this.ln;
+ this.renderer.tag_ln(this.ln);
-+
- switch (token.type) {
- case 'space': {
-@@ -105,7 +111,10 @@ module.exports = class Parser {
+
+ // Run any renderer extensions
+@@ -124,7 +129,10 @@ module.exports = class Parser {
}
- body += this.renderer.tablerow(cell);
@@ -173,7 +173,7 @@ diff --git a/src/Parser.js b/src/Parser.js
+ out += this.renderer.tag_ln(token.ln).table(header, body);
continue;
}
-@@ -148,8 +157,12 @@ module.exports = class Parser {
+@@ -167,8 +175,12 @@ module.exports = class Parser {
itemBody += this.parse(item.tokens, loose);
- body += this.renderer.listitem(itemBody, task, checked);
@@ -188,7 +188,7 @@ diff --git a/src/Parser.js b/src/Parser.js
+ out += this.renderer.tag_ln(token.ln).list(body, ordered, start);
continue;
}
-@@ -160,5 +173,6 @@ module.exports = class Parser {
+@@ -179,5 +191,6 @@ module.exports = class Parser {
}
case 'paragraph': {
- out += this.renderer.paragraph(this.parseInline(token.tokens));
@@ -196,22 +196,14 @@ diff --git a/src/Parser.js b/src/Parser.js
+ out += this.renderer.tag_ln(token.ln).paragraph(t);
continue;
}
-@@ -199,4 +213,6 @@ module.exports = class Parser {
- for (i = 0; i < l; i++) {
+@@ -221,4 +234,7 @@ module.exports = class Parser {
token = tokens[i];
+
+ // another thing that only affects
and other inlines
+ this.ln = token.ln || this.ln;
- switch (token.type) {
- case 'escape': {
-@@ -229,5 +245,7 @@ module.exports = class Parser {
- }
- case 'br': {
-- out += renderer.br();
-+ // update the html attribute before writing each
,
-+ // don't care about the others
-+ out += renderer.tag_ln(this.ln).br();
- break;
- }
++
+ // Run any renderer extensions
+ if (this.options.extensions && this.options.extensions.renderers && this.options.extensions.renderers[token.type]) {
diff --git a/src/Renderer.js b/src/Renderer.js
--- a/src/Renderer.js
+++ b/src/Renderer.js
@@ -228,7 +220,7 @@ diff --git a/src/Renderer.js b/src/Renderer.js
+
code(code, infostring, escaped) {
const lang = (infostring || '').match(/\S*/)[0];
-@@ -24,10 +30,10 @@ module.exports = class Renderer {
+@@ -26,10 +32,10 @@ module.exports = class Renderer {
if (!lang) {
- return '
'
@@ -241,58 +233,69 @@ diff --git a/src/Renderer.js b/src/Renderer.js
+ return '' + text + '\n';
+ return '' + text + ' \n';
}
-@@ -73,5 +80,5 @@ module.exports = class Renderer {
+@@ -75,5 +82,5 @@ module.exports = class Renderer {
listitem(text) {
- return '' + text + ' \n';
+ return '' + text + ' \n';
}
-@@ -85,5 +92,5 @@ module.exports = class Renderer {
+@@ -87,5 +94,5 @@ module.exports = class Renderer {
paragraph(text) {
- return '' + text + '
\n';
+ return '' + text + '
\n';
}
-@@ -100,5 +107,5 @@ module.exports = class Renderer {
+@@ -102,5 +109,5 @@ module.exports = class Renderer {
tablerow(content) {
- return '\n' + content + ' \n';
+ return '\n' + content + ' \n';
}
-@@ -125,5 +132,5 @@ module.exports = class Renderer {
+@@ -127,5 +134,5 @@ module.exports = class Renderer {
br() {
- return this.options.xhtml ? '
' : '
';
+ return this.options.xhtml ? '
' : '
';
}
-@@ -151,5 +158,5 @@ module.exports = class Renderer {
+@@ -153,5 +160,5 @@ module.exports = class Renderer {
}
- let out = '
{
-@@ -53,3 +49,2 @@ runSpecs('Original', './original', false, { gfm: false, pedantic: true });
+ const before = process.hrtime();
+@@ -53,3 +48,2 @@ runSpecs('Original', './original', false, { gfm: false, pedantic: true });
runSpecs('New', './new');
runSpecs('ReDOS', './redos');
-runSpecs('Security', './security', false, { silent: true }); // silent - do not show deprecation warning
diff --git a/test/unit/Lexer-spec.js b/test/unit/Lexer-spec.js
--- a/test/unit/Lexer-spec.js
+++ b/test/unit/Lexer-spec.js
-@@ -465,5 +465,5 @@ a | b
+@@ -589,5 +589,5 @@ paragraph
});
- it('sanitize', () => {
+ /*it('sanitize', () => {
expectTokens({
md: 'html',
-@@ -483,5 +483,5 @@ a | b
+@@ -607,5 +607,5 @@ paragraph
]
});
- });
+ });*/
});
-@@ -587,5 +587,5 @@ a | b
+@@ -652,5 +652,5 @@ paragraph
});
- it('html sanitize', () => {
+ /*it('html sanitize', () => {
expectInlineTokens({
md: 'html',
-@@ -597,5 +597,5 @@ a | b
+@@ -660,5 +660,5 @@ paragraph
]
});
- });
+ });*/
it('link', () => {
-@@ -909,5 +909,5 @@ a | b
+@@ -971,5 +971,5 @@ paragraph
});
- it('autolink mangle email', () => {
+ /*it('autolink mangle email', () => {
expectInlineTokens({
md: '',
-@@ -929,5 +929,5 @@ a | b
+@@ -991,5 +991,5 @@ paragraph
]
});
- });
+ });*/
it('url', () => {
-@@ -966,5 +966,5 @@ a | b
+@@ -1028,5 +1028,5 @@ paragraph
});
- it('url mangle email', () => {
+ /*it('url mangle email', () => {
expectInlineTokens({
md: 'test@example.com',
-@@ -986,5 +986,5 @@ a | b
+@@ -1048,5 +1048,5 @@ paragraph
]
});
- });
+ });*/
});
-@@ -1002,5 +1002,5 @@ a | b
+@@ -1064,5 +1064,5 @@ paragraph
});
- describe('smartypants', () => {
+ /*describe('smartypants', () => {
it('single quotes', () => {
expectInlineTokens({
-@@ -1072,5 +1072,5 @@ a | b
+@@ -1134,5 +1134,5 @@ paragraph
});
});
- });
diff --git a/srv/test.md b/srv/test.md
index 05affa33..838739cf 100644
--- a/srv/test.md
+++ b/srv/test.md
@@ -140,12 +140,12 @@ a newline toplevel
| a table | on the right |
| second row | foo bar |
-||
+a||a
--|:-:|-:
a table | big text in this | aaakbfddd
second row | centred | bbb
-||
+||||
--|--|--
foo