From d8809f0b7e792664ebc067087dc4c78ca31c0ab8 Mon Sep 17 00:00:00 2001 From: Tienson Qin Date: Tue, 21 Oct 2025 16:32:12 +0800 Subject: [PATCH] feat: cljs sdk (#12168) Add clojurescript plugins API --- bb.edn | 9 +- libs/.npmignore | 1 + libs/README.md | 13 + libs/cljs-sdk/.gitignore | 38 ++ libs/cljs-sdk/LICENSE | 21 ++ libs/cljs-sdk/bb.edn | 31 ++ libs/cljs-sdk/build.clj | 46 +++ libs/cljs-sdk/deps.edn | 20 + libs/cljs-sdk/package.json | 27 ++ libs/cljs-sdk/src/com/logseq/app.cljs | 348 +++++++++++++++++ libs/cljs-sdk/src/com/logseq/assets.cljs | 37 ++ libs/cljs-sdk/src/com/logseq/core.cljs | 149 ++++++++ libs/cljs-sdk/src/com/logseq/db.cljs | 34 ++ libs/cljs-sdk/src/com/logseq/editor.cljs | 432 ++++++++++++++++++++++ libs/cljs-sdk/src/com/logseq/git.cljs | 23 ++ libs/cljs-sdk/src/com/logseq/ui.cljs | 49 +++ libs/cljs-sdk/src/com/logseq/util.cljs | 31 ++ libs/cljs-sdk/yarn.lock | 121 ++++++ libs/package.json | 4 +- libs/scripts/extract-sdk-schema.js | 184 +++++++++ libs/src/LSPlugin.core.ts | 4 +- libs/src/LSPlugin.user.ts | 1 + libs/yarn.lock | 147 ++++++++ resources/js/lsplugin.core.js | 2 +- scripts/src/logseq/libs/sdk_generator.clj | 234 ++++++++++++ src/main/logseq/api/db_based.cljs | 9 +- src/main/logseq/sdk/utils.cljs | 22 +- 27 files changed, 2027 insertions(+), 10 deletions(-) create mode 100644 libs/cljs-sdk/.gitignore create mode 100644 libs/cljs-sdk/LICENSE create mode 100644 libs/cljs-sdk/bb.edn create mode 100644 libs/cljs-sdk/build.clj create mode 100644 libs/cljs-sdk/deps.edn create mode 100644 libs/cljs-sdk/package.json create mode 100644 libs/cljs-sdk/src/com/logseq/app.cljs create mode 100644 libs/cljs-sdk/src/com/logseq/assets.cljs create mode 100644 libs/cljs-sdk/src/com/logseq/core.cljs create mode 100644 libs/cljs-sdk/src/com/logseq/db.cljs create mode 100644 libs/cljs-sdk/src/com/logseq/editor.cljs create mode 100644 libs/cljs-sdk/src/com/logseq/git.cljs create mode 100644 libs/cljs-sdk/src/com/logseq/ui.cljs create mode 100644 libs/cljs-sdk/src/com/logseq/util.cljs create mode 100644 libs/cljs-sdk/yarn.lock create mode 100755 libs/scripts/extract-sdk-schema.js create mode 100644 scripts/src/logseq/libs/sdk_generator.clj diff --git a/bb.edn b/bb.edn index 57b9cdbf6a..8caec6962e 100644 --- a/bb.edn +++ b/bb.edn @@ -10,7 +10,9 @@ logseq/graph-parser {:local/root "deps/graph-parser"} org.clj-commons/digest - {:mvn/version "1.4.100"}} + {:mvn/version "1.4.100"} + cheshire/cheshire + {:mvn/version "5.12.0"}} :pods {clj-kondo/clj-kondo {:version "2024.09.27"} org.babashka/fswatcher {:version "0.0.3"} @@ -19,6 +21,11 @@ {dev:desktop-watch logseq.tasks.dev.desktop/watch + libs:generate-cljs-sdk + {:doc "Generate CLJS wrappers based on the JS SDK declarations" + :requires ([logseq.libs.sdk-generator :as sdk-gen]) + :task (sdk-gen/run! (sdk-gen/parse-args *command-line-args*))} + dev:open-dev-electron-app logseq.tasks.dev.desktop/open-dev-electron-app diff --git a/libs/.npmignore b/libs/.npmignore index afb310abc9..a108de303c 100644 --- a/libs/.npmignore +++ b/libs/.npmignore @@ -2,3 +2,4 @@ src/ webpack.* .DS_Store docs/ +cljs-sdk/ \ No newline at end of file diff --git a/libs/README.md b/libs/README.md index b3b6aa6562..7bcfa28c3b 100644 --- a/libs/README.md +++ b/libs/README.md @@ -30,3 +30,16 @@ import "@logseq/libs" #### Feedback If you have any feedback or encounter any issues, feel free to join Logseq's discord group. https://discord.gg/KpN4eHY + +#### Generate CLJS SDK wrappers + +To regenerate the ClojureScript facade from the JS SDK declarations (keeping the same argument shapes as the JS APIs while auto-converting to/from CLJS data): + +```bash +yarn run generate:schema # emits dist/logseq-sdk-schema.json +bb libs:generate-cljs-sdk # emits logseq/core.cljs and per-proxy files under target/generated-cljs +``` + +Non-proxy methods (those defined on `ILSPluginUser`, e.g. `ready`, `provide-ui`) land in `logseq.core`. Each proxy (`IAppProxy`, `IEditorProxy`, ...) is emitted to its own namespace such as `logseq.app` or `logseq.editor`, preserving the original JS argument ordering while automatically bean-converting CLJS data. + +Pass `--out-dir` to change the output location or `--ns-prefix` to pick a different namespace root. diff --git a/libs/cljs-sdk/.gitignore b/libs/cljs-sdk/.gitignore new file mode 100644 index 0000000000..a776cc8289 --- /dev/null +++ b/libs/cljs-sdk/.gitignore @@ -0,0 +1,38 @@ +# Clojure/Leiningen +pom.xml +pom.xml.asc +*.jar +*.class +/lib/ +/classes/ +/target/ +/checkouts/ +.lein-deps-sum +.lein-repl-history +.lein-plugins/ +.lein-failures +.nrepl-port + +# ClojureScript/Build +.cpcache/ +.shadow-cljs/ +dist/ +out/ + +# Node.js +node_modules/ +package-lock.json +coverage/ +.nyc_output/ + +# IDE +.idea/ +.vscode/ +.calva/ +.calva/output-window +.lsp/ +.clj-kondo/ + +# OS +.DS_Store +*.log diff --git a/libs/cljs-sdk/LICENSE b/libs/cljs-sdk/LICENSE new file mode 100644 index 0000000000..8aab574488 --- /dev/null +++ b/libs/cljs-sdk/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Logseq + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/cljs-sdk/bb.edn b/libs/cljs-sdk/bb.edn new file mode 100644 index 0000000000..a53432bf04 --- /dev/null +++ b/libs/cljs-sdk/bb.edn @@ -0,0 +1,31 @@ +{:paths ["src" "test"] + :deps {org.babashka/cli {:mvn/version "0.7.53"} + slipset/deps-deploy {:mvn/version "0.2.1"}} + :tasks + {:requires ([babashka.cli :as cli]) + :init (do + (defn run [cmd] + (let [result (shell cmd)] + (when-not (zero? (:exit result)) + (throw (ex-info "Command failed" result)))))) + + clean {:doc "Clean compiled files" + :task (do + (run "rm -rf dist") + (run "rm -rf .shadow-cljs") + (run "rm -rf node_modules") + (run "rm -rf out") + (run "rm -rf .nyc_output") + (run "rm -rf coverage"))} + + install {:doc "Install dependencies" + :task (run "yarn install")} + + build-jar {:doc "Build jar file" + :task (shell "clojure -T:build jar")} + + deploy {:doc "Deploy jar to Clojars" + :task (shell "clojure -T:build deploy")} + + release {:doc "Build release version and deploy to Clojars" + :depends [clean install build-jar deploy]}}} diff --git a/libs/cljs-sdk/build.clj b/libs/cljs-sdk/build.clj new file mode 100644 index 0000000000..348179d64e --- /dev/null +++ b/libs/cljs-sdk/build.clj @@ -0,0 +1,46 @@ +(ns build + (:require [clojure.data.json :as json] + [clojure.tools.build.api :as b] + [deps-deploy.deps-deploy :as dd])) + +(def lib 'com.logseq/libs) +(def version + (-> (slurp "package.json") + (json/read-str :key-fn keyword) + :version)) +(def class-dir "target/classes") +(def basis (delay (b/create-basis {:project "deps.edn"}))) +(def jar-file (format "target/%s-%s.jar" (name lib) version)) + +(def pom-template + [[:description "ClojureScript wrapper for @logseq/libs"] + [:url "https://github.com/logseq/logseq"] + [:licenses + [:license + [:name "MIT License"] + [:url "https://opensource.org/licenses/MIT"]]]]) + +(def options + {:class-dir class-dir + :lib lib + :version version + :basis @basis + :jar-file jar-file + :src-dirs ["src"] + :pom-data pom-template}) + +(defn clean [_] + (b/delete {:path "target"})) + +(defn jar [_] + (clean nil) + (b/write-pom options) + (b/copy-dir {:src-dirs (:paths @basis) + :target-dir class-dir}) + (b/jar options)) + +(defn deploy [_] + (jar nil) + (dd/deploy {:installer :remote + :artifact jar-file + :pom-file (b/pom-path {:lib lib :class-dir class-dir})})) diff --git a/libs/cljs-sdk/deps.edn b/libs/cljs-sdk/deps.edn new file mode 100644 index 0000000000..da21c47044 --- /dev/null +++ b/libs/cljs-sdk/deps.edn @@ -0,0 +1,20 @@ +{:paths ["src" "test"] + :deps {org.clojure/clojurescript {:mvn/version "1.11.60"} + cljs-bean/cljs-bean {:mvn/version "1.5.0"}} + + :npm-deps {"@logseq/libs" "0.2.3"} + + :aliases + {:dev + {:extra-paths ["example"]} + + :test + {:extra-paths ["test"] + :extra-deps {org.clojure/test.check {:mvn/version "1.1.1"}} + :ns-default build} + + :build + {:deps {io.github.clojure/tools.build {:mvn/version "0.9.6"} + slipset/deps-deploy {:mvn/version "0.2.1"} + org.clojure/data.json {:mvn/version "2.4.0"}} + :ns-default build}}} diff --git a/libs/cljs-sdk/package.json b/libs/cljs-sdk/package.json new file mode 100644 index 0000000000..f234c4acf9 --- /dev/null +++ b/libs/cljs-sdk/package.json @@ -0,0 +1,27 @@ +{ + "name": "@logseq/cljs-libs", + "version": "0.0.10", + "description": "Logseq plugin API wrapper", + "dependencies": { + "@logseq/libs": "^0.2.3" + }, + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/logseq/logseq.git" + }, + "keywords": [ + "logseq", + "clojurescript", + "plugin", + "@logseq/libs" + ], + "author": "logseq", + "license": "MIT", + "bugs": { + "url": "https://github.com/logseq/logseq/issues" + }, + "homepage": "https://github.com/logseq/logseq#readme" +} diff --git a/libs/cljs-sdk/src/com/logseq/app.cljs b/libs/cljs-sdk/src/com/logseq/app.cljs new file mode 100644 index 0000000000..b6289f6734 --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/app.cljs @@ -0,0 +1,348 @@ +;; Auto-generated via `bb libs:generate-cljs-sdk` +(ns com.logseq.app + (:require [com.logseq.core :as core])) + +(def api-proxy (aget js/logseq "App")) + +(defn- get-info-impl + [key] + (let [method (aget api-proxy "getInfo") + args [key]] + (core/call-method api-proxy method args))) + +(defn get-info + ([] + (get-info-impl nil)) + ([key] + (get-info-impl key))) + +(defn get-user-info + [] + (let [method (aget api-proxy "getUserInfo") + args []] + (core/call-method api-proxy method args))) + +(defn get-user-configs + [] + (let [method (aget api-proxy "getUserConfigs") + args []] + (core/call-method api-proxy method args))) + +(defn register-search-service + [s] + (let [method (aget api-proxy "registerSearchService") + args [s]] + (core/call-method api-proxy method args))) + +(defn register-command + [type opts action] + (let [method (aget api-proxy "registerCommand") + args [type opts action]] + (core/call-method api-proxy method args))) + +(defn register-command-palette + [opts action] + (let [method (aget api-proxy "registerCommandPalette") + args [opts action]] + (core/call-method api-proxy method args))) + +(defn- register-command-shortcut-impl + [keybinding action opts] + (let [method (aget api-proxy "registerCommandShortcut") + args [keybinding action opts]] + (core/call-method api-proxy method args))) + +(defn register-command-shortcut + "Supported key names" + ([keybinding action] + (register-command-shortcut-impl keybinding action nil)) + ([keybinding action opts] + (register-command-shortcut-impl keybinding action opts))) + +(defn invoke-external-command + "Supported all registered palette commands" + [type & args] + (let [method (aget api-proxy "invokeExternalCommand") + rest-args (vec args) + args (into [type] rest-args)] + (core/call-method api-proxy method args))) + +(defn invoke-external-plugin + "Call external plugin command provided by models or registered commands" + [type & args] + (let [method (aget api-proxy "invokeExternalPlugin") + rest-args (vec args) + args (into [type] rest-args)] + (core/call-method api-proxy method args))) + +(defn get-external-plugin + [pid] + (let [method (aget api-proxy "getExternalPlugin") + args [pid]] + (core/call-method api-proxy method args))) + +(defn get-state-from-store + "Get state from app store\nvalid state is here\nhttps://github.com/logseq/logseq/blob/master/src/main/frontend/state.cljs#L27" + [path] + (let [method (aget api-proxy "getStateFromStore") + args [path]] + (core/call-method api-proxy method args))) + +(defn set-state-from-store + [path value] + (let [method (aget api-proxy "setStateFromStore") + args [path value]] + (core/call-method api-proxy method args))) + +(defn relaunch + [] + (let [method (aget api-proxy "relaunch") + args []] + (core/call-method api-proxy method args))) + +(defn quit + [] + (let [method (aget api-proxy "quit") + args []] + (core/call-method api-proxy method args))) + +(defn open-external-link + [url] + (let [method (aget api-proxy "openExternalLink") + args [url]] + (core/call-method api-proxy method args))) + +(defn exec-git-command + [args] + (let [method (aget api-proxy "execGitCommand") + args [args]] + (core/call-method api-proxy method args))) + +(defn get-current-graph + [] + (let [method (aget api-proxy "getCurrentGraph") + args []] + (core/call-method api-proxy method args))) + +(defn check-current-is-db-graph + [] + (let [method (aget api-proxy "checkCurrentIsDbGraph") + args []] + (core/call-method api-proxy method args))) + +(defn get-current-graph-configs + [& keys] + (let [method (aget api-proxy "getCurrentGraphConfigs") + rest-keys (vec keys) + args (into [] rest-keys)] + (core/call-method api-proxy method args))) + +(defn set-current-graph-configs + [configs] + (let [method (aget api-proxy "setCurrentGraphConfigs") + args [configs]] + (core/call-method api-proxy method args))) + +(defn get-current-graph-favorites + [] + (let [method (aget api-proxy "getCurrentGraphFavorites") + args []] + (core/call-method api-proxy method args))) + +(defn get-current-graph-recent + [] + (let [method (aget api-proxy "getCurrentGraphRecent") + args []] + (core/call-method api-proxy method args))) + +(defn get-current-graph-templates + [] + (let [method (aget api-proxy "getCurrentGraphTemplates") + args []] + (core/call-method api-proxy method args))) + +(defn- push-state-impl + [k params query] + (let [method (aget api-proxy "pushState") + args [k params query]] + (core/call-method api-proxy method args))) + +(defn push-state + ([k] + (push-state-impl k nil nil)) + ([k params] + (push-state-impl k params nil)) + ([k params query] + (push-state-impl k params query))) + +(defn- replace-state-impl + [k params query] + (let [method (aget api-proxy "replaceState") + args [k params query]] + (core/call-method api-proxy method args))) + +(defn replace-state + ([k] + (replace-state-impl k nil nil)) + ([k params] + (replace-state-impl k params nil)) + ([k params query] + (replace-state-impl k params query))) + +(defn get-template + [name] + (let [method (aget api-proxy "getTemplate") + args [name]] + (core/call-method api-proxy method args))) + +(defn exist-template + [name] + (let [method (aget api-proxy "existTemplate") + args [name]] + (core/call-method api-proxy method args))) + +(defn- create-template-impl + [target name opts] + (let [method (aget api-proxy "createTemplate") + args [target name opts]] + (core/call-method api-proxy method args))) + +(defn create-template + ([target name] + (create-template-impl target name nil)) + ([target name opts] + (create-template-impl target name opts))) + +(defn remove-template + [name] + (let [method (aget api-proxy "removeTemplate") + args [name]] + (core/call-method api-proxy method args))) + +(defn insert-template + [target name] + (let [method (aget api-proxy "insertTemplate") + args [target name]] + (core/call-method api-proxy method args))) + +(defn set-zoom-factor + [factor] + (let [method (aget api-proxy "setZoomFactor") + args [factor]] + (core/call-method api-proxy method args))) + +(defn set-full-screen + [flag] + (let [method (aget api-proxy "setFullScreen") + args [flag]] + (core/call-method api-proxy method args))) + +(defn set-left-sidebar-visible + [flag] + (let [method (aget api-proxy "setLeftSidebarVisible") + args [flag]] + (core/call-method api-proxy method args))) + +(defn set-right-sidebar-visible + [flag] + (let [method (aget api-proxy "setRightSidebarVisible") + args [flag]] + (core/call-method api-proxy method args))) + +(defn- clear-right-sidebar-blocks-impl + [opts] + (let [method (aget api-proxy "clearRightSidebarBlocks") + args [opts]] + (core/call-method api-proxy method args))) + +(defn clear-right-sidebar-blocks + ([] + (clear-right-sidebar-blocks-impl nil)) + ([opts] + (clear-right-sidebar-blocks-impl opts))) + +(defn register-ui-item + [type opts] + (let [method (aget api-proxy "registerUIItem") + args [type opts]] + (core/call-method api-proxy method args))) + +(defn register-page-menu-item + [tag action] + (let [method (aget api-proxy "registerPageMenuItem") + args [tag action]] + (core/call-method api-proxy method args))) + +(defn on-current-graph-changed + [callback] + (let [method (aget api-proxy "onCurrentGraphChanged") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-graph-after-indexed + [callback] + (let [method (aget api-proxy "onGraphAfterIndexed") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-theme-mode-changed + [callback] + (let [method (aget api-proxy "onThemeModeChanged") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-theme-changed + [callback] + (let [method (aget api-proxy "onThemeChanged") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-today-journal-created + [callback] + (let [method (aget api-proxy "onTodayJournalCreated") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-before-command-invoked + [condition callback] + (let [method (aget api-proxy "onBeforeCommandInvoked") + args [condition callback]] + (core/call-method api-proxy method args))) + +(defn on-after-command-invoked + [condition callback] + (let [method (aget api-proxy "onAfterCommandInvoked") + args [condition callback]] + (core/call-method api-proxy method args))) + +(defn on-block-renderer-slotted + "provide ui slot to specific block with UUID" + [condition callback] + (let [method (aget api-proxy "onBlockRendererSlotted") + args [condition callback]] + (core/call-method api-proxy method args))) + +(defn on-macro-renderer-slotted + "provide ui slot to block `renderer` macro for `{{renderer arg1, arg2}}`" + [callback] + (let [method (aget api-proxy "onMacroRendererSlotted") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-page-head-actions-slotted + [callback] + (let [method (aget api-proxy "onPageHeadActionsSlotted") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-route-changed + [callback] + (let [method (aget api-proxy "onRouteChanged") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-sidebar-visible-changed + [callback] + (let [method (aget api-proxy "onSidebarVisibleChanged") + args [callback]] + (core/call-method api-proxy method args))) diff --git a/libs/cljs-sdk/src/com/logseq/assets.cljs b/libs/cljs-sdk/src/com/logseq/assets.cljs new file mode 100644 index 0000000000..0fb8316a58 --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/assets.cljs @@ -0,0 +1,37 @@ +;; Auto-generated via `bb libs:generate-cljs-sdk` +(ns com.logseq.assets + (:require [com.logseq.core :as core])) + +(def api-proxy (aget js/logseq "Assets")) + +(defn- list-files-of-current-graph-impl + [exts] + (let [method (aget api-proxy "listFilesOfCurrentGraph") + args [exts]] + (core/call-method api-proxy method args))) + +(defn list-files-of-current-graph + ([] + (list-files-of-current-graph-impl nil)) + ([exts] + (list-files-of-current-graph-impl exts))) + +(defn make-sandbox-storage + [] + (let [method (aget api-proxy "makeSandboxStorage") + args []] + (core/call-method api-proxy method args))) + +(defn make-url + "make assets scheme url based on current graph" + [path] + (let [method (aget api-proxy "makeUrl") + args [path]] + (core/call-method api-proxy method args))) + +(defn built-in-open + "try to open asset type file in Logseq app" + [path] + (let [method (aget api-proxy "builtInOpen") + args [path]] + (core/call-method api-proxy method args))) diff --git a/libs/cljs-sdk/src/com/logseq/core.cljs b/libs/cljs-sdk/src/com/logseq/core.cljs new file mode 100644 index 0000000000..67eb38890c --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/core.cljs @@ -0,0 +1,149 @@ +;; Auto-generated via `bb libs:generate-cljs-sdk` +(ns com.logseq.core + (:require ["@logseq/libs"] + [cljs-bean.core :as bean] + [com.logseq.util :as util])) + +(defn- normalize-result [result] + (if (instance? js/Promise result) + (.then result (fn [value] (normalize-result value))) + (util/->clj-tagged result))) + +(defn call-method [owner method args] + (when-not method + (throw (js/Error. "Missing method on logseq namespace"))) + (normalize-result (.apply method owner (bean/->js args)))) + +(def api-proxy js/logseq) + +(defn- ready-impl + [model callback] + (let [method (aget api-proxy "ready") + args [model callback]] + (-> (call-method api-proxy method args) + (.then (fn [] + (js/logseq._execCallableAPIAsync + "setSDKMetadata" + #js {:runtime "cljs"})))))) + +(defn ready + ([] + (ready-impl nil nil)) + ([model] + (ready-impl model nil)) + ([model callback] + (ready-impl model callback))) + +(defn ensure-connected + [] + (let [method (aget api-proxy "ensureConnected") + args []] + (call-method api-proxy method args))) + +(defn beforeunload + [callback] + (let [method (aget api-proxy "beforeunload") + args [callback]] + (call-method api-proxy method args))) + +(defn provide-model + [model] + (let [method (aget api-proxy "provideModel") + args [model]] + (call-method api-proxy method args))) + +(defn provide-theme + [theme] + (let [method (aget api-proxy "provideTheme") + args [theme]] + (call-method api-proxy method args))) + +(defn provide-style + [style] + (let [method (aget api-proxy "provideStyle") + args [style]] + (call-method api-proxy method args))) + +(defn provide-ui + [ui] + (let [method (aget api-proxy "provideUI") + args [ui]] + (call-method api-proxy method args))) + +(defn use-settings-schema + [schema] + (let [method (aget api-proxy "useSettingsSchema") + args [schema]] + (call-method api-proxy method args))) + +(defn update-settings + [attrs] + (let [method (aget api-proxy "updateSettings") + args [attrs]] + (call-method api-proxy method args))) + +(defn on-settings-changed + [cb] + (let [method (aget api-proxy "onSettingsChanged") + args [cb]] + (call-method api-proxy method args))) + +(defn show-settings-ui + [] + (let [method (aget api-proxy "showSettingsUI") + args []] + (call-method api-proxy method args))) + +(defn hide-settings-ui + [] + (let [method (aget api-proxy "hideSettingsUI") + args []] + (call-method api-proxy method args))) + +(defn set-main-ui-attrs + [attrs] + (let [method (aget api-proxy "setMainUIAttrs") + args [attrs]] + (call-method api-proxy method args))) + +(defn set-main-ui-inline-style + [style] + (let [method (aget api-proxy "setMainUIInlineStyle") + args [style]] + (call-method api-proxy method args))) + +(defn- hide-main-ui-impl + [opts] + (let [method (aget api-proxy "hideMainUI") + args [opts]] + (call-method api-proxy method args))) + +(defn hide-main-ui + ([] + (hide-main-ui-impl nil)) + ([opts] + (hide-main-ui-impl opts))) + +(defn- show-main-ui-impl + [opts] + (let [method (aget api-proxy "showMainUI") + args [opts]] + (call-method api-proxy method args))) + +(defn show-main-ui + ([] + (show-main-ui-impl nil)) + ([opts] + (show-main-ui-impl opts))) + +(defn toggle-main-ui + [] + (let [method (aget api-proxy "toggleMainUI") + args []] + (call-method api-proxy method args))) + +(defn resolve-resource-full-url + [file-path] + (let [method (aget api-proxy "resolveResourceFullUrl") + args [file-path]] + (call-method api-proxy method args))) diff --git a/libs/cljs-sdk/src/com/logseq/db.cljs b/libs/cljs-sdk/src/com/logseq/db.cljs new file mode 100644 index 0000000000..b317c05919 --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/db.cljs @@ -0,0 +1,34 @@ +;; Auto-generated via `bb libs:generate-cljs-sdk` +(ns com.logseq.db + (:require [com.logseq.core :as core])) + +(def api-proxy (aget js/logseq "DB")) + +(defn q + "Run a DSL query" + [dsl] + (let [method (aget api-proxy "q") + args [dsl]] + (core/call-method api-proxy method args))) + +(defn datascript-query + "Run a datascript query" + [query & inputs] + (let [method (aget api-proxy "datascriptQuery") + rest-inputs (vec inputs) + args (into [query] rest-inputs)] + (core/call-method api-proxy method args))) + +(defn on-changed + "Hook all transaction data of DB" + [callback] + (let [method (aget api-proxy "onChanged") + args [callback]] + (core/call-method api-proxy method args))) + +(defn on-block-changed + "Subscribe a specific block changed event" + [uuid callback] + (let [method (aget api-proxy "onBlockChanged") + args [uuid callback]] + (core/call-method api-proxy method args))) diff --git a/libs/cljs-sdk/src/com/logseq/editor.cljs b/libs/cljs-sdk/src/com/logseq/editor.cljs new file mode 100644 index 0000000000..8a8df2941d --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/editor.cljs @@ -0,0 +1,432 @@ +;; Auto-generated via `bb libs:generate-cljs-sdk` +(ns com.logseq.editor + (:require [com.logseq.core :as core])) + +(def api-proxy (aget js/logseq "Editor")) + +(defn register-slash-command + "register a custom command which will be added to the Logseq slash command list" + [tag action] + (let [method (aget api-proxy "registerSlashCommand") + args [tag action]] + (core/call-method api-proxy method args))) + +(defn register-block-context-menu-item + "register a custom command in the block context menu (triggered by right-clicking the block dot)" + [label action] + (let [method (aget api-proxy "registerBlockContextMenuItem") + args [label action]] + (core/call-method api-proxy method args))) + +(defn- register-highlight-context-menu-item-impl + [label action opts] + (let [method (aget api-proxy "registerHighlightContextMenuItem") + args [label action opts]] + (core/call-method api-proxy method args))) + +(defn register-highlight-context-menu-item + "Current it's only available for pdf viewer" + ([label action] + (register-highlight-context-menu-item-impl label action nil)) + ([label action opts] + (register-highlight-context-menu-item-impl label action opts))) + +(defn check-editing + [] + (let [method (aget api-proxy "checkEditing") + args []] + (core/call-method api-proxy method args))) + +(defn insert-at-editing-cursor + [content] + (let [method (aget api-proxy "insertAtEditingCursor") + args [content]] + (core/call-method api-proxy method args))) + +(defn restore-editing-cursor + [] + (let [method (aget api-proxy "restoreEditingCursor") + args []] + (core/call-method api-proxy method args))) + +(defn- exit-editing-mode-impl + [select-block] + (let [method (aget api-proxy "exitEditingMode") + args [select-block]] + (core/call-method api-proxy method args))) + +(defn exit-editing-mode + ([] + (exit-editing-mode-impl nil)) + ([select-block] + (exit-editing-mode-impl select-block))) + +(defn get-editing-cursor-position + [] + (let [method (aget api-proxy "getEditingCursorPosition") + args []] + (core/call-method api-proxy method args))) + +(defn get-editing-block-content + [] + (let [method (aget api-proxy "getEditingBlockContent") + args []] + (core/call-method api-proxy method args))) + +(defn get-current-page + [] + (let [method (aget api-proxy "getCurrentPage") + args []] + (core/call-method api-proxy method args))) + +(defn get-current-block + [] + (let [method (aget api-proxy "getCurrentBlock") + args []] + (core/call-method api-proxy method args))) + +(defn get-selected-blocks + [] + (let [method (aget api-proxy "getSelectedBlocks") + args []] + (core/call-method api-proxy method args))) + +(defn clear-selected-blocks + [] + (let [method (aget api-proxy "clearSelectedBlocks") + args []] + (core/call-method api-proxy method args))) + +(defn get-current-page-blocks-tree + "get all blocks of the current page as a tree structure" + [] + (let [method (aget api-proxy "getCurrentPageBlocksTree") + args []] + (core/call-method api-proxy method args))) + +(defn get-page-blocks-tree + "get all blocks for the specified page" + [src-page] + (let [method (aget api-proxy "getPageBlocksTree") + args [src-page]] + (core/call-method api-proxy method args))) + +(defn get-page-linked-references + "get all page/block linked references" + [src-page] + (let [method (aget api-proxy "getPageLinkedReferences") + args [src-page]] + (core/call-method api-proxy method args))) + +(defn get-pages-from-namespace + "get flatten pages from top namespace" + [namespace] + (let [method (aget api-proxy "getPagesFromNamespace") + args [namespace]] + (core/call-method api-proxy method args))) + +(defn get-pages-tree-from-namespace + "construct pages tree from namespace pages" + [namespace] + (let [method (aget api-proxy "getPagesTreeFromNamespace") + args [namespace]] + (core/call-method api-proxy method args))) + +(defn new-block-uuid + "Create a unique UUID string which can then be assigned to a block." + [] + (let [method (aget api-proxy "newBlockUUID") + args []] + (core/call-method api-proxy method args))) + +(defn is-page-block + [block] + (let [method (aget api-proxy "isPageBlock") + args [block]] + (core/call-method api-proxy method args))) + +(defn- insert-block-impl + [src-block content opts] + (let [method (aget api-proxy "insertBlock") + args [src-block content opts]] + (core/call-method api-proxy method args))) + +(defn insert-block + ([src-block content] + (insert-block-impl src-block content nil)) + ([src-block content opts] + (insert-block-impl src-block content opts))) + +(defn- insert-batch-block-impl + [src-block batch opts] + (let [method (aget api-proxy "insertBatchBlock") + args [src-block batch opts]] + (core/call-method api-proxy method args))) + +(defn insert-batch-block + ([src-block batch] + (insert-batch-block-impl src-block batch nil)) + ([src-block batch opts] + (insert-batch-block-impl src-block batch opts))) + +(defn- update-block-impl + [src-block content opts] + (let [method (aget api-proxy "updateBlock") + args [src-block content opts]] + (core/call-method api-proxy method args))) + +(defn update-block + ([src-block content] + (update-block-impl src-block content nil)) + ([src-block content opts] + (update-block-impl src-block content opts))) + +(defn remove-block + [src-block] + (let [method (aget api-proxy "removeBlock") + args [src-block]] + (core/call-method api-proxy method args))) + +(defn- get-block-impl + [src-block opts] + (let [method (aget api-proxy "getBlock") + args [src-block opts]] + (core/call-method api-proxy method args))) + +(defn get-block + ([src-block] + (get-block-impl src-block nil)) + ([src-block opts] + (get-block-impl src-block opts))) + +(defn set-block-collapsed + [uuid opts] + (let [method (aget api-proxy "setBlockCollapsed") + args [uuid opts]] + (core/call-method api-proxy method args))) + +(defn- get-page-impl + [src-page opts] + (let [method (aget api-proxy "getPage") + args [src-page opts]] + (core/call-method api-proxy method args))) + +(defn get-page + ([src-page] + (get-page-impl src-page nil)) + ([src-page opts] + (get-page-impl src-page opts))) + +(defn- create-page-impl + [page-name properties opts] + (let [method (aget api-proxy "createPage") + args [page-name properties opts]] + (core/call-method api-proxy method args))) + +(defn create-page + ([page-name] + (create-page-impl page-name nil nil)) + ([page-name properties] + (create-page-impl page-name properties nil)) + ([page-name properties opts] + (create-page-impl page-name properties opts))) + +(defn create-journal-page + [date] + (let [method (aget api-proxy "createJournalPage") + args [date]] + (core/call-method api-proxy method args))) + +(defn delete-page + [page-name] + (let [method (aget api-proxy "deletePage") + args [page-name]] + (core/call-method api-proxy method args))) + +(defn rename-page + [old-name new-name] + (let [method (aget api-proxy "renamePage") + args [old-name new-name]] + (core/call-method api-proxy method args))) + +(defn- get-all-pages-impl + [repo] + (let [method (aget api-proxy "getAllPages") + args [repo]] + (core/call-method api-proxy method args))) + +(defn get-all-pages + ([] + (get-all-pages-impl nil)) + ([repo] + (get-all-pages-impl repo))) + +(defn get-all-tags + [] + (let [method (aget api-proxy "getAllTags") + args []] + (core/call-method api-proxy method args))) + +(defn get-all-properties + [] + (let [method (aget api-proxy "getAllProperties") + args []] + (core/call-method api-proxy method args))) + +(defn get-tag-objects + [page-identity] + (let [method (aget api-proxy "getTagObjects") + args [page-identity]] + (core/call-method api-proxy method args))) + +(defn- prepend-block-in-page-impl + [page content opts] + (let [method (aget api-proxy "prependBlockInPage") + args [page content opts]] + (core/call-method api-proxy method args))) + +(defn prepend-block-in-page + ([page content] + (prepend-block-in-page-impl page content nil)) + ([page content opts] + (prepend-block-in-page-impl page content opts))) + +(defn- append-block-in-page-impl + [page content opts] + (let [method (aget api-proxy "appendBlockInPage") + args [page content opts]] + (core/call-method api-proxy method args))) + +(defn append-block-in-page + ([page content] + (append-block-in-page-impl page content nil)) + ([page content opts] + (append-block-in-page-impl page content opts))) + +(defn get-previous-sibling-block + [src-block] + (let [method (aget api-proxy "getPreviousSiblingBlock") + args [src-block]] + (core/call-method api-proxy method args))) + +(defn get-next-sibling-block + [src-block] + (let [method (aget api-proxy "getNextSiblingBlock") + args [src-block]] + (core/call-method api-proxy method args))) + +(defn- move-block-impl + [src-block target-block opts] + (let [method (aget api-proxy "moveBlock") + args [src-block target-block opts]] + (core/call-method api-proxy method args))) + +(defn move-block + ([src-block target-block] + (move-block-impl src-block target-block nil)) + ([src-block target-block opts] + (move-block-impl src-block target-block opts))) + +(defn- edit-block-impl + [src-block opts] + (let [method (aget api-proxy "editBlock") + args [src-block opts]] + (core/call-method api-proxy method args))) + +(defn edit-block + ([src-block] + (edit-block-impl src-block nil)) + ([src-block opts] + (edit-block-impl src-block opts))) + +(defn select-block + [src-block] + (let [method (aget api-proxy "selectBlock") + args [src-block]] + (core/call-method api-proxy method args))) + +(defn save-focused-code-editor-content + [] + (let [method (aget api-proxy "saveFocusedCodeEditorContent") + args []] + (core/call-method api-proxy method args))) + +(defn get-property + [key] + (let [method (aget api-proxy "getProperty") + args [key]] + (core/call-method api-proxy method args))) + +(defn- upsert-property-impl + [key schema opts] + (let [method (aget api-proxy "upsertProperty") + args [key schema opts]] + (core/call-method api-proxy method args))) + +(defn upsert-property + ([key] + (upsert-property-impl key nil nil)) + ([key schema] + (upsert-property-impl key schema nil)) + ([key schema opts] + (upsert-property-impl key schema opts))) + +(defn remove-property + [key] + (let [method (aget api-proxy "removeProperty") + args [key]] + (core/call-method api-proxy method args))) + +(defn upsert-block-property + [block key value] + (let [method (aget api-proxy "upsertBlockProperty") + args [block key value]] + (core/call-method api-proxy method args))) + +(defn remove-block-property + [block key] + (let [method (aget api-proxy "removeBlockProperty") + args [block key]] + (core/call-method api-proxy method args))) + +(defn get-block-property + [block key] + (let [method (aget api-proxy "getBlockProperty") + args [block key]] + (core/call-method api-proxy method args))) + +(defn get-block-properties + [block] + (let [method (aget api-proxy "getBlockProperties") + args [block]] + (core/call-method api-proxy method args))) + +(defn get-page-properties + [page] + (let [method (aget api-proxy "getPageProperties") + args [page]] + (core/call-method api-proxy method args))) + +(defn- scroll-to-block-in-page-impl + [page-name block-id opts] + (let [method (aget api-proxy "scrollToBlockInPage") + args [page-name block-id opts]] + (core/call-method api-proxy method args))) + +(defn scroll-to-block-in-page + ([page-name block-id] + (scroll-to-block-in-page-impl page-name block-id nil)) + ([page-name block-id opts] + (scroll-to-block-in-page-impl page-name block-id opts))) + +(defn open-in-right-sidebar + [id] + (let [method (aget api-proxy "openInRightSidebar") + args [id]] + (core/call-method api-proxy method args))) + +(defn on-input-selection-end + [callback] + (let [method (aget api-proxy "onInputSelectionEnd") + args [callback]] + (core/call-method api-proxy method args))) diff --git a/libs/cljs-sdk/src/com/logseq/git.cljs b/libs/cljs-sdk/src/com/logseq/git.cljs new file mode 100644 index 0000000000..e11db3f252 --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/git.cljs @@ -0,0 +1,23 @@ +;; Auto-generated via `bb libs:generate-cljs-sdk` +(ns com.logseq.git + (:require [com.logseq.core :as core])) + +(def api-proxy (aget js/logseq "Git")) + +(defn exec-command + [args] + (let [method (aget api-proxy "execCommand") + args [args]] + (core/call-method api-proxy method args))) + +(defn load-ignore-file + [] + (let [method (aget api-proxy "loadIgnoreFile") + args []] + (core/call-method api-proxy method args))) + +(defn save-ignore-file + [content] + (let [method (aget api-proxy "saveIgnoreFile") + args [content]] + (core/call-method api-proxy method args))) diff --git a/libs/cljs-sdk/src/com/logseq/ui.cljs b/libs/cljs-sdk/src/com/logseq/ui.cljs new file mode 100644 index 0000000000..f05c09b992 --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/ui.cljs @@ -0,0 +1,49 @@ +;; Auto-generated via `bb libs:generate-cljs-sdk` +(ns com.logseq.ui + (:require [com.logseq.core :as core])) + +(def api-proxy (aget js/logseq "UI")) + +(defn- show-msg-impl + [content status opts] + (let [method (aget api-proxy "showMsg") + args [content status opts]] + (core/call-method api-proxy method args))) + +(defn show-msg + ([content] + (show-msg-impl content nil nil)) + ([content status] + (show-msg-impl content status nil)) + ([content status opts] + (show-msg-impl content status opts))) + +(defn close-msg + [key] + (let [method (aget api-proxy "closeMsg") + args [key]] + (core/call-method api-proxy method args))) + +(defn query-element-rect + [selector] + (let [method (aget api-proxy "queryElementRect") + args [selector]] + (core/call-method api-proxy method args))) + +(defn query-element-by-id + [id] + (let [method (aget api-proxy "queryElementById") + args [id]] + (core/call-method api-proxy method args))) + +(defn check-slot-valid + [slot] + (let [method (aget api-proxy "checkSlotValid") + args [slot]] + (core/call-method api-proxy method args))) + +(defn resolve-theme-css-props-vals + [props] + (let [method (aget api-proxy "resolveThemeCssPropsVals") + args [props]] + (core/call-method api-proxy method args))) diff --git a/libs/cljs-sdk/src/com/logseq/util.cljs b/libs/cljs-sdk/src/com/logseq/util.cljs new file mode 100644 index 0000000000..ddde0b4702 --- /dev/null +++ b/libs/cljs-sdk/src/com/logseq/util.cljs @@ -0,0 +1,31 @@ +(ns com.logseq.util + (:require [cljs-bean.core :as bean] + [clojure.string :as string] + [clojure.walk :as walk])) + +(def ^:private kw-tag "___kw___") + +(defn- decode-kw [v] + (if (and (string? v) (string/starts-with? v kw-tag)) + (let [s (subs v (count kw-tag)) + i (.indexOf s "/")] + (if (neg? i) + (keyword s) ; :name + (keyword (subs s 0 i) (subs s (inc i))))) ; :ns/name + v)) + +(defn ->clj-tagged [js] + (some->> js + bean/->clj + (walk/postwalk (fn [f] + (cond + (keyword? f) + (decode-kw (if-let [ns (namespace f)] + (str ns "/" (name f)) + (name f))) + + (string? f) + (decode-kw f) + + :else + f))))) diff --git a/libs/cljs-sdk/yarn.lock b/libs/cljs-sdk/yarn.lock new file mode 100644 index 0000000000..552385efd1 --- /dev/null +++ b/libs/cljs-sdk/yarn.lock @@ -0,0 +1,121 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@logseq/libs@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@logseq/libs/-/libs-0.2.3.tgz#33c4b7ad1db02a2335269cd38eac7e5f5196f675" + integrity sha512-aMtZFsNvbFgVhiaA9K9DANPhIv+ZKaC5qW61si2UMsfwgykr4/hyT9Q7aoqf7ir3ZIwYDDhfEJqpthZCsUwbeA== + dependencies: + csstype "3.1.0" + debug "4.3.4" + deepmerge "4.3.1" + dompurify "2.5.4" + eventemitter3 "4.0.7" + fast-deep-equal "3.1.3" + lodash-es "4.17.21" + path "0.12.7" + snake-case "3.0.4" + +csstype@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2" + integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA== + +debug@4.3.4: + version "4.3.4" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + +deepmerge@4.3.1: + version "4.3.1" + resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" + integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== + +dompurify@2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/dompurify/-/dompurify-2.5.4.tgz#347e91070963b22db31c7c8d0ce9a0a2c3c08746" + integrity sha512-l5NNozANzaLPPe0XaAwvg3uZcHtDBnziX/HjsY1UcDj1MxTK8Dd0Kv096jyPK5HRzs/XM5IMj20dW8Fk+HnbUA== + +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" + +eventemitter3@4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +fast-deep-equal@3.1.3: + 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== + +inherits@2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw== + +lodash-es@4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee" + integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw== + +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" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +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" + +path@0.12.7: + version "0.12.7" + resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f" + integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q== + dependencies: + process "^0.11.1" + util "^0.10.3" + +process@^0.11.1: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A== + +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" + +tslib@^2.0.3: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +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" diff --git a/libs/package.json b/libs/package.json index 20529d3720..57a448b36f 100644 --- a/libs/package.json +++ b/libs/package.json @@ -1,6 +1,6 @@ { "name": "@logseq/libs", - "version": "0.2.1", + "version": "0.2.3", "description": "Logseq SDK libraries", "main": "dist/lsplugin.user.js", "typings": "index.d.ts", @@ -10,6 +10,7 @@ "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", + "generate:schema": "node scripts/extract-sdk-schema.js", "build": "tsc && rm dist/*.js && npm run build:user", "lint": "prettier --check \"src/**/*.{ts, js}\"", "fix": "prettier --write \"src/**/*.{ts, js}\"", @@ -27,6 +28,7 @@ "snake-case": "3.0.4" }, "devDependencies": { + "ts-morph": "^22.0.0", "@babel/core": "^7.20.2", "@babel/preset-env": "^7.20.2", "@types/debug": "^4.1.5", diff --git a/libs/scripts/extract-sdk-schema.js b/libs/scripts/extract-sdk-schema.js new file mode 100755 index 0000000000..4ef791b625 --- /dev/null +++ b/libs/scripts/extract-sdk-schema.js @@ -0,0 +1,184 @@ +#!/usr/bin/env node +/** + * Extracts metadata about the Logseq JS SDK from the generated *.d.ts files. + * + * This script uses ts-morph so we can rely on the TypeScript compiler's view of + * the declarations. We intentionally read the emitted declaration files in + * dist/ so that consumers do not need to depend on the source layout. + * + * The resulting schema is written to dist/logseq-sdk-schema.json and contains + * a simplified representation that downstream tooling (Babashka) can consume. + */ + +const fs = require('node:fs'); +const path = require('node:path'); +const { Project, Node } = require('ts-morph'); + +const ROOT = path.resolve(__dirname, '..'); +const DIST_DIR = path.join(ROOT, 'dist'); +const OUTPUT_FILE = path.join(DIST_DIR, 'logseq-sdk-schema.json'); +const DECL_FILES = [ + 'LSPlugin.d.ts', + 'LSPlugin.user.d.ts', +]; + +/** + * Interfaces whose methods will be turned into CLJS wrappers at runtime. + * These correspond to `logseq.` targets in the JS SDK. + */ +const TARGET_INTERFACES = [ + 'IAppProxy', + 'IEditorProxy', + 'IDBProxy', + 'IUIProxy', + 'IUtilsProxy', + 'IGitProxy', + 'IAssetsProxy', +]; + +/** + * Simple heuristics to determine whether a parameter should be converted via + * cljs-bean when crossing the JS <-> CLJS boundary. + */ +const BEAN_TO_JS_REGEX = + /(Record<|Array<|Partial<|UIOptions|UIContainerAttrs|StyleString|StyleOptions|object|any|unknown|IHookEvent|BlockEntity|PageEntity|Promise<\s*Record)/i; + +const project = new Project({ + compilerOptions: { allowJs: true }, +}); + +DECL_FILES.forEach((file) => { + const full = path.join(DIST_DIR, file); + if (fs.existsSync(full)) { + project.addSourceFileAtPath(full); + } +}); + +const schema = { + generatedAt: new Date().toISOString(), + interfaces: {}, + classes: {}, +}; + +const serializeDoc = (symbol) => { + if (!symbol) return undefined; + const decl = symbol.getDeclarations()[0]; + if (!decl) return undefined; + + const docs = decl + .getJsDocs() + .map((doc) => doc.getComment()) + .filter(Boolean); + return docs.length ? docs.join('\n\n') : undefined; +}; + +const serializeParameter = (signature, symbol, memberNode) => { + const name = symbol.getName(); + const declaration = symbol.getDeclarations()[0]; + + let typeText; + let optional = symbol.isOptional?.() ?? false; + let rest = symbol.isRestParameter?.() ?? false; + + if (declaration && Node.isParameterDeclaration(declaration)) { + typeText = declaration.getType().getText(); + optional = declaration.hasQuestionToken?.() ?? false; + rest = declaration.isRestParameter?.() ?? false; + } else { + const location = + signature.getDeclaration?.() ?? + memberNode ?? + declaration ?? + symbol.getDeclarations()[0]; + typeText = symbol.getTypeAtLocation(location).getText(); + } + + const convertToJs = BEAN_TO_JS_REGEX.test(typeText); + + return { + name, + type: typeText, + optional, + rest, + beanToJs: convertToJs, + }; +}; + +const serializeSignature = (sig, memberNode) => { + const params = sig.getParameters().map((paramSymbol) => + serializeParameter(sig, paramSymbol, memberNode) + ); + const returnType = sig.getReturnType().getText(); + return { + parameters: params, + returnType, + }; +}; + +const serializeCallable = (symbol, member) => { + if (!symbol) return null; + const type = symbol.getTypeAtLocation(member); + const callSignatures = type.getCallSignatures(); + if (!callSignatures.length) { + return null; + } + + return { + name: symbol.getName(), + documentation: serializeDoc(symbol), + signatures: callSignatures.map((sig) => serializeSignature(sig, member)), + }; +}; + +const sourceFiles = project.getSourceFiles(); +sourceFiles.forEach((source) => { + source.getInterfaces().forEach((iface) => { + const name = iface.getName(); + if (!TARGET_INTERFACES.includes(name)) { + return; + } + + const interfaceSymbol = iface.getType().getSymbol(); + const doc = serializeDoc(interfaceSymbol); + const methods = iface + .getMembers() + .map((member) => serializeCallable(member.getSymbol(), member)) + .filter(Boolean); + + schema.interfaces[name] = { + documentation: doc, + methods, + }; + }); + + source.getClasses().forEach((cls) => { + const name = cls.getName(); + if (name !== 'LSPluginUser') { + return; + } + + const classSymbol = cls.getType().getSymbol(); + const doc = serializeDoc(classSymbol); + const methods = cls + .getInstanceMethods() + .filter((method) => method.getName() !== 'constructor') + .map((method) => serializeCallable(method.getSymbol(), method)) + .filter(Boolean); + const getters = cls.getGetAccessors().map((accessor) => ({ + name: accessor.getName(), + documentation: serializeDoc(accessor.getSymbol()), + returnType: accessor.getReturnType().getText(), + })); + + schema.classes[name] = { + documentation: doc, + methods, + getters, + }; + }); +}); + +fs.mkdirSync(DIST_DIR, { recursive: true }); +fs.writeFileSync(OUTPUT_FILE, JSON.stringify(schema, null, 2)); + +console.log(`Wrote ${OUTPUT_FILE}`); diff --git a/libs/src/LSPlugin.core.ts b/libs/src/LSPlugin.core.ts index d16b87e4d4..17b98240d0 100644 --- a/libs/src/LSPlugin.core.ts +++ b/libs/src/LSPlugin.core.ts @@ -154,6 +154,7 @@ interface PluginLocalOptions { url: string // Plugin package absolute fs location name: string version: string + runtime: string mode: 'shadow' | 'iframe' webPkg?: any // web plugin package.json data settingsSchema?: SettingSchemaDesc[] @@ -166,6 +167,7 @@ interface PluginLocalOptions { interface PluginLocalSDKMetadata { version: string + runtime: string [key: string]: any } @@ -669,7 +671,7 @@ class PluginLocal extends EventEmitter< ? `` : `` } - +
diff --git a/libs/src/LSPlugin.user.ts b/libs/src/LSPlugin.user.ts index 95c116296d..658d5b1e61 100644 --- a/libs/src/LSPlugin.user.ts +++ b/libs/src/LSPlugin.user.ts @@ -575,6 +575,7 @@ export class LSPluginUser try { await this._execCallableAPIAsync('setSDKMetadata', { version: this._version, + runtime: 'js', }) } catch (e) { console.warn(e) diff --git a/libs/yarn.lock b/libs/yarn.lock index e74f55349e..47f255adb7 100644 --- a/libs/yarn.lock +++ b/libs/yarn.lock @@ -1066,11 +1066,42 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + "@polka/url@^1.0.0-next.17": version "1.0.0-next.17" resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.17.tgz#25fdbdfd282c2f86ddf3fcefbd98be99cd2627e2" integrity sha512-0p1rCgM3LLbAdwBnc7gqgnvjHg9KpbhcSphergHShlkWz8EdPawoMJ3/VbezI0mGC5eKCDzMaPgF9Yca6cKvrg== +"@ts-morph/common@~0.23.0": + version "0.23.0" + resolved "https://registry.yarnpkg.com/@ts-morph/common/-/common-0.23.0.tgz#bd4ddbd3f484f29476c8bd985491592ae5fc147e" + integrity sha512-m7Lllj9n/S6sOkCkRftpM7L24uvmfXQFedlW/4hENcuJH1HHm9u5EgxZb9uVjQSCGrbBWBkOGgcTxNg36r6ywA== + dependencies: + fast-glob "^3.3.2" + minimatch "^9.0.3" + mkdirp "^3.0.1" + path-browserify "^1.0.1" + "@types/debug@^4.1.5": version "4.1.7" resolved "https://registry.yarnpkg.com/@types/debug/-/debug-4.1.7.tgz#7cc0ea761509124709b8b2d1090d8f6c17aadb82" @@ -1434,6 +1465,13 @@ braces@^3.0.1: dependencies: fill-range "^7.0.1" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + browserslist@^4.14.5: version "4.16.8" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.16.8.tgz#cb868b0b554f137ba6e33de0ecff2eda403c4fb0" @@ -1501,6 +1539,11 @@ clone-deep@^4.0.1: kind-of "^6.0.2" shallow-clone "^3.0.0" +code-block-writer@^13.0.1: + version "13.0.3" + resolved "https://registry.yarnpkg.com/code-block-writer/-/code-block-writer-13.0.3.tgz#90f8a84763a5012da7af61319dd638655ae90b5b" + integrity sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg== + color-convert@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" @@ -1709,6 +1752,17 @@ fast-deep-equal@3.1.3, fast-deep-equal@^3.1.1, fast-deep-equal@^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-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.8" + 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" @@ -1719,6 +1773,13 @@ fastest-levenshtein@^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== +fastq@^1.6.0: + version "1.19.1" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.19.1.tgz#d50eaba803c8846a883c16492821ebcd2cda55f5" + integrity sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ== + dependencies: + reusify "^1.0.4" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -1726,6 +1787,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-cache-dir@^3.3.2: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -1763,6 +1831,13 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + 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" @@ -1868,6 +1943,18 @@ is-core-module@^2.9.0: dependencies: has "^1.0.3" +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-glob@^4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -2028,6 +2115,11 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== +merge2@^1.3.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + micromatch@^4.0.0: version "4.0.4" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" @@ -2036,6 +2128,14 @@ micromatch@^4.0.0: braces "^3.0.1" picomatch "^2.2.3" +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.49.0: version "1.49.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.49.0.tgz#f3dfde60c99e9cf3bc9701d687778f537001cbed" @@ -2065,6 +2165,18 @@ minimatch@^5.0.1, minimatch@^5.1.0: dependencies: brace-expansion "^2.0.1" +minimatch@^9.0.3: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +mkdirp@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-3.0.1.tgz#e44e4c5607fb279c168241713cc6e0fea9adcb50" + integrity sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg== + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" @@ -2150,6 +2262,11 @@ p-try@^2.0.0: resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + path-exists@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" @@ -2183,6 +2300,11 @@ picomatch@^2.2.3: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + pkg-dir@^4.1.0, pkg-dir@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" @@ -2210,6 +2332,11 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -2314,6 +2441,18 @@ resolve@^1.9.0: is-core-module "^2.2.0" path-parse "^1.0.6" +reusify@^1.0.4: + version "1.1.0" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.1.0.tgz#0fe13b9522e1473f51b558ee796e08f11f9b489f" + integrity sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw== + +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + safe-buffer@^5.1.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" @@ -2535,6 +2674,14 @@ ts-loader@9.3.0: micromatch "^4.0.0" semver "^7.3.4" +ts-morph@^22.0.0: + version "22.0.0" + resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-22.0.0.tgz#5532c592fb6dddae08846f12c9ab0fc590b1d42e" + integrity sha512-M9MqFGZREyeb5fTl6gNHKZLqBQA0TjA1lea+CR48R8EBTDuWrNqW6ccC5QvjNR4s6wDumD3LTCjOFSp9iwlzaw== + dependencies: + "@ts-morph/common" "~0.23.0" + code-block-writer "^13.0.1" + tslib@^2.0.3: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" diff --git a/resources/js/lsplugin.core.js b/resources/js/lsplugin.core.js index 45487cc162..a7fcfcc3b0 100644 --- a/resources/js/lsplugin.core.js +++ b/resources/js/lsplugin.core.js @@ -1,2 +1,2 @@ /*! For license information please see lsplugin.core.js.LICENSE.txt */ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define([],t):"object"==typeof exports?exports.LSPlugin=t():e.LSPlugin=t()}(self,(()=>(()=>{var e={227:(e,t,n)=>{var r=n(155);t.formatArgs=function(t){if(t[0]=(this.useColors?"%c":"")+this.namespace+(this.useColors?" %c":" ")+t[0]+(this.useColors?"%c ":" ")+"+"+e.exports.humanize(this.diff),!this.useColors)return;const n="color: "+this.color;t.splice(1,0,n,"color: inherit");let r=0,i=0;t[0].replace(/%[a-zA-Z%]/g,(e=>{"%%"!==e&&(r++,"%c"===e&&(i=r))})),t.splice(i,0,n)},t.save=function(e){try{e?t.storage.setItem("debug",e):t.storage.removeItem("debug")}catch(e){}},t.load=function(){let e;try{e=t.storage.getItem("debug")}catch(e){}return!e&&void 0!==r&&"env"in r&&(e=r.env.DEBUG),e},t.useColors=function(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type&&!window.process.__nwjs)||("undefined"==typeof navigator||!navigator.userAgent||!navigator.userAgent.toLowerCase().match(/(edge|trident)\/(\d+)/))&&("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))},t.storage=function(){try{return localStorage}catch(e){}}(),t.destroy=(()=>{let e=!1;return()=>{e||(e=!0,console.warn("Instance method `debug.destroy()` is deprecated and no longer does anything. It will be removed in the next major version of `debug`."))}})(),t.colors=["#0000CC","#0000FF","#0033CC","#0033FF","#0066CC","#0066FF","#0099CC","#0099FF","#00CC00","#00CC33","#00CC66","#00CC99","#00CCCC","#00CCFF","#3300CC","#3300FF","#3333CC","#3333FF","#3366CC","#3366FF","#3399CC","#3399FF","#33CC00","#33CC33","#33CC66","#33CC99","#33CCCC","#33CCFF","#6600CC","#6600FF","#6633CC","#6633FF","#66CC00","#66CC33","#9900CC","#9900FF","#9933CC","#9933FF","#99CC00","#99CC33","#CC0000","#CC0033","#CC0066","#CC0099","#CC00CC","#CC00FF","#CC3300","#CC3333","#CC3366","#CC3399","#CC33CC","#CC33FF","#CC6600","#CC6633","#CC9900","#CC9933","#CCCC00","#CCCC33","#FF0000","#FF0033","#FF0066","#FF0099","#FF00CC","#FF00FF","#FF3300","#FF3333","#FF3366","#FF3399","#FF33CC","#FF33FF","#FF6600","#FF6633","#FF9900","#FF9933","#FFCC00","#FFCC33"],t.log=console.debug||console.log||(()=>{}),e.exports=n(447)(t);const{formatters:i}=e.exports;i.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}}},447:(e,t,n)=>{e.exports=function(e){function t(e){let n,i,o,s=null;function a(...e){if(!a.enabled)return;const r=a,i=Number(new Date),o=i-(n||i);r.diff=o,r.prev=n,r.curr=i,n=i,e[0]=t.coerce(e[0]),"string"!=typeof e[0]&&e.unshift("%O");let s=0;e[0]=e[0].replace(/%([a-zA-Z%])/g,((n,i)=>{if("%%"===n)return"%";s++;const o=t.formatters[i];if("function"==typeof o){const t=e[s];n=o.call(r,t),e.splice(s,1),s--}return n})),t.formatArgs.call(r,e),(r.log||t.log).apply(r,e)}return a.namespace=e,a.useColors=t.useColors(),a.color=t.selectColor(e),a.extend=r,a.destroy=t.destroy,Object.defineProperty(a,"enabled",{enumerable:!0,configurable:!1,get:()=>null!==s?s:(i!==t.namespaces&&(i=t.namespaces,o=t.enabled(e)),o),set:e=>{s=e}}),"function"==typeof t.init&&t.init(a),a}function r(e,n){const r=t(this.namespace+(void 0===n?":":n)+e);return r.log=this.log,r}function i(e){return e.toString().substring(2,e.toString().length-2).replace(/\.\*\?$/,"*")}return t.debug=t,t.default=t,t.coerce=function(e){return e instanceof Error?e.stack||e.message:e},t.disable=function(){const e=[...t.names.map(i),...t.skips.map(i).map((e=>"-"+e))].join(",");return t.enable(""),e},t.enable=function(e){let n;t.save(e),t.namespaces=e,t.names=[],t.skips=[];const r=("string"==typeof e?e:"").split(/[\s,]+/),i=r.length;for(n=0;n{t[n]=e[n]})),t.names=[],t.skips=[],t.formatters={},t.selectColor=function(e){let n=0;for(let t=0;t{"use strict";var t=function(e){return function(e){return!!e&&"object"==typeof e}(e)&&!function(e){var t=Object.prototype.toString.call(e);return"[object RegExp]"===t||"[object Date]"===t||function(e){return e.$$typeof===n}(e)}(e)},n="function"==typeof Symbol&&Symbol.for?Symbol.for("react.element"):60103;function r(e,t){return!1!==t.clone&&t.isMergeableObject(e)?a((n=e,Array.isArray(n)?[]:{}),e,t):e;var n}function i(e,t,n){return e.concat(t).map((function(e){return r(e,n)}))}function o(e){return Object.keys(e).concat(function(e){return Object.getOwnPropertySymbols?Object.getOwnPropertySymbols(e).filter((function(t){return Object.propertyIsEnumerable.call(e,t)})):[]}(e))}function s(e,t){try{return t in e}catch(e){return!1}}function a(e,n,c){(c=c||{}).arrayMerge=c.arrayMerge||i,c.isMergeableObject=c.isMergeableObject||t,c.cloneUnlessOtherwiseSpecified=r;var l=Array.isArray(n);return l===Array.isArray(e)?l?c.arrayMerge(e,n,c):function(e,t,n){var i={};return n.isMergeableObject(e)&&o(e).forEach((function(t){i[t]=r(e[t],n)})),o(t).forEach((function(o){(function(e,t){return s(e,t)&&!(Object.hasOwnProperty.call(e,t)&&Object.propertyIsEnumerable.call(e,t))})(e,o)||(s(e,o)&&n.isMergeableObject(t[o])?i[o]=function(e,t){if(!t.customMerge)return a;var n=t.customMerge(e);return"function"==typeof n?n:a}(o,n)(e[o],t[o],n):i[o]=r(t[o],n))})),i}(e,n,c):r(n,c)}a.all=function(e,t){if(!Array.isArray(e))throw new Error("first argument should be an array");return e.reduce((function(e,n){return a(e,n,t)}),{})};var c=a;e.exports=c},856:function(e){e.exports=function(){"use strict";function e(t){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(t)}function t(e,n){return t=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},t(e,n)}function n(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}function r(e,i,o){return r=n()?Reflect.construct:function(e,n,r){var i=[null];i.push.apply(i,n);var o=new(Function.bind.apply(e,i));return r&&t(o,r.prototype),o},r.apply(null,arguments)}function i(e){return function(e){if(Array.isArray(e))return o(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(e){if("string"==typeof e)return o(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?o(e,t):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function o(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n1?n-1:0),i=1;i/gm),J=d(/\${[\w\W]*}/gm),K=d(/^data-[\-\w.\u00B7-\uFFFF]/),V=d(/^aria-[\-\w]+$/),Z=d(/^(?:(?:(?:f|ht)tps?|mailto|tel|callto|cid|xmpp):|[^a-z]|[a-z+.\-]+(?:[^a-z+.\-:]|$))/i),Y=d(/^(?:\w+script|data):/i),Q=d(/[\u0000-\u0020\u00A0\u1680\u180E\u2000-\u2029\u205F\u3000]/g),X=d(/^html$/i),ee=d(/^[a-z][.\w]*(-[.\w]+)+$/i),te=function(){return"undefined"==typeof window?null:window},ne=function(t,n){if("object"!==e(t)||"function"!=typeof t.createPolicy)return null;var r=null,i="data-tt-policy-suffix";n.currentScript&&n.currentScript.hasAttribute(i)&&(r=n.currentScript.getAttribute(i));var o="dompurify"+(r?"#"+r:"");try{return t.createPolicy(o,{createHTML:function(e){return e},createScriptURL:function(e){return e}})}catch(e){return console.warn("TrustedTypes policy "+o+" could not be created."),null}};return function t(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:te(),r=function(e){return t(e)};if(r.version="2.5.4",r.removed=[],!n||!n.document||9!==n.document.nodeType)return r.isSupported=!1,r;var o=n.document,s=n.document,a=n.DocumentFragment,c=n.HTMLTemplateElement,l=n.Node,u=n.Element,d=n.NodeFilter,p=n.NamedNodeMap,f=void 0===p?n.NamedNodeMap||n.MozNamedAttrMap:p,g=n.HTMLFormElement,m=n.DOMParser,y=n.trustedTypes,T=u.prototype,re=P(T,"cloneNode"),ie=P(T,"nextSibling"),oe=P(T,"childNodes"),se=P(T,"parentNode");if("function"==typeof c){var ae=s.createElement("template");ae.content&&ae.content.ownerDocument&&(s=ae.content.ownerDocument)}var ce=ne(y,o),le=ce?ce.createHTML(""):"",ue=s,he=ue.implementation,de=ue.createNodeIterator,pe=ue.createDocumentFragment,fe=ue.getElementsByTagName,ge=o.importNode,me={};try{me=L(s).documentMode?s.documentMode:{}}catch(e){}var ye={};r.isSupported="function"==typeof se&&he&&void 0!==he.createHTMLDocument&&9!==me;var _e,be,ve=B,we=G,xe=J,Ce=K,Se=V,Ee=Y,Oe=Q,Ae=ee,ke=Z,je=null,Te=I({},[].concat(i(M),i(R),i(N),i(D),i($))),Ie=null,Le=I({},[].concat(i(z),i(H),i(W),i(q))),Pe=Object.seal(Object.create(null,{tagNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},attributeNameCheck:{writable:!0,configurable:!1,enumerable:!0,value:null},allowCustomizedBuiltInElements:{writable:!0,configurable:!1,enumerable:!0,value:!1}})),Me=null,Re=null,Ne=!0,Fe=!0,De=!1,Ue=!0,$e=!1,ze=!0,He=!1,We=!1,qe=!1,Be=!1,Ge=!1,Je=!1,Ke=!0,Ve=!1,Ze="user-content-",Ye=!0,Qe=!1,Xe={},et=null,tt=I({},["annotation-xml","audio","colgroup","desc","foreignobject","head","iframe","math","mi","mn","mo","ms","mtext","noembed","noframes","noscript","plaintext","script","style","svg","template","thead","title","video","xmp"]),nt=null,rt=I({},["audio","video","img","source","image","track"]),it=null,ot=I({},["alt","class","for","id","label","name","pattern","placeholder","role","summary","title","value","style","xmlns"]),st="http://www.w3.org/1998/Math/MathML",at="http://www.w3.org/2000/svg",ct="http://www.w3.org/1999/xhtml",lt=ct,ut=!1,ht=null,dt=I({},[st,at,ct],x),pt=["application/xhtml+xml","text/html"],ft="text/html",gt=null,mt=255,yt=s.createElement("form"),_t=function(e){return e instanceof RegExp||e instanceof Function},bt=function(t){gt&>===t||(t&&"object"===e(t)||(t={}),t=L(t),_e=_e=-1===pt.indexOf(t.PARSER_MEDIA_TYPE)?ft:t.PARSER_MEDIA_TYPE,be="application/xhtml+xml"===_e?x:w,je="ALLOWED_TAGS"in t?I({},t.ALLOWED_TAGS,be):Te,Ie="ALLOWED_ATTR"in t?I({},t.ALLOWED_ATTR,be):Le,ht="ALLOWED_NAMESPACES"in t?I({},t.ALLOWED_NAMESPACES,x):dt,it="ADD_URI_SAFE_ATTR"in t?I(L(ot),t.ADD_URI_SAFE_ATTR,be):ot,nt="ADD_DATA_URI_TAGS"in t?I(L(rt),t.ADD_DATA_URI_TAGS,be):rt,et="FORBID_CONTENTS"in t?I({},t.FORBID_CONTENTS,be):tt,Me="FORBID_TAGS"in t?I({},t.FORBID_TAGS,be):{},Re="FORBID_ATTR"in t?I({},t.FORBID_ATTR,be):{},Xe="USE_PROFILES"in t&&t.USE_PROFILES,Ne=!1!==t.ALLOW_ARIA_ATTR,Fe=!1!==t.ALLOW_DATA_ATTR,De=t.ALLOW_UNKNOWN_PROTOCOLS||!1,Ue=!1!==t.ALLOW_SELF_CLOSE_IN_ATTR,$e=t.SAFE_FOR_TEMPLATES||!1,ze=!1!==t.SAFE_FOR_XML,He=t.WHOLE_DOCUMENT||!1,Be=t.RETURN_DOM||!1,Ge=t.RETURN_DOM_FRAGMENT||!1,Je=t.RETURN_TRUSTED_TYPE||!1,qe=t.FORCE_BODY||!1,Ke=!1!==t.SANITIZE_DOM,Ve=t.SANITIZE_NAMED_PROPS||!1,Ye=!1!==t.KEEP_CONTENT,Qe=t.IN_PLACE||!1,ke=t.ALLOWED_URI_REGEXP||ke,lt=t.NAMESPACE||ct,Pe=t.CUSTOM_ELEMENT_HANDLING||{},t.CUSTOM_ELEMENT_HANDLING&&_t(t.CUSTOM_ELEMENT_HANDLING.tagNameCheck)&&(Pe.tagNameCheck=t.CUSTOM_ELEMENT_HANDLING.tagNameCheck),t.CUSTOM_ELEMENT_HANDLING&&_t(t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck)&&(Pe.attributeNameCheck=t.CUSTOM_ELEMENT_HANDLING.attributeNameCheck),t.CUSTOM_ELEMENT_HANDLING&&"boolean"==typeof t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements&&(Pe.allowCustomizedBuiltInElements=t.CUSTOM_ELEMENT_HANDLING.allowCustomizedBuiltInElements),$e&&(Fe=!1),Ge&&(Be=!0),Xe&&(je=I({},i($)),Ie=[],!0===Xe.html&&(I(je,M),I(Ie,z)),!0===Xe.svg&&(I(je,R),I(Ie,H),I(Ie,q)),!0===Xe.svgFilters&&(I(je,N),I(Ie,H),I(Ie,q)),!0===Xe.mathMl&&(I(je,D),I(Ie,W),I(Ie,q))),t.ADD_TAGS&&(je===Te&&(je=L(je)),I(je,t.ADD_TAGS,be)),t.ADD_ATTR&&(Ie===Le&&(Ie=L(Ie)),I(Ie,t.ADD_ATTR,be)),t.ADD_URI_SAFE_ATTR&&I(it,t.ADD_URI_SAFE_ATTR,be),t.FORBID_CONTENTS&&(et===tt&&(et=L(et)),I(et,t.FORBID_CONTENTS,be)),Ye&&(je["#text"]=!0),He&&I(je,["html","head","body"]),je.table&&(I(je,["tbody"]),delete Me.tbody),h&&h(t),gt=t)},vt=I({},["mi","mo","mn","ms","mtext"]),wt=I({},["foreignobject","annotation-xml"]),xt=I({},["title","style","font","a","script"]),Ct=I({},R);I(Ct,N),I(Ct,F);var St=I({},D);I(St,U);var Et=function(e){var t=se(e);t&&t.tagName||(t={namespaceURI:lt,tagName:"template"});var n=w(e.tagName),r=w(t.tagName);return!!ht[e.namespaceURI]&&(e.namespaceURI===at?t.namespaceURI===ct?"svg"===n:t.namespaceURI===st?"svg"===n&&("annotation-xml"===r||vt[r]):Boolean(Ct[n]):e.namespaceURI===st?t.namespaceURI===ct?"math"===n:t.namespaceURI===at?"math"===n&&wt[r]:Boolean(St[n]):e.namespaceURI===ct?!(t.namespaceURI===at&&!wt[r])&&!(t.namespaceURI===st&&!vt[r])&&!St[n]&&(xt[n]||!Ct[n]):!("application/xhtml+xml"!==_e||!ht[e.namespaceURI]))},Ot=function(e){v(r.removed,{element:e});try{e.parentNode.removeChild(e)}catch(t){try{e.outerHTML=le}catch(t){e.remove()}}},At=function(e,t){try{v(r.removed,{attribute:t.getAttributeNode(e),from:t})}catch(e){v(r.removed,{attribute:null,from:t})}if(t.removeAttribute(e),"is"===e&&!Ie[e])if(Be||Ge)try{Ot(t)}catch(e){}else try{t.setAttribute(e,"")}catch(e){}},kt=function(e){var t,n;if(qe)e=""+e;else{var r=C(e,/^[\r\n\t ]+/);n=r&&r[0]}"application/xhtml+xml"===_e&<===ct&&(e=''+e+"");var i=ce?ce.createHTML(e):e;if(lt===ct)try{t=(new m).parseFromString(i,_e)}catch(e){}if(!t||!t.documentElement){t=he.createDocument(lt,"template",null);try{t.documentElement.innerHTML=ut?le:i}catch(e){}}var o=t.body||t.documentElement;return e&&n&&o.insertBefore(s.createTextNode(n),o.childNodes[0]||null),lt===ct?fe.call(t,He?"html":"body")[0]:He?t.documentElement:o},jt=function(e){return de.call(e.ownerDocument||e,e,d.SHOW_ELEMENT|d.SHOW_COMMENT|d.SHOW_TEXT|d.SHOW_PROCESSING_INSTRUCTION|d.SHOW_CDATA_SECTION,null,!1)},Tt=function(e){return e instanceof g&&(void 0!==e.__depth&&"number"!=typeof e.__depth||void 0!==e.__removalCount&&"number"!=typeof e.__removalCount||"string"!=typeof e.nodeName||"string"!=typeof e.textContent||"function"!=typeof e.removeChild||!(e.attributes instanceof f)||"function"!=typeof e.removeAttribute||"function"!=typeof e.setAttribute||"string"!=typeof e.namespaceURI||"function"!=typeof e.insertBefore||"function"!=typeof e.hasChildNodes)},It=function(t){return"object"===e(l)?t instanceof l:t&&"object"===e(t)&&"number"==typeof t.nodeType&&"string"==typeof t.nodeName},Lt=function(e,t,n){ye[e]&&_(ye[e],(function(e){e.call(r,t,n,gt)}))},Pt=function(e){var t;if(Lt("beforeSanitizeElements",e,null),Tt(e))return Ot(e),!0;if(A(/[\u0080-\uFFFF]/,e.nodeName))return Ot(e),!0;var n=be(e.nodeName);if(Lt("uponSanitizeElement",e,{tagName:n,allowedTags:je}),e.hasChildNodes()&&!It(e.firstElementChild)&&(!It(e.content)||!It(e.content.firstElementChild))&&A(/<[/\w]/g,e.innerHTML)&&A(/<[/\w]/g,e.textContent))return Ot(e),!0;if("select"===n&&A(/