diff --git a/calcit.cirru b/calcit.cirru index 6a339a4..d752f95 100644 --- a/calcit.cirru +++ b/calcit.cirru @@ -1,52 +1,67 @@ -{} (:about "|Machine-generated snapshot. Do not edit directly — changes will be overwritten. Use `calcit query` to inspect and `calcit edit`/`calcit tree` to modify. Run `calcit docs agents --full` first. Manual edits must follow format and schema conventions, then run `calcit edit format`.") (:package |app) - :entries $ {} - :default $ {} (:description |) (:init-fn 'app.main/main!) (:mode :js) (:reload-fn 'app.main/reload!) +{} + :about "|Machine-generated snapshot. Do not edit directly — changes will be overwritten. Use `calcit query` to inspect and `calcit edit`/`calcit tree` to modify. Run `calcit docs agents --contract` before mutations; use `--full` for first orientation or changed contract digest. Manual edits must follow format and schema conventions, then run `calcit edit format`." + :package |app + :entries $ {} $ :default + {} (:description |) (:init-fn 'app.main/main!) (:mode :js) (:reload-fn 'app.main/reload!) :feature-policy $ {} :modules $ [] |respo.calcit/ |lilac/ |memof/ |respo-ui.calcit/ |respo-markdown.calcit/ |reel.calcit/ :type-slots $ {} :files $ {} 'app.comp.container $ %{} 'FileEntry :defs $ {} + 'HighlightResultHost $ %{} 'CodeEntry (:doc |) + :code $ quote $ deftrait HighlightResultHost (:value 'String) + :examples $ [] + :ffi $ {} (:backend :js) (:kind :external-object) + :schema $ :: 'Trait + 'HljsHost $ %{} 'CodeEntry (:doc |) + :code $ quote $ deftrait HljsHost + .register-language! $ :: 'Fn $ {} + :args $ [] 'app.comp.container/HljsHost 'String 'Dynamic + :return 'Unit + .highlight $ :: 'Fn $ {} + :args $ [] 'app.comp.container/HljsHost 'String 'JsObject + :return 'app.comp.container/HighlightResultHost + :examples $ [] + :ffi $ {} (:backend :js) (:kind :external-object) + :names $ {} $ :register-language! |registerLanguage + :schema $ :: 'Trait 'comp-container $ %{} 'CodeEntry (:doc |) - :code $ quote - defcomp comp-container (reel) - let - store $ unsafe-coerce (get reel :store) 'app.types/Store - states $ :states store + :code $ quote $ defcomp comp-container (reel) + let + store $ unsafe-coerce (get reel :store) 'app.types/Store + states $ :states store + div + {} $ :style $ merge ui/global ui/fullscreen ui/row + {} $ :justify-content |center div - {} $ :style - merge ui/global ui/fullscreen ui/row $ {} (:justify-content |center) - div - {} $ :style - {} (:max-width 800) (:width |60%) - :border $ str "|1px solid " (hsl 0 0 90) - :padding 16 - :padding-bottom 200 - :overflow :auto - comp-md-block (slurp |docs/guide.md) - {} (:class-name |markdown-body) - :highlight $ fn (code lang) - if (= lang |cirru) (color/generate code) - .-value $ unsafe-coerce - .!highlight hljs code $ js-object (:language lang) - , js-object - when dev? $ comp-reel (>> states :reel) reel ({}) + {} $ :style $ {} (:max-width 800) (:width |60%) + :border $ str "|1px solid " $ hsl 0 0 90 + :padding 16 + :padding-bottom 200 + :overflow :auto + comp-md-block (slurp |docs/guide.md) + {} (:class-name |markdown-body) + :highlight $ fn (code lang) + if (= lang |cirru) (color/generate code) + .-value $ .highlight (unsafe-coerce hljs 'app.comp.container/HljsHost) code $ js-object (:language lang) + when dev? $ comp-reel (>> states :reel) reel $ {} :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'respo.schema/Component) + :args $ [] 'Dynamic + :features $ #{} :js-ffi 'slurp $ %{} 'CodeEntry (:doc |) - :code $ quote - defmacro slurp (path) - read-file $ str path + :code $ quote $ defmacro slurp (path) + read-file $ str path :examples $ [] - :schema $ :: 'Macro - {} - :capabilities $ #{} :fs-read - :expansion $ :: 'Expr 'String - :required $ [] (:: 'Expr 'String) + :schema $ :: 'Macro $ {} + :capabilities $ #{} :fs-read + :expansion $ :: 'Expr 'String + :required $ [] $ :: 'Expr 'String :ns $ %{} 'NsEntry (:doc |) - :code $ quote - ns app.comp.container $ :require + :code $ quote $ ns app.comp.container + :require respo-ui.core :refer $ hsl respo-ui.core :as ui respo.core :refer $ defcomp >> <> div button textarea span @@ -60,8 +75,8 @@ 'app.config $ %{} 'FileEntry :defs $ {} 'cdn? $ %{} 'CodeEntry (:doc |) - :code $ quote - def cdn? $ cond + :code $ quote $ def cdn? + cond exists? js/window , false (exists? js/process) (= |true js/process.env.cdn) @@ -69,86 +84,115 @@ :examples $ [] :schema $ :: 'Dynamic 'dev? $ %{} 'CodeEntry (:doc |) - :code $ quote - def dev? $ = |dev - option:unwrap-or (get-env |mode) |release + :code $ quote $ def dev? + = |dev $ option:unwrap-or (get-env |mode) |release :examples $ [] :schema $ :: 'Bool 'site $ %{} 'CodeEntry (:doc |) - :code $ quote - def site $ %{} app.types/SiteConfig (:dev-ui |http://localhost:8100/main-fonts.css) (:release-ui |http://cdn.tiye.me/favored-fonts/main-fonts.css) (:cdn-url |http://cdn.tiye.me/cumulo-org/) (:title "|Cumulo Home Page") (:icon |http://cdn.tiye.me/logo/respo.png) (:storage-key |cumulo.org) + :code $ quote $ def site + %{} app.types/SiteConfig (:dev-ui |http://localhost:8100/main-fonts.css) (:release-ui |http://cdn.tiye.me/favored-fonts/main-fonts.css) (:cdn-url |http://cdn.tiye.me/cumulo-org/) (:title "|Cumulo Home Page") (:icon |http://cdn.tiye.me/logo/respo.png) (:storage-key |cumulo.org) :examples $ [] :schema $ :: 'app.types/SiteConfig :ns $ %{} 'NsEntry (:doc |) - :code $ quote - ns app.config $ :require - app.types :refer $ SiteConfig + :code $ quote $ ns app.config + :require $ app.types :refer $ SiteConfig 'app.main $ %{} 'FileEntry :defs $ {} '*reel $ %{} 'CodeEntry (:doc |) - :code $ quote - defatom *reel $ -> reel-schema/reel (assoc :base schema/store) (assoc :store schema/store) + :code $ quote $ defatom *reel + -> reel-schema/reel (assoc :base schema/store) (assoc :store schema/store) :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Ref $ :: 'Map 'Tag 'Dynamic + 'decode-store $ %{} 'CodeEntry + :doc "|Validates open persisted data before it enters the typed application store." + :code $ quote $ defn decode-store (data) + let + states $ get data :states + content $ get data :content + if + and (option:some? states) (option:some? content) + map? $ option:unwrap states + string? $ option:unwrap content + %some $ %{} app.types/Store + :states $ assert-type (option:unwrap states) 'Map + :content $ assert-type (option:unwrap content) 'String + %none + :examples $ [] + :schema $ :: 'Fn $ {} + :args $ [] $ :: 'Map 'Tag 'Dynamic + :return $ :: 'Option 'app.types/Store 'dispatch! $ %{} 'CodeEntry (:doc |) - :code $ quote - defn dispatch! (op) (; println |Dispatch: op) - reset! *reel $ reel-updater updater @*reel op + :code $ quote $ defn dispatch! (op) (; println |Dispatch: op) + reset! *reel $ reel-updater updater @*reel op :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'Unit) + :args $ [] 'Dynamic 'main! $ %{} 'CodeEntry (:doc |) - :code $ quote - defn main! () - println "|Running mode:" $ if config/dev? |dev |release - if ssr? $ render-app! realize-ssr! - .!registerLanguage hljs |clojure clojure-lang - .!registerLanguage hljs |bash bash-lang - render-app! render! - add-watch *reel :changes $ fn (r p) (render-app! render!) - listen-devtools! |k dispatch! - js/window.addEventListener |beforeunload persist-storage! - js/setInterval persist-storage! $ * 1000 60 - let - raw $ js/localStorage.getItem (:storage-key config/site) - when (js-present? raw) - dispatch! $ :: :hydrate-storage - parse-cirru-edn $ unsafe-coerce raw String - println "|App started." + :code $ quote $ defn main! () + println "|Running mode:" $ if config/dev? |dev |release + if ssr? $ render-app! realize-ssr! + .register-language! (unsafe-coerce hljs 'app.comp.container/HljsHost) |clojure clojure-lang + .register-language! (unsafe-coerce hljs 'app.comp.container/HljsHost) |bash bash-lang + render-app! render! + add-watch *reel :changes $ fn (r p) (render-app! render!) + listen-devtools! |k dispatch! + js/window.addEventListener |beforeunload $ fn (event) (persist-storage!) + js/setInterval persist-storage! $ * 1000 60 + let + raw $ js/localStorage.getItem $ :storage-key config/site + when (js-present? raw) + let + parsed $ parse-cirru-edn $ unsafe-coerce raw String + when (map? parsed) + let + restored $ decode-store $ assert-type parsed (:: 'Map 'Tag 'Dynamic) + when (option:some? restored) + dispatch! $ :: :hydrate-storage $ option:unwrap restored + println "|App started." :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'Dynamic) + :args $ [] + :features $ #{} :js-ffi 'mount-target $ %{} 'CodeEntry (:doc |) - :code $ quote - def mount-target $ js/document.querySelector |.app + :code $ quote $ defn mount-target () (js/document.querySelector |.app) :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'Dynamic) + :args $ [] + :features $ #{} :js-ffi 'persist-storage! $ %{} 'CodeEntry (:doc |) - :code $ quote - defn persist-storage! (? e) - js/localStorage.setItem (:storage-key config/site) - format-cirru-edn $ reel-schema/read-field @*reel :store + :code $ quote $ defn persist-storage! () + js/localStorage.setItem (:storage-key config/site) + format-cirru-edn $ reel-schema/read-field @*reel :store + , &unit :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'Unit) + :args $ [] + :features $ #{} :js-ffi 'reload! $ %{} 'CodeEntry (:doc |) - :code $ quote - defn reload! () (clear-cache!) - reset! *reel $ refresh-reel @*reel schema/store updater - println "|Code updated." + :code $ quote $ defn reload! () (clear-cache!) + reset! *reel $ assert-type (refresh-reel @*reel schema/store updater) (:: 'Map 'Tag 'Dynamic) + println "|Code updated." :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'Unit) + :args $ [] 'render-app! $ %{} 'CodeEntry (:doc |) - :code $ quote - defn render-app! (renderer) - renderer mount-target (comp-container @*reel) dispatch! + :code $ quote $ defn render-app! (renderer) + renderer (mount-target) (comp-container @*reel) dispatch! :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'Unit) + :args $ [] $ :: 'Fn + {} (:return 'Unit) + :args $ [] 'Dynamic 'respo.schema/Component $ :: 'Fn + {} (:return 'Unit) + :args $ [] 'Dynamic 'ssr? $ %{} 'CodeEntry (:doc |) - :code $ quote - def ssr? $ js-present? (js/document.querySelector |meta.respo-ssr) + :code $ quote $ def ssr? + js-present? $ js/document.querySelector |meta.respo-ssr :examples $ [] :schema $ :: 'Dynamic :ns $ %{} 'NsEntry (:doc |) - :code $ quote - ns app.main $ :require + :code $ quote $ ns app.main + :require respo.core :refer $ render! clear-cache! realize-ssr! app.comp.container :refer $ comp-container app.updater :refer $ updater @@ -164,8 +208,8 @@ 'app.page $ %{} 'FileEntry :defs $ {} 'base-info $ %{} 'CodeEntry (:doc |) - :code $ quote - def base-info $ {} + :code $ quote $ def base-info + {} :title $ :title config/site :icon $ :icon config/site :ssr nil @@ -173,42 +217,42 @@ :examples $ [] :schema $ :: 'Dynamic 'dev-page $ %{} 'CodeEntry (:doc |) - :code $ quote - defn dev-page () $ make-page | - merge base-info $ {} - :styles $ [] (<< "|http://~(get-ip!):8100/main.css") |/entry/main.css - :scripts $ [] |/client.js - :inline-styles $ [] (slurp |entry/github-gist.css) (slurp |node_modules/github-markdown-css/github-markdown.css) + :code $ quote $ defn dev-page () + make-page | $ merge base-info $ {} + :styles $ [] (<< "|http://~(get-ip!):8100/main.css") |/entry/main.css + :scripts $ [] |/client.js + :inline-styles $ [] (slurp |entry/github-gist.css) + slurp |node_modules/github-markdown-css/github-markdown.css :examples $ [] :schema $ :: 'Dynamic 'main! $ %{} 'CodeEntry (:doc |) - :code $ quote - defn main! () - println "|Running mode:" $ if config/dev? |dev |release - if config/dev? - spit |target/index.html $ dev-page - spit |dist/index.html $ prod-page + :code $ quote $ defn main! () + println "|Running mode:" $ if config/dev? |dev |release + if config/dev? + spit |target/index.html $ dev-page + spit |dist/index.html $ prod-page :examples $ [] :schema $ :: 'Dynamic 'prod-page $ %{} 'CodeEntry (:doc |) - :code $ quote - defn prod-page () $ let + :code $ quote $ defn prod-page () + let reel $ -> reel-schema/reel (assoc :base schema/store) (assoc :store schema/store) - html-content $ make-string (comp-container reel) - assets $ read-string (slurp |dist/assets.edn) + html-content $ make-string $ comp-container reel + assets $ read-string $ slurp |dist/assets.edn cdn $ if config/cdn? (:cdn-url config/site) | prefix-cdn $ fn (x) (str cdn x) - make-page html-content $ merge base-info - {} - :styles $ [] (:release-ui config/site) - :scripts $ map ("#()" -> % :output-name prefix-cdn) assets - :ssr |respo-ssr - :inline-styles $ [] (slurp |entry/github-gist.css) (slurp |node_modules/github-markdown-css/github-markdown.css) (slurp |./entry/main.css) + make-page html-content $ merge base-info $ {} + :styles $ [] $ :release-ui config/site + :scripts $ map ("#()" -> % :output-name prefix-cdn) assets + :ssr |respo-ssr + :inline-styles $ [] (slurp |entry/github-gist.css) + slurp |node_modules/github-markdown-css/github-markdown.css + slurp |./entry/main.css :examples $ [] :schema $ :: 'Dynamic :ns $ %{} 'NsEntry (:doc |) - :code $ quote - ns app.page $ :require + :code $ quote $ ns app.page + :require respo.render.html :refer $ make-string shell-page.core :refer $ make-page spit slurp app.comp.container :refer $ comp-container @@ -219,45 +263,41 @@ cumulo-util.build :refer $ get-ip! clojure.core.strint :refer $ << 'app.schema $ %{} 'FileEntry - :defs $ {} - 'store $ %{} 'CodeEntry (:doc |) - :code $ quote - def store $ %{} app.types/Store + :defs $ {} $ 'store + %{} 'CodeEntry (:doc |) + :code $ quote $ def store + %{} app.types/Store :states $ {} :content | :examples $ [] :schema $ :: 'app.types/Store :ns $ %{} 'NsEntry (:doc |) - :code $ quote - ns app.schema $ :require - app.types :refer $ Store + :code $ quote $ ns app.schema + :require $ app.types :refer $ Store 'app.types $ %{} 'FileEntry :defs $ {} 'SiteConfig $ %{} 'CodeEntry (:doc |) - :code $ quote - defstruct SiteConfig (:dev-ui 'String) (:release-ui 'String) (:cdn-url 'String) (:title 'String) (:icon 'String) (:storage-key 'String) + :code $ quote $ defstruct SiteConfig (:dev-ui 'String) (:release-ui 'String) (:cdn-url 'String) (:title 'String) (:icon 'String) (:storage-key 'String) :examples $ [] :schema $ :: 'StructDef 'Store $ %{} 'CodeEntry (:doc |) - :code $ quote - defstruct Store (:states 'Map) (:content 'String) + :code $ quote $ defstruct Store (:states 'Map) (:content 'String) :examples $ [] :schema $ :: 'StructDef :ns $ %{} 'NsEntry (:doc |) - :code $ quote (ns app.types) + :code $ quote $ ns app.types 'app.updater $ %{} 'FileEntry - :defs $ {} - 'updater $ %{} 'CodeEntry (:doc |) - :code $ quote - defn updater (store op op-id op-time) - match op - (:states cursor s) (update-states store cursor s) - (:content c) (assoc store :content c) - (:hydrate-storage d) d - _ $ do (eprintln "|Unknown op:" op) store + :defs $ {} $ 'updater + %{} 'CodeEntry (:doc |) + :code $ quote $ defn updater (store op op-id op-time) + match op + (:states cursor s) (update-states store cursor s) + (:content c) (assoc store :content c) + (:hydrate-storage d) d + _ $ do (eprintln "|Unknown op:" op) store :examples $ [] - :schema $ :: 'Dynamic + :schema $ :: 'Fn $ {} (:return 'app.types/Store) + :args $ [] 'app.types/Store 'Dynamic 'Dynamic 'Dynamic :ns $ %{} 'NsEntry (:doc |) - :code $ quote - ns app.updater $ :require - respo.cursor :refer $ update-states + :code $ quote $ ns app.updater + :require $ respo.cursor :refer $ update-states diff --git a/config/calcit-quality.cirru b/config/calcit-quality.cirru index 738331f..e317f5e 100644 --- a/config/calcit-quality.cirru +++ b/config/calcit-quality.cirru @@ -4,10 +4,10 @@ :codeNil 0 :declaredOptional 0 :deprecatedCalls 0 - :schemaDynamic 1 - :typeNone 1 + :schemaDynamic 0 + :typeNone 0 :typeNotFull 1 - :unresolved 1 + :unresolved 0 :unsafeCoerce 2 |app.config/cdn? $ {} (:codeDynamic 0) :codeNil 0 @@ -27,59 +27,50 @@ :typeNotFull 1 :unresolved 1 :unsafeCoerce 0 - |app.main/dispatch! $ {} (:codeDynamic 0) + |app.main/decode-store $ {} (:codeDynamic 0) :codeNil 0 :declaredOptional 0 :deprecatedCalls 0 :schemaDynamic 1 - :typeNone 1 + :typeNone 0 :typeNotFull 1 :unresolved 1 :unsafeCoerce 0 - |app.main/main! $ {} (:codeDynamic 0) - :codeNil 0 - :declaredOptional 0 - :deprecatedCalls 0 - :schemaDynamic 1 - :typeNone 1 - :typeNotFull 1 - :unresolved 1 - :unsafeCoerce 1 - |app.main/mount-target $ {} (:codeDynamic 0) + |app.main/dispatch! $ {} (:codeDynamic 0) :codeNil 0 :declaredOptional 0 :deprecatedCalls 0 :schemaDynamic 1 - :typeNone 1 + :typeNone 0 :typeNotFull 1 :unresolved 1 :unsafeCoerce 0 - |app.main/persist-storage! $ {} (:codeDynamic 0) + |app.main/main! $ {} (:codeDynamic 0) :codeNil 0 :declaredOptional 0 :deprecatedCalls 0 - :schemaDynamic 1 - :typeNone 1 + :schemaDynamic 0 + :typeNone 0 :typeNotFull 1 - :unresolved 1 - :unsafeCoerce 0 - |app.main/reload! $ {} (:codeDynamic 0) + :unresolved 0 + :unsafeCoerce 3 + |app.main/mount-target $ {} (:codeDynamic 0) :codeNil 0 :declaredOptional 0 :deprecatedCalls 0 - :schemaDynamic 1 - :typeNone 1 + :schemaDynamic 0 + :typeNone 0 :typeNotFull 1 - :unresolved 1 + :unresolved 0 :unsafeCoerce 0 |app.main/render-app! $ {} (:codeDynamic 0) :codeNil 0 :declaredOptional 0 :deprecatedCalls 0 - :schemaDynamic 1 - :typeNone 1 + :schemaDynamic 2 + :typeNone 0 :typeNotFull 1 - :unresolved 1 + :unresolved 2 :unsafeCoerce 0 |app.main/ssr? $ {} (:codeDynamic 0) :codeNil 0 @@ -130,20 +121,20 @@ :codeNil 0 :declaredOptional 0 :deprecatedCalls 0 - :schemaDynamic 1 - :typeNone 1 + :schemaDynamic 3 + :typeNone 0 :typeNotFull 1 - :unresolved 1 + :unresolved 3 :unsafeCoerce 0 :metrics $ {} (:codeDynamic 0) :codeNil 2 :declaredOptional 0 :deprecatedCalls 0 - :schemaDynamic 15 - :typeNone 13 - :typeNotFull 14 - :unresolved 17 - :unsafeCoerce 3 + :schemaDynamic 14 + :typeNone 5 + :typeNotFull 13 + :unresolved 16 + :unsafeCoerce 5 :scope $ {} (:includeDependencies false) :namespace nil :namespacePrefix nil diff --git a/deps.cirru b/deps.cirru index b26221d..55225a0 100644 --- a/deps.cirru +++ b/deps.cirru @@ -1,8 +1,9 @@ -{} (:calcit-version |0.13.77) (:version |0.1.0) - :dependencies $ {} (|Respo/reel.calcit |0.6.19) - |Respo/respo-markdown.calcit |0.4.33 - |Respo/respo-ui.calcit |0.7.19 - |Respo/respo.calcit |0.16.95 +{} (:calcit-version |0.14.17) + :version |0.1.0 + :dependencies $ {} (|Respo/reel.calcit |0.6.23) + |Respo/respo-markdown.calcit |0.4.36 + |Respo/respo-ui.calcit |0.7.22 + |Respo/respo.calcit |0.16.102 |calcit-lang/lilac |0.5.9 - |calcit-lang/memof |0.0.31 + |calcit-lang/memof |0.0.33 diff --git a/package.json b/package.json index 1fa1cc5..d92d9fd 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,7 @@ "vite": "8.2.2" }, "dependencies": { - "@calcit/procs": "0.13.77", + "@calcit/procs": "0.14.17", "cirru-color": "^0.2.4", "copy-text-to-clipboard": "^3.2.1", "dayjs": "^1.11.21", diff --git a/yarn.lock b/yarn.lock index 6f583a5..f5b367b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5,14 +5,14 @@ __metadata: version: 8 cacheKey: 10c0 -"@calcit/procs@npm:0.13.77": - version: 0.13.77 - resolution: "@calcit/procs@npm:0.13.77" +"@calcit/procs@npm:0.14.17": + version: 0.14.17 + resolution: "@calcit/procs@npm:0.14.17" dependencies: "@calcit/ternary-tree": "npm:0.0.26" "@cirru/parser.ts": "npm:^0.0.9" "@cirru/writer.ts": "npm:^0.1.9" - checksum: 10c0/7f0d79ad9e7963728518c3754174136d7c2e906c7177785d633f622300be11b84a8f9ae659c5b93c9fb8f7d47e4fffba773bbe90a30a0f53fc3d1258ab850851 + checksum: 10c0/91b236157b56eb3c9478796d31e2bb96f3668ec57dddb2875162c4a069f5b8ee769b8dd9146f3f34d71812393e72cff0c47022e59e605fffecbeca2b0787b8da languageName: node linkType: hard @@ -193,7 +193,7 @@ __metadata: version: 0.0.0-use.local resolution: "calcit-workflow@workspace:." dependencies: - "@calcit/procs": "npm:0.13.77" + "@calcit/procs": "npm:0.14.17" bottom-tip: "npm:^0.1.5" cirru-color: "npm:^0.2.4" copy-text-to-clipboard: "npm:^3.2.1"