Browse Source

Revert "feat(plugin): merge implementation"

This reverts commit 7f867236d7337b1ac791eb9a2d6211a081bff920.
Tienson Qin 4 years ago
parent
commit
f1f9800d96

+ 0 - 1
.gitignore

@@ -31,4 +31,3 @@ strings.csv
 resources/electron.js
 .clj-kondo/
 .lsp/
-/libs/dist/

+ 1 - 2
deps.edn

@@ -34,8 +34,7 @@
   thheller/shadow-cljs        {:mvn/version "2.12.5"}
   expound/expound             {:mvn/version "0.8.6"}
   com.lambdaisland/glogi      {:mvn/version "1.0.116"}
-  binaryage/devtools          {:mvn/version "1.0.2"}
-  camel-snake-kebab/camel-snake-kebab {:mvn/version "0.4.2"}}
+  binaryage/devtools          {:mvn/version "1.0.2"}}
 
  :aliases {:cljs {:extra-paths ["src/dev-cljs/" "src/test/" "src/electron/"]
                   :extra-deps  {org.clojure/clojurescript   {:mvn/version "1.10.844"}

+ 0 - 2
libs/.npmignore

@@ -1,2 +0,0 @@
-src/
-webpack.*

+ 0 - 17
libs/README.md

@@ -1,17 +0,0 @@
-## @logseq/libs
-
-🚀 Logseq SDK libraries [WIP].
-
-#### Installation
-
-```shell
-yarn add @logseq/libs
-```
-
-#### Usage
-
-Load `logseq` plugin sdk as global namespace
-
-```js
-import "@logseq/libs"
-```

+ 0 - 5
libs/index.d.ts

@@ -1,5 +0,0 @@
-import { ILSPluginUser } from './dist/LSPlugin'
-
-declare global {
-  var logseq: ILSPluginUser
-}

+ 0 - 34
libs/package.json

@@ -1,34 +0,0 @@
-{
-  "name": "@logseq/libs",
-  "version": "0.0.1-alpha.6",
-  "description": "Logseq SDK libraries",
-  "main": "dist/lsplugin.user.js",
-  "typings": "index.d.ts",
-  "private": false,
-  "scripts": {
-    "build:user": "webpack --mode production",
-    "dev:user": "npm run build:user -- --mode development --watch",
-    "build:core": "webpack --config webpack.config.core.js --mode production",
-    "dev:core": "npm run build:core -- --mode development --watch",
-    "build": "tsc && rm dist/*.js && cp src/*.d.ts dist/ && npm run build:user"
-  },
-  "dependencies": {
-    "debug": "^4.3.1",
-    "dompurify": "^2.2.7",
-    "eventemitter3": "^4.0.7",
-    "path": "^0.12.7",
-    "postmate": "^1.5.2",
-    "snake-case": "^3.0.4"
-  },
-  "devDependencies": {
-    "@types/debug": "^4.1.5",
-    "@types/dompurify": "^2.2.1",
-    "@types/lodash-es": "^4.17.4",
-    "@types/postmate": "^1.5.1",
-    "ts-loader": "^8.0.17",
-    "typescript": "^4.2.2",
-    "webpack": "^5.24.3",
-    "webpack-bundle-analyzer": "^4.4.0",
-    "webpack-cli": "^4.5.0"
-  }
-}

+ 0 - 286
libs/src/LSPlugin.caller.ts

@@ -1,286 +0,0 @@
-import Postmate from 'postmate'
-import EventEmitter from 'eventemitter3'
-import { PluginLocal } from './LSPlugin.core'
-import Debug from 'debug'
-import { deferred } from './helpers'
-import { LSPluginShadowFrame } from './LSPlugin.shadow'
-
-const debug = Debug('LSPlugin:caller')
-
-type DeferredActor = ReturnType<typeof deferred>
-
-export const LSPMSG = '#lspmsg#'
-export const LSPMSG_SETTINGS = '#lspmsg#settings#'
-export const LSPMSG_SYNC = '#lspmsg#reply#'
-export const LSPMSG_READY = '#lspmsg#ready#'
-export const LSPMSGFn = (id: string) => `${LSPMSG}${id}`
-
-/**
- * Call between core and user
- */
-class LSPluginCaller extends EventEmitter {
-  private _connected: boolean = false
-
-  private _parent?: Postmate.ParentAPI
-  private _child?: Postmate.ChildAPI
-
-  private _shadow?: LSPluginShadowFrame
-
-  private _status?: 'pending' | 'timeout'
-  private _userModel: any = {}
-
-  private _call?: (type: string, payload: any, actor?: DeferredActor) => Promise<any>
-  private _callUserModel?: (type: string, payload: any) => Promise<any>
-
-  constructor (
-    private _pluginLocal: PluginLocal | null
-  ) {
-    super()
-  }
-
-  async connectToChild () {
-    if (this._connected) return
-
-    const { shadow } = this._pluginLocal!
-
-    if (shadow) {
-      await this._setupShadowSandbox()
-    } else {
-      await this._setupIframeSandbox()
-    }
-  }
-
-  async connectToParent (userModel = {}) {
-    if (this._connected) return
-
-    const caller = this
-    const isShadowMode = this._pluginLocal != null
-
-    let syncGCTimer: any = 0
-    let syncTag = 0
-    const syncActors = new Map<number, DeferredActor>()
-    const readyDeferred = deferred()
-
-    const model: any = this._extendUserModel({
-      [LSPMSG_READY]: async () => {
-        await readyDeferred.resolve()
-      },
-
-      [LSPMSG_SETTINGS]: async ({ type, payload }) => {
-        caller.emit('settings:changed', payload)
-      },
-
-      [LSPMSG]: async ({ ns, type, payload }: any) => {
-        debug(`[call from host #${this._pluginLocal?.id}]`, ns, type, payload)
-
-        if (ns && ns.startsWith('hook')) {
-          caller.emit(`${ns}:${type}`, payload)
-          return
-        }
-
-        caller.emit(type, payload)
-      },
-
-      [LSPMSG_SYNC]: ({ _sync, result }: any) => {
-        debug(`sync reply #${_sync}`, result)
-        if (syncActors.has(_sync)) {
-          // TODO: handle exception
-          syncActors.get(_sync)?.resolve(result)
-          syncActors.delete(_sync)
-        }
-      },
-
-      ...userModel
-    })
-
-    if (isShadowMode) {
-      await readyDeferred.promise
-      return JSON.parse(JSON.stringify(this._pluginLocal?.toJSON()))
-    }
-
-    const handshake = new Postmate.Model(model)
-
-    this._status = 'pending'
-
-    await handshake.then(refParent => {
-      this._child = refParent
-      this._connected = true
-
-      this._call = async (type, payload = {}, actor) => {
-        if (actor) {
-          const tag = ++syncTag
-          syncActors.set(tag, actor)
-          payload._sync = tag
-
-          actor.setTag(`async call #${tag}`)
-          debug('async call #', tag)
-        }
-
-        refParent.emit(LSPMSGFn(model.baseInfo.id), { type, payload })
-
-        return actor?.promise as Promise<any>
-      }
-
-      this._callUserModel = async (type, payload) => {
-        try {
-          model[type](payload)
-        } catch (e) {
-          debug(`model method #${type} not existed`)
-        }
-      }
-
-      // actors GC
-      syncGCTimer = setInterval(() => {
-        if (syncActors.size > 100) {
-          for (const [k, v] of syncActors) {
-            if (v.settled) {
-              syncActors.delete(k)
-            }
-          }
-        }
-      }, 1000 * 60 * 30)
-    }).finally(() => {
-      this._status = undefined
-    })
-
-    // TODO: timeout
-    await readyDeferred.promise
-
-    return model.baseInfo
-  }
-
-  async call (type: any, payload: any = {}) {
-    // TODO: ?
-    this.emit(type, payload)
-    return this._call?.call(this, type, payload)
-  }
-
-  async callAsync (type: any, payload: any = {}) {
-    const actor = deferred(1000 * 10)
-    return this._call?.call(this, type, payload, actor)
-  }
-
-  async callUserModel (type: string, payload: any = {}) {
-    return this._callUserModel?.call(this, type, payload)
-  }
-
-  async _setupIframeSandbox () {
-    const pl = this._pluginLocal!
-
-    const handshake = new Postmate({
-      container: document.body,
-      url: pl.options.entry!,
-      classListArray: ['lsp-iframe-sandbox'],
-      model: { baseInfo: JSON.parse(JSON.stringify(pl.toJSON())) }
-    })
-
-    this._status = 'pending'
-
-    // timeout for handshake
-    let timer
-
-    return new Promise((resolve, reject) => {
-      timer = setTimeout(() => {
-        reject(new Error(`handshake Timeout`))
-      }, 3 * 1000) // 3secs
-
-      handshake.then(refChild => {
-        this._parent = refChild
-        this._connected = true
-        this.emit('connected')
-
-        refChild.frame.setAttribute('id', pl.id)
-        refChild.on(LSPMSGFn(pl.id), ({ type, payload }: any) => {
-          debug(`[call from plugin] `, type, payload)
-
-          this._pluginLocal?.emit(type, payload || {})
-        })
-
-        this._call = async (...args: any) => {
-          // parent all will get message
-          await refChild.call(LSPMSGFn(pl.id), { type: args[0], payload: args[1] || {} })
-        }
-
-        this._callUserModel = async (...args: any) => {
-          await refChild.call(args[0], args[1] || {})
-        }
-
-        resolve(null)
-      }).catch(e => {
-        reject(e)
-      }).finally(() => {
-        clearTimeout(timer)
-      })
-    }).catch(e => {
-      debug('iframe sandbox error', e)
-      throw e
-    }).finally(() => {
-      this._status = undefined
-    })
-  }
-
-  async _setupShadowSandbox () {
-    const pl = this._pluginLocal!
-    const shadow = this._shadow = new LSPluginShadowFrame(pl)
-
-    try {
-      this._status = 'pending'
-
-      await shadow.load()
-
-      this._connected = true
-      this.emit('connected')
-
-      this._call = async (type, payload = {}, actor) => {
-        actor && (payload.actor = actor)
-
-        // TODO: support sync call
-        // @ts-ignore Call in same thread
-        this._pluginLocal?.emit(type, payload)
-
-        return actor?.promise
-      }
-
-      this._callUserModel = async (...args: any) => {
-        const type = args[0]
-        const payload = args[1] || {}
-        const fn = this._userModel[type]
-
-        if (typeof fn === 'function') {
-          await fn.call(null, payload)
-        }
-      }
-    } catch (e) {
-      debug('shadow sandbox error', e)
-      throw e
-    } finally {
-      this._status = undefined
-    }
-  }
-
-  _extendUserModel (model: any) {
-    return Object.assign(this._userModel, model)
-  }
-
-  _getSandboxIframeContainer () {
-    return this._parent?.frame
-  }
-
-  _getSandboxShadowContainer () {
-    return this._shadow?.frame
-  }
-
-  async destroy () {
-    if (this._parent) {
-      await this._parent.destroy()
-    }
-
-    if (this._shadow) {
-      this._shadow.destroy()
-    }
-  }
-}
-
-export {
-  LSPluginCaller
-}

+ 0 - 1001
libs/src/LSPlugin.core.ts

@@ -1,1001 +0,0 @@
-import EventEmitter from 'eventemitter3'
-import {
-  deepMerge,
-  setupInjectedStyle,
-  genID,
-  setupInjectedTheme,
-  setupInjectedUI,
-  deferred,
-  invokeHostExportedApi,
-  isObject, withFileProtocol
-} from './helpers'
-import Debug from 'debug'
-import { LSPluginCaller, LSPMSG_READY, LSPMSG_SYNC, LSPMSG, LSPMSG_SETTINGS } from './LSPlugin.caller'
-import {
-  ILSPluginThemeManager,
-  LSPluginPkgConfig,
-  StyleOptions,
-  StyleString,
-  ThemeOptions,
-  UIOptions
-} from './LSPlugin'
-import { snakeCase } from 'snake-case'
-import DOMPurify from 'dompurify'
-import * as path from 'path'
-
-const debug = Debug('LSPlugin:core')
-
-declare global {
-  interface Window {
-    LSPluginCore: LSPluginCore
-  }
-}
-
-type DeferredActor = ReturnType<typeof deferred>
-type LSPluginCoreOptions = {
-  localUserConfigRoot: string
-}
-
-/**
- * User settings
- */
-class PluginSettings extends EventEmitter<'change'> {
-  private _settings: Record<string, any> = {
-    disabled: false
-  }
-
-  constructor (private _userPluginSettings: any) {
-    super()
-
-    Object.assign(this._settings, _userPluginSettings)
-  }
-
-  get<T = any> (k: string): T {
-    return this._settings[k]
-  }
-
-  set (k: string | Record<string, any>, v?: any) {
-    const o = deepMerge({}, this._settings)
-
-    if (typeof k === 'string') {
-      if (this._settings[k] == v) return
-      this._settings[k] = v
-    } else if (isObject(k)) {
-      deepMerge(this._settings, k)
-    } else {
-      return
-    }
-
-    this.emit('change',
-      Object.assign({}, this._settings), o)
-  }
-
-  toJSON () {
-    return this._settings
-  }
-}
-
-class PluginLogger extends EventEmitter<'change'> {
-  private _logs: Array<[type: string, payload: any]> = []
-
-  constructor (private _tag: string) {
-    super()
-  }
-
-  write (type: string, payload: any[]) {
-    let msg = payload.reduce((ac, it) => {
-      if (it && it instanceof Error) {
-        ac += `${it.message} ${it.stack}`
-      } else {
-        ac += it.toString()
-      }
-      return ac
-    }, `[${this._tag}][${new Date().toLocaleTimeString()}] `)
-
-    this._logs.push([type, msg])
-    this.emit('change')
-  }
-
-  clear () {
-    this._logs = []
-    this.emit('change')
-  }
-
-  info (...args: any[]) {
-    this.write('INFO', args)
-  }
-
-  error (...args: any[]) {
-    this.write('ERROR', args)
-  }
-
-  warn (...args: any[]) {
-    this.write('WARN', args)
-  }
-
-  toJSON () {
-    return this._logs
-  }
-}
-
-type UserPreferences = {
-  theme: ThemeOptions
-  externals: Array<string> // external plugin locations
-
-  [key: string]: any
-}
-
-type PluginLocalOptions = {
-  key?: string // Unique from Logseq Plugin Store
-  entry: string // Plugin main file
-  url: string // Plugin package fs location
-  name: string
-  version: string
-  mode: 'shadow' | 'iframe'
-  settings?: PluginSettings
-  logger?: PluginLogger
-
-  [key: string]: any
-}
-
-type PluginLocalUrl = Pick<PluginLocalOptions, 'url'> & { [key: string]: any }
-type RegisterPluginOpts = PluginLocalOptions | PluginLocalUrl
-
-type PluginLocalIdentity = string
-
-enum PluginLocalLoadStatus {
-  LOADING = 'loading',
-  UNLOADING = 'unloading',
-  LOADED = 'loaded',
-  UNLOADED = 'unload',
-  ERROR = 'error'
-}
-
-function initUserSettingsHandlers (pluginLocal: PluginLocal) {
-  const _ = (label: string): any => `settings:${label}`
-
-  pluginLocal.on(_('update'), (attrs) => {
-    if (!attrs) return
-    pluginLocal.settings?.set(attrs)
-  })
-}
-
-function initMainUIHandlers (pluginLocal: PluginLocal) {
-  const _ = (label: string): any => `main-ui:${label}`
-
-  pluginLocal.on(_('visible'), ({ visible, toggle }) => {
-    const el = pluginLocal.getMainUI()
-    el?.classList[toggle ? 'toggle' : (visible ? 'add' : 'remove')]('visible')
-    // pluginLocal.caller!.callUserModel(LSPMSG, { type: _('visible'), payload: visible })
-    // auto focus frame
-    if (!pluginLocal.shadow && el) {
-      (el as HTMLIFrameElement).contentWindow?.focus()
-    }
-  })
-
-  pluginLocal.on(_('attrs'), (attrs: Record<string, any>) => {
-    const el = pluginLocal.getMainUI()
-    Object.entries(attrs).forEach(([k, v]) => {
-      el?.setAttribute(k, v)
-    })
-  })
-
-  pluginLocal.on(_('style'), (style: Record<string, any>) => {
-    const el = pluginLocal.getMainUI()
-    Object.entries(style).forEach(([k, v]) => {
-      el!.style[k] = v
-    })
-  })
-}
-
-function initProviderHandlers (pluginLocal: PluginLocal) {
-  let _ = (label: string): any => `provider:${label}`
-  let themed = false
-
-  pluginLocal.on(_('theme'), (theme: ThemeOptions) => {
-    pluginLocal.themeMgr.registerTheme(
-      pluginLocal.id,
-      theme
-    )
-
-    if (!themed) {
-      pluginLocal._dispose(() => {
-        pluginLocal.themeMgr.unregisterTheme(pluginLocal.id)
-      })
-
-      themed = true
-    }
-  })
-
-  pluginLocal.on(_('style'), (style: StyleString | StyleOptions) => {
-    let key: string | undefined
-
-    if (typeof style !== 'string') {
-      key = style.key
-      style = style.style
-    }
-
-    if (!style || !style.trim()) return
-
-    pluginLocal._dispose(
-      setupInjectedStyle(style, {
-        'data-injected-style': key ? `${key}-${pluginLocal.id}` : '',
-        'data-ref': pluginLocal.id
-      })
-    )
-  })
-
-  pluginLocal.on(_('ui'), (ui: UIOptions) => {
-    pluginLocal._onHostMounted(() => {
-      // safe template
-      ui.template = DOMPurify.sanitize(ui.template)
-
-      pluginLocal._dispose(
-        setupInjectedUI.call(pluginLocal,
-          ui, {
-            'data-ref': pluginLocal.id
-          })
-      )
-    })
-  })
-}
-
-function initApiProxyHandlers (pluginLocal: PluginLocal) {
-  let _ = (label: string): any => `api:${label}`
-
-  pluginLocal.on(_('call'), (payload) => {
-    const rt = invokeHostExportedApi(payload.method, ...payload.args)
-    const { _sync } = payload
-
-    if (pluginLocal.shadow) {
-      if (payload.actor) {
-        payload.actor.resolve(rt)
-      }
-      return
-    }
-
-    if (_sync != null) {
-      const reply = (result: any) => {
-        pluginLocal.caller?.callUserModel(LSPMSG_SYNC, {
-          result, _sync
-        })
-      }
-
-      Promise.resolve(rt).then(reply, reply)
-    }
-  })
-}
-
-class IllegalPluginPackageError extends Error {
-  constructor (message: string) {
-    super(message)
-    this.name = IllegalPluginPackageError.name
-  }
-}
-
-class ExistedImportedPluginPackageError extends Error {
-  constructor (message: string) {
-    super(message)
-    this.name = ExistedImportedPluginPackageError.name
-  }
-}
-
-/**
- * Host plugin for local
- */
-class PluginLocal
-  extends EventEmitter<'loaded' | 'unloaded' | 'beforeunload' | 'error'> {
-
-  private _disposes: Array<() => Promise<any>> = []
-  private _id: PluginLocalIdentity
-  private _status: PluginLocalLoadStatus = PluginLocalLoadStatus.UNLOADED
-  private _loadErr?: Error
-  private _localRoot?: string
-  private _userSettingsFile?: string
-  private _caller?: LSPluginCaller
-
-  /**
-   * @param _options
-   * @param _themeMgr
-   * @param _ctx
-   */
-  constructor (
-    private _options: PluginLocalOptions,
-    private _themeMgr: ILSPluginThemeManager,
-    private _ctx: LSPluginCore
-  ) {
-    super()
-
-    this._id = _options.key || genID()
-
-    initUserSettingsHandlers(this)
-    initMainUIHandlers(this)
-    initProviderHandlers(this)
-    initApiProxyHandlers(this)
-  }
-
-  async _setupUserSettings () {
-    const { _options } = this
-    const key = _options.name.replace(/[^a-z0-9]/gi, '_').toLowerCase() + '_' + this.id
-    const logger = _options.logger = new PluginLogger('Loader')
-
-    try {
-      const [userSettingsFilePath, userSettings] = await invokeHostExportedApi('load_plugin_user_settings', key)
-      this._userSettingsFile = userSettingsFilePath
-
-      const settings = _options.settings = new PluginSettings(userSettings)
-
-      // observe settings
-      settings.on('change', (a, b) => {
-        debug('linked settings change', a)
-
-        if (!a.disabled && b.disabled) {
-          // Enable plugin
-          this.load()
-        }
-
-        if (a.disabled && !b.disabled) {
-          // Disable plugin
-          this.unload()
-        }
-
-        if (a) {
-          invokeHostExportedApi(`save_plugin_user_settings`, key, a)
-        }
-      })
-    } catch (e) {
-      debug('[load plugin user settings Error]', e)
-      logger?.error(e)
-    }
-  }
-
-  getMainUI (): HTMLElement | undefined {
-    if (this.shadow) {
-      return this.caller?._getSandboxShadowContainer()
-    }
-
-    return this.caller?._getSandboxIframeContainer()
-  }
-
-  async _preparePackageConfigs () {
-    const { url } = this._options
-    let pkg: any
-
-    try {
-      if (!url) {
-        throw new Error('Can not resolve package config location')
-      }
-
-      debug('prepare package root', url)
-
-      pkg = await invokeHostExportedApi('load_plugin_config', url)
-
-      if (!pkg || (pkg = JSON.parse(pkg), !pkg)) {
-        throw new Error(`Parse package config error #${url}/package.json`)
-      }
-    } catch (e) {
-      throw new IllegalPluginPackageError(e.message)
-    }
-
-    // Pick legal attrs
-    ['name', 'author', 'version', 'description'].forEach(k => {
-      this._options[k] = pkg[k]
-    })
-
-    // TODO: How with local protocol
-    const localRoot = this._localRoot = url
-    const logseq: Partial<LSPluginPkgConfig> = pkg.logseq || {}
-    const makeFullUrl = (loc, useFileProtocol = false) => {
-      if (!loc) return
-      const reg = /^(http|file|assets)/
-      if (!reg.test(loc)) {
-        const url = path.join(localRoot, loc)
-        loc = reg.test(url) ? url : ('file://' + url)
-      }
-      return useFileProtocol ? loc : loc.replace('file:', 'assets:')
-    }
-    const validateMain = (main) => main && /\.(js|html)$/.test(main)
-
-    // Entry from main
-    if (validateMain(pkg.main)) {
-      this._options.entry = makeFullUrl(pkg.main, true)
-
-      if (logseq.mode) {
-        this._options.mode = logseq.mode
-      }
-    }
-
-    const icon = logseq.icon || pkg.icon
-
-    if (icon) {
-      this._options.icon = makeFullUrl(icon)
-    }
-
-    // TODO: strategy for Logseq plugins center
-    if (logseq.id) {
-      this._id = logseq.id
-    } else {
-      logseq.id = this.id
-      try {
-        await invokeHostExportedApi('save_plugin_config', url, { ...pkg, logseq })
-      } catch (e) {
-        debug('[save plugin ID Error] ', e)
-      }
-    }
-
-    // Validate id
-    const { registeredPlugins, isRegistering } = this._ctx
-    if (isRegistering && registeredPlugins.has(logseq.id)) {
-      throw new ExistedImportedPluginPackageError('prepare package Error')
-    }
-
-    return async () => {
-      try {
-        // 0. Install Themes
-        let themes = logseq.themes
-
-        if (themes) {
-          await this._loadConfigThemes(
-            Array.isArray(themes) ? themes : [themes]
-          )
-        }
-      } catch (e) {
-        debug('[prepare package effect Error]', e)
-      }
-    }
-  }
-
-  async _tryToNormalizeEntry () {
-    let { entry, settings } = this.options
-    let devEntry = settings?.get('_devEntry')
-
-    if (devEntry) {
-      this._options.entry = devEntry
-      return
-    }
-
-    if (!entry.endsWith('.js')) return
-
-    let sdkPath = await invokeHostExportedApi('_callApplication', 'getAppPath')
-    let entryPath = await invokeHostExportedApi(
-      'write_user_tmp_file',
-      `${this._id}_index.html`,
-      `<!doctype html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8">
-    <title>logseq plugin entry</title>
-    <script src="${sdkPath}/js/lsplugin.user.js"></script>
-  </head>
-  <body>
-  <div id="app"></div>
-  <script src="${entry}"></script>
-  </body>
-</html>`)
-
-    this._options.entry = withFileProtocol(entryPath)
-  }
-
-  async _loadConfigThemes (themes: Array<ThemeOptions>) {
-    themes.forEach((options) => {
-      if (!options.url) return
-
-      if (!options.url.startsWith('http') && this._localRoot) {
-        options.url = path.join(this._localRoot, options.url)
-        // file:// for native
-        if (!options.url.startsWith('file:')) {
-          options.url = 'assets://' + options.url
-        }
-      }
-
-      // @ts-ignore
-      this.emit('provider:theme', options)
-    })
-  }
-
-  async load (readyIndicator?: DeferredActor) {
-    if (this.pending) {
-      return
-    }
-
-    this._status = PluginLocalLoadStatus.LOADING
-    this._loadErr = undefined
-
-    try {
-      let installPackageThemes: () => Promise<void> = () => Promise.resolve()
-
-      if (!this.options.entry) { // Themes package no entry field
-        installPackageThemes = await this._preparePackageConfigs()
-      }
-
-      if (!this.settings) {
-        await this._setupUserSettings()
-      }
-
-      if (!this.disabled) {
-        await installPackageThemes.call(null)
-      }
-
-      if (this.disabled || !this.options.entry) {
-        return
-      }
-
-      await this._tryToNormalizeEntry()
-
-      this._caller = new LSPluginCaller(this)
-      await this._caller.connectToChild()
-
-      const readyFn = () => {
-        this._caller?.callUserModel(LSPMSG_READY)
-      }
-
-      if (readyIndicator) {
-        readyIndicator.promise.then(readyFn)
-      } else {
-        readyFn()
-      }
-
-      this._disposes.push(async () => {
-        await this._caller?.destroy()
-      })
-    } catch (e) {
-      debug('[Load Plugin Error] ', e)
-      this.logger?.error(e)
-
-      this._status = PluginLocalLoadStatus.ERROR
-      this._loadErr = e
-    } finally {
-      if (!this._loadErr) {
-        this._status = PluginLocalLoadStatus.LOADED
-      }
-    }
-  }
-
-  async reload () {
-    debug('TODO: reload plugin', this.id)
-  }
-
-  /**
-   * @param unregister If true delete plugin files
-   */
-  async unload (unregister: boolean = false) {
-    if (this.pending) {
-      return
-    }
-
-    if (unregister) {
-      await this.unload()
-
-      if (this.isInstalledInUserRoot) {
-        debug('TODO: remove plugin local files from user home root :)')
-      }
-
-      return
-    }
-
-    try {
-      this._status = PluginLocalLoadStatus.UNLOADING
-
-      const eventBeforeUnload = {}
-
-      // sync call
-      try {
-        this.emit('beforeunload', eventBeforeUnload)
-      } catch (e) {
-        console.error('[beforeunload Error]', e)
-      }
-
-      await this.dispose()
-
-      this.emit('unloaded')
-    } catch (e) {
-      debug('[plugin unload Error]', e)
-    } finally {
-      this._status = PluginLocalLoadStatus.UNLOADED
-    }
-  }
-
-  private async dispose () {
-    for (const fn of this._disposes) {
-      try {
-        fn && (await fn())
-      } catch (e) {
-        console.error(this.debugTag, 'dispose Error', e)
-      }
-    }
-
-    // clear
-    this._disposes = []
-  }
-
-  _dispose (fn: any) {
-    if (!fn) return
-    this._disposes.push(fn)
-  }
-
-  _onHostMounted (callback: () => void) {
-    const actor = this._ctx.hostMountedActor
-
-    if (!actor || actor.settled) {
-      callback()
-    } else {
-      actor?.promise.then(callback)
-    }
-  }
-
-  get isInstalledInUserRoot () {
-    const userRoot = this._ctx.options.localUserConfigRoot
-    const plugRoot = this._localRoot
-    return userRoot && plugRoot && plugRoot.startsWith(userRoot)
-  }
-
-  get loaded () {
-    return this._status === PluginLocalLoadStatus.LOADED
-  }
-
-  get pending () {
-    return [PluginLocalLoadStatus.LOADING, PluginLocalLoadStatus.UNLOADING]
-      .includes(this._status)
-  }
-
-  get status (): PluginLocalLoadStatus {
-    return this._status
-  }
-
-  get settings () {
-    return this.options.settings
-  }
-
-  get logger () {
-    return this.options.logger
-  }
-
-  get disabled () {
-    return this.settings?.get('disabled')
-  }
-
-  get caller () {
-    return this._caller
-  }
-
-  get id (): string {
-    return this._id
-  }
-
-  get shadow (): boolean {
-    return this.options.mode === 'shadow'
-  }
-
-  get options (): PluginLocalOptions {
-    return this._options
-  }
-
-  get themeMgr (): ILSPluginThemeManager {
-    return this._themeMgr
-  }
-
-  get debugTag () {
-    return `[${this._options?.name} #${this._id}]`
-  }
-
-  get localRoot (): string {
-    return this._localRoot || this._options.url
-  }
-
-  get loadErr (): Error | undefined {
-    return this._loadErr
-  }
-
-  get userSettingsFile (): string | undefined {
-    return this._userSettingsFile
-  }
-
-  toJSON () {
-    const json = { ...this.options } as any
-    json.id = this.id
-    json.err = this.loadErr
-    json.usf = this.userSettingsFile
-    return json
-  }
-}
-
-/**
- * Host plugin core
- */
-class LSPluginCore
-  extends EventEmitter<'beforeenable' | 'enabled' | 'beforedisable' | 'disabled' | 'registered' | 'error' | 'unregistered' |
-    'theme-changed' | 'theme-selected' | 'settings-changed'>
-  implements ILSPluginThemeManager {
-
-  private _isRegistering = false
-  private _readyIndicator?: DeferredActor
-  private _hostMountedActor: DeferredActor = deferred()
-  private _userPreferences: Partial<UserPreferences> = {}
-  private _registeredThemes = new Map<PluginLocalIdentity, Array<ThemeOptions>>()
-  private _registeredPlugins = new Map<PluginLocalIdentity, PluginLocal>()
-
-  /**
-   * @param _options
-   */
-  constructor (private _options: Partial<LSPluginCoreOptions>) {
-    super()
-  }
-
-  async loadUserPreferences () {
-    try {
-      const settings = await invokeHostExportedApi(`load_user_preferences`)
-
-      if (settings) {
-        Object.assign(this._userPreferences, settings)
-      }
-    } catch (e) {
-      debug('[load user preferences Error]', e)
-    }
-  }
-
-  async saveUserPreferences (settings: Partial<UserPreferences>) {
-    try {
-      if (settings) {
-        Object.assign(this._userPreferences, settings)
-      }
-
-      await invokeHostExportedApi(`save_user_preferences`, this._userPreferences)
-    } catch (e) {
-      debug('[save user preferences Error]', e)
-    }
-  }
-
-  async activateUserPreferences () {
-    const { theme } = this._userPreferences
-
-    // 0. theme
-    if (theme) {
-      await this.selectTheme(theme, false)
-    }
-  }
-
-  /**
-   * @param plugins
-   * @param initial
-   */
-  async register (
-    plugins: Array<RegisterPluginOpts> | RegisterPluginOpts,
-    initial = false
-  ) {
-    if (!Array.isArray(plugins)) {
-      await this.register([plugins])
-      return
-    }
-
-    try {
-      this._isRegistering = true
-
-      const userConfigRoot = this._options.localUserConfigRoot
-      const readyIndicator = this._readyIndicator = deferred()
-
-      await this.loadUserPreferences()
-
-      const externals = new Set(this._userPreferences.externals || [])
-
-      if (initial) {
-        plugins = plugins.concat([...externals].filter(url => {
-          return !plugins.length || (plugins as RegisterPluginOpts[]).every((p) => !p.entry && (p.url !== url))
-        }).map(url => ({ url })))
-      }
-
-      for (const pluginOptions of plugins) {
-        const { url } = pluginOptions as PluginLocalOptions
-        const pluginLocal = new PluginLocal(pluginOptions as PluginLocalOptions, this, this)
-
-        const timeLabel = `Load plugin #${pluginLocal.id}`
-        console.time(timeLabel)
-
-        await pluginLocal.load(readyIndicator)
-
-        const { loadErr } = pluginLocal
-
-        if (loadErr) {
-          debug(`Failed load plugin #`, pluginOptions)
-
-          this.emit('error', loadErr)
-
-          if (
-            loadErr instanceof IllegalPluginPackageError ||
-            loadErr instanceof ExistedImportedPluginPackageError) {
-            // TODO: notify global log system?
-            continue
-          }
-        }
-
-        console.timeEnd(timeLabel)
-
-        pluginLocal.settings?.on('change', (a) => {
-          this.emit('settings-changed', pluginLocal.id, a)
-          pluginLocal.caller?.callUserModel(LSPMSG_SETTINGS, { payload: a })
-        })
-
-        this._registeredPlugins.set(pluginLocal.id, pluginLocal)
-        this.emit('registered', pluginLocal)
-
-        // external plugins
-        if (!pluginLocal.isInstalledInUserRoot) {
-          externals.add(url)
-        }
-      }
-
-      await this.saveUserPreferences({ externals: Array.from(externals) })
-      await this.activateUserPreferences()
-
-      readyIndicator.resolve('ready')
-    } catch (e) {
-      console.error(e)
-    } finally {
-      this._isRegistering = false
-    }
-  }
-
-  async reload (plugins: Array<PluginLocalIdentity> | PluginLocalIdentity) {
-    if (!Array.isArray(plugins)) {
-      await this.reload([plugins])
-      return
-    }
-
-    for (const identity of plugins) {
-      const p = this.ensurePlugin(identity)
-      await p.reload()
-    }
-  }
-
-  async unregister (plugins: Array<PluginLocalIdentity> | PluginLocalIdentity) {
-    if (!Array.isArray(plugins)) {
-      await this.unregister([plugins])
-      return
-    }
-
-    const unregisteredExternals: Array<string> = []
-
-    for (const identity of plugins) {
-      const p = this.ensurePlugin(identity)
-
-      if (!p.isInstalledInUserRoot) {
-        unregisteredExternals.push(p.options.url)
-      }
-
-      await p.unload(true)
-
-      this._registeredPlugins.delete(identity)
-      this.emit('unregistered', identity)
-    }
-
-    let externals = this._userPreferences.externals || []
-    if (externals.length && unregisteredExternals.length) {
-      await this.saveUserPreferences({
-        externals: externals.filter((it) => {
-          return !unregisteredExternals.includes(it)
-        })
-      })
-    }
-  }
-
-  async enable (plugin: PluginLocalIdentity) {
-    const p = this.ensurePlugin(plugin)
-    if (p.pending) return
-
-    this.emit('beforeenable')
-    p.settings?.set('disabled', false)
-    // this.emit('enabled', p)
-  }
-
-  async disable (plugin: PluginLocalIdentity) {
-    const p = this.ensurePlugin(plugin)
-    if (p.pending) return
-
-    this.emit('beforedisable')
-    p.settings?.set('disabled', true)
-    // this.emit('disabled', p)
-  }
-
-  async _hook (ns: string, type: string, payload?: any, pid?: string) {
-    for (const [_, p] of this._registeredPlugins) {
-      if (!pid || pid === p.id) {
-        p.caller?.callUserModel(LSPMSG, {
-          ns, type: snakeCase(type), payload
-        })
-      }
-    }
-  }
-
-  hookApp (type: string, payload?: any, pid?: string) {
-    this._hook(`hook:app`, type, payload, pid)
-  }
-
-  hookEditor (type: string, payload?: any, pid?: string) {
-    this._hook(`hook:editor`, type, payload, pid)
-  }
-
-  _execDirective (tag: string, ...params: any[]) {
-
-  }
-
-  ensurePlugin (plugin: PluginLocalIdentity | PluginLocal) {
-    if (plugin instanceof PluginLocal) {
-      return plugin
-    }
-
-    const p = this._registeredPlugins.get(plugin)
-
-    if (!p) {
-      throw new Error(`plugin #${plugin} not existed.`)
-    }
-
-    return p
-  }
-
-  hostMounted () {
-    this._hostMountedActor.resolve()
-  }
-
-  get registeredPlugins (): Map<PluginLocalIdentity, PluginLocal> {
-    return this._registeredPlugins
-  }
-
-  get options () {
-    return this._options
-  }
-
-  get readyIndicator (): DeferredActor | undefined {
-    return this._readyIndicator
-  }
-
-  get hostMountedActor (): DeferredActor {
-    return this._hostMountedActor
-  }
-
-  get isRegistering (): boolean {
-    return this._isRegistering
-  }
-
-  get themes (): Map<PluginLocalIdentity, Array<ThemeOptions>> {
-    return this._registeredThemes
-  }
-
-  async registerTheme (id: PluginLocalIdentity, opt: ThemeOptions): Promise<void> {
-    debug('registered Theme #', id, opt)
-
-    if (!id) return
-    let themes: Array<ThemeOptions> = this._registeredThemes.get(id)!
-    if (!themes) {
-      this._registeredThemes.set(id, themes = [])
-    }
-
-    themes.push(opt)
-    this.emit('theme-changed', this.themes, { id, ...opt })
-  }
-
-  async selectTheme (opt?: ThemeOptions, effect = true): Promise<void> {
-    setupInjectedTheme(opt?.url)
-    this.emit('theme-selected', opt)
-    effect && this.saveUserPreferences({ theme: opt })
-  }
-
-  async unregisterTheme (id: PluginLocalIdentity): Promise<void> {
-    debug('unregistered Theme #', id)
-
-    if (!this._registeredThemes.has(id)) return
-    this._registeredThemes.delete(id)
-    this.emit('theme-changed', this.themes, { id })
-  }
-}
-
-function setupPluginCore (options: any) {
-  const pluginCore = new LSPluginCore(options)
-
-  debug('=== 🔗 Setup Logseq Plugin System 🔗 ===')
-
-  window.LSPluginCore = pluginCore
-}
-
-export {
-  PluginLocal,
-  setupPluginCore
-}

+ 0 - 196
libs/src/LSPlugin.d.ts

@@ -1,196 +0,0 @@
-import EventEmitter from 'eventemitter3'
-import { LSPluginCaller } from './LSPlugin.caller'
-import { LSPluginUser } from './LSPlugin.user'
-
-type PluginLocalIdentity = string
-
-type ThemeOptions = {
-  name: string
-  url: string
-  description?: string
-  mode?: 'dark' | 'light'
-
-  [key: string]: any
-}
-
-type StyleString = string
-type StyleOptions = {
-  key?: string
-  style: StyleString
-}
-
-type UIBaseOptions = {
-  key?: string
-  replace?: boolean
-  template: string
-}
-
-type UIPathIdentity = {
-  path: string // dom selector
-}
-
-type UISlotIdentity = {
-  slot: string // slot key
-}
-
-type UISlotOptions = UIBaseOptions & UISlotIdentity
-type UIPathOptions = UIBaseOptions & UIPathIdentity
-type UIOptions = UIPathOptions & UISlotOptions
-
-interface LSPluginPkgConfig {
-  id: PluginLocalIdentity
-  mode: 'shadow' | 'iframe'
-  themes: Array<ThemeOptions>
-  icon: string
-}
-
-interface LSPluginBaseInfo {
-  id: string // should be unique
-  mode: 'shadow' | 'iframe'
-
-  settings: {
-    disabled: boolean
-    [key: string]: any
-  },
-
-  [key: string]: any
-}
-
-type IHookEvent = {
-  [key: string]: any
-}
-
-type IUserHook = (callback: (e: IHookEvent) => void) => void
-type IUserSlotHook = (callback: (e: IHookEvent & UISlotIdentity) => void) => void
-
-interface BlockEntity {
-  uuid: string
-  content: string
-
-  [key: string]: any
-}
-
-type BlockIdentity = 'string' | Pick<BlockEntity, 'uuid'>
-type SlashCommandActionTag = 'editor/input' | 'editor/hook' | 'editor/clear-current-slash'
-type SlashCommandAction = [SlashCommandActionTag, ...args: any]
-
-interface IAppProxy {
-  pushState: (k: string, params?: {}) => void
-  replaceState: (k: string, params?: {}) => void
-  getUserState: () => Promise<any>
-  showMsg: (content: string, status?: 'success' | 'warning' | string) => void
-  setZoomFactor: (factor: number) => void
-  onThemeModeChanged: IUserHook
-  onPageFileMounted: IUserSlotHook
-  onBlockRendererMounted: IUserSlotHook
-}
-
-interface IEditorProxy {
-  registerSlashCommand: (this: LSPluginUser, tag: string, actions: Array<SlashCommandAction>) => boolean
-  registerBlockContextMenu: (this: LSPluginUser, tag: string, action: () => void) => boolean
-
-  // TODO: Block related APIs
-  getCurrentBlock: () => Promise<BlockIdentity>
-  getCurrentPageBlocksTree: <T = any> () => Promise<T>
-
-  insertBlock: (srcBlock: BlockIdentity, content: string, opts: Partial<{ before: boolean, sibling: boolean, props: {} }>) => Promise<BlockIdentity>
-  updateBlock: (srcBlock: BlockIdentity, content: string, opts: Partial<{ props: {} }>) => Promise<void>
-  removeBlock: (srcBlock: BlockIdentity, opts: Partial<{ includeChildren: boolean }>) => Promise<void>
-  touchBlock: (srcBlock: BlockIdentity) => Promise<BlockIdentity>
-  moveBlock: (srcBlock: BlockIdentity, targetBlock: BlockIdentity, opts: Partial<{ before: boolean, sibling: boolean }>) => Promise<void>
-
-  updateBlockProperty: (block: BlockIdentity, key: string, value: any) => Promise<void>
-  removeBlockProperty: (block: BlockIdentity) => Promise<void>
-}
-
-interface IDBProxy {
-  datascriptQuery: <T = any>(query: string) => Promise<T>
-}
-
-interface ILSPluginThemeManager extends EventEmitter {
-  themes: Map<PluginLocalIdentity, Array<ThemeOptions>>
-
-  registerTheme (id: PluginLocalIdentity, opt: ThemeOptions): Promise<void>
-
-  unregisterTheme (id: PluginLocalIdentity): Promise<void>
-
-  selectTheme (opt?: ThemeOptions): Promise<void>
-}
-
-type LSPluginUserEvents = 'ui:visible:changed' | 'settings:changed'
-
-interface ILSPluginUser extends EventEmitter<LSPluginUserEvents> {
-  /**
-   * Indicate connected with host
-   */
-  connected: boolean
-
-  /**
-   * Duplex message caller
-   */
-  caller: LSPluginCaller
-
-  /**
-   * Most from packages
-   */
-  baseInfo: LSPluginBaseInfo
-
-  /**
-   * Plugin user settings
-   */
-  settings?: LSPluginBaseInfo['settings']
-
-  /**
-   * Ready for host connected
-   */
-  ready (model?: Record<string, any>): Promise<any>
-
-  ready (callback?: (e: any) => void | {}): Promise<any>
-
-  ready (model?: Record<string, any>, callback?: (e: any) => void | {}): Promise<any>
-
-  /**
-   * @param model
-   */
-  provideModel (model: Record<string, any>): this
-
-  /**
-   * @param theme options
-   */
-  provideTheme (theme: ThemeOptions): this
-
-  /**
-   * @param style
-   */
-  provideStyle (style: StyleString | StyleOptions): this
-
-  /**
-   * @param ui options
-   */
-  provideUI (ui: UIOptions): this
-
-  /**
-   * @param attrs
-   */
-  updateSettings (attrs: Record<string, any>): void
-
-  /**
-   * MainUI for index.html
-   * @param attrs
-   */
-  setMainUIAttrs (attrs: Record<string, any>): void
-
-  setMainUIInlineStyle (style: CSSStyleDeclaration): void
-
-  showMainUI (): void
-
-  hideMainUI (): void
-
-  toggleMainUI (): void
-
-  isMainUIVisible: boolean
-
-  App: IAppProxy
-  Editor: IEditorProxy
-  DB: IDBProxy
-}

+ 0 - 116
libs/src/LSPlugin.shadow.ts

@@ -1,116 +0,0 @@
-import EventEmitter from 'eventemitter3'
-import { PluginLocal } from './LSPlugin.core'
-import { LSPluginUser } from './LSPlugin.user'
-
-// @ts-ignore
-const { importHTML, createSandboxContainer } = window.QSandbox || {}
-
-function userFetch (url, opts) {
-  if (!url.startsWith('http')) {
-    url = url.replace('file://', '')
-    return new Promise(async (resolve, reject) => {
-      try {
-        const content = await window.apis.doAction(['readFile', url])
-        resolve({
-          text () {
-            return content
-          }
-        })
-      } catch (e) {
-        console.error(e)
-        reject(e)
-      }
-    })
-  }
-
-  return fetch(url, opts)
-}
-
-class LSPluginShadowFrame extends EventEmitter<'mounted' | 'unmounted'> {
-  private _frame?: HTMLElement
-  private _root?: ShadowRoot
-  private _loaded = false
-  private _unmountFns: Array<() => Promise<void>> = []
-
-  constructor (
-    private _pluginLocal: PluginLocal
-  ) {
-    super()
-
-    _pluginLocal._dispose(() => {
-      this._unmount()
-    })
-  }
-
-  async load () {
-    const { name, entry } = this._pluginLocal.options
-
-    if (this.loaded || !entry) return
-
-    const { template, execScripts } = await importHTML(entry, { fetch: userFetch })
-
-    this._mount(template, document.body)
-
-    const sandbox = createSandboxContainer(
-      name, {
-        elementGetter: () => this._root?.firstChild,
-      }
-    )
-
-    const global = sandbox.instance.proxy as any
-
-    global.__shadow_mode__ = true
-    global.LSPluginLocal = this._pluginLocal
-    global.LSPluginShadow = this
-    global.LSPluginUser = global.logseq = new LSPluginUser(
-      this._pluginLocal.toJSON() as any,
-      this._pluginLocal.caller!
-    )
-
-    // TODO: {mount, unmount}
-    const execResult: any = await execScripts(global, true)
-
-    this._unmountFns.push(execResult.unmount)
-
-    this._loaded = true
-  }
-
-  _mount (content: string, container: HTMLElement) {
-    const frame = this._frame = document.createElement('div')
-    frame.classList.add('lsp-shadow-sandbox')
-    frame.id = this._pluginLocal.id
-
-    this._root = frame.attachShadow({ mode: 'open' })
-    this._root.innerHTML = `<div>${content}</div>`
-
-    container.appendChild(frame)
-
-    this.emit('mounted')
-  }
-
-  _unmount () {
-    for (const fn of this._unmountFns) {
-      fn && fn.call(null)
-    }
-  }
-
-  destroy () {
-    this.frame?.parentNode?.removeChild(this.frame)
-  }
-
-  get loaded (): boolean {
-    return this._loaded
-  }
-
-  get document () {
-    return this._root?.firstChild as HTMLElement
-  }
-
-  get frame (): HTMLElement {
-    return this._frame!
-  }
-}
-
-export {
-  LSPluginShadowFrame
-}

+ 0 - 303
libs/src/LSPlugin.user.ts

@@ -1,303 +0,0 @@
-import { deepMerge, invokeHostExportedApi } from './helpers'
-import { LSPluginCaller } from './LSPlugin.caller'
-import {
-  IAppProxy, IDBProxy,
-  IEditorProxy,
-  ILSPluginUser,
-  LSPluginBaseInfo, LSPluginUserEvents, SlashCommandAction,
-  StyleString,
-  ThemeOptions,
-  UIOptions
-} from './LSPlugin'
-import Debug from 'debug'
-import { snakeCase } from 'snake-case'
-import EventEmitter from 'eventemitter3'
-
-declare global {
-  interface Window {
-    __LSP__HOST__: boolean
-    logseq: ILSPluginUser
-  }
-}
-
-const debug = Debug('LSPlugin:user')
-
-const app: Partial<IAppProxy> = {}
-
-let registeredCmdUid = 0
-
-const editor: Partial<IEditorProxy> = {
-  registerSlashCommand (
-    this: LSPluginUser,
-    tag: string,
-    actions: Array<SlashCommandAction>
-  ) {
-    debug('Register slash command #', this.baseInfo.id, tag, actions)
-
-    actions = actions.map((it) => {
-      const [tag, ...args] = it
-
-      switch (tag) {
-        case 'editor/hook':
-          let key = args[0]
-          let fn = () => {
-            this.caller?.callUserModel(key)
-          }
-
-          if (typeof key === 'function') {
-            fn = key
-          }
-
-          const eventKey = `SlashCommandHook${tag}${++registeredCmdUid}`
-
-          it[1] = eventKey
-
-          // register command listener
-          this.Editor['on' + eventKey](fn)
-          break
-        default:
-      }
-
-      return it
-    })
-
-    this.caller?.call(`api:call`, {
-      method: 'register-plugin-slash-command',
-      args: [this.baseInfo.id, [tag, actions]]
-    })
-
-    return false
-  },
-
-  registerBlockContextMenu (
-    this: LSPluginUser,
-    tag: string,
-    action: () => void
-  ): boolean {
-    if (typeof action !== 'function') {
-      return false
-    }
-
-    const key = tag
-    const label = tag
-    const type = 'block-context-menu'
-    const eventKey = `SimpleCommandHook${tag}${++registeredCmdUid}`
-
-    this.Editor['on' + eventKey](action)
-
-    this.caller?.call(`api:call`, {
-      method: 'register-plugin-simple-command',
-      args: [this.baseInfo.id, [{ key, label, type }, ['editor/hook', eventKey]]]
-    })
-
-    return false
-  }
-}
-
-const db: Partial<IDBProxy> = {}
-
-type uiState = {
-  key?: number,
-  visible: boolean
-}
-
-const KEY_MAIN_UI = 0
-
-/**
- * User plugin instance
- */
-export class LSPluginUser extends EventEmitter<LSPluginUserEvents> implements ILSPluginUser {
-  /**
-   * Indicate connected with host
-   * @private
-   */
-  private _connected: boolean = false
-  private _ui = new Map<number, uiState>()
-
-  /**
-   * @param _baseInfo
-   * @param _caller
-   */
-  constructor (
-    private _baseInfo: LSPluginBaseInfo,
-    private _caller: LSPluginCaller
-  ) {
-    super()
-
-    _caller.on('settings:changed', (payload) => {
-      const b = Object.assign({}, this.settings)
-      const a = Object.assign(this._baseInfo.settings, payload)
-      this.emit('settings:changed', { ...a }, b)
-    })
-  }
-
-  async ready (
-    model?: any,
-    callback?: any
-  ) {
-    if (this._connected) return
-
-    try {
-
-      if (typeof model === 'function') {
-        callback = model
-        model = {}
-      }
-
-      let baseInfo = await this._caller.connectToParent(model)
-
-      baseInfo = deepMerge(this._baseInfo, baseInfo)
-
-      this._connected = true
-
-      callback && callback.call(this, baseInfo)
-    } catch (e) {
-      console.error('[LSPlugin Ready Error]', e)
-    }
-  }
-
-  provideModel (model: Record<string, any>) {
-    this.caller._extendUserModel(model)
-    return this
-  }
-
-  provideTheme (theme: ThemeOptions) {
-    this.caller.call('provider:theme', theme)
-    return this
-  }
-
-  provideStyle (style: StyleString) {
-    this.caller.call('provider:style', style)
-    return this
-  }
-
-  provideUI (ui: UIOptions) {
-    this.caller.call('provider:ui', ui)
-    return this
-  }
-
-  updateSettings (attrs: Record<string, any>) {
-    this.caller.call('settings:update', attrs)
-    // TODO: update associated baseInfo settings
-  }
-
-  setMainUIAttrs (attrs: Record<string, any>): void {
-    this.caller.call('main-ui:attrs', attrs)
-  }
-
-  setMainUIInlineStyle (style: CSSStyleDeclaration): void {
-    this.caller.call('main-ui:style', style)
-  }
-
-  hideMainUI (): void {
-    const payload = { key: KEY_MAIN_UI, visible: false }
-    this.caller.call('main-ui:visible', payload)
-    this.emit('ui:visible:changed', payload)
-    this._ui.set(payload.key, payload)
-  }
-
-  showMainUI (): void {
-    const payload = { key: KEY_MAIN_UI, visible: true }
-    this.caller.call('main-ui:visible', payload)
-    this.emit('ui:visible:changed', payload)
-    this._ui.set(payload.key, payload)
-  }
-
-  toggleMainUI (): void {
-    const payload = { key: KEY_MAIN_UI, toggle: true }
-    const state = this._ui.get(payload.key)
-    if (state && state.visible) {
-      this.hideMainUI()
-    } else {
-      this.showMainUI()
-    }
-  }
-
-  get isMainUIVisible (): boolean {
-    const state = this._ui.get(0)
-    return Boolean(state && state.visible)
-  }
-
-  get connected (): boolean {
-    return this._connected
-  }
-
-  get baseInfo (): LSPluginBaseInfo {
-    return this._baseInfo
-  }
-
-  get settings () {
-    return this.baseInfo?.settings
-  }
-
-  get caller (): LSPluginCaller {
-    return this._caller
-  }
-
-  _makeUserProxy (
-    target: any,
-    tag?: 'app' | 'editor' | 'db'
-  ) {
-    const that = this
-    const caller = this.caller
-
-    return new Proxy(target, {
-      get (target: any, propKey, receiver) {
-        const origMethod = target[propKey]
-
-        return function (this: any, ...args: any) {
-          if (origMethod) {
-            const ret = origMethod.apply(that, args)
-            if (ret === false) return
-          }
-
-          // Handle hook
-          if (tag) {
-            const hookMatcher = propKey.toString().match(/^(once|off|on)/i)
-
-            if (hookMatcher != null) {
-              const f = hookMatcher[0]
-              const s = hookMatcher.input!
-              const e = s.slice(f.length)
-
-              caller[f.toLowerCase()](`hook:${tag}:${snakeCase(e)}`, args[0])
-              return
-            }
-          }
-
-          // Call host
-          return caller.callAsync(`api:call`, {
-            method: propKey,
-            args: args
-          })
-        }
-      }
-    })
-  }
-
-  get App (): IAppProxy {
-    return this._makeUserProxy(app, 'app')
-  }
-
-  get Editor () {
-    return this._makeUserProxy(editor, 'editor')
-  }
-
-  get DB (): IDBProxy {
-    return this._makeUserProxy(db)
-  }
-}
-
-export function setupPluginUserInstance (
-  pluginBaseInfo: LSPluginBaseInfo,
-  pluginCaller: LSPluginCaller
-) {
-  return new LSPluginUser(pluginBaseInfo, pluginCaller)
-}
-
-if (window.__LSP__HOST__ == null) { // Entry of iframe mode
-  debug('Entry of iframe mode.')
-
-  const caller = new LSPluginCaller(null)
-  window.logseq = setupPluginUserInstance({} as any, caller)
-}

+ 0 - 279
libs/src/helpers.ts

@@ -1,279 +0,0 @@
-import { StyleString, UIOptions } from './LSPlugin'
-import { PluginLocal } from './LSPlugin.core'
-import { snakeCase } from 'snake-case'
-
-interface IObject {
-  [key: string]: any;
-}
-
-declare global {
-  interface Window {
-    api: any
-    apis: any
-  }
-}
-
-export function isObject (item: any) {
-  return (item === Object(item) && !Array.isArray(item))
-}
-
-export function deepMerge (
-  target: IObject,
-  ...sources: Array<IObject>
-) {
-  // return the target if no sources passed
-  if (!sources.length) {
-    return target
-  }
-
-  const result: IObject = target
-
-  if (isObject(result)) {
-    const len: number = sources.length
-
-    for (let i = 0; i < len; i += 1) {
-      const elm: any = sources[i]
-
-      if (isObject(elm)) {
-        for (const key in elm) {
-          if (elm.hasOwnProperty(key)) {
-            if (isObject(elm[key])) {
-              if (!result[key] || !isObject(result[key])) {
-                result[key] = {}
-              }
-              deepMerge(result[key], elm[key])
-            } else {
-              if (Array.isArray(result[key]) && Array.isArray(elm[key])) {
-                // concatenate the two arrays and remove any duplicate primitive values
-                result[key] = Array.from(new Set(result[key].concat(elm[key])))
-              } else {
-                result[key] = elm[key]
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-
-  return result
-}
-
-export function genID () {
-  // Math.random should be unique because of its seeding algorithm.
-  // Convert it to base 36 (numbers + letters), and grab the first 9 characters
-  // after the decimal.
-  return '_' + Math.random().toString(36).substr(2, 9)
-}
-
-export function ucFirst (str: string) {
-  return str.charAt(0).toUpperCase() + str.slice(1)
-}
-
-export function withFileProtocol (path: string) {
-  if (!path) return ''
-  const reg = /^(http|file|assets)/
-
-  if (!reg.test(path)) {
-    path = 'file://' + path
-  }
-
-  return path
-}
-
-/**
- * @param timeout milliseconds
- * @param tag string
- */
-export function deferred<T = any> (timeout?: number, tag?: string) {
-  let resolve: any, reject: any
-  let settled = false
-  const timeFn = (r: Function) => {
-    return (v: T) => {
-      timeout && clearTimeout(timeout)
-      r(v)
-      settled = true
-    }
-  }
-
-  const promise = new Promise<T>((resolve1, reject1) => {
-    resolve = timeFn(resolve1)
-    reject = timeFn(reject1)
-
-    if (timeout) {
-      // @ts-ignore
-      timeout = setTimeout(() => reject(new Error(`[deferred timeout] ${tag}`)), timeout)
-    }
-  })
-
-  return {
-    created: Date.now(),
-    setTag: (t: string) => tag = t,
-    resolve, reject, promise,
-    get settled () {
-      return settled
-    }
-  }
-}
-
-export function invokeHostExportedApi (
-  method: string,
-  ...args: Array<any>
-) {
-  const method1 = snakeCase(method)
-  const fn = window.api[method1] || window.apis[method1] ||
-    window.api[method] || window.apis[method]
-
-  if (!fn) {
-    throw new Error(`Not existed method #${method}`)
-  }
-  return typeof fn !== 'function' ? fn : fn.apply(null, args)
-}
-
-export function setupIframeSandbox (
-  props: Record<string, any>,
-  target: HTMLElement
-) {
-  const iframe = document.createElement('iframe')
-
-  iframe.classList.add('lsp-iframe-sandbox')
-
-  Object.entries(props).forEach(([k, v]) => {
-    iframe.setAttribute(k, v)
-  })
-
-  target.appendChild(iframe)
-
-  return async () => {
-    target.removeChild(iframe)
-  }
-}
-
-export function setupInjectedStyle (
-  style: StyleString,
-  attrs: Record<string, any>
-) {
-  const key = attrs['data-injected-style']
-  let el = key && document.querySelector(`[data-injected-style=${key}]`)
-
-  if (el) {
-    el.textContent = style
-    return
-  }
-
-  el = document.createElement('style')
-  el.textContent = style
-
-  attrs && Object.entries(attrs).forEach(([k, v]) => {
-    el.setAttribute(k, v)
-  })
-
-  document.head.append(el)
-
-  return () => {
-    document.head.removeChild(el)
-  }
-}
-
-export function setupInjectedUI (
-  this: PluginLocal,
-  ui: UIOptions,
-  attrs: Record<string, any>
-) {
-  const pl = this
-  const selector = ui.path || `#${ui.slot}`
-
-  const target = selector && document.querySelector(selector)
-  if (!target) {
-    console.error(`${this.debugTag} can not resolve selector target ${selector}`)
-    return
-  }
-
-  const key = `${ui.key}-${pl.id}`
-
-  let el = document.querySelector(`div[data-injected-ui="${key}"]`) as HTMLElement
-
-  if (el) {
-    el.innerHTML = ui.template
-    return
-  }
-
-  el = document.createElement('div')
-  el.dataset.injectedUi = key || ''
-
-  // TODO: Support more
-  el.innerHTML = ui.template
-
-  attrs && Object.entries(attrs).forEach(([k, v]) => {
-    el.setAttribute(k, v)
-  })
-
-  target.appendChild(el);
-
-  // TODO: How handle events
-  ['click', 'focus', 'focusin', 'focusout', 'blur', 'dblclick',
-    'keyup', 'keypress', 'keydown', 'change', 'input'].forEach((type) => {
-    el.addEventListener(type, (e) => {
-      const target = e.target! as HTMLElement
-      const trigger = target.closest(`[data-on-${type}]`) as HTMLElement
-      if (!trigger) return
-
-      const msgType = trigger.dataset[`on${ucFirst(type)}`]
-      msgType && pl.caller?.callUserModel(msgType, transformableEvent(trigger, e))
-    }, false)
-  })
-
-  return () => {
-    target!.removeChild(el)
-  }
-}
-
-export function transformableEvent (target: HTMLElement, e: Event) {
-  const obj: any = {}
-
-  if (target) {
-    const ds = target.dataset
-    const FLAG_RECT = 'rect'
-
-    ;['value', 'id', 'className',
-      'dataset', FLAG_RECT
-    ].forEach((k) => {
-      let v: any
-
-      switch (k) {
-        case FLAG_RECT:
-          if (!ds.hasOwnProperty(FLAG_RECT)) return
-          v = target.getBoundingClientRect().toJSON()
-          break
-        default:
-          v = target[k]
-      }
-
-      if (typeof v === 'object') {
-        v = { ...v }
-      }
-
-      obj[k] = v
-    })
-  }
-
-  return obj
-}
-
-let injectedThemeEffect: any = null
-
-export function setupInjectedTheme (url?: string) {
-  injectedThemeEffect?.call()
-
-  if (!url) return
-
-  const link = document.createElement('link')
-  link.rel = 'stylesheet'
-  link.href = url
-  document.head.appendChild(link)
-
-  return (injectedThemeEffect = () => {
-    document.head.removeChild(link)
-    injectedThemeEffect = null
-  })
-}

+ 0 - 88
libs/tsconfig.json

@@ -1,88 +0,0 @@
-{
-  "compilerOptions": {
-    /* Visit https://aka.ms/tsconfig.json to read more about this file */
-
-    /* Basic Options */
-    // "incremental": true,                   /* Enable incremental compilation */
-    "target": "ESNext",
-    /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
-    "module": "ESNext",
-    /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
-    // "lib": [],                             /* Specify library files to be included in the compilation. */
-    "allowJs": true,
-    /* Allow javascript files to be compiled. */
-    // "checkJs": true,                       /* Report errors in .js files. */
-    "jsx": "react",
-    /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
-    "declaration": true,
-    /* Generates corresponding '.d.ts' file. */
-    // "declarationMap": true,                /* Generates a sourcemap for each corresponding '.d.ts' file. */
-    "sourceMap": false,
-    /* Generates corresponding '.map' file. */
-    // "outFile": "./",                       /* Concatenate and emit output to single file. */
-    "outDir": "dist",
-    /* Redirect output structure to the directory. */
-    "rootDir": "src",
-    /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
-    // "composite": true,                     /* Enable project compilation */
-    // "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */
-    // "removeComments": true,                /* Do not emit comments to output. */
-    //    "noEmit": true,
-    /* Do not emit outputs. */
-    // "importHelpers": true,                 /* Import emit helpers from 'tslib'. */
-    // "downlevelIteration": true,            /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */
-    // "isolatedModules": true,               /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */
-
-    /* Strict Type-Checking Options */
-    // "strict": true,
-    /* Enable all strict type-checking options. */
-    // "noImplicitAny": true,                 /* Raise error on expressions and declarations with an implied 'any' type. */
-    "strictNullChecks": true,
-    /* Enable strict null checks. */
-    // "strictFunctionTypes": true,           /* Enable strict checking of function types. */
-    // "strictBindCallApply": true,           /* Enable strict 'bind', 'call', and 'apply' methods on functions. */
-    "strictPropertyInitialization": true,
-    /* Enable strict checking of property initialization in classes. */
-    // "noImplicitThis": true,                /* Raise error on 'this' expressions with an implied 'any' type. */
-    // "alwaysStrict": true,                  /* Parse in strict mode and emit "use strict" for each source file. */
-
-    /* Additional Checks */
-    // "noUnusedLocals": true,                /* Report errors on unused locals. */
-    // "noUnusedParameters": true,            /* Report errors on unused parameters. */
-    // "noImplicitReturns": true,             /* Report error when not all code paths in function return a value. */
-    // "noFallthroughCasesInSwitch": true,    /* Report errors for fallthrough cases in switch statement. */
-
-    /* Module Resolution Options */
-    "moduleResolution": "node",
-    /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
-    // "baseUrl": "./",                       /* Base directory to resolve non-absolute module names. */
-    // "paths": {},                           /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
-    // "rootDirs": [],                        /* List of root folders whose combined content represents the structure of the project at runtime. */
-    // "typeRoots": [],                       /* List of folders to include type definitions from. */
-    // "types": [],                           /* Type declaration files to be included in compilation. */
-    // "allowSyntheticDefaultImports": true,  /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
-    "esModuleInterop": true,
-    /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
-    // "preserveSymlinks": true,              /* Do not resolve the real path of symlinks. */
-    // "allowUmdGlobalAccess": true,          /* Allow accessing UMD globals from modules. */
-
-    /* Source Map Options */
-    // "sourceRoot": "",                      /* Specify the location where debugger should locate TypeScript files instead of source locations. */
-    // "mapRoot": "",                         /* Specify the location where debugger should locate map files instead of generated locations. */
-    // "inlineSourceMap": true,               /* Emit a single file with source maps instead of having a separate file. */
-    // "inlineSources": true,                 /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
-
-    /* Experimental Options */
-    // "experimentalDecorators": true,        /* Enables experimental support for ES7 decorators. */
-    // "emitDecoratorMetadata": true,         /* Enables experimental support for emitting type metadata for decorators. */
-
-    /* Advanced Options */
-    "skipLibCheck": true,
-    /* Skip type checking of declaration files. */
-    "forceConsistentCasingInFileNames": true
-    /* Disallow inconsistently-cased references to the same file. */
-  },
-  "include": [
-    "src/**/*.ts"
-  ]
-}

+ 0 - 32
libs/webpack.config.core.js

@@ -1,32 +0,0 @@
-const webpack = require('webpack')
-const path = require('path')
-const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
-
-module.exports = {
-  entry: './src/LSPlugin.core.ts',
-  devtool: 'inline-source-map',
-  module: {
-    rules: [
-      {
-        test: /\.tsx?$/,
-        use: 'ts-loader',
-        exclude: /node_modules/,
-      },
-    ],
-  },
-  resolve: {
-    extensions: ['.tsx', '.ts', '.js'],
-  },
-  plugins: [
-    new webpack.ProvidePlugin({
-      process: 'process/browser',
-    }),
-    // new BundleAnalyzerPlugin()
-  ],
-  output: {
-    library: 'LSPlugin',
-    libraryTarget: 'umd',
-    filename: 'lsplugin.core.js',
-    path: path.resolve(__dirname, '../static/js'),
-  },
-}

+ 0 - 27
libs/webpack.config.js

@@ -1,27 +0,0 @@
-const path = require('path')
-const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin
-
-module.exports = {
-  entry: './src/LSPlugin.user.ts',
-  module: {
-    rules: [
-      {
-        test: /\.tsx?$/,
-        use: 'ts-loader',
-        exclude: /node_modules/,
-      },
-    ],
-  },
-  resolve: {
-    extensions: ['.tsx', '.ts', '.js'],
-  },
-  plugins: [
-    // new BundleAnalyzerPlugin()
-  ],
-  output: {
-    library: "LSPluginEntry",
-    libraryTarget: "umd",
-    filename: 'lsplugin.user.js',
-    path: path.resolve(__dirname, 'dist')
-  },
-}

+ 0 - 1251
libs/yarn.lock

@@ -1,1251 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@discoveryjs/json-ext@^0.5.0":
-  version "0.5.2"
-  resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
-  integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==
-
-"@polka/url@^1.0.0-next.9":
-  version "1.0.0-next.11"
-  resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.11.tgz#aeb16f50649a91af79dbe36574b66d0f9e4d9f71"
-  integrity sha512-3NsZsJIA/22P3QUyrEDNA2D133H4j224twJrdipXN38dpnIOzAbUDtOwkcJ5pXmn75w7LSQDjA4tO9dm1XlqlA==
-
-"@types/debug@^4.1.5":
-  version "4.1.5"
-  resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.5.tgz#b14efa8852b7768d898906613c23f688713e02cd"
-  integrity sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==
-
-"@types/dompurify@^2.2.1":
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/@types/dompurify/-/dompurify-2.2.1.tgz#eebf3af8afe2f577a53acab9d98a3a4cb04bbbe7"
-  integrity sha512-3JwbEeRVQ3n6+JgBW/hCdkydRk9/vWT+UEglcXEJqLJEcUganDH37zlfLznxPKTZZfDqA9K229l1qN458ubcOQ==
-  dependencies:
-    "@types/trusted-types" "*"
-
-"@types/eslint-scope@^3.7.0":
-  version "3.7.0"
-  resolved "https://registry.yarnpkg.com/@types/eslint-scope/-/eslint-scope-3.7.0.tgz#4792816e31119ebd506902a482caec4951fabd86"
-  integrity sha512-O/ql2+rrCUe2W2rs7wMR+GqPRcgB6UiqN5RhrR5xruFlY7l9YLMn0ZkDzjoHLeiFkR8MCQZVudUuuvQ2BLC9Qw==
-  dependencies:
-    "@types/eslint" "*"
-    "@types/estree" "*"
-
-"@types/eslint@*":
-  version "7.2.6"
-  resolved "https://registry.yarnpkg.com/@types/eslint/-/eslint-7.2.6.tgz#5e9aff555a975596c03a98b59ecd103decc70c3c"
-  integrity sha512-I+1sYH+NPQ3/tVqCeUSBwTE/0heyvtXqpIopUUArlBm0Kpocb8FbMa3AZ/ASKIFpN3rnEx932TTXDbt9OXsNDw==
-  dependencies:
-    "@types/estree" "*"
-    "@types/json-schema" "*"
-
-"@types/estree@*", "@types/estree@^0.0.46":
-  version "0.0.46"
-  resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe"
-  integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==
-
-"@types/json-schema@*", "@types/json-schema@^7.0.6":
-  version "7.0.7"
-  resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
-  integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
-
-"@types/lodash-es@^4.17.4":
-  version "4.17.4"
-  resolved "https://registry.yarnpkg.com/@types/lodash-es/-/lodash-es-4.17.4.tgz#b2e440d2bf8a93584a9fd798452ec497986c9b97"
-  integrity sha512-BBz79DCJbD2CVYZH67MBeHZRX++HF+5p8Mo5MzjZi64Wac39S3diedJYHZtScbRVf4DjZyN6LzA0SB0zy+HSSQ==
-  dependencies:
-    "@types/lodash" "*"
-
-"@types/lodash@*":
-  version "4.14.168"
-  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.168.tgz#fe24632e79b7ade3f132891afff86caa5e5ce008"
-  integrity sha512-oVfRvqHV/V6D1yifJbVRU3TMp8OT6o6BG+U9MkwuJ3U8/CsDHvalRpsxBqivn71ztOFZBTfJMvETbqHiaNSj7Q==
-
-"@types/node@*":
-  version "14.14.31"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.31.tgz#72286bd33d137aa0d152d47ec7c1762563d34055"
-  integrity sha512-vFHy/ezP5qI0rFgJ7aQnjDXwAMrG0KqqIH7tQG5PPv3BWBayOPIQNBjVc/P6hhdZfMx51REc6tfDNXHUio893g==
-
-"@types/postmate@^1.5.1":
-  version "1.5.1"
-  resolved "https://registry.yarnpkg.com/@types/postmate/-/postmate-1.5.1.tgz#56a506c371a7b4388beebacb4420838c2c3c4a2b"
-  integrity sha512-sFia2ycFNrxf1YZS59ShTDkMwhUlOYWAw7EslLePF52x5czUDrvdqB4f3eCXCiQp7yXpqHqwPCf4OBvCTqbaWw==
-
-"@types/trusted-types@*":
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/@types/trusted-types/-/trusted-types-2.0.0.tgz#aee6e868fcef74f2b8c71614b6df81a601a42f17"
-  integrity sha512-I8MnZqNXsOLHsU111oHbn3khtvKMi5Bn4qVFsIWSJcCP1KKDiXX5AEw8UPk0nSopeC+Hvxt6yAy1/a5PailFqg==
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.11.0.tgz#a5aa679efdc9e51707a4207139da57920555961f"
-  integrity sha512-kX2W49LWsbthrmIRMbQZuQDhGtjyqXfEmmHyEi4XWnSZtPmxY0+3anPIzsnRb45VH/J55zlOfWvZuY47aJZTJg==
-  dependencies:
-    "@webassemblyjs/helper-numbers" "1.11.0"
-    "@webassemblyjs/helper-wasm-bytecode" "1.11.0"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.0.tgz#34d62052f453cd43101d72eab4966a022587947c"
-  integrity sha512-Q/aVYs/VnPDVYvsCBL/gSgwmfjeCb4LW8+TMrO3cSzJImgv8lxxEPM2JA5jMrivE7LSz3V+PFqtMbls3m1exDA==
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.0.tgz#aaea8fb3b923f4aaa9b512ff541b013ffb68d2d4"
-  integrity sha512-baT/va95eXiXb2QflSx95QGT5ClzWpGaa8L7JnJbgzoYeaA27FCvuBXU758l+KXWRndEmUXjP0Q5fibhavIn8w==
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.0.tgz#d026c25d175e388a7dbda9694e91e743cbe9b642"
-  integrity sha512-u9HPBEl4DS+vA8qLQdEQ6N/eJQ7gT7aNvMIo8AAWvAl/xMrcOSiI2M0MAnMCy3jIFke7bEee/JwdX1nUpCtdyA==
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.0.tgz#7ab04172d54e312cc6ea4286d7d9fa27c88cd4f9"
-  integrity sha512-DhRQKelIj01s5IgdsOJMKLppI+4zpmcMQ3XboFPLwCpSNH6Hqo1ritgHgD0nqHeSYqofA6aBN/NmXuGjM1jEfQ==
-  dependencies:
-    "@webassemblyjs/floating-point-hex-parser" "1.11.0"
-    "@webassemblyjs/helper-api-error" "1.11.0"
-    "@xtuc/long" "4.2.2"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.0.tgz#85fdcda4129902fe86f81abf7e7236953ec5a4e1"
-  integrity sha512-MbmhvxXExm542tWREgSFnOVo07fDpsBJg3sIl6fSp9xuu75eGz5lz31q7wTLffwL3Za7XNRCMZy210+tnsUSEA==
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.0.tgz#9ce2cc89300262509c801b4af113d1ca25c1a75b"
-  integrity sha512-3Eb88hcbfY/FCukrg6i3EH8H2UsD7x8Vy47iVJrP967A9JGqgBVL9aH71SETPx1JrGsOUVLo0c7vMCN22ytJew==
-  dependencies:
-    "@webassemblyjs/ast" "1.11.0"
-    "@webassemblyjs/helper-buffer" "1.11.0"
-    "@webassemblyjs/helper-wasm-bytecode" "1.11.0"
-    "@webassemblyjs/wasm-gen" "1.11.0"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.11.0.tgz#46975d583f9828f5d094ac210e219441c4e6f5cf"
-  integrity sha512-KXzOqpcYQwAfeQ6WbF6HXo+0udBNmw0iXDmEK5sFlmQdmND+tr773Ti8/5T/M6Tl/413ArSJErATd8In3B+WBA==
-  dependencies:
-    "@xtuc/ieee754" "^1.2.0"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.11.0.tgz#f7353de1df38aa201cba9fb88b43f41f75ff403b"
-  integrity sha512-aqbsHa1mSQAbeeNcl38un6qVY++hh8OpCOzxhixSYgbRfNWcxJNJQwe2rezK9XEcssJbbWIkblaJRwGMS9zp+g==
-  dependencies:
-    "@xtuc/long" "4.2.2"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.11.0.tgz#86e48f959cf49e0e5091f069a709b862f5a2cadf"
-  integrity sha512-A/lclGxH6SpSLSyFowMzO/+aDEPU4hvEiooCMXQPcQFPPJaYcPQNKGOCLUySJsYJ4trbpr+Fs08n4jelkVTGVw==
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.0.tgz#ee4a5c9f677046a210542ae63897094c2027cb78"
-  integrity sha512-JHQ0damXy0G6J9ucyKVXO2j08JVJ2ntkdJlq1UTiUrIgfGMmA7Ik5VdC/L8hBK46kVJgujkBIoMtT8yVr+yVOQ==
-  dependencies:
-    "@webassemblyjs/ast" "1.11.0"
-    "@webassemblyjs/helper-buffer" "1.11.0"
-    "@webassemblyjs/helper-wasm-bytecode" "1.11.0"
-    "@webassemblyjs/helper-wasm-section" "1.11.0"
-    "@webassemblyjs/wasm-gen" "1.11.0"
-    "@webassemblyjs/wasm-opt" "1.11.0"
-    "@webassemblyjs/wasm-parser" "1.11.0"
-    "@webassemblyjs/wast-printer" "1.11.0"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.0.tgz#3cdb35e70082d42a35166988dda64f24ceb97abe"
-  integrity sha512-BEUv1aj0WptCZ9kIS30th5ILASUnAPEvE3tVMTrItnZRT9tXCLW2LEXT8ezLw59rqPP9klh9LPmpU+WmRQmCPQ==
-  dependencies:
-    "@webassemblyjs/ast" "1.11.0"
-    "@webassemblyjs/helper-wasm-bytecode" "1.11.0"
-    "@webassemblyjs/ieee754" "1.11.0"
-    "@webassemblyjs/leb128" "1.11.0"
-    "@webassemblyjs/utf8" "1.11.0"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.0.tgz#1638ae188137f4bb031f568a413cd24d32f92978"
-  integrity sha512-tHUSP5F4ywyh3hZ0+fDQuWxKx3mJiPeFufg+9gwTpYp324mPCQgnuVKwzLTZVqj0duRDovnPaZqDwoyhIO8kYg==
-  dependencies:
-    "@webassemblyjs/ast" "1.11.0"
-    "@webassemblyjs/helper-buffer" "1.11.0"
-    "@webassemblyjs/wasm-gen" "1.11.0"
-    "@webassemblyjs/wasm-parser" "1.11.0"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.0.tgz#3e680b8830d5b13d1ec86cc42f38f3d4a7700754"
-  integrity sha512-6L285Sgu9gphrcpDXINvm0M9BskznnzJTE7gYkjDbxET28shDqp27wpruyx3C2S/dvEwiigBwLA1cz7lNUi0kw==
-  dependencies:
-    "@webassemblyjs/ast" "1.11.0"
-    "@webassemblyjs/helper-api-error" "1.11.0"
-    "@webassemblyjs/helper-wasm-bytecode" "1.11.0"
-    "@webassemblyjs/ieee754" "1.11.0"
-    "@webassemblyjs/leb128" "1.11.0"
-    "@webassemblyjs/utf8" "1.11.0"
-
-"@webassemblyjs/[email protected]":
-  version "1.11.0"
-  resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.11.0.tgz#680d1f6a5365d6d401974a8e949e05474e1fab7e"
-  integrity sha512-Fg5OX46pRdTgB7rKIUojkh9vXaVN6sGYCnEiJN1GYkb0RPwShZXp6KTDqmoMdQPKhcroOXh3fEzmkWmCYaKYhQ==
-  dependencies:
-    "@webassemblyjs/ast" "1.11.0"
-    "@xtuc/long" "4.2.2"
-
-"@webpack-cli/configtest@^1.0.1":
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/configtest/-/configtest-1.0.1.tgz#241aecfbdc715eee96bed447ed402e12ec171935"
-  integrity sha512-B+4uBUYhpzDXmwuo3V9yBH6cISwxEI4J+NO5ggDaGEEHb0osY/R7MzeKc0bHURXQuZjMM4qD+bSJCKIuI3eNBQ==
-
-"@webpack-cli/info@^1.2.2":
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/info/-/info-1.2.2.tgz#ef3c0cd947a1fa083e174a59cb74e0b6195c236c"
-  integrity sha512-5U9kUJHnwU+FhKH4PWGZuBC1hTEPYyxGSL5jjoBI96Gx8qcYJGOikpiIpFoTq8mmgX3im2zAo2wanv/alD74KQ==
-  dependencies:
-    envinfo "^7.7.3"
-
-"@webpack-cli/serve@^1.3.0":
-  version "1.3.0"
-  resolved "https://registry.yarnpkg.com/@webpack-cli/serve/-/serve-1.3.0.tgz#2730c770f5f1f132767c63dcaaa4ec28f8c56a6c"
-  integrity sha512-k2p2VrONcYVX1wRRrf0f3X2VGltLWcv+JzXRBDmvCxGlCeESx4OXw91TsWeKOkp784uNoVQo313vxJFHXPPwfw==
-
-"@xtuc/ieee754@^1.2.0":
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
-  integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
-
-"@xtuc/[email protected]":
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
-  integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
-
-acorn-walk@^8.0.0:
-  version "8.0.2"
-  resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.0.2.tgz#d4632bfc63fd93d0f15fd05ea0e984ffd3f5a8c3"
-  integrity sha512-+bpA9MJsHdZ4bgfDcpk0ozQyhhVct7rzOmO0s1IIr0AGGgKBljss8n2zp11rRP2wid5VGeh04CgeKzgat5/25A==
-
-acorn@^8.0.4:
-  version "8.0.5"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.0.5.tgz#a3bfb872a74a6a7f661bc81b9849d9cac12601b7"
-  integrity sha512-v+DieK/HJkJOpFBETDJioequtc3PfxsWMaxIdIwujtF7FEV/MAyDQLlm6/zPvr7Mix07mLh6ccVwIsloceodlg==
-
-ajv-keywords@^3.5.2:
-  version "3.5.2"
-  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d"
-  integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==
-
-ajv@^6.12.5:
-  version "6.12.6"
-  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
-  integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
-  dependencies:
-    fast-deep-equal "^3.1.1"
-    fast-json-stable-stringify "^2.0.0"
-    json-schema-traverse "^0.4.1"
-    uri-js "^4.2.2"
-
-ansi-colors@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348"
-  integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==
-
-ansi-styles@^4.1.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
-  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
-  dependencies:
-    color-convert "^2.0.1"
-
-big.js@^5.2.2:
-  version "5.2.2"
-  resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
-  integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
-
-braces@^3.0.1:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
-  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
-  dependencies:
-    fill-range "^7.0.1"
-
-browserslist@^4.14.5:
-  version "4.16.3"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.3.tgz#340aa46940d7db878748567c5dea24a48ddf3717"
-  integrity sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==
-  dependencies:
-    caniuse-lite "^1.0.30001181"
-    colorette "^1.2.1"
-    electron-to-chromium "^1.3.649"
-    escalade "^3.1.1"
-    node-releases "^1.1.70"
-
-buffer-from@^1.0.0:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
-  integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
-
-caniuse-lite@^1.0.30001181:
-  version "1.0.30001196"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001196.tgz#00518a2044b1abf3e0df31fadbe5ed90b63f4e64"
-  integrity sha512-CPvObjD3ovWrNBaXlAIGWmg2gQQuJ5YhuciUOjPRox6hIQttu8O+b51dx6VIpIY9ESd2d0Vac1RKpICdG4rGUg==
-
-chalk@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a"
-  integrity sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==
-  dependencies:
-    ansi-styles "^4.1.0"
-    supports-color "^7.1.0"
-
-chrome-trace-event@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
-  integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==
-  dependencies:
-    tslib "^1.9.0"
-
-clone-deep@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387"
-  integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==
-  dependencies:
-    is-plain-object "^2.0.4"
-    kind-of "^6.0.2"
-    shallow-clone "^3.0.0"
-
-color-convert@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
-  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
-  dependencies:
-    color-name "~1.1.4"
-
-color-name@~1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
-  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-colorette@^1.2.1:
-  version "1.2.2"
-  resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.2.2.tgz#cbcc79d5e99caea2dbf10eb3a26fd8b3e6acfa94"
-  integrity sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==
-
-commander@^2.20.0:
-  version "2.20.3"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
-  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-
-commander@^6.2.0:
-  version "6.2.1"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c"
-  integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==
-
-commander@^7.0.0:
-  version "7.1.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff"
-  integrity sha512-pRxBna3MJe6HKnBGsDyMv8ETbptw3axEdYHoqNh7gu5oDcew8fs0xnivZGm06Ogk8zGAJ9VX+OPEr2GXEQK4dg==
-
-core-util-is@~1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
-  integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
-
-cross-spawn@^7.0.3:
-  version "7.0.3"
-  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
-  integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
-  dependencies:
-    path-key "^3.1.0"
-    shebang-command "^2.0.0"
-    which "^2.0.1"
-
-debug@^4.3.1:
-  version "4.3.1"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
-  integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
-  dependencies:
-    ms "2.1.2"
-
-dompurify@^2.2.7:
-  version "2.2.7"
-  resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.2.7.tgz#a5f055a2a471638680e779bd08fc334962d11fd8"
-  integrity sha512-jdtDffdGNY+C76jvodNTu9jt5yYj59vuTUyx+wXdzcSwAGTYZDAQkQ7Iwx9zcGrA4ixC1syU4H3RZROqRxokxg==
-
-dot-case@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
-  integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
-  dependencies:
-    no-case "^3.0.4"
-    tslib "^2.0.3"
-
-duplexer@^0.1.2:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
-  integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==
-
-electron-to-chromium@^1.3.649:
-  version "1.3.680"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.680.tgz#88cc44bd2a85b46cf7521f714db57dd74d0cd488"
-  integrity sha512-XBACJT9RdpdWtoMXQPR8Be3ZtmizWWbxfw8cY2b5feUwiDO3FUl8qo4W2jXoq/WnnA3xBRqafu1XbpczqyUvlA==
-
-emojis-list@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78"
-  integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==
-
-enhanced-resolve@^4.0.0:
-  version "4.5.0"
-  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec"
-  integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg==
-  dependencies:
-    graceful-fs "^4.1.2"
-    memory-fs "^0.5.0"
-    tapable "^1.0.0"
-
-enhanced-resolve@^5.7.0:
-  version "5.7.0"
-  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.7.0.tgz#525c5d856680fbd5052de453ac83e32049958b5c"
-  integrity sha512-6njwt/NsZFUKhM6j9U8hzVyD4E4r0x7NQzhTCbcWOJ0IQjNSAoalWmb0AE51Wn+fwan5qVESWi7t2ToBxs9vrw==
-  dependencies:
-    graceful-fs "^4.2.4"
-    tapable "^2.2.0"
-
-enquirer@^2.3.6:
-  version "2.3.6"
-  resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d"
-  integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==
-  dependencies:
-    ansi-colors "^4.1.1"
-
-envinfo@^7.7.3:
-  version "7.7.4"
-  resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.7.4.tgz#c6311cdd38a0e86808c1c9343f667e4267c4a320"
-  integrity sha512-TQXTYFVVwwluWSFis6K2XKxgrD22jEv0FTuLCQI+OjH7rn93+iY0fSSFM5lrSxFY+H1+B0/cvvlamr3UsBivdQ==
-
-errno@^0.1.3:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
-  integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
-  dependencies:
-    prr "~1.0.1"
-
-es-module-lexer@^0.4.0:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-0.4.1.tgz#dda8c6a14d8f340a24e34331e0fab0cb50438e0e"
-  integrity sha512-ooYciCUtfw6/d2w56UVeqHPcoCFAiJdz5XOkYpv/Txl1HMUozpXjz/2RIQgqwKdXNDPSF1W7mJCFse3G+HDyAA==
-
-escalade@^3.1.1:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
-  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-eslint-scope@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
-  integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
-  dependencies:
-    esrecurse "^4.3.0"
-    estraverse "^4.1.1"
-
-esrecurse@^4.3.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921"
-  integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==
-  dependencies:
-    estraverse "^5.2.0"
-
-estraverse@^4.1.1:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d"
-  integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==
-
-estraverse@^5.2.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.2.0.tgz#307df42547e6cc7324d3cf03c155d5cdb8c53880"
-  integrity sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==
-
-eventemitter3@^4.0.7:
-  version "4.0.7"
-  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f"
-  integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==
-
-events@^3.2.0:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400"
-  integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==
-
-execa@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376"
-  integrity sha512-ov6w/2LCiuyO4RLYGdpFGjkcs0wMTgGE8PrkTHikeUy5iJekXyPIKUjifk5CsE0pt7sMCrMZ3YNqoCj6idQOnQ==
-  dependencies:
-    cross-spawn "^7.0.3"
-    get-stream "^6.0.0"
-    human-signals "^2.1.0"
-    is-stream "^2.0.0"
-    merge-stream "^2.0.0"
-    npm-run-path "^4.0.1"
-    onetime "^5.1.2"
-    signal-exit "^3.0.3"
-    strip-final-newline "^2.0.0"
-
-fast-deep-equal@^3.1.1:
-  version "3.1.3"
-  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
-  integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
-
-fast-json-stable-stringify@^2.0.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633"
-  integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==
-
-fastest-levenshtein@^1.0.12:
-  version "1.0.12"
-  resolved "https://registry.yarnpkg.com/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz#9990f7d3a88cc5a9ffd1f1745745251700d497e2"
-  integrity sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==
-
-fill-range@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
-  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
-  dependencies:
-    to-regex-range "^5.0.1"
-
-find-up@^4.0.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
-  integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
-  dependencies:
-    locate-path "^5.0.0"
-    path-exists "^4.0.0"
-
-function-bind@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
-  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-get-stream@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.0.tgz#3e0012cb6827319da2706e601a1583e8629a6718"
-  integrity sha512-A1B3Bh1UmL0bidM/YX2NsCOTnGJePL9rO/M+Mw3m9f2gUpfokS0hi5Eah0WSUEWZdZhIZtMjkIYS7mDfOqNHbg==
-
-glob-to-regexp@^0.4.1:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e"
-  integrity sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==
-
-graceful-fs@^4.1.2, graceful-fs@^4.2.4:
-  version "4.2.6"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.6.tgz#ff040b2b0853b23c3d31027523706f1885d76bee"
-  integrity sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==
-
-gzip-size@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462"
-  integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q==
-  dependencies:
-    duplexer "^0.1.2"
-
-has-flag@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
-  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
-  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
-  dependencies:
-    function-bind "^1.1.1"
-
-human-signals@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0"
-  integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==
-
-import-local@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6"
-  integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA==
-  dependencies:
-    pkg-dir "^4.2.0"
-    resolve-cwd "^3.0.0"
-
[email protected]:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
-
-inherits@~2.0.3:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
-  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-interpret@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/interpret/-/interpret-2.2.0.tgz#1a78a0b5965c40a5416d007ad6f50ad27c417df9"
-  integrity sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==
-
-is-core-module@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.2.0.tgz#97037ef3d52224d85163f5597b2b63d9afed981a"
-  integrity sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==
-  dependencies:
-    has "^1.0.3"
-
-is-number@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
-  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-
-is-plain-object@^2.0.4:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
-  integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
-  dependencies:
-    isobject "^3.0.1"
-
-is-stream@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
-  integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
-
-isarray@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
-  integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
-
-isexe@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
-  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
-
-isobject@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
-  integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
-
-jest-worker@^26.6.2:
-  version "26.6.2"
-  resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed"
-  integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==
-  dependencies:
-    "@types/node" "*"
-    merge-stream "^2.0.0"
-    supports-color "^7.0.0"
-
-json-parse-better-errors@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
-  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
-
-json-schema-traverse@^0.4.1:
-  version "0.4.1"
-  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
-  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
-
-json5@^2.1.2:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.0.tgz#2dfefe720c6ba525d9ebd909950f0515316c89a3"
-  integrity sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==
-  dependencies:
-    minimist "^1.2.5"
-
-kind-of@^6.0.2:
-  version "6.0.3"
-  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
-  integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
-
-loader-runner@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-4.2.0.tgz#d7022380d66d14c5fb1d496b89864ebcfd478384"
-  integrity sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==
-
-loader-utils@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0"
-  integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==
-  dependencies:
-    big.js "^5.2.2"
-    emojis-list "^3.0.0"
-    json5 "^2.1.2"
-
-locate-path@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0"
-  integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==
-  dependencies:
-    p-locate "^4.1.0"
-
-lodash@^4.17.20:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
-  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-lower-case@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
-  integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
-  dependencies:
-    tslib "^2.0.3"
-
-lru-cache@^6.0.0:
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94"
-  integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
-  dependencies:
-    yallist "^4.0.0"
-
-memory-fs@^0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c"
-  integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==
-  dependencies:
-    errno "^0.1.3"
-    readable-stream "^2.0.1"
-
-merge-stream@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
-  integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-
-micromatch@^4.0.0:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259"
-  integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q==
-  dependencies:
-    braces "^3.0.1"
-    picomatch "^2.0.5"
-
[email protected]:
-  version "1.46.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.46.0.tgz#6267748a7f799594de3cbc8cde91def349661cee"
-  integrity sha512-svXaP8UQRZ5K7or+ZmfNhg2xX3yKDMUzqadsSqi4NCH/KomcH75MAMYAGVlvXn4+b/xOPhS3I2uHKRUzvjY7BQ==
-
-mime-types@^2.1.27:
-  version "2.1.29"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.29.tgz#1d4ab77da64b91f5f72489df29236563754bb1b2"
-  integrity sha512-Y/jMt/S5sR9OaqteJtslsFZKWOIIqMACsJSiHghlCAyhf7jfVYjKBmLiX8OgpWeW+fjJ2b+Az69aPFPkUOY6xQ==
-  dependencies:
-    mime-db "1.46.0"
-
-mime@^2.3.1:
-  version "2.5.2"
-  resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe"
-  integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==
-
-mimic-fn@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
-  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
-
-minimist@^1.2.5:
-  version "1.2.5"
-  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602"
-  integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==
-
[email protected]:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
-  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-neo-async@^2.6.2:
-  version "2.6.2"
-  resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f"
-  integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==
-
-no-case@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
-  integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
-  dependencies:
-    lower-case "^2.0.2"
-    tslib "^2.0.3"
-
-node-releases@^1.1.70:
-  version "1.1.71"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb"
-  integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==
-
-npm-run-path@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea"
-  integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==
-  dependencies:
-    path-key "^3.0.0"
-
-onetime@^5.1.2:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e"
-  integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==
-  dependencies:
-    mimic-fn "^2.1.0"
-
-opener@^1.5.2:
-  version "1.5.2"
-  resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598"
-  integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==
-
-p-limit@^2.2.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1"
-  integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==
-  dependencies:
-    p-try "^2.0.0"
-
-p-limit@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b"
-  integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==
-  dependencies:
-    yocto-queue "^0.1.0"
-
-p-locate@^4.1.0:
-  version "4.1.0"
-  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07"
-  integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==
-  dependencies:
-    p-limit "^2.2.0"
-
-p-try@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
-  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
-
-path-exists@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
-  integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==
-
-path-key@^3.0.0, path-key@^3.1.0:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375"
-  integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==
-
-path-parse@^1.0.6:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
-  integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
-
-path@^0.12.7:
-  version "0.12.7"
-  resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
-  integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=
-  dependencies:
-    process "^0.11.1"
-    util "^0.10.3"
-
-picomatch@^2.0.5:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad"
-  integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==
-
-pkg-dir@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3"
-  integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==
-  dependencies:
-    find-up "^4.0.0"
-
-postmate@^1.5.2:
-  version "1.5.2"
-  resolved "https://registry.yarnpkg.com/postmate/-/postmate-1.5.2.tgz#d59a78b3780023c5d32225fd40633b364958bdb3"
-  integrity sha512-EHLlEmrUA/hALls49oBrtE7BzDXXjB9EiO4MZpsoO3R/jRuBmD+2WKQuYAbeuVEpTzrPpUTT79z2cz4qaFgPRg==
-
-process-nextick-args@~2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
-  integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
-
-process@^0.11.1:
-  version "0.11.10"
-  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
-  integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
-
-prr@~1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
-  integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
-
-punycode@^2.1.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
-  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
-
-randombytes@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
-  integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
-  dependencies:
-    safe-buffer "^5.1.0"
-
-readable-stream@^2.0.1:
-  version "2.3.7"
-  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57"
-  integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==
-  dependencies:
-    core-util-is "~1.0.0"
-    inherits "~2.0.3"
-    isarray "~1.0.0"
-    process-nextick-args "~2.0.0"
-    safe-buffer "~5.1.1"
-    string_decoder "~1.1.1"
-    util-deprecate "~1.0.1"
-
-rechoir@^0.7.0:
-  version "0.7.0"
-  resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.7.0.tgz#32650fd52c21ab252aa5d65b19310441c7e03aca"
-  integrity sha512-ADsDEH2bvbjltXEP+hTIAmeFekTFK0V2BTxMkok6qILyAJEXV0AFfoWcAq4yfll5VdIMd/RVXq0lR+wQi5ZU3Q==
-  dependencies:
-    resolve "^1.9.0"
-
-resolve-cwd@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d"
-  integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==
-  dependencies:
-    resolve-from "^5.0.0"
-
-resolve-from@^5.0.0:
-  version "5.0.0"
-  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69"
-  integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==
-
-resolve@^1.9.0:
-  version "1.20.0"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.20.0.tgz#629a013fb3f70755d6f0b7935cc1c2c5378b1975"
-  integrity sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==
-  dependencies:
-    is-core-module "^2.2.0"
-    path-parse "^1.0.6"
-
-safe-buffer@^5.1.0:
-  version "5.2.1"
-  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6"
-  integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==
-
-safe-buffer@~5.1.0, safe-buffer@~5.1.1:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
-  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-schema-utils@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.0.0.tgz#67502f6aa2b66a2d4032b4279a2944978a0913ef"
-  integrity sha512-6D82/xSzO094ajanoOSbe4YvXWMfn2A//8Y1+MUqFAJul5Bs+yn36xbK9OtNDcRVSBJ9jjeoXftM6CfztsjOAA==
-  dependencies:
-    "@types/json-schema" "^7.0.6"
-    ajv "^6.12.5"
-    ajv-keywords "^3.5.2"
-
-semver@^7.3.4:
-  version "7.3.4"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.4.tgz#27aaa7d2e4ca76452f98d3add093a72c943edc97"
-  integrity sha512-tCfb2WLjqFAtXn4KEdxIhalnRtoKFN7nAwj0B3ZXCbQloV2tq5eDbcTmT68JJD3nRJq24/XgxtQKFIpQdtvmVw==
-  dependencies:
-    lru-cache "^6.0.0"
-
-serialize-javascript@^5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
-  integrity sha512-SaaNal9imEO737H2c05Og0/8LUXG7EnsZyMa8MzkmuHoELfT6txuj0cMqRj6zfPKnmQ1yasR4PCJc8x+M4JSPA==
-  dependencies:
-    randombytes "^2.1.0"
-
-shallow-clone@^3.0.0:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"
-  integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==
-  dependencies:
-    kind-of "^6.0.2"
-
-shebang-command@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea"
-  integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==
-  dependencies:
-    shebang-regex "^3.0.0"
-
-shebang-regex@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172"
-  integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==
-
-signal-exit@^3.0.3:
-  version "3.0.3"
-  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
-  integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
-
-sirv@^1.0.7:
-  version "1.0.11"
-  resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.11.tgz#81c19a29202048507d6ec0d8ba8910fda52eb5a4"
-  integrity sha512-SR36i3/LSWja7AJNRBz4fF/Xjpn7lQFI30tZ434dIy+bitLYSP+ZEenHg36i23V2SGEz+kqjksg0uOGZ5LPiqg==
-  dependencies:
-    "@polka/url" "^1.0.0-next.9"
-    mime "^2.3.1"
-    totalist "^1.0.0"
-
-snake-case@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c"
-  integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==
-  dependencies:
-    dot-case "^3.0.4"
-    tslib "^2.0.3"
-
-source-list-map@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
-  integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
-
-source-map-support@~0.5.19:
-  version "0.5.19"
-  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.19.tgz#a98b62f86dcaf4f67399648c085291ab9e8fed61"
-  integrity sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==
-  dependencies:
-    buffer-from "^1.0.0"
-    source-map "^0.6.0"
-
-source-map@^0.6.0, source-map@^0.6.1:
-  version "0.6.1"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
-  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-
-source-map@~0.7.2:
-  version "0.7.3"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383"
-  integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==
-
-string_decoder@~1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
-  integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
-  dependencies:
-    safe-buffer "~5.1.0"
-
-strip-final-newline@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad"
-  integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==
-
-supports-color@^7.0.0, supports-color@^7.1.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
-  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
-  dependencies:
-    has-flag "^4.0.0"
-
-tapable@^1.0.0:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
-  integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
-
-tapable@^2.1.1, tapable@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.0.tgz#5c373d281d9c672848213d0e037d1c4165ab426b"
-  integrity sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==
-
-terser-webpack-plugin@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-5.1.1.tgz#7effadee06f7ecfa093dbbd3e9ab23f5f3ed8673"
-  integrity sha512-5XNNXZiR8YO6X6KhSGXfY0QrGrCRlSwAEjIIrlRQR4W8nP69TaJUlh3bkuac6zzgspiGPfKEHcY295MMVExl5Q==
-  dependencies:
-    jest-worker "^26.6.2"
-    p-limit "^3.1.0"
-    schema-utils "^3.0.0"
-    serialize-javascript "^5.0.1"
-    source-map "^0.6.1"
-    terser "^5.5.1"
-
-terser@^5.5.1:
-  version "5.6.0"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-5.6.0.tgz#138cdf21c5e3100b1b3ddfddf720962f88badcd2"
-  integrity sha512-vyqLMoqadC1uR0vywqOZzriDYzgEkNJFK4q9GeyOBHIbiECHiWLKcWfbQWAUaPfxkjDhapSlZB9f7fkMrvkVjA==
-  dependencies:
-    commander "^2.20.0"
-    source-map "~0.7.2"
-    source-map-support "~0.5.19"
-
-to-regex-range@^5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
-  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
-  dependencies:
-    is-number "^7.0.0"
-
-totalist@^1.0.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df"
-  integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g==
-
-ts-loader@^8.0.17:
-  version "8.0.17"
-  resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.0.17.tgz#98f2ccff9130074f4079fd89b946b4c637b1f2fc"
-  integrity sha512-OeVfSshx6ot/TCxRwpBHQ/4lRzfgyTkvi7ghDVrLXOHzTbSK413ROgu/xNqM72i3AFeAIJgQy78FwSMKmOW68w==
-  dependencies:
-    chalk "^4.1.0"
-    enhanced-resolve "^4.0.0"
-    loader-utils "^2.0.0"
-    micromatch "^4.0.0"
-    semver "^7.3.4"
-
-tslib@^1.9.0:
-  version "1.14.1"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
-  integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
-
-tslib@^2.0.3:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
-  integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
-
-typescript@^4.2.2:
-  version "4.2.2"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.2.tgz#1450f020618f872db0ea17317d16d8da8ddb8c4c"
-  integrity sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ==
-
-uri-js@^4.2.2:
-  version "4.4.1"
-  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
-  integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
-  dependencies:
-    punycode "^2.1.0"
-
-util-deprecate@~1.0.1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
-  integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
-
-util@^0.10.3:
-  version "0.10.4"
-  resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
-  integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
-  dependencies:
-    inherits "2.0.3"
-
-v8-compile-cache@^2.2.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.2.0.tgz#9471efa3ef9128d2f7c6a7ca39c4dd6b5055b132"
-  integrity sha512-gTpR5XQNKFwOd4clxfnhaqvfqMpqEwr4tOtCyz4MtYZX2JYhfr1JvBFKdS+7K/9rfpZR3VLX+YWBbKoxCgS43Q==
-
-watchpack@^2.0.0:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-2.1.1.tgz#e99630550fca07df9f90a06056987baa40a689c7"
-  integrity sha512-Oo7LXCmc1eE1AjyuSBmtC3+Wy4HcV8PxWh2kP6fOl8yTlNS7r0K9l1ao2lrrUza7V39Y3D/BbJgY8VeSlc5JKw==
-  dependencies:
-    glob-to-regexp "^0.4.1"
-    graceful-fs "^4.1.2"
-
-webpack-bundle-analyzer@^4.4.0:
-  version "4.4.0"
-  resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.0.tgz#74013106e7e2b07cbd64f3a5ae847f7e814802c7"
-  integrity sha512-9DhNa+aXpqdHk8LkLPTBU/dMfl84Y+WE2+KnfI6rSpNRNVKa0VGLjPd2pjFubDeqnWmulFggxmWBxhfJXZnR0g==
-  dependencies:
-    acorn "^8.0.4"
-    acorn-walk "^8.0.0"
-    chalk "^4.1.0"
-    commander "^6.2.0"
-    gzip-size "^6.0.0"
-    lodash "^4.17.20"
-    opener "^1.5.2"
-    sirv "^1.0.7"
-    ws "^7.3.1"
-
-webpack-cli@^4.5.0:
-  version "4.5.0"
-  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-4.5.0.tgz#b5213b84adf6e1f5de6391334c9fa53a48850466"
-  integrity sha512-wXg/ef6Ibstl2f50mnkcHblRPN/P9J4Nlod5Hg9HGFgSeF8rsqDGHJeVe4aR26q9l62TUJi6vmvC2Qz96YJw1Q==
-  dependencies:
-    "@discoveryjs/json-ext" "^0.5.0"
-    "@webpack-cli/configtest" "^1.0.1"
-    "@webpack-cli/info" "^1.2.2"
-    "@webpack-cli/serve" "^1.3.0"
-    colorette "^1.2.1"
-    commander "^7.0.0"
-    enquirer "^2.3.6"
-    execa "^5.0.0"
-    fastest-levenshtein "^1.0.12"
-    import-local "^3.0.2"
-    interpret "^2.2.0"
-    rechoir "^0.7.0"
-    v8-compile-cache "^2.2.0"
-    webpack-merge "^5.7.3"
-
-webpack-merge@^5.7.3:
-  version "5.7.3"
-  resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-5.7.3.tgz#2a0754e1877a25a8bbab3d2475ca70a052708213"
-  integrity sha512-6/JUQv0ELQ1igjGDzHkXbVDRxkfA57Zw7PfiupdLFJYrgFqY5ZP8xxbpp2lU3EPwYx89ht5Z/aDkD40hFCm5AA==
-  dependencies:
-    clone-deep "^4.0.1"
-    wildcard "^2.0.0"
-
-webpack-sources@^2.1.1:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.2.0.tgz#058926f39e3d443193b6c31547229806ffd02bac"
-  integrity sha512-bQsA24JLwcnWGArOKUxYKhX3Mz/nK1Xf6hxullKERyktjNMC4x8koOeaDNTA2fEJ09BdWLbM/iTW0ithREUP0w==
-  dependencies:
-    source-list-map "^2.0.1"
-    source-map "^0.6.1"
-
-webpack@^5.24.3:
-  version "5.24.3"
-  resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.24.3.tgz#6ec0f5059f8d7c7961075fa553cfce7b7928acb3"
-  integrity sha512-x7lrWZ7wlWAdyKdML6YPvfVZkhD1ICuIZGODE5SzKJjqI9A4SpqGTjGJTc6CwaHqn19gGaoOR3ONJ46nYsn9rw==
-  dependencies:
-    "@types/eslint-scope" "^3.7.0"
-    "@types/estree" "^0.0.46"
-    "@webassemblyjs/ast" "1.11.0"
-    "@webassemblyjs/wasm-edit" "1.11.0"
-    "@webassemblyjs/wasm-parser" "1.11.0"
-    acorn "^8.0.4"
-    browserslist "^4.14.5"
-    chrome-trace-event "^1.0.2"
-    enhanced-resolve "^5.7.0"
-    es-module-lexer "^0.4.0"
-    eslint-scope "^5.1.1"
-    events "^3.2.0"
-    glob-to-regexp "^0.4.1"
-    graceful-fs "^4.2.4"
-    json-parse-better-errors "^1.0.2"
-    loader-runner "^4.2.0"
-    mime-types "^2.1.27"
-    neo-async "^2.6.2"
-    schema-utils "^3.0.0"
-    tapable "^2.1.1"
-    terser-webpack-plugin "^5.1.1"
-    watchpack "^2.0.0"
-    webpack-sources "^2.1.1"
-
-which@^2.0.1:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1"
-  integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==
-  dependencies:
-    isexe "^2.0.0"
-
-wildcard@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
-  integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
-
-ws@^7.3.1:
-  version "7.4.4"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.4.tgz#383bc9742cb202292c9077ceab6f6047b17f2d59"
-  integrity sha512-Qm8k8ojNQIMx7S+Zp8u/uHOx7Qazv3Yv4q68MiWWWOJhiwG5W3x7iqmRtJo8xxrciZUY4vRxUTJCKuRnF28ZZw==
-
-yallist@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72"
-  integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==
-
-yocto-queue@^0.1.0:
-  version "0.1.0"
-  resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"
-  integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==

+ 0 - 132
src/main/api.cljs

@@ -1,137 +1,10 @@
 (ns ^:no-doc api
   (:require [frontend.db :as db]
-            [frontend.db.model :as db-model]
-            [frontend.handler.block :as block-handler]
-            [frontend.util :as util]
-            [electron.ipc :as ipc]
-            [promesa.core :as p]
-            [camel-snake-kebab.core :as csk]
-            [cljs-bean.core :as bean]
             [frontend.state :as state]
-            [frontend.components.plugins :as plugins]
-            [frontend.handler.plugin :as plugin-handler]
-            [frontend.handler.notification :as notification]
             [datascript.core :as d]
-            [frontend.fs :as fs]
-            [clojure.string :as string]
-            [clojure.walk :as walk]
             [cljs.reader]
-            [reitit.frontend.easy :as rfe]
             [frontend.db.query-dsl :as query-dsl]))
 
-;; base
-(def ^:export show_themes
-  (fn []
-    (plugins/open-select-theme!)))
-
-(def ^:export set_theme_mode
-  (fn [mode]
-    (state/set-theme! (if (= mode "light") "white" "dark"))))
-
-(def ^:export load_plugin_config
-  (fn [path]
-    (fs/read-file "" (util/node-path.join path "package.json"))))
-
-(def ^:export load_plugin_readme
-  (fn [path]
-    (fs/read-file "" (util/node-path.join path "readme.md"))))
-
-(def ^:export save_plugin_config
-  (fn [path ^js data]
-    (let [repo ""
-          path (util/node-path.join path "package.json")]
-      (fs/write-file! repo "" path (js/JSON.stringify data nil 2) {:skip-mtime? true}))))
-
-(def ^:export write_user_tmp_file
-  (fn [file content]
-    (p/let [repo ""
-            path (plugin-handler/get-ls-dotdir-root)
-            path (util/node-path.join path "tmp")
-            exist? (fs/file-exists? path "")
-            _ (when-not exist? (fs/mkdir! path))
-            path (util/node-path.join path file)
-            _ (fs/write-file! repo "" path content {:skip-mtime? true})]
-      path)))
-
-(def ^:export load_user_preferences
-  (fn []
-    (p/let [repo ""
-            path (plugin-handler/get-ls-dotdir-root)
-            path (util/node-path.join path "preferences.json")
-            _ (fs/create-if-not-exists repo "" path)
-            json (fs/read-file "" path)
-            json (if (string/blank? json) "{}" json)]
-      (js/JSON.parse json))))
-
-(def ^:export save_user_preferences
-  (fn [^js data]
-    (when data
-      (p/let [repo ""
-              path (plugin-handler/get-ls-dotdir-root)
-              path (util/node-path.join path "preferences.json")]
-        (fs/write-file! repo "" path (js/JSON.stringify data nil 2) {:skip-mtime? true})))))
-
-(def ^:export load_plugin_user_settings
-  (fn [key]
-    (p/let [repo ""
-            path (plugin-handler/get-ls-dotdir-root)
-            exist? (fs/file-exists? path "settings")
-            _ (when-not exist? (fs/mkdir! (util/node-path.join path "settings")))
-            path (util/node-path.join path "settings" (str key ".json"))
-            _ (fs/create-if-not-exists repo "" path "{}")
-            json (fs/read-file "" path)]
-      [path (js/JSON.parse json)])))
-
-(def ^:export save_plugin_user_settings
-  (fn [key ^js data]
-    (p/let [repo ""
-            path (plugin-handler/get-ls-dotdir-root)
-            path (util/node-path.join path "settings" (str key ".json"))]
-      (fs/write-file! repo "" path (js/JSON.stringify data nil 2) {:skip-mtime? true}))))
-
-(def ^:export register_plugin_slash_command
-  (fn [pid ^js cmd-actions]
-    (when-let [[cmd actions] (bean/->clj cmd-actions)]
-      (plugin-handler/register-plugin-slash-command
-        pid [cmd (mapv #(into [(keyword (first %))]
-                              (rest %)) actions)]))))
-
-(def ^:export register_plugin_simple_command
-  (fn [pid ^js cmd-action]
-    (when-let [[cmd action] (bean/->clj cmd-action)]
-      (plugin-handler/register-plugin-simple-command
-        pid cmd (assoc action 0 (keyword (first action)))))))
-
-;; app
-(def ^:export push_state
-  (fn [^js k ^js params]
-    (rfe/push-state
-      (keyword k) (bean/->clj params))))
-
-(def ^:export replace_state
-  (fn [^js k ^js params]
-    (rfe/replace-state
-      (keyword k) (bean/->clj params))))
-
-;; editor
-(def ^:export get_current_page_blocks_tree
-  (fn []
-    (when-let [page (state/get-current-page)]
-      (let [blocks (db-model/get-page-blocks-no-cache page)
-            blocks (mapv #(-> %
-                              (dissoc :block/children)
-                              (assoc :block/uuid (str (:block/uuid %))))
-                         blocks)
-            blocks (block-handler/blocks->vec-tree blocks)
-            ;; clean key
-            blocks (walk/postwalk
-                     (fn [a]
-                       (if (keyword? a)
-                         (csk/->camelCase (name a))
-                         a)) blocks)]
-        (bean/->js blocks)))))
-
-;; db
 (defn ^:export q
   [query-string]
   (when-let [repo (state/get-current-repo)]
@@ -148,8 +21,3 @@
         (clj->js result)))))
 
 (def ^:export custom_query db/custom-query)
-
-;; helpers
-(defn ^:export show_msg
-  ([content] (show_msg content :success))
-  ([content status] (notification/show! content (keyword status))))

+ 0 - 154
src/main/frontend/components/plugins.cljs

@@ -1,154 +0,0 @@
-(ns frontend.components.plugins
-  (:require [rum.core :as rum]
-            [frontend.state :as state]
-            [cljs-bean.core :as bean]
-            [frontend.ui :as ui]
-            [frontend.util :as util]
-            [electron.ipc :as ipc]
-            [promesa.core :as p]
-            [frontend.components.svg :as svg]
-            [frontend.handler.notification :as notification]
-            [frontend.handler.plugin :as plugin-handler]))
-
-(rum/defc installed-themes
-  < rum/reactive
-  []
-  (let [themes (state/sub :plugin/installed-themes)
-        selected (state/sub :plugin/selected-theme)]
-    [:div.cp__themes-installed
-     [:h2.mb-4.text-xl "Installed Themes"]
-     (for [opt themes]
-       (let [current-selected (= selected (:url opt))]
-         [:div.it.flex.px-3.py-2.mb-2.rounded-sm.justify-between
-          {:key   (:url opt)
-           :class [(if current-selected "selected")]
-           :on-click #(do (js/LSPluginCore.selectTheme (if current-selected nil (clj->js opt)))
-                          (state/set-modal! nil))}
-          [:section
-           [:strong.block (:name opt)]
-           [:small.opacity-30 (:description opt)]]
-          [:small.flex-shrink-0.flex.items-center.opacity-10
-           (if current-selected "current")]]))]))
-
-(rum/defc unpacked-plugin-loader
-  [unpacked-pkg-path]
-  (rum/use-effect!
-   (fn []
-     (let [err-handle
-           (fn [^js e]
-             (case (keyword (aget e "name"))
-               :IllegalPluginPackageError
-               (notification/show! "Illegal Logseq plugin package." :error)
-               :ExistedImportedPluginPackageError
-               (notification/show! "Existed Imported plugin package." :error)
-               :default)
-             (plugin-handler/reset-unpacked-state))
-           reg-handle #(plugin-handler/reset-unpacked-state)]
-       (when unpacked-pkg-path
-         (doto js/LSPluginCore
-           (.once "error" err-handle)
-           (.once "registered" reg-handle)
-           (.register (bean/->js {:url unpacked-pkg-path}))))
-       #(doto js/LSPluginCore
-          (.off "error" err-handle)
-          (.off "registered" reg-handle))))
-   [unpacked-pkg-path])
-
-  (when unpacked-pkg-path
-    [:strong.inline-flex.px-3 "Loading ..."]))
-
-(rum/defc simple-markdown-display
-  < rum/reactive
-  []
-  (let [content (state/sub :plugin/active-readme)]
-    [:textarea.p-1.bg-transparent.border-none
-     {:style {:width "700px" :min-height "60vw"}}
-     content]))
-
-(rum/defc plugin-item-card
-  [{:keys [id name settings version url description author icon usf] :as item}]
-  (let [disabled (:disabled settings)]
-    [:div.cp__plugins-item-card
-     [:div.l.link-block
-      {:on-click #(plugin-handler/open-readme! url simple-markdown-display)}
-      (if icon
-        [:img.icon {:src icon}]
-        svg/folder)]
-     [:div.r
-      [:h3.head.text-xl.font-bold.pt-1.5
-       {:on-click #(plugin-handler/open-readme! url simple-markdown-display)}
-       [:span name]
-       [:sup.inline-block.px-1.text-xs.opacity-30 version]]
-      [:div.desc.text-xs.opacity-60
-       [:p description]
-       [:small (js/JSON.stringify (bean/->js settings))]]
-      [:div.flag
-       [:p.text-xs.text-gray-300.pr-2.flex.justify-between.dark:opacity-40
-        [:small author]
-        [:small (str "ID: " id)]]]
-
-      [:div.ctl
-       [:div.l
-        [:div.de
-         [:strong svg/settings-sm]
-         [:ul.menu-list
-          [:li {:on-click #(if usf (js/apis.openPath usf))} "Open settings"]
-          [:li {:on-click
-                #(let [confirm-fn
-                       (ui/make-confirm-modal
-                        {:title      (str "Are you sure uninstall plugin - " name "?")
-                         :on-confirm (fn [_ {:keys [close-fn]}]
-                                       (close-fn)
-                                       (plugin-handler/unregister-plugin id))})]
-                   (state/set-modal! confirm-fn))}
-           "Uninstall plugin"]]]]
-
-       [:div.flex.items-center
-        [:small.de (if disabled "Disabled" "Enabled")]
-        (ui/toggle (not disabled)
-                   (fn []
-                     (js-invoke js/LSPluginCore (if disabled "enable" "disable") id))
-                   true)]]]]))
-
-(rum/defc installed-page
-  < rum/reactive
-  []
-  (let [installed-plugins (state/sub :plugin/installed-plugins)
-        selected-unpacked-pkg (state/sub :plugin/selected-unpacked-pkg)]
-    [:div.cp__plugins-page-installed
-     [:h1 "Installed Plugins"]
-     [:div.mb-6.flex.items-center.justify-between
-      (ui/button
-       "Load unpacked plugin"
-       :intent "logseq"
-       :on-click plugin-handler/load-unpacked-plugin)
-      (unpacked-plugin-loader selected-unpacked-pkg)
-      (when (util/electron?)
-        (ui/button
-         [:span.flex.items-center
-           ;;svg/settings-sm
-          "Open plugin preferences file"]
-         :intent "logseq"
-         :on-click (fn []
-                     (p/let [root (plugin-handler/get-ls-dotdir-root)]
-                       (js/apis.openPath (str root "/preferences.json"))))))]
-
-     [:div.cp__plugins-item-lists.grid-cols-1.md:grid-cols-2.lg:grid-cols-3
-      (for [[_ item] installed-plugins]
-        (rum/with-key (plugin-item-card item) (:id item)))]]))
-
-(defn open-select-theme!
-  []
-  (state/set-modal! installed-themes))
-
-(rum/defc hook-ui-slot
-  ([type payload] (hook-ui-slot type payload nil))
-  ([type payload opts]
-   (let [id (str "slot__" (util/rand-str 8))]
-     (rum/use-effect!
-       (fn []
-         (plugin-handler/hook-plugin-app type {:slot id :payload payload} nil)
-         #())
-       [])
-     [:div.lsp-hook-ui-slot
-      (merge opts {:id id})])))

+ 0 - 185
src/main/frontend/components/plugins.css

@@ -1,185 +0,0 @@
-.cp__plugins {
-  &-page-installed {
-    min-height: 60vh;
-    padding-top: 20px;
-
-    > h1 {
-      padding: 20px 0;
-      font-size: 38px;
-    }
-  }
-
-  &-item-lists {
-    @apply w-full grid grid-flow-row gap-3 pt-1;
-  }
-
-  &-item-card {
-    @apply flex py-3 px-1 rounded-md;
-
-    background-color: var(--ls-secondary-background-color);
-    height: 180px;
-
-    svg, .icon {
-      width: 70px;
-      height: 70px;
-      opacity: .8;
-
-      &:hover {
-        opacity: 1;
-      }
-    }
-
-    .head {
-      max-height: 60px;
-      overflow: hidden;
-
-      cursor: pointer;
-
-      &:active {
-        opacity: .8;
-      }
-    }
-
-    .desc {
-      height: 60px;
-      overflow: hidden;
-    }
-
-    .flag {
-      position: absolute;
-      bottom: 20px;
-      left: 0;
-      width: 100%;
-    }
-
-    > .l {
-      padding: 8px;
-    }
-
-    > .r {
-      flex: 1;
-      position: relative;
-
-      p {
-        @apply py-1 m-0;
-      }
-
-      .ctl {
-        @apply flex pl-2 items-center justify-between absolute w-full;
-
-        bottom: -8px;
-        right: 8px;
-
-        .de {
-          font-size: 10px;
-          padding: 5px 0;
-          padding-right: 10px;
-          border-radius: 2px;
-          user-select: none;
-          transition: none;
-          opacity: .2;
-          position: relative;
-
-          .menu-list {
-            @apply shadow-md rounded-sm absolute hidden list-none overflow-hidden m-0 p-0;
-
-            background-color: var(--ls-primary-background-color);
-            top: 20px;
-            left: 0;
-            min-width: 100px;
-
-            > li {
-              margin: 0;
-              padding: 3px;
-              transition: background-color .2s;
-              user-select: none;
-              opacity: .8;
-
-              &:hover {
-                background-color: var(--ls-quaternary-background-color);
-
-                &:active {
-                  opacity: 1;
-                }
-              }
-            }
-          }
-
-          &.err {
-            @apply text-red-500 opacity-100;
-          }
-
-          &.log {
-            padding: 5px;
-          }
-
-          svg {
-            width: 13px;
-            height: 13px;
-          }
-        }
-
-        > .l {
-          @apply flex items-center;
-
-          margin-left: -80px;
-
-          .de {
-            &:hover {
-              opacity: .9;
-
-              .menu-list {
-                display: block;
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-}
-
-.cp__themes {
-  &-installed {
-    min-width: 480px;
-
-    > .it {
-      user-select: none;
-      cursor: pointer;
-      background-color: var(--ls-secondary-background-color);
-      border: 1px solid transparent;
-      transition: background-color .3s;
-
-      &:hover, &.selected {
-        background-color: var(--ls-quaternary-background-color);
-      }
-    }
-  }
-}
-
-.lsp-iframe-sandbox, .lsp-shadow-sandbox {
-  position: absolute;
-  top: 0;
-  left: 0;
-  z-index: -1;
-  visibility: hidden;
-  height: 0;
-  width: 0;
-  padding: 0;
-  margin: 0;
-
-  &.visible {
-    z-index: 1;
-    width: 100vw;
-    height: 100vh;
-    visibility: visible;
-  }
-}
-
-body {
-  &[data-page=page] {
-    .lsp-hook-ui-slot {
-      @apply flex items-center px-1 opacity-70;
-    }
-  }
-}

+ 0 - 181
src/main/frontend/handler/plugin.cljs

@@ -1,181 +0,0 @@
-(ns frontend.handler.plugin
-  (:require [promesa.core :as p]
-            [rum.core :as rum]
-            [frontend.util :as util]
-            [frontend.fs :as fs]
-            [frontend.handler.notification :as notifications]
-            [camel-snake-kebab.core :as csk]
-            [frontend.state :as state]
-            [medley.core :as md]
-            [electron.ipc :as ipc]
-            [cljs-bean.core :as bean]
-            [clojure.string :as string]))
-
-(defonce lsp-enabled? (util/electron?))
-
-;; state handlers
-(defn register-plugin
-  [pl]
-  (swap! state/state update-in [:plugin/installed-plugins] assoc (keyword (:id pl)) pl))
-
-(defn unregister-plugin
-  [id]
-  (js/LSPluginCore.unregister id))
-
-(defn host-mounted!
-  []
-  (and lsp-enabled? (js/LSPluginCore.hostMounted)))
-
-(defn register-plugin-slash-command
-  [pid [cmd actions]]
-  (prn (if-let [pid (keyword pid)]
-         (when (contains? (:plugin/installed-plugins @state/state) pid)
-           (do (swap! state/state update-in [:plugin/installed-commands pid]
-                      (fnil merge {}) (hash-map cmd (mapv #(conj % {:pid pid}) actions)))
-               true)))))
-
-(defn unregister-plugin-slash-command
-  [pid]
-  (swap! state/state md/dissoc-in [:plugin/installed-commands (keyword pid)]))
-
-(defn register-plugin-simple-command
-  ;; action => [:action-key :event-key]
-  [pid {:keys [key label type] :as cmd}  action]
-  (if-let [pid (keyword pid)]
-    (when (contains? (:plugin/installed-plugins @state/state) pid)
-      (do (swap! state/state update-in [:plugin/simple-commands pid]
-                 (fnil conj []) [type cmd action pid])
-          true))))
-
-(defn unregister-plugin-simple-command
-  [pid]
-  (swap! state/state md/dissoc-in [:plugin/simple-commands (keyword pid)]))
-
-(defn update-plugin-settings
-  [id settings]
-  (swap! state/state update-in [:plugin/installed-plugins id] assoc :settings settings))
-
-(defn open-readme!
-  [url display]
-  (when url
-    (-> (p/let [content (js/api.load_plugin_readme url)]
-          (state/set-state! :plugin/active-readme content)
-          (state/set-modal! display))
-        (p/catch #(notifications/show! "No README file." :warn)))))
-
-(defn load-unpacked-plugin
-  []
-  (if util/electron?
-    (p/let [path (ipc/ipc "openDialogSync")]
-      (when-not (:plugin/selected-unpacked-pkg @state/state)
-        (state/set-state! :plugin/selected-unpacked-pkg path)))))
-
-(defn reset-unpacked-state
-  []
-  (state/set-state! :plugin/selected-unpacked-pkg nil))
-
-(defn hook-plugin
-  [tag type payload plugin-id]
-  (when lsp-enabled?
-    (js-invoke js/LSPluginCore
-               (str "hook" (string/capitalize (name tag)))
-               (name type)
-               (if (map? payload)
-                 (bean/->js (into {} (for [[k v] payload] [(csk/->camelCase k) (if (uuid? v) (str v) v)]))))
-               (if (keyword? plugin-id) (name plugin-id) plugin-id))))
-
-(defn hook-plugin-app
-  ([type payload] (hook-plugin-app type payload nil))
-  ([type payload plugin-id] (hook-plugin :app type payload plugin-id)))
-
-(defn hook-plugin-editor
-  ([type payload] (hook-plugin-editor type payload nil))
-  ([type payload plugin-id] (hook-plugin :editor type payload plugin-id)))
-
-(defn get-ls-dotdir-root
-  []
-  (ipc/ipc "getLogseqDotDirRoot"))
-
-(defn- get-user-default-plugins
-  []
-  (p/catch
-   (p/let [files ^js (ipc/ipc "getUserDefaultPlugins")
-           files (js->clj files)]
-     (map #(hash-map :url %) files))
-   (fn [e]
-     (js/console.error e))))
-
-;; components
-(rum/defc lsp-indicator < rum/reactive
-  []
-  (let [text (state/sub :plugin/indicator-text)]
-    (if (= text "END")
-      [:span]
-      [:div
-       {:style
-        {:width           "100%"
-         :height          "100vh"
-         :display         "flex"
-         :align-items     "center"
-         :justify-content "center"}}
-       [:span
-        {:style
-         {:color     "#aaa"
-          :font-size "38px"}} (or text "Loading ...")]])))
-
-(defn init-plugins
-  [callback]
-
-  (let [el (js/document.createElement "div")]
-    (.appendChild js/document.body el)
-    (rum/mount
-     (lsp-indicator) el))
-
-  (state/set-state! :plugin/indicator-text "Loading...")
-
-  (p/then
-   (p/let [root (get-ls-dotdir-root)
-           _ (.setupPluginCore js/LSPlugin (bean/->js {:localUserConfigRoot root}))
-           _ (doto js/LSPluginCore
-               (.on "registered"
-                    (fn [^js pl]
-                      (register-plugin
-                       (bean/->clj (.parse js/JSON (.stringify js/JSON pl))))))
-
-               (.on "unregistered" (fn [pid]
-                                     (let [pid (keyword pid)]
-                                        ;; plugins
-                                       (swap! state/state md/dissoc-in [:plugin/installed-plugins (keyword pid)])
-                                        ;; commands
-                                       (unregister-plugin-slash-command pid))))
-
-               (.on "theme-changed" (fn [^js themes]
-                                      (swap! state/state assoc :plugin/installed-themes
-                                             (vec (mapcat (fn [[_ vs]] (bean/->clj vs)) (bean/->clj themes))))))
-
-               (.on "theme-selected" (fn [^js opts]
-                                       (let [opts (bean/->clj opts)
-                                             url (:url opts)
-                                             mode (:mode opts)]
-                                         (when mode (state/set-theme! mode))
-                                         (state/set-state! :plugin/selected-theme url))))
-
-               (.on "settings-changed" (fn [id ^js settings]
-                                         (let [id (keyword id)]
-                                           (when (and settings
-                                                      (contains? (:plugin/installed-plugins @state/state) id))
-                                             (update-plugin-settings id (bean/->clj settings)))))))
-
-           default-plugins (get-user-default-plugins)
-
-           _ (.register js/LSPluginCore (bean/->js (if (seq default-plugins) default-plugins [])) true)])
-   #(do
-      (state/set-state! :plugin/indicator-text "END")
-      (callback))))
-
-(defn setup!
-  "setup plugin core handler"
-  [callback]
-  (if (not lsp-enabled?)
-    (callback)
-    (init-plugins callback)))