Skip to content

Commit

Permalink
Migrate syntax to TypeScript
Browse files Browse the repository at this point in the history
  • Loading branch information
luin committed Aug 15, 2022
1 parent 114d7b7 commit 2b130d5
Showing 1 changed file with 51 additions and 14 deletions.
65 changes: 51 additions & 14 deletions modules/syntax.js → modules/syntax.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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);
Expand All @@ -41,6 +46,7 @@ class CodeToken extends Inline {
}

optimize(...args) {
// @ts-expect-error
super.optimize(...args);
if (!TokenAttributor.value(this.domNode)) {
this.unwrap();
Expand All @@ -51,58 +57,69 @@ 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);
}

format(name, value) {
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,
Expand All @@ -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);
Expand All @@ -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);
}
Expand All @@ -146,33 +166,45 @@ class SyntaxCodeBlockContainer extends CodeBlockContainer {
)}\n</pre>`;
}

optimize(context) {
optimize(context: unknown) {
super.optimize(context);
if (
this.parent != null &&
this.children.head != null &&
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<SyntaxOptions> {
static register() {
Quill.register(CodeToken, true);
// @ts-expect-error
Quill.register(SyntaxCodeBlock, true);
Quill.register(SyntaxCodeBlockContainer, true);
}

constructor(quill, options) {
languages: Record<string, true>;

constructor(quill: Quill, options: Partial<SyntaxOptions>) {
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.',
Expand Down Expand Up @@ -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);
Expand All @@ -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(
Expand All @@ -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);
Expand All @@ -284,6 +320,7 @@ class Syntax extends Module {
}
Syntax.DEFAULTS = {
hljs: (() => {
// @ts-expect-error
return window.hljs;
})(),
interval: 1000,
Expand Down

0 comments on commit 2b130d5

Please sign in to comment.