class

Analyzer::Javascript::Remix

Inherits Analyzer::Javascript::JavascriptEngine < Analyzer < FileHelper < Reference < Object

Remix v2 is filesystem-routed under app/routes/. The route URL is derived from the filename via dot-flat naming and a handful of special prefixes:

app/routes/_index.tsx → GET / app/routes/about.tsx → GET /about app/routes/users._index.tsx → GET /users app/routes/users.$id.tsx → GET /users/{id} app/routes/_auth.login.tsx → GET /login (_auth is a pathless layout — no URL effect) app/routes/api.users.ts → exports drive verbs app/routes/$.tsx → catch-all

Verb detection:

  • .tsx / .jsx files render a page — emit GET.
  • Files exporting loader add GET (or keep it).
  • Files exporting action add POST / PUT / PATCH / DELETE (Remix dispatches every non-GET to action at runtime; we surface the full set so downstream tooling can fan out).
  • Resource-only .ts / .js files without loader or action are skipped — they're not handler routes.

Out of scope for this first cut:

  • Per-handler request-helper scanning. Remix loaders / actions receive { request, params, context } — accurate read tracking needs cross-call value flow. Path placeholders still surface via the optimizer.
  • Optional segments ($lang) (translated to a literal lang today; Remix folds optionality into a wildcard match that's hard to represent without per-route alternatives).
  • The legacy v1 nested-folder convention — v2 flat is what the toolchain has been on since Remix 1.15 / Remix 2.

Constants

EXTENSIONS = PAGE_EXTENSIONS + RESOURCE_EXTENSIONS
FLAT_SEGMENT_RULES = Noir::TopLevelSplit::Rules.new(nest: Noir::TopLevelSplit::Nest::Bracket, quotes: "", escape: Noir::TopLevelSplit::Escape::None, strip: false, empties: Noir::TopLevelSplit::Empties::Keep, per_kind: false, clamp: true)

[...] is the only thing that nests in a Remix flat-route filename, and a filename has no string literals, so quote handling is off — a route named it's.tsx would otherwise open a quoted run and never split. Empties are kept and parts are not stripped because normalize_segment and the caller decide what an empty segment means; a filename cannot contain leading or trailing whitespace worth trimming anyway.

HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH"]
NON_GET_VERBS = ["POST", "PUT", "PATCH", "DELETE"]
PAGE_EXTENSIONS = [".tsx", ".jsx"]
RESOURCE_EXTENSIONS = [".ts", ".js", ".mjs"]

Class methods

tech_name
Source

Instance methods

analyze
Source
tech

Instance-side view of the same declaration. The per-file rescues live on this base class, which has no way to name the analyzer that is running inside them, so a skipped file could not be attributed to a tech. Deriving it from analyzer_for keeps the name written exactly once.

Source