-
Notifications
You must be signed in to change notification settings - Fork 30
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
implant: add UI scraping subsystem via :scrape automation action
- Loading branch information
Showing
3 changed files
with
171 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
(ns dirac.implant.automation.scrapers | ||
(:require-macros [com.rpl.specter.macros :refer [providepath declarepath transform select select-one select-first]]) | ||
(:require [chromex.support :refer-macros [oget oset ocall oapply]] | ||
[chromex.logging :refer-macros [log warn error info]] | ||
[cljs.pprint :refer [pprint]] | ||
[com.rpl.specter :refer [must continue-then-stay multi-path if-path ALL STAY]] | ||
[dirac.implant.automation.scraping :as scraping :refer [RepWalker select-subrep select-subreps scrape-rep]] | ||
[clojure.string :as string])) | ||
|
||
; -- helpers ---------------------------------------------------------------------------------------------------------------- | ||
|
||
(defn pp-rep [rep] | ||
(with-out-str (pprint rep))) | ||
|
||
(defn widget-rep? [rep] | ||
(some? (re-find #"widget" (str (:class rep))))) | ||
|
||
(defn title-rep? [rep] | ||
(= "title" (:class rep))) | ||
|
||
(defn subtitle-rep? [rep] | ||
(= "subtitle" (:class rep))) | ||
|
||
(defn print-list [list] | ||
(if (empty? list) | ||
"no items displayed" | ||
(str "displayed " (count list) " items:\n" | ||
(string/join "\n" (map #(str " * " (or % "<empty>")) list))))) | ||
|
||
; -- call stack UI ---------------------------------------------------------------------------------------------------------- | ||
|
||
(defn is-callstack-title-el? [el] | ||
(= (oget el "textContent") "Call Stack")) | ||
|
||
(defn find-callstack-pane-element [] | ||
(let [title-els (scraping/query-selector "html /deep/ .sidebar-pane-title")] | ||
(if-let [callstack-title-el (select-first [ALL is-callstack-title-el?] title-els)] | ||
(oget callstack-title-el "nextElementSibling")))) | ||
|
||
(defn get-callstack-pane-rep [callstack-pane-el] | ||
(scrape-rep callstack-pane-el)) | ||
|
||
(defn select-callstack-widget-rep [rep] | ||
; example output | ||
(comment | ||
{:tag "div", | ||
:class "widget vbox", | ||
:children | ||
({:tag "div", | ||
:class "list-item selected", | ||
:children ({:tag "div", | ||
:class "subtitle", | ||
:content "core.cljs:10", | ||
:title "http://localhost:9080/compiled/tests/dirac/tests/scenarios/breakpoint/core.cljs:10"} | ||
{:tag "div", | ||
:class "title", | ||
:content "breakpoint-demo", | ||
:title "dirac.tests.scenarios.breakpoint.core/breakpoint-demo"})} | ||
; ... | ||
{:tag "div", | ||
:class "list-item", | ||
:children ({:tag "div", | ||
:class "subtitle", | ||
:content "notifications.cljs:53", | ||
:title "http://localhost:9080/compiled/tests/dirac/automation/notifications.cljs:53"} | ||
{:tag "div", | ||
:class "title", | ||
:content "process-event!", | ||
:title "dirac.automation.notifications/process-event!"})})}) | ||
|
||
(select-subrep widget-rep? rep)) | ||
|
||
(defn print-callstack-function [rep] | ||
(let [{:keys [title content]} rep] | ||
(str content (if title (str " / " title))))) | ||
|
||
(defn print-callstack-location [rep] | ||
(let [{:keys [title content]} rep] | ||
(str content (if title (str " / " title))))) | ||
|
||
; -- general interface for :scrape automation action ------------------------------------------------------------------------ | ||
|
||
(defmulti scrape (fn [name & _args] | ||
(keyword name))) | ||
|
||
(defmethod scrape :default [name & _] | ||
(str "! scraper '" name "' has missing implementation in dirac.implant.automation.scrapers")) | ||
|
||
(defmethod scrape :callstack-pane-functions [_ & _] | ||
(->> (find-callstack-pane-element) | ||
(get-callstack-pane-rep) | ||
(select-callstack-widget-rep) | ||
(select-subreps title-rep?) | ||
(map print-callstack-function) | ||
(print-list))) | ||
|
||
(defmethod scrape :callstack-pane-locations [_ & _] | ||
(->> (find-callstack-pane-element) | ||
(get-callstack-pane-rep) | ||
(select-callstack-widget-rep) | ||
(select-subreps subtitle-rep?) | ||
(map print-callstack-location) | ||
(print-list))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,65 @@ | ||
(ns dirac.implant.automation.scraping | ||
(:require-macros [com.rpl.specter.macros :refer [providepath declarepath select select-first]]) | ||
(:require [chromex.support :refer-macros [oget oset ocall oapply]] | ||
[chromex.logging :refer-macros [log warn error info]] | ||
[com.rpl.specter :refer [must continue-then-stay multi-path if-path ALL]] | ||
[dirac.dom.shim] | ||
[clojure.string :as string])) | ||
|
||
; -- specter walker --------------------------------------------------------------------------------------------------------- | ||
|
||
(declarepath RepWalker) | ||
|
||
(providepath RepWalker | ||
(continue-then-stay | ||
(multi-path | ||
[(must :children) ALL] | ||
(must :shadowRoot)) | ||
RepWalker)) | ||
|
||
; -- helpers ---------------------------------------------------------------------------------------------------------------- | ||
|
||
(defn clean-rep [rep] | ||
(into {} (remove (comp empty? second) rep))) | ||
|
||
(defn select-subrep [pred rep] | ||
(select-first [RepWalker pred] rep)) | ||
|
||
(defn select-subreps [pred rep] | ||
(select [RepWalker pred] rep)) | ||
|
||
; -- DOM reading ------------------------------------------------------------------------------------------------------------ | ||
|
||
(defn query-selector [selector] | ||
(.querySelectorAll js/document selector)) | ||
|
||
(defn get-tag-name [el] | ||
(if-let [tag-name (oget el "tagName")] | ||
(string/lower-case tag-name))) | ||
|
||
(defn get-class-name [el] | ||
(oget el "className")) | ||
|
||
(defn get-children [el] | ||
(oget el "children")) | ||
|
||
(defn get-shadow-root [el] | ||
(oget el "shadowRoot")) | ||
|
||
(defn get-own-text-content [el] | ||
(if (empty? (get-children el)) | ||
(oget el "textContent"))) | ||
|
||
(defn get-title [el] | ||
(oget el "title")) | ||
|
||
; -- DOM scraping ----------------------------------------------------------------------------------------------------------- | ||
|
||
(defn scrape-rep [el] | ||
(if (some? el) | ||
(clean-rep {:tag (get-tag-name el) | ||
:class (get-class-name el) | ||
:content (get-own-text-content el) | ||
:title (get-title el) | ||
:children (doall (map scrape-rep (get-children el))) | ||
:shadowRoot (scrape-rep (get-shadow-root el))}))) |