1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! The bounded type oracle: what a node's type is, and where its name came from.
//!
//! This is the "bounded oracle" of the type-aware rules design, and the bound is *depth*
//! rather than the file. [`TypeScriptOracle`] answers from one parse and nothing else;
//! [`BuiltinProvider`] wraps it and follows an import out of that file — to a sibling source,
//! to a `.d.ts`, into `node_modules` — through the caller's [`lanekeep_core::FileAccess`], so
//! every file it opens is a recorded dependency of the answer. What it still has no notion of
//! is a *program*: no `tsconfig.json`, no path mapping, no compiler, and a fixed number of
//! hops rather than a transitive closure.
//!
//! It answers `None` whenever it cannot be sure. That is the whole contract: a rule choosing
//! to be silent on `None` is sound, and one choosing to report on it is the author's decision
//! rather than the engine's.
//!
//! # Why this is its own crate
//!
//! It reaches declarations through [`lanekeep_lang::binding::BindingResolver::declaration_of`]
//! and [`lanekeep_lang::binding::BindingResolver::declares`], two language-neutral questions,
//! so it never needs a language crate's internals — `lanekeep-lang-js` is a dependency of its
//! tests alone. Only its knowledge of TypeScript *syntax* is language-specific, and that is
//! held in one type whose constructor refuses a grammar that does not speak it.
//!
//! # What is deliberately absent
//!
//! No clock, no environment, no randomness, no `HashMap` iteration, and no filesystem access
//! that is not a [`lanekeep_core::FileAccess`] read. A cached result computed by this oracle
//! must still be valid, so nothing here may observe anything the cache key does not cover: the
//! bytes it was handed, and the tracked reads it made from them.
pub use BuiltinProvider;
pub use ;
pub use ;
pub use ;
pub use resolve_specifier;
pub use ;
/// What this oracle *is*, as a digest of every source file that decides an answer.
///
/// A cache-key input for whoever wires the oracle up: a result computed by an oracle that no
/// longer exists must not be served. It is derived rather than hand-maintained, because the
/// hand-maintained alternative is `lanekeep_js::HOST_API_VERSION`, whose own documentation
/// says plainly that nothing detects a missed bump.
///
/// **Not a hash of the tables.** The `+` arm, the shadow check on builtin calls and the
/// recursion bound are logic rather than table rows, and an oracle whose `+` arm is corrected
/// gives different answers from an identical table. Hashing the data alone would
/// under-invalidate on exactly the changes most likely to matter, which is the asymmetric
/// failure the cache key exists to prevent.
///
/// This over-invalidates instead: editing a comment in this crate discards every cached
/// type-aware result. That is the trade `hash_ruleset` already makes for rule source, and
/// for the same reason — over-invalidation costs a recompute, under-invalidation reports a
/// wrong answer and gives no sign that it did.
///
/// The grammar is not folded in here. A run's cache key already carries a structural digest of
/// every registered grammar, so a TypeScript grammar bump invalidates through that term;
/// hashing it twice would be one place too many.