From 958e5a80b7164cff58f17a994b336d2436303ae3 Mon Sep 17 00:00:00 2001 From: Laurent Cozic Date: Fri, 16 Oct 2020 22:55:48 +0100 Subject: [PATCH] Desktop: Fixes #3903: Header links with special characters were no longer working --- CliClient/package-lock.json | 28 +++++++-- CliClient/package.json | 2 +- .../tests/support/plugins/toc/src/index.ts | 4 +- ElectronClient/package-lock.json | 59 +++++++++++++++---- ElectronClient/package.json | 2 +- .../lib/joplin-renderer/MdToHtml.js | 4 +- .../lib/joplin-renderer/package-lock.json | 31 ++++++++-- .../lib/joplin-renderer/package.json | 2 +- .../lib/services/plugins/PluginService.ts | 4 +- ReactNativeClient/package-lock.json | 31 ++++++++-- ReactNativeClient/package.json | 2 +- readme/api/tutorials/toc_plugin.md | 6 +- 12 files changed, 137 insertions(+), 38 deletions(-) diff --git a/CliClient/package-lock.json b/CliClient/package-lock.json index 07d9a08e5..e20374e28 100644 --- a/CliClient/package-lock.json +++ b/CliClient/package-lock.json @@ -5895,11 +5895,6 @@ "is-fullwidth-code-point": "^2.0.0" } }, - "slug": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/slug/-/slug-3.5.0.tgz", - "integrity": "sha512-+pZLDhMtmAc+ZcojQSMlUKDZBYmvhZiZmK8Ffx/D3Q/MIMHPDBAMbWvWN8vJb9xl2MfbDdRWxFzrdOhBiyVpow==" - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -6762,6 +6757,11 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" }, + "unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" + }, "unpack-string": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/unpack-string/-/unpack-string-0.0.2.tgz", @@ -6864,6 +6864,24 @@ "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==" }, + "uslug": { + "version": "git+https://github.com/laurent22/uslug.git#ba2834d79beb0435318709958b2f5e817d96674d", + "from": "git+https://github.com/laurent22/uslug.git#emoji-support", + "requires": { + "node-emoji": "^1.10.0", + "unorm": ">= 1.0.0" + }, + "dependencies": { + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "requires": { + "lodash.toarray": "^4.4.0" + } + } + } + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", diff --git a/CliClient/package.json b/CliClient/package.json index b2d1b0690..95b9e4c45 100644 --- a/CliClient/package.json +++ b/CliClient/package.json @@ -101,7 +101,6 @@ "sax": "^1.2.4", "server-destroy": "^1.0.1", "sharp": "^0.23.2", - "slug": "^3.5.0", "sprintf-js": "^1.1.1", "sqlite3": "^4.1.1", "string-padding": "^1.0.2", @@ -113,6 +112,7 @@ "terminal-kit": "^1.30.0", "tkwidgets": "^0.5.26", "url-parse": "^1.4.7", + "uslug": "git+https://github.com/laurent22/uslug.git#emoji-support", "uuid": "^3.0.1", "valid-url": "^1.0.9", "word-wrap": "^1.2.3", diff --git a/CliClient/tests/support/plugins/toc/src/index.ts b/CliClient/tests/support/plugins/toc/src/index.ts index 8393be258..e72bf662d 100644 --- a/CliClient/tests/support/plugins/toc/src/index.ts +++ b/CliClient/tests/support/plugins/toc/src/index.ts @@ -1,6 +1,6 @@ import joplin from 'api'; -const nodeSlug = require('slug'); +const uslug = require('uslug'); // From https://stackoverflow.com/a/6234804/561309 function escapeHtml(unsafe:string) { @@ -29,7 +29,7 @@ function noteHeaders(noteBody:string) { let slugs:any = {}; function headerSlug(headerText:string) { - const s = nodeSlug(headerText); + const s = uslug(headerText); let num = slugs[s] ? slugs[s] : 1; const output = [s]; if (num > 1) output.push(num); diff --git a/ElectronClient/package-lock.json b/ElectronClient/package-lock.json index 7c98b7e26..1a117ba17 100644 --- a/ElectronClient/package-lock.json +++ b/ElectronClient/package-lock.json @@ -1535,7 +1535,8 @@ }, "mkdirp": { "version": "0.5.1", - "resolved": "", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", "dev": true, "optional": true, "requires": { @@ -1700,7 +1701,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -1815,7 +1817,8 @@ }, "tar": { "version": "4.4.8", - "resolved": "", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", "dev": true, "optional": true, "requires": { @@ -5946,8 +5949,22 @@ }, "mkdirp": { "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", "dev": true, - "optional": true + "optional": true, + "requires": { + "minimist": "^1.2.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true, + "optional": true + } + } }, "ms": { "version": "2.1.2", @@ -6117,7 +6134,8 @@ "dependencies": { "minimist": { "version": "1.2.0", - "resolved": "", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", "dev": true, "optional": true } @@ -7762,6 +7780,11 @@ "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -8490,6 +8513,14 @@ "semver": "^5.4.1" } }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "requires": { + "lodash.toarray": "^4.4.0" + } + }, "node-fetch": { "version": "1.7.3", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", @@ -10668,11 +10699,6 @@ } } }, - "slug": { - "version": "3.5.0", - "resolved": "https://registry.npmjs.org/slug/-/slug-3.5.0.tgz", - "integrity": "sha512-+pZLDhMtmAc+ZcojQSMlUKDZBYmvhZiZmK8Ffx/D3Q/MIMHPDBAMbWvWN8vJb9xl2MfbDdRWxFzrdOhBiyVpow==" - }, "smalltalk": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/smalltalk/-/smalltalk-2.5.1.tgz", @@ -11735,6 +11761,11 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz", "integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=" }, + "unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" + }, "unset-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", @@ -11926,6 +11957,14 @@ "integrity": "sha1-K1viOjK2Onyd640PKNSFcko98ZA=", "dev": true }, + "uslug": { + "version": "git+https://github.com/laurent22/uslug.git#ba2834d79beb0435318709958b2f5e817d96674d", + "from": "git+https://github.com/laurent22/uslug.git#emoji-support", + "requires": { + "node-emoji": "^1.10.0", + "unorm": ">= 1.0.0" + } + }, "utf8-byte-length": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz", diff --git a/ElectronClient/package.json b/ElectronClient/package.json index 463893304..846851bda 100644 --- a/ElectronClient/package.json +++ b/ElectronClient/package.json @@ -195,7 +195,6 @@ "roboto-fontface": "^0.10.0", "sax": "^1.2.4", "server-destroy": "^1.0.1", - "slug": "^3.5.0", "smalltalk": "^2.5.1", "sprintf-js": "^1.1.1", "sqlite3": "^4.1.1", @@ -211,6 +210,7 @@ "tinymce": "^5.2.0", "uglifycss": "0.0.29", "url-parse": "^1.4.3", + "uslug": "git+https://github.com/laurent22/uslug.git#emoji-support", "uuid": "^3.2.1", "valid-url": "^1.0.9", "xml2js": "^0.4.19" diff --git a/ReactNativeClient/lib/joplin-renderer/MdToHtml.js b/ReactNativeClient/lib/joplin-renderer/MdToHtml.js index 8a0c3979d..cdbc2619f 100644 --- a/ReactNativeClient/lib/joplin-renderer/MdToHtml.js +++ b/ReactNativeClient/lib/joplin-renderer/MdToHtml.js @@ -22,7 +22,7 @@ const rules = { // const eventManager = require('lib/eventManager').default; const setupLinkify = require('./MdToHtml/setupLinkify'); const hljs = require('highlight.js'); -const nodeSlug = require('slug'); +const uslug = require('uslug'); const markdownItAnchor = require('markdown-it-anchor'); // The keys must match the corresponding entry in Setting.js const plugins = { @@ -41,7 +41,7 @@ const plugins = { const defaultNoteStyle = require('./defaultNoteStyle'); function slugify(s) { - return nodeSlug(s); + return uslug(s); } // Share across all instances of MdToHtml diff --git a/ReactNativeClient/lib/joplin-renderer/package-lock.json b/ReactNativeClient/lib/joplin-renderer/package-lock.json index 2b2b35f6f..d5c6304ef 100644 --- a/ReactNativeClient/lib/joplin-renderer/package-lock.json +++ b/ReactNativeClient/lib/joplin-renderer/package-lock.json @@ -738,6 +738,11 @@ "resolved": "https://registry.npmjs.org/lodash.repeat/-/lodash.repeat-4.1.0.tgz", "integrity": "sha1-/H3oEx2MisB+S0n3T/6CnR8r7EQ=" }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, "lower-case": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz", @@ -915,6 +920,14 @@ "lower-case": "^1.1.1" } }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "requires": { + "lodash.toarray": "^4.4.0" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", @@ -966,11 +979,6 @@ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" }, - "slug": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/slug/-/slug-3.5.1.tgz", - "integrity": "sha512-ei0JnJzg8HKhLunZy+vpNlILRRradfaAQ+p2YEI4b4r8yX/5TlFi1JSwcYQCg7INZxdTC43BT68rHMkRxzn7Xg==" - }, "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", @@ -1057,11 +1065,24 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" + }, "upper-case": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz", "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=" }, + "uslug": { + "version": "git+https://github.com/laurent22/uslug.git#ba2834d79beb0435318709958b2f5e817d96674d", + "from": "git+https://github.com/laurent22/uslug.git#emoji-support", + "requires": { + "node-emoji": "^1.10.0", + "unorm": ">= 1.0.0" + } + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/ReactNativeClient/lib/joplin-renderer/package.json b/ReactNativeClient/lib/joplin-renderer/package.json index d24202be2..ca1a8f857 100644 --- a/ReactNativeClient/lib/joplin-renderer/package.json +++ b/ReactNativeClient/lib/joplin-renderer/package.json @@ -37,6 +37,6 @@ "markdown-it-toc-done-right": "^4.1.0", "md5": "^2.2.1", "mermaid": "^8.8.1", - "slug": "^3.5.0" + "uslug": "git+https://github.com/laurent22/uslug.git#emoji-support" } } diff --git a/ReactNativeClient/lib/services/plugins/PluginService.ts b/ReactNativeClient/lib/services/plugins/PluginService.ts index 89d19c566..f5d7d1444 100644 --- a/ReactNativeClient/lib/services/plugins/PluginService.ts +++ b/ReactNativeClient/lib/services/plugins/PluginService.ts @@ -5,7 +5,7 @@ import BasePluginRunner from 'lib/services/plugins/BasePluginRunner'; import BaseService from '../BaseService'; import shim from 'lib/shim'; const { filename, dirname } = require('lib/path-utils'); -const nodeSlug = require('slug'); +const uslug = require('uslug'); interface Plugins { [key:string]: Plugin @@ -13,7 +13,7 @@ interface Plugins { function makePluginId(source:string):string { // https://www.npmjs.com/package/slug#options - return nodeSlug(source, nodeSlug.defaults.modes['rfc3986']).substr(0,32); + return uslug(source).substr(0,32); } export default class PluginService extends BaseService { diff --git a/ReactNativeClient/package-lock.json b/ReactNativeClient/package-lock.json index a9f1fb075..f399a82a7 100644 --- a/ReactNativeClient/package-lock.json +++ b/ReactNativeClient/package-lock.json @@ -5232,6 +5232,11 @@ "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", "integrity": "sha1-wj6RtxAkKscMN/HhzaknTMOb8vQ=" }, + "lodash.toarray": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz", + "integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=" + }, "log-symbols": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-2.2.0.tgz", @@ -7125,6 +7130,14 @@ "lower-case": "^1.1.1" } }, + "node-emoji": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz", + "integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==", + "requires": { + "lodash.toarray": "^4.4.0" + } + }, "node-fetch": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", @@ -9196,11 +9209,6 @@ "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz", "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc=" }, - "slug": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/slug/-/slug-3.5.1.tgz", - "integrity": "sha512-ei0JnJzg8HKhLunZy+vpNlILRRradfaAQ+p2YEI4b4r8yX/5TlFi1JSwcYQCg7INZxdTC43BT68rHMkRxzn7Xg==" - }, "snapdragon": { "version": "0.8.2", "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", @@ -9855,6 +9863,11 @@ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==" }, + "unorm": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz", + "integrity": "sha512-b2/KCUlYZUeA7JFUuRJZPUtr4gZvBh7tavtv4fvk4+KV9pfGiR6CQAQAWl49ZpR3ts2dk4FYkP7EIgDJoiOLDA==" + }, "unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -9950,6 +9963,14 @@ "object-assign": "^4.1.1" } }, + "uslug": { + "version": "git+https://github.com/laurent22/uslug.git#ba2834d79beb0435318709958b2f5e817d96674d", + "from": "git+https://github.com/laurent22/uslug.git#emoji-support", + "requires": { + "node-emoji": "^1.10.0", + "unorm": ">= 1.0.0" + } + }, "utf8": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/utf8/-/utf8-3.0.0.tgz", diff --git a/ReactNativeClient/package.json b/ReactNativeClient/package.json index 3d997bfa7..79f26dbaa 100644 --- a/ReactNativeClient/package.json +++ b/ReactNativeClient/package.json @@ -81,13 +81,13 @@ "redux": "4.0.0", "reselect": "^4.0.0", "rn-fetch-blob": "^0.12.0", - "slug": "^3.5.0", "stream": "0.0.2", "string-natural-compare": "^2.0.2", "string-padding": "^1.0.2", "timers": "^0.1.1", "url": "^0.11.0", "url-parse": "^1.4.7", + "uslug": "git+https://github.com/laurent22/uslug.git#emoji-support", "uuid": "^3.0.1", "valid-url": "^1.0.9", "word-wrap": "^1.2.3", diff --git a/readme/api/tutorials/toc_plugin.md b/readme/api/tutorials/toc_plugin.md index 6df267d40..ecb21869e 100644 --- a/readme/api/tutorials/toc_plugin.md +++ b/readme/api/tutorials/toc_plugin.md @@ -125,17 +125,17 @@ joplin.plugins.register({ }); ``` -Later you will also need a way to generate the slug for each header. A slug is an identifier which is used to link to a particular header. Essentially a header text like "My Header" is converted to "my-header". And if there's already a slug with that name, a number is appended to it. Without going into too much details, you will need the "slug" package to generate this for you, so install it using `npm i -s slug` from the root of your plugin directory. +Later you will also need a way to generate the slug for each header. A slug is an identifier which is used to link to a particular header. Essentially a header text like "My Header" is converted to "my-header". And if there's already a slug with that name, a number is appended to it. Without going into too much details, you will need the "slug" package to generate this for you, so install it using `npm i -s uslug` from the root of your plugin directory. Then this is the function you will need for Joplin, so copy it somewhere in your file: ```typescript -const nodeSlug = require('slug'); +const uslug = require('uslug'); let slugs = {}; function headerSlug(headerText) { - const s = nodeSlug(headerText); + const s = uslug(headerText); let num = slugs[s] ? slugs[s] : 1; const output = [s]; if (num > 1) output.push(num);