Class: Mbeditor::JsGlobalsService

Inherits:
Object
  • Object
show all
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_$]*/
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, declaring a/n/t as ambient any silences 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



47
48
49
50
51
52
53
54
55
56
57
58
# File 'app/services/mbeditor/js_globals_service.rb', line 47

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



60
61
62
# File 'app/services/mbeditor/js_globals_service.rb', line 60

def invalidate(workspace_root)
  MUTEX.synchronize { (@cache ||= {}).delete(workspace_root.to_s) }
end