Class: Mbeditor::JsGlobalsService
- Inherits:
-
Object
- Object
- Mbeditor::JsGlobalsService
- Defined in:
- app/services/mbeditor/js_globals_service.rb
Overview
Enumerates every top-level JavaScript declaration in the workspace so the
editor can declare them as ambient globals in one shot. This models the
Sprockets concatenation world: files share one global script scope, so an
unindented var/function/class (or a window.X = assignment) in any
JS-family file is visible everywhere with no import statement.
Backed by CodeSearchService (rg > git grep > grep over JS_GLOBS, which includes *.js.jsx / *.js.erb), with a short cache invalidated whenever mbeditor mutates a file.
Constant Summary collapse
- MAX_SYMBOLS =
3000- CACHE_TTL =
seconds
30- PATTERN =
Column-0 anchored so only true top-level declarations match (Sprockets globals are by definition unindented); window assignments may be indented (IIFE bodies). BSD-grep-safe ERE: no \s, no non-greedy ops.
'^((var|let|const|function|class|async[ \t]+function)[ \t]+[A-Za-z_$][A-Za-z0-9_$]*' \ '|[ \t]*window\.[A-Za-z_$][A-Za-z0-9_$]*[ \t]*=)'
- IDENTIFIER =
/[A-Za-z_$][A-Za-z0-9_$]*/- KNOWN_RUNTIME_GLOBALS =
Runtime globals no static scan can reach, for the same reason React and lodash can't be reached: a UMD bundle assigns its name through a closure parameter. react-rails ships
root["ReactRailsUJS"] = factory()in the gem's lib/assets/javascripts/react_ujs.js — outside the workspace, so it is never scanned, and bracket-assigned to a parameter, so widening PATTERN toIDENT["Str"] =would not help and would declare thousands of junk names out of every minified bundle. Seeded like js_global_identifiers, so both consumers (the TS worker's ambient declarations and the babel scope lint's whitelist) get them. %w[ReactRailsUJS].freeze
- MINIFIED_NAME =
Minified bundles are the reason for both guards below.
A minified file is one enormous line, and it usually opens with a multi-declarator
var a,b,c,d,…running to thousands of names. Split on commas, that ONE line yields thousands of one-letter symbols — enough to exhaust MAX_SYMBOLS on its own, so the workspace's actual components are never reached and every reference to them shows "Cannot find name". Worse, declaringa/n/tas ambientanysilences genuine diagnostics for those names everywhere.The name check catches the conventional cases; the line-length check catches bundles that don't say "min" in the filename. Neither is a judgement about vendored code in general — a normally-formatted vendor/assets library still contributes its globals, which is correct under Sprockets.
/[.\-]min\.(js|jsx|ts|tsx)\z/i- MAX_LINE_LENGTH =
2_000
Class Method Summary collapse
Class Method Details
.call(workspace_root) ⇒ Object
58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'app/services/mbeditor/js_globals_service.rb', line 58 def call(workspace_root) root = workspace_root.to_s now = monotonic MUTEX.synchronize do entry = (@cache ||= {})[root] return entry[:data] if entry && (now - entry[:ts]) < CACHE_TTL end data = compute(root) MUTEX.synchronize { (@cache ||= {})[root] = { ts: monotonic, data: data } } data end |
.invalidate(workspace_root) ⇒ Object
71 72 73 |
# File 'app/services/mbeditor/js_globals_service.rb', line 71 def invalidate(workspace_root) MUTEX.synchronize { (@cache ||= {}).delete(workspace_root.to_s) } end |