├── .circleci
└── config.yml
├── .github
└── workflows
│ └── push.yml
├── .gitignore
├── .gitmodules
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── bb.clj
├── deps.edn
├── docs
└── api
│ ├── clj-chrome-devtools.automation.fixture.html
│ ├── clj-chrome-devtools.automation.html
│ ├── clj-chrome-devtools.automation.launcher.html
│ ├── clj-chrome-devtools.commands.accessibility.html
│ ├── clj-chrome-devtools.commands.animation.html
│ ├── clj-chrome-devtools.commands.application-cache.html
│ ├── clj-chrome-devtools.commands.audits.html
│ ├── clj-chrome-devtools.commands.background-service.html
│ ├── clj-chrome-devtools.commands.browser.html
│ ├── clj-chrome-devtools.commands.cache-storage.html
│ ├── clj-chrome-devtools.commands.cast.html
│ ├── clj-chrome-devtools.commands.console.html
│ ├── clj-chrome-devtools.commands.css.html
│ ├── clj-chrome-devtools.commands.database.html
│ ├── clj-chrome-devtools.commands.debugger.html
│ ├── clj-chrome-devtools.commands.device-orientation.html
│ ├── clj-chrome-devtools.commands.dom-debugger.html
│ ├── clj-chrome-devtools.commands.dom-snapshot.html
│ ├── clj-chrome-devtools.commands.dom-storage.html
│ ├── clj-chrome-devtools.commands.dom.html
│ ├── clj-chrome-devtools.commands.domdebugger.html
│ ├── clj-chrome-devtools.commands.domsnapshot.html
│ ├── clj-chrome-devtools.commands.domstorage.html
│ ├── clj-chrome-devtools.commands.emulation.html
│ ├── clj-chrome-devtools.commands.event-breakpoints.html
│ ├── clj-chrome-devtools.commands.fetch.html
│ ├── clj-chrome-devtools.commands.headless-experimental.html
│ ├── clj-chrome-devtools.commands.heap-profiler.html
│ ├── clj-chrome-devtools.commands.indexed-db.html
│ ├── clj-chrome-devtools.commands.input.html
│ ├── clj-chrome-devtools.commands.inspector.html
│ ├── clj-chrome-devtools.commands.io.html
│ ├── clj-chrome-devtools.commands.layer-tree.html
│ ├── clj-chrome-devtools.commands.log.html
│ ├── clj-chrome-devtools.commands.media.html
│ ├── clj-chrome-devtools.commands.memory.html
│ ├── clj-chrome-devtools.commands.network.html
│ ├── clj-chrome-devtools.commands.overlay.html
│ ├── clj-chrome-devtools.commands.page.html
│ ├── clj-chrome-devtools.commands.performance-timeline.html
│ ├── clj-chrome-devtools.commands.performance.html
│ ├── clj-chrome-devtools.commands.profiler.html
│ ├── clj-chrome-devtools.commands.runtime.html
│ ├── clj-chrome-devtools.commands.schema.html
│ ├── clj-chrome-devtools.commands.security.html
│ ├── clj-chrome-devtools.commands.service-worker.html
│ ├── clj-chrome-devtools.commands.storage.html
│ ├── clj-chrome-devtools.commands.system-info.html
│ ├── clj-chrome-devtools.commands.target.html
│ ├── clj-chrome-devtools.commands.tethering.html
│ ├── clj-chrome-devtools.commands.tracing.html
│ ├── clj-chrome-devtools.commands.web-audio.html
│ ├── clj-chrome-devtools.commands.web-authn.html
│ ├── clj-chrome-devtools.core.html
│ ├── clj-chrome-devtools.events.html
│ ├── clj-chrome-devtools.impl.command.html
│ ├── clj-chrome-devtools.impl.connection.html
│ ├── clj-chrome-devtools.impl.define.html
│ ├── clj-chrome-devtools.impl.util.html
│ ├── clj-chrome-devtools.protocol-definitions.html
│ ├── css
│ ├── default.css
│ └── highlight.css
│ ├── index.html
│ └── js
│ ├── highlight.min.js
│ ├── jquery.min.js
│ └── page_effects.js
├── project.clj
├── resources
├── clj_chrome_devtools_runner.tpl
└── test-page.tpl
├── src
└── clj_chrome_devtools
│ ├── automation.cljc
│ ├── automation
│ ├── fixture.clj
│ └── launcher.clj
│ ├── cljs
│ └── test.clj
│ ├── commands
│ ├── accessibility.clj
│ ├── animation.clj
│ ├── application_cache.clj
│ ├── audits.clj
│ ├── background_service.clj
│ ├── browser.clj
│ ├── cache_storage.clj
│ ├── cast.clj
│ ├── console.clj
│ ├── css.clj
│ ├── database.clj
│ ├── debugger.clj
│ ├── device_orientation.clj
│ ├── dom.clj
│ ├── dom_debugger.clj
│ ├── dom_snapshot.clj
│ ├── dom_storage.clj
│ ├── emulation.clj
│ ├── event_breakpoints.clj
│ ├── fetch.clj
│ ├── headless_experimental.clj
│ ├── heap_profiler.clj
│ ├── indexed_db.clj
│ ├── input.clj
│ ├── inspector.clj
│ ├── io.clj
│ ├── layer_tree.clj
│ ├── log.clj
│ ├── media.clj
│ ├── memory.clj
│ ├── network.clj
│ ├── overlay.clj
│ ├── page.clj
│ ├── performance.clj
│ ├── performance_timeline.clj
│ ├── profiler.clj
│ ├── runtime.clj
│ ├── schema.clj
│ ├── security.clj
│ ├── service_worker.clj
│ ├── storage.clj
│ ├── system_info.clj
│ ├── target.clj
│ ├── tethering.clj
│ ├── tracing.clj
│ ├── web_audio.clj
│ └── web_authn.clj
│ ├── core.clj
│ ├── events.clj
│ ├── impl
│ ├── command.clj
│ ├── connection.cljc
│ ├── define.clj
│ └── util.clj
│ └── protocol_definitions.clj
├── test
├── clj_chrome_devtools
│ ├── automation_test.clj
│ ├── chrome_test.clj
│ ├── domain_test.clj
│ └── impl
│ │ └── connection_test.clj
└── test-page.html
└── update-devtools-protocol.sh
/.circleci/config.yml:
--------------------------------------------------------------------------------
1 | # Clojure CircleCI 2.0 configuration file
2 | #
3 | # Check https://circleci.com/docs/2.0/language-clojure/ for more details
4 | #
5 | version: 2
6 | jobs:
7 | build:
8 | docker:
9 | # specify the version you desire here
10 | - image: circleci/clojure:lein-2.7.1-browsers
11 |
12 | working_directory: ~/repo
13 |
14 | environment:
15 | LEIN_ROOT: "true"
16 | # Customize the JVM maximum heap limit
17 | JVM_OPTS: -Xmx3200m
18 |
19 | steps:
20 | - checkout
21 |
22 | - run: git submodule update --init
23 |
24 | # Download and cache dependencies
25 | - restore_cache:
26 | keys:
27 | - v1-dependencies-{{ checksum "project.clj" }}
28 | # fallback to using the latest cache if no exact match is found
29 | - v1-dependencies-
30 |
31 | - run: lein deps
32 |
33 | - save_cache:
34 | paths:
35 | - ~/.m2
36 | key: v1-dependencies-{{ checksum "project.clj" }}
37 |
38 | # run tests!
39 | - run: lein test
--------------------------------------------------------------------------------
/.github/workflows/push.yml:
--------------------------------------------------------------------------------
1 | name: Push
2 | on: push
3 | jobs:
4 | Test:
5 | runs-on: ubuntu-latest
6 | steps:
7 | - uses: actions/checkout@v1
8 | - name: Install Clojure
9 | # So we’ll have the `clojure` command and tools.deps.
10 | run: |
11 | curl -O https://download.clojure.org/install/linux-install-1.10.1.469.sh
12 | chmod +x linux-install-1.10.1.469.sh
13 | sudo ./linux-install-1.10.1.469.sh
14 | # Once GitHub adds a dependency caching feature to Actions we’ll be able to use it here to speed
15 | # up this job. In the meantime, the following step will download all the deps every time it is
16 | # run.
17 | - name: Run tests
18 | run: clojure -A:test
19 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | pom.xml
2 | pom.xml.asc
3 | *.jar
4 | *.class
5 | /lib/
6 | /classes/
7 | /target/
8 | /checkouts/
9 | .cpcache
10 | .lein-deps-sum
11 | .lein-repl-history
12 | .lein-plugins/
13 | .lein-failures
14 | .nrepl-port
15 | .idea
16 | *.iml
17 | /CLOJARS_deploy_token
18 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tatut/clj-chrome-devtools/7c895ab355b17a630b38070a334eef2196b0f91a/.gitmodules
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | ## 20220405
2 | - Major changes under the hood
3 | - Add support for using with Babashka
4 | - Remove jetty (use JDK11 HTTP library native WebSocket)
5 | - Remove timbre (prefer clojure.tools.logging in libraries)
6 | - Remove core.async (use simpler promises and callbacks)
7 |
8 | ## 20200423
9 | - Avoid blocking IO in go-block (#27)
10 |
11 | ## 20190601
12 | - Change test output video to APNG for better quality
13 | - Generate videos even if cljs tests fail
14 | - Add :loop-video? option to control looping
15 |
16 | ## 20190530.1
17 | - Add :verbose? flag to test runner (for better troubleshooting)
18 | - Add :ring-handler flag to test runner (if tests need to load some resources)
19 | - Detect if test page has error before tests are started
20 |
21 | ## 20190530
22 | - Ability to take screenshots in cljs tests (use `(js/screenshot)`)
23 | - Combine multiple screenshots to GIF animation
24 |
25 |
26 | ## 20190529
27 | - More reliable project.clj loading in cljs test runner
28 |
29 | ## 20190502
30 | - Deps update release
31 |
32 | ## 20190329
33 | - Made ws client optionally configurable
34 |
35 | ## 20180528
36 | - Add `:no-sandbox?` option (mikkoronkkomaki)
37 |
38 | ## 20180310
39 | - ClojureScript test runner as a Clojure test (see `clj-chrome-devtools.cljs.test` namespace)
40 | - Moved to date based versioning
41 |
42 | ## [0.2.4] - 2018-01-04
43 | - Fixed connection timeout (hagmonk)
44 | - Changed generated API inflections (hagmonk)
45 |
46 | ## [0.2.3] - 2017-12-20
47 | - Started this change log
48 | - Improved connection handling (thanks hagmonk)
49 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # New automation functionality
2 |
3 | The higher level automation utilities is where most of the work is done and new automation utilities are welcome.
4 | PRs welcome, just follow the common pattern of providing two arities: one for using the global automation context
5 | and one where it is provided as the first parameter.
6 |
7 | # Compatibility
8 |
9 | Please add tests for new functionality. Breaking existing tests or changing published API will not be merged.
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Tatu Tarvainen
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # clj-chrome-devtools
2 |
3 | [](https://clojars.org/clj-chrome-devtools) 
4 |
5 | clj-chrome-devtools is a simple library for controlling a headless Chrome with the
6 | Chrome DevTools Protocol. The protocol is based on a websocket connection between
7 | clojure and chrome. All the functions are automatically generated from the protocol
8 | specification JSON files.
9 |
10 | ## Quick start with Babashka
11 |
12 | See [bb.clj](https://github.com/tatut/clj-chrome-devtools/blob/master/bb.clj) file for a quick
13 | script that can be used from [Babashka](https://babashka.org).
14 |
15 | ## Goals
16 |
17 | The goal of the project is to provide a general purpose library for using headless chrome, both in
18 | production use and in testing scenarios.
19 |
20 | The CDP part, which is autogenerated, should be stable and will be updated when CDP protocol changes.
21 |
22 | The higher level automation utilities is where most of the work is done and new automation utilities are welcome.
23 | PRs welcome, just follow the common pattern of providing two arities: one for using the global automation context and
24 | one where it is provided as the first parameter.
25 |
26 |
27 | ## API Docs
28 |
29 | See codox generated [API docs](https://tatut.github.io/clj-chrome-devtools/api/index.html).
30 |
31 | All the low-level auto-generated commands from Chrome Devtools Protocol are in `clj-chrome-devtools.command.*`
32 | namespaces. Note: to use the low-level API you need to implement event handlers for listening to data Chrome sends
33 | the client.
34 |
35 | There is the beginnings of a rudimentary higher level API in `clj-chrome-devtools.automation`.
36 | There is also a `clojure.test` fixture to run tests with a fresh headless chrome in `clj-chrome-devtools.automation.fixture`.
37 |
38 | ## Example usage
39 |
40 | For using the higher level API for screen scraping and browser testing, see [chrome_test.clj](https://github.com/tatut/clj-chrome-devtools/blob/master/test/clj_chrome_devtools/chrome_test.clj) file.
41 |
42 | The following shows a simple REPL usage, navigating to a page and inspecting content.
43 | The connection is the first parameter of all calls. You can also set the connection to use with
44 | `set-current-connection!` and omit the connection parameter for convenience.
45 |
46 |
47 | ```clojure
48 | clj-chrome-devtools.core> (def c (connect "localhost" 9222))
49 | #'clj-chrome-devtools.core/c
50 | clj-chrome-devtools.core> (require '[clj-chrome-devtools.commands.page :as page]
51 | '[clj-chrome-devtools.commands.dom :as dom])
52 | nil
53 | clj-chrome-devtools.core> (page/navigate c {:url "http://webjure.org/"})
54 | {:frame-id "68439.1"}
55 | clj-chrome-devtools.core> (dom/get-document c {:depth 1})
56 | {:root
57 | {:children
58 | [{:node-type 1,
59 | :node-id 2,
60 | :backend-node-id 4,
61 | :parent-id 1,
62 | :node-name "HTML",
63 | :node-value "",
64 | :frame-id "68439.1",
65 | :local-name "html",
66 | :child-node-count 2,
67 | :attributes []}],
68 | :document-url "http://webjure.org/",
69 | :node-type 9,
70 | :base-url "http://webjure.org/",
71 | :node-id 1,
72 | :backend-node-id 3,
73 | :node-name "#document",
74 | :node-value "",
75 | :xml-version "",
76 | :local-name "",
77 | :child-node-count 1}}
78 | clj-chrome-devtools.core> (use 'clojure.repl)
79 | nil
80 | clj-chrome-devtools.core> (doc dom/get-outer-html)
81 | -------------------------
82 | clj-chrome-devtools.commands.dom/get-outer-html
83 | ([] [{:as params, :keys [node-id]}] [connection {:as params, :keys [node-id]}])
84 | Returns node's HTML markup.
85 |
86 | Parameters map keys:
87 | :node-id Id of the node to get markup for.
88 |
89 | Return map keys:
90 | :outer-html Outer HTML markup.
91 | nil
92 | clj-chrome-devtools.core> (dom/get-outer-html c {:node-id 1})
93 | {:outer-html
94 | "
\n Webjure\n \n \n Coming soon-ish!\n \n\n"}
95 | ```
96 |
97 | ## Running ClojureScript test suite with `clj-chrome-devtools`
98 |
99 | The `clj-chrome-devtools.cljs.test` contains a function that can be used to build and run
100 | ClojureScript tests as part of your Clojure test without needing `doo` plugin or `karma` installed.
101 |
102 | See [example in Tuck project](https://github.com/tatut/tuck/blob/master/test/tuck/chrome_test.clj).
103 |
104 | The `build-and-test` function is meant to be called inside your test and it will build the specified
105 | ClojureScript build that is defined in `project.clj` (e.g. "test") with an added test runner that
106 | requires the specified namespaces and runs tests in them.
107 |
--------------------------------------------------------------------------------
/bb.clj:
--------------------------------------------------------------------------------
1 | ;; Example of using clj-chrome-devtools with babashka
2 | ;;
3 | ;; Start Chrome in the background:
4 | ;; /some/chrome-binary --remote-debugging-port=9222 --headless &
5 | ;;
6 | ;; Run with:
7 | ;; $ bb bb.clj
8 |
9 | (require '[babashka.deps :as deps])
10 | (deps/add-deps
11 | '{:deps {tatut/devtools {:git/url "https://github.com/tatut/clj-chrome-devtools"
12 | :git/sha "cc96255433ca406aaba8bcee17d0d0b3b16dc423"}
13 | org.babashka/spec.alpha {:git/url "https://github.com/babashka/spec.alpha"
14 | :git/sha "1a841c4cc1d4f6dab7505a98ed2d532dd9d56b78"}}})
15 |
16 | (require '[clj-chrome-devtools.core :as core]
17 | '[clj-chrome-devtools.automation :as auto])
18 |
19 | (println "Printing to bb.pdf")
20 | (def a (auto/create-automation (core/connect)))
21 | (auto/to a "https://babashka.org")
22 | (auto/print-pdf a "bb.pdf"
23 | {:print-background true
24 | :paper-width 8.3
25 | :paper-height 11.7})
26 |
--------------------------------------------------------------------------------
/deps.edn:
--------------------------------------------------------------------------------
1 | {:deps {org.clojure/clojure {:mvn/version "1.9.0"}
2 | cheshire/cheshire {:mvn/version "5.10.2"}
3 | org.clojure/tools.logging {:mvn/version "1.2.4"}
4 | java-http-clj/java-http-clj {:mvn/version "0.4.3"}
5 | }
6 | :paths ["src" "resources"]
7 | :aliases
8 | {:bb {:extra-deps {org.babashka/spec.alpha {:git/url "https://github.com/babashka/spec.alpha"
9 | :git/sha "1a841c4cc1d4f6dab7505a98ed2d532dd9d56b78"}}}
10 | :test {:extra-paths ["test"]
11 | ; This is a simplistic test runner but it’s sufficient for now.
12 | :extra-deps {test-runner/test-runner {:git/url "https://github.com/cognitect-labs/test-runner"
13 | :sha "209b64504cb3bd3b99ecfec7937b358a879f55c1"}}
14 | :main-opts ["-m" "cognitect.test-runner"]}}}
15 |
--------------------------------------------------------------------------------
/docs/api/css/default.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: Helvetica, Arial, sans-serif;
3 | font-size: 15px;
4 | }
5 |
6 | pre, code {
7 | font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
8 | font-size: 9pt;
9 | margin: 15px 0;
10 | }
11 |
12 | h1 {
13 | font-weight: normal;
14 | font-size: 29px;
15 | margin: 10px 0 2px 0;
16 | padding: 0;
17 | }
18 |
19 | h2 {
20 | font-weight: normal;
21 | font-size: 25px;
22 | }
23 |
24 | h5.license {
25 | margin: 9px 0 22px 0;
26 | color: #555;
27 | font-weight: normal;
28 | font-size: 12px;
29 | font-style: italic;
30 | }
31 |
32 | .document h1, .namespace-index h1 {
33 | font-size: 32px;
34 | margin-top: 12px;
35 | }
36 |
37 | #header, #content, .sidebar {
38 | position: fixed;
39 | }
40 |
41 | #header {
42 | top: 0;
43 | left: 0;
44 | right: 0;
45 | height: 22px;
46 | color: #f5f5f5;
47 | padding: 5px 7px;
48 | }
49 |
50 | #content {
51 | top: 32px;
52 | right: 0;
53 | bottom: 0;
54 | overflow: auto;
55 | background: #fff;
56 | color: #333;
57 | padding: 0 18px;
58 | }
59 |
60 | .sidebar {
61 | position: fixed;
62 | top: 32px;
63 | bottom: 0;
64 | overflow: auto;
65 | }
66 |
67 | .sidebar.primary {
68 | background: #e2e2e2;
69 | border-right: solid 1px #cccccc;
70 | left: 0;
71 | width: 250px;
72 | }
73 |
74 | .sidebar.secondary {
75 | background: #f2f2f2;
76 | border-right: solid 1px #d7d7d7;
77 | left: 251px;
78 | width: 200px;
79 | }
80 |
81 | #content.namespace-index, #content.document {
82 | left: 251px;
83 | }
84 |
85 | #content.namespace-docs {
86 | left: 452px;
87 | }
88 |
89 | #content.document {
90 | padding-bottom: 10%;
91 | }
92 |
93 | #header {
94 | background: #3f3f3f;
95 | box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
96 | z-index: 100;
97 | }
98 |
99 | #header h1 {
100 | margin: 0;
101 | padding: 0;
102 | font-size: 18px;
103 | font-weight: lighter;
104 | text-shadow: -1px -1px 0px #333;
105 | }
106 |
107 | #header h1 .project-version {
108 | font-weight: normal;
109 | }
110 |
111 | .project-version {
112 | padding-left: 0.15em;
113 | }
114 |
115 | #header a, .sidebar a {
116 | display: block;
117 | text-decoration: none;
118 | }
119 |
120 | #header a {
121 | color: #f5f5f5;
122 | }
123 |
124 | .sidebar a {
125 | color: #333;
126 | }
127 |
128 | #header h2 {
129 | float: right;
130 | font-size: 9pt;
131 | font-weight: normal;
132 | margin: 4px 3px;
133 | padding: 0;
134 | color: #bbb;
135 | }
136 |
137 | #header h2 a {
138 | display: inline;
139 | }
140 |
141 | .sidebar h3 {
142 | margin: 0;
143 | padding: 10px 13px 0 13px;
144 | font-size: 19px;
145 | font-weight: lighter;
146 | }
147 |
148 | .sidebar h3 a {
149 | color: #444;
150 | }
151 |
152 | .sidebar h3.no-link {
153 | color: #636363;
154 | }
155 |
156 | .sidebar ul {
157 | padding: 7px 0 6px 0;
158 | margin: 0;
159 | }
160 |
161 | .sidebar ul.index-link {
162 | padding-bottom: 4px;
163 | }
164 |
165 | .sidebar li {
166 | display: block;
167 | vertical-align: middle;
168 | }
169 |
170 | .sidebar li a, .sidebar li .no-link {
171 | border-left: 3px solid transparent;
172 | padding: 0 10px;
173 | white-space: nowrap;
174 | }
175 |
176 | .sidebar li .no-link {
177 | display: block;
178 | color: #777;
179 | font-style: italic;
180 | }
181 |
182 | .sidebar li .inner {
183 | display: inline-block;
184 | padding-top: 7px;
185 | height: 24px;
186 | }
187 |
188 | .sidebar li a, .sidebar li .tree {
189 | height: 31px;
190 | }
191 |
192 | .depth-1 .inner { padding-left: 2px; }
193 | .depth-2 .inner { padding-left: 6px; }
194 | .depth-3 .inner { padding-left: 20px; }
195 | .depth-4 .inner { padding-left: 34px; }
196 | .depth-5 .inner { padding-left: 48px; }
197 | .depth-6 .inner { padding-left: 62px; }
198 |
199 | .sidebar li .tree {
200 | display: block;
201 | float: left;
202 | position: relative;
203 | top: -10px;
204 | margin: 0 4px 0 0;
205 | padding: 0;
206 | }
207 |
208 | .sidebar li.depth-1 .tree {
209 | display: none;
210 | }
211 |
212 | .sidebar li .tree .top, .sidebar li .tree .bottom {
213 | display: block;
214 | margin: 0;
215 | padding: 0;
216 | width: 7px;
217 | }
218 |
219 | .sidebar li .tree .top {
220 | border-left: 1px solid #aaa;
221 | border-bottom: 1px solid #aaa;
222 | height: 19px;
223 | }
224 |
225 | .sidebar li .tree .bottom {
226 | height: 22px;
227 | }
228 |
229 | .sidebar li.branch .tree .bottom {
230 | border-left: 1px solid #aaa;
231 | }
232 |
233 | .sidebar.primary li.current a {
234 | border-left: 3px solid #a33;
235 | color: #a33;
236 | }
237 |
238 | .sidebar.secondary li.current a {
239 | border-left: 3px solid #33a;
240 | color: #33a;
241 | }
242 |
243 | .namespace-index h2 {
244 | margin: 30px 0 0 0;
245 | }
246 |
247 | .namespace-index h3 {
248 | font-size: 16px;
249 | font-weight: bold;
250 | margin-bottom: 0;
251 | }
252 |
253 | .namespace-index .topics {
254 | padding-left: 30px;
255 | margin: 11px 0 0 0;
256 | }
257 |
258 | .namespace-index .topics li {
259 | padding: 5px 0;
260 | }
261 |
262 | .namespace-docs h3 {
263 | font-size: 18px;
264 | font-weight: bold;
265 | }
266 |
267 | .public h3 {
268 | margin: 0;
269 | float: left;
270 | }
271 |
272 | .usage {
273 | clear: both;
274 | }
275 |
276 | .public {
277 | margin: 0;
278 | border-top: 1px solid #e0e0e0;
279 | padding-top: 14px;
280 | padding-bottom: 6px;
281 | }
282 |
283 | .public:last-child {
284 | margin-bottom: 20%;
285 | }
286 |
287 | .members .public:last-child {
288 | margin-bottom: 0;
289 | }
290 |
291 | .members {
292 | margin: 15px 0;
293 | }
294 |
295 | .members h4 {
296 | color: #555;
297 | font-weight: normal;
298 | font-variant: small-caps;
299 | margin: 0 0 5px 0;
300 | }
301 |
302 | .members .inner {
303 | padding-top: 5px;
304 | padding-left: 12px;
305 | margin-top: 2px;
306 | margin-left: 7px;
307 | border-left: 1px solid #bbb;
308 | }
309 |
310 | #content .members .inner h3 {
311 | font-size: 12pt;
312 | }
313 |
314 | .members .public {
315 | border-top: none;
316 | margin-top: 0;
317 | padding-top: 6px;
318 | padding-bottom: 0;
319 | }
320 |
321 | .members .public:first-child {
322 | padding-top: 0;
323 | }
324 |
325 | h4.type,
326 | h4.dynamic,
327 | h4.added,
328 | h4.deprecated {
329 | float: left;
330 | margin: 3px 10px 15px 0;
331 | font-size: 15px;
332 | font-weight: bold;
333 | font-variant: small-caps;
334 | }
335 |
336 | .public h4.type,
337 | .public h4.dynamic,
338 | .public h4.added,
339 | .public h4.deprecated {
340 | font-size: 13px;
341 | font-weight: bold;
342 | margin: 3px 0 0 10px;
343 | }
344 |
345 | .members h4.type,
346 | .members h4.added,
347 | .members h4.deprecated {
348 | margin-top: 1px;
349 | }
350 |
351 | h4.type {
352 | color: #717171;
353 | }
354 |
355 | h4.dynamic {
356 | color: #9933aa;
357 | }
358 |
359 | h4.added {
360 | color: #508820;
361 | }
362 |
363 | h4.deprecated {
364 | color: #880000;
365 | }
366 |
367 | .namespace {
368 | margin-bottom: 30px;
369 | }
370 |
371 | .namespace:last-child {
372 | margin-bottom: 10%;
373 | }
374 |
375 | .index {
376 | padding: 0;
377 | font-size: 80%;
378 | margin: 15px 0;
379 | line-height: 16px;
380 | }
381 |
382 | .index * {
383 | display: inline;
384 | }
385 |
386 | .index p {
387 | padding-right: 3px;
388 | }
389 |
390 | .index li {
391 | padding-right: 5px;
392 | }
393 |
394 | .index ul {
395 | padding-left: 0;
396 | }
397 |
398 | .type-sig {
399 | clear: both;
400 | color: #088;
401 | }
402 |
403 | .type-sig pre {
404 | padding-top: 10px;
405 | margin: 0;
406 | }
407 |
408 | .usage code {
409 | display: block;
410 | color: #008;
411 | margin: 2px 0;
412 | }
413 |
414 | .usage code:first-child {
415 | padding-top: 10px;
416 | }
417 |
418 | p {
419 | margin: 15px 0;
420 | }
421 |
422 | .public p:first-child, .public pre.plaintext {
423 | margin-top: 12px;
424 | }
425 |
426 | .doc {
427 | margin: 0 0 26px 0;
428 | clear: both;
429 | }
430 |
431 | .public .doc {
432 | margin: 0;
433 | }
434 |
435 | .namespace-index .doc {
436 | margin-bottom: 20px;
437 | }
438 |
439 | .namespace-index .namespace .doc {
440 | margin-bottom: 10px;
441 | }
442 |
443 | .markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
444 | line-height: 22px;
445 | }
446 |
447 | .markdown li {
448 | padding: 2px 0;
449 | }
450 |
451 | .markdown h2 {
452 | font-weight: normal;
453 | font-size: 25px;
454 | margin: 30px 0 10px 0;
455 | }
456 |
457 | .markdown h3 {
458 | font-weight: normal;
459 | font-size: 20px;
460 | margin: 30px 0 0 0;
461 | }
462 |
463 | .markdown h4 {
464 | font-size: 15px;
465 | margin: 22px 0 -4px 0;
466 | }
467 |
468 | .doc, .public, .namespace .index {
469 | max-width: 680px;
470 | overflow-x: visible;
471 | }
472 |
473 | .markdown pre > code {
474 | display: block;
475 | padding: 10px;
476 | }
477 |
478 | .markdown pre > code, .src-link a {
479 | border: 1px solid #e4e4e4;
480 | border-radius: 2px;
481 | }
482 |
483 | .markdown code:not(.hljs), .src-link a {
484 | background: #f6f6f6;
485 | }
486 |
487 | pre.deps {
488 | display: inline-block;
489 | margin: 0 10px;
490 | border: 1px solid #e4e4e4;
491 | border-radius: 2px;
492 | padding: 10px;
493 | background-color: #f6f6f6;
494 | }
495 |
496 | .markdown hr {
497 | border-style: solid;
498 | border-top: none;
499 | color: #ccc;
500 | }
501 |
502 | .doc ul, .doc ol {
503 | padding-left: 30px;
504 | }
505 |
506 | .doc table {
507 | border-collapse: collapse;
508 | margin: 0 10px;
509 | }
510 |
511 | .doc table td, .doc table th {
512 | border: 1px solid #dddddd;
513 | padding: 4px 6px;
514 | }
515 |
516 | .doc table th {
517 | background: #f2f2f2;
518 | }
519 |
520 | .doc dl {
521 | margin: 0 10px 20px 10px;
522 | }
523 |
524 | .doc dl dt {
525 | font-weight: bold;
526 | margin: 0;
527 | padding: 3px 0;
528 | border-bottom: 1px solid #ddd;
529 | }
530 |
531 | .doc dl dd {
532 | padding: 5px 0;
533 | margin: 0 0 5px 10px;
534 | }
535 |
536 | .doc abbr {
537 | border-bottom: 1px dotted #333;
538 | font-variant: none;
539 | cursor: help;
540 | }
541 |
542 | .src-link {
543 | margin-bottom: 15px;
544 | }
545 |
546 | .src-link a {
547 | font-size: 70%;
548 | padding: 1px 4px;
549 | text-decoration: none;
550 | color: #5555bb;
551 | }
552 |
--------------------------------------------------------------------------------
/docs/api/css/highlight.css:
--------------------------------------------------------------------------------
1 | /*
2 | github.com style (c) Vasily Polovnyov
3 | */
4 |
5 | .hljs {
6 | display: block;
7 | overflow-x: auto;
8 | padding: 0.5em;
9 | color: #333;
10 | background: #f8f8f8;
11 | }
12 |
13 | .hljs-comment,
14 | .hljs-quote {
15 | color: #998;
16 | font-style: italic;
17 | }
18 |
19 | .hljs-keyword,
20 | .hljs-selector-tag,
21 | .hljs-subst {
22 | color: #333;
23 | font-weight: bold;
24 | }
25 |
26 | .hljs-number,
27 | .hljs-literal,
28 | .hljs-variable,
29 | .hljs-template-variable,
30 | .hljs-tag .hljs-attr {
31 | color: #008080;
32 | }
33 |
34 | .hljs-string,
35 | .hljs-doctag {
36 | color: #d14;
37 | }
38 |
39 | .hljs-title,
40 | .hljs-section,
41 | .hljs-selector-id {
42 | color: #900;
43 | font-weight: bold;
44 | }
45 |
46 | .hljs-subst {
47 | font-weight: normal;
48 | }
49 |
50 | .hljs-type,
51 | .hljs-class .hljs-title {
52 | color: #458;
53 | font-weight: bold;
54 | }
55 |
56 | .hljs-tag,
57 | .hljs-name,
58 | .hljs-attribute {
59 | color: #000080;
60 | font-weight: normal;
61 | }
62 |
63 | .hljs-regexp,
64 | .hljs-link {
65 | color: #009926;
66 | }
67 |
68 | .hljs-symbol,
69 | .hljs-bullet {
70 | color: #990073;
71 | }
72 |
73 | .hljs-built_in,
74 | .hljs-builtin-name {
75 | color: #0086b3;
76 | }
77 |
78 | .hljs-meta {
79 | color: #999;
80 | font-weight: bold;
81 | }
82 |
83 | .hljs-deletion {
84 | background: #fdd;
85 | }
86 |
87 | .hljs-addition {
88 | background: #dfd;
89 | }
90 |
91 | .hljs-emphasis {
92 | font-style: italic;
93 | }
94 |
95 | .hljs-strong {
96 | font-weight: bold;
97 | }
98 |
--------------------------------------------------------------------------------
/docs/api/js/highlight.min.js:
--------------------------------------------------------------------------------
1 | /*! highlight.js v9.6.0 | BSD3 License | git.io/hljslicense */
2 | !function(e){var n="object"==typeof window&&window||"object"==typeof self&&self;"undefined"!=typeof exports?e(exports):n&&(n.hljs=e({}),"function"==typeof define&&define.amd&&define([],function(){return n.hljs}))}(function(e){function n(e){return e.replace(/[&<>]/gm,function(e){return I[e]})}function t(e){return e.nodeName.toLowerCase()}function r(e,n){var t=e&&e.exec(n);return t&&0===t.index}function a(e){return k.test(e)}function i(e){var n,t,r,i,o=e.className+" ";if(o+=e.parentNode?e.parentNode.className:"",t=B.exec(o))return R(t[1])?t[1]:"no-highlight";for(o=o.split(/\s+/),n=0,r=o.length;r>n;n++)if(i=o[n],a(i)||R(i))return i}function o(e,n){var t,r={};for(t in e)r[t]=e[t];if(n)for(t in n)r[t]=n[t];return r}function u(e){var n=[];return function r(e,a){for(var i=e.firstChild;i;i=i.nextSibling)3===i.nodeType?a+=i.nodeValue.length:1===i.nodeType&&(n.push({event:"start",offset:a,node:i}),a=r(i,a),t(i).match(/br|hr|img|input/)||n.push({event:"stop",offset:a,node:i}));return a}(e,0),n}function c(e,r,a){function i(){return e.length&&r.length?e[0].offset!==r[0].offset?e[0].offset"}function u(e){l+=""+t(e)+">"}function c(e){("start"===e.event?o:u)(e.node)}for(var s=0,l="",f=[];e.length||r.length;){var g=i();if(l+=n(a.substr(s,g[0].offset-s)),s=g[0].offset,g===e){f.reverse().forEach(u);do c(g.splice(0,1)[0]),g=i();while(g===e&&g.length&&g[0].offset===s);f.reverse().forEach(o)}else"start"===g[0].event?f.push(g[0].node):f.pop(),c(g.splice(0,1)[0])}return l+n(a.substr(s))}function s(e){function n(e){return e&&e.source||e}function t(t,r){return new RegExp(n(t),"m"+(e.cI?"i":"")+(r?"g":""))}function r(a,i){if(!a.compiled){if(a.compiled=!0,a.k=a.k||a.bK,a.k){var u={},c=function(n,t){e.cI&&(t=t.toLowerCase()),t.split(" ").forEach(function(e){var t=e.split("|");u[t[0]]=[n,t[1]?Number(t[1]):1]})};"string"==typeof a.k?c("keyword",a.k):E(a.k).forEach(function(e){c(e,a.k[e])}),a.k=u}a.lR=t(a.l||/\w+/,!0),i&&(a.bK&&(a.b="\\b("+a.bK.split(" ").join("|")+")\\b"),a.b||(a.b=/\B|\b/),a.bR=t(a.b),a.e||a.eW||(a.e=/\B|\b/),a.e&&(a.eR=t(a.e)),a.tE=n(a.e)||"",a.eW&&i.tE&&(a.tE+=(a.e?"|":"")+i.tE)),a.i&&(a.iR=t(a.i)),null==a.r&&(a.r=1),a.c||(a.c=[]);var s=[];a.c.forEach(function(e){e.v?e.v.forEach(function(n){s.push(o(e,n))}):s.push("self"===e?a:e)}),a.c=s,a.c.forEach(function(e){r(e,a)}),a.starts&&r(a.starts,i);var l=a.c.map(function(e){return e.bK?"\\.?("+e.b+")\\.?":e.b}).concat([a.tE,a.i]).map(n).filter(Boolean);a.t=l.length?t(l.join("|"),!0):{exec:function(){return null}}}}r(e)}function l(e,t,a,i){function o(e,n){var t,a;for(t=0,a=n.c.length;a>t;t++)if(r(n.c[t].bR,e))return n.c[t]}function u(e,n){if(r(e.eR,n)){for(;e.endsParent&&e.parent;)e=e.parent;return e}return e.eW?u(e.parent,n):void 0}function c(e,n){return!a&&r(n.iR,e)}function g(e,n){var t=N.cI?n[0].toLowerCase():n[0];return e.k.hasOwnProperty(t)&&e.k[t]}function h(e,n,t,r){var a=r?"":y.classPrefix,i='',i+n+o}function p(){var e,t,r,a;if(!E.k)return n(B);for(a="",t=0,E.lR.lastIndex=0,r=E.lR.exec(B);r;)a+=n(B.substr(t,r.index-t)),e=g(E,r),e?(M+=e[1],a+=h(e[0],n(r[0]))):a+=n(r[0]),t=E.lR.lastIndex,r=E.lR.exec(B);return a+n(B.substr(t))}function d(){var e="string"==typeof E.sL;if(e&&!x[E.sL])return n(B);var t=e?l(E.sL,B,!0,L[E.sL]):f(B,E.sL.length?E.sL:void 0);return E.r>0&&(M+=t.r),e&&(L[E.sL]=t.top),h(t.language,t.value,!1,!0)}function b(){k+=null!=E.sL?d():p(),B=""}function v(e){k+=e.cN?h(e.cN,"",!0):"",E=Object.create(e,{parent:{value:E}})}function m(e,n){if(B+=e,null==n)return b(),0;var t=o(n,E);if(t)return t.skip?B+=n:(t.eB&&(B+=n),b(),t.rB||t.eB||(B=n)),v(t,n),t.rB?0:n.length;var r=u(E,n);if(r){var a=E;a.skip?B+=n:(a.rE||a.eE||(B+=n),b(),a.eE&&(B=n));do E.cN&&(k+=C),E.skip||(M+=E.r),E=E.parent;while(E!==r.parent);return r.starts&&v(r.starts,""),a.rE?0:n.length}if(c(n,E))throw new Error('Illegal lexeme "'+n+'" for mode "'+(E.cN||"")+'"');return B+=n,n.length||1}var N=R(e);if(!N)throw new Error('Unknown language: "'+e+'"');s(N);var w,E=i||N,L={},k="";for(w=E;w!==N;w=w.parent)w.cN&&(k=h(w.cN,"",!0)+k);var B="",M=0;try{for(var I,j,O=0;;){if(E.t.lastIndex=O,I=E.t.exec(t),!I)break;j=m(t.substr(O,I.index-O),I[0]),O=I.index+j}for(m(t.substr(O)),w=E;w.parent;w=w.parent)w.cN&&(k+=C);return{r:M,value:k,language:e,top:E}}catch(T){if(T.message&&-1!==T.message.indexOf("Illegal"))return{r:0,value:n(t)};throw T}}function f(e,t){t=t||y.languages||E(x);var r={r:0,value:n(e)},a=r;return t.filter(R).forEach(function(n){var t=l(n,e,!1);t.language=n,t.r>a.r&&(a=t),t.r>r.r&&(a=r,r=t)}),a.language&&(r.second_best=a),r}function g(e){return y.tabReplace||y.useBR?e.replace(M,function(e,n){return y.useBR&&"\n"===e?"
":y.tabReplace?n.replace(/\t/g,y.tabReplace):void 0}):e}function h(e,n,t){var r=n?L[n]:t,a=[e.trim()];return e.match(/\bhljs\b/)||a.push("hljs"),-1===e.indexOf(r)&&a.push(r),a.join(" ").trim()}function p(e){var n,t,r,o,s,p=i(e);a(p)||(y.useBR?(n=document.createElementNS("http://www.w3.org/1999/xhtml","div"),n.innerHTML=e.innerHTML.replace(/\n/g,"").replace(/
/g,"\n")):n=e,s=n.textContent,r=p?l(p,s,!0):f(s),t=u(n),t.length&&(o=document.createElementNS("http://www.w3.org/1999/xhtml","div"),o.innerHTML=r.value,r.value=c(t,u(o),s)),r.value=g(r.value),e.innerHTML=r.value,e.className=h(e.className,p,r.language),e.result={language:r.language,re:r.r},r.second_best&&(e.second_best={language:r.second_best.language,re:r.second_best.r}))}function d(e){y=o(y,e)}function b(){if(!b.called){b.called=!0;var e=document.querySelectorAll("pre code");w.forEach.call(e,p)}}function v(){addEventListener("DOMContentLoaded",b,!1),addEventListener("load",b,!1)}function m(n,t){var r=x[n]=t(e);r.aliases&&r.aliases.forEach(function(e){L[e]=n})}function N(){return E(x)}function R(e){return e=(e||"").toLowerCase(),x[e]||x[L[e]]}var w=[],E=Object.keys,x={},L={},k=/^(no-?highlight|plain|text)$/i,B=/\blang(?:uage)?-([\w-]+)\b/i,M=/((^(<[^>]+>|\t|)+|(?:\n)))/gm,C="",y={classPrefix:"hljs-",tabReplace:null,useBR:!1,languages:void 0},I={"&":"&","<":"<",">":">"};return e.highlight=l,e.highlightAuto=f,e.fixMarkup=g,e.highlightBlock=p,e.configure=d,e.initHighlighting=b,e.initHighlightingOnLoad=v,e.registerLanguage=m,e.listLanguages=N,e.getLanguage=R,e.inherit=o,e.IR="[a-zA-Z]\\w*",e.UIR="[a-zA-Z_]\\w*",e.NR="\\b\\d+(\\.\\d+)?",e.CNR="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",e.BNR="\\b(0b[01]+)",e.RSR="!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~",e.BE={b:"\\\\[\\s\\S]",r:0},e.ASM={cN:"string",b:"'",e:"'",i:"\\n",c:[e.BE]},e.QSM={cN:"string",b:'"',e:'"',i:"\\n",c:[e.BE]},e.PWM={b:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|like)\b/},e.C=function(n,t,r){var a=e.inherit({cN:"comment",b:n,e:t,c:[]},r||{});return a.c.push(e.PWM),a.c.push({cN:"doctag",b:"(?:TODO|FIXME|NOTE|BUG|XXX):",r:0}),a},e.CLCM=e.C("//","$"),e.CBCM=e.C("/\\*","\\*/"),e.HCM=e.C("#","$"),e.NM={cN:"number",b:e.NR,r:0},e.CNM={cN:"number",b:e.CNR,r:0},e.BNM={cN:"number",b:e.BNR,r:0},e.CSSNM={cN:"number",b:e.NR+"(%|em|ex|ch|rem|vw|vh|vmin|vmax|cm|mm|in|pt|pc|px|deg|grad|rad|turn|s|ms|Hz|kHz|dpi|dpcm|dppx)?",r:0},e.RM={cN:"regexp",b:/\//,e:/\/[gimuy]*/,i:/\n/,c:[e.BE,{b:/\[/,e:/\]/,r:0,c:[e.BE]}]},e.TM={cN:"title",b:e.IR,r:0},e.UTM={cN:"title",b:e.UIR,r:0},e.METHOD_GUARD={b:"\\.\\s*"+e.UIR,r:0},e});hljs.registerLanguage("clojure",function(e){var t={"builtin-name":"def defonce cond apply if-not if-let if not not= = < > <= >= == + / * - rem quot neg? pos? delay? symbol? keyword? true? false? integer? empty? coll? list? set? ifn? fn? associative? sequential? sorted? counted? reversible? number? decimal? class? distinct? isa? float? rational? reduced? ratio? odd? even? char? seq? vector? string? map? nil? contains? zero? instance? not-every? not-any? libspec? -> ->> .. . inc compare do dotimes mapcat take remove take-while drop letfn drop-last take-last drop-while while intern condp case reduced cycle split-at split-with repeat replicate iterate range merge zipmap declare line-seq sort comparator sort-by dorun doall nthnext nthrest partition eval doseq await await-for let agent atom send send-off release-pending-sends add-watch mapv filterv remove-watch agent-error restart-agent set-error-handler error-handler set-error-mode! error-mode shutdown-agents quote var fn loop recur throw try monitor-enter monitor-exit defmacro defn defn- macroexpand macroexpand-1 for dosync and or when when-not when-let comp juxt partial sequence memoize constantly complement identity assert peek pop doto proxy defstruct first rest cons defprotocol cast coll deftype defrecord last butlast sigs reify second ffirst fnext nfirst nnext defmulti defmethod meta with-meta ns in-ns create-ns import refer keys select-keys vals key val rseq name namespace promise into transient persistent! conj! assoc! dissoc! pop! disj! use class type num float double short byte boolean bigint biginteger bigdec print-method print-dup throw-if printf format load compile get-in update-in pr pr-on newline flush read slurp read-line subvec with-open memfn time re-find re-groups rand-int rand mod locking assert-valid-fdecl alias resolve ref deref refset swap! reset! set-validator! compare-and-set! alter-meta! reset-meta! commute get-validator alter ref-set ref-history-count ref-min-history ref-max-history ensure sync io! new next conj set! to-array future future-call into-array aset gen-class reduce map filter find empty hash-map hash-set sorted-map sorted-map-by sorted-set sorted-set-by vec vector seq flatten reverse assoc dissoc list disj get union difference intersection extend extend-type extend-protocol int nth delay count concat chunk chunk-buffer chunk-append chunk-first chunk-rest max min dec unchecked-inc-int unchecked-inc unchecked-dec-inc unchecked-dec unchecked-negate unchecked-add-int unchecked-add unchecked-subtract-int unchecked-subtract chunk-next chunk-cons chunked-seq? prn vary-meta lazy-seq spread list* str find-keyword keyword symbol gensym force rationalize"},r="a-zA-Z_\\-!.?+*=<>'",n="["+r+"]["+r+"0-9/;:]*",a="[-+]?\\d+(\\.\\d+)?",o={b:n,r:0},s={cN:"number",b:a,r:0},i=e.inherit(e.QSM,{i:null}),c=e.C(";","$",{r:0}),d={cN:"literal",b:/\b(true|false|nil)\b/},l={b:"[\\[\\{]",e:"[\\]\\}]"},m={cN:"comment",b:"\\^"+n},p=e.C("\\^\\{","\\}"),u={cN:"symbol",b:"[:]{1,2}"+n},f={b:"\\(",e:"\\)"},h={eW:!0,r:0},y={k:t,l:n,cN:"name",b:n,starts:h},b=[f,i,m,p,c,u,l,s,d,o];return f.c=[e.C("comment",""),y,h],h.c=b,l.c=b,{aliases:["clj"],i:/\S/,c:[f,i,m,p,c,u,l,s,d]}});hljs.registerLanguage("clojure-repl",function(e){return{c:[{cN:"meta",b:/^([\w.-]+|\s*#_)=>/,starts:{e:/$/,sL:"clojure"}}]}});
--------------------------------------------------------------------------------
/docs/api/js/page_effects.js:
--------------------------------------------------------------------------------
1 | function visibleInParent(element) {
2 | var position = $(element).position().top
3 | return position > -50 && position < ($(element).offsetParent().height() - 50)
4 | }
5 |
6 | function hasFragment(link, fragment) {
7 | return $(link).attr("href").indexOf("#" + fragment) != -1
8 | }
9 |
10 | function findLinkByFragment(elements, fragment) {
11 | return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
12 | }
13 |
14 | function scrollToCurrentVarLink(elements) {
15 | var elements = $(elements);
16 | var parent = elements.offsetParent();
17 |
18 | if (elements.length == 0) return;
19 |
20 | var top = elements.first().position().top;
21 | var bottom = elements.last().position().top + elements.last().height();
22 |
23 | if (top >= 0 && bottom <= parent.height()) return;
24 |
25 | if (top < 0) {
26 | parent.scrollTop(parent.scrollTop() + top);
27 | }
28 | else if (bottom > parent.height()) {
29 | parent.scrollTop(parent.scrollTop() + bottom - parent.height());
30 | }
31 | }
32 |
33 | function setCurrentVarLink() {
34 | $('.secondary a').parent().removeClass('current')
35 | $('.anchor').
36 | filter(function(index) { return visibleInParent(this) }).
37 | each(function(index, element) {
38 | findLinkByFragment(".secondary a", element.id).
39 | parent().
40 | addClass('current')
41 | });
42 | scrollToCurrentVarLink('.secondary .current');
43 | }
44 |
45 | var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
46 |
47 | function scrollPositionId(element) {
48 | var directory = window.location.href.replace(/[^\/]+\.html$/, '')
49 | return 'scroll::' + $(element).attr('id') + '::' + directory
50 | }
51 |
52 | function storeScrollPosition(element) {
53 | if (!hasStorage) return;
54 | localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
55 | localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
56 | }
57 |
58 | function recallScrollPosition(element) {
59 | if (!hasStorage) return;
60 | $(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
61 | $(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
62 | }
63 |
64 | function persistScrollPosition(element) {
65 | recallScrollPosition(element)
66 | $(element).scroll(function() { storeScrollPosition(element) })
67 | }
68 |
69 | function sidebarContentWidth(element) {
70 | var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
71 | return Math.max.apply(Math, widths)
72 | }
73 |
74 | function calculateSize(width, snap, margin, minimum) {
75 | if (width == 0) {
76 | return 0
77 | }
78 | else {
79 | return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
80 | }
81 | }
82 |
83 | function resizeSidebars() {
84 | var primaryWidth = sidebarContentWidth('.primary')
85 | var secondaryWidth = 0
86 |
87 | if ($('.secondary').length != 0) {
88 | secondaryWidth = sidebarContentWidth('.secondary')
89 | }
90 |
91 | // snap to grid
92 | primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
93 | secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
94 |
95 | $('.primary').css('width', primaryWidth)
96 | $('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
97 |
98 | if (secondaryWidth > 0) {
99 | $('#content').css('left', primaryWidth + secondaryWidth + 2)
100 | }
101 | else {
102 | $('#content').css('left', primaryWidth + 1)
103 | }
104 | }
105 |
106 | $(window).ready(resizeSidebars)
107 | $(window).ready(setCurrentVarLink)
108 | $(window).ready(function() { persistScrollPosition('.primary')})
109 | $(window).ready(function() {
110 | $('#content').scroll(setCurrentVarLink)
111 | $(window).resize(setCurrentVarLink)
112 | })
113 |
--------------------------------------------------------------------------------
/project.clj:
--------------------------------------------------------------------------------
1 | (defproject clj-chrome-devtools "20220405"
2 | :description "Clojure API for Chrome DevTools remote"
3 | :license {:name "MIT License"}
4 | :url "https://github.com/tatut/clj-chrome-devtools"
5 | :plugins [[lein-codox "0.10.8"]
6 | [lein-tools-deps "0.4.5"]]
7 | :codox {:output-path "docs/api"
8 | :metadata {:doc/format :markdown}}
9 | :middleware [lein-tools-deps.plugin/resolve-dependencies-with-deps-edn]
10 | :lein-tools-deps/config {:config-files [:install :user :project]})
11 |
--------------------------------------------------------------------------------
/resources/clj_chrome_devtools_runner.tpl:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools-runner
2 | (:require [cljs.test :refer [run-tests]]
3 | __REQUIRE_NAMESPACES__))
4 |
5 | (def PRINTED (atom []))
6 |
7 | (defn get-printed []
8 | (let [v @PRINTED]
9 | (reset! PRINTED [])
10 | (clj->js v)))
11 |
12 | (def screenshot-number (atom {:name nil :number 0}))
13 |
14 | (defn screenshot-file-name []
15 | (let [test-name (-> (cljs.test/get-current-env) :testing-vars first meta :name)]
16 | (str test-name
17 | "-"
18 | (:number (swap! screenshot-number
19 | (fn [{:keys [name number]}]
20 | {:name test-name
21 | :number (if (= name test-name)
22 | (inc number)
23 | 0)})))
24 | ".png")))
25 |
26 | (defn screenshot [& file-name]
27 | (let [file-name (or file-name (screenshot-file-name))]
28 | (js/Promise.
29 | (fn [resolve _]
30 | (aset js/window "CLJ_SCREENSHOT_NAME" file-name)
31 | (aset js/window "CLJ_SCREENSHOT_RESOLVE" resolve)))))
32 |
33 | (aset js/window "screenshot" screenshot)
34 | (aset js/window "CLJ_TEST_GET_PRINTED" get-printed)
35 |
36 | (defn run-chrome-tests []
37 | (aset js/window "CLJ_TESTS_STARTED" true)
38 | (set! *print-fn* (fn [& msg] (swap! PRINTED conj (apply str msg))))
39 | (run-tests __TEST_NAMESPACES__ ))
40 |
--------------------------------------------------------------------------------
/resources/test-page.tpl:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
13 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/automation/fixture.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.automation.fixture
2 | "Provides a `clojure.test` fixture for starting a new Chrome headless instance
3 | and an automation context for it."
4 | (:require [clj-chrome-devtools.automation :as automation]
5 | [clj-chrome-devtools.automation.launcher :as launcher]))
6 |
7 | ;; Define previously defined public vars here for backwards compatibility
8 | (def possible-chrome-binaries launcher/possible-chrome-binaries)
9 | (def binary-path launcher/binary-path)
10 | (def find-chrome-binary launcher/find-chrome-binary)
11 | (def launch-chrome launcher/launch-chrome)
12 | (def default-options launcher/default-options)
13 |
14 | (defn create-chrome-fixture
15 | ([] (create-chrome-fixture {}))
16 | ([options]
17 | (fn [tests]
18 | (let [prev-current-automation @automation/current-automation]
19 | (try
20 | (with-open [^java.lang.AutoCloseable automation (launcher/launch-automation options)]
21 | (reset! automation/current-automation automation)
22 | (tests))
23 | (finally
24 | (reset! automation/current-automation prev-current-automation)))))))
25 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/automation/launcher.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.automation.launcher
2 | "Launch a headless Chrome for automation purposes."
3 | (:require [clojure.java.shell :as sh]
4 | [clojure.string :as str]
5 | [clojure.tools.logging :as log]
6 | [clj-chrome-devtools.automation :as automation]
7 | [clj-chrome-devtools.impl.util :as util]
8 | [clj-chrome-devtools.impl.connection :as connection]))
9 |
10 | (set! *warn-on-reflection* true)
11 |
12 | (def possible-chrome-binaries
13 | ["/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
14 | "google-chrome-stable"
15 | "google-chrome"
16 | "chromium-browser"
17 | "chromium"
18 | "chrome.exe"])
19 |
20 | (defn- is-windows? []
21 | (when-let [os (System/getenv "os")]
22 | (str/starts-with? os "Windows")))
23 |
24 | (defn binary-path [candidate]
25 | (let [{:keys [exit out]}
26 | (if (is-windows?)
27 | ;; Note: usually this is the default location
28 | ;; "C:/Program Files (x86)/Google/Chrome/Application/chrome.exe"
29 | ;; "C:/Program Files (x86)/Google/Chrome Beta/Application/chrome.exe"
30 | (sh/sh "where.exe" candidate)
31 | ;; Assume Linux/MacOS
32 | (sh/sh "which" candidate))]
33 | (when (= exit 0)
34 | (str/trim-newline out))))
35 |
36 | (defn find-chrome-binary []
37 | (some binary-path possible-chrome-binaries))
38 |
39 | (defn launch-chrome [binary-path remote-debugging-port options]
40 | (log/trace "Launching Chrome headless, binary: " binary-path
41 | ", remote debugging port: " remote-debugging-port
42 | ", options: " (pr-str options))
43 | (let [args (remove nil? (concat [binary-path
44 | (when (:headless? options) "--headless")
45 | (when (:no-sandbox? options) "--no-sandbox")
46 | (when-not (:enable-gpu? options) "--disable-gpu")
47 | (str "--remote-debugging-port=" remote-debugging-port)]
48 | (:args options)))]
49 | (.exec (Runtime/getRuntime)
50 | ^"[Ljava.lang.String;" (into-array String args))))
51 |
52 | (defn default-options []
53 | {:chrome-binary (find-chrome-binary)
54 | :remote-debugging-port nil
55 | :headless? true})
56 |
57 | (defn launch-automation [options]
58 | (let [options (merge (default-options) options)
59 | {:keys [chrome-binary remote-debugging-port headless?]} options
60 | port (or remote-debugging-port (util/random-free-port))
61 | ^java.lang.Process process (launch-chrome chrome-binary port options)]
62 | (automation/create-automation
63 | (connection/connect "localhost" port 30000)
64 | (fn [_]
65 | (.destroy process)))))
66 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/cljs/test.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.cljs.test
2 | "Build a ClojureScript build and run its tests as a clojure
3 | test. This can hook your cljs app tests into the normal
4 | clojure testing run."
5 | (:require [cljs.build.api :as cljs-build]
6 | [clojure.java.io :as io]
7 | [clj-chrome-devtools.automation.fixture :refer [create-chrome-fixture]]
8 | [clj-chrome-devtools.automation :as automation]
9 | [clj-chrome-devtools.impl.util :refer [random-free-port]]
10 | [org.httpkit.server :as http-server]
11 | [clojure.string :as str]
12 | [clojure.test :refer [is]]
13 | [clojure.java.shell :as sh])
14 | (:import (java.io File)))
15 |
16 |
17 |
18 | (defn no-op-log [& _args]
19 | nil)
20 |
21 | (defn println-log [& args]
22 | (println (str/join " " args)))
23 |
24 | (def ^:dynamic log no-op-log)
25 |
26 | (defn- find-defproject [file]
27 | (log "Loading leiningen project from: " file)
28 | (with-open [in (java.io.PushbackReader. (io/reader file))]
29 | (loop [form (read in false ::eof)]
30 | (cond
31 | (= ::eof form)
32 | (throw (ex-info "Can't find defproject form" {:file file}))
33 |
34 |
35 | (and (coll? form) (= (first form) 'defproject))
36 | (do
37 | (log "Found defproject: " (nth form 1) (nth form 2))
38 | form)
39 |
40 | :else
41 | (recur (read in))))))
42 |
43 | (defn- load-project-clj
44 | "Load project.clj file and turn it into a map."
45 | []
46 | (->> "project.clj" find-defproject
47 | (drop 3) ;; remove defproject, name and version
48 | (partition 2) ;; take top level :key val pairs
49 | (map vec)
50 | (into {})))
51 |
52 | (defn- build-by-id [project-clj build-id]
53 | (->> project-clj :cljsbuild :builds
54 | (some #(when (= build-id (:id %))
55 | %))))
56 |
57 | (defn- test-runner-forms
58 | "ClojureScript forms for test runner"
59 | [namespaces]
60 | (log "Generating test runner forms for namespaces: " namespaces)
61 | (-> "clj_chrome_devtools_runner.tpl"
62 | io/resource slurp
63 | (str/replace "__REQUIRE_NAMESPACES__"
64 | (str/join "\n " namespaces))
65 | (str/replace "__TEST_NAMESPACES__"
66 | (str/join "\n "
67 | (map #(str "'" %) namespaces)))))
68 |
69 | (defn- with-test-runner-source [namespaces source-path fun]
70 | ;; Create a test runner source file in the given source path
71 | ;; We have to put this in an existing source path as
72 | ;; we can't add a new source path dynamically (files therein
73 | ;; won't be found with io/resource). It is simpler to add
74 | ;; it to an existing source path and remove afterwards.
75 | (let [runner (io/file source-path
76 | "clj_chrome_devtools_runner.cljs")]
77 | (spit runner (test-runner-forms namespaces))
78 | (try
79 | (fun)
80 | (finally
81 | (io/delete-file runner)))))
82 |
83 | (defn build [project-clj build-id test-runner-namespaces]
84 | (let [{:keys [source-paths compiler] :as _build}
85 | (build-by-id project-clj build-id)]
86 | (log "Building ClojureScript, source paths: " source-paths)
87 | (with-test-runner-source test-runner-namespaces (last source-paths)
88 | #(cljs-build/build
89 | (cljs-build/inputs source-paths)
90 | (assoc compiler
91 | :main "clj-chrome-devtools-runner"
92 | :warnings {:single-segment-namespace false})))
93 | (assert (.exists (io/file (:output-to compiler)))
94 | "build output file exists")
95 | {:js (:output-to compiler)
96 | :js-directory (:output-dir compiler)}))
97 |
98 | (defn- test-page [{:keys [js runner]
99 | :or {runner "clj_chrome_devtools_runner.run_chrome_tests();"}}]
100 | (-> "test-page.tpl" io/resource slurp
101 | (str/replace "__RUNNER__" runner)
102 | (str/replace "__JS__" (slurp js))))
103 |
104 | (defn- file-handler [root-paths {:keys [uri request-method] :as _req}]
105 | (log "REQUEST: " uri)
106 | (let [path (subs uri 1)
107 | file (some (fn [root-path]
108 | (let [f (io/file root-path path)]
109 | (when (.exists f)
110 | f)))
111 | root-paths)]
112 | (if (and (= request-method :get) (.canRead file))
113 | {:status 200
114 | :headers {"Content-Type" (cond
115 | (str/ends-with? uri ".html")
116 | "text/html"
117 |
118 | (str/ends-with? uri ".js")
119 | "application/javascript"
120 |
121 | :else
122 | "application/octet-stream")}
123 | :body (slurp file)}
124 |
125 | {:status 404})))
126 |
127 | (def ^{:doc "cljs.test failure/error report regex"
128 | :private true}
129 | final-test-report-pattern #"(\d+) failures, (\d+) errors.")
130 |
131 | (defn- test-result [msg]
132 | (let [[match errors failures] (re-matches final-test-report-pattern msg)]
133 | (when match
134 | (if (= "0" errors failures)
135 | :ok
136 | :fail))))
137 |
138 | (defn- poll-test-execution []
139 | (loop [started? false
140 | screenshots []]
141 | (if (not started?)
142 | ;; Tests have not started yet, check for fatal error or start flag
143 | (if-let [fatal-error (automation/evaluate "window['CLJ_FATAL_ERROR'] || null")]
144 | (throw (ex-info "Test page had error before tests were started." {:error fatal-error}))
145 |
146 | (if (automation/evaluate "window['CLJ_TESTS_STARTED'] || false")
147 | (recur true screenshots)
148 | (do
149 | (Thread/sleep 100)
150 | (recur false screenshots))))
151 |
152 | ;; Tests have started, poll for screenshots and printed output
153 | (if-let [screenshot-file-name (automation/evaluate "window['CLJ_SCREENSHOT_NAME'] || null")]
154 | (do
155 | ;; Take screenshot if requested
156 | (log "Taking screenshot to:" screenshot-file-name)
157 | (automation/screenshot @automation/current-automation screenshot-file-name)
158 | (automation/evaluate "window.CLJ_SCREENSHOT_NAME = null")
159 | (automation/evaluate "window.CLJ_SCREENSHOT_RESOLVE(true)")
160 | (recur started? (conj screenshots screenshot-file-name)))
161 | (let [msgs (automation/evaluate "CLJ_TEST_GET_PRINTED()")]
162 | (doseq [m (mapcat #(str/split % #"\n") msgs)]
163 | (println "[CLJS]" m))
164 |
165 | (if-let [result (some test-result msgs)]
166 | {:result result
167 | :screenshots screenshots}
168 | (do
169 | (Thread/sleep 100)
170 | (recur started? screenshots))))))))
171 |
172 | (defn output-screenshot-videos [screenshots framerate loop-video?]
173 | (let [video-names (into #{}
174 | (keep #(second (re-matches #"^([^\d]+)-(\d+)\.png$" %)))
175 | screenshots)]
176 | (loop [[video-name & video-names] video-names]
177 | (when video-name
178 | (let [input (str video-name "-%d.png")
179 | output (str video-name ".png")
180 | cmd ["ffmpeg"
181 | "-framerate" (str framerate)
182 | "-y" "-i" input "-f" "apng"
183 | "-plays" (if loop-video? "0" "1")
184 | output]]
185 | (println "Generate video " output)
186 | (let [{exit :exit err :err} (apply sh/sh cmd)]
187 | (if (zero? exit)
188 | (recur video-names)
189 | (println "Failed to generate video with command: \n > "
190 | (str/join " " cmd)
191 | "\n Check ffmpeg installation, subprocess err: \n"
192 | err))))))))
193 |
194 | (defn run-tests
195 | ([build-output]
196 | (run-tests build-output nil))
197 | ([{:keys [js runner]} {:keys [headless? no-sandbox?
198 | screenshot-video? framerate loop-video?
199 | ring-handler on-test-result
200 | root-paths]
201 | :or {root-paths #{"."}}}]
202 | (log "Run compiled js test file:" js)
203 | (let [chrome-fixture (create-chrome-fixture {:headless? (if (some? headless?)
204 | headless?
205 | true)
206 | :no-sandbox? no-sandbox?})]
207 | (chrome-fixture
208 | (fn []
209 | (log "Chrome launched")
210 | (let [port (random-free-port)
211 | file-handler (partial file-handler root-paths)
212 | server (http-server/run-server (fn [req]
213 | (or (and ring-handler (ring-handler req))
214 | (file-handler req)))
215 | {:port port})
216 | f (File/createTempFile "test" ".html" (io/file "."))
217 | url (str "http://localhost:" port "/" (.getName f))]
218 | (try
219 | (spit f (test-page (merge
220 | {:js js}
221 | (when runner
222 | {:runner runner}))))
223 |
224 | (log "Navigate to:" url)
225 | (automation/to url)
226 |
227 | (log "Wait for test output")
228 | (let [{:keys [result screenshots] :as test-result} (poll-test-execution)]
229 | (when screenshot-video?
230 | (output-screenshot-videos screenshots (or framerate 2) loop-video?))
231 | (if on-test-result
232 | (on-test-result test-result)
233 | (is (= result :ok)
234 | "ClojureScript tests had failures or errors, see previous output for details ")))
235 |
236 | (log "Tests done, cleanup")
237 | (server)
238 | (finally
239 | (io/delete-file f)))))))))
240 |
241 | (defn build-and-test
242 | ([build-id namespaces]
243 | (build-and-test build-id namespaces nil))
244 | ([build-id namespaces options]
245 | (binding [log (if (:verbose? options)
246 | println-log
247 | no-op-log)]
248 | (let [project-clj (load-project-clj)
249 | build-output (build project-clj build-id namespaces)]
250 | (run-tests build-output options)))))
251 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/animation.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.animation
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (s/def
7 | ::animation
8 | (s/keys
9 | :req-un
10 | [::id
11 | ::name
12 | ::paused-state
13 | ::play-state
14 | ::playback-rate
15 | ::start-time
16 | ::current-time
17 | ::type]
18 | :opt-un
19 | [::source
20 | ::css-id]))
21 |
22 | (s/def
23 | ::animation-effect
24 | (s/keys
25 | :req-un
26 | [::delay
27 | ::end-delay
28 | ::iteration-start
29 | ::iterations
30 | ::duration
31 | ::direction
32 | ::fill
33 | ::easing]
34 | :opt-un
35 | [::backend-node-id
36 | ::keyframes-rule]))
37 |
38 | (s/def
39 | ::keyframes-rule
40 | (s/keys
41 | :req-un
42 | [::keyframes]
43 | :opt-un
44 | [::name]))
45 |
46 | (s/def
47 | ::keyframe-style
48 | (s/keys
49 | :req-un
50 | [::offset
51 | ::easing]))
52 | (defn
53 | disable
54 | "Disables animation domain notifications."
55 | ([]
56 | (disable
57 | (c/get-current-connection)
58 | {}))
59 | ([{:as params, :keys []}]
60 | (disable
61 | (c/get-current-connection)
62 | params))
63 | ([connection {:as params, :keys []}]
64 | (cmd/command
65 | connection
66 | "Animation"
67 | "disable"
68 | params
69 | {})))
70 |
71 | (s/fdef
72 | disable
73 | :args
74 | (s/or
75 | :no-args
76 | (s/cat)
77 | :just-params
78 | (s/cat :params (s/keys))
79 | :connection-and-params
80 | (s/cat
81 | :connection
82 | (s/?
83 | c/connection?)
84 | :params
85 | (s/keys)))
86 | :ret
87 | (s/keys))
88 |
89 | (defn
90 | enable
91 | "Enables animation domain notifications."
92 | ([]
93 | (enable
94 | (c/get-current-connection)
95 | {}))
96 | ([{:as params, :keys []}]
97 | (enable
98 | (c/get-current-connection)
99 | params))
100 | ([connection {:as params, :keys []}]
101 | (cmd/command
102 | connection
103 | "Animation"
104 | "enable"
105 | params
106 | {})))
107 |
108 | (s/fdef
109 | enable
110 | :args
111 | (s/or
112 | :no-args
113 | (s/cat)
114 | :just-params
115 | (s/cat :params (s/keys))
116 | :connection-and-params
117 | (s/cat
118 | :connection
119 | (s/?
120 | c/connection?)
121 | :params
122 | (s/keys)))
123 | :ret
124 | (s/keys))
125 |
126 | (defn
127 | get-current-time
128 | "Returns the current time of the an animation.\n\nParameters map keys:\n\n\n Key | Description \n ----|------------ \n :id | Id of animation.\n\nReturn map keys:\n\n\n Key | Description \n --------------|------------ \n :current-time | Current time of the page."
129 | ([]
130 | (get-current-time
131 | (c/get-current-connection)
132 | {}))
133 | ([{:as params, :keys [id]}]
134 | (get-current-time
135 | (c/get-current-connection)
136 | params))
137 | ([connection {:as params, :keys [id]}]
138 | (cmd/command
139 | connection
140 | "Animation"
141 | "getCurrentTime"
142 | params
143 | {:id "id"})))
144 |
145 | (s/fdef
146 | get-current-time
147 | :args
148 | (s/or
149 | :no-args
150 | (s/cat)
151 | :just-params
152 | (s/cat
153 | :params
154 | (s/keys
155 | :req-un
156 | [::id]))
157 | :connection-and-params
158 | (s/cat
159 | :connection
160 | (s/?
161 | c/connection?)
162 | :params
163 | (s/keys
164 | :req-un
165 | [::id])))
166 | :ret
167 | (s/keys
168 | :req-un
169 | [::current-time]))
170 |
171 | (defn
172 | get-playback-rate
173 | "Gets the playback rate of the document timeline.\n\nReturn map keys:\n\n\n Key | Description \n ---------------|------------ \n :playback-rate | Playback rate for animations on page."
174 | ([]
175 | (get-playback-rate
176 | (c/get-current-connection)
177 | {}))
178 | ([{:as params, :keys []}]
179 | (get-playback-rate
180 | (c/get-current-connection)
181 | params))
182 | ([connection {:as params, :keys []}]
183 | (cmd/command
184 | connection
185 | "Animation"
186 | "getPlaybackRate"
187 | params
188 | {})))
189 |
190 | (s/fdef
191 | get-playback-rate
192 | :args
193 | (s/or
194 | :no-args
195 | (s/cat)
196 | :just-params
197 | (s/cat :params (s/keys))
198 | :connection-and-params
199 | (s/cat
200 | :connection
201 | (s/?
202 | c/connection?)
203 | :params
204 | (s/keys)))
205 | :ret
206 | (s/keys
207 | :req-un
208 | [::playback-rate]))
209 |
210 | (defn
211 | release-animations
212 | "Releases a set of animations to no longer be manipulated.\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :animations | List of animation ids to seek."
213 | ([]
214 | (release-animations
215 | (c/get-current-connection)
216 | {}))
217 | ([{:as params, :keys [animations]}]
218 | (release-animations
219 | (c/get-current-connection)
220 | params))
221 | ([connection {:as params, :keys [animations]}]
222 | (cmd/command
223 | connection
224 | "Animation"
225 | "releaseAnimations"
226 | params
227 | {:animations "animations"})))
228 |
229 | (s/fdef
230 | release-animations
231 | :args
232 | (s/or
233 | :no-args
234 | (s/cat)
235 | :just-params
236 | (s/cat
237 | :params
238 | (s/keys
239 | :req-un
240 | [::animations]))
241 | :connection-and-params
242 | (s/cat
243 | :connection
244 | (s/?
245 | c/connection?)
246 | :params
247 | (s/keys
248 | :req-un
249 | [::animations])))
250 | :ret
251 | (s/keys))
252 |
253 | (defn
254 | resolve-animation
255 | "Gets the remote object of the Animation.\n\nParameters map keys:\n\n\n Key | Description \n --------------|------------ \n :animation-id | Animation id.\n\nReturn map keys:\n\n\n Key | Description \n ---------------|------------ \n :remote-object | Corresponding remote object."
256 | ([]
257 | (resolve-animation
258 | (c/get-current-connection)
259 | {}))
260 | ([{:as params, :keys [animation-id]}]
261 | (resolve-animation
262 | (c/get-current-connection)
263 | params))
264 | ([connection {:as params, :keys [animation-id]}]
265 | (cmd/command
266 | connection
267 | "Animation"
268 | "resolveAnimation"
269 | params
270 | {:animation-id "animationId"})))
271 |
272 | (s/fdef
273 | resolve-animation
274 | :args
275 | (s/or
276 | :no-args
277 | (s/cat)
278 | :just-params
279 | (s/cat
280 | :params
281 | (s/keys
282 | :req-un
283 | [::animation-id]))
284 | :connection-and-params
285 | (s/cat
286 | :connection
287 | (s/?
288 | c/connection?)
289 | :params
290 | (s/keys
291 | :req-un
292 | [::animation-id])))
293 | :ret
294 | (s/keys
295 | :req-un
296 | [::remote-object]))
297 |
298 | (defn
299 | seek-animations
300 | "Seek a set of animations to a particular time within each animation.\n\nParameters map keys:\n\n\n Key | Description \n --------------|------------ \n :animations | List of animation ids to seek.\n :current-time | Set the current time of each animation."
301 | ([]
302 | (seek-animations
303 | (c/get-current-connection)
304 | {}))
305 | ([{:as params, :keys [animations current-time]}]
306 | (seek-animations
307 | (c/get-current-connection)
308 | params))
309 | ([connection {:as params, :keys [animations current-time]}]
310 | (cmd/command
311 | connection
312 | "Animation"
313 | "seekAnimations"
314 | params
315 | {:animations "animations", :current-time "currentTime"})))
316 |
317 | (s/fdef
318 | seek-animations
319 | :args
320 | (s/or
321 | :no-args
322 | (s/cat)
323 | :just-params
324 | (s/cat
325 | :params
326 | (s/keys
327 | :req-un
328 | [::animations
329 | ::current-time]))
330 | :connection-and-params
331 | (s/cat
332 | :connection
333 | (s/?
334 | c/connection?)
335 | :params
336 | (s/keys
337 | :req-un
338 | [::animations
339 | ::current-time])))
340 | :ret
341 | (s/keys))
342 |
343 | (defn
344 | set-paused
345 | "Sets the paused state of a set of animations.\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :animations | Animations to set the pause state of.\n :paused | Paused state to set to."
346 | ([]
347 | (set-paused
348 | (c/get-current-connection)
349 | {}))
350 | ([{:as params, :keys [animations paused]}]
351 | (set-paused
352 | (c/get-current-connection)
353 | params))
354 | ([connection {:as params, :keys [animations paused]}]
355 | (cmd/command
356 | connection
357 | "Animation"
358 | "setPaused"
359 | params
360 | {:animations "animations", :paused "paused"})))
361 |
362 | (s/fdef
363 | set-paused
364 | :args
365 | (s/or
366 | :no-args
367 | (s/cat)
368 | :just-params
369 | (s/cat
370 | :params
371 | (s/keys
372 | :req-un
373 | [::animations
374 | ::paused]))
375 | :connection-and-params
376 | (s/cat
377 | :connection
378 | (s/?
379 | c/connection?)
380 | :params
381 | (s/keys
382 | :req-un
383 | [::animations
384 | ::paused])))
385 | :ret
386 | (s/keys))
387 |
388 | (defn
389 | set-playback-rate
390 | "Sets the playback rate of the document timeline.\n\nParameters map keys:\n\n\n Key | Description \n ---------------|------------ \n :playback-rate | Playback rate for animations on page"
391 | ([]
392 | (set-playback-rate
393 | (c/get-current-connection)
394 | {}))
395 | ([{:as params, :keys [playback-rate]}]
396 | (set-playback-rate
397 | (c/get-current-connection)
398 | params))
399 | ([connection {:as params, :keys [playback-rate]}]
400 | (cmd/command
401 | connection
402 | "Animation"
403 | "setPlaybackRate"
404 | params
405 | {:playback-rate "playbackRate"})))
406 |
407 | (s/fdef
408 | set-playback-rate
409 | :args
410 | (s/or
411 | :no-args
412 | (s/cat)
413 | :just-params
414 | (s/cat
415 | :params
416 | (s/keys
417 | :req-un
418 | [::playback-rate]))
419 | :connection-and-params
420 | (s/cat
421 | :connection
422 | (s/?
423 | c/connection?)
424 | :params
425 | (s/keys
426 | :req-un
427 | [::playback-rate])))
428 | :ret
429 | (s/keys))
430 |
431 | (defn
432 | set-timing
433 | "Sets the timing of an animation node.\n\nParameters map keys:\n\n\n Key | Description \n --------------|------------ \n :animation-id | Animation id.\n :duration | Duration of the animation.\n :delay | Delay of the animation."
434 | ([]
435 | (set-timing
436 | (c/get-current-connection)
437 | {}))
438 | ([{:as params, :keys [animation-id duration delay]}]
439 | (set-timing
440 | (c/get-current-connection)
441 | params))
442 | ([connection {:as params, :keys [animation-id duration delay]}]
443 | (cmd/command
444 | connection
445 | "Animation"
446 | "setTiming"
447 | params
448 | {:animation-id "animationId",
449 | :duration "duration",
450 | :delay "delay"})))
451 |
452 | (s/fdef
453 | set-timing
454 | :args
455 | (s/or
456 | :no-args
457 | (s/cat)
458 | :just-params
459 | (s/cat
460 | :params
461 | (s/keys
462 | :req-un
463 | [::animation-id
464 | ::duration
465 | ::delay]))
466 | :connection-and-params
467 | (s/cat
468 | :connection
469 | (s/?
470 | c/connection?)
471 | :params
472 | (s/keys
473 | :req-un
474 | [::animation-id
475 | ::duration
476 | ::delay])))
477 | :ret
478 | (s/keys))
479 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/application_cache.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.application-cache
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (s/def
7 | ::application-cache-resource
8 | (s/keys
9 | :req-un
10 | [::url
11 | ::size
12 | ::type]))
13 |
14 | (s/def
15 | ::application-cache
16 | (s/keys
17 | :req-un
18 | [::manifest-url
19 | ::size
20 | ::creation-time
21 | ::update-time
22 | ::resources]))
23 |
24 | (s/def
25 | ::frame-with-manifest
26 | (s/keys
27 | :req-un
28 | [::frame-id
29 | ::manifest-url
30 | ::status]))
31 | (defn
32 | enable
33 | "Enables application cache domain notifications."
34 | ([]
35 | (enable
36 | (c/get-current-connection)
37 | {}))
38 | ([{:as params, :keys []}]
39 | (enable
40 | (c/get-current-connection)
41 | params))
42 | ([connection {:as params, :keys []}]
43 | (cmd/command
44 | connection
45 | "ApplicationCache"
46 | "enable"
47 | params
48 | {})))
49 |
50 | (s/fdef
51 | enable
52 | :args
53 | (s/or
54 | :no-args
55 | (s/cat)
56 | :just-params
57 | (s/cat :params (s/keys))
58 | :connection-and-params
59 | (s/cat
60 | :connection
61 | (s/?
62 | c/connection?)
63 | :params
64 | (s/keys)))
65 | :ret
66 | (s/keys))
67 |
68 | (defn
69 | get-application-cache-for-frame
70 | "Returns relevant application cache data for the document in given frame.\n\nParameters map keys:\n\n\n Key | Description \n ----------|------------ \n :frame-id | Identifier of the frame containing document whose application cache is retrieved.\n\nReturn map keys:\n\n\n Key | Description \n -------------------|------------ \n :application-cache | Relevant application cache data for the document in given frame."
71 | ([]
72 | (get-application-cache-for-frame
73 | (c/get-current-connection)
74 | {}))
75 | ([{:as params, :keys [frame-id]}]
76 | (get-application-cache-for-frame
77 | (c/get-current-connection)
78 | params))
79 | ([connection {:as params, :keys [frame-id]}]
80 | (cmd/command
81 | connection
82 | "ApplicationCache"
83 | "getApplicationCacheForFrame"
84 | params
85 | {:frame-id "frameId"})))
86 |
87 | (s/fdef
88 | get-application-cache-for-frame
89 | :args
90 | (s/or
91 | :no-args
92 | (s/cat)
93 | :just-params
94 | (s/cat
95 | :params
96 | (s/keys
97 | :req-un
98 | [::frame-id]))
99 | :connection-and-params
100 | (s/cat
101 | :connection
102 | (s/?
103 | c/connection?)
104 | :params
105 | (s/keys
106 | :req-un
107 | [::frame-id])))
108 | :ret
109 | (s/keys
110 | :req-un
111 | [::application-cache]))
112 |
113 | (defn
114 | get-frames-with-manifests
115 | "Returns array of frame identifiers with manifest urls for each frame containing a document\nassociated with some application cache.\n\nReturn map keys:\n\n\n Key | Description \n -----------|------------ \n :frame-ids | Array of frame identifiers with manifest urls for each frame containing a document\nassociated with some application cache."
116 | ([]
117 | (get-frames-with-manifests
118 | (c/get-current-connection)
119 | {}))
120 | ([{:as params, :keys []}]
121 | (get-frames-with-manifests
122 | (c/get-current-connection)
123 | params))
124 | ([connection {:as params, :keys []}]
125 | (cmd/command
126 | connection
127 | "ApplicationCache"
128 | "getFramesWithManifests"
129 | params
130 | {})))
131 |
132 | (s/fdef
133 | get-frames-with-manifests
134 | :args
135 | (s/or
136 | :no-args
137 | (s/cat)
138 | :just-params
139 | (s/cat :params (s/keys))
140 | :connection-and-params
141 | (s/cat
142 | :connection
143 | (s/?
144 | c/connection?)
145 | :params
146 | (s/keys)))
147 | :ret
148 | (s/keys
149 | :req-un
150 | [::frame-ids]))
151 |
152 | (defn
153 | get-manifest-for-frame
154 | "Returns manifest URL for document in the given frame.\n\nParameters map keys:\n\n\n Key | Description \n ----------|------------ \n :frame-id | Identifier of the frame containing document whose manifest is retrieved.\n\nReturn map keys:\n\n\n Key | Description \n --------------|------------ \n :manifest-url | Manifest URL for document in the given frame."
155 | ([]
156 | (get-manifest-for-frame
157 | (c/get-current-connection)
158 | {}))
159 | ([{:as params, :keys [frame-id]}]
160 | (get-manifest-for-frame
161 | (c/get-current-connection)
162 | params))
163 | ([connection {:as params, :keys [frame-id]}]
164 | (cmd/command
165 | connection
166 | "ApplicationCache"
167 | "getManifestForFrame"
168 | params
169 | {:frame-id "frameId"})))
170 |
171 | (s/fdef
172 | get-manifest-for-frame
173 | :args
174 | (s/or
175 | :no-args
176 | (s/cat)
177 | :just-params
178 | (s/cat
179 | :params
180 | (s/keys
181 | :req-un
182 | [::frame-id]))
183 | :connection-and-params
184 | (s/cat
185 | :connection
186 | (s/?
187 | c/connection?)
188 | :params
189 | (s/keys
190 | :req-un
191 | [::frame-id])))
192 | :ret
193 | (s/keys
194 | :req-un
195 | [::manifest-url]))
196 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/background_service.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.background-service
2 | "Defines events for background web platform features."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::service-name
9 | #{"pushMessaging" "paymentHandler" "notifications" "backgroundSync"
10 | "periodicBackgroundSync" "backgroundFetch"})
11 |
12 | (s/def
13 | ::event-metadata
14 | (s/keys
15 | :req-un
16 | [::key
17 | ::value]))
18 |
19 | (s/def
20 | ::background-service-event
21 | (s/keys
22 | :req-un
23 | [::timestamp
24 | ::origin
25 | ::service-worker-registration-id
26 | ::service
27 | ::event-name
28 | ::instance-id
29 | ::event-metadata]))
30 | (defn
31 | start-observing
32 | "Enables event updates for the service.\n\nParameters map keys:\n\n\n Key | Description \n ---------|------------ \n :service | null"
33 | ([]
34 | (start-observing
35 | (c/get-current-connection)
36 | {}))
37 | ([{:as params, :keys [service]}]
38 | (start-observing
39 | (c/get-current-connection)
40 | params))
41 | ([connection {:as params, :keys [service]}]
42 | (cmd/command
43 | connection
44 | "BackgroundService"
45 | "startObserving"
46 | params
47 | {:service "service"})))
48 |
49 | (s/fdef
50 | start-observing
51 | :args
52 | (s/or
53 | :no-args
54 | (s/cat)
55 | :just-params
56 | (s/cat
57 | :params
58 | (s/keys
59 | :req-un
60 | [::service]))
61 | :connection-and-params
62 | (s/cat
63 | :connection
64 | (s/?
65 | c/connection?)
66 | :params
67 | (s/keys
68 | :req-un
69 | [::service])))
70 | :ret
71 | (s/keys))
72 |
73 | (defn
74 | stop-observing
75 | "Disables event updates for the service.\n\nParameters map keys:\n\n\n Key | Description \n ---------|------------ \n :service | null"
76 | ([]
77 | (stop-observing
78 | (c/get-current-connection)
79 | {}))
80 | ([{:as params, :keys [service]}]
81 | (stop-observing
82 | (c/get-current-connection)
83 | params))
84 | ([connection {:as params, :keys [service]}]
85 | (cmd/command
86 | connection
87 | "BackgroundService"
88 | "stopObserving"
89 | params
90 | {:service "service"})))
91 |
92 | (s/fdef
93 | stop-observing
94 | :args
95 | (s/or
96 | :no-args
97 | (s/cat)
98 | :just-params
99 | (s/cat
100 | :params
101 | (s/keys
102 | :req-un
103 | [::service]))
104 | :connection-and-params
105 | (s/cat
106 | :connection
107 | (s/?
108 | c/connection?)
109 | :params
110 | (s/keys
111 | :req-un
112 | [::service])))
113 | :ret
114 | (s/keys))
115 |
116 | (defn
117 | set-recording
118 | "Set the recording state for the service.\n\nParameters map keys:\n\n\n Key | Description \n ---------------|------------ \n :should-record | null\n :service | null"
119 | ([]
120 | (set-recording
121 | (c/get-current-connection)
122 | {}))
123 | ([{:as params, :keys [should-record service]}]
124 | (set-recording
125 | (c/get-current-connection)
126 | params))
127 | ([connection {:as params, :keys [should-record service]}]
128 | (cmd/command
129 | connection
130 | "BackgroundService"
131 | "setRecording"
132 | params
133 | {:should-record "shouldRecord", :service "service"})))
134 |
135 | (s/fdef
136 | set-recording
137 | :args
138 | (s/or
139 | :no-args
140 | (s/cat)
141 | :just-params
142 | (s/cat
143 | :params
144 | (s/keys
145 | :req-un
146 | [::should-record
147 | ::service]))
148 | :connection-and-params
149 | (s/cat
150 | :connection
151 | (s/?
152 | c/connection?)
153 | :params
154 | (s/keys
155 | :req-un
156 | [::should-record
157 | ::service])))
158 | :ret
159 | (s/keys))
160 |
161 | (defn
162 | clear-events
163 | "Clears all stored data for the service.\n\nParameters map keys:\n\n\n Key | Description \n ---------|------------ \n :service | null"
164 | ([]
165 | (clear-events
166 | (c/get-current-connection)
167 | {}))
168 | ([{:as params, :keys [service]}]
169 | (clear-events
170 | (c/get-current-connection)
171 | params))
172 | ([connection {:as params, :keys [service]}]
173 | (cmd/command
174 | connection
175 | "BackgroundService"
176 | "clearEvents"
177 | params
178 | {:service "service"})))
179 |
180 | (s/fdef
181 | clear-events
182 | :args
183 | (s/or
184 | :no-args
185 | (s/cat)
186 | :just-params
187 | (s/cat
188 | :params
189 | (s/keys
190 | :req-un
191 | [::service]))
192 | :connection-and-params
193 | (s/cat
194 | :connection
195 | (s/?
196 | c/connection?)
197 | :params
198 | (s/keys
199 | :req-un
200 | [::service])))
201 | :ret
202 | (s/keys))
203 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/cache_storage.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.cache-storage
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (s/def
7 | ::cache-id
8 | string?)
9 |
10 | (s/def
11 | ::cached-response-type
12 | #{"opaqueResponse" "error" "cors" "default" "opaqueRedirect" "basic"})
13 |
14 | (s/def
15 | ::data-entry
16 | (s/keys
17 | :req-un
18 | [::request-url
19 | ::request-method
20 | ::request-headers
21 | ::response-time
22 | ::response-status
23 | ::response-status-text
24 | ::response-type
25 | ::response-headers]))
26 |
27 | (s/def
28 | ::cache
29 | (s/keys
30 | :req-un
31 | [::cache-id
32 | ::security-origin
33 | ::cache-name]))
34 |
35 | (s/def
36 | ::header
37 | (s/keys
38 | :req-un
39 | [::name
40 | ::value]))
41 |
42 | (s/def
43 | ::cached-response
44 | (s/keys
45 | :req-un
46 | [::body]))
47 | (defn
48 | delete-cache
49 | "Deletes a cache.\n\nParameters map keys:\n\n\n Key | Description \n ----------|------------ \n :cache-id | Id of cache for deletion."
50 | ([]
51 | (delete-cache
52 | (c/get-current-connection)
53 | {}))
54 | ([{:as params, :keys [cache-id]}]
55 | (delete-cache
56 | (c/get-current-connection)
57 | params))
58 | ([connection {:as params, :keys [cache-id]}]
59 | (cmd/command
60 | connection
61 | "CacheStorage"
62 | "deleteCache"
63 | params
64 | {:cache-id "cacheId"})))
65 |
66 | (s/fdef
67 | delete-cache
68 | :args
69 | (s/or
70 | :no-args
71 | (s/cat)
72 | :just-params
73 | (s/cat
74 | :params
75 | (s/keys
76 | :req-un
77 | [::cache-id]))
78 | :connection-and-params
79 | (s/cat
80 | :connection
81 | (s/?
82 | c/connection?)
83 | :params
84 | (s/keys
85 | :req-un
86 | [::cache-id])))
87 | :ret
88 | (s/keys))
89 |
90 | (defn
91 | delete-entry
92 | "Deletes a cache entry.\n\nParameters map keys:\n\n\n Key | Description \n ----------|------------ \n :cache-id | Id of cache where the entry will be deleted.\n :request | URL spec of the request."
93 | ([]
94 | (delete-entry
95 | (c/get-current-connection)
96 | {}))
97 | ([{:as params, :keys [cache-id request]}]
98 | (delete-entry
99 | (c/get-current-connection)
100 | params))
101 | ([connection {:as params, :keys [cache-id request]}]
102 | (cmd/command
103 | connection
104 | "CacheStorage"
105 | "deleteEntry"
106 | params
107 | {:cache-id "cacheId", :request "request"})))
108 |
109 | (s/fdef
110 | delete-entry
111 | :args
112 | (s/or
113 | :no-args
114 | (s/cat)
115 | :just-params
116 | (s/cat
117 | :params
118 | (s/keys
119 | :req-un
120 | [::cache-id
121 | ::request]))
122 | :connection-and-params
123 | (s/cat
124 | :connection
125 | (s/?
126 | c/connection?)
127 | :params
128 | (s/keys
129 | :req-un
130 | [::cache-id
131 | ::request])))
132 | :ret
133 | (s/keys))
134 |
135 | (defn
136 | request-cache-names
137 | "Requests cache names.\n\nParameters map keys:\n\n\n Key | Description \n -----------------|------------ \n :security-origin | Security origin.\n\nReturn map keys:\n\n\n Key | Description \n --------|------------ \n :caches | Caches for the security origin."
138 | ([]
139 | (request-cache-names
140 | (c/get-current-connection)
141 | {}))
142 | ([{:as params, :keys [security-origin]}]
143 | (request-cache-names
144 | (c/get-current-connection)
145 | params))
146 | ([connection {:as params, :keys [security-origin]}]
147 | (cmd/command
148 | connection
149 | "CacheStorage"
150 | "requestCacheNames"
151 | params
152 | {:security-origin "securityOrigin"})))
153 |
154 | (s/fdef
155 | request-cache-names
156 | :args
157 | (s/or
158 | :no-args
159 | (s/cat)
160 | :just-params
161 | (s/cat
162 | :params
163 | (s/keys
164 | :req-un
165 | [::security-origin]))
166 | :connection-and-params
167 | (s/cat
168 | :connection
169 | (s/?
170 | c/connection?)
171 | :params
172 | (s/keys
173 | :req-un
174 | [::security-origin])))
175 | :ret
176 | (s/keys
177 | :req-un
178 | [::caches]))
179 |
180 | (defn
181 | request-cached-response
182 | "Fetches cache entry.\n\nParameters map keys:\n\n\n Key | Description \n -----------------|------------ \n :cache-id | Id of cache that contains the entry.\n :request-url | URL spec of the request.\n :request-headers | headers of the request.\n\nReturn map keys:\n\n\n Key | Description \n ----------|------------ \n :response | Response read from the cache."
183 | ([]
184 | (request-cached-response
185 | (c/get-current-connection)
186 | {}))
187 | ([{:as params, :keys [cache-id request-url request-headers]}]
188 | (request-cached-response
189 | (c/get-current-connection)
190 | params))
191 | ([connection
192 | {:as params, :keys [cache-id request-url request-headers]}]
193 | (cmd/command
194 | connection
195 | "CacheStorage"
196 | "requestCachedResponse"
197 | params
198 | {:cache-id "cacheId",
199 | :request-url "requestURL",
200 | :request-headers "requestHeaders"})))
201 |
202 | (s/fdef
203 | request-cached-response
204 | :args
205 | (s/or
206 | :no-args
207 | (s/cat)
208 | :just-params
209 | (s/cat
210 | :params
211 | (s/keys
212 | :req-un
213 | [::cache-id
214 | ::request-url
215 | ::request-headers]))
216 | :connection-and-params
217 | (s/cat
218 | :connection
219 | (s/?
220 | c/connection?)
221 | :params
222 | (s/keys
223 | :req-un
224 | [::cache-id
225 | ::request-url
226 | ::request-headers])))
227 | :ret
228 | (s/keys
229 | :req-un
230 | [::response]))
231 |
232 | (defn
233 | request-entries
234 | "Requests data from cache.\n\nParameters map keys:\n\n\n Key | Description \n -------------|------------ \n :cache-id | ID of cache to get entries from.\n :skip-count | Number of records to skip. (optional)\n :page-size | Number of records to fetch. (optional)\n :path-filter | If present, only return the entries containing this substring in the path (optional)\n\nReturn map keys:\n\n\n Key | Description \n --------------------|------------ \n :cache-data-entries | Array of object store data entries.\n :return-count | Count of returned entries from this storage. If pathFilter is empty, it\nis the count of all entries from this storage."
235 | ([]
236 | (request-entries
237 | (c/get-current-connection)
238 | {}))
239 | ([{:as params, :keys [cache-id skip-count page-size path-filter]}]
240 | (request-entries
241 | (c/get-current-connection)
242 | params))
243 | ([connection
244 | {:as params, :keys [cache-id skip-count page-size path-filter]}]
245 | (cmd/command
246 | connection
247 | "CacheStorage"
248 | "requestEntries"
249 | params
250 | {:cache-id "cacheId",
251 | :skip-count "skipCount",
252 | :page-size "pageSize",
253 | :path-filter "pathFilter"})))
254 |
255 | (s/fdef
256 | request-entries
257 | :args
258 | (s/or
259 | :no-args
260 | (s/cat)
261 | :just-params
262 | (s/cat
263 | :params
264 | (s/keys
265 | :req-un
266 | [::cache-id]
267 | :opt-un
268 | [::skip-count
269 | ::page-size
270 | ::path-filter]))
271 | :connection-and-params
272 | (s/cat
273 | :connection
274 | (s/?
275 | c/connection?)
276 | :params
277 | (s/keys
278 | :req-un
279 | [::cache-id]
280 | :opt-un
281 | [::skip-count
282 | ::page-size
283 | ::path-filter])))
284 | :ret
285 | (s/keys
286 | :req-un
287 | [::cache-data-entries
288 | ::return-count]))
289 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/cast.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.cast
2 | "A domain for interacting with Cast, Presentation API, and Remote Playback API\nfunctionalities."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::sink
9 | (s/keys
10 | :req-un
11 | [::name
12 | ::id]
13 | :opt-un
14 | [::session]))
15 | (defn
16 | enable
17 | "Starts observing for sinks that can be used for tab mirroring, and if set,\nsinks compatible with |presentationUrl| as well. When sinks are found, a\n|sinksUpdated| event is fired.\nAlso starts observing for issue messages. When an issue is added or removed,\nan |issueUpdated| event is fired.\n\nParameters map keys:\n\n\n Key | Description \n ------------------|------------ \n :presentation-url | null (optional)"
18 | ([]
19 | (enable
20 | (c/get-current-connection)
21 | {}))
22 | ([{:as params, :keys [presentation-url]}]
23 | (enable
24 | (c/get-current-connection)
25 | params))
26 | ([connection {:as params, :keys [presentation-url]}]
27 | (cmd/command
28 | connection
29 | "Cast"
30 | "enable"
31 | params
32 | {:presentation-url "presentationUrl"})))
33 |
34 | (s/fdef
35 | enable
36 | :args
37 | (s/or
38 | :no-args
39 | (s/cat)
40 | :just-params
41 | (s/cat
42 | :params
43 | (s/keys
44 | :opt-un
45 | [::presentation-url]))
46 | :connection-and-params
47 | (s/cat
48 | :connection
49 | (s/?
50 | c/connection?)
51 | :params
52 | (s/keys
53 | :opt-un
54 | [::presentation-url])))
55 | :ret
56 | (s/keys))
57 |
58 | (defn
59 | disable
60 | "Stops observing for sinks and issues."
61 | ([]
62 | (disable
63 | (c/get-current-connection)
64 | {}))
65 | ([{:as params, :keys []}]
66 | (disable
67 | (c/get-current-connection)
68 | params))
69 | ([connection {:as params, :keys []}]
70 | (cmd/command
71 | connection
72 | "Cast"
73 | "disable"
74 | params
75 | {})))
76 |
77 | (s/fdef
78 | disable
79 | :args
80 | (s/or
81 | :no-args
82 | (s/cat)
83 | :just-params
84 | (s/cat :params (s/keys))
85 | :connection-and-params
86 | (s/cat
87 | :connection
88 | (s/?
89 | c/connection?)
90 | :params
91 | (s/keys)))
92 | :ret
93 | (s/keys))
94 |
95 | (defn
96 | set-sink-to-use
97 | "Sets a sink to be used when the web page requests the browser to choose a\nsink via Presentation API, Remote Playback API, or Cast SDK.\n\nParameters map keys:\n\n\n Key | Description \n -----------|------------ \n :sink-name | null"
98 | ([]
99 | (set-sink-to-use
100 | (c/get-current-connection)
101 | {}))
102 | ([{:as params, :keys [sink-name]}]
103 | (set-sink-to-use
104 | (c/get-current-connection)
105 | params))
106 | ([connection {:as params, :keys [sink-name]}]
107 | (cmd/command
108 | connection
109 | "Cast"
110 | "setSinkToUse"
111 | params
112 | {:sink-name "sinkName"})))
113 |
114 | (s/fdef
115 | set-sink-to-use
116 | :args
117 | (s/or
118 | :no-args
119 | (s/cat)
120 | :just-params
121 | (s/cat
122 | :params
123 | (s/keys
124 | :req-un
125 | [::sink-name]))
126 | :connection-and-params
127 | (s/cat
128 | :connection
129 | (s/?
130 | c/connection?)
131 | :params
132 | (s/keys
133 | :req-un
134 | [::sink-name])))
135 | :ret
136 | (s/keys))
137 |
138 | (defn
139 | start-desktop-mirroring
140 | "Starts mirroring the desktop to the sink.\n\nParameters map keys:\n\n\n Key | Description \n -----------|------------ \n :sink-name | null"
141 | ([]
142 | (start-desktop-mirroring
143 | (c/get-current-connection)
144 | {}))
145 | ([{:as params, :keys [sink-name]}]
146 | (start-desktop-mirroring
147 | (c/get-current-connection)
148 | params))
149 | ([connection {:as params, :keys [sink-name]}]
150 | (cmd/command
151 | connection
152 | "Cast"
153 | "startDesktopMirroring"
154 | params
155 | {:sink-name "sinkName"})))
156 |
157 | (s/fdef
158 | start-desktop-mirroring
159 | :args
160 | (s/or
161 | :no-args
162 | (s/cat)
163 | :just-params
164 | (s/cat
165 | :params
166 | (s/keys
167 | :req-un
168 | [::sink-name]))
169 | :connection-and-params
170 | (s/cat
171 | :connection
172 | (s/?
173 | c/connection?)
174 | :params
175 | (s/keys
176 | :req-un
177 | [::sink-name])))
178 | :ret
179 | (s/keys))
180 |
181 | (defn
182 | start-tab-mirroring
183 | "Starts mirroring the tab to the sink.\n\nParameters map keys:\n\n\n Key | Description \n -----------|------------ \n :sink-name | null"
184 | ([]
185 | (start-tab-mirroring
186 | (c/get-current-connection)
187 | {}))
188 | ([{:as params, :keys [sink-name]}]
189 | (start-tab-mirroring
190 | (c/get-current-connection)
191 | params))
192 | ([connection {:as params, :keys [sink-name]}]
193 | (cmd/command
194 | connection
195 | "Cast"
196 | "startTabMirroring"
197 | params
198 | {:sink-name "sinkName"})))
199 |
200 | (s/fdef
201 | start-tab-mirroring
202 | :args
203 | (s/or
204 | :no-args
205 | (s/cat)
206 | :just-params
207 | (s/cat
208 | :params
209 | (s/keys
210 | :req-un
211 | [::sink-name]))
212 | :connection-and-params
213 | (s/cat
214 | :connection
215 | (s/?
216 | c/connection?)
217 | :params
218 | (s/keys
219 | :req-un
220 | [::sink-name])))
221 | :ret
222 | (s/keys))
223 |
224 | (defn
225 | stop-casting
226 | "Stops the active Cast session on the sink.\n\nParameters map keys:\n\n\n Key | Description \n -----------|------------ \n :sink-name | null"
227 | ([]
228 | (stop-casting
229 | (c/get-current-connection)
230 | {}))
231 | ([{:as params, :keys [sink-name]}]
232 | (stop-casting
233 | (c/get-current-connection)
234 | params))
235 | ([connection {:as params, :keys [sink-name]}]
236 | (cmd/command
237 | connection
238 | "Cast"
239 | "stopCasting"
240 | params
241 | {:sink-name "sinkName"})))
242 |
243 | (s/fdef
244 | stop-casting
245 | :args
246 | (s/or
247 | :no-args
248 | (s/cat)
249 | :just-params
250 | (s/cat
251 | :params
252 | (s/keys
253 | :req-un
254 | [::sink-name]))
255 | :connection-and-params
256 | (s/cat
257 | :connection
258 | (s/?
259 | c/connection?)
260 | :params
261 | (s/keys
262 | :req-un
263 | [::sink-name])))
264 | :ret
265 | (s/keys))
266 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/console.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.console
2 | "This domain is deprecated - use Runtime or Log instead."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::console-message
9 | (s/keys
10 | :req-un
11 | [::source
12 | ::level
13 | ::text]
14 | :opt-un
15 | [::url
16 | ::line
17 | ::column]))
18 | (defn
19 | clear-messages
20 | "Does nothing."
21 | ([]
22 | (clear-messages
23 | (c/get-current-connection)
24 | {}))
25 | ([{:as params, :keys []}]
26 | (clear-messages
27 | (c/get-current-connection)
28 | params))
29 | ([connection {:as params, :keys []}]
30 | (cmd/command
31 | connection
32 | "Console"
33 | "clearMessages"
34 | params
35 | {})))
36 |
37 | (s/fdef
38 | clear-messages
39 | :args
40 | (s/or
41 | :no-args
42 | (s/cat)
43 | :just-params
44 | (s/cat :params (s/keys))
45 | :connection-and-params
46 | (s/cat
47 | :connection
48 | (s/?
49 | c/connection?)
50 | :params
51 | (s/keys)))
52 | :ret
53 | (s/keys))
54 |
55 | (defn
56 | disable
57 | "Disables console domain, prevents further console messages from being reported to the client."
58 | ([]
59 | (disable
60 | (c/get-current-connection)
61 | {}))
62 | ([{:as params, :keys []}]
63 | (disable
64 | (c/get-current-connection)
65 | params))
66 | ([connection {:as params, :keys []}]
67 | (cmd/command
68 | connection
69 | "Console"
70 | "disable"
71 | params
72 | {})))
73 |
74 | (s/fdef
75 | disable
76 | :args
77 | (s/or
78 | :no-args
79 | (s/cat)
80 | :just-params
81 | (s/cat :params (s/keys))
82 | :connection-and-params
83 | (s/cat
84 | :connection
85 | (s/?
86 | c/connection?)
87 | :params
88 | (s/keys)))
89 | :ret
90 | (s/keys))
91 |
92 | (defn
93 | enable
94 | "Enables console domain, sends the messages collected so far to the client by means of the\n`messageAdded` notification."
95 | ([]
96 | (enable
97 | (c/get-current-connection)
98 | {}))
99 | ([{:as params, :keys []}]
100 | (enable
101 | (c/get-current-connection)
102 | params))
103 | ([connection {:as params, :keys []}]
104 | (cmd/command
105 | connection
106 | "Console"
107 | "enable"
108 | params
109 | {})))
110 |
111 | (s/fdef
112 | enable
113 | :args
114 | (s/or
115 | :no-args
116 | (s/cat)
117 | :just-params
118 | (s/cat :params (s/keys))
119 | :connection-and-params
120 | (s/cat
121 | :connection
122 | (s/?
123 | c/connection?)
124 | :params
125 | (s/keys)))
126 | :ret
127 | (s/keys))
128 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/database.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.database
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (s/def
7 | ::database-id
8 | string?)
9 |
10 | (s/def
11 | ::database
12 | (s/keys
13 | :req-un
14 | [::id
15 | ::domain
16 | ::name
17 | ::version]))
18 |
19 | (s/def
20 | ::error
21 | (s/keys
22 | :req-un
23 | [::message
24 | ::code]))
25 | (defn
26 | disable
27 | "Disables database tracking, prevents database events from being sent to the client."
28 | ([]
29 | (disable
30 | (c/get-current-connection)
31 | {}))
32 | ([{:as params, :keys []}]
33 | (disable
34 | (c/get-current-connection)
35 | params))
36 | ([connection {:as params, :keys []}]
37 | (cmd/command
38 | connection
39 | "Database"
40 | "disable"
41 | params
42 | {})))
43 |
44 | (s/fdef
45 | disable
46 | :args
47 | (s/or
48 | :no-args
49 | (s/cat)
50 | :just-params
51 | (s/cat :params (s/keys))
52 | :connection-and-params
53 | (s/cat
54 | :connection
55 | (s/?
56 | c/connection?)
57 | :params
58 | (s/keys)))
59 | :ret
60 | (s/keys))
61 |
62 | (defn
63 | enable
64 | "Enables database tracking, database events will now be delivered to the client."
65 | ([]
66 | (enable
67 | (c/get-current-connection)
68 | {}))
69 | ([{:as params, :keys []}]
70 | (enable
71 | (c/get-current-connection)
72 | params))
73 | ([connection {:as params, :keys []}]
74 | (cmd/command
75 | connection
76 | "Database"
77 | "enable"
78 | params
79 | {})))
80 |
81 | (s/fdef
82 | enable
83 | :args
84 | (s/or
85 | :no-args
86 | (s/cat)
87 | :just-params
88 | (s/cat :params (s/keys))
89 | :connection-and-params
90 | (s/cat
91 | :connection
92 | (s/?
93 | c/connection?)
94 | :params
95 | (s/keys)))
96 | :ret
97 | (s/keys))
98 |
99 | (defn
100 | execute-sql
101 | "\n\nParameters map keys:\n\n\n Key | Description \n -------------|------------ \n :database-id | null\n :query | null\n\nReturn map keys:\n\n\n Key | Description \n --------------|------------ \n :column-names | null (optional)\n :values | null (optional)\n :sql-error | null (optional)"
102 | ([]
103 | (execute-sql
104 | (c/get-current-connection)
105 | {}))
106 | ([{:as params, :keys [database-id query]}]
107 | (execute-sql
108 | (c/get-current-connection)
109 | params))
110 | ([connection {:as params, :keys [database-id query]}]
111 | (cmd/command
112 | connection
113 | "Database"
114 | "executeSQL"
115 | params
116 | {:database-id "databaseId", :query "query"})))
117 |
118 | (s/fdef
119 | execute-sql
120 | :args
121 | (s/or
122 | :no-args
123 | (s/cat)
124 | :just-params
125 | (s/cat
126 | :params
127 | (s/keys
128 | :req-un
129 | [::database-id
130 | ::query]))
131 | :connection-and-params
132 | (s/cat
133 | :connection
134 | (s/?
135 | c/connection?)
136 | :params
137 | (s/keys
138 | :req-un
139 | [::database-id
140 | ::query])))
141 | :ret
142 | (s/keys
143 | :opt-un
144 | [::column-names
145 | ::values
146 | ::sql-error]))
147 |
148 | (defn
149 | get-database-table-names
150 | "\n\nParameters map keys:\n\n\n Key | Description \n -------------|------------ \n :database-id | null\n\nReturn map keys:\n\n\n Key | Description \n -------------|------------ \n :table-names | null"
151 | ([]
152 | (get-database-table-names
153 | (c/get-current-connection)
154 | {}))
155 | ([{:as params, :keys [database-id]}]
156 | (get-database-table-names
157 | (c/get-current-connection)
158 | params))
159 | ([connection {:as params, :keys [database-id]}]
160 | (cmd/command
161 | connection
162 | "Database"
163 | "getDatabaseTableNames"
164 | params
165 | {:database-id "databaseId"})))
166 |
167 | (s/fdef
168 | get-database-table-names
169 | :args
170 | (s/or
171 | :no-args
172 | (s/cat)
173 | :just-params
174 | (s/cat
175 | :params
176 | (s/keys
177 | :req-un
178 | [::database-id]))
179 | :connection-and-params
180 | (s/cat
181 | :connection
182 | (s/?
183 | c/connection?)
184 | :params
185 | (s/keys
186 | :req-un
187 | [::database-id])))
188 | :ret
189 | (s/keys
190 | :req-un
191 | [::table-names]))
192 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/device_orientation.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.device-orientation
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (defn
7 | clear-device-orientation-override
8 | "Clears the overridden Device Orientation."
9 | ([]
10 | (clear-device-orientation-override
11 | (c/get-current-connection)
12 | {}))
13 | ([{:as params, :keys []}]
14 | (clear-device-orientation-override
15 | (c/get-current-connection)
16 | params))
17 | ([connection {:as params, :keys []}]
18 | (cmd/command
19 | connection
20 | "DeviceOrientation"
21 | "clearDeviceOrientationOverride"
22 | params
23 | {})))
24 |
25 | (s/fdef
26 | clear-device-orientation-override
27 | :args
28 | (s/or
29 | :no-args
30 | (s/cat)
31 | :just-params
32 | (s/cat :params (s/keys))
33 | :connection-and-params
34 | (s/cat
35 | :connection
36 | (s/?
37 | c/connection?)
38 | :params
39 | (s/keys)))
40 | :ret
41 | (s/keys))
42 |
43 | (defn
44 | set-device-orientation-override
45 | "Overrides the Device Orientation.\n\nParameters map keys:\n\n\n Key | Description \n -------|------------ \n :alpha | Mock alpha\n :beta | Mock beta\n :gamma | Mock gamma"
46 | ([]
47 | (set-device-orientation-override
48 | (c/get-current-connection)
49 | {}))
50 | ([{:as params, :keys [alpha beta gamma]}]
51 | (set-device-orientation-override
52 | (c/get-current-connection)
53 | params))
54 | ([connection {:as params, :keys [alpha beta gamma]}]
55 | (cmd/command
56 | connection
57 | "DeviceOrientation"
58 | "setDeviceOrientationOverride"
59 | params
60 | {:alpha "alpha", :beta "beta", :gamma "gamma"})))
61 |
62 | (s/fdef
63 | set-device-orientation-override
64 | :args
65 | (s/or
66 | :no-args
67 | (s/cat)
68 | :just-params
69 | (s/cat
70 | :params
71 | (s/keys
72 | :req-un
73 | [::alpha
74 | ::beta
75 | ::gamma]))
76 | :connection-and-params
77 | (s/cat
78 | :connection
79 | (s/?
80 | c/connection?)
81 | :params
82 | (s/keys
83 | :req-un
84 | [::alpha
85 | ::beta
86 | ::gamma])))
87 | :ret
88 | (s/keys))
89 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/dom_snapshot.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.dom-snapshot
2 | "This domain facilitates obtaining document snapshots with DOM, layout, and style information."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::dom-node
9 | (s/keys
10 | :req-un
11 | [::node-type
12 | ::node-name
13 | ::node-value
14 | ::backend-node-id]
15 | :opt-un
16 | [::text-value
17 | ::input-value
18 | ::input-checked
19 | ::option-selected
20 | ::child-node-indexes
21 | ::attributes
22 | ::pseudo-element-indexes
23 | ::layout-node-index
24 | ::document-url
25 | ::base-url
26 | ::content-language
27 | ::document-encoding
28 | ::public-id
29 | ::system-id
30 | ::frame-id
31 | ::content-document-index
32 | ::pseudo-type
33 | ::shadow-root-type
34 | ::is-clickable
35 | ::event-listeners
36 | ::current-source-url
37 | ::origin-url
38 | ::scroll-offset-x
39 | ::scroll-offset-y]))
40 |
41 | (s/def
42 | ::inline-text-box
43 | (s/keys
44 | :req-un
45 | [::bounding-box
46 | ::start-character-index
47 | ::num-characters]))
48 |
49 | (s/def
50 | ::layout-tree-node
51 | (s/keys
52 | :req-un
53 | [::dom-node-index
54 | ::bounding-box]
55 | :opt-un
56 | [::layout-text
57 | ::inline-text-nodes
58 | ::style-index
59 | ::paint-order
60 | ::is-stacking-context]))
61 |
62 | (s/def
63 | ::computed-style
64 | (s/keys
65 | :req-un
66 | [::properties]))
67 |
68 | (s/def
69 | ::name-value
70 | (s/keys
71 | :req-un
72 | [::name
73 | ::value]))
74 |
75 | (s/def
76 | ::string-index
77 | integer?)
78 |
79 | (s/def
80 | ::array-of-strings
81 | (s/coll-of any?))
82 |
83 | (s/def
84 | ::rare-string-data
85 | (s/keys
86 | :req-un
87 | [::index
88 | ::value]))
89 |
90 | (s/def
91 | ::rare-boolean-data
92 | (s/keys
93 | :req-un
94 | [::index]))
95 |
96 | (s/def
97 | ::rare-integer-data
98 | (s/keys
99 | :req-un
100 | [::index
101 | ::value]))
102 |
103 | (s/def
104 | ::rectangle
105 | (s/coll-of number?))
106 |
107 | (s/def
108 | ::document-snapshot
109 | (s/keys
110 | :req-un
111 | [::document-url
112 | ::title
113 | ::base-url
114 | ::content-language
115 | ::encoding-name
116 | ::public-id
117 | ::system-id
118 | ::frame-id
119 | ::nodes
120 | ::layout
121 | ::text-boxes]
122 | :opt-un
123 | [::scroll-offset-x
124 | ::scroll-offset-y
125 | ::content-width
126 | ::content-height]))
127 |
128 | (s/def
129 | ::node-tree-snapshot
130 | (s/keys
131 | :opt-un
132 | [::parent-index
133 | ::node-type
134 | ::shadow-root-type
135 | ::node-name
136 | ::node-value
137 | ::backend-node-id
138 | ::attributes
139 | ::text-value
140 | ::input-value
141 | ::input-checked
142 | ::option-selected
143 | ::content-document-index
144 | ::pseudo-type
145 | ::is-clickable
146 | ::current-source-url
147 | ::origin-url]))
148 |
149 | (s/def
150 | ::layout-tree-snapshot
151 | (s/keys
152 | :req-un
153 | [::node-index
154 | ::styles
155 | ::bounds
156 | ::text
157 | ::stacking-contexts]
158 | :opt-un
159 | [::paint-orders
160 | ::offset-rects
161 | ::scroll-rects
162 | ::client-rects
163 | ::blended-background-colors
164 | ::text-color-opacities]))
165 |
166 | (s/def
167 | ::text-box-snapshot
168 | (s/keys
169 | :req-un
170 | [::layout-index
171 | ::bounds
172 | ::start
173 | ::length]))
174 | (defn
175 | disable
176 | "Disables DOM snapshot agent for the given page."
177 | ([]
178 | (disable
179 | (c/get-current-connection)
180 | {}))
181 | ([{:as params, :keys []}]
182 | (disable
183 | (c/get-current-connection)
184 | params))
185 | ([connection {:as params, :keys []}]
186 | (cmd/command
187 | connection
188 | "DOMSnapshot"
189 | "disable"
190 | params
191 | {})))
192 |
193 | (s/fdef
194 | disable
195 | :args
196 | (s/or
197 | :no-args
198 | (s/cat)
199 | :just-params
200 | (s/cat :params (s/keys))
201 | :connection-and-params
202 | (s/cat
203 | :connection
204 | (s/?
205 | c/connection?)
206 | :params
207 | (s/keys)))
208 | :ret
209 | (s/keys))
210 |
211 | (defn
212 | enable
213 | "Enables DOM snapshot agent for the given page."
214 | ([]
215 | (enable
216 | (c/get-current-connection)
217 | {}))
218 | ([{:as params, :keys []}]
219 | (enable
220 | (c/get-current-connection)
221 | params))
222 | ([connection {:as params, :keys []}]
223 | (cmd/command
224 | connection
225 | "DOMSnapshot"
226 | "enable"
227 | params
228 | {})))
229 |
230 | (s/fdef
231 | enable
232 | :args
233 | (s/or
234 | :no-args
235 | (s/cat)
236 | :just-params
237 | (s/cat :params (s/keys))
238 | :connection-and-params
239 | (s/cat
240 | :connection
241 | (s/?
242 | c/connection?)
243 | :params
244 | (s/keys)))
245 | :ret
246 | (s/keys))
247 |
248 | (defn
249 | get-snapshot
250 | "Returns a document snapshot, including the full DOM tree of the root node (including iframes,\ntemplate contents, and imported documents) in a flattened array, as well as layout and\nwhite-listed computed style information for the nodes. Shadow DOM in the returned DOM tree is\nflattened.\n\nParameters map keys:\n\n\n Key | Description \n --------------------------------|------------ \n :computed-style-whitelist | Whitelist of computed styles to return.\n :include-event-listeners | Whether or not to retrieve details of DOM listeners (default false). (optional)\n :include-paint-order | Whether to determine and include the paint order index of LayoutTreeNodes (default false). (optional)\n :include-user-agent-shadow-tree | Whether to include UA shadow tree in the snapshot (default false). (optional)\n\nReturn map keys:\n\n\n Key | Description \n -------------------|------------ \n :dom-nodes | The nodes in the DOM tree. The DOMNode at index 0 corresponds to the root document.\n :layout-tree-nodes | The nodes in the layout tree.\n :computed-styles | Whitelisted ComputedStyle properties for each node in the layout tree."
251 | ([]
252 | (get-snapshot
253 | (c/get-current-connection)
254 | {}))
255 | ([{:as params,
256 | :keys
257 | [computed-style-whitelist
258 | include-event-listeners
259 | include-paint-order
260 | include-user-agent-shadow-tree]}]
261 | (get-snapshot
262 | (c/get-current-connection)
263 | params))
264 | ([connection
265 | {:as params,
266 | :keys
267 | [computed-style-whitelist
268 | include-event-listeners
269 | include-paint-order
270 | include-user-agent-shadow-tree]}]
271 | (cmd/command
272 | connection
273 | "DOMSnapshot"
274 | "getSnapshot"
275 | params
276 | {:computed-style-whitelist "computedStyleWhitelist",
277 | :include-event-listeners "includeEventListeners",
278 | :include-paint-order "includePaintOrder",
279 | :include-user-agent-shadow-tree "includeUserAgentShadowTree"})))
280 |
281 | (s/fdef
282 | get-snapshot
283 | :args
284 | (s/or
285 | :no-args
286 | (s/cat)
287 | :just-params
288 | (s/cat
289 | :params
290 | (s/keys
291 | :req-un
292 | [::computed-style-whitelist]
293 | :opt-un
294 | [::include-event-listeners
295 | ::include-paint-order
296 | ::include-user-agent-shadow-tree]))
297 | :connection-and-params
298 | (s/cat
299 | :connection
300 | (s/?
301 | c/connection?)
302 | :params
303 | (s/keys
304 | :req-un
305 | [::computed-style-whitelist]
306 | :opt-un
307 | [::include-event-listeners
308 | ::include-paint-order
309 | ::include-user-agent-shadow-tree])))
310 | :ret
311 | (s/keys
312 | :req-un
313 | [::dom-nodes
314 | ::layout-tree-nodes
315 | ::computed-styles]))
316 |
317 | (defn
318 | capture-snapshot
319 | "Returns a document snapshot, including the full DOM tree of the root node (including iframes,\ntemplate contents, and imported documents) in a flattened array, as well as layout and\nwhite-listed computed style information for the nodes. Shadow DOM in the returned DOM tree is\nflattened.\n\nParameters map keys:\n\n\n Key | Description \n -----------------------------------|------------ \n :computed-styles | Whitelist of computed styles to return.\n :include-paint-order | Whether to include layout object paint orders into the snapshot. (optional)\n :include-dom-rects | Whether to include DOM rectangles (offsetRects, clientRects, scrollRects) into the snapshot (optional)\n :include-blended-background-colors | Whether to include blended background colors in the snapshot (default: false).\nBlended background color is achieved by blending background colors of all elements\nthat overlap with the current element. (optional)\n :include-text-color-opacities | Whether to include text color opacity in the snapshot (default: false).\nAn element might have the opacity property set that affects the text color of the element.\nThe final text color opacity is computed based on the opacity of all overlapping elements. (optional)\n\nReturn map keys:\n\n\n Key | Description \n -----------|------------ \n :documents | The nodes in the DOM tree. The DOMNode at index 0 corresponds to the root document.\n :strings | Shared string table that all string properties refer to with indexes."
320 | ([]
321 | (capture-snapshot
322 | (c/get-current-connection)
323 | {}))
324 | ([{:as params,
325 | :keys
326 | [computed-styles
327 | include-paint-order
328 | include-dom-rects
329 | include-blended-background-colors
330 | include-text-color-opacities]}]
331 | (capture-snapshot
332 | (c/get-current-connection)
333 | params))
334 | ([connection
335 | {:as params,
336 | :keys
337 | [computed-styles
338 | include-paint-order
339 | include-dom-rects
340 | include-blended-background-colors
341 | include-text-color-opacities]}]
342 | (cmd/command
343 | connection
344 | "DOMSnapshot"
345 | "captureSnapshot"
346 | params
347 | {:computed-styles "computedStyles",
348 | :include-paint-order "includePaintOrder",
349 | :include-dom-rects "includeDOMRects",
350 | :include-blended-background-colors
351 | "includeBlendedBackgroundColors",
352 | :include-text-color-opacities "includeTextColorOpacities"})))
353 |
354 | (s/fdef
355 | capture-snapshot
356 | :args
357 | (s/or
358 | :no-args
359 | (s/cat)
360 | :just-params
361 | (s/cat
362 | :params
363 | (s/keys
364 | :req-un
365 | [::computed-styles]
366 | :opt-un
367 | [::include-paint-order
368 | ::include-dom-rects
369 | ::include-blended-background-colors
370 | ::include-text-color-opacities]))
371 | :connection-and-params
372 | (s/cat
373 | :connection
374 | (s/?
375 | c/connection?)
376 | :params
377 | (s/keys
378 | :req-un
379 | [::computed-styles]
380 | :opt-un
381 | [::include-paint-order
382 | ::include-dom-rects
383 | ::include-blended-background-colors
384 | ::include-text-color-opacities])))
385 | :ret
386 | (s/keys
387 | :req-un
388 | [::documents
389 | ::strings]))
390 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/dom_storage.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.dom-storage
2 | "Query and modify DOM storage."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::storage-id
9 | (s/keys
10 | :req-un
11 | [::security-origin
12 | ::is-local-storage]))
13 |
14 | (s/def
15 | ::item
16 | (s/coll-of string?))
17 | (defn
18 | clear
19 | "\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :storage-id | null"
20 | ([]
21 | (clear
22 | (c/get-current-connection)
23 | {}))
24 | ([{:as params, :keys [storage-id]}]
25 | (clear
26 | (c/get-current-connection)
27 | params))
28 | ([connection {:as params, :keys [storage-id]}]
29 | (cmd/command
30 | connection
31 | "DOMStorage"
32 | "clear"
33 | params
34 | {:storage-id "storageId"})))
35 |
36 | (s/fdef
37 | clear
38 | :args
39 | (s/or
40 | :no-args
41 | (s/cat)
42 | :just-params
43 | (s/cat
44 | :params
45 | (s/keys
46 | :req-un
47 | [::storage-id]))
48 | :connection-and-params
49 | (s/cat
50 | :connection
51 | (s/?
52 | c/connection?)
53 | :params
54 | (s/keys
55 | :req-un
56 | [::storage-id])))
57 | :ret
58 | (s/keys))
59 |
60 | (defn
61 | disable
62 | "Disables storage tracking, prevents storage events from being sent to the client."
63 | ([]
64 | (disable
65 | (c/get-current-connection)
66 | {}))
67 | ([{:as params, :keys []}]
68 | (disable
69 | (c/get-current-connection)
70 | params))
71 | ([connection {:as params, :keys []}]
72 | (cmd/command
73 | connection
74 | "DOMStorage"
75 | "disable"
76 | params
77 | {})))
78 |
79 | (s/fdef
80 | disable
81 | :args
82 | (s/or
83 | :no-args
84 | (s/cat)
85 | :just-params
86 | (s/cat :params (s/keys))
87 | :connection-and-params
88 | (s/cat
89 | :connection
90 | (s/?
91 | c/connection?)
92 | :params
93 | (s/keys)))
94 | :ret
95 | (s/keys))
96 |
97 | (defn
98 | enable
99 | "Enables storage tracking, storage events will now be delivered to the client."
100 | ([]
101 | (enable
102 | (c/get-current-connection)
103 | {}))
104 | ([{:as params, :keys []}]
105 | (enable
106 | (c/get-current-connection)
107 | params))
108 | ([connection {:as params, :keys []}]
109 | (cmd/command
110 | connection
111 | "DOMStorage"
112 | "enable"
113 | params
114 | {})))
115 |
116 | (s/fdef
117 | enable
118 | :args
119 | (s/or
120 | :no-args
121 | (s/cat)
122 | :just-params
123 | (s/cat :params (s/keys))
124 | :connection-and-params
125 | (s/cat
126 | :connection
127 | (s/?
128 | c/connection?)
129 | :params
130 | (s/keys)))
131 | :ret
132 | (s/keys))
133 |
134 | (defn
135 | get-dom-storage-items
136 | "\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :storage-id | null\n\nReturn map keys:\n\n\n Key | Description \n ---------|------------ \n :entries | null"
137 | ([]
138 | (get-dom-storage-items
139 | (c/get-current-connection)
140 | {}))
141 | ([{:as params, :keys [storage-id]}]
142 | (get-dom-storage-items
143 | (c/get-current-connection)
144 | params))
145 | ([connection {:as params, :keys [storage-id]}]
146 | (cmd/command
147 | connection
148 | "DOMStorage"
149 | "getDOMStorageItems"
150 | params
151 | {:storage-id "storageId"})))
152 |
153 | (s/fdef
154 | get-dom-storage-items
155 | :args
156 | (s/or
157 | :no-args
158 | (s/cat)
159 | :just-params
160 | (s/cat
161 | :params
162 | (s/keys
163 | :req-un
164 | [::storage-id]))
165 | :connection-and-params
166 | (s/cat
167 | :connection
168 | (s/?
169 | c/connection?)
170 | :params
171 | (s/keys
172 | :req-un
173 | [::storage-id])))
174 | :ret
175 | (s/keys
176 | :req-un
177 | [::entries]))
178 |
179 | (defn
180 | remove-dom-storage-item
181 | "\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :storage-id | null\n :key | null"
182 | ([]
183 | (remove-dom-storage-item
184 | (c/get-current-connection)
185 | {}))
186 | ([{:as params, :keys [storage-id key]}]
187 | (remove-dom-storage-item
188 | (c/get-current-connection)
189 | params))
190 | ([connection {:as params, :keys [storage-id key]}]
191 | (cmd/command
192 | connection
193 | "DOMStorage"
194 | "removeDOMStorageItem"
195 | params
196 | {:storage-id "storageId", :key "key"})))
197 |
198 | (s/fdef
199 | remove-dom-storage-item
200 | :args
201 | (s/or
202 | :no-args
203 | (s/cat)
204 | :just-params
205 | (s/cat
206 | :params
207 | (s/keys
208 | :req-un
209 | [::storage-id
210 | ::key]))
211 | :connection-and-params
212 | (s/cat
213 | :connection
214 | (s/?
215 | c/connection?)
216 | :params
217 | (s/keys
218 | :req-un
219 | [::storage-id
220 | ::key])))
221 | :ret
222 | (s/keys))
223 |
224 | (defn
225 | set-dom-storage-item
226 | "\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :storage-id | null\n :key | null\n :value | null"
227 | ([]
228 | (set-dom-storage-item
229 | (c/get-current-connection)
230 | {}))
231 | ([{:as params, :keys [storage-id key value]}]
232 | (set-dom-storage-item
233 | (c/get-current-connection)
234 | params))
235 | ([connection {:as params, :keys [storage-id key value]}]
236 | (cmd/command
237 | connection
238 | "DOMStorage"
239 | "setDOMStorageItem"
240 | params
241 | {:storage-id "storageId", :key "key", :value "value"})))
242 |
243 | (s/fdef
244 | set-dom-storage-item
245 | :args
246 | (s/or
247 | :no-args
248 | (s/cat)
249 | :just-params
250 | (s/cat
251 | :params
252 | (s/keys
253 | :req-un
254 | [::storage-id
255 | ::key
256 | ::value]))
257 | :connection-and-params
258 | (s/cat
259 | :connection
260 | (s/?
261 | c/connection?)
262 | :params
263 | (s/keys
264 | :req-un
265 | [::storage-id
266 | ::key
267 | ::value])))
268 | :ret
269 | (s/keys))
270 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/event_breakpoints.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.event-breakpoints
2 | "EventBreakpoints permits setting breakpoints on particular operations and\nevents in targets that run JavaScript but do not have a DOM.\nJavaScript execution will stop on these operations as if there was a regular\nbreakpoint set."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (defn
8 | set-instrumentation-breakpoint
9 | "Sets breakpoint on particular native event.\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :event-name | Instrumentation name to stop on."
10 | ([]
11 | (set-instrumentation-breakpoint
12 | (c/get-current-connection)
13 | {}))
14 | ([{:as params, :keys [event-name]}]
15 | (set-instrumentation-breakpoint
16 | (c/get-current-connection)
17 | params))
18 | ([connection {:as params, :keys [event-name]}]
19 | (cmd/command
20 | connection
21 | "EventBreakpoints"
22 | "setInstrumentationBreakpoint"
23 | params
24 | {:event-name "eventName"})))
25 |
26 | (s/fdef
27 | set-instrumentation-breakpoint
28 | :args
29 | (s/or
30 | :no-args
31 | (s/cat)
32 | :just-params
33 | (s/cat
34 | :params
35 | (s/keys
36 | :req-un
37 | [::event-name]))
38 | :connection-and-params
39 | (s/cat
40 | :connection
41 | (s/?
42 | c/connection?)
43 | :params
44 | (s/keys
45 | :req-un
46 | [::event-name])))
47 | :ret
48 | (s/keys))
49 |
50 | (defn
51 | remove-instrumentation-breakpoint
52 | "Removes breakpoint on particular native event.\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :event-name | Instrumentation name to stop on."
53 | ([]
54 | (remove-instrumentation-breakpoint
55 | (c/get-current-connection)
56 | {}))
57 | ([{:as params, :keys [event-name]}]
58 | (remove-instrumentation-breakpoint
59 | (c/get-current-connection)
60 | params))
61 | ([connection {:as params, :keys [event-name]}]
62 | (cmd/command
63 | connection
64 | "EventBreakpoints"
65 | "removeInstrumentationBreakpoint"
66 | params
67 | {:event-name "eventName"})))
68 |
69 | (s/fdef
70 | remove-instrumentation-breakpoint
71 | :args
72 | (s/or
73 | :no-args
74 | (s/cat)
75 | :just-params
76 | (s/cat
77 | :params
78 | (s/keys
79 | :req-un
80 | [::event-name]))
81 | :connection-and-params
82 | (s/cat
83 | :connection
84 | (s/?
85 | c/connection?)
86 | :params
87 | (s/keys
88 | :req-un
89 | [::event-name])))
90 | :ret
91 | (s/keys))
92 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/headless_experimental.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.headless-experimental
2 | "This domain provides experimental commands only supported in headless mode."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::screenshot-params
9 | (s/keys
10 | :opt-un
11 | [::format
12 | ::quality]))
13 | (defn
14 | begin-frame
15 | "Sends a BeginFrame to the target and returns when the frame was completed. Optionally captures a\nscreenshot from the resulting frame. Requires that the target was created with enabled\nBeginFrameControl. Designed for use with --run-all-compositor-stages-before-draw, see also\nhttps://goo.gl/3zHXhB for more background.\n\nParameters map keys:\n\n\n Key | Description \n --------------------|------------ \n :frame-time-ticks | Timestamp of this BeginFrame in Renderer TimeTicks (milliseconds of uptime). If not set,\nthe current time will be used. (optional)\n :interval | The interval between BeginFrames that is reported to the compositor, in milliseconds.\nDefaults to a 60 frames/second interval, i.e. about 16.666 milliseconds. (optional)\n :no-display-updates | Whether updates should not be committed and drawn onto the display. False by default. If\ntrue, only side effects of the BeginFrame will be run, such as layout and animations, but\nany visual updates may not be visible on the display or in screenshots. (optional)\n :screenshot | If set, a screenshot of the frame will be captured and returned in the response. Otherwise,\nno screenshot will be captured. Note that capturing a screenshot can fail, for example,\nduring renderer initialization. In such a case, no screenshot data will be returned. (optional)\n\nReturn map keys:\n\n\n Key | Description \n -----------------|------------ \n :has-damage | Whether the BeginFrame resulted in damage and, thus, a new frame was committed to the\ndisplay. Reported for diagnostic uses, may be removed in the future.\n :screenshot-data | Base64-encoded image data of the screenshot, if one was requested and successfully taken. (Encoded as a base64 string when passed over JSON) (optional)"
16 | ([]
17 | (begin-frame
18 | (c/get-current-connection)
19 | {}))
20 | ([{:as params,
21 | :keys [frame-time-ticks interval no-display-updates screenshot]}]
22 | (begin-frame
23 | (c/get-current-connection)
24 | params))
25 | ([connection
26 | {:as params,
27 | :keys [frame-time-ticks interval no-display-updates screenshot]}]
28 | (cmd/command
29 | connection
30 | "HeadlessExperimental"
31 | "beginFrame"
32 | params
33 | {:frame-time-ticks "frameTimeTicks",
34 | :interval "interval",
35 | :no-display-updates "noDisplayUpdates",
36 | :screenshot "screenshot"})))
37 |
38 | (s/fdef
39 | begin-frame
40 | :args
41 | (s/or
42 | :no-args
43 | (s/cat)
44 | :just-params
45 | (s/cat
46 | :params
47 | (s/keys
48 | :opt-un
49 | [::frame-time-ticks
50 | ::interval
51 | ::no-display-updates
52 | ::screenshot]))
53 | :connection-and-params
54 | (s/cat
55 | :connection
56 | (s/?
57 | c/connection?)
58 | :params
59 | (s/keys
60 | :opt-un
61 | [::frame-time-ticks
62 | ::interval
63 | ::no-display-updates
64 | ::screenshot])))
65 | :ret
66 | (s/keys
67 | :req-un
68 | [::has-damage]
69 | :opt-un
70 | [::screenshot-data]))
71 |
72 | (defn
73 | disable
74 | "Disables headless events for the target."
75 | ([]
76 | (disable
77 | (c/get-current-connection)
78 | {}))
79 | ([{:as params, :keys []}]
80 | (disable
81 | (c/get-current-connection)
82 | params))
83 | ([connection {:as params, :keys []}]
84 | (cmd/command
85 | connection
86 | "HeadlessExperimental"
87 | "disable"
88 | params
89 | {})))
90 |
91 | (s/fdef
92 | disable
93 | :args
94 | (s/or
95 | :no-args
96 | (s/cat)
97 | :just-params
98 | (s/cat :params (s/keys))
99 | :connection-and-params
100 | (s/cat
101 | :connection
102 | (s/?
103 | c/connection?)
104 | :params
105 | (s/keys)))
106 | :ret
107 | (s/keys))
108 |
109 | (defn
110 | enable
111 | "Enables headless events for the target."
112 | ([]
113 | (enable
114 | (c/get-current-connection)
115 | {}))
116 | ([{:as params, :keys []}]
117 | (enable
118 | (c/get-current-connection)
119 | params))
120 | ([connection {:as params, :keys []}]
121 | (cmd/command
122 | connection
123 | "HeadlessExperimental"
124 | "enable"
125 | params
126 | {})))
127 |
128 | (s/fdef
129 | enable
130 | :args
131 | (s/or
132 | :no-args
133 | (s/cat)
134 | :just-params
135 | (s/cat :params (s/keys))
136 | :connection-and-params
137 | (s/cat
138 | :connection
139 | (s/?
140 | c/connection?)
141 | :params
142 | (s/keys)))
143 | :ret
144 | (s/keys))
145 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/inspector.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.inspector
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (defn
7 | disable
8 | "Disables inspector domain notifications."
9 | ([]
10 | (disable
11 | (c/get-current-connection)
12 | {}))
13 | ([{:as params, :keys []}]
14 | (disable
15 | (c/get-current-connection)
16 | params))
17 | ([connection {:as params, :keys []}]
18 | (cmd/command
19 | connection
20 | "Inspector"
21 | "disable"
22 | params
23 | {})))
24 |
25 | (s/fdef
26 | disable
27 | :args
28 | (s/or
29 | :no-args
30 | (s/cat)
31 | :just-params
32 | (s/cat :params (s/keys))
33 | :connection-and-params
34 | (s/cat
35 | :connection
36 | (s/?
37 | c/connection?)
38 | :params
39 | (s/keys)))
40 | :ret
41 | (s/keys))
42 |
43 | (defn
44 | enable
45 | "Enables inspector domain notifications."
46 | ([]
47 | (enable
48 | (c/get-current-connection)
49 | {}))
50 | ([{:as params, :keys []}]
51 | (enable
52 | (c/get-current-connection)
53 | params))
54 | ([connection {:as params, :keys []}]
55 | (cmd/command
56 | connection
57 | "Inspector"
58 | "enable"
59 | params
60 | {})))
61 |
62 | (s/fdef
63 | enable
64 | :args
65 | (s/or
66 | :no-args
67 | (s/cat)
68 | :just-params
69 | (s/cat :params (s/keys))
70 | :connection-and-params
71 | (s/cat
72 | :connection
73 | (s/?
74 | c/connection?)
75 | :params
76 | (s/keys)))
77 | :ret
78 | (s/keys))
79 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/io.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.io
2 | "Input/Output operations for streams produced by DevTools."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::stream-handle
9 | string?)
10 | (defn
11 | close
12 | "Close the stream, discard any temporary backing storage.\n\nParameters map keys:\n\n\n Key | Description \n --------|------------ \n :handle | Handle of the stream to close."
13 | ([]
14 | (close
15 | (c/get-current-connection)
16 | {}))
17 | ([{:as params, :keys [handle]}]
18 | (close
19 | (c/get-current-connection)
20 | params))
21 | ([connection {:as params, :keys [handle]}]
22 | (cmd/command
23 | connection
24 | "IO"
25 | "close"
26 | params
27 | {:handle "handle"})))
28 |
29 | (s/fdef
30 | close
31 | :args
32 | (s/or
33 | :no-args
34 | (s/cat)
35 | :just-params
36 | (s/cat
37 | :params
38 | (s/keys
39 | :req-un
40 | [::handle]))
41 | :connection-and-params
42 | (s/cat
43 | :connection
44 | (s/?
45 | c/connection?)
46 | :params
47 | (s/keys
48 | :req-un
49 | [::handle])))
50 | :ret
51 | (s/keys))
52 |
53 | (defn
54 | read
55 | "Read a chunk of the stream\n\nParameters map keys:\n\n\n Key | Description \n --------|------------ \n :handle | Handle of the stream to read.\n :offset | Seek to the specified offset before reading (if not specificed, proceed with offset\nfollowing the last read). Some types of streams may only support sequential reads. (optional)\n :size | Maximum number of bytes to read (left upon the agent discretion if not specified). (optional)\n\nReturn map keys:\n\n\n Key | Description \n ----------------|------------ \n :base64-encoded | Set if the data is base64-encoded (optional)\n :data | Data that were read.\n :eof | Set if the end-of-file condition occurred while reading."
56 | ([]
57 | (read
58 | (c/get-current-connection)
59 | {}))
60 | ([{:as params, :keys [handle offset size]}]
61 | (read
62 | (c/get-current-connection)
63 | params))
64 | ([connection {:as params, :keys [handle offset size]}]
65 | (cmd/command
66 | connection
67 | "IO"
68 | "read"
69 | params
70 | {:handle "handle", :offset "offset", :size "size"})))
71 |
72 | (s/fdef
73 | read
74 | :args
75 | (s/or
76 | :no-args
77 | (s/cat)
78 | :just-params
79 | (s/cat
80 | :params
81 | (s/keys
82 | :req-un
83 | [::handle]
84 | :opt-un
85 | [::offset
86 | ::size]))
87 | :connection-and-params
88 | (s/cat
89 | :connection
90 | (s/?
91 | c/connection?)
92 | :params
93 | (s/keys
94 | :req-un
95 | [::handle]
96 | :opt-un
97 | [::offset
98 | ::size])))
99 | :ret
100 | (s/keys
101 | :req-un
102 | [::data
103 | ::eof]
104 | :opt-un
105 | [::base64-encoded]))
106 |
107 | (defn
108 | resolve-blob
109 | "Return UUID of Blob object specified by a remote object id.\n\nParameters map keys:\n\n\n Key | Description \n -----------|------------ \n :object-id | Object id of a Blob object wrapper.\n\nReturn map keys:\n\n\n Key | Description \n ------|------------ \n :uuid | UUID of the specified Blob."
110 | ([]
111 | (resolve-blob
112 | (c/get-current-connection)
113 | {}))
114 | ([{:as params, :keys [object-id]}]
115 | (resolve-blob
116 | (c/get-current-connection)
117 | params))
118 | ([connection {:as params, :keys [object-id]}]
119 | (cmd/command
120 | connection
121 | "IO"
122 | "resolveBlob"
123 | params
124 | {:object-id "objectId"})))
125 |
126 | (s/fdef
127 | resolve-blob
128 | :args
129 | (s/or
130 | :no-args
131 | (s/cat)
132 | :just-params
133 | (s/cat
134 | :params
135 | (s/keys
136 | :req-un
137 | [::object-id]))
138 | :connection-and-params
139 | (s/cat
140 | :connection
141 | (s/?
142 | c/connection?)
143 | :params
144 | (s/keys
145 | :req-un
146 | [::object-id])))
147 | :ret
148 | (s/keys
149 | :req-un
150 | [::uuid]))
151 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/log.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.log
2 | "Provides access to log entries."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::log-entry
9 | (s/keys
10 | :req-un
11 | [::source
12 | ::level
13 | ::text
14 | ::timestamp]
15 | :opt-un
16 | [::category
17 | ::url
18 | ::line-number
19 | ::stack-trace
20 | ::network-request-id
21 | ::worker-id
22 | ::args]))
23 |
24 | (s/def
25 | ::violation-setting
26 | (s/keys
27 | :req-un
28 | [::name
29 | ::threshold]))
30 | (defn
31 | clear
32 | "Clears the log."
33 | ([]
34 | (clear
35 | (c/get-current-connection)
36 | {}))
37 | ([{:as params, :keys []}]
38 | (clear
39 | (c/get-current-connection)
40 | params))
41 | ([connection {:as params, :keys []}]
42 | (cmd/command
43 | connection
44 | "Log"
45 | "clear"
46 | params
47 | {})))
48 |
49 | (s/fdef
50 | clear
51 | :args
52 | (s/or
53 | :no-args
54 | (s/cat)
55 | :just-params
56 | (s/cat :params (s/keys))
57 | :connection-and-params
58 | (s/cat
59 | :connection
60 | (s/?
61 | c/connection?)
62 | :params
63 | (s/keys)))
64 | :ret
65 | (s/keys))
66 |
67 | (defn
68 | disable
69 | "Disables log domain, prevents further log entries from being reported to the client."
70 | ([]
71 | (disable
72 | (c/get-current-connection)
73 | {}))
74 | ([{:as params, :keys []}]
75 | (disable
76 | (c/get-current-connection)
77 | params))
78 | ([connection {:as params, :keys []}]
79 | (cmd/command
80 | connection
81 | "Log"
82 | "disable"
83 | params
84 | {})))
85 |
86 | (s/fdef
87 | disable
88 | :args
89 | (s/or
90 | :no-args
91 | (s/cat)
92 | :just-params
93 | (s/cat :params (s/keys))
94 | :connection-and-params
95 | (s/cat
96 | :connection
97 | (s/?
98 | c/connection?)
99 | :params
100 | (s/keys)))
101 | :ret
102 | (s/keys))
103 |
104 | (defn
105 | enable
106 | "Enables log domain, sends the entries collected so far to the client by means of the\n`entryAdded` notification."
107 | ([]
108 | (enable
109 | (c/get-current-connection)
110 | {}))
111 | ([{:as params, :keys []}]
112 | (enable
113 | (c/get-current-connection)
114 | params))
115 | ([connection {:as params, :keys []}]
116 | (cmd/command
117 | connection
118 | "Log"
119 | "enable"
120 | params
121 | {})))
122 |
123 | (s/fdef
124 | enable
125 | :args
126 | (s/or
127 | :no-args
128 | (s/cat)
129 | :just-params
130 | (s/cat :params (s/keys))
131 | :connection-and-params
132 | (s/cat
133 | :connection
134 | (s/?
135 | c/connection?)
136 | :params
137 | (s/keys)))
138 | :ret
139 | (s/keys))
140 |
141 | (defn
142 | start-violations-report
143 | "start violation reporting.\n\nParameters map keys:\n\n\n Key | Description \n --------|------------ \n :config | Configuration for violations."
144 | ([]
145 | (start-violations-report
146 | (c/get-current-connection)
147 | {}))
148 | ([{:as params, :keys [config]}]
149 | (start-violations-report
150 | (c/get-current-connection)
151 | params))
152 | ([connection {:as params, :keys [config]}]
153 | (cmd/command
154 | connection
155 | "Log"
156 | "startViolationsReport"
157 | params
158 | {:config "config"})))
159 |
160 | (s/fdef
161 | start-violations-report
162 | :args
163 | (s/or
164 | :no-args
165 | (s/cat)
166 | :just-params
167 | (s/cat
168 | :params
169 | (s/keys
170 | :req-un
171 | [::config]))
172 | :connection-and-params
173 | (s/cat
174 | :connection
175 | (s/?
176 | c/connection?)
177 | :params
178 | (s/keys
179 | :req-un
180 | [::config])))
181 | :ret
182 | (s/keys))
183 |
184 | (defn
185 | stop-violations-report
186 | "Stop violation reporting."
187 | ([]
188 | (stop-violations-report
189 | (c/get-current-connection)
190 | {}))
191 | ([{:as params, :keys []}]
192 | (stop-violations-report
193 | (c/get-current-connection)
194 | params))
195 | ([connection {:as params, :keys []}]
196 | (cmd/command
197 | connection
198 | "Log"
199 | "stopViolationsReport"
200 | params
201 | {})))
202 |
203 | (s/fdef
204 | stop-violations-report
205 | :args
206 | (s/or
207 | :no-args
208 | (s/cat)
209 | :just-params
210 | (s/cat :params (s/keys))
211 | :connection-and-params
212 | (s/cat
213 | :connection
214 | (s/?
215 | c/connection?)
216 | :params
217 | (s/keys)))
218 | :ret
219 | (s/keys))
220 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/media.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.media
2 | "This domain allows detailed inspection of media elements"
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::player-id
9 | string?)
10 |
11 | (s/def
12 | ::timestamp
13 | number?)
14 |
15 | (s/def
16 | ::player-message
17 | (s/keys
18 | :req-un
19 | [::level
20 | ::message]))
21 |
22 | (s/def
23 | ::player-property
24 | (s/keys
25 | :req-un
26 | [::name
27 | ::value]))
28 |
29 | (s/def
30 | ::player-event
31 | (s/keys
32 | :req-un
33 | [::timestamp
34 | ::value]))
35 |
36 | (s/def
37 | ::player-error
38 | (s/keys
39 | :req-un
40 | [::type
41 | ::error-code]))
42 | (defn
43 | enable
44 | "Enables the Media domain"
45 | ([]
46 | (enable
47 | (c/get-current-connection)
48 | {}))
49 | ([{:as params, :keys []}]
50 | (enable
51 | (c/get-current-connection)
52 | params))
53 | ([connection {:as params, :keys []}]
54 | (cmd/command
55 | connection
56 | "Media"
57 | "enable"
58 | params
59 | {})))
60 |
61 | (s/fdef
62 | enable
63 | :args
64 | (s/or
65 | :no-args
66 | (s/cat)
67 | :just-params
68 | (s/cat :params (s/keys))
69 | :connection-and-params
70 | (s/cat
71 | :connection
72 | (s/?
73 | c/connection?)
74 | :params
75 | (s/keys)))
76 | :ret
77 | (s/keys))
78 |
79 | (defn
80 | disable
81 | "Disables the Media domain."
82 | ([]
83 | (disable
84 | (c/get-current-connection)
85 | {}))
86 | ([{:as params, :keys []}]
87 | (disable
88 | (c/get-current-connection)
89 | params))
90 | ([connection {:as params, :keys []}]
91 | (cmd/command
92 | connection
93 | "Media"
94 | "disable"
95 | params
96 | {})))
97 |
98 | (s/fdef
99 | disable
100 | :args
101 | (s/or
102 | :no-args
103 | (s/cat)
104 | :just-params
105 | (s/cat :params (s/keys))
106 | :connection-and-params
107 | (s/cat
108 | :connection
109 | (s/?
110 | c/connection?)
111 | :params
112 | (s/keys)))
113 | :ret
114 | (s/keys))
115 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/memory.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.memory
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (s/def
7 | ::pressure-level
8 | #{"critical" "moderate"})
9 |
10 | (s/def
11 | ::sampling-profile-node
12 | (s/keys
13 | :req-un
14 | [::size
15 | ::total
16 | ::stack]))
17 |
18 | (s/def
19 | ::sampling-profile
20 | (s/keys
21 | :req-un
22 | [::samples
23 | ::modules]))
24 |
25 | (s/def
26 | ::module
27 | (s/keys
28 | :req-un
29 | [::name
30 | ::uuid
31 | ::base-address
32 | ::size]))
33 | (defn
34 | get-dom-counters
35 | "\n\nReturn map keys:\n\n\n Key | Description \n --------------------|------------ \n :documents | null\n :nodes | null\n :js-event-listeners | null"
36 | ([]
37 | (get-dom-counters
38 | (c/get-current-connection)
39 | {}))
40 | ([{:as params, :keys []}]
41 | (get-dom-counters
42 | (c/get-current-connection)
43 | params))
44 | ([connection {:as params, :keys []}]
45 | (cmd/command
46 | connection
47 | "Memory"
48 | "getDOMCounters"
49 | params
50 | {})))
51 |
52 | (s/fdef
53 | get-dom-counters
54 | :args
55 | (s/or
56 | :no-args
57 | (s/cat)
58 | :just-params
59 | (s/cat :params (s/keys))
60 | :connection-and-params
61 | (s/cat
62 | :connection
63 | (s/?
64 | c/connection?)
65 | :params
66 | (s/keys)))
67 | :ret
68 | (s/keys
69 | :req-un
70 | [::documents
71 | ::nodes
72 | ::js-event-listeners]))
73 |
74 | (defn
75 | prepare-for-leak-detection
76 | ""
77 | ([]
78 | (prepare-for-leak-detection
79 | (c/get-current-connection)
80 | {}))
81 | ([{:as params, :keys []}]
82 | (prepare-for-leak-detection
83 | (c/get-current-connection)
84 | params))
85 | ([connection {:as params, :keys []}]
86 | (cmd/command
87 | connection
88 | "Memory"
89 | "prepareForLeakDetection"
90 | params
91 | {})))
92 |
93 | (s/fdef
94 | prepare-for-leak-detection
95 | :args
96 | (s/or
97 | :no-args
98 | (s/cat)
99 | :just-params
100 | (s/cat :params (s/keys))
101 | :connection-and-params
102 | (s/cat
103 | :connection
104 | (s/?
105 | c/connection?)
106 | :params
107 | (s/keys)))
108 | :ret
109 | (s/keys))
110 |
111 | (defn
112 | forcibly-purge-java-script-memory
113 | "Simulate OomIntervention by purging V8 memory."
114 | ([]
115 | (forcibly-purge-java-script-memory
116 | (c/get-current-connection)
117 | {}))
118 | ([{:as params, :keys []}]
119 | (forcibly-purge-java-script-memory
120 | (c/get-current-connection)
121 | params))
122 | ([connection {:as params, :keys []}]
123 | (cmd/command
124 | connection
125 | "Memory"
126 | "forciblyPurgeJavaScriptMemory"
127 | params
128 | {})))
129 |
130 | (s/fdef
131 | forcibly-purge-java-script-memory
132 | :args
133 | (s/or
134 | :no-args
135 | (s/cat)
136 | :just-params
137 | (s/cat :params (s/keys))
138 | :connection-and-params
139 | (s/cat
140 | :connection
141 | (s/?
142 | c/connection?)
143 | :params
144 | (s/keys)))
145 | :ret
146 | (s/keys))
147 |
148 | (defn
149 | set-pressure-notifications-suppressed
150 | "Enable/disable suppressing memory pressure notifications in all processes.\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :suppressed | If true, memory pressure notifications will be suppressed."
151 | ([]
152 | (set-pressure-notifications-suppressed
153 | (c/get-current-connection)
154 | {}))
155 | ([{:as params, :keys [suppressed]}]
156 | (set-pressure-notifications-suppressed
157 | (c/get-current-connection)
158 | params))
159 | ([connection {:as params, :keys [suppressed]}]
160 | (cmd/command
161 | connection
162 | "Memory"
163 | "setPressureNotificationsSuppressed"
164 | params
165 | {:suppressed "suppressed"})))
166 |
167 | (s/fdef
168 | set-pressure-notifications-suppressed
169 | :args
170 | (s/or
171 | :no-args
172 | (s/cat)
173 | :just-params
174 | (s/cat
175 | :params
176 | (s/keys
177 | :req-un
178 | [::suppressed]))
179 | :connection-and-params
180 | (s/cat
181 | :connection
182 | (s/?
183 | c/connection?)
184 | :params
185 | (s/keys
186 | :req-un
187 | [::suppressed])))
188 | :ret
189 | (s/keys))
190 |
191 | (defn
192 | simulate-pressure-notification
193 | "Simulate a memory pressure notification in all processes.\n\nParameters map keys:\n\n\n Key | Description \n -------|------------ \n :level | Memory pressure level of the notification."
194 | ([]
195 | (simulate-pressure-notification
196 | (c/get-current-connection)
197 | {}))
198 | ([{:as params, :keys [level]}]
199 | (simulate-pressure-notification
200 | (c/get-current-connection)
201 | params))
202 | ([connection {:as params, :keys [level]}]
203 | (cmd/command
204 | connection
205 | "Memory"
206 | "simulatePressureNotification"
207 | params
208 | {:level "level"})))
209 |
210 | (s/fdef
211 | simulate-pressure-notification
212 | :args
213 | (s/or
214 | :no-args
215 | (s/cat)
216 | :just-params
217 | (s/cat
218 | :params
219 | (s/keys
220 | :req-un
221 | [::level]))
222 | :connection-and-params
223 | (s/cat
224 | :connection
225 | (s/?
226 | c/connection?)
227 | :params
228 | (s/keys
229 | :req-un
230 | [::level])))
231 | :ret
232 | (s/keys))
233 |
234 | (defn
235 | start-sampling
236 | "Start collecting native memory profile.\n\nParameters map keys:\n\n\n Key | Description \n ---------------------|------------ \n :sampling-interval | Average number of bytes between samples. (optional)\n :suppress-randomness | Do not randomize intervals between samples. (optional)"
237 | ([]
238 | (start-sampling
239 | (c/get-current-connection)
240 | {}))
241 | ([{:as params, :keys [sampling-interval suppress-randomness]}]
242 | (start-sampling
243 | (c/get-current-connection)
244 | params))
245 | ([connection
246 | {:as params, :keys [sampling-interval suppress-randomness]}]
247 | (cmd/command
248 | connection
249 | "Memory"
250 | "startSampling"
251 | params
252 | {:sampling-interval "samplingInterval",
253 | :suppress-randomness "suppressRandomness"})))
254 |
255 | (s/fdef
256 | start-sampling
257 | :args
258 | (s/or
259 | :no-args
260 | (s/cat)
261 | :just-params
262 | (s/cat
263 | :params
264 | (s/keys
265 | :opt-un
266 | [::sampling-interval
267 | ::suppress-randomness]))
268 | :connection-and-params
269 | (s/cat
270 | :connection
271 | (s/?
272 | c/connection?)
273 | :params
274 | (s/keys
275 | :opt-un
276 | [::sampling-interval
277 | ::suppress-randomness])))
278 | :ret
279 | (s/keys))
280 |
281 | (defn
282 | stop-sampling
283 | "Stop collecting native memory profile."
284 | ([]
285 | (stop-sampling
286 | (c/get-current-connection)
287 | {}))
288 | ([{:as params, :keys []}]
289 | (stop-sampling
290 | (c/get-current-connection)
291 | params))
292 | ([connection {:as params, :keys []}]
293 | (cmd/command
294 | connection
295 | "Memory"
296 | "stopSampling"
297 | params
298 | {})))
299 |
300 | (s/fdef
301 | stop-sampling
302 | :args
303 | (s/or
304 | :no-args
305 | (s/cat)
306 | :just-params
307 | (s/cat :params (s/keys))
308 | :connection-and-params
309 | (s/cat
310 | :connection
311 | (s/?
312 | c/connection?)
313 | :params
314 | (s/keys)))
315 | :ret
316 | (s/keys))
317 |
318 | (defn
319 | get-all-time-sampling-profile
320 | "Retrieve native memory allocations profile\ncollected since renderer process startup.\n\nReturn map keys:\n\n\n Key | Description \n ---------|------------ \n :profile | null"
321 | ([]
322 | (get-all-time-sampling-profile
323 | (c/get-current-connection)
324 | {}))
325 | ([{:as params, :keys []}]
326 | (get-all-time-sampling-profile
327 | (c/get-current-connection)
328 | params))
329 | ([connection {:as params, :keys []}]
330 | (cmd/command
331 | connection
332 | "Memory"
333 | "getAllTimeSamplingProfile"
334 | params
335 | {})))
336 |
337 | (s/fdef
338 | get-all-time-sampling-profile
339 | :args
340 | (s/or
341 | :no-args
342 | (s/cat)
343 | :just-params
344 | (s/cat :params (s/keys))
345 | :connection-and-params
346 | (s/cat
347 | :connection
348 | (s/?
349 | c/connection?)
350 | :params
351 | (s/keys)))
352 | :ret
353 | (s/keys
354 | :req-un
355 | [::profile]))
356 |
357 | (defn
358 | get-browser-sampling-profile
359 | "Retrieve native memory allocations profile\ncollected since browser process startup.\n\nReturn map keys:\n\n\n Key | Description \n ---------|------------ \n :profile | null"
360 | ([]
361 | (get-browser-sampling-profile
362 | (c/get-current-connection)
363 | {}))
364 | ([{:as params, :keys []}]
365 | (get-browser-sampling-profile
366 | (c/get-current-connection)
367 | params))
368 | ([connection {:as params, :keys []}]
369 | (cmd/command
370 | connection
371 | "Memory"
372 | "getBrowserSamplingProfile"
373 | params
374 | {})))
375 |
376 | (s/fdef
377 | get-browser-sampling-profile
378 | :args
379 | (s/or
380 | :no-args
381 | (s/cat)
382 | :just-params
383 | (s/cat :params (s/keys))
384 | :connection-and-params
385 | (s/cat
386 | :connection
387 | (s/?
388 | c/connection?)
389 | :params
390 | (s/keys)))
391 | :ret
392 | (s/keys
393 | :req-un
394 | [::profile]))
395 |
396 | (defn
397 | get-sampling-profile
398 | "Retrieve native memory allocations profile collected since last\n`startSampling` call.\n\nReturn map keys:\n\n\n Key | Description \n ---------|------------ \n :profile | null"
399 | ([]
400 | (get-sampling-profile
401 | (c/get-current-connection)
402 | {}))
403 | ([{:as params, :keys []}]
404 | (get-sampling-profile
405 | (c/get-current-connection)
406 | params))
407 | ([connection {:as params, :keys []}]
408 | (cmd/command
409 | connection
410 | "Memory"
411 | "getSamplingProfile"
412 | params
413 | {})))
414 |
415 | (s/fdef
416 | get-sampling-profile
417 | :args
418 | (s/or
419 | :no-args
420 | (s/cat)
421 | :just-params
422 | (s/cat :params (s/keys))
423 | :connection-and-params
424 | (s/cat
425 | :connection
426 | (s/?
427 | c/connection?)
428 | :params
429 | (s/keys)))
430 | :ret
431 | (s/keys
432 | :req-un
433 | [::profile]))
434 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/performance.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.performance
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (s/def
7 | ::metric
8 | (s/keys
9 | :req-un
10 | [::name
11 | ::value]))
12 | (defn
13 | disable
14 | "Disable collecting and reporting metrics."
15 | ([]
16 | (disable
17 | (c/get-current-connection)
18 | {}))
19 | ([{:as params, :keys []}]
20 | (disable
21 | (c/get-current-connection)
22 | params))
23 | ([connection {:as params, :keys []}]
24 | (cmd/command
25 | connection
26 | "Performance"
27 | "disable"
28 | params
29 | {})))
30 |
31 | (s/fdef
32 | disable
33 | :args
34 | (s/or
35 | :no-args
36 | (s/cat)
37 | :just-params
38 | (s/cat :params (s/keys))
39 | :connection-and-params
40 | (s/cat
41 | :connection
42 | (s/?
43 | c/connection?)
44 | :params
45 | (s/keys)))
46 | :ret
47 | (s/keys))
48 |
49 | (defn
50 | enable
51 | "Enable collecting and reporting metrics.\n\nParameters map keys:\n\n\n Key | Description \n -------------|------------ \n :time-domain | Time domain to use for collecting and reporting duration metrics. (optional)"
52 | ([]
53 | (enable
54 | (c/get-current-connection)
55 | {}))
56 | ([{:as params, :keys [time-domain]}]
57 | (enable
58 | (c/get-current-connection)
59 | params))
60 | ([connection {:as params, :keys [time-domain]}]
61 | (cmd/command
62 | connection
63 | "Performance"
64 | "enable"
65 | params
66 | {:time-domain "timeDomain"})))
67 |
68 | (s/fdef
69 | enable
70 | :args
71 | (s/or
72 | :no-args
73 | (s/cat)
74 | :just-params
75 | (s/cat
76 | :params
77 | (s/keys
78 | :opt-un
79 | [::time-domain]))
80 | :connection-and-params
81 | (s/cat
82 | :connection
83 | (s/?
84 | c/connection?)
85 | :params
86 | (s/keys
87 | :opt-un
88 | [::time-domain])))
89 | :ret
90 | (s/keys))
91 |
92 | (defn
93 | set-time-domain
94 | "Sets time domain to use for collecting and reporting duration metrics.\nNote that this must be called before enabling metrics collection. Calling\nthis method while metrics collection is enabled returns an error.\n\nParameters map keys:\n\n\n Key | Description \n -------------|------------ \n :time-domain | Time domain"
95 | ([]
96 | (set-time-domain
97 | (c/get-current-connection)
98 | {}))
99 | ([{:as params, :keys [time-domain]}]
100 | (set-time-domain
101 | (c/get-current-connection)
102 | params))
103 | ([connection {:as params, :keys [time-domain]}]
104 | (cmd/command
105 | connection
106 | "Performance"
107 | "setTimeDomain"
108 | params
109 | {:time-domain "timeDomain"})))
110 |
111 | (s/fdef
112 | set-time-domain
113 | :args
114 | (s/or
115 | :no-args
116 | (s/cat)
117 | :just-params
118 | (s/cat
119 | :params
120 | (s/keys
121 | :req-un
122 | [::time-domain]))
123 | :connection-and-params
124 | (s/cat
125 | :connection
126 | (s/?
127 | c/connection?)
128 | :params
129 | (s/keys
130 | :req-un
131 | [::time-domain])))
132 | :ret
133 | (s/keys))
134 |
135 | (defn
136 | get-metrics
137 | "Retrieve current values of run-time metrics.\n\nReturn map keys:\n\n\n Key | Description \n ---------|------------ \n :metrics | Current values for run-time metrics."
138 | ([]
139 | (get-metrics
140 | (c/get-current-connection)
141 | {}))
142 | ([{:as params, :keys []}]
143 | (get-metrics
144 | (c/get-current-connection)
145 | params))
146 | ([connection {:as params, :keys []}]
147 | (cmd/command
148 | connection
149 | "Performance"
150 | "getMetrics"
151 | params
152 | {})))
153 |
154 | (s/fdef
155 | get-metrics
156 | :args
157 | (s/or
158 | :no-args
159 | (s/cat)
160 | :just-params
161 | (s/cat :params (s/keys))
162 | :connection-and-params
163 | (s/cat
164 | :connection
165 | (s/?
166 | c/connection?)
167 | :params
168 | (s/keys)))
169 | :ret
170 | (s/keys
171 | :req-un
172 | [::metrics]))
173 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/performance_timeline.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.performance-timeline
2 | "Reporting of performance timeline events, as specified in\nhttps://w3c.github.io/performance-timeline/#dom-performanceobserver."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::largest-contentful-paint
9 | (s/keys
10 | :req-un
11 | [::render-time
12 | ::load-time
13 | ::size]
14 | :opt-un
15 | [::element-id
16 | ::url
17 | ::node-id]))
18 |
19 | (s/def
20 | ::layout-shift-attribution
21 | (s/keys
22 | :req-un
23 | [::previous-rect
24 | ::current-rect]
25 | :opt-un
26 | [::node-id]))
27 |
28 | (s/def
29 | ::layout-shift
30 | (s/keys
31 | :req-un
32 | [::value
33 | ::had-recent-input
34 | ::last-input-time
35 | ::sources]))
36 |
37 | (s/def
38 | ::timeline-event
39 | (s/keys
40 | :req-un
41 | [::frame-id
42 | ::type
43 | ::name
44 | ::time]
45 | :opt-un
46 | [::duration
47 | ::lcp-details
48 | ::layout-shift-details]))
49 | (defn
50 | enable
51 | "Previously buffered events would be reported before method returns.\nSee also: timelineEventAdded\n\nParameters map keys:\n\n\n Key | Description \n -------------|------------ \n :event-types | The types of event to report, as specified in\nhttps://w3c.github.io/performance-timeline/#dom-performanceentry-entrytype\nThe specified filter overrides any previous filters, passing empty\nfilter disables recording.\nNote that not all types exposed to the web platform are currently supported."
52 | ([]
53 | (enable
54 | (c/get-current-connection)
55 | {}))
56 | ([{:as params, :keys [event-types]}]
57 | (enable
58 | (c/get-current-connection)
59 | params))
60 | ([connection {:as params, :keys [event-types]}]
61 | (cmd/command
62 | connection
63 | "PerformanceTimeline"
64 | "enable"
65 | params
66 | {:event-types "eventTypes"})))
67 |
68 | (s/fdef
69 | enable
70 | :args
71 | (s/or
72 | :no-args
73 | (s/cat)
74 | :just-params
75 | (s/cat
76 | :params
77 | (s/keys
78 | :req-un
79 | [::event-types]))
80 | :connection-and-params
81 | (s/cat
82 | :connection
83 | (s/?
84 | c/connection?)
85 | :params
86 | (s/keys
87 | :req-un
88 | [::event-types])))
89 | :ret
90 | (s/keys))
91 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/schema.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.schema
2 | "This domain is deprecated."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::domain
9 | (s/keys
10 | :req-un
11 | [::name
12 | ::version]))
13 | (defn
14 | get-domains
15 | "Returns supported domains.\n\nReturn map keys:\n\n\n Key | Description \n ---------|------------ \n :domains | List of supported domains."
16 | ([]
17 | (get-domains
18 | (c/get-current-connection)
19 | {}))
20 | ([{:as params, :keys []}]
21 | (get-domains
22 | (c/get-current-connection)
23 | params))
24 | ([connection {:as params, :keys []}]
25 | (cmd/command
26 | connection
27 | "Schema"
28 | "getDomains"
29 | params
30 | {})))
31 |
32 | (s/fdef
33 | get-domains
34 | :args
35 | (s/or
36 | :no-args
37 | (s/cat)
38 | :just-params
39 | (s/cat :params (s/keys))
40 | :connection-and-params
41 | (s/cat
42 | :connection
43 | (s/?
44 | c/connection?)
45 | :params
46 | (s/keys)))
47 | :ret
48 | (s/keys
49 | :req-un
50 | [::domains]))
51 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/security.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.security
2 | "Security"
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::certificate-id
9 | integer?)
10 |
11 | (s/def
12 | ::mixed-content-type
13 | #{"none" "blockable" "optionally-blockable"})
14 |
15 | (s/def
16 | ::security-state
17 | #{"neutral" "info" "insecure-broken" "secure" "unknown" "insecure"})
18 |
19 | (s/def
20 | ::certificate-security-state
21 | (s/keys
22 | :req-un
23 | [::protocol
24 | ::key-exchange
25 | ::cipher
26 | ::certificate
27 | ::subject-name
28 | ::issuer
29 | ::valid-from
30 | ::valid-to
31 | ::certificate-has-weak-signature
32 | ::certificate-has-sha1-signature
33 | ::modern-ssl
34 | ::obsolete-ssl-protocol
35 | ::obsolete-ssl-key-exchange
36 | ::obsolete-ssl-cipher
37 | ::obsolete-ssl-signature]
38 | :opt-un
39 | [::key-exchange-group
40 | ::mac
41 | ::certificate-network-error]))
42 |
43 | (s/def
44 | ::safety-tip-status
45 | #{"badReputation" "lookalike"})
46 |
47 | (s/def
48 | ::safety-tip-info
49 | (s/keys
50 | :req-un
51 | [::safety-tip-status]
52 | :opt-un
53 | [::safe-url]))
54 |
55 | (s/def
56 | ::visible-security-state
57 | (s/keys
58 | :req-un
59 | [::security-state
60 | ::security-state-issue-ids]
61 | :opt-un
62 | [::certificate-security-state
63 | ::safety-tip-info]))
64 |
65 | (s/def
66 | ::security-state-explanation
67 | (s/keys
68 | :req-un
69 | [::security-state
70 | ::title
71 | ::summary
72 | ::description
73 | ::mixed-content-type
74 | ::certificate]
75 | :opt-un
76 | [::recommendations]))
77 |
78 | (s/def
79 | ::insecure-content-status
80 | (s/keys
81 | :req-un
82 | [::ran-mixed-content
83 | ::displayed-mixed-content
84 | ::contained-mixed-form
85 | ::ran-content-with-cert-errors
86 | ::displayed-content-with-cert-errors
87 | ::ran-insecure-content-style
88 | ::displayed-insecure-content-style]))
89 |
90 | (s/def
91 | ::certificate-error-action
92 | #{"cancel" "continue"})
93 | (defn
94 | disable
95 | "Disables tracking security state changes."
96 | ([]
97 | (disable
98 | (c/get-current-connection)
99 | {}))
100 | ([{:as params, :keys []}]
101 | (disable
102 | (c/get-current-connection)
103 | params))
104 | ([connection {:as params, :keys []}]
105 | (cmd/command
106 | connection
107 | "Security"
108 | "disable"
109 | params
110 | {})))
111 |
112 | (s/fdef
113 | disable
114 | :args
115 | (s/or
116 | :no-args
117 | (s/cat)
118 | :just-params
119 | (s/cat :params (s/keys))
120 | :connection-and-params
121 | (s/cat
122 | :connection
123 | (s/?
124 | c/connection?)
125 | :params
126 | (s/keys)))
127 | :ret
128 | (s/keys))
129 |
130 | (defn
131 | enable
132 | "Enables tracking security state changes."
133 | ([]
134 | (enable
135 | (c/get-current-connection)
136 | {}))
137 | ([{:as params, :keys []}]
138 | (enable
139 | (c/get-current-connection)
140 | params))
141 | ([connection {:as params, :keys []}]
142 | (cmd/command
143 | connection
144 | "Security"
145 | "enable"
146 | params
147 | {})))
148 |
149 | (s/fdef
150 | enable
151 | :args
152 | (s/or
153 | :no-args
154 | (s/cat)
155 | :just-params
156 | (s/cat :params (s/keys))
157 | :connection-and-params
158 | (s/cat
159 | :connection
160 | (s/?
161 | c/connection?)
162 | :params
163 | (s/keys)))
164 | :ret
165 | (s/keys))
166 |
167 | (defn
168 | set-ignore-certificate-errors
169 | "Enable/disable whether all certificate errors should be ignored.\n\nParameters map keys:\n\n\n Key | Description \n --------|------------ \n :ignore | If true, all certificate errors will be ignored."
170 | ([]
171 | (set-ignore-certificate-errors
172 | (c/get-current-connection)
173 | {}))
174 | ([{:as params, :keys [ignore]}]
175 | (set-ignore-certificate-errors
176 | (c/get-current-connection)
177 | params))
178 | ([connection {:as params, :keys [ignore]}]
179 | (cmd/command
180 | connection
181 | "Security"
182 | "setIgnoreCertificateErrors"
183 | params
184 | {:ignore "ignore"})))
185 |
186 | (s/fdef
187 | set-ignore-certificate-errors
188 | :args
189 | (s/or
190 | :no-args
191 | (s/cat)
192 | :just-params
193 | (s/cat
194 | :params
195 | (s/keys
196 | :req-un
197 | [::ignore]))
198 | :connection-and-params
199 | (s/cat
200 | :connection
201 | (s/?
202 | c/connection?)
203 | :params
204 | (s/keys
205 | :req-un
206 | [::ignore])))
207 | :ret
208 | (s/keys))
209 |
210 | (defn
211 | handle-certificate-error
212 | "Handles a certificate error that fired a certificateError event.\n\nParameters map keys:\n\n\n Key | Description \n ----------|------------ \n :event-id | The ID of the event.\n :action | The action to take on the certificate error."
213 | ([]
214 | (handle-certificate-error
215 | (c/get-current-connection)
216 | {}))
217 | ([{:as params, :keys [event-id action]}]
218 | (handle-certificate-error
219 | (c/get-current-connection)
220 | params))
221 | ([connection {:as params, :keys [event-id action]}]
222 | (cmd/command
223 | connection
224 | "Security"
225 | "handleCertificateError"
226 | params
227 | {:event-id "eventId", :action "action"})))
228 |
229 | (s/fdef
230 | handle-certificate-error
231 | :args
232 | (s/or
233 | :no-args
234 | (s/cat)
235 | :just-params
236 | (s/cat
237 | :params
238 | (s/keys
239 | :req-un
240 | [::event-id
241 | ::action]))
242 | :connection-and-params
243 | (s/cat
244 | :connection
245 | (s/?
246 | c/connection?)
247 | :params
248 | (s/keys
249 | :req-un
250 | [::event-id
251 | ::action])))
252 | :ret
253 | (s/keys))
254 |
255 | (defn
256 | set-override-certificate-errors
257 | "Enable/disable overriding certificate errors. If enabled, all certificate error events need to\nbe handled by the DevTools client and should be answered with `handleCertificateError` commands.\n\nParameters map keys:\n\n\n Key | Description \n ----------|------------ \n :override | If true, certificate errors will be overridden."
258 | ([]
259 | (set-override-certificate-errors
260 | (c/get-current-connection)
261 | {}))
262 | ([{:as params, :keys [override]}]
263 | (set-override-certificate-errors
264 | (c/get-current-connection)
265 | params))
266 | ([connection {:as params, :keys [override]}]
267 | (cmd/command
268 | connection
269 | "Security"
270 | "setOverrideCertificateErrors"
271 | params
272 | {:override "override"})))
273 |
274 | (s/fdef
275 | set-override-certificate-errors
276 | :args
277 | (s/or
278 | :no-args
279 | (s/cat)
280 | :just-params
281 | (s/cat
282 | :params
283 | (s/keys
284 | :req-un
285 | [::override]))
286 | :connection-and-params
287 | (s/cat
288 | :connection
289 | (s/?
290 | c/connection?)
291 | :params
292 | (s/keys
293 | :req-un
294 | [::override])))
295 | :ret
296 | (s/keys))
297 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/system_info.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.system-info
2 | "The SystemInfo domain defines methods and events for querying low-level system information."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::gpu-device
9 | (s/keys
10 | :req-un
11 | [::vendor-id
12 | ::device-id
13 | ::vendor-string
14 | ::device-string
15 | ::driver-vendor
16 | ::driver-version]
17 | :opt-un
18 | [::sub-sys-id
19 | ::revision]))
20 |
21 | (s/def
22 | ::size
23 | (s/keys
24 | :req-un
25 | [::width
26 | ::height]))
27 |
28 | (s/def
29 | ::video-decode-accelerator-capability
30 | (s/keys
31 | :req-un
32 | [::profile
33 | ::max-resolution
34 | ::min-resolution]))
35 |
36 | (s/def
37 | ::video-encode-accelerator-capability
38 | (s/keys
39 | :req-un
40 | [::profile
41 | ::max-resolution
42 | ::max-framerate-numerator
43 | ::max-framerate-denominator]))
44 |
45 | (s/def
46 | ::subsampling-format
47 | #{"yuv422" "yuv444" "yuv420"})
48 |
49 | (s/def
50 | ::image-type
51 | #{"webp" "jpeg" "unknown"})
52 |
53 | (s/def
54 | ::image-decode-accelerator-capability
55 | (s/keys
56 | :req-un
57 | [::image-type
58 | ::max-dimensions
59 | ::min-dimensions
60 | ::subsamplings]))
61 |
62 | (s/def
63 | ::gpu-info
64 | (s/keys
65 | :req-un
66 | [::devices
67 | ::driver-bug-workarounds
68 | ::video-decoding
69 | ::video-encoding
70 | ::image-decoding]
71 | :opt-un
72 | [::aux-attributes
73 | ::feature-status]))
74 |
75 | (s/def
76 | ::process-info
77 | (s/keys
78 | :req-un
79 | [::type
80 | ::id
81 | ::cpu-time]))
82 | (defn
83 | get-info
84 | "Returns information about the system.\n\nReturn map keys:\n\n\n Key | Description \n ---------------|------------ \n :gpu | Information about the GPUs on the system.\n :model-name | A platform-dependent description of the model of the machine. On Mac OS, this is, for\nexample, 'MacBookPro'. Will be the empty string if not supported.\n :model-version | A platform-dependent description of the version of the machine. On Mac OS, this is, for\nexample, '10.1'. Will be the empty string if not supported.\n :command-line | The command line string used to launch the browser. Will be the empty string if not\nsupported."
85 | ([]
86 | (get-info
87 | (c/get-current-connection)
88 | {}))
89 | ([{:as params, :keys []}]
90 | (get-info
91 | (c/get-current-connection)
92 | params))
93 | ([connection {:as params, :keys []}]
94 | (cmd/command
95 | connection
96 | "SystemInfo"
97 | "getInfo"
98 | params
99 | {})))
100 |
101 | (s/fdef
102 | get-info
103 | :args
104 | (s/or
105 | :no-args
106 | (s/cat)
107 | :just-params
108 | (s/cat :params (s/keys))
109 | :connection-and-params
110 | (s/cat
111 | :connection
112 | (s/?
113 | c/connection?)
114 | :params
115 | (s/keys)))
116 | :ret
117 | (s/keys
118 | :req-un
119 | [::gpu
120 | ::model-name
121 | ::model-version
122 | ::command-line]))
123 |
124 | (defn
125 | get-process-info
126 | "Returns information about all running processes.\n\nReturn map keys:\n\n\n Key | Description \n --------------|------------ \n :process-info | An array of process info blocks."
127 | ([]
128 | (get-process-info
129 | (c/get-current-connection)
130 | {}))
131 | ([{:as params, :keys []}]
132 | (get-process-info
133 | (c/get-current-connection)
134 | params))
135 | ([connection {:as params, :keys []}]
136 | (cmd/command
137 | connection
138 | "SystemInfo"
139 | "getProcessInfo"
140 | params
141 | {})))
142 |
143 | (s/fdef
144 | get-process-info
145 | :args
146 | (s/or
147 | :no-args
148 | (s/cat)
149 | :just-params
150 | (s/cat :params (s/keys))
151 | :connection-and-params
152 | (s/cat
153 | :connection
154 | (s/?
155 | c/connection?)
156 | :params
157 | (s/keys)))
158 | :ret
159 | (s/keys
160 | :req-un
161 | [::process-info]))
162 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/tethering.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.tethering
2 | "The Tethering domain defines methods and events for browser port binding."
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (defn
8 | bind
9 | "Request browser port binding.\n\nParameters map keys:\n\n\n Key | Description \n ------|------------ \n :port | Port number to bind."
10 | ([]
11 | (bind
12 | (c/get-current-connection)
13 | {}))
14 | ([{:as params, :keys [port]}]
15 | (bind
16 | (c/get-current-connection)
17 | params))
18 | ([connection {:as params, :keys [port]}]
19 | (cmd/command
20 | connection
21 | "Tethering"
22 | "bind"
23 | params
24 | {:port "port"})))
25 |
26 | (s/fdef
27 | bind
28 | :args
29 | (s/or
30 | :no-args
31 | (s/cat)
32 | :just-params
33 | (s/cat
34 | :params
35 | (s/keys
36 | :req-un
37 | [::port]))
38 | :connection-and-params
39 | (s/cat
40 | :connection
41 | (s/?
42 | c/connection?)
43 | :params
44 | (s/keys
45 | :req-un
46 | [::port])))
47 | :ret
48 | (s/keys))
49 |
50 | (defn
51 | unbind
52 | "Request browser port unbinding.\n\nParameters map keys:\n\n\n Key | Description \n ------|------------ \n :port | Port number to unbind."
53 | ([]
54 | (unbind
55 | (c/get-current-connection)
56 | {}))
57 | ([{:as params, :keys [port]}]
58 | (unbind
59 | (c/get-current-connection)
60 | params))
61 | ([connection {:as params, :keys [port]}]
62 | (cmd/command
63 | connection
64 | "Tethering"
65 | "unbind"
66 | params
67 | {:port "port"})))
68 |
69 | (s/fdef
70 | unbind
71 | :args
72 | (s/or
73 | :no-args
74 | (s/cat)
75 | :just-params
76 | (s/cat
77 | :params
78 | (s/keys
79 | :req-un
80 | [::port]))
81 | :connection-and-params
82 | (s/cat
83 | :connection
84 | (s/?
85 | c/connection?)
86 | :params
87 | (s/keys
88 | :req-un
89 | [::port])))
90 | :ret
91 | (s/keys))
92 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/tracing.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.tracing
2 | (:require [clojure.spec.alpha :as s]
3 | [clj-chrome-devtools.impl.command :as cmd]
4 | [clj-chrome-devtools.impl.connection :as c]))
5 |
6 | (s/def
7 | ::memory-dump-config
8 | (s/keys))
9 |
10 | (s/def
11 | ::trace-config
12 | (s/keys
13 | :opt-un
14 | [::record-mode
15 | ::enable-sampling
16 | ::enable-systrace
17 | ::enable-argument-filter
18 | ::included-categories
19 | ::excluded-categories
20 | ::synthetic-delays
21 | ::memory-dump-config]))
22 |
23 | (s/def
24 | ::stream-format
25 | #{"json" "proto"})
26 |
27 | (s/def
28 | ::stream-compression
29 | #{"none" "gzip"})
30 |
31 | (s/def
32 | ::memory-dump-level-of-detail
33 | #{"detailed" "light" "background"})
34 |
35 | (s/def
36 | ::tracing-backend
37 | #{"auto" "chrome" "system"})
38 | (defn
39 | end
40 | "Stop trace events collection."
41 | ([]
42 | (end
43 | (c/get-current-connection)
44 | {}))
45 | ([{:as params, :keys []}]
46 | (end
47 | (c/get-current-connection)
48 | params))
49 | ([connection {:as params, :keys []}]
50 | (cmd/command
51 | connection
52 | "Tracing"
53 | "end"
54 | params
55 | {})))
56 |
57 | (s/fdef
58 | end
59 | :args
60 | (s/or
61 | :no-args
62 | (s/cat)
63 | :just-params
64 | (s/cat :params (s/keys))
65 | :connection-and-params
66 | (s/cat
67 | :connection
68 | (s/?
69 | c/connection?)
70 | :params
71 | (s/keys)))
72 | :ret
73 | (s/keys))
74 |
75 | (defn
76 | get-categories
77 | "Gets supported tracing categories.\n\nReturn map keys:\n\n\n Key | Description \n ------------|------------ \n :categories | A list of supported tracing categories."
78 | ([]
79 | (get-categories
80 | (c/get-current-connection)
81 | {}))
82 | ([{:as params, :keys []}]
83 | (get-categories
84 | (c/get-current-connection)
85 | params))
86 | ([connection {:as params, :keys []}]
87 | (cmd/command
88 | connection
89 | "Tracing"
90 | "getCategories"
91 | params
92 | {})))
93 |
94 | (s/fdef
95 | get-categories
96 | :args
97 | (s/or
98 | :no-args
99 | (s/cat)
100 | :just-params
101 | (s/cat :params (s/keys))
102 | :connection-and-params
103 | (s/cat
104 | :connection
105 | (s/?
106 | c/connection?)
107 | :params
108 | (s/keys)))
109 | :ret
110 | (s/keys
111 | :req-un
112 | [::categories]))
113 |
114 | (defn
115 | record-clock-sync-marker
116 | "Record a clock sync marker in the trace.\n\nParameters map keys:\n\n\n Key | Description \n ---------|------------ \n :sync-id | The ID of this clock sync marker"
117 | ([]
118 | (record-clock-sync-marker
119 | (c/get-current-connection)
120 | {}))
121 | ([{:as params, :keys [sync-id]}]
122 | (record-clock-sync-marker
123 | (c/get-current-connection)
124 | params))
125 | ([connection {:as params, :keys [sync-id]}]
126 | (cmd/command
127 | connection
128 | "Tracing"
129 | "recordClockSyncMarker"
130 | params
131 | {:sync-id "syncId"})))
132 |
133 | (s/fdef
134 | record-clock-sync-marker
135 | :args
136 | (s/or
137 | :no-args
138 | (s/cat)
139 | :just-params
140 | (s/cat
141 | :params
142 | (s/keys
143 | :req-un
144 | [::sync-id]))
145 | :connection-and-params
146 | (s/cat
147 | :connection
148 | (s/?
149 | c/connection?)
150 | :params
151 | (s/keys
152 | :req-un
153 | [::sync-id])))
154 | :ret
155 | (s/keys))
156 |
157 | (defn
158 | request-memory-dump
159 | "Request a global memory dump.\n\nParameters map keys:\n\n\n Key | Description \n -----------------|------------ \n :deterministic | Enables more deterministic results by forcing garbage collection (optional)\n :level-of-detail | Specifies level of details in memory dump. Defaults to \"detailed\". (optional)\n\nReturn map keys:\n\n\n Key | Description \n -----------|------------ \n :dump-guid | GUID of the resulting global memory dump.\n :success | True iff the global memory dump succeeded."
160 | ([]
161 | (request-memory-dump
162 | (c/get-current-connection)
163 | {}))
164 | ([{:as params, :keys [deterministic level-of-detail]}]
165 | (request-memory-dump
166 | (c/get-current-connection)
167 | params))
168 | ([connection {:as params, :keys [deterministic level-of-detail]}]
169 | (cmd/command
170 | connection
171 | "Tracing"
172 | "requestMemoryDump"
173 | params
174 | {:deterministic "deterministic", :level-of-detail "levelOfDetail"})))
175 |
176 | (s/fdef
177 | request-memory-dump
178 | :args
179 | (s/or
180 | :no-args
181 | (s/cat)
182 | :just-params
183 | (s/cat
184 | :params
185 | (s/keys
186 | :opt-un
187 | [::deterministic
188 | ::level-of-detail]))
189 | :connection-and-params
190 | (s/cat
191 | :connection
192 | (s/?
193 | c/connection?)
194 | :params
195 | (s/keys
196 | :opt-un
197 | [::deterministic
198 | ::level-of-detail])))
199 | :ret
200 | (s/keys
201 | :req-un
202 | [::dump-guid
203 | ::success]))
204 |
205 | (defn
206 | start
207 | "Start trace events collection.\n\nParameters map keys:\n\n\n Key | Description \n ---------------------------------|------------ \n :categories | Category/tag filter (optional)\n :options | Tracing options (optional)\n :buffer-usage-reporting-interval | If set, the agent will issue bufferUsage events at this interval, specified in milliseconds (optional)\n :transfer-mode | Whether to report trace events as series of dataCollected events or to save trace to a\nstream (defaults to `ReportEvents`). (optional)\n :stream-format | Trace data format to use. This only applies when using `ReturnAsStream`\ntransfer mode (defaults to `json`). (optional)\n :stream-compression | Compression format to use. This only applies when using `ReturnAsStream`\ntransfer mode (defaults to `none`) (optional)\n :trace-config | null (optional)\n :perfetto-config | Base64-encoded serialized perfetto.protos.TraceConfig protobuf message\nWhen specified, the parameters `categories`, `options`, `traceConfig`\nare ignored. (Encoded as a base64 string when passed over JSON) (optional)\n :tracing-backend | Backend type (defaults to `auto`) (optional)"
208 | ([]
209 | (start
210 | (c/get-current-connection)
211 | {}))
212 | ([{:as params,
213 | :keys
214 | [categories
215 | options
216 | buffer-usage-reporting-interval
217 | transfer-mode
218 | stream-format
219 | stream-compression
220 | trace-config
221 | perfetto-config
222 | tracing-backend]}]
223 | (start
224 | (c/get-current-connection)
225 | params))
226 | ([connection
227 | {:as params,
228 | :keys
229 | [categories
230 | options
231 | buffer-usage-reporting-interval
232 | transfer-mode
233 | stream-format
234 | stream-compression
235 | trace-config
236 | perfetto-config
237 | tracing-backend]}]
238 | (cmd/command
239 | connection
240 | "Tracing"
241 | "start"
242 | params
243 | {:categories "categories",
244 | :options "options",
245 | :buffer-usage-reporting-interval "bufferUsageReportingInterval",
246 | :transfer-mode "transferMode",
247 | :stream-format "streamFormat",
248 | :stream-compression "streamCompression",
249 | :trace-config "traceConfig",
250 | :perfetto-config "perfettoConfig",
251 | :tracing-backend "tracingBackend"})))
252 |
253 | (s/fdef
254 | start
255 | :args
256 | (s/or
257 | :no-args
258 | (s/cat)
259 | :just-params
260 | (s/cat
261 | :params
262 | (s/keys
263 | :opt-un
264 | [::categories
265 | ::options
266 | ::buffer-usage-reporting-interval
267 | ::transfer-mode
268 | ::stream-format
269 | ::stream-compression
270 | ::trace-config
271 | ::perfetto-config
272 | ::tracing-backend]))
273 | :connection-and-params
274 | (s/cat
275 | :connection
276 | (s/?
277 | c/connection?)
278 | :params
279 | (s/keys
280 | :opt-un
281 | [::categories
282 | ::options
283 | ::buffer-usage-reporting-interval
284 | ::transfer-mode
285 | ::stream-format
286 | ::stream-compression
287 | ::trace-config
288 | ::perfetto-config
289 | ::tracing-backend])))
290 | :ret
291 | (s/keys))
292 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/commands/web_audio.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.commands.web-audio
2 | "This domain allows inspection of Web Audio API.\nhttps://webaudio.github.io/web-audio-api/"
3 | (:require [clojure.spec.alpha :as s]
4 | [clj-chrome-devtools.impl.command :as cmd]
5 | [clj-chrome-devtools.impl.connection :as c]))
6 |
7 | (s/def
8 | ::graph-object-id
9 | string?)
10 |
11 | (s/def
12 | ::context-type
13 | #{"realtime" "offline"})
14 |
15 | (s/def
16 | ::context-state
17 | #{"running" "closed" "suspended"})
18 |
19 | (s/def
20 | ::node-type
21 | string?)
22 |
23 | (s/def
24 | ::channel-count-mode
25 | #{"max" "clamped-max" "explicit"})
26 |
27 | (s/def
28 | ::channel-interpretation
29 | #{"speakers" "discrete"})
30 |
31 | (s/def
32 | ::param-type
33 | string?)
34 |
35 | (s/def
36 | ::automation-rate
37 | #{"k-rate" "a-rate"})
38 |
39 | (s/def
40 | ::context-realtime-data
41 | (s/keys
42 | :req-un
43 | [::current-time
44 | ::render-capacity
45 | ::callback-interval-mean
46 | ::callback-interval-variance]))
47 |
48 | (s/def
49 | ::base-audio-context
50 | (s/keys
51 | :req-un
52 | [::context-id
53 | ::context-type
54 | ::context-state
55 | ::callback-buffer-size
56 | ::max-output-channel-count
57 | ::sample-rate]
58 | :opt-un
59 | [::realtime-data]))
60 |
61 | (s/def
62 | ::audio-listener
63 | (s/keys
64 | :req-un
65 | [::listener-id
66 | ::context-id]))
67 |
68 | (s/def
69 | ::audio-node
70 | (s/keys
71 | :req-un
72 | [::node-id
73 | ::context-id
74 | ::node-type
75 | ::number-of-inputs
76 | ::number-of-outputs
77 | ::channel-count
78 | ::channel-count-mode
79 | ::channel-interpretation]))
80 |
81 | (s/def
82 | ::audio-param
83 | (s/keys
84 | :req-un
85 | [::param-id
86 | ::node-id
87 | ::context-id
88 | ::param-type
89 | ::rate
90 | ::default-value
91 | ::min-value
92 | ::max-value]))
93 | (defn
94 | enable
95 | "Enables the WebAudio domain and starts sending context lifetime events."
96 | ([]
97 | (enable
98 | (c/get-current-connection)
99 | {}))
100 | ([{:as params, :keys []}]
101 | (enable
102 | (c/get-current-connection)
103 | params))
104 | ([connection {:as params, :keys []}]
105 | (cmd/command
106 | connection
107 | "WebAudio"
108 | "enable"
109 | params
110 | {})))
111 |
112 | (s/fdef
113 | enable
114 | :args
115 | (s/or
116 | :no-args
117 | (s/cat)
118 | :just-params
119 | (s/cat :params (s/keys))
120 | :connection-and-params
121 | (s/cat
122 | :connection
123 | (s/?
124 | c/connection?)
125 | :params
126 | (s/keys)))
127 | :ret
128 | (s/keys))
129 |
130 | (defn
131 | disable
132 | "Disables the WebAudio domain."
133 | ([]
134 | (disable
135 | (c/get-current-connection)
136 | {}))
137 | ([{:as params, :keys []}]
138 | (disable
139 | (c/get-current-connection)
140 | params))
141 | ([connection {:as params, :keys []}]
142 | (cmd/command
143 | connection
144 | "WebAudio"
145 | "disable"
146 | params
147 | {})))
148 |
149 | (s/fdef
150 | disable
151 | :args
152 | (s/or
153 | :no-args
154 | (s/cat)
155 | :just-params
156 | (s/cat :params (s/keys))
157 | :connection-and-params
158 | (s/cat
159 | :connection
160 | (s/?
161 | c/connection?)
162 | :params
163 | (s/keys)))
164 | :ret
165 | (s/keys))
166 |
167 | (defn
168 | get-realtime-data
169 | "Fetch the realtime data from the registered contexts.\n\nParameters map keys:\n\n\n Key | Description \n ------------|------------ \n :context-id | null\n\nReturn map keys:\n\n\n Key | Description \n ---------------|------------ \n :realtime-data | null"
170 | ([]
171 | (get-realtime-data
172 | (c/get-current-connection)
173 | {}))
174 | ([{:as params, :keys [context-id]}]
175 | (get-realtime-data
176 | (c/get-current-connection)
177 | params))
178 | ([connection {:as params, :keys [context-id]}]
179 | (cmd/command
180 | connection
181 | "WebAudio"
182 | "getRealtimeData"
183 | params
184 | {:context-id "contextId"})))
185 |
186 | (s/fdef
187 | get-realtime-data
188 | :args
189 | (s/or
190 | :no-args
191 | (s/cat)
192 | :just-params
193 | (s/cat
194 | :params
195 | (s/keys
196 | :req-un
197 | [::context-id]))
198 | :connection-and-params
199 | (s/cat
200 | :connection
201 | (s/?
202 | c/connection?)
203 | :params
204 | (s/keys
205 | :req-un
206 | [::context-id])))
207 | :ret
208 | (s/keys
209 | :req-un
210 | [::realtime-data]))
211 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/core.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.core
2 | (:require [clj-chrome-devtools.impl.connection :as connection]))
3 |
4 |
5 | (def current-connection connection/current-connection)
6 |
7 | (defn set-current-connection!
8 | "Set the globally used current connection"
9 | [c]
10 | (reset! connection/current-connection c))
11 |
12 | (def connect connection/connect)
13 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/events.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.events
2 | "Listening to events coming from Chrome."
3 | (:require [clj-chrome-devtools.impl.connection :as connection]))
4 |
5 | (def default-wait-ms 30000)
6 |
7 | (defn listen
8 | "Subscribe to listen to given domain event. Both domain and event are keywords.
9 | Returns a 0-arity function that removes the listener when invoked."
10 | ([domain event callback]
11 | (listen (connection/get-current-connection) domain event callback))
12 | ([connection domain event callback]
13 | (connection/listen connection domain event callback)))
14 |
15 | (defn listen-once
16 | "Synchronously listen for an event once, remove the listener and return the event."
17 | ([domain event]
18 | (listen-once (connection/get-current-connection) domain event))
19 | ([connection domain event]
20 | (let [p (promise)
21 | unlisten (listen connection domain event #(deliver p %))
22 | val @p]
23 | (unlisten)
24 | val)))
25 |
26 | (defn unlisten
27 | "Remove the listening callback from the subscribers of the specified
28 | domain event type."
29 | ([domain event callback]
30 | (unlisten (connection/get-current-connection) domain event callback))
31 | ([connection domain event callback]
32 | (connection/unlisten connection domain event callback)))
33 |
34 | (defn wait-for-event
35 | "Synchronously wait for an event with specific parameters."
36 | ([domain event params]
37 | (wait-for-event (connection/get-current-connection) domain event params))
38 | ([connection domain event params]
39 | (wait-for-event connection domain event params default-wait-ms))
40 | ([connection domain event params timeout-ms]
41 | (wait-for-event connection domain event params timeout-ms nil))
42 | ([connection domain event params timeout-ms after-attach-listener-fn]
43 | (let [p (promise)
44 | callback #(when (= params (select-keys (:params %) (keys params)))
45 | (deliver p (:params %)))
46 | unlisten (listen connection domain event callback)
47 | _ (when after-attach-listener-fn
48 | (after-attach-listener-fn))
49 | val (deref p timeout-ms ::timeout)]
50 | (unlisten)
51 | (if (= val ::timeout)
52 | (throw (ex-info "Timeout! Specified event was not received."
53 | {:domain domain :event event :params params
54 | :timeout timeout-ms}))
55 | val))))
56 |
57 | (defmacro with-event-wait
58 | "Execute body that causes some later events and wait for the event before returning.
59 | If the event is not received after waiting timeout-ms milliseconds, an exception is thrown."
60 | ([domain event body]
61 | `(with-event-wait (connection/get-current-connection) ~domain ~event ~body))
62 | ([connection domain event body]
63 | `(with-event-wait ~connection ~domain ~event default-wait-ms ~body))
64 | ([connection domain event timeout-ms body]
65 | `(wait-for-event ~connection ~domain ~event {} ~timeout-ms
66 | (fn []
67 | ~body))))
68 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/impl/command.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.impl.command
2 | "Implementation utils for commands"
3 | (:require [clojure.set :as set]
4 | [clj-chrome-devtools.impl.connection :as connection]))
5 |
6 | (defonce command-id (atom 0))
7 |
8 | (defn next-command-id! []
9 | (swap! command-id inc))
10 |
11 | (defn command-payload [id name params parameter-names]
12 | {:id id
13 | :method name
14 | :params (set/rename-keys params parameter-names)})
15 |
16 | (defn command [connection domain name params param-names]
17 | (let [id (next-command-id!)
18 | method (str domain "." name)
19 | payload (command-payload id method params param-names)
20 | result (connection/send-command connection payload id)]
21 | (if-let [error (:error result)]
22 | (throw (ex-info (str "Error in command " method ": " (:message error))
23 | {:request payload
24 | :error error}))
25 | (:result result))))
26 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/impl/connection.cljc:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.impl.connection
2 | "The remote debugging WebSocket connection"
3 | (:require [cheshire.core :as cheshire]
4 | [java-http-clj.core :as http]
5 | [java-http-clj.websocket :as ws]
6 | [clj-chrome-devtools.impl.util :refer [camel->clojure]]
7 | [clojure.string :as str]
8 | [clojure.tools.logging :as log])
9 | (:import (java.util.concurrent
10 | #?@(:bb [Executors]
11 | :clj [Executors ExecutorService]))
12 | (java.net.http WebSocket)))
13 |
14 | (set! *warn-on-reflection* true)
15 |
16 | (def ^:private executor (Executors/newCachedThreadPool))
17 |
18 |
19 | (defn- submit! [^Runnable func]
20 | (.submit #?(:bb executor
21 | :clj ^ExecutorService executor) func))
22 |
23 | (defrecord Connection [ws-connection requests event-listeners]
24 | #?@(:bb [] ;; babashka doesn't support implementing interfaces at this time
25 | :clj [java.lang.AutoCloseable
26 | (close [{ws-conn :ws-connection}]
27 | (when ws-conn
28 | (ws/close ws-conn)))]))
29 |
30 | (defn connection? [c]
31 | (instance? Connection c))
32 |
33 | (defonce current-connection (atom nil))
34 |
35 | (defn get-current-connection []
36 | (let [c @current-connection]
37 | (assert c "No current Chrome Devtools connection!")
38 | c))
39 |
40 | (defn- parse-json [string]
41 | (cheshire/parse-string string (comp keyword camel->clojure)))
42 |
43 | (defn- publish-event [event-listeners msg]
44 | (let [[domain event :as event-key]
45 | (map (comp keyword camel->clojure)
46 | (str/split (:method msg) #"\."))
47 | listeners (get event-listeners event-key)]
48 | (when (seq listeners)
49 | (let [event {:domain domain
50 | :event event
51 | :params (:params msg)}]
52 | (submit! #(doseq [listener listeners]
53 | (listener event)))))))
54 |
55 | (defn unlisten [connection domain event callback]
56 | (swap! (:event-listeners connection) update [domain event]
57 | #(disj (or % #{}) callback)))
58 |
59 | (defn listen
60 | "Listen to an event in the specific domain. Invokes callback when an event is
61 | received.
62 |
63 | Returns a 0-arity function that will remove the listener when invoked."
64 | [connection domain event callback]
65 |
66 | (swap! (:event-listeners connection) update [domain event]
67 | #(conj (or % #{}) callback))
68 | #(unlisten connection domain event callback))
69 |
70 |
71 | (defn- on-receive-text [requests event-listeners-atom]
72 | (let [builder (StringBuilder.)]
73 | (fn [_ws msg last?]
74 | (.append builder msg)
75 | (when last?
76 | (try
77 | (let [{id :id :as json-msg} (parse-json (str builder))]
78 | (if id
79 | ;; Has id: this is a response to our previously sent command
80 | (let [callback (@requests id)]
81 | (swap! requests dissoc id)
82 | (submit! #(callback json-msg)))
83 | ;; This is an event
84 | (publish-event @event-listeners-atom json-msg)))
85 | (catch Throwable t
86 | (log/error "Exception in devtools WebSocket receive, msg: " msg
87 | ", throwable: " t))
88 | (finally
89 | (.setLength builder 0)))))))
90 |
91 | (defn- on-close
92 | [_ws code reason]
93 | (log/info "WebSocket connection closed with status code and reason:" code reason))
94 |
95 | (defn- wait-for-remote-debugging-port [host port max-wait-time-ms]
96 | (let [wait-until (+ (System/currentTimeMillis) max-wait-time-ms)
97 | url (str "http://" host ":" port "/json/version")
98 | get! #(try
99 | (http/get url)
100 | (catch Exception e
101 | (log/trace "Exception while waiting for remote debugging port request" e)
102 | nil))]
103 | (loop [response (get!)]
104 | (cond
105 | (= (:status response) 200)
106 | :ok
107 |
108 | (> (System/currentTimeMillis) wait-until)
109 | (throw (ex-info "Chrome remote debugging port not up"
110 | {:host host :port port
111 | :max-wait-time-ms max-wait-time-ms}))
112 |
113 | :else
114 | (do (Thread/sleep 100)
115 | (recur (get!)))))))
116 |
117 | (defn inspectable-pages
118 | "Collect the list of inspectable pages returned by the DevTools protocol."
119 | ([host port]
120 | (inspectable-pages host port 1000))
121 | ([host port max-wait-time-ms]
122 | (wait-for-remote-debugging-port host port max-wait-time-ms)
123 | (let [response (http/get (str "http://" host ":" port "/json/list"))]
124 | (some->> response
125 | :body
126 | parse-json))))
127 |
128 | (defn- first-inspectable-page [pages]
129 | (or (some->> pages
130 | (filter (comp #{"page"} :type))
131 | (keep :web-socket-debugger-url)
132 | first)
133 | (throw (ex-info "No debuggable pages found. In headless mode, Chrome requires a :url-to-open parameter in options."
134 | {:pages pages}))))
135 |
136 | #_(defn make-ws-client
137 | "Constructs ws client. Idle timeout defaults to 0, which means keep it
138 | alive for the session. The `max-msg-size-mb` defaults to 1MB."
139 | [ & [{:keys [idle-timeout max-msg-size-mb]
140 | :or {idle-timeout 0
141 | max-msg-size-mb (* 1024 1024)}}]]
142 | (let [client (ws/client)]
143 | (doto (.getPolicy client)
144 | (.setIdleTimeout idle-timeout)
145 | (.setMaxTextMessageSize max-msg-size-mb))
146 | client))
147 |
148 | (def ^:private
149 | default-ws-handlers
150 | {:on-binary (fn [& args] (log/error "Should not receive binary messages, args: " args))
151 | :on-error (fn [& args]
152 | (log/error
153 | "Error in devtools WebSocket connection; throwable:" args))
154 | :on-close on-close
155 | :on-open (fn [^WebSocket ws]
156 | (log/info "Inspector WebSocket connected: " ws)
157 | (.request ws 1))
158 | :on-ping (fn [^WebSocket ws _msg]
159 | (.request ws 1)
160 | nil)
161 | :on-pong (fn [^WebSocket ws _msg]
162 | (.request ws 1)
163 | nil)})
164 |
165 | (defn connect-url
166 | "Establish a websocket connection to web-socket-debugger-url, as given by
167 | inspectable-pages."
168 | [web-socket-debugger-url & [ws-builder-opts]]
169 | (assert web-socket-debugger-url)
170 | (let [;; Request id to callback
171 | requests (atom {})
172 |
173 | ;; Event listeners by event domain and type
174 | event-listeners (atom {})]
175 |
176 | (->Connection
177 | (ws/build-websocket web-socket-debugger-url
178 | (merge
179 | default-ws-handlers
180 | {:on-text (on-receive-text requests event-listeners)})
181 | (or ws-builder-opts {}))
182 | requests
183 | event-listeners)))
184 |
185 | (defn connect
186 | "Establish a websocket connection to the DevTools protocol at host:port.
187 | Selects the first inspectable page returned; to attach to a specific page,
188 | see connect-url. Initial connection will be retried for up to
189 | max-wait-time-ms milliseconds (default 1000) before giving up."
190 | ([]
191 | (connect "localhost" 9222))
192 | ([host port]
193 | (connect host port 1000))
194 | ([host port max-wait-time-ms]
195 | (connect host port max-wait-time-ms {}))
196 | ([host port max-wait-time-ms ws-builder-options]
197 | (when max-wait-time-ms
198 | (wait-for-remote-debugging-port host port max-wait-time-ms))
199 | (let [url (-> (inspectable-pages host port)
200 | (first-inspectable-page))]
201 | (connect-url url ws-builder-options))))
202 |
203 | (defn send-command-async
204 | "Send command and return a promise for its result."
205 | [{requests :requests con :ws-connection} payload id]
206 | (let [p (promise)]
207 | (swap! requests assoc id #(deliver p %))
208 | (ws/send con (cheshire/encode payload))
209 | p))
210 |
211 | (defn send-command
212 | "Send command synchronously. Blocks until result is done and returns it."
213 | [connection payload id]
214 | @(send-command-async connection payload id))
215 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/impl/define.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.impl.define
2 | "Macro for defining a domain of commands."
3 | (:require [clj-chrome-devtools.protocol-definitions :as proto]
4 | [clj-chrome-devtools.impl.connection :as connection]
5 | [clojure.string :as str]
6 | [clj-chrome-devtools.impl.util :refer [camel->clojure]]
7 | [clojure.spec.alpha :as s]
8 | [clojure.pprint :as pprint]))
9 |
10 |
11 | (def to-symbol (comp symbol camel->clojure))
12 |
13 | (defn process-doc [doc]
14 | (some-> doc
15 | (str/replace #"" "`")
16 | (str/replace #"
" "`")))
17 |
18 | (defn- describe-map-keys [ks]
19 | (let [max-key-length (reduce max 0 (map (comp count camel->clojure :name) ks))]
20 | (str "\n\n Key " (str/join (repeat (- max-key-length 2) " ")) "| Description "
21 | "\n " (str/join (repeat (+ 2 max-key-length) "-")) "|------------ \n"
22 | (str/join "\n"
23 | (map #(str (format (str " :%-" max-key-length "s | %s")
24 | (camel->clojure (:name %))
25 | (process-doc (:description %)))
26 | (when (:optional %)
27 | " (optional)"))
28 | ks)))))
29 |
30 | (def kw (comp keyword camel->clojure))
31 |
32 | (defn ns-kw [string]
33 | (keyword (str *ns*) (camel->clojure string)))
34 |
35 | (defn keys-spec [properties]
36 | (let [{opt-un true req-un false} (group-by (comp boolean :optional) properties)]
37 | `(s/keys ~@(when-not (empty? req-un)
38 | `(:req-un [~@(map (comp ns-kw :name) req-un)]))
39 | ~@(when-not (empty? opt-un)
40 | `(:opt-un [~@(map (comp ns-kw :name) opt-un)])))))
41 |
42 | (defn spec-for-type [{type :type :as t}]
43 | (if (:enum t)
44 | ;; Enumerated type, just output the set of valid values
45 | (into #{} (:enum t))
46 |
47 | (case type
48 | "object" (keys-spec (:properties t))
49 | "string" `string?
50 | "integer" `integer?
51 | "number" `number?
52 | "boolean" `boolean?
53 | "array" `(s/coll-of ~(spec-for-type (:items t)))
54 | `any?)))
55 |
56 | (defmacro define-type-specs [domain]
57 | `(do
58 | ~@(for [{id :id type :type :as t} (proto/types-for-domain domain)
59 | :let [name-kw (ns-kw id)]]
60 |
61 | `(do
62 | ;; If this is an object, create specs for basic type keys
63 | ~@(for [{name :name :as property-type} (:properties t)
64 | :when (#{"string" "number" "integer" "boolean" "array"} type)]
65 | `(s/def ~(ns-kw name)
66 | ~(spec-for-type property-type)))
67 | (s/def ~name-kw ~(spec-for-type t))))))
68 |
69 | (defn generate-type-specs [domain]
70 | (mapcat
71 | (fn [{id :id type :type :as t}]
72 | (let [name-kw (ns-kw id)]
73 | (concat
74 | ;; If this is an object, create specs for basic type keys
75 | (for [{name :name :as property-type} (:properties t)
76 | :when (#{"string" "number" "integer" "boolean" "array"} type)]
77 | `(s/def ~(ns-kw name)
78 | ~(spec-for-type property-type)))
79 | [`(s/def ~name-kw ~(spec-for-type t))])))
80 | (proto/types-for-domain domain)))
81 |
82 | (defmacro define-command-functions [domain]
83 | `(do
84 | ~@(for [{:keys [name description parameters returns]} (proto/commands-for-domain domain)
85 | :let [fn-name (to-symbol name)
86 | params (mapv (comp to-symbol :name) parameters)
87 | param-names (zipmap (map (comp keyword camel->clojure :name) parameters)
88 | (map :name parameters))
89 | [required-params optional-params] (split-with (comp not :optional) params)]]
90 | `(do
91 | (defn ~fn-name
92 | ~(str (process-doc description)
93 | (when-not (empty? parameters)
94 | (str "\n\nParameters map keys:\n"
95 | (describe-map-keys parameters)))
96 | (when-not (empty? returns)
97 | (str "\n\nReturn map keys:\n"
98 | (describe-map-keys returns))))
99 | ([] (~(to-symbol name) (connection/get-current-connection) {}))
100 | ([{:keys [~@params] :as ~'params}]
101 | (~(to-symbol name) (connection/get-current-connection) ~'params))
102 | ([~'connection {:keys [~@params] :as ~'params}]
103 | (let [id# (next-command-id!)
104 | method# ~(str domain "." name)
105 | payload# (command-payload id# method# ~'params
106 | ~param-names)
107 | result (connection/send-command ~'connection payload# id#)]
108 | (if-let [error# (:error result#)]
109 | (throw (ex-info (str "Error in command " method# ": " (:message error#))
110 | {:request payload#
111 | :error error#}))
112 | (:result result#)))))
113 | (s/fdef ~fn-name
114 | :args (s/or :no-args
115 | (s/cat)
116 |
117 | :just-params
118 | (s/cat :params ~(keys-spec parameters))
119 |
120 | :connection-and-params
121 | (s/cat
122 | :connection (s/? connection/connection?)
123 | :params ~(keys-spec parameters)))
124 | :ret ~(keys-spec returns))))))
125 |
126 | (defn generate-command-functions [domain]
127 | (mapcat
128 | (fn [{:keys [name description parameters returns]}]
129 | (let [fn-name (to-symbol name)
130 | params (mapv (comp to-symbol :name) parameters)
131 | param-names (zipmap (map (comp keyword camel->clojure :name) parameters)
132 | (map :name parameters))
133 | [required-params optional-params] (split-with (comp not :optional) params)]
134 | [`(defn ~fn-name
135 | ~(str (process-doc description)
136 | (when-not (empty? parameters)
137 | (str "\n\nParameters map keys:\n"
138 | (describe-map-keys parameters)))
139 | (when-not (empty? returns)
140 | (str "\n\nReturn map keys:\n"
141 | (describe-map-keys returns))))
142 | ([] (~(to-symbol name) (connection/get-current-connection) {}))
143 | ([{:keys [~@params] :as ~'params}]
144 | (~(to-symbol name) (connection/get-current-connection) ~'params))
145 | ([~'connection {:keys [~@params] :as ~'params}]
146 | (clj-chrome-devtools.impl.command/command
147 | ~'connection ~domain ~name ~'params ~param-names)))
148 | `(s/fdef ~fn-name
149 | :args (s/or :no-args
150 | (s/cat)
151 |
152 | :just-params
153 | (s/cat :params ~(keys-spec parameters))
154 |
155 | :connection-and-params
156 | (s/cat
157 | :connection (s/? connection/connection?)
158 | :params ~(keys-spec parameters)))
159 | :ret ~(keys-spec returns))]))
160 | (proto/commands-for-domain domain)))
161 |
162 | (defn call-in-ns [ns fun]
163 | (let [old-ns (ns-name *ns*)]
164 | (in-ns ns)
165 | (let [ret (fun)]
166 | (in-ns old-ns)
167 | ret)))
168 |
169 | (defn pretty-print-code [the-ns code]
170 | (str/join "\n"
171 | (map #(-> (with-out-str
172 | (pprint/pprint %))
173 |
174 | ;; Make ns references pretties
175 | (str/replace "clojure.spec.alpha/" "s/")
176 | (str/replace "clj-chrome-devtools.impl.connection/" "c/")
177 | (str/replace "clj-chrome-devtools.impl.command/" "cmd/")
178 | (str/replace "clojure.core/" "")
179 |
180 | ;; Use same ns keywords
181 | (str/replace (str ":" the-ns "/")
182 | (str "::"))) code)))
183 |
184 | #_(defmacro define-event-handlers [domain]
185 | `(do
186 | ~@(for [{:keys [name parameters description] :as event} (proto/events-for-domain domain)
187 | :let [fn-name (symbol (str "on-" (camel->clojure name)))]]
188 | `(defn ~fn-name
189 | ~(str "Register handler for " name " event.\n" description "\n\n"
190 | (when-not (empty? parameters)
191 | (str "The handler will be called with a map with the following keys: "
192 | (describe-map-keys parameters)))
193 | "\n\nReturns a 0 arity function that will remove this handler when called.")
194 | [connection# handler#]
195 | ))))
196 |
197 |
198 | (defmacro define-domain [domain]
199 | `(do
200 | (define-type-specs ~domain)
201 | (define-command-functions ~domain)
202 | #_(define-event-handlers domain)))
203 |
204 | (defn -main [& args]
205 | (doseq [{:keys [domain description]} (proto/all-domains)]
206 | (let [clj-name (camel->clojure domain)
207 | file-name (str "src/clj_chrome_devtools/commands/" (str/lower-case (str/replace clj-name "-" "_")) ".clj")
208 | ns-name (str "clj-chrome-devtools.commands." (str/lower-case clj-name))
209 | ns-sym (symbol ns-name)]
210 | (println "Generate command namespace: " file-name)
211 | (spit file-name
212 | (str "(ns clj-chrome-devtools.commands." (str/lower-case clj-name) "\n"
213 | (when description
214 | (str " " (pr-str (process-doc description)) "\n"))
215 | " (:require [clojure.spec.alpha :as s]\n"
216 | " [clj-chrome-devtools.impl.command :as cmd]\n"
217 | " [clj-chrome-devtools.impl.connection :as c]))\n\n"
218 | (pretty-print-code ns-name (call-in-ns ns-sym #(generate-type-specs domain)))
219 | (pretty-print-code ns-name (call-in-ns ns-sym #(generate-command-functions domain))))))))
220 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/impl/util.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.impl.util
2 | (:require [clojure.string :as str]))
3 |
4 | (defn camel->clojure [string]
5 | (-> string
6 | ;; borrowed from r0man/inflections
7 | ;; -------------------------------
8 | ;; consoleAPICalled -> console-api-called
9 | (str/replace #"([A-Z]+)([A-Z][a-z])" "$1-$2")
10 | ;; console1APICalled -> console1-api-called
11 | (str/replace #"([a-z\d])([A-Z])" "$1-$2")
12 | ;; console api called -> console-api-called
13 | (str/replace #"\s+" "-")
14 | ;; ;; console_api_called -> console-api-called
15 | (str/replace #"_" "-")
16 | ;; Lower case everything
17 | (str/lower-case)))
18 |
19 | (defn random-free-port []
20 | (let [s (doto (java.net.ServerSocket. 0)
21 | (.setReuseAddress true))]
22 | (try
23 | (.getLocalPort s)
24 | (finally (.close s)))))
25 |
--------------------------------------------------------------------------------
/src/clj_chrome_devtools/protocol_definitions.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.protocol-definitions
2 | "Loads CDP protocol definition JSON files for consumption by def macros."
3 | (:require [cheshire.core :as cheshire]))
4 |
5 | (defn- load-json [json-file]
6 | (as-> json-file it
7 | (str "devtools-protocol/json/" it)
8 | (slurp it)
9 | (cheshire/parse-string it true)))
10 |
11 | (def protocol-files ["browser_protocol.json" "js_protocol.json"])
12 |
13 | (defn all-domains []
14 | (mapcat (comp :domains load-json) protocol-files))
15 |
16 | (defn domain-by-name [domain]
17 | (some #(when (= (:domain %) domain) %) (all-domains)))
18 |
19 | (defn commands-for-domain [domain]
20 | (:commands (domain-by-name domain)))
21 |
22 | (defn types-for-domain [domain]
23 | (:types (domain-by-name domain)))
24 |
25 | (defn events-for-domain [domain]
26 | (:events (domain-by-name domain)))
27 |
28 | (defn domains []
29 | (into #{}
30 | (map :domain)
31 | (all-domains)))
32 |
--------------------------------------------------------------------------------
/test/clj_chrome_devtools/automation_test.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.automation-test
2 | (:require [clj-chrome-devtools.automation :as a]
3 | [clj-chrome-devtools.automation.fixture :refer [create-chrome-fixture]]
4 | [clojure.spec.test.alpha :as stest]
5 | [clojure.test :as t :refer [deftest is testing]]
6 | [clojure.string :as str]
7 | [clojure.java.io :as io]))
8 |
9 | (stest/instrument)
10 |
11 | (defonce chrome-fixture (create-chrome-fixture {:url-to-open (str (io/resource "test-page.html"))}))
12 | (t/use-fixtures :each chrome-fixture)
13 |
14 | (deftest evaluate
15 | (testing "a call that takes longer than the default timeout should throw an exception"
16 | (let [[prior-default-timeout _] (reset-vals! a/default-timeout-ms 100)]
17 | (is (thrown-with-msg?
18 | RuntimeException
19 | #"^Timeout!.+"
20 | (a/evaluate "Array(1024 ** 3).fill().map(Math.random).length")))
21 | (reset! a/default-timeout-ms prior-default-timeout)))
22 | (testing "a call that takes longer than the supplied timeout should throw an exception"
23 | (is (thrown-with-msg?
24 | RuntimeException
25 | #"^Timeout!.+"
26 | (a/evaluate @a/current-automation
27 | "Array(1024 ** 3).fill().map(Math.random).length"
28 | 100)))))
29 |
30 |
31 | (deftest pdf-print-test
32 | (a/to "http://example.com")
33 | (a/print-pdf @a/current-automation "example.pdf")
34 | (let [pdf (slurp "example.pdf")]
35 | (is (str/starts-with? pdf "%PDF-1.4")) ; file exists and starts with proper PDF header
36 | (is (> (count pdf) 30000)))) ; file should be little over 30k
37 |
--------------------------------------------------------------------------------
/test/clj_chrome_devtools/chrome_test.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.chrome-test
2 | "Some tests with an actual running Chrome"
3 | (:require [clj-chrome-devtools.automation.fixture :refer [create-chrome-fixture]]
4 | [clj-chrome-devtools.automation :refer :all]
5 | [clojure.test :as t :refer [deftest is testing]]
6 | [clojure.java.io :as io]
7 | [clojure.spec.test.alpha :as stest]))
8 |
9 | (stest/instrument)
10 |
11 | (def test-page
12 | (io/resource "test-page.html"))
13 |
14 | (defonce chrome-fixture (create-chrome-fixture {:url-to-open (str test-page)}))
15 | (t/use-fixtures :each chrome-fixture)
16 |
17 | (deftest simple-page-load
18 | (to test-page)
19 | (is (= (map text-of (sel "ul#thelist li")) '("foo" "bar" "baz"))))
20 |
21 | (deftest selectors
22 | (to test-page)
23 | (testing "Selectors work in place of node-refences"
24 | (is (= "0" (text-of "#counter")))
25 | (click [:div.countertest :button.increment])
26 | (is (= "1" (text-of [:#counter])))
27 | (click (sel1 "button.increment"))
28 | (is (= "2" (text-of "div#counter")))
29 | (double-click "button.reset")
30 | (is (= "0" (text-of [:div#counter])))))
31 |
32 | (deftest input
33 | (to test-page)
34 | (testing "Typing into an input field works"
35 | (is (= "NO GREETING YET" (text-of "#greeting")))
36 | (doseq [txt ["old friend"
37 | "foo@bar"
38 | "keys [ that require $ modifiers"]]
39 | (input-text [:#greeter :input] txt)
40 | (click "#greeter button")
41 | (is (= (str "Hello, " txt "!") (text-of [:#greeting])))
42 | (clear-text-input [:#greeter :input]))))
43 |
--------------------------------------------------------------------------------
/test/clj_chrome_devtools/domain_test.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.domain-test
2 | "Test that all namespaces can be required and have public vars."
3 | (:require [clojure.test :as t :refer [deftest is]]))
4 |
5 | (def domains '[clj-chrome-devtools.commands.accessibility
6 | clj-chrome-devtools.commands.animation
7 | clj-chrome-devtools.commands.application-cache
8 | clj-chrome-devtools.commands.audits
9 | clj-chrome-devtools.commands.browser
10 | clj-chrome-devtools.commands.cache-storage
11 | clj-chrome-devtools.commands.console
12 | clj-chrome-devtools.commands.css
13 | clj-chrome-devtools.commands.database
14 | clj-chrome-devtools.commands.debugger
15 | clj-chrome-devtools.commands.device-orientation
16 | clj-chrome-devtools.commands.dom
17 | clj-chrome-devtools.commands.dom-debugger
18 | clj-chrome-devtools.commands.dom-snapshot
19 | clj-chrome-devtools.commands.dom-storage
20 | clj-chrome-devtools.commands.emulation
21 | clj-chrome-devtools.commands.heap-profiler
22 | clj-chrome-devtools.commands.indexed-db
23 | clj-chrome-devtools.commands.input
24 | clj-chrome-devtools.commands.inspector
25 | clj-chrome-devtools.commands.io
26 | clj-chrome-devtools.commands.layer-tree
27 | clj-chrome-devtools.commands.log
28 | clj-chrome-devtools.commands.memory
29 | clj-chrome-devtools.commands.network
30 | clj-chrome-devtools.commands.overlay
31 | clj-chrome-devtools.commands.page
32 | clj-chrome-devtools.commands.performance
33 | clj-chrome-devtools.commands.profiler
34 | clj-chrome-devtools.commands.runtime
35 | clj-chrome-devtools.commands.schema
36 | clj-chrome-devtools.commands.security
37 | clj-chrome-devtools.commands.service-worker
38 | clj-chrome-devtools.commands.storage
39 | clj-chrome-devtools.commands.system-info
40 | clj-chrome-devtools.commands.target
41 | clj-chrome-devtools.commands.tethering
42 | clj-chrome-devtools.commands.tracing])
43 |
44 | (deftest require-domain-namespaces
45 | (doseq [ns domains]
46 | (require ns)
47 | (is (>= (count (ns-publics ns)) 1))))
48 |
--------------------------------------------------------------------------------
/test/clj_chrome_devtools/impl/connection_test.clj:
--------------------------------------------------------------------------------
1 | (ns clj-chrome-devtools.impl.connection-test
2 | (:require [clj-chrome-devtools.automation :refer [create-automation sel text-of to]]
3 | [clj-chrome-devtools.automation.fixture :refer [create-chrome-fixture]]
4 | [clj-chrome-devtools.impl.connection :as c]
5 | [clj-chrome-devtools.impl.util :as util]
6 | [clojure.java.io :as io]
7 | [clojure.spec.test.alpha :as stest]
8 | [clojure.test :as t :refer [deftest is testing]])
9 | (:import [java.util.concurrent CompletionException]))
10 |
11 | (stest/instrument)
12 |
13 | ;; We need to start Chrome up listening for devtools connections on a random free port, and then
14 | ;; pass the same port number to c/connect.
15 | (defonce port (util/random-free-port))
16 |
17 | (defonce chrome-fixture (create-chrome-fixture {:remote-debugging-port port
18 | :url-to-open (io/resource "test-page.html")}))
19 | (t/use-fixtures :each chrome-fixture)
20 |
21 | (defn- make-conn
22 | "The main reason we need this is so it’ll use the value of the port var. See the comment on that
23 | var above."
24 | []
25 | (c/connect "localhost" port))
26 |
27 |
28 | (def test-page
29 | (io/resource "test-page.html"))
30 |
31 | (deftest closeable
32 | (testing "Connection objects should work with (be closed by) with-open"
33 | (let [conn (make-conn)
34 | auto (create-automation conn)]
35 | (with-open [_ conn]
36 | ;; Simple validation that the connection works
37 | (to auto test-page)
38 | (is (= (map #(text-of auto %)
39 | (sel auto "ul#thelist li"))
40 | '("foo" "bar" "baz"))))
41 | (is (thrown-with-msg?
42 | CompletionException #"Output closed"
43 | (to auto test-page))))))
44 |
--------------------------------------------------------------------------------
/test/test-page.html:
--------------------------------------------------------------------------------
1 |
2 |
3 | clj-chrome-devtools test page
4 |
18 |
19 |
20 |
21 | - foo
22 | - bar
23 | - baz
24 |
25 |
26 |
27 |
28 |
29 | id |
30 | name |
31 |
32 |
33 |
34 |
35 | 1 |
36 | Foo Barsky |
37 |
38 |
39 | 2 |
40 | Alan Smithee |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
0
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
NO GREETING YET
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/update-devtools-protocol.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | git clone https://github.com/ChromeDevTools/devtools-protocol
4 |
5 | clojure -m clj-chrome-devtools.impl.define
6 |
7 | rm -rf devtools-protocol
8 |
--------------------------------------------------------------------------------