From 2b130d5af811e67fafa43b7f76bf90055888be59 Mon Sep 17 00:00:00 2001 From: Zihua Li Date: Mon, 15 Aug 2022 14:33:33 +0800 Subject: [PATCH] Migrate syntax to TypeScript --- modules/{syntax.js => syntax.ts} | 65 +++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 14 deletions(-) rename modules/{syntax.js => syntax.ts} (84%) diff --git a/modules/syntax.js b/modules/syntax.ts similarity index 84% rename from modules/syntax.js rename to modules/syntax.ts index da91073a89..b7c994c5dc 100644 --- a/modules/syntax.js +++ b/modules/syntax.ts @@ -1,5 +1,5 @@ import Delta from 'quill-delta'; -import { ClassAttributor, Scope } from 'parchment'; +import { ClassAttributor, Scope, ScrollBlot } from 'parchment'; import Inline from '../blots/inline'; import Quill from '../core/quill'; import Module from '../core/module'; @@ -14,25 +14,30 @@ const TokenAttributor = new ClassAttributor('code-token', 'hljs', { scope: Scope.INLINE, }); class CodeToken extends Inline { - static formats(node, scroll) { + static formats(node: Element, scroll: ScrollBlot) { while (node != null && node !== scroll.domNode) { if (node.classList && node.classList.contains(CodeBlock.className)) { + // @ts-expect-error return super.formats(node, scroll); } + // @ts-expect-error node = node.parentNode; } return undefined; } - constructor(scroll, domNode, value) { + constructor(scroll: ScrollBlot, domNode: Node, value: unknown) { + // @ts-expect-error super(scroll, domNode, value); + // @ts-expect-error TokenAttributor.add(this.domNode, value); } - format(format, value) { + format(format: string, value: unknown) { if (format !== CodeToken.blotName) { super.format(format, value); } else if (value) { + // @ts-expect-error TokenAttributor.add(this.domNode, value); } else { TokenAttributor.remove(this.domNode); @@ -41,6 +46,7 @@ class CodeToken extends Inline { } optimize(...args) { + // @ts-expect-error super.optimize(...args); if (!TokenAttributor.value(this.domNode)) { this.unwrap(); @@ -51,38 +57,45 @@ CodeToken.blotName = 'code-token'; CodeToken.className = 'ql-token'; class SyntaxCodeBlock extends CodeBlock { - static create(value) { + static create(value: unknown) { const domNode = super.create(value); if (typeof value === 'string') { + // @ts-expect-error domNode.setAttribute('data-language', value); } return domNode; } - static formats(domNode) { + static formats(domNode: Node) { + // @ts-expect-error return domNode.getAttribute('data-language') || 'plain'; } static register() {} // Syntax module will register - format(name, value) { + format(name: string, value: unknown) { if (name === this.statics.blotName && value) { + // @ts-expect-error this.domNode.setAttribute('data-language', value); } else { super.format(name, value); } } - replaceWith(name, value) { + replaceWith(name: string, value: unknown) { this.formatAt(0, this.length(), CodeToken.blotName, false); return super.replaceWith(name, value); } } class SyntaxCodeBlockContainer extends CodeBlockContainer { + forceNext?: boolean; + cachedText?: string | null; + attach() { super.attach(); this.forceNext = false; + // @ts-expect-error this.scroll.emitMount(this); } @@ -90,19 +103,23 @@ class SyntaxCodeBlockContainer extends CodeBlockContainer { if (name === SyntaxCodeBlock.blotName) { this.forceNext = true; this.children.forEach(child => { + // @ts-expect-error child.format(name, value); }); } } - formatAt(index, length, name, value) { + formatAt(index: number, length: number, name, value) { if (name === SyntaxCodeBlock.blotName) { this.forceNext = true; } super.formatAt(index, length, name, value); } - highlight(highlight, forced = false) { + highlight( + highlight: (text: string, language: string) => Delta, + forced = false, + ) { if (this.children.head == null) return; const nodes = Array.from(this.domNode.childNodes).filter( node => node !== this.uiNode, @@ -112,6 +129,7 @@ class SyntaxCodeBlockContainer extends CodeBlockContainer { if (forced || this.forceNext || this.cachedText !== text) { if (text.trim().length > 0 || this.cachedText == null) { const oldDelta = this.children.reduce((delta, child) => { + // @ts-expect-error return delta.concat(blockDelta(child, false)); }, new Delta()); const delta = highlight(text, language); @@ -123,10 +141,12 @@ class SyntaxCodeBlockContainer extends CodeBlockContainer { if ( [SyntaxCodeBlock.blotName, CodeToken.blotName].includes(format) ) { + // @ts-expect-error this.formatAt(index, retain, format, attributes[format]); } }); } + // @ts-expect-error return index + retain; }, 0); } @@ -146,7 +166,7 @@ class SyntaxCodeBlockContainer extends CodeBlockContainer { )}\n`; } - optimize(context) { + optimize(context: unknown) { super.optimize(context); if ( this.parent != null && @@ -154,25 +174,37 @@ class SyntaxCodeBlockContainer extends CodeBlockContainer { this.uiNode != null ) { const language = SyntaxCodeBlock.formats(this.children.head.domNode); + // @ts-expect-error if (language !== this.uiNode.value) { + // @ts-expect-error this.uiNode.value = language; } } } } +// @ts-expect-error SyntaxCodeBlockContainer.allowedChildren = [SyntaxCodeBlock]; SyntaxCodeBlock.requiredContainer = SyntaxCodeBlockContainer; SyntaxCodeBlock.allowedChildren = [CodeToken, CursorBlot, TextBlot, BreakBlot]; -class Syntax extends Module { +interface SyntaxOptions { + interval: number; + languages: { key: string; label: string }[]; +} + +class Syntax extends Module { static register() { Quill.register(CodeToken, true); + // @ts-expect-error Quill.register(SyntaxCodeBlock, true); Quill.register(SyntaxCodeBlockContainer, true); } - constructor(quill, options) { + languages: Record; + + constructor(quill: Quill, options: Partial) { super(quill, options); + // @ts-expect-error if (this.options.hljs == null) { throw new Error( 'Syntax module requires highlight.js. Please include the library on the page before Quill.', @@ -228,7 +260,8 @@ class Syntax extends Module { const range = this.quill.getSelection(); const blots = blot == null - ? this.quill.scroll.descendants(SyntaxCodeBlockContainer) + ? // @ts-expect-error + this.quill.scroll.descendants(SyntaxCodeBlockContainer) : [blot]; blots.forEach(container => { container.highlight(this.highlightBlot, force); @@ -253,12 +286,14 @@ class Syntax extends Module { } const container = this.quill.root.ownerDocument.createElement('div'); container.classList.add(CodeBlock.className); + // @ts-expect-error container.innerHTML = this.options.hljs.highlight(language, text).value; return traverse( this.quill.scroll, container, [ (node, delta) => { + // @ts-expect-error const value = TokenAttributor.value(node); if (value) { return delta.compose( @@ -272,6 +307,7 @@ class Syntax extends Module { ], [ (node, delta) => { + // @ts-expect-error return node.data.split('\n').reduce((memo, nodeText, i) => { if (i !== 0) memo.insert('\n', { [CodeBlock.blotName]: language }); return memo.insert(nodeText); @@ -284,6 +320,7 @@ class Syntax extends Module { } Syntax.DEFAULTS = { hljs: (() => { + // @ts-expect-error return window.hljs; })(), interval: 1000,