diff --git a/apps/server/package.json b/apps/server/package.json index ab6938a8f..38b64de7e 100644 --- a/apps/server/package.json +++ b/apps/server/package.json @@ -126,7 +126,7 @@ "swagger-jsdoc": "6.2.8", "time2fa": "1.4.2", "tmp": "0.2.5", - "turndown": "7.2.2", + "turnish": "1.7.1", "unescape": "1.0.1", "vite": "7.3.1", "ws": "8.19.0", diff --git a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote.html b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote.html index 439cdab93..30a170a9c 100644 --- a/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote.html +++ b/apps/server/src/assets/doc_notes/en/User Guide/User Guide/Basic Concepts and Features/Import & Export/Evernote.html @@ -1,55 +1,53 @@ -

- Trilium can import ENEX files, which are used by Evernote for backup/export. +

Trilium can import ENEX files, which are used by Evernote for backup/export. One ENEX file represents the content (notes and resources) of one notebook.

Export ENEX from Evernote

To export ENEX files from Evernote, you can use:

Import ENEX in Trilium

Once you have your ENEX files, do the following to import them in Trilium:

    -
  1. In the Trilium note tree, right-click the note under which you want to +
  2. In the Trilium note tree, right-click the note under which you want to import one or more of your ENEX files. The notes in the files will be imported as child notes of the selected note.
  3. -
  4. Click Import into note.
  5. -
  6. Choose your ENEX file or files and click Import.
  7. -
  8. During the import, you will see "Import in progress" message. If the import +
  9. Click Import into note.
  10. +
  11. Choose your ENEX file or files and click Import.
  12. +
  13. During the import, you will see "Import in progress" message. If the import is successful, the message will change to “Import finished successfully” and then disappear.
  14. -
  15. We recommend you to check the imported notes and their attachments to +
  16. We recommend you to check the imported notes and their attachments to verify that you haven’t lost any data.

A non-exhaustive list of what the importer preserves:

However, we do not guarantee that all of your formatting will be imported 100% correctly.

Limitations

@@ -59,24 +57,24 @@

If you want to restore the internal links in Trilium after you import all of your ENEX files, you can use or adapt this custom script:  Process internal links by title + class="reference-link" href="#root/_help_dj3j8dG4th4l">Process internal links by title

The script does the following:

    -
  1. It finds all Evernote internal links.
  2. -
  3. For each one, it checks if its link text matches a note title, and if +
  4. It finds all Evernote internal links.
  5. +
  6. For each one, it checks if its link text matches a note title, and if yes, it replaces the Evernote link with an internal Trilium link. If not, it leaves the Evernote link in place.
  7. -
  8. If it finds more than one note with a matching note title, it leaves the +
  9. If it finds more than one note with a matching note title, it leaves the Evernote link in place.
  10. -
  11. It outputs the results in a log that you can see in the respective code - note in Trilium. 
  12. +
  13. It outputs the results in a log that you can see in the respective code + note in Trilium.

The script has the following limitations:

\ No newline at end of file diff --git a/apps/server/src/services/export/markdown.spec.ts b/apps/server/src/services/export/markdown.spec.ts index 4fa2913fc..505d4b02d 100644 --- a/apps/server/src/services/export/markdown.spec.ts +++ b/apps/server/src/services/export/markdown.spec.ts @@ -387,4 +387,58 @@ describe("Markdown export", () => { expect(markdownExportService.toMarkdown(html)).toBe(expected); }); + it("maintains escaped HTML tags", () => { + const html = /*html*/`

<div>Hello World</div>

`; + const expected = `\\Hello World\\`; + expect(markdownExportService.toMarkdown(html)).toBe(expected); + }); + + it("escapes HTML tags inside list", () => { + const html = trimIndentation/*html*/`\ + + `; + const expected = trimIndentation`\ + * \\ is note.`; + expect(markdownExportService.toMarkdown(html)).toBe(expected); + }); + + it("exports jQuery code in table properly", () => { + const html = trimIndentation`\ +
+ + + + + + + + + + + +
+ Code +
+
+            this.$widget = $("<div>");
+                                
+
+
+ `; + const expected = trimIndentation`\ +
Code
this.$widget = $("<div>");
+                                
`; + expect(markdownExportService.toMarkdown(html)).toBe(expected); + }); + + it("renders emphasis with underscore", () => { + const html = /*html*/`

This is underlined text.

`; + const expected = `This is _underlined_ text.`; + expect(markdownExportService.toMarkdown(html)).toBe(expected); + }); + }); diff --git a/apps/server/src/services/export/markdown.ts b/apps/server/src/services/export/markdown.ts index ed16c6b30..35e08ee11 100644 --- a/apps/server/src/services/export/markdown.ts +++ b/apps/server/src/services/export/markdown.ts @@ -1,9 +1,7 @@ -"use strict"; - -import TurndownService, { type Rule } from "turndown"; import { gfm } from "@triliumnext/turndown-plugin-gfm"; +import Turnish, { type Rule } from "turnish"; -let instance: TurndownService | null = null; +let instance: Turnish | null = null; // TODO: Move this to a dedicated file someday. export const ADMONITION_TYPE_MAPPINGS: Record = { @@ -16,12 +14,12 @@ export const ADMONITION_TYPE_MAPPINGS: Record = { export const DEFAULT_ADMONITION_TYPE = ADMONITION_TYPE_MAPPINGS.note; -const fencedCodeBlockFilter: TurndownService.Rule = { - filter: function (node, options) { +const fencedCodeBlockFilter: Rule = { + filter (node, options) { return options.codeBlockStyle === "fenced" && node.nodeName === "PRE" && node.firstChild !== null && node.firstChild.nodeName === "CODE"; }, - replacement: function (content, node, options) { + replacement (content, node, options) { if (!node.firstChild || !("getAttribute" in node.firstChild) || typeof node.firstChild.getAttribute !== "function") { return content; } @@ -29,23 +27,25 @@ const fencedCodeBlockFilter: TurndownService.Rule = { const className = node.firstChild.getAttribute("class") || ""; const language = rewriteLanguageTag((className.match(/language-(\S+)/) || [null, ""])[1]); - return "\n\n" + options.fence + language + "\n" + node.firstChild.textContent + "\n" + options.fence + "\n\n"; + return `\n\n${options.fence}${language}\n${node.firstChild.textContent}\n${options.fence}\n\n`; } }; function toMarkdown(content: string) { if (instance === null) { - instance = new TurndownService({ + instance = new Turnish({ headingStyle: "atx", + bulletListMarker: "*", + emDelimiter: "_", codeBlockStyle: "fenced", - blankReplacement(content, node, options) { - if (node.nodeName === "SECTION" && (node as HTMLElement).classList.contains("include-note")) { - return (node as HTMLElement).outerHTML; + blankReplacement(_content, node) { + if (node.nodeName === "SECTION" && node.classList.contains("include-note")) { + return node.outerHTML; } // Original implementation as per https://github.com/mixmark-io/turndown/blob/master/src/turndown.js. - return ("isBlock" in node && node.isBlock) ? '\n\n' : '' - } + return ("isBlock" in node && node.isBlock) ? '\n\n' : ''; + }, }); // Filter is heavily based on: https://github.com/mixmark-io/turndown/issues/274#issuecomment-458730974 instance.addRule("fencedCodeBlock", fencedCodeBlockFilter); @@ -59,7 +59,7 @@ function toMarkdown(content: string) { instance.keep([ "kbd", "sup", "sub" ]); } - return instance.turndown(content); + return instance.render(content); } function rewriteLanguageTag(source: string) { @@ -85,14 +85,14 @@ function buildImageFilter() { const ESCAPE_PATTERNS = { before: /([\\*`[\]_]|(?:^[-+>])|(?:^~~~)|(?:^#{1-6}))/g, after: /((?:^\d+(?=\.)))/ - } + }; - const escapePattern = new RegExp('(?:' + ESCAPE_PATTERNS.before.source + '|' + ESCAPE_PATTERNS.after.source + ')', 'g'); + const escapePattern = new RegExp(`(?:${ESCAPE_PATTERNS.before.source}|${ESCAPE_PATTERNS.after.source})`, 'g'); function escapeMarkdown (content: string) { - return content.replace(escapePattern, function (match, before, after) { - return before ? '\\' + before : after + '\\' - }) + return content.replace(escapePattern, (match, before, after) => { + return before ? `\\${before}` : `${after}\\`; + }); } function escapeLinkDestination(destination: string) { @@ -102,10 +102,10 @@ function buildImageFilter() { } function escapeLinkTitle (title: string) { - return title.replace(/"/g, '\\"') + return title.replace(/"/g, '\\"'); } - const imageFilter: TurndownService.Rule = { + const imageFilter: Rule = { filter: "img", replacement(content, _node) { const node = _node as HTMLElement; @@ -117,12 +117,12 @@ function buildImageFilter() { // TODO: Deduplicate with upstream. const untypedNode = (node as any); - const alt = escapeMarkdown(cleanAttribute(untypedNode.getAttribute('alt'))) - const src = escapeLinkDestination(untypedNode.getAttribute('src') || '') - const title = cleanAttribute(untypedNode.getAttribute('title')) - const titlePart = title ? ' "' + escapeLinkTitle(title) + '"' : '' + const alt = escapeMarkdown(cleanAttribute(untypedNode.getAttribute('alt'))); + const src = escapeLinkDestination(untypedNode.getAttribute('src') || ''); + const title = cleanAttribute(untypedNode.getAttribute('title')); + const titlePart = title ? ` "${escapeLinkTitle(title)}"` : ''; - return src ? '![' + alt + ']' + '(' + src + titlePart + ')' : '' + return src ? `![${alt}](${src}${titlePart})` : ''; } }; return imageFilter; @@ -151,7 +151,7 @@ function buildAdmonitionFilter() { return DEFAULT_ADMONITION_TYPE; } - const admonitionFilter: TurndownService.Rule = { + const admonitionFilter: Rule = { filter(node, options) { return node.nodeName === "ASIDE" && node.classList.contains("admonition"); }, @@ -161,11 +161,11 @@ function buildAdmonitionFilter() { content = content.replace(/^\n+|\n+$/g, ''); content = content.replace(/^/gm, '> '); - content = `> [!${admonitionType}]\n` + content; + content = `> [!${admonitionType}]\n${content}`; - return "\n\n" + content + "\n\n"; + return `\n\n${content}\n\n`; } - } + }; return admonitionFilter; } @@ -178,15 +178,15 @@ function buildAdmonitionFilter() { */ function buildInlineLinkFilter(): Rule { return { - filter: function (node, options) { + filter (node, options) { return ( options.linkStyle === 'inlined' && node.nodeName === 'A' && !!node.getAttribute('href') - ) + ); }, - replacement: function (content, _node) { + replacement (content, _node) { const node = _node as HTMLElement; // Return reference links verbatim. @@ -196,13 +196,13 @@ function buildInlineLinkFilter(): Rule { // Otherwise treat as normal. // TODO: Call super() somehow instead of duplicating the implementation. - let href = node.getAttribute('href') - if (href) href = href.replace(/([()])/g, '\\$1') - let title = cleanAttribute(node.getAttribute('title')) - if (title) title = ' "' + title.replace(/"/g, '\\"') + '"' - return '[' + content + '](' + href + title + ')' + let href = node.getAttribute('href'); + if (href) href = href.replace(/([()])/g, '\\$1'); + let title = cleanAttribute(node.getAttribute('title')); + if (title) title = ` "${title.replace(/"/g, '\\"')}"`; + return `[${content}](${href}${title})`; } - } + }; } function buildFigureFilter(): Rule { @@ -214,7 +214,7 @@ function buildFigureFilter(): Rule { replacement(content, node) { return (node as HTMLElement).outerHTML; } - } + }; } // Keep in line with https://github.com/mixmark-io/turndown/blob/master/src/commonmark-rules.js. @@ -224,13 +224,13 @@ function buildListItemFilter(): Rule { replacement(content, node, options) { content = content .trim() - .replace(/\n/gm, '\n ') // indent - let prefix = options.bulletListMarker + ' ' + .replace(/\n/gm, '\n '); // indent + let prefix = `${options.bulletListMarker} `; const parent = node.parentNode as HTMLElement; if (parent.nodeName === 'OL') { - var start = parent.getAttribute('start') - var index = Array.prototype.indexOf.call(parent.children, node) - prefix = (start ? Number(start) + index : index + 1) + '. ' + const start = parent.getAttribute('start'); + const index = Array.prototype.indexOf.call(parent.children, node); + prefix = `${start ? Number(start) + index : index + 1}. `; } else if (parent.classList.contains("todo-list")) { const isChecked = node.querySelector("input[type=checkbox]:checked"); prefix = (isChecked ? "- [x] " : "- [ ] "); @@ -239,7 +239,7 @@ function buildListItemFilter(): Rule { const result = prefix + content + (node.nextSibling && !/\n$/.test(content) ? '\n' : ''); return result; } - } + }; } function buildMathFilter(): Rule { @@ -270,13 +270,13 @@ function buildMathFilter(): Rule { // Unknown. return content; } - } + }; } // Taken from upstream since it's not exposed. // https://github.com/mixmark-io/turndown/blob/master/src/commonmark-rules.js function cleanAttribute(attribute: string | null | undefined) { - return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : '' + return attribute ? attribute.replace(/(\n+\s*)+/g, '\n') : ''; } export default { diff --git a/apps/server/src/services/import/markdown.spec.ts b/apps/server/src/services/import/markdown.spec.ts index 1ac49f613..e692c7baa 100644 --- a/apps/server/src/services/import/markdown.spec.ts +++ b/apps/server/src/services/import/markdown.spec.ts @@ -314,4 +314,9 @@ $$`; expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected); }); + it("preserves HTML entities in list", () => { + const input = `* <note> is note.`; + const expected = /*html*/`
  • <note> is note.
`; + expect(markdownService.renderToHtml(input, "Title")).toStrictEqual(expected); + }); }); diff --git a/docs/Developer Guide/Developer Guide/Documentation.md b/docs/Developer Guide/Developer Guide/Documentation.md index 4f833f93b..73e47ab6b 100644 --- a/docs/Developer Guide/Developer Guide/Documentation.md +++ b/docs/Developer Guide/Developer Guide/Documentation.md @@ -1,5 +1,5 @@ # Documentation -There are multiple types of documentation for Trilium: +There are multiple types of documentation for Trilium: * The _User Guide_ represents the user-facing documentation. This documentation can be browsed by users directly from within Trilium, by pressing F1. * The _Developer's Guide_ represents a set of Markdown documents that present the internals of Trilium, for developers. diff --git a/docs/Release Notes/Release Notes/v0.101.2.md b/docs/Release Notes/Release Notes/v0.101.2.md index 6942b2e8e..d6baaabde 100644 --- a/docs/Release Notes/Release Notes/v0.101.2.md +++ b/docs/Release Notes/Release Notes/v0.101.2.md @@ -18,5 +18,5 @@ * [Max content width is not respected when switching between note types in the same tab](https://github.com/TriliumNext/Trilium/issues/8065) * [Crash When a Note Includes Itself](https://github.com/TriliumNext/Trilium/issues/8294) * [Severe Performance Degradation and Crash Issues Due to Recursive Inclusion in Included Notes](https://github.com/TriliumNext/Trilium/issues/8017) -* [ is not a launcher even though it's in the launcher subtree](https://github.com/TriliumNext/Trilium/issues/8218) +* [\ is not a launcher even though it's in the launcher subtree](https://github.com/TriliumNext/Trilium/issues/8218) * [Archived subnotes of direct children appear in grid view without #includeArchived](https://github.com/TriliumNext/Trilium/issues/8184) \ No newline at end of file diff --git a/docs/User Guide/!!!meta.json b/docs/User Guide/!!!meta.json index 2c8eafa53..9965fbda6 100644 --- a/docs/User Guide/!!!meta.json +++ b/docs/User Guide/!!!meta.json @@ -6169,6 +6169,20 @@ "type": "text", "mime": "text/markdown", "attributes": [ + { + "type": "relation", + "name": "internalLink", + "value": "dj3j8dG4th4l", + "isInheritable": false, + "position": 10 + }, + { + "type": "relation", + "name": "internalLink", + "value": "wy8So3yZZlH9", + "isInheritable": false, + "position": 20 + }, { "type": "label", "name": "shareAlias", @@ -6182,20 +6196,6 @@ "value": "bx bx-window-open", "isInheritable": false, "position": 30 - }, - { - "type": "relation", - "name": "internalLink", - "value": "dj3j8dG4th4l", - "isInheritable": false, - "position": 40 - }, - { - "type": "relation", - "name": "internalLink", - "value": "wy8So3yZZlH9", - "isInheritable": false, - "position": 50 } ], "format": "markdown", diff --git a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes.md b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes.md index 539f42ac0..7519e7be4 100644 --- a/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes.md +++ b/docs/User Guide/User Guide/Basic Concepts and Features/Notes/Sorting Notes.md @@ -28,4 +28,4 @@ Sorting is done by comparing note properties or specific labels on child notes. * **Label Sorting**: If `#sorted` has any other value, this value is treated as the name of a child note's label, and sorting is based on the values of this label. For example, setting `#sorted=myOrder` on the parent note and using `#myOrder=001`, `#myOrder=002`, etc., on child notes. 4. **Alphabetical Sorting**: Used as a last resort when other criteria result in equality. -All comparisons are made string-wise (e.g., "1" < "2" or "2020-10-10" < "2021-01-15", but also "2" > "10"). \ No newline at end of file +All comparisons are made string-wise (e.g., "1" \< "2" or "2020-10-10" < "2021-01-15", but also "2" \> "10"). \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4aab82cc0..9ddb28ceb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -792,9 +792,9 @@ importers: tmp: specifier: 0.2.5 version: 0.2.5 - turndown: - specifier: 7.2.2 - version: 7.2.2 + turnish: + specifier: 1.7.1 + version: 1.7.1 unescape: specifier: 1.0.1 version: 1.0.1 @@ -1461,6 +1461,9 @@ importers: packages: + '@adobe/css-tools@4.4.4': + resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -13466,6 +13469,9 @@ packages: turndown@7.2.2: resolution: {integrity: sha512-1F7db8BiExOKxjSMU2b7if62D/XOyQyZbPKq/nUwopfgnHlqXHqQ0lvfUTeUIr1lZJzOPFn43dODyMSIfvWRKQ==} + turnish@1.7.1: + resolution: {integrity: sha512-NgyY7pIDABjKyg2isRgZyFPav6tOyvmqpTx3HROsKrOaE3JccP4C1P2IhAtkAZ8DkQb/O1R7HOFAkxY8uaJmcQ==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -14407,6 +14413,8 @@ packages: snapshots: + '@adobe/css-tools@4.4.4': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -15078,6 +15086,8 @@ snapshots: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-upload': 47.4.0 ckeditor5: 47.4.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-ai@47.4.0(bufferutil@4.0.9)(utf-8-validate@6.0.5)': dependencies: @@ -15218,12 +15228,16 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-cloud-services@47.4.0': dependencies: '@ckeditor/ckeditor5-core': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-code-block@47.4.0(patch_hash=2361d8caad7d6b5bddacc3a3b4aa37dbfba260b1c1b22a450413a79c1bb1ce95)': dependencies: @@ -15416,6 +15430,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-classic@47.4.0': dependencies: @@ -15425,6 +15441,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-decoupled@47.4.0': dependencies: @@ -15434,6 +15452,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-editor-inline@47.4.0': dependencies: @@ -15467,8 +15487,6 @@ snapshots: '@ckeditor/ckeditor5-table': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-emoji@47.4.0': dependencies: @@ -15525,8 +15543,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-export-word@47.4.0': dependencies: @@ -15551,6 +15567,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-font@47.4.0': dependencies: @@ -15625,6 +15643,8 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 + transitivePeerDependencies: + - supports-color '@ckeditor/ckeditor5-html-embed@47.4.0': dependencies: @@ -15670,8 +15690,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-import-word@47.4.0': dependencies: @@ -15684,8 +15702,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-indent@47.4.0': dependencies: @@ -15697,8 +15713,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-inspector@5.0.0': {} @@ -15708,8 +15722,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-line-height@47.4.0': dependencies: @@ -15734,8 +15746,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-list-multi-level@47.4.0': dependencies: @@ -15759,8 +15769,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-markdown-gfm@47.4.0': dependencies: @@ -15798,8 +15806,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-mention@47.4.0(patch_hash=5981fb59ba35829e4dff1d39cf771000f8a8fdfa7a34b51d8af9549541f2d62d)': dependencies: @@ -15809,8 +15815,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-merge-fields@47.4.0': dependencies: @@ -15823,8 +15827,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-minimap@47.4.0': dependencies: @@ -15833,8 +15835,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-operations-compressor@47.4.0': dependencies: @@ -15889,8 +15889,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-pagination@47.4.0': dependencies: @@ -15998,8 +15996,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-slash-command@47.4.0': dependencies: @@ -16012,8 +16008,6 @@ snapshots: '@ckeditor/ckeditor5-ui': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-source-editing-enhanced@47.4.0': dependencies: @@ -16061,8 +16055,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-table@47.4.0': dependencies: @@ -16075,8 +16067,6 @@ snapshots: '@ckeditor/ckeditor5-widget': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-template@47.4.0': dependencies: @@ -16189,8 +16179,6 @@ snapshots: '@ckeditor/ckeditor5-engine': 47.4.0 '@ckeditor/ckeditor5-utils': 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@ckeditor/ckeditor5-widget@47.4.0': dependencies: @@ -16210,8 +16198,6 @@ snapshots: '@ckeditor/ckeditor5-utils': 47.4.0 ckeditor5: 47.4.0 es-toolkit: 1.39.5 - transitivePeerDependencies: - - supports-color '@codemirror/autocomplete@6.18.6': dependencies: @@ -21678,8 +21664,6 @@ snapshots: ckeditor5-collaboration@47.4.0: dependencies: '@ckeditor/ckeditor5-collaboration-core': 47.4.0 - transitivePeerDependencies: - - supports-color ckeditor5-premium-features@47.4.0(bufferutil@4.0.9)(ckeditor5@47.4.0)(utf-8-validate@6.0.5): dependencies: @@ -30075,6 +30059,11 @@ snapshots: dependencies: '@mixmark-io/domino': 2.2.0 + turnish@1.7.1: + dependencies: + '@adobe/css-tools': 4.4.4 + '@mixmark-io/domino': 2.2.0 + type-check@0.4.0: dependencies: prelude-ls: 1.2.1