Module refinery.lib.scripts.js.analysis.environment
The host environment a script is assumed to run in, and the set of global names that environment
guarantees a bare read resolves rather than throwing a ReferenceError.
A bare read of a name the program neither declares nor assigns reaches the host's global object.
Which names are there is not a language fact but a host one: window exists in a browser and throws
under Node, global the other way around. The deobfuscator's sound default asserts only what every
host shares — GUARANTEED_GLOBALS, the names the ECMAScript specification mandates — and answers
every other bare read may-throw, so no pass drops the ReferenceError an absent host raises. An
analyst who knows where a sample runs pins the host with the djs unit's -e switch, and the reads
that host guarantees become certain, recovering the folds the sound default refuses.
This module is the single datum those decisions read. HostEnvironment.provides() answers, from data
alone, whether a host resolves a name; SemanticModel.read_may_throw is the one seam that consults it.
The data is host-partitioned and, per host, built from the language floor (GUARANTEED_GLOBALS) plus a
conservative set of host-conditional globals: a name is listed only where its presence is certain, since
under-listing costs at most a fold a wider table would recover while over-listing would drop a real
throw. The node set was established by reading the globals out of Node v24 (benign introspection, no
sample executed); the browser and worker sets are the web-platform globals every implementation of
those scopes exposes.
Each pinned host models its current mainstream version — the analyst asserting -e node/-e browser
is asserting a present-day runtime, so recently standardized globals (fetch, structuredClone,
navigator under Node) are treated as present; a sample targeting an older engine is not the case a pin
serves. worker models a dedicated worker: its present set carries the dedicated-worker surface
(XMLHttpRequest, the nested Worker constructor), which a service worker does not share, so -e worker
is the pin for a dedicated worker rather than a service worker.
Expand source code Browse git
"""
The host environment a script is assumed to run in, and the set of global names that environment
guarantees a bare read resolves rather than throwing a `ReferenceError`.
A bare read of a name the program neither declares nor assigns reaches the host's global object.
Which names are there is not a language fact but a host one: `window` exists in a browser and throws
under Node, `global` the other way around. The deobfuscator's sound default asserts only what every
host shares — `GUARANTEED_GLOBALS`, the names the ECMAScript specification mandates — and answers
every other bare read may-throw, so no pass drops the `ReferenceError` an absent host raises. An
analyst who knows where a sample runs pins the host with the `djs` unit's `-e` switch, and the reads
that host guarantees become certain, recovering the folds the sound default refuses.
This module is the single datum those decisions read. `HostEnvironment.provides` answers, from data
alone, whether a host resolves a name; `SemanticModel.read_may_throw` is the one seam that consults it.
The data is host-partitioned and, per host, built from the language floor (`GUARANTEED_GLOBALS`) plus a
conservative set of host-conditional globals: a name is listed only where its presence is certain, since
under-listing costs at most a fold a wider table would recover while over-listing would drop a real
throw. The `node` set was established by reading the globals out of Node v24 (benign introspection, no
sample executed); the `browser` and `worker` sets are the web-platform globals every implementation of
those scopes exposes.
Each pinned host models its *current mainstream* version — the analyst asserting `-e node`/`-e browser`
is asserting a present-day runtime, so recently standardized globals (`fetch`, `structuredClone`,
`navigator` under Node) are treated as present; a sample targeting an older engine is not the case a pin
serves. `worker` models a *dedicated* worker: its present set carries the dedicated-worker surface
(`XMLHttpRequest`, the nested `Worker` constructor), which a service worker does not share, so `-e worker`
is the pin for a dedicated worker rather than a service worker.
"""
from __future__ import annotations
import enum
import operator
from dataclasses import dataclass
from typing import Callable, NamedTuple
from refinery.lib.scripts.js.builtins import ITERATOR_METHODS
class Presence(enum.Enum):
"""
What a pinned host knows about whether a global name resolves. `PRESENT` and `ABSENT` are the two
certain answers a `typeof` fold may act on — present names fold to their type, absent names to
`'undefined'`; `UNKNOWN` means the host neither guarantees nor rules out the name, so a fold that
would assert either abstains. The default `universal` host answers `PRESENT` only for the language
floor and `UNKNOWN` for every other name, since some host defines it and some does not.
"""
PRESENT = 'present'
ABSENT = 'absent'
UNKNOWN = 'unknown'
GUARANTEED_GLOBAL_TYPEOF: dict[str, str] = {
'globalThis': 'object',
'NaN': 'number',
'Infinity': 'number',
'undefined': 'undefined',
'eval': 'function',
'isFinite': 'function',
'isNaN': 'function',
'parseFloat': 'function',
'parseInt': 'function',
'decodeURI': 'function',
'decodeURIComponent': 'function',
'encodeURI': 'function',
'encodeURIComponent': 'function',
'Object': 'function',
'Function': 'function',
'Boolean': 'function',
'Symbol': 'function',
'BigInt': 'function',
'Error': 'function',
'AggregateError': 'function',
'EvalError': 'function',
'RangeError': 'function',
'ReferenceError': 'function',
'SyntaxError': 'function',
'TypeError': 'function',
'URIError': 'function',
'Number': 'function',
'Math': 'object',
'Date': 'function',
'String': 'function',
'RegExp': 'function',
'Array': 'function',
'Int8Array': 'function',
'Uint8Array': 'function',
'Uint8ClampedArray': 'function',
'Int16Array': 'function',
'Uint16Array': 'function',
'Int32Array': 'function',
'Uint32Array': 'function',
'Float32Array': 'function',
'Float64Array': 'function',
'BigInt64Array': 'function',
'BigUint64Array': 'function',
'Map': 'function',
'Set': 'function',
'WeakMap': 'function',
'WeakSet': 'function',
'WeakRef': 'function',
'FinalizationRegistry': 'function',
'ArrayBuffer': 'function',
'DataView': 'function',
'JSON': 'object',
'Promise': 'function',
'Reflect': 'object',
'Proxy': 'function',
}
"""
Maps each `GUARANTEED_GLOBALS` name to the string its `typeof` yields. Because the name resolves in
every host to a value of a fixed type — a constructor or built-in function (`'function'`), a namespace
object such as `Math`/`JSON`/`Reflect` or `globalThis` itself (`'object'`), the two numeric constants
(`'number'`), or `undefined` — the operator's result is host-independent, unlike a host-conditional
alias (`window`, `self`, …) whose `typeof` is `'undefined'` where the host omits the name. This is what
lets a simplification fold `typeof globalThis !== 'undefined'` to `true` for a name it can prove
pristine; the values were established under Node 24. `GUARANTEED_GLOBALS` is the key set of this map, so
the two cannot drift.
"""
GUARANTEED_GLOBALS = frozenset(GUARANTEED_GLOBAL_TYPEOF)
"""
Names the ECMAScript specification mandates as properties of the global object and that every mainstream
engine exposes unconditionally, so a bare read of one is guaranteed to resolve rather than throw a
`ReferenceError`. This is an *existence* allowlist — distinct from the getter-purity and host-presence
sets in `refinery.lib.scripts.js.analysis.effects` — used to decide whether `<global-alias>.name` may be
collapsed to the bare `name` without turning the member read's `undefined` into a throw. It excludes host
and alias names (`window`, `self`, `global`, `top`, `frames`, `console`, timers, `Buffer`, …) that are not
universal, and `SharedArrayBuffer`/`Atomics`, which a conformant host may withhold outside a
cross-origin-isolated context. `GUARANTEED_GLOBAL_TYPEOF` additionally records the `typeof` of each. It is
the provide-set of the `UNIVERSAL` host and the language floor every pinned host builds on.
"""
UNIVERSAL_TYPEOF: dict[str, str] = {**GUARANTEED_GLOBAL_TYPEOF, 'escape': 'function', 'unescape': 'function'}
"""
The `typeof` of every name whose result is the same in every host, so a `typeof` of one folds without a
host pin. It is `GUARANTEED_GLOBAL_TYPEOF` plus `escape` and `unescape`, the Annex B pair every mainstream
engine defines but the existence floor omits: their `typeof` is `'function'` everywhere even though a bare
read of one is not part of the language-mandated `GUARANTEED_GLOBALS` set.
"""
_HOST_CONDITIONAL_TYPEOF: dict[str, str] = {
'global': 'object',
'process': 'object',
'console': 'object',
'window': 'object',
'self': 'object',
'top': 'object',
'parent': 'object',
'frames': 'object',
'document': 'object',
'location': 'object',
'navigator': 'object',
'history': 'object',
'screen': 'object',
'localStorage': 'object',
'sessionStorage': 'object',
'performance': 'object',
'crypto': 'object',
'Atomics': 'object',
'WebAssembly': 'object',
'Intl': 'object',
'Buffer': 'function',
'importScripts': 'function',
'setTimeout': 'function',
'setInterval': 'function',
'setImmediate': 'function',
'clearTimeout': 'function',
'clearInterval': 'function',
'clearImmediate': 'function',
'queueMicrotask': 'function',
'requestAnimationFrame': 'function',
'cancelAnimationFrame': 'function',
'btoa': 'function',
'atob': 'function',
'fetch': 'function',
'structuredClone': 'function',
'SharedArrayBuffer': 'function',
'TextEncoder': 'function',
'TextDecoder': 'function',
'URL': 'function',
'URLSearchParams': 'function',
'XMLHttpRequest': 'function',
'WebSocket': 'function',
'Blob': 'function',
'File': 'function',
'FileReader': 'function',
'FormData': 'function',
'Headers': 'function',
'Request': 'function',
'Response': 'function',
'Event': 'function',
'CustomEvent': 'function',
'MessageChannel': 'function',
'AbortController': 'function',
'Worker': 'function',
'Image': 'function',
'alert': 'function',
'confirm': 'function',
'prompt': 'function',
}
"""
The `typeof` of each host-conditional global when the host defines it: a `typeof` of one folds only under
a pin that answers `Presence.PRESENT` for it, to the string recorded here, or `Presence.ABSENT`, to
`'undefined'`. A namespace or DOM object is `'object'`; a constructor, timer, or plain function is
`'function'`. A present name absent from this map has an unrecorded type, so its `typeof` abstains rather
than guess.
"""
_NODE_GLOBALS = frozenset({
'global',
'Buffer',
'process',
'navigator',
'console',
'setTimeout',
'setInterval',
'setImmediate',
'clearTimeout',
'clearInterval',
'clearImmediate',
'queueMicrotask',
'TextEncoder',
'TextDecoder',
'atob',
'btoa',
'URL',
'URLSearchParams',
'fetch',
'structuredClone',
'performance',
'crypto',
'SharedArrayBuffer',
'Atomics',
'WebAssembly',
'Intl',
})
"""
Global names a current Node exposes beyond `GUARANTEED_GLOBALS`, read out of Node v24. `global` is Node's
same-realm global-object alias. The CommonJS wrapper locals `require`, `module`, `exports`, `__dirname`,
and `__filename` are deliberately absent: they are injected into a CommonJS file's function scope rather
than being properties of the global object, and an ES module does not see them at all, so whether a bare
read of one resolves is the question `refinery.lib.scripts.js.options.ExecutionModel` answers, not a
host-existence one.
"""
_BROWSER_GLOBALS = frozenset({
'window',
'self',
'top',
'parent',
'frames',
'document',
'location',
'navigator',
'history',
'screen',
'localStorage',
'sessionStorage',
'console',
'alert',
'confirm',
'prompt',
'setTimeout',
'setInterval',
'clearTimeout',
'clearInterval',
'requestAnimationFrame',
'cancelAnimationFrame',
'queueMicrotask',
'fetch',
'XMLHttpRequest',
'WebSocket',
'URL',
'URLSearchParams',
'btoa',
'atob',
'TextEncoder',
'TextDecoder',
'performance',
'crypto',
'structuredClone',
'Blob',
'File',
'FileReader',
'FormData',
'Headers',
'Request',
'Response',
'Event',
'CustomEvent',
'MessageChannel',
'AbortController',
'Worker',
'Image',
'Intl',
'WebAssembly',
})
"""
Global names a browser window exposes beyond `GUARANTEED_GLOBALS`. `window` and `self` are the same-realm
aliases of the window's own global object; `top`, `parent`, and `frames` resolve too, but in a framed
document they name another realm's global object, which is why the global-object finder keys its
substitution to `refinery.lib.scripts.js.analysis.model.SAME_REALM_GLOBAL_OBJECT_ALIASES` — which admits
`window` and `self` but not `top`, `parent`, or `frames` — rather than to mere existence. The set is
conservative: a name is listed only where every current browser provides it.
"""
_WORKER_GLOBALS = frozenset({
'self',
'location',
'navigator',
'console',
'setTimeout',
'setInterval',
'clearTimeout',
'clearInterval',
'queueMicrotask',
'fetch',
'XMLHttpRequest',
'WebSocket',
'URL',
'URLSearchParams',
'btoa',
'atob',
'TextEncoder',
'TextDecoder',
'performance',
'crypto',
'structuredClone',
'Blob',
'File',
'FileReader',
'FormData',
'Headers',
'Request',
'Response',
'Event',
'CustomEvent',
'MessageChannel',
'AbortController',
'Worker',
'importScripts',
'Intl',
'WebAssembly',
})
"""
Global names a worker global scope exposes beyond `GUARANTEED_GLOBALS`. `self` is the worker's own
same-realm global-object alias; the window-only names `window`, `top`, `parent`, `frames`, `document`,
and the DOM and storage surface are absent, because a worker has no document and no window to frame.
"""
_NODE_ABSENT = frozenset({
'window',
'self',
'top',
'parent',
'frames',
'document',
'location',
'history',
'screen',
'localStorage',
'sessionStorage',
'alert',
'confirm',
'prompt',
'XMLHttpRequest',
'requestAnimationFrame',
'Image',
'define',
'angular',
})
"""
Well-known browser globals a bare read of which is certain to throw under Node, read out of Node
v24 as `typeof` `'undefined'`, and two a page gets from a library it loads: the `define` of an AMD
loader and AngularJS's `angular`, which code built to run anywhere probes before it hands itself to
them. `navigator` is deliberately absent from this set: Node exposes it, so it is a present name,
not an absent one — the trap a `typeof` fold must not fall into. The set is used only to fold
`typeof <name>` to `'undefined'` under `-e node`; a name neither provided nor listed here stays
unknown.
"""
NODE_BUILTIN_MODULES = frozenset({
'_http_agent',
'_http_client',
'_http_common',
'_http_incoming',
'_http_outgoing',
'_http_server',
'_stream_duplex',
'_stream_passthrough',
'_stream_readable',
'_stream_transform',
'_stream_wrap',
'_stream_writable',
'_tls_common',
'_tls_wrap',
'assert',
'assert/strict',
'async_hooks',
'buffer',
'child_process',
'cluster',
'console',
'constants',
'crypto',
'dgram',
'diagnostics_channel',
'dns',
'dns/promises',
'domain',
'events',
'fs',
'fs/promises',
'http',
'http2',
'https',
'inspector',
'inspector/promises',
'module',
'net',
'os',
'path',
'path/posix',
'path/win32',
'perf_hooks',
'process',
'punycode',
'querystring',
'readline',
'readline/promises',
'repl',
'stream',
'stream/consumers',
'stream/promises',
'stream/web',
'string_decoder',
'sys',
'timers',
'timers/promises',
'tls',
'trace_events',
'tty',
'url',
'util',
'util/types',
'v8',
'vm',
'wasi',
'worker_threads',
'zlib',
'node:sea',
'node:sqlite',
'node:test',
'node:test/reporters',
})
"""
The modules Node's `require` loads from itself rather than from a file, read out of Node v24 as
`require('module').builtinModules`. A name with the `node:` prefix is one Node loads only under that
prefix; every other one it also loads with the prefix.
"""
NODE_MODULES_THAT_RUN_CODE = frozenset({
'inspector',
'inspector/promises',
'module',
'repl',
'vm',
})
"""
The built-in modules through which a program has code run that its text does not hold: `vm` and
`repl` evaluate source text, the inspector evaluates it through a session, and `module` loads any
file and compiles source into a module.
"""
def node_require_runs_no_code(specifier: str) -> bool:
"""
Whether Node's `require` of *specifier* runs no code the file's text does not hold: it names a
built-in module (`NODE_BUILTIN_MODULES`), with or without the `node:` prefix it allows, outside
`NODE_MODULES_THAT_RUN_CODE`. Any other specifier names a file or a package, whose code runs
when it is loaded.
"""
name = specifier
if name.startswith('node:'):
if specifier in NODE_BUILTIN_MODULES:
return True
name = name[5:]
elif F'node:{name}' in NODE_BUILTIN_MODULES:
return False
return name in NODE_BUILTIN_MODULES and name not in NODE_MODULES_THAT_RUN_CODE
_BROWSER_ABSENT = frozenset({
'global',
'Buffer',
'process',
'require',
'module',
'exports',
'__dirname',
'__filename',
'setImmediate',
'clearImmediate',
'importScripts',
})
"""
The Node and worker globals a browser window is certain to lack. These are the names that separate a
Node target from a browser one, so `typeof global`/`typeof Buffer`/`typeof require` fold to `'undefined'`
under `-e browser`.
"""
_WORKER_ABSENT = _BROWSER_ABSENT - frozenset({'importScripts'}) | frozenset({
'window',
'top',
'parent',
'frames',
'document',
'history',
'screen',
'localStorage',
'sessionStorage',
'alert',
'confirm',
'prompt',
'Image',
})
"""
The window-only and Node-only globals a dedicated worker global scope is certain to lack: it has no
document and no window to frame, and it is not Node. `importScripts` is a worker global, so it is excluded
from the Node/browser-absent base this builds on. `requestAnimationFrame` is deliberately *not* listed: a
dedicated worker exposes it through the `AnimationFrameProvider` mixin, so it is left `UNKNOWN` rather than
asserted absent — which would fold `typeof requestAnimationFrame` to `'undefined'` where the host in fact
yields `'function'`.
"""
_WINDOW_EVENT_HANDLERS = frozenset({
'onabort',
'onafterprint',
'onanimationcancel',
'onanimationend',
'onanimationiteration',
'onanimationstart',
'onappinstalled',
'onauxclick',
'onbeforeinput',
'onbeforeinstallprompt',
'onbeforematch',
'onbeforeprint',
'onbeforetoggle',
'onbeforeunload',
'onbeforexrselect',
'onblur',
'oncancel',
'oncanplay',
'oncanplaythrough',
'onchange',
'onclick',
'onclose',
'oncommand',
'oncontentvisibilityautostatechange',
'oncontextlost',
'oncontextmenu',
'oncontextrestored',
'oncuechange',
'ondblclick',
'ondevicemotion',
'ondeviceorientation',
'ondeviceorientationabsolute',
'ondrag',
'ondragend',
'ondragenter',
'ondragleave',
'ondragover',
'ondragstart',
'ondrop',
'ondurationchange',
'onemptied',
'onended',
'onerror',
'onfocus',
'onformdata',
'ongamepadconnected',
'ongamepaddisconnected',
'ongotpointercapture',
'onhashchange',
'oninput',
'oninvalid',
'onkeydown',
'onkeypress',
'onkeyup',
'onlanguagechange',
'onload',
'onloadeddata',
'onloadedmetadata',
'onloadstart',
'onlostpointercapture',
'onmessage',
'onmessageerror',
'onmousedown',
'onmouseenter',
'onmouseleave',
'onmousemove',
'onmouseout',
'onmouseover',
'onmouseup',
'onmousewheel',
'onoffline',
'ononline',
'onpagehide',
'onpagereveal',
'onpageshow',
'onpageswap',
'onpause',
'onplay',
'onplaying',
'onpointercancel',
'onpointerdown',
'onpointerenter',
'onpointerleave',
'onpointermove',
'onpointerout',
'onpointerover',
'onpointerrawupdate',
'onpointerup',
'onpopstate',
'onprogress',
'onratechange',
'onrejectionhandled',
'onreset',
'onresize',
'onscroll',
'onscrollend',
'onscrollsnapchange',
'onscrollsnapchanging',
'onsearch',
'onsecuritypolicyviolation',
'onseeked',
'onseeking',
'onselect',
'onselectionchange',
'onselectstart',
'onslotchange',
'onstalled',
'onstorage',
'onsubmit',
'onsuspend',
'ontimeupdate',
'ontoggle',
'ontransitioncancel',
'ontransitionend',
'ontransitionrun',
'ontransitionstart',
'onunhandledrejection',
'onunload',
'onvolumechange',
'onwaiting',
'onwebkitanimationend',
'onwebkitanimationiteration',
'onwebkitanimationstart',
'onwebkittransitionend',
'onwheel',
})
"""
The event handler attributes of a browser window: properties of the global object whose value the
window calls when the event they name fires, so a function a script stores in one runs with no call
in the file. The set is every name starting with `on` on a window of a current Chromium browser and
its prototype chain. A name only another browser defines is missing, which keeps a store into it
dead.
"""
_WORKER_EVENT_HANDLERS = frozenset({
'onerror',
'onlanguagechange',
'onmessage',
'onmessageerror',
'onrejectionhandled',
'onrtctransform',
'onunhandledrejection',
})
"""
The event handler attributes of a dedicated worker global scope, in the sense of
`_WINDOW_EVENT_HANDLERS`, read out of the same browser.
"""
class JsEngine(enum.Enum):
"""
The engine a host runs scripts in, where every engine the host covers is that one engine. It
answers what the language leaves to the engine: the text a function the language installs
converts to, the text a regular expression converts to, and the characters `Date()` writes at
fixed positions. A host whose engines differ has none, and a fold of any of these refuses there.
The answers of `v8` were read out of Node 24.
"""
v8 = 'v8'
def function_text(self, name: str) -> str:
"""
The text a function the language installs under *name* converts to, which reads as follows
for `[].at`:
function at() { [native code] }
"""
return F'function {name}() {{ [native code] }}'
def regexp_text(self, source: str) -> str:
"""
The text a regular expression without flags converts to, whose pattern *source* is made of
characters standing for themselves: the engine writes an empty pattern as `(?:)` and a slash
as an escaped one, so that the text reads back as the same expression.
"""
escaped = source.replace('/', '\\/') if source else '(?:)'
return F'/{escaped}/'
def date_character(self, index: int) -> str | None:
"""
The character the string `Date()` returns holds at *index* whatever the time, or `None`
where it depends on the time. The string reads as follows and then holds the name of the
time zone, which fixes these positions where the year has four digits:
Www Mmm DD YYYY HH:MM:SS GMT+hhmm
"""
return _V8_DATE_CHARACTERS.get(index)
_V8_DATE_CHARACTERS = {
3 : ' ',
7 : ' ',
10 : ' ',
15 : ' ',
18 : ':',
21 : ':',
24 : ' ',
25 : 'G',
26 : 'M',
27 : 'T',
}
ENGINE_FUNCTIONS = frozenset(('Array', method) for method in ITERATOR_METHODS)
"""
The functions the language installs, by the owner of the prototype holding them and their key,
that a host covering the Windows Script Host does not have: JScript, its engine, has no iterators.
Only a host with one engine is known to have them (`HostEnvironment.has_function`).
"""
@dataclass(frozen=True)
class _EnvironmentSpec:
"""
The existence answer for one host: *provided* is every name a bare read resolves in it, and
*mandated* is the subset the language guarantees, which the delete guard never retracts. A
host-conditional global is a configurable, deletable property of the global object, so a program
that deletes one makes a later bare read of it throw; a language-mandated name is treated as present
regardless, preserving the sound default's behavior exactly where the host adds nothing.
*engine* is the engine every engine the host covers is, where there is one. *handlers* are the
properties of the global object whose value the host calls.
"""
provided: frozenset[str]
mandated: frozenset[str]
absent: frozenset[str] = frozenset()
engine: JsEngine | None = None
handlers: frozenset[str] = frozenset()
def provides(self, name: str) -> bool:
return name in self.provided
def withholds_on_delete(self, name: str) -> bool:
return name in self.provided and name not in self.mandated
def presence(self, name: str) -> Presence:
if name in self.provided:
return Presence.PRESENT
if name in self.absent:
return Presence.ABSENT
return Presence.UNKNOWN
COMMONJS_WRAPPER_PARAMETERS = ('exports', 'require', 'module', '__filename', '__dirname')
"""
The parameters of the function a CommonJS host wraps around a file's text, in their order. Where the
file declares none of these names itself, a bare read of one reads the value the host passed and a
bare assignment writes it; the global scope holds none of them. Code run by a `Function`
construction, an indirect `eval` or a string timer is global code outside that function and does not
see them. A `let`, `const` or `class` declaration of one at the top of the file redeclares a
parameter, which Node refuses to compile as CommonJS; it runs such a file as an ES module.
"""
class FileKind(enum.Enum):
"""
What the code of one file is, decided for a run from the execution model and the file's own text
(`refinery.lib.scripts.js.options.file_kind`):
- `script`: a classic script, whose top-level `var` and function declarations are properties of
the global object.
- `commonjs`: the body of the function a CommonJS host wraps around the text.
- `es_module`: an ES module, strict code throughout.
- `commonjs_or_es_module`: one of the two without saying which; an answer must hold for both.
"""
script = 'script'
commonjs = 'commonjs'
es_module = 'es-module'
commonjs_or_es_module = 'commonjs-or-es-module'
@property
def scopes_declarations_to_the_file(self) -> bool:
return self is not FileKind.script
@property
def may_be_an_es_module(self) -> bool:
return self is FileKind.es_module or self is FileKind.commonjs_or_es_module
@property
def may_be_commonjs(self) -> bool:
return self is FileKind.commonjs or self is FileKind.commonjs_or_es_module
class HostEnvironment(enum.Enum):
"""
The host a script is assumed to run in, selected by the `djs` unit's `-e` switch. `universal` is
the default and asserts only `GUARANTEED_GLOBALS`, so deobfuscation stays byte-identical to an
unpinned run; each other member adds the globals that host guarantees, recovering the folds the
sound default refuses for a name no universal host defines.
"""
universal = 'universal'
node = 'node'
browser = 'browser'
worker = 'worker'
def provides(self, name: str) -> bool:
"""
Whether a bare read of *name* is guaranteed to resolve in this host rather than throw a
`ReferenceError`, judged from the host's global-name data alone.
"""
return _SPECS[self].provides(name)
def withholds_on_delete(self, name: str) -> bool:
"""
Whether *name* is a host-conditional global whose presence a `delete` of it retracts, as opposed
to a language-mandated name the guard leaves present. A name this answers `True` for is withheld
program-wide once the program deletes it off a same-realm global alias anywhere, which over-keeps
a read's throw rather than dropping one, and so stays sound.
"""
return _SPECS[self].withholds_on_delete(name)
def presence(self, name: str) -> Presence:
"""
Whether this host is certain *name* resolves (`PRESENT`), certain it does not (`ABSENT`), or
neither (`UNKNOWN`). `provides` is the `PRESENT` half; the `ABSENT` half names the well-known
globals of *other* hosts this one is characterized to lack, so that `typeof <name>` folds to
`'undefined'` under a pin without asserting absence for a name merely left off the present set.
"""
return _SPECS[self].presence(name)
def has_function(self, owner: str | None, key: str) -> bool:
"""
Whether a call of the function the language installs under *key* on the prototype of the
constructor *owner*, or as a global where *owner* is `None`, finds that function in this
host. Every host is taken to have each such function but those of `ENGINE_FUNCTIONS`, which
only a host with one engine is known to have.
"""
return self.engine is not None or (owner, key) not in ENGINE_FUNCTIONS
def calls_handler(self, name: str) -> bool:
"""
Whether some host this one covers calls the function a script stores in the property *name*
of the global object, an event handler attribute such as the `onload` of a browser window.
The host calls it with no call in the file, so a store there is never dead. The default
`universal` covers browser windows and workers, so their handlers are called there too, also
in a Windows Script Host, where the name is an ordinary global.
"""
return name in _SPECS[self].handlers
@property
def engine(self) -> JsEngine | None:
"""
The engine every engine this host covers is, or `None` where they may differ. Only `node`
has one. The Windows Script Host, which `universal` covers, writes the text of a function
the language installs with a line break before `function`, before `[native code]`, and on
either side of the closing brace, so it shares no character with what V8 writes; the
engines of the browsers are not measured.
"""
return _SPECS[self].engine
def typeof_of_global(name: str, environment: HostEnvironment) -> str | None:
"""
The string `typeof name` yields for a global *name* under *environment*, or `None` when the answer is
host-dependent and the host is not pinned to one that settles it. A name whose `typeof` is the same in
every host (`UNIVERSAL_TYPEOF`) folds always; a host-conditional name folds only where the pin makes
it certainly present — to its recorded type — or certainly absent — to `'undefined'`. The default
`universal` host settles only the universal names, so `typeof Buffer` and `typeof window` abstain
unpinned, exactly as a bare read of either is answered may-throw.
"""
if name in UNIVERSAL_TYPEOF:
return UNIVERSAL_TYPEOF[name]
presence = environment.presence(name)
if presence is Presence.ABSENT:
return 'undefined'
if presence is Presence.PRESENT:
return _HOST_CONDITIONAL_TYPEOF.get(name)
return None
_CLOCK_COMPARISONS: dict[str, Callable[[float, float], bool]] = {
'<' : operator.lt,
'<=' : operator.le,
'>' : operator.gt,
'>=' : operator.ge,
'==' : operator.eq,
'===' : operator.eq,
'!=' : operator.ne,
'!==' : operator.ne,
}
class ClockWindow(NamedTuple):
"""
The times between which a run reads the host's clock, in milliseconds since the epoch, both
included.
"""
earliest: float
latest: float
def comparison(self, comparison: str, time: float) -> bool | None:
"""
What `clock <comparison> time` yields for a number *time* where every reading of the clock
inside this window yields the same, or `None`: a time inside the window, `NaN`, or an
operator that is not a comparison.
"""
compare = _CLOCK_COMPARISONS.get(comparison)
if compare is None or time != time or self.earliest <= time <= self.latest:
return None
return compare(self.earliest, time)
ASSUMED_CLOCK = ClockWindow(946771200000, 4102358400000)
"""
The window a run is assumed to read the host's clock in: from the start of 2000-01-02 to the start
of 2099-12-31, both in UTC, a day after 2000 and a day before 2100. A lock that hangs or breaks the
script outside a window of dates compares the clock with the first day of 2000 or of 2100, moved by
some seconds; that defense is not the program's behavior, and the comparison answers the same for
every reading inside the window. A date inside it, an expiry or a time the program waits for, is
the program's own and stays.
"""
_SPECS: dict[HostEnvironment, _EnvironmentSpec] = {
HostEnvironment.universal: _EnvironmentSpec(
GUARANTEED_GLOBALS,
GUARANTEED_GLOBALS,
handlers=_WINDOW_EVENT_HANDLERS | _WORKER_EVENT_HANDLERS,
),
HostEnvironment.node: _EnvironmentSpec(
GUARANTEED_GLOBALS | _NODE_GLOBALS,
GUARANTEED_GLOBALS,
_NODE_ABSENT,
engine=JsEngine.v8,
),
HostEnvironment.browser: _EnvironmentSpec(
GUARANTEED_GLOBALS | _BROWSER_GLOBALS,
GUARANTEED_GLOBALS,
_BROWSER_ABSENT,
handlers=_WINDOW_EVENT_HANDLERS,
),
HostEnvironment.worker: _EnvironmentSpec(
GUARANTEED_GLOBALS | _WORKER_GLOBALS,
GUARANTEED_GLOBALS,
_WORKER_ABSENT,
handlers=_WORKER_EVENT_HANDLERS,
),
}
Global variables
var GUARANTEED_GLOBAL_TYPEOF-
Maps each
GUARANTEED_GLOBALSname to the string itstypeofyields. Because the name resolves in every host to a value of a fixed type — a constructor or built-in function ('function'), a namespace object such asMath/JSON/ReflectorglobalThisitself ('object'), the two numeric constants ('number'), orundefined— the operator's result is host-independent, unlike a host-conditional alias (window,self, …) whosetypeofis'undefined'where the host omits the name. This is what lets a simplification foldtypeof globalThis !== 'undefined'totruefor a name it can prove pristine; the values were established under Node 24.GUARANTEED_GLOBALSis the key set of this map, so the two cannot drift. var GUARANTEED_GLOBALS-
Names the ECMAScript specification mandates as properties of the global object and that every mainstream engine exposes unconditionally, so a bare read of one is guaranteed to resolve rather than throw a
ReferenceError. This is an existence allowlist — distinct from the getter-purity and host-presence sets inrefinery.lib.scripts.js.analysis.effects— used to decide whether<global-alias>.namemay be collapsed to the barenamewithout turning the member read'sundefinedinto a throw. It excludes host and alias names (window,self,global,top,frames,console, timers,Buffer, …) that are not universal, andSharedArrayBuffer/Atomics, which a conformant host may withhold outside a cross-origin-isolated context.GUARANTEED_GLOBAL_TYPEOFadditionally records thetypeofof each. It is the provide-set of theUNIVERSALhost and the language floor every pinned host builds on. var UNIVERSAL_TYPEOF-
The
typeofof every name whose result is the same in every host, so atypeofof one folds without a host pin. It isGUARANTEED_GLOBAL_TYPEOFplusescapeandunescape, the Annex B pair every mainstream engine defines but the existence floor omits: theirtypeofis'function'everywhere even though a bare read of one is not part of the language-mandatedGUARANTEED_GLOBALSset. var NODE_BUILTIN_MODULES-
The modules Node's
requireloads from itself rather than from a file, read out of Node v24 asrequire('module').builtinModules. A name with thenode:prefix is one Node loads only under that prefix; every other one it also loads with the prefix. var NODE_MODULES_THAT_RUN_CODE-
The built-in modules through which a program has code run that its text does not hold:
vmandreplevaluate source text, the inspector evaluates it through a session, andmoduleloads any file and compiles source into a module. var ENGINE_FUNCTIONS-
The functions the language installs, by the owner of the prototype holding them and their key, that a host covering the Windows Script Host does not have: JScript, its engine, has no iterators. Only a host with one engine is known to have them (
HostEnvironment.has_function()). var COMMONJS_WRAPPER_PARAMETERS-
The parameters of the function a CommonJS host wraps around a file's text, in their order. Where the file declares none of these names itself, a bare read of one reads the value the host passed and a bare assignment writes it; the global scope holds none of them. Code run by a
Functionconstruction, an indirectevalor a string timer is global code outside that function and does not see them. Alet,constorclassdeclaration of one at the top of the file redeclares a parameter, which Node refuses to compile as CommonJS; it runs such a file as an ES module. var ASSUMED_CLOCK-
The window a run is assumed to read the host's clock in: from the start of 2000-01-02 to the start of 2099-12-31, both in UTC, a day after 2000 and a day before 2100. A lock that hangs or breaks the script outside a window of dates compares the clock with the first day of 2000 or of 2100, moved by some seconds; that defense is not the program's behavior, and the comparison answers the same for every reading inside the window. A date inside it, an expiry or a time the program waits for, is the program's own and stays.
Functions
def node_require_runs_no_code(specifier)-
Whether Node's
requireof specifier runs no code the file's text does not hold: it names a built-in module (NODE_BUILTIN_MODULES), with or without thenode:prefix it allows, outsideNODE_MODULES_THAT_RUN_CODE. Any other specifier names a file or a package, whose code runs when it is loaded.Expand source code Browse git
def node_require_runs_no_code(specifier: str) -> bool: """ Whether Node's `require` of *specifier* runs no code the file's text does not hold: it names a built-in module (`NODE_BUILTIN_MODULES`), with or without the `node:` prefix it allows, outside `NODE_MODULES_THAT_RUN_CODE`. Any other specifier names a file or a package, whose code runs when it is loaded. """ name = specifier if name.startswith('node:'): if specifier in NODE_BUILTIN_MODULES: return True name = name[5:] elif F'node:{name}' in NODE_BUILTIN_MODULES: return False return name in NODE_BUILTIN_MODULES and name not in NODE_MODULES_THAT_RUN_CODE def typeof_of_global(name, environment)-
The string
typeof nameyields for a global name under environment, orNonewhen the answer is host-dependent and the host is not pinned to one that settles it. A name whosetypeofis the same in every host (UNIVERSAL_TYPEOF) folds always; a host-conditional name folds only where the pin makes it certainly present — to its recorded type — or certainly absent — to'undefined'. The defaultuniversalhost settles only the universal names, sotypeof Bufferandtypeof windowabstain unpinned, exactly as a bare read of either is answered may-throw.Expand source code Browse git
def typeof_of_global(name: str, environment: HostEnvironment) -> str | None: """ The string `typeof name` yields for a global *name* under *environment*, or `None` when the answer is host-dependent and the host is not pinned to one that settles it. A name whose `typeof` is the same in every host (`UNIVERSAL_TYPEOF`) folds always; a host-conditional name folds only where the pin makes it certainly present — to its recorded type — or certainly absent — to `'undefined'`. The default `universal` host settles only the universal names, so `typeof Buffer` and `typeof window` abstain unpinned, exactly as a bare read of either is answered may-throw. """ if name in UNIVERSAL_TYPEOF: return UNIVERSAL_TYPEOF[name] presence = environment.presence(name) if presence is Presence.ABSENT: return 'undefined' if presence is Presence.PRESENT: return _HOST_CONDITIONAL_TYPEOF.get(name) return None
Classes
class Presence (*args, **kwds)-
What a pinned host knows about whether a global name resolves.
PRESENTandABSENTare the two certain answers atypeoffold may act on — present names fold to their type, absent names to'undefined';UNKNOWNmeans the host neither guarantees nor rules out the name, so a fold that would assert either abstains. The defaultuniversalhost answersPRESENTonly for the language floor andUNKNOWNfor every other name, since some host defines it and some does not.Expand source code Browse git
class Presence(enum.Enum): """ What a pinned host knows about whether a global name resolves. `PRESENT` and `ABSENT` are the two certain answers a `typeof` fold may act on — present names fold to their type, absent names to `'undefined'`; `UNKNOWN` means the host neither guarantees nor rules out the name, so a fold that would assert either abstains. The default `universal` host answers `PRESENT` only for the language floor and `UNKNOWN` for every other name, since some host defines it and some does not. """ PRESENT = 'present' ABSENT = 'absent' UNKNOWN = 'unknown'Ancestors
- enum.Enum
Class variables
var PRESENT-
The type of the None singleton.
var ABSENT-
The type of the None singleton.
var UNKNOWN-
The type of the None singleton.
class JsEngine (*args, **kwds)-
The engine a host runs scripts in, where every engine the host covers is that one engine. It answers what the language leaves to the engine: the text a function the language installs converts to, the text a regular expression converts to, and the characters
Date()writes at fixed positions. A host whose engines differ has none, and a fold of any of these refuses there. The answers ofv8were read out of Node 24.Expand source code Browse git
class JsEngine(enum.Enum): """ The engine a host runs scripts in, where every engine the host covers is that one engine. It answers what the language leaves to the engine: the text a function the language installs converts to, the text a regular expression converts to, and the characters `Date()` writes at fixed positions. A host whose engines differ has none, and a fold of any of these refuses there. The answers of `v8` were read out of Node 24. """ v8 = 'v8' def function_text(self, name: str) -> str: """ The text a function the language installs under *name* converts to, which reads as follows for `[].at`: function at() { [native code] } """ return F'function {name}() {{ [native code] }}' def regexp_text(self, source: str) -> str: """ The text a regular expression without flags converts to, whose pattern *source* is made of characters standing for themselves: the engine writes an empty pattern as `(?:)` and a slash as an escaped one, so that the text reads back as the same expression. """ escaped = source.replace('/', '\\/') if source else '(?:)' return F'/{escaped}/' def date_character(self, index: int) -> str | None: """ The character the string `Date()` returns holds at *index* whatever the time, or `None` where it depends on the time. The string reads as follows and then holds the name of the time zone, which fixes these positions where the year has four digits: Www Mmm DD YYYY HH:MM:SS GMT+hhmm """ return _V8_DATE_CHARACTERS.get(index)Ancestors
- enum.Enum
Class variables
var v8-
The type of the None singleton.
Methods
def function_text(self, name)-
The text a function the language installs under name converts to, which reads as follows for
[].at:function at() { [native code] }Expand source code Browse git
def function_text(self, name: str) -> str: """ The text a function the language installs under *name* converts to, which reads as follows for `[].at`: function at() { [native code] } """ return F'function {name}() {{ [native code] }}' def regexp_text(self, source)-
The text a regular expression without flags converts to, whose pattern source is made of characters standing for themselves: the engine writes an empty pattern as
(?:)and a slash as an escaped one, so that the text reads back as the same expression.Expand source code Browse git
def regexp_text(self, source: str) -> str: """ The text a regular expression without flags converts to, whose pattern *source* is made of characters standing for themselves: the engine writes an empty pattern as `(?:)` and a slash as an escaped one, so that the text reads back as the same expression. """ escaped = source.replace('/', '\\/') if source else '(?:)' return F'/{escaped}/' def date_character(self, index)-
The character the string
Date()returns holds at index whatever the time, orNonewhere it depends on the time. The string reads as follows and then holds the name of the time zone, which fixes these positions where the year has four digits:Www Mmm DD YYYY HH:MM:SS GMT+hhmmExpand source code Browse git
def date_character(self, index: int) -> str | None: """ The character the string `Date()` returns holds at *index* whatever the time, or `None` where it depends on the time. The string reads as follows and then holds the name of the time zone, which fixes these positions where the year has four digits: Www Mmm DD YYYY HH:MM:SS GMT+hhmm """ return _V8_DATE_CHARACTERS.get(index)
class FileKind (*args, **kwds)-
What the code of one file is, decided for a run from the execution model and the file's own text (
file_kind()):script: a classic script, whose top-levelvarand function declarations are properties of the global object.commonjs: the body of the function a CommonJS host wraps around the text.es_module: an ES module, strict code throughout.commonjs_or_es_module: one of the two without saying which; an answer must hold for both.
Expand source code Browse git
class FileKind(enum.Enum): """ What the code of one file is, decided for a run from the execution model and the file's own text (`refinery.lib.scripts.js.options.file_kind`): - `script`: a classic script, whose top-level `var` and function declarations are properties of the global object. - `commonjs`: the body of the function a CommonJS host wraps around the text. - `es_module`: an ES module, strict code throughout. - `commonjs_or_es_module`: one of the two without saying which; an answer must hold for both. """ script = 'script' commonjs = 'commonjs' es_module = 'es-module' commonjs_or_es_module = 'commonjs-or-es-module' @property def scopes_declarations_to_the_file(self) -> bool: return self is not FileKind.script @property def may_be_an_es_module(self) -> bool: return self is FileKind.es_module or self is FileKind.commonjs_or_es_module @property def may_be_commonjs(self) -> bool: return self is FileKind.commonjs or self is FileKind.commonjs_or_es_moduleAncestors
- enum.Enum
Class variables
var script-
The type of the None singleton.
var commonjs-
The type of the None singleton.
var es_module-
The type of the None singleton.
var commonjs_or_es_module-
The type of the None singleton.
Instance variables
var scopes_declarations_to_the_file-
Expand source code Browse git
@property def scopes_declarations_to_the_file(self) -> bool: return self is not FileKind.script var may_be_an_es_module-
Expand source code Browse git
@property def may_be_an_es_module(self) -> bool: return self is FileKind.es_module or self is FileKind.commonjs_or_es_module var may_be_commonjs-
Expand source code Browse git
@property def may_be_commonjs(self) -> bool: return self is FileKind.commonjs or self is FileKind.commonjs_or_es_module
class HostEnvironment (*args, **kwds)-
The host a script is assumed to run in, selected by the
djsunit's-eswitch.universalis the default and asserts onlyGUARANTEED_GLOBALS, so deobfuscation stays byte-identical to an unpinned run; each other member adds the globals that host guarantees, recovering the folds the sound default refuses for a name no universal host defines.Expand source code Browse git
class HostEnvironment(enum.Enum): """ The host a script is assumed to run in, selected by the `djs` unit's `-e` switch. `universal` is the default and asserts only `GUARANTEED_GLOBALS`, so deobfuscation stays byte-identical to an unpinned run; each other member adds the globals that host guarantees, recovering the folds the sound default refuses for a name no universal host defines. """ universal = 'universal' node = 'node' browser = 'browser' worker = 'worker' def provides(self, name: str) -> bool: """ Whether a bare read of *name* is guaranteed to resolve in this host rather than throw a `ReferenceError`, judged from the host's global-name data alone. """ return _SPECS[self].provides(name) def withholds_on_delete(self, name: str) -> bool: """ Whether *name* is a host-conditional global whose presence a `delete` of it retracts, as opposed to a language-mandated name the guard leaves present. A name this answers `True` for is withheld program-wide once the program deletes it off a same-realm global alias anywhere, which over-keeps a read's throw rather than dropping one, and so stays sound. """ return _SPECS[self].withholds_on_delete(name) def presence(self, name: str) -> Presence: """ Whether this host is certain *name* resolves (`PRESENT`), certain it does not (`ABSENT`), or neither (`UNKNOWN`). `provides` is the `PRESENT` half; the `ABSENT` half names the well-known globals of *other* hosts this one is characterized to lack, so that `typeof <name>` folds to `'undefined'` under a pin without asserting absence for a name merely left off the present set. """ return _SPECS[self].presence(name) def has_function(self, owner: str | None, key: str) -> bool: """ Whether a call of the function the language installs under *key* on the prototype of the constructor *owner*, or as a global where *owner* is `None`, finds that function in this host. Every host is taken to have each such function but those of `ENGINE_FUNCTIONS`, which only a host with one engine is known to have. """ return self.engine is not None or (owner, key) not in ENGINE_FUNCTIONS def calls_handler(self, name: str) -> bool: """ Whether some host this one covers calls the function a script stores in the property *name* of the global object, an event handler attribute such as the `onload` of a browser window. The host calls it with no call in the file, so a store there is never dead. The default `universal` covers browser windows and workers, so their handlers are called there too, also in a Windows Script Host, where the name is an ordinary global. """ return name in _SPECS[self].handlers @property def engine(self) -> JsEngine | None: """ The engine every engine this host covers is, or `None` where they may differ. Only `node` has one. The Windows Script Host, which `universal` covers, writes the text of a function the language installs with a line break before `function`, before `[native code]`, and on either side of the closing brace, so it shares no character with what V8 writes; the engines of the browsers are not measured. """ return _SPECS[self].engineAncestors
- enum.Enum
Class variables
var universal-
The type of the None singleton.
var node-
The type of the None singleton.
var browser-
The type of the None singleton.
var worker-
The type of the None singleton.
Instance variables
var engine-
The engine every engine this host covers is, or
Nonewhere they may differ. Onlynodehas one. The Windows Script Host, whichuniversalcovers, writes the text of a function the language installs with a line break beforefunction, before[native code], and on either side of the closing brace, so it shares no character with what V8 writes; the engines of the browsers are not measured.Expand source code Browse git
@property def engine(self) -> JsEngine | None: """ The engine every engine this host covers is, or `None` where they may differ. Only `node` has one. The Windows Script Host, which `universal` covers, writes the text of a function the language installs with a line break before `function`, before `[native code]`, and on either side of the closing brace, so it shares no character with what V8 writes; the engines of the browsers are not measured. """ return _SPECS[self].engine
Methods
def provides(self, name)-
Whether a bare read of name is guaranteed to resolve in this host rather than throw a
ReferenceError, judged from the host's global-name data alone.Expand source code Browse git
def provides(self, name: str) -> bool: """ Whether a bare read of *name* is guaranteed to resolve in this host rather than throw a `ReferenceError`, judged from the host's global-name data alone. """ return _SPECS[self].provides(name) def withholds_on_delete(self, name)-
Whether name is a host-conditional global whose presence a
deleteof it retracts, as opposed to a language-mandated name the guard leaves present. A name this answersTruefor is withheld program-wide once the program deletes it off a same-realm global alias anywhere, which over-keeps a read's throw rather than dropping one, and so stays sound.Expand source code Browse git
def withholds_on_delete(self, name: str) -> bool: """ Whether *name* is a host-conditional global whose presence a `delete` of it retracts, as opposed to a language-mandated name the guard leaves present. A name this answers `True` for is withheld program-wide once the program deletes it off a same-realm global alias anywhere, which over-keeps a read's throw rather than dropping one, and so stays sound. """ return _SPECS[self].withholds_on_delete(name) def presence(self, name)-
Whether this host is certain name resolves (
PRESENT), certain it does not (ABSENT), or neither (UNKNOWN).providesis thePRESENThalf; theABSENThalf names the well-known globals of other hosts this one is characterized to lack, so thattypeof <name>folds to'undefined'under a pin without asserting absence for a name merely left off the present set.Expand source code Browse git
def presence(self, name: str) -> Presence: """ Whether this host is certain *name* resolves (`PRESENT`), certain it does not (`ABSENT`), or neither (`UNKNOWN`). `provides` is the `PRESENT` half; the `ABSENT` half names the well-known globals of *other* hosts this one is characterized to lack, so that `typeof <name>` folds to `'undefined'` under a pin without asserting absence for a name merely left off the present set. """ return _SPECS[self].presence(name) def has_function(self, owner, key)-
Whether a call of the function the language installs under key on the prototype of the constructor owner, or as a global where owner is
None, finds that function in this host. Every host is taken to have each such function but those ofENGINE_FUNCTIONS, which only a host with one engine is known to have.Expand source code Browse git
def has_function(self, owner: str | None, key: str) -> bool: """ Whether a call of the function the language installs under *key* on the prototype of the constructor *owner*, or as a global where *owner* is `None`, finds that function in this host. Every host is taken to have each such function but those of `ENGINE_FUNCTIONS`, which only a host with one engine is known to have. """ return self.engine is not None or (owner, key) not in ENGINE_FUNCTIONS def calls_handler(self, name)-
Whether some host this one covers calls the function a script stores in the property name of the global object, an event handler attribute such as the
onloadof a browser window. The host calls it with no call in the file, so a store there is never dead. The defaultuniversalcovers browser windows and workers, so their handlers are called there too, also in a Windows Script Host, where the name is an ordinary global.Expand source code Browse git
def calls_handler(self, name: str) -> bool: """ Whether some host this one covers calls the function a script stores in the property *name* of the global object, an event handler attribute such as the `onload` of a browser window. The host calls it with no call in the file, so a store there is never dead. The default `universal` covers browser windows and workers, so their handlers are called there too, also in a Windows Script Host, where the name is an ordinary global. """ return name in _SPECS[self].handlers
class ClockWindow (earliest, latest)-
The times between which a run reads the host's clock, in milliseconds since the epoch, both included.
Expand source code Browse git
class ClockWindow(NamedTuple): """ The times between which a run reads the host's clock, in milliseconds since the epoch, both included. """ earliest: float latest: float def comparison(self, comparison: str, time: float) -> bool | None: """ What `clock <comparison> time` yields for a number *time* where every reading of the clock inside this window yields the same, or `None`: a time inside the window, `NaN`, or an operator that is not a comparison. """ compare = _CLOCK_COMPARISONS.get(comparison) if compare is None or time != time or self.earliest <= time <= self.latest: return None return compare(self.earliest, time)Ancestors
- builtins.tuple
Instance variables
var earliest-
Alias for field number 0
Expand source code Browse git
class ClockWindow(NamedTuple): """ The times between which a run reads the host's clock, in milliseconds since the epoch, both included. """ earliest: float latest: float def comparison(self, comparison: str, time: float) -> bool | None: """ What `clock <comparison> time` yields for a number *time* where every reading of the clock inside this window yields the same, or `None`: a time inside the window, `NaN`, or an operator that is not a comparison. """ compare = _CLOCK_COMPARISONS.get(comparison) if compare is None or time != time or self.earliest <= time <= self.latest: return None return compare(self.earliest, time) var latest-
Alias for field number 1
Expand source code Browse git
class ClockWindow(NamedTuple): """ The times between which a run reads the host's clock, in milliseconds since the epoch, both included. """ earliest: float latest: float def comparison(self, comparison: str, time: float) -> bool | None: """ What `clock <comparison> time` yields for a number *time* where every reading of the clock inside this window yields the same, or `None`: a time inside the window, `NaN`, or an operator that is not a comparison. """ compare = _CLOCK_COMPARISONS.get(comparison) if compare is None or time != time or self.earliest <= time <= self.latest: return None return compare(self.earliest, time)
Methods
def comparison(self, comparison, time)-
What
clock <comparison> timeyields for a number time where every reading of the clock inside this window yields the same, orNone: a time inside the window,NaN, or an operator that is not a comparison.Expand source code Browse git
def comparison(self, comparison: str, time: float) -> bool | None: """ What `clock <comparison> time` yields for a number *time* where every reading of the clock inside this window yields the same, or `None`: a time inside the window, `NaN`, or an operator that is not a comparison. """ compare = _CLOCK_COMPARISONS.get(comparison) if compare is None or time != time or self.earliest <= time <= self.latest: return None return compare(self.earliest, time)