; router.push('...')
(call_expression
  function: (member_expression
    object: (identifier) @_router
    property: (property_identifier) @nav.method)
  arguments: (arguments
    .
    (string (string_fragment) @nav.target.literal))
  (#eq? @_router "router")
  (#match? @nav.method "^(push|replace)$"))

; router.push(`...`)
(call_expression
  function: (member_expression
    object: (identifier) @_router2
    property: (property_identifier) @nav.method.template)
  arguments: (arguments
    .
    (template_string) @nav.target.template)
  (#eq? @_router2 "router")
  (#match? @nav.method.template "^(push|replace)$"))

; <ANY href="LITERAL"> — opening element with href prop. Captures
; <Link>, <a>, and any custom wrapper component (LinkRow, NavItem, …). The
; resolver filters non-route literals out of the final edge set.
(jsx_opening_element
  name: (_) @nav.link.tag
  attribute: (jsx_attribute
    (property_identifier) @_href
    (string (string_fragment) @nav.link.literal))
  (#eq? @_href "href"))

; <ANY href="LITERAL" /> — self-closing
(jsx_self_closing_element
  name: (_) @nav.link.tag.self
  attribute: (jsx_attribute
    (property_identifier) @_href2
    (string (string_fragment) @nav.link.literal.self))
  (#eq? @_href2 "href"))

; <ANY href={`...`}> — template, opening
(jsx_opening_element
  name: (_) @nav.link.tag.tpl
  attribute: (jsx_attribute
    (property_identifier) @_href3
    (jsx_expression
      (template_string) @nav.link.template))
  (#eq? @_href3 "href"))

; <ANY href={`...`} /> — template, self-closing
(jsx_self_closing_element
  name: (_) @nav.link.tag.tpl.self
  attribute: (jsx_attribute
    (property_identifier) @_href4
    (jsx_expression
      (template_string) @nav.link.template.self))
  (#eq? @_href4 "href"))

; redirect('/path')  /  redirect(`/path/${id}`) — bare call. Convention from
; next/navigation; matches by name regardless of import path so wrappers
; that re-export `redirect` still work. Filtering noise: callers like
; redirect(url) (variable) are skipped because we only capture string args.
(call_expression
  function: (identifier) @_redirect_fn
  arguments: (arguments
    .
    (string (string_fragment) @nav.redirect.literal))
  (#eq? @_redirect_fn "redirect"))

(call_expression
  function: (identifier) @_redirect_fn_tpl
  arguments: (arguments
    .
    (template_string) @nav.redirect.template)
  (#eq? @_redirect_fn_tpl "redirect"))

; window.location.href = '...'
(assignment_expression
  left: (member_expression
    object: (member_expression
      object: (identifier) @_win
      property: (property_identifier) @_loc)
    property: (property_identifier) @_href5)
  right: (string (string_fragment) @nav.window.literal)
  (#eq? @_win "window")
  (#eq? @_loc "location")
  (#eq? @_href5 "href"))

; window.location.assign('...')
(call_expression
  function: (member_expression
    object: (member_expression
      object: (identifier) @_win2
      property: (property_identifier) @_loc2)
    property: (property_identifier) @nav.window.method)
  arguments: (arguments
    .
    (string (string_fragment) @nav.window.assign.target))
  (#eq? @_win2 "window")
  (#eq? @_loc2 "location")
  (#match? @nav.window.method "^(assign|replace)$"))
