The parity check keyed on the whole [display](target) pattern, so a link
whose display text contains brackets (Array[T] Models) never matched and the
bracket case asserted nothing. Key on the ](target) boundary instead — wiki
targets contain no ) or whitespace — so bracketed labels are actually checked.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The wiki exporter wrote each article as {slug}.md but emitted the link as
quote({slug}.md), so any label with ( ) & # or non-ASCII produced a
percent-encoded target that names no file on disk. Removes the quote() fork
and hardens _safe_filename so the slug is URL-safe by construction; the link
and the on-disk filename are now the same string.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds two regression tests on top of #2684: each referencing symbol gets its
own INFERRED uses edge (guarding against the old every-class fan-out and
against source collapse), and a true module-top-level reference emits no edge
(the deliberate drop). Also adds the CHANGELOG entry.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rewrites Pass 2 of the Python cross-file import resolver so an INFERRED
`uses` edge anchors on the symbol whose body actually references the
imported name (a class as a unit, or a module-level function) at the real
reference line, instead of fanning out from the import statement line to
every class in the importing file.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
New graphify/extractors/ocaml.py handles both the implementation grammar
(language_ocaml, .ml) and the interface grammar (language_ocaml_interface,
.mli). Emits nodes for modules, top-level/module-level values and functions,
types and their variant constructors; edges for defines/contains, open ->
imports_from, and application -> calls. Qualified paths (Geo.area) resolve to
the final value name, not the module qualifier; local let ... in bindings do
not mint nodes or steal call attribution. Cross-file open/call targets are
sourceless stubs so the corpus rewire collapses them onto the unique real
definition (no #1402 sourced-stub leak).
Wired into detect.py (CODE_EXTENSIONS), extract.py (dispatch +
_EXTRA_FOR_EXTENSION), pyproject.toml ([ocaml] extra + all + dev dep), and
README. Adds tests/test_ocaml.py (behind importorskip).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The #2475 fix recomputed the match path against the explicit scan root but
skipped the _nfc() normalization rel_anchor gets, so an NFD-named path
could miss a parent ignore pattern under the #2544 NFC-matching regime.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The #2600 title helper preferred a cwd-relative label, which still leaks
host/user path segments when the graph is built from a directory above the
project. Keep from the graphify-out / GRAPHIFY_OUT marker onward first
(portable in every case); fall back to cwd-relative only for a fully custom
output path with no marker.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The <title> previously embedded str(output_path), so Windows absolute
host paths leaked into a tracked artifact (regression of #433, #2598).
Prefer a cwd-relative label, else keep from the graphify-out segment
onward, else the filename only.