orinium_browser/engine/js/web_apis/
missing_api_detector.rs1use crate::engine::js::JsRuntime;
17
18pub(crate) const SUSPECT_GLOBALS: &[&str] = &[
21 "AbortController",
22 "AbortSignal",
23 "Blob",
24 "Comment",
25 "CustomElementRegistry",
26 "Document",
27 "DocumentFragment",
28 "Element",
29 "EventTarget",
30 "FileReader",
31 "FormData",
32 "HTMLAudioElement",
33 "HTMLCanvasElement",
34 "HTMLMediaElement",
35 "HTMLScriptElement",
36 "HTMLSlotElement",
37 "HTMLTemplateElement",
38 "HTMLVideoElement",
39 "Headers",
40 "HTMLElement",
41 "IntersectionObserver",
42 "KeyboardEvent",
43 "MediaSource",
44 "MutationObserver",
45 "MouseEvent",
46 "Node",
47 "PointerEvent",
48 "RegExp",
49 "Request",
50 "Response",
51 "ResizeObserver",
52 "SVGElement",
53 "SVGSVGElement",
54 "ShadowRoot",
55 "SourceBuffer",
56 "Text",
57 "TextDecoder",
58 "TextEncoder",
59 "URL",
60 "URLSearchParams",
61 "WheelEvent",
62 "XMLHttpRequest",
63 "cancelAnimationFrame",
64 "customElements",
65 "getComputedStyle",
66 "matchMedia",
67 "performance",
68 "queueMicrotask",
69 "requestAnimationFrame",
70];
71
72pub(crate) const SUSPECT_DOCUMENT_METHODS: &[&str] = &[
77 "adoptedStyleSheets",
78 "body",
79 "createElementNS",
80 "currentScript",
81 "documentElement",
82 "elementFromPoint",
83 "elementsFromPoint",
84 "execCommand",
85 "fonts",
86 "getSelection",
87 "head",
88 "importNode",
89 "pictureInPictureElement",
90 "scripts",
91];
92
93pub(crate) const SUSPECT_ELEMENT_PROTOTYPE_METHODS: &[&str] = &[
96 "attachShadow",
97 "closest",
98 "getAnimations",
99 "getRootNode",
100 "insertAdjacentElement",
101 "matches",
102 "requestFullscreen",
103 "scrollIntoView",
104 "scrollTo",
105];
106
107pub(crate) fn prologue() -> String {
112 let mut code = String::new();
113 code.push_str("(function(){var missing = [];\n");
114 for name in SUSPECT_GLOBALS {
115 code.push_str(&format!(
116 "if (typeof {name} === 'undefined') missing.push('window.{name}');\n"
117 ));
118 }
119 for name in SUSPECT_DOCUMENT_METHODS {
120 code.push_str(&format!(
121 "if (typeof document.{name} === 'undefined') missing.push('document.{name}');\n"
122 ));
123 }
124 for name in SUSPECT_ELEMENT_PROTOTYPE_METHODS {
125 code.push_str(&format!(
126 "if (typeof Element !== 'undefined' && Element.prototype && typeof Element.prototype.{name} === 'undefined') missing.push('Element.prototype.{name}');\n"
127 ));
128 }
129 code.push_str("if (missing.length) console.warn('[missing-api] ' + missing.join(','));\n");
130 code.push_str("}).call(window);\n");
131 code
132}
133
134pub fn install_missing_api_report(runtime: &mut JsRuntime) {
148 runtime.run_script(&prologue(), None);
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154 use crate::engine::html::Parser;
155 use std::rc::Rc;
156
157 #[test]
158 fn prologue_evaluates_without_error() {
159 let dom = Rc::new(Parser::new(r#"<div></div>"#).parse());
160 let mut runtime = JsRuntime::new(dom);
161 install_missing_api_report(&mut runtime);
162 }
164}