#[must_use]
pub fn is_javascript_global_builtin(name: &str) -> bool {
matches!(
name,
"Array" | "Object" | "Number" | "String" | "Boolean" | "BigInt"
| "Symbol" | "Function" | "Math" | "JSON" | "Reflect" | "Proxy"
| "Date" | "RegExp" | "Promise" | "Map" | "Set" | "WeakMap"
| "WeakSet" | "WeakRef" | "Iterator" | "Generator" | "Intl"
| "Error" | "TypeError" | "RangeError" | "SyntaxError"
| "ReferenceError" | "EvalError" | "URIError" | "AggregateError"
| "ArrayBuffer" | "SharedArrayBuffer" | "DataView" | "Int8Array"
| "Uint8Array" | "Uint8ClampedArray" | "Int16Array" | "Uint16Array"
| "Int32Array" | "Uint32Array" | "Float32Array" | "Float64Array"
| "BigInt64Array" | "BigUint64Array"
| "parseInt" | "parseFloat" | "isNaN" | "isFinite" | "structuredClone"
| "encodeURIComponent" | "decodeURIComponent" | "encodeURI" | "decodeURI"
| "queueMicrotask" | "setTimeout" | "clearTimeout" | "setInterval"
| "clearInterval"
| "globalThis" | "global" | "self" | "window" | "console" | "process"
| "TextEncoder" | "TextDecoder" | "URL" | "URLSearchParams" | "Blob"
| "File" | "FormData" | "Headers" | "Request" | "Response" | "Buffer"
| "AbortController" | "AbortSignal" | "Event" | "EventTarget"
)
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[non_exhaustive]
pub enum GlobalPresence {
Present,
Absent,
Unknown,
}
const NON_DOM_ABSENT_GLOBALS: &[&str] = &["window", "self", "document"];
#[must_use]
pub fn global_member_presence(name: &str) -> GlobalPresence {
if NON_DOM_ABSENT_GLOBALS.contains(&name) {
return GlobalPresence::Absent;
}
if matches!(name, "structuredClone" | "crypto" | "fetch") {
return GlobalPresence::Unknown;
}
if is_javascript_global_builtin(name) {
GlobalPresence::Present
} else {
GlobalPresence::Unknown
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn recognizes_known_globals() {
for name in ["Array", "Number", "Reflect", "Proxy", "TextEncoder", "globalThis"] {
assert!(is_javascript_global_builtin(name), "{name} should be a builtin");
}
}
#[test]
fn rejects_user_identifiers() {
for name in ["Foo", "curried", "myHelper", "Circle"] {
assert!(!is_javascript_global_builtin(name), "{name} should not be a builtin");
}
}
#[test]
fn recognized_node_globals_are_present() {
for name in ["Map", "Set", "ArrayBuffer", "Reflect", "Promise", "process"] {
assert_eq!(global_member_presence(name), GlobalPresence::Present, "{name}");
}
}
#[test]
fn dom_only_globals_are_absent() {
for name in ["window", "self", "document"] {
assert_eq!(global_member_presence(name), GlobalPresence::Absent, "{name}");
}
}
#[test]
fn unmodeled_members_are_unknown() {
for name in ["DocumentFragment", "__feature", "structuredClone", "crypto"] {
assert_eq!(global_member_presence(name), GlobalPresence::Unknown, "{name}");
}
}
#[test]
fn presence_tracks_recognition_registry() {
for name in ["Array", "JSON", "Math", "Buffer", "URL", "TextEncoder"] {
assert_ne!(
global_member_presence(name),
GlobalPresence::Unknown,
"recognized builtin {name} should have a decided presence"
);
}
}
}