module

Noir::JSHandlerResolver

Resolves a route's named handler (app.get('/x', login), router.post('/y', users.create), app.use(auth())) to the file and line that define it: a same-file function login / const login =, or the target of the import that brought the name in.

Best-effort by design. An inline closure has no name, a package import (express.static) has no file in the scan, and a re-exported symbol is followed one hop only. Each of those yields nil rather than a guess.

Constants

DEFAULT_EXPORT_RE = /^[ \t]*(?:module\.)?exports\s*=|^[ \t]*export\s+default\b/m
IMPORT_DEFAULT_RE = /\bimport\s+([A-Za-z_$][\w$]*)\s*(?:,\s*\{[^}]*\}\s*)?from\s*['"]([^'"]+)['"]/
IMPORT_NAMED_RE = /\bimport\s*(?:[A-Za-z_$][\w$]*\s*,\s*)?\{([^}]*)\}\s*from\s*['"]([^'"]+)['"]/
IMPORT_STAR_RE = /\bimport\s*\*\s*as\s+([A-Za-z_$][\w$]*)\s*from\s*['"]([^'"]+)['"]/
MIDDLEWARE_FACTORIES = Set {"cors", "helmet", "morgan", "compression", "cookieParser", "csrf", "csurf", "rateLimit", "serveStatic", "favicon", "session", "methodOverride", "multer", "bodyParser", "express", "passport", "serveIndex", "timeout", "responseTime"}

Factories that register middleware, never a route's handler. A route whose last argument is one of these has no named handler to report.

REFERENCE_RE = /\A([A-Za-z_$][\w$]*)((?:\s*\.\s*[A-Za-z_$][\w$]*)*)\s*(?:\(\s*\))?\z/
REQUIRE_NAMED_RE = /\b(?:const|let|var)\s*\{([^}]*)\}\s*=\s*require\s*\(\s*['"]([^'"]+)['"]\s*\)/
REQUIRE_RE = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*require\s*\(\s*['"]([^'"]+)['"]\s*\)(?:\s*\.\s*([A-Za-z_$][\w$]*))?/
SPREAD_REQUIRE = /\.\.\.\s*require\s*\(\s*['"]([^'"]+)['"]\s*\)|^[ \t]*export\s*\*\s*from\s*['"]([^'"]+)['"]/m
TSCONFIG_BASE_URL_RE = /"baseUrl"\s*:\s*"([^"]+)"/
TSCONFIG_ENTRY_RE = /"([^"\s]+)"\s*:\s*\[\s*"([^"\s]+)"/
TSCONFIG_PATHS_RE = /"paths"\s*:\s*\{([^}]*)\}/m
WRAPPER_BARE_RE = /\A[^\n]*?(?:=|\bdefault\b)\s*(?:async\s+)?([A-Za-z_$][\w$]*)\s*=>/
WRAPPER_CALL_RE = /\A((?:[A-Za-z_$][\w$]*\s*\.\s*)?[A-Za-z_$][\w$]*)\s*\(/
WRAPPER_HEAD_RE = /\A[^\n]*?(?:\bfunction\b\s*\*?\s*[\w$]*\s*|(?:=|\bdefault\b)\s*(?:async\s+)?)(?:<[^\n]*?>\s*)?\(/

The wrapper head: function name<T>(, name = <T extends H>(, = async (, module.exports = (, export default function (; or a bare = fn =>.

WRAPPER_INNER_RE = /\bfunction\b\s*\*?\s*[\w$]*\s*\(\s*([A-Za-z_$][\w$]*)|\(\s*([A-Za-z_$][\w$]*)[^()]*\)\s*(?::[^=;{]*)?=>|(?<![\w$.])([A-Za-z_$][\w$]*)\s*=>/

The request parameter of the function a wrapper returns: (req, res, next) =>, function (req, res), req =>.

WRAPPER_MAX_SPAN = 4000
WRAPPER_NAME_RE = /(?:\A|\.)(?:asyncHandler|asyncWrap|asyncWrapper|asyncMiddleware|wrap|wrapAsync|catchAsync|catchErrors|handleAsync|expressAsyncHandler|tryCatch|ah)\z/

utils.asyncHandler(login()), wrap(ctrl.show): the handler is the argument, the wrapper only catches its rejection. A wrapper defined in the scan is judged by its definition (unwrap); these names are the fallback for one that comes from a package (express-async-handler). validate(schema) is middleware, not a wrapped schema.

WRAPPER_REFUSAL = /\b(?:status|sendStatus|code)\s*\(\s*40[13]\b|\bstatus\s*=\s*40[13]\b|\.throw\s*\(\s*40[13]\b|\bredirect\s*\(|\bthrow\s+new\b/

Instance methods

bind_parameter(file : String, name : String, module_path : String) : Nil
Source
export_aliases(content : String) : String

Names the module's exports object goes by: exports, module.exports, and a local bound to it (const Posts = module.exports;, or module.exports = Posts; at the end), as an alternation.

Source
imports_of(content : String, file_path : String) : Imports
Source
reset
Source
resolve(handler_text : String, content : String, file_path : String, guards : Bool = false) : Handler | Nil

handler_text is the route argument as written. Returns nil unless it is a plain reference that resolves to a definition.

Source
resolve_module_export(specifier : String, name : String | Nil, file_path : String) : Handler | Nil

await import("./x.handler") in a handler body: name as exported by the module specifier names, or its default export when nil.

Source
unwrap(text : String, content : String, file_path : String, guards : Bool = false) : Tuple(String, Int32, String) | Nil

A wrapper call W(x) as {x, its char offset in text, W}, when the wrapper hands the request on to its argument: its definition takes a function and returns one that calls it ((fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next)). A wrapper with no definition in the scan, or one whose definition cannot be read, is taken by name (WRAPPER_NAME_RE). A wrapper that can itself refuse the request ((fn) => (req, res, next) => req.user ? fn(req, res, next) : res.sendStatus(401)) is a guard around x: it is only unwrapped when the caller reports that guard (guards: true).

Source

Nested types