gadget-inspector
所属分类:其他
开发工具:Clojure
文件大小:0KB
下载次数:0
上传日期:2023-04-12 10:16:17
上 传 者:
sh-1993
说明: ClojureScript数据浏览器-从Chrome扩展或通过任何浏览器中的服务器使用,
(ClojureScript data browser - use from a Chrome extension or over a server in any browser,)
文件列表:
.dir-locals.el (149, 2023-04-12)
LICENSE (11218, 2023-04-12)
Makefile (2630, 2023-04-12)
demo/ (0, 2023-04-12)
demo/deps.edn (357, 2023-04-12)
demo/dev.cljs.edn (269, 2023-04-12)
demo/prod.cljs.edn (111, 2023-04-12)
demo/resources/ (0, 2023-04-12)
demo/resources/public/ (0, 2023-04-12)
demo/resources/public/gadget-demo.js (957, 2023-04-12)
demo/resources/public/index.html (486, 2023-04-12)
demo/src/ (0, 2023-04-12)
demo/src/gadget_demo/ (0, 2023-04-12)
demo/src/gadget_demo/core.cljs (11700, 2023-04-12)
extension/ (0, 2023-04-12)
extension/background.js (929, 2023-04-12)
extension/cljs.png (64806, 2023-04-12)
extension/content-script.js (1432, 2023-04-12)
extension/devtools.html (36, 2023-04-12)
extension/devtools.js (1926, 2023-04-12)
extension/firefox-manifest.json (135, 2023-04-12)
extension/icon-128.png (16721, 2023-04-12)
extension/icon-24.png (1220, 2023-04-12)
extension/icon-256.png (41607, 2023-04-12)
extension/icon-36.png (1780, 2023-04-12)
extension/icon-48.png (4233, 2023-04-12)
extension/manifest.json (903, 2023-04-12)
extension/panel.html (241, 2023-04-12)
icon.xcf (2167449, 2023-04-12)
inspector/ (0, 2023-04-12)
inspector/cljs.edn (57, 2023-04-12)
inspector/deps.edn (868, 2023-04-12)
inspector/remote-cljs.edn (68, 2023-04-12)
inspector/src/ (0, 2023-04-12)
inspector/src/cljs_data_browser/ (0, 2023-04-12)
inspector/src/cljs_data_browser/actions.cljs (81, 2023-04-12)
inspector/src/cljs_data_browser/inspector.cljs (5373, 2023-04-12)
inspector/src/cljs_data_browser/panel.cljs (838, 2023-04-12)
... ...
# ClojureScript Data Browser
Developer tooling for inspecting ClojureScript data structures from running
programs. Inspect data in devtools using the Chrome or Firefox extension, or
in any other browser using the remote inspector.
## WARNING
This is software in the making, not even alpha level. It *will* have breaking
changes. If you're curious, please see below for usage. If you can wait, this
tool will at some point become stable, at which point breaking changes will
never occur intentionally.
## Inspecting a page
You need the small agent library to expose data for inspection. It is available
from Clojars:
```clj
cjohansen/gadget-inspector {:mvn/version "0.2023.04.12"}
```
*NB!* Gadget requires `clojure.datafy`, and will only work with ClojureScript
1.9.520 or newer.
Then, either create your app-wide atom with the inspector, or inspect an
existing atom:
```clj
(require '[gadget.inspector :as inspector])
;; Either
(def store (inspector/create-atom "App state" {}))
;; ...or
(def my-store (atom {}))
(inspector/inspect "App state" my-store)
```
You can also inspect regular persistent data structures, for example the data
going into a UI component, with the `inspect` function:
```clj
(def data {:band "Rush"})
(inspector/inspect "Band data" data)
```
The label operates as both an identifier for your data, and a header, so you can
tell structures apart. Inspecting another piece of data with the same label will
replace the corresponding section in the inspector.
### Controlling the liveness of the inspector
By default, the inspector will only update its UI 250ms after changes to your
data occurred. This should help avoid the inspector detracting from your app's
performance. You can override this value if you wish:
```clj
(require '[gadget.inspector :as inspector])
;; Render less frequently
(inspector/set-render-debounce-ms! 1000)
;; Render synchronously on every change
(inspector/set-render-debounce-ms! 0)
```
### Temporarily pausing inspection
Even with debouncing, you may find that the work done by the inspector is too
much in performance critical moments. While this will never be a problem for
regular users in production, it can still be annoying during development. For
those cases, you can pause the inspector, and resume it when the intensive work
has completed:
```clj
(require '[gadget.inspector :as inspector]
'[cljs.core.async :refer [go s js/atob js/JSON.parse (js->clj :keywordize-keys true)))
(defmethod datafy/datafy :jwt [token]
(let [[header data sig] (str/split token #"\.")]
{:header (base64json header)
:data (base64json data)
:signature sig}))
(defmethod gadget/render [:inline :jwt] [_ {:keys [raw]}]
[:strong "JWT: " [:gadget/string raw]])
```
Let's see this in practice. Given this data:
```clj
(def data
{:token "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"})
```
When Gadget renders this map, the token will be rendered with the `:inline`
view. This view is passed both the token string, and the map returned from the
`datafy` implementation. This particular inline view renders the token string
with the `"JWT: "` prefix. Since the datafy result is a map, the token will be
navigable in the browser.
When you click the token, Gadget will render the token in the `:full` view. For
`:jwt`, this view renders the datafyed value with the map browser. Since this is
a map, it can be navigated deeper without any further ado.
### Rendering custom data types
The first step in rendering custom data types is to define a custom type
inference. Let's say we have some literals from the server that we want to
preserve with their literal form, such as
[java.time literals](https://github.com/cjohansen/gadget-inspector/blob/master/https://github.com/magnars/java-time-literals).
Step 1 is to define the type inference:
```clj
(require '[gadget.datafy :as datafy])
(datafy/add-type-inference
(fn [data]
(when (and (string? data) (re-find #"^#time" data))
:java-time-literal)))
```
The Java time literals are just strings on the client - if we do nothing else,
they will be rendered as strings, e.g. `"#time/ld \"2019-08-01\""`. To make them
render as literals, we'll implement the renderer function for inline views of
the `:java-time-literal` type:
```cl
(require '[clojure.string :as str]
'[gadget.core :as gadget])
(defmethod gadget/render [:inline :java-time-literal] [_ {:keys [raw]}]
(let [[prefix str] (str/split raw " ")]
[:gadget/literal {:prefix prefix
:value (cljs.reader/read-string str)}]))
```
There is no point in implementing the `:full` view, because the literal is a
string, and strings are not navigable by default, thus it will never be rendered
with the `:full` view.
We could implement `datafy` for the literal and produce a JS date object, and
then use that to power a `:full` view:
```clj
(require '[clojure.string :as str]
'[gadget.datafy :as datafy])
(defmethod datafy/datafy :java-time-literal [literal]
(let [[prefix str] (str/split raw " ")]
(case prefix
"#time/ld" (let [date-str (cljs.reader/read-string str)
[y m d] (map #(js/parseInt % 10) (str/split date-str
#"-"))]
(js/Date. y (dec m) d)))))
```
Gadget's built-in instant tooling would pick this up and allow you to navigate
into this value to see year, month, date, etc. Please disregard the abomination
that is converting a local date to an instant like this.
### Sorting
When adding custom types for maps, you might want a different sorting than the
default. By default, Gadget will try to sort keys alpha-numerically. You can
override the default behavior by implementing the `gadget.core/Browsable`
protocol. It defines a single method, `(entries [d])`, which takes the data
(e.g. a map), and returns a vector of key value pairs, in preferred order. You
can implement this for individual maps by including an implementation as
metadata:
```clj
(def key-order [:preferred :order :of :keys])
(defmethod gadget.datafy/datafy :my-type [m]
(with-meta
m
{`entries (fn [m]
(sort-by (gadget.core/key-order key-order)))}))
```
## Components
Gadget allows renderers to return pure unadulterated
[hiccup](https://github.com/cjohansen/gadget-inspector/blob/master/https://github.com/weavejester/hiccup), essentially allowing you to
dictate the exact rendering of a piece of data. To avoid re-implementing
components that the Gadget inspector already uses in an uncanny valley
all-you-can-eat, Gadget allows you to use some components via namespaced
keywords.
### Basic types
Dedicated inline components for basic types. All of these take the value as
their only argument, e.g:
```clj
;; Just the string component
[:gadget/string "Some string"]
;; Embedded in other markup
[:div {}
[:gadget/string "Some string"]
[:gadget/number 12]]
```
The available types are:
- `:gadget/string`
- `:gadget/number`
- `:gadget/keyword`
- `:gadget/boolean`
- `:gadget/date`
### Literals
```clj
[`:gadget/literal` {:prefix "#inst" :str "2019-01-01T12:00:00Z"}]
```
### Link
Renders a value like a link.
```clj
[`:gadget/link` "{100 keys}"]
```
### Code
Inline code samples can be created with `[:gadget/code code-string]`.
### Map browser
Most `:full` renders use the browser component. It takes a sequence of key-value
pairs:
```clj
[:gadget/browser kv-coll]
```
`kv-coll` should be a collection of maps with keys `{:k :v :actions}` where:
- `:k` is hiccup for the key/index
- `:v` is hiccup for the value
- `:actions` is an actions map - `:go` and `:copy` are currently supported
## Reference
All functions that are exposed for extension.
### `(defmethod gadget.core/copy type-kw [v])`
Returns the value copied to the copy buffer when clicking the copy button next
to this value. Dispatches on the synthetic keyword type. The default
implementation returns `(pr-str v)`.
### `(defmethod gadget.core/render [view type] [view data & [view-opts]])`
Render the data of type `type` with view `view`. Currently `view` is one of
`:inline` or `:full`. `data` is a map with keys `:raw` - the raw data, `:type` -
the synthetic type, and `:data` - the datafied data.
### `(gadget.core/add-type-inference type [f])`
Add type inference. Type inference is done by calling each registered function
until a non-nil value is returned. LIFO - the last registered inference will be
tried first. The function should return `nil` for unknown values, otherwise a
keyword that names the "type". Any other return value will cause an error.
### `(gadget.datafy/datafy type [val])`
A wrapper around `clojure.datafy/datafy` that dispatches on Gadget's synthtic
types. The default implementation calls `clojure.datafy/datafy`.
## Developing Gadget
To develop gadget inspector, clone the repo and open
[lib/deps.edn](https://github.com/cjohansen/gadget-inspector/blob/master/lib/deps.edn). From there, open CIDER (assuming Emacs). If not in
Emacs, you should be able to run a Figwheel REPL with:
```
clojure -A:dev -m figwheel.main --build dev --repl
```
The [lib/dev/gadget/dev.clj](https://github.com/cjohansen/gadget-inspector/blob/master/dev namespace) provides some test data for you to
play with. The REPL runs the inspector in a regular browser tab in
[http://localhost:9570](https://github.com/cjohansen/gadget-inspector/blob/master/http://localhost:9500).
## License
Copyright 2018-2023 Christian Johansen
Distributed under the Eclipse Public License either version 1.0 or (at your
option) any later version.
近期下载者:
相关文件:
收藏者: