From 00cc5b0180d4c53d3beac357c34678115dc30d2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Philipp=20Ku=CC=88hn?= Date: Wed, 11 Mar 2020 10:02:47 +0100 Subject: [PATCH] add magic methods --- packages/tiptap-core/src/Editor.ts | 30 ++++-- .../tiptap-core/src/utils/magicMethods.js | 94 +++++++++++++++++++ tsconfig.json | 1 + 3 files changed, 116 insertions(+), 9 deletions(-) create mode 100644 packages/tiptap-core/src/utils/magicMethods.js diff --git a/packages/tiptap-core/src/Editor.ts b/packages/tiptap-core/src/Editor.ts index 8e487ada..69e6151a 100644 --- a/packages/tiptap-core/src/Editor.ts +++ b/packages/tiptap-core/src/Editor.ts @@ -14,6 +14,9 @@ import ExtensionManager from './ExtensionManager' import Extension from './Extension' import Node from './Node' +// @ts-ignore +import magicMethods from './utils/magicMethods' + type EditorContent = string | JSON type Command = (next: Function, editor: Editor, ...args: any) => any @@ -23,6 +26,7 @@ interface Options { injectCSS: Boolean } +@magicMethods export class Editor extends EventEmitter { element = document.createElement('div') @@ -55,24 +59,31 @@ export class Editor extends EventEmitter { } } + __get(name: string) { + const command = this.commands[name] + + if (!command) { + throw new Error(`tiptap: command '${name}' not found.`) + } + + return (...args: any) => command(...args) + } + public registerCommand(name: string, callback: Command): Editor { if (this.commands[name]) { throw new Error(`tiptap: command '${name}' is already defined.`) } - - this.commands[name] = callback - - // @ts-ignore - this[name] = this.chainCommand((...args: any) => { + + this.commands[name] = this.chainCommand((...args: any) => { return new Promise(resolve => callback(resolve, this, ...args)) }) - return this + // @ts-ignore + return this.proxy } public command(name: string, ...args: any) { - // @ts-ignore - return this[name](...args) + return this.commands[name](...args) } private createExtensionManager() { @@ -112,7 +123,8 @@ export class Editor extends EventEmitter { .then(() => method.apply(this, args)) .catch(console.error) - return this + // @ts-ignore + return this.proxy } private createDocument(content: EditorContent, parseOptions: any = {}): any { diff --git a/packages/tiptap-core/src/utils/magicMethods.js b/packages/tiptap-core/src/utils/magicMethods.js new file mode 100644 index 00000000..fcb0ddef --- /dev/null +++ b/packages/tiptap-core/src/utils/magicMethods.js @@ -0,0 +1,94 @@ +// export default function magicMethods (clazz) { +// const classHandler = Object.create(null) + +// // Trap for class instantiation +// classHandler.construct = (target, args) => { +// // Wrapped class instance +// const instance = new clazz(...args) +// // Instance traps +// const instanceHandler = Object.create(null) + +// const get = Object.getOwnPropertyDescriptor(clazz.prototype, 'command') +// if (get) { +// instanceHandler.get = (target, name) => { +// const exists = name in target + +// if (exists) { +// return target[name] +// } else { +// return get.value.call(target, name) +// } +// } +// } + +// return new Proxy(instance, instanceHandler) +// } + +// return new Proxy(clazz, classHandler) +// } + +// export default function magicMethods (clazz) { +// const classHandler = Object.create(null) + +// // Trap for class instantiation +// classHandler.construct = (target, args) => { +// // Wrapped class instance +// const instance = new clazz(...args) +// // Instance traps +// const instanceHandler = Object.create(null) + +// const get = Object.getOwnPropertyDescriptor(clazz.prototype, 'command') +// if (get) { +// instanceHandler.get = (target, name) => { +// const exists = name in target + +// if (exists) { +// return target[name] +// } else { +// return get.value.call(target, name) +// } +// } +// } + +// // return new Proxy(instance, instanceHandler) +// const proxy = new Proxy(instance, instanceHandler) +// instance.proxy = proxy + +// return proxy +// } + +// return new Proxy(clazz, classHandler) +// } + + +export default function magicMethods (clazz) { + const classHandler = Object.create(null) + + classHandler.construct = (target, args) => { + const instance = new clazz(...args) + const instanceHandler = Object.create(null) + const get = Object.getOwnPropertyDescriptor(clazz.prototype, '__get') + + if (get) { + instanceHandler.get = (target, name) => { + if (typeof name !== 'string') { + return + } + + const exists = name in target || name.startsWith('_') + + if (exists) { + return target[name] + } else { + return get.value.call(target, name) + } + } + } + + instance.proxy = new Proxy(instance, instanceHandler) + + return instance.proxy + } + + return new Proxy(clazz, classHandler) +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 1b67a7c5..db0194ad 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -8,6 +8,7 @@ "moduleResolution": "node", "esModuleInterop": true, "allowSyntheticDefaultImports": true, + "experimentalDecorators": true, "sourceMap": true, "baseUrl": ".", "types": [