Analyzer::Javascript::JsModuleResolver
Resolves a JS/TS require('./x') / import ... from './x' specifier
to a file on disk.
Extracted from RouterMountScanner so RouteHelperScanner resolves
specifiers identically: the mount pass decides which file a prefix
belongs to and the helper pass decides which file defines a helper, and
the two have to name the same file for a helper's routes to end up
under the right prefix.
root anchors the @/ and ~/ aliases — the scan base the importing
file belongs to. Bare specifiers (express, @hapi/hapi) resolve to
nil; a node_modules walk is deliberately out of scope.
Constants
require(__dirname + '/routes/pets'), require(`${__dirname}/routes/pets`)
and require(path.join(__dirname, 'routes', 'pets')) (or path.resolve,
or import(...)) all name ./routes/pets relative to the importing
file. Every specifier matcher only reads quoted literals, so the
computed forms are rewritten to that literal before matching.
TypeScript ESM (moduleResolution: NodeNext) imports a sibling .ts
source through a .js-family specifier. Map each JS extension to the
TS source extension(s) it can stand in for.