Repository navigation
feat(docs): doc-comment links for eight more languages, diagrams and OpenAPI operations in the graph - #2593
Merged
Conversation
…udit Go doc comments name code as doc links ([Name], [Recv.Name], [pkg.Name], [pkg.Recv.Name], an import path for pkg), the way go/doc/comment reads them. The Go leg (doclink_go.c extracts them and a go.mod's module path as the scope; doc_links_go.c resolves them against the package's declarations and its imports) is ported onto the restacked core: the family row carries its edge type, and resolve() takes the per-file state the core now passes (Go keeps none). The family is held (ships=false) until its held-out audit passes: a resolved doc link is a below_bar_tier row until then. The suite ships it through the test seam, like the other held families; doc_mentions_go_tokens asserts the production default. Kubernetes at 8c078bc32e90 with the family shipped (a measurement build): 1,928 edges (1,115 exact, 813 unique) and 101 rows (external 61, graph_gap 22, missing 18), the same numbers the leg measured on the old core. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…edges, held until their audit
Java's {@link}, {@linkplain}, @see, @throws and {@value}, and Kotlin's [Name]
links, @see, @throws and @sample, bound the way javadoc and Dokka search for a
member (one resolver for both languages, so a Kotlin doc can name a Java type
and back). The leg (doclink_jvm.c extracts the references and each file's
scope; doc_links_jvm.c resolves them) is ported onto the restacked core:
family rows carry their edge type, resolve() takes the per-file state (none
here). All nine families are held (ships=false) until their held-out audit
passes; the suite ships them through the test seam.
The graph moved under the leg since it was written: a Java field's node is
named by the field alone (no longer by its whole declarator, `MAX = 10`), and
a field named like a method of its class has its own node,
<Owner>.<name>#field, where the method used to take the name. The tests
follow: the expected field names lose the initializer, a changed
initializer is a local change repaired file by file (it renamed the node
before, which forced a full run), and a field that shares its accessor's name
is now an edge target and a source (doc_mentions_jvm_java_families_and_reasons,
doc_mentions_jvm_node_ownership), where both were graph_gap rows.
Measured with the leg's binary (1078036f) and this one on the same input:
- elasticsearch subset (libs/ + server/src/main at f3dc4b0bd3a0, 5,956 files):
no edge lost; 66 new edges and 7 edges moved onto a field's own #field node;
81 graph_gap rows gone, no new row, no reason changed. A seeded sample of 8
of the gone rows read against the source: every new edge is right (a field
named like its accessor, enum constants, a field's own doc as the source).
- Exposed (Kotlin, c419caaab61f): identical, 896 edges and 371 rows.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…eir audit Rustdoc's intra-doc links ([`Name`], [path], [text](path), the kind disambiguators struct@, fn@, macro@ ...) and links that take their destination from a link reference definition, bound the way rustdoc resolves them: the item's module scope, its use declarations, the crate root and the crates Cargo.toml names. The leg (doclink_rs.c extracts the links and each file's scope, a Cargo.toml its crate facts; doc_links_rs.c resolves them) is ported onto the restacked core: family rows carry their edge type, resolve() takes the per-file state (none here). Both families are held (ships=false) until their held-out audit passes; the suite ships them through the test seam. The graph moved under the leg: cfg-gated twins are one definition with its variants on one node (42a9320), so a name declared twice under cfg now binds that node instead of being ambiguous, and a #[cfg(test)] item keeps its plain qualified name. The two tests follow. Made lint-clean for CI's cppcheck 2.20 by refactoring, no suppression: the `///` / `//!` test reads the line's indent through a helper and decides by early returns (2.20 took the combined condition for always false), and rs_put_node returns early for a missing definition (and for one without a qualified name, which strlen would have read) before any arithmetic on it. clang-format applied to both files. meilisearch at 979167f13b5f, the leg's binary (5d8cb835) against this one with the families shipped: edges and rows byte-identical (120 edges, 406 rows). Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A POD section whose =head / =item names a sub is that sub's doc (#2459). Everything else (NAME, DESCRIPTION, SEE ALSO, the text of a section around the subs it holds, sections that name an attribute or helper without a node) was stored nowhere, so nothing could read it. It is now the file's module doc, stored on the File node as Go package comments and Rust inner docs are: every POD block with the sections a sub's doc holds cut out, each remaining run as it stands in the source, in document order and joined by a blank line (a sub's doc joins its sections the same way); a run of only =cut, =pod, =over and =back lines is dropped. A section is marked when a sub's doc takes it, so the module doc is built after the definitions and the two never hold the same text. Its first line is noted for the doc-link layer. Mojolicious at 93f591742a7d: L< codes in stored docs 624 (subs, unchanged) + 1,595 (File nodes of 112 modules) = 2,219, the count of L<> codes in the POD of its .pm and .pl files, none stored twice. Test: doc_perl_module_doc_is_the_pod_no_sub_holds (the module doc's exact text, the sub's doc unchanged, no module doc when every section is a sub's); red at its first assertion with the module doc not built. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…r audit A sub's POD section and the module's own POD (the File node's doc) name code with L<> codes: L<Module::Name>, L<Module::Name/section>, L</section>, with a `text|` prefix or not. doclink_perl.c reads them the way perlpodspec and Pod::Simple do (verbatim paragraphs and data regions hold none, an L inside an L is no link, a URL is the core's href family) and writes each file's scope: its packages, its subs and its headings. Lines are exact: a sub's doc is matched against the file's sections, and the module doc's runs (extract_defs.c) are found again in the source in order; a module doc is POD from its start, so a run that begins with text is read too. doc_links_perl.c resolves them: - a module is the file that declares its package; of several, the one the library layout names (.../Name/Space.pm), else ambiguous. The target is the file's File node, as the field test's audited prototype has it (a Module node is missing where a same-named Folder holds its qualified name, lib/Mojo.pm next to lib/Mojo/). - L<Module/section>: the sub its heading names when the module's file defines that sub; any other section is a place in the module's documentation, the module. - L</section>: a sub the heading names; a heading that names no sub is the page itself (local, neither edge nor row); a section the page has no heading for is missing. - a module the repository does not declare (CPAN, the core, a .pod page: discovery keeps no .pod file) and a man page are external; test code (t/, xt/, *.t, and cbm_is_test_file, which has no Perl rule) binds only from test code. There is no scope_delta hook yet: a change to a file's packages, subs or headings re-resolves every Perl reference. The family is held (ships=false) until its held-out audit passes; the suite ships it through the test seam. Tests (doc_mentions_perl): tokens with their lines, file-level and sub-level, each read once; every resolution rule; incremental equals full (a module doc edit and an added module-level reference repair the file, a heading change is a full run); 60 modules give the same edges and rows with one worker and several. Each rule red with it reverted (the module doc's line mapping, a module run read from its start, the missing section, the library layout). Mojolicious at 93f591742a7d (the family shipped, a measurement build) against the field test's prototype records of its .pm/.pl files: 950 (source, target) pairs both have; the 197 only the prototype has are all references within one file (570), which the core makes no edge of; 8 only here come from the extensionless scripts the prototype did not read. Every prototype row has its row here: external 102, missing 1, and the 172 targets in .pod pages external by the ruling for .pod pages. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…l their audit
A TypeScript, TSX or JavaScript doc comment (a block comment opening with a
slash and two stars) names code with {@link Ref}, {@linkcode Ref} (each with
an optional `|` label) and `@see Ref` at the start of a tag line that holds
no inline tag. doclink_ts.c harvests them (code spans and fenced blocks hold
none, {@linkplain} is not harvested, a hyphenated word after @see is prose, a
reference naming the declaration's own parameter is dropped, a URL is the
core's href family) and writes each file's scope: imports, exports, export *
barrels, top-level declarations, namespace bodies and functions or classes
declared inside a function body.
doc_links_ts.c resolves a reference as the TypeScript checker sees it from
the documented declaration, in one index over TS, TSX and JS files:
1. the namespaces around the reference, innermost first;
2. a function or class declared in the enclosing function body (the graph
gives it a file-level name: two of one name in one file share one node,
a graph gap);
3. the file's own top-level declarations;
4. its imports, followed through export { a as b }, export ... from and
export * barrels (cycle guard, depth bound; two barrels that answer
differently are ambiguous); a relative specifier resolves with the usual
extension and index rules, a bare one is external;
5. the standard library's global names: external;
6. the top-level declarations of script files (no import, no export): one
binds, several are ambiguous;
7. the members of the documented class or interface, `this.` included.
The other segments walk members or a module's exports. A member declared
without a node of its own is a graph gap; test code binds only from test
code. There is no scope_delta hook yet: an export change is a full run.
The families are held (ships=false) until their held-out audit passes; the
suite ships them through the test seam.
Proof: the TypeScript compiler (perf-bench/typescript b465fdbfe175), ship
build, against the field test's prototype records (cascade results left
out): 69 edges; 57 of the prototype's 61 pairs bound alike. The 4 others are
doc blocks without a definition of their own (on an `if` statement, a local
`var`, an enum member, a free-standing @typedef block), which the core does
not harvest. Of the 12 edges the prototype has no pair for, 4 are the same
targets the prototype resolved without recording a source node, and 8 bind
PropertyDescriptor to the repository's own src/lib/es5.d.ts, which the
prototype called an external library global (kept: the repository declares
it). Unresolved rows agree with the prototype's reasons apart from the
documented reason split (not_in_scope -> missing/ambiguous).
Known limit: package.json and tsconfig.json are not indexed (discovery
ignores them), so workspace packages and tsconfig `paths` stay external.
Tests (doc_mentions_ts): tokens with their lines; the scope blob and its
persisted form; every resolution rule, including a function-body
declaration that binds and two of one name that do not; incremental equals
full (a doc edit and a body edit repair one file, an export change is a full
run); 60 modules give the same edges and rows with one worker and several.
Each rule red with it reverted (the body declaration's visibility and its
line check, barrel ambiguity, the parameter rule, code spans, the library
globals).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…til their audit
A PHP doc block names code with `@see Ref` at the start of a tag line (a
description may follow) and with inline `{@see Ref}`, both family `see`.
doclink_php.c harvests them (code spans and fenced blocks hold none; @link,
@uses and the other tags are not harvested; a URL is the core's href family)
and writes each file's scope: namespace blocks, use imports, types with
their supertypes already qualified in their own file, members, functions.
The persisted scope drops lines and imports: other files read names only.
Declarations inside a top-level conditional count as top level
(`if (!function_exists('f')) { function f() {} }`), never a function body.
doc_links_php.c resolves a reference as a FQSEN with PHP's own name rules:
- a leading backslash is taken as written; otherwise the first segment is
replaced when it is the alias of a class `use` of the namespace block the
reference is written in, else the block's namespace is put in front
(phpDocumentor's resolver);
- beyond that tool, as PHP itself has them: an unqualified function name is
taken from a `use function` import, else from the current namespace, else
from the global namespace; and self/static/parent name the documented
type and its superclass;
- a bare `name()` that would bind a function but is written in a type that
declares or inherits a method of that name is ambiguous (the method or the
function; the reference does not say which);
- members are looked up on the type, its traits, its superclass and its
interfaces (depth first); type, function and method names compare without
case, properties and constants with it;
- properties, class constants and enum cases have no graph node: graph_gap;
so has a type or function the graph folds into another one of the same
name in its file (two namespace blocks), which the scope flags;
- a name the repository does not declare is external outside the
repository's namespace roots (built-ins, Composer dependencies), else
missing. Residual: a function a dependency declares in the current
namespace is invisible, so the fallback would bind a global function of
that name.
There is no scope_delta hook yet: a declaration change is a full run.
The family is held (ships=false) until its held-out audit passes; the suite
ships it through the test seam.
Proof (ship build, Apple M5 Pro / 48 GB, base 196ca71):
- koel 04ed8beaec34 vs the field test's prototype: 4 of its 5 pairs bound
alike; the fifth sits in a class constant's doc block, which has no node.
- cakephp a75828db: 342 edge mentions + 39 unresolved rows = every one of
the 381 non-URL references in function and type doc blocks; 36 more sit
in property and constant doc blocks (no node, not harvested).
- symfony 9917e115: 452 edge mentions (434 edges) + 205 rows = all 657; 24
in property, constant and other doc blocks.
- edges only through the global fallback: 1 (cakephp `@see debug()` in
Cake\Core, the global debug() helper: correct); one more on symfony was
wrong (`@see run()` meaning the class's own method bound a global script
function) and the method-name rule above makes it ambiguous. Through
self/static/parent: 20, all correct (12 + 5 self, 3 parent).
- a random sample of 24 edges (12 per corpus) read against their source
lines: all correct.
Tests (doc_mentions_php): tokens with their lines; the scope blob, its
persisted form, namespace blocks and conditional declarations; every
resolution rule; the global fallback and self/static/parent each in a test
of its own; incremental equals full (a doc edit and a body edit repair one
file, a removed function is a full run); 60 modules give the same edges and
rows with one worker and several. Each rule red with it reverted (global
fallback, self/static, parent, trait members, the folded-name gap, use
aliases, method names without case, the bare-name method lookup, the
namespace roots, code spans, the method-name guard, conditional
declarations).
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
… until their audit
A Doxygen comment in a .c or .h file (a block opening with slash-star-star
or slash-star-bang, a run of /// or //! lines) names code with `@ref name`
or `\ref name` (family doxygen_ref) and with the names an `@see`, `\see`,
`@sa` or `\sa` paragraph lists that have the shape of a symbol (`name`,
`name()`, `::name`, `Type::member`; family see). Code blocks, fences, code
spans, quoted labels and the word after \c, \p, \a, \b, \e, \em hold none; a
URL is the core's href family. A .h is parsed as C++, which does not change
the rule; other C++ and Objective-C files are not part of the leg.
C keeps no node for a function prototype, so the docs of a header's API
were never stored anywhere. The doc-link driver gets an optional loose_docs
hook, called after the definitions and the file's own doc: the C leg reads
every Doxygen block outside function bodies that no definition took, and
its references belong to the file (the File node is the source).
The scope ("c1") lists the definitions with nodes (function, variable,
type, enum constant, field, object-like and function-like macro) with their
qualified names, their linkage (static, or a type, constant or macro of a
.c file, is the file's own) and the parent of a constant or field, and the
pages, groups, anchors and sections the file's docs define.
doc_links_c.c resolves a name as Doxygen does, without imports:
- a page, group, anchor or section name is no code entity (graph_gap) and
never binds a symbol of the same name;
- then the documented file's own definitions (static ones too), its fields,
then what every file sees (external linkage, a header's types, constants
and macros); a static definition of another file is not visible;
- candidates count by qualified name (a prototype and its definition, #if
variants: one node); with `()` written a function or function-like macro
wins, then a definition wins over a macro;
- `Type::member`: a field of the struct or union Type, or a constant of the
enum Type;
- one candidate binds, several are ambiguous; a word of an @see paragraph
that names nothing and is a plain lowercase word is prose (Doxygen prints
it as text): no row; test code binds only from test code.
There is no scope_delta hook yet: a declaration or linkage change is a full
run.
The families are held (ships=false) until their held-out audit passes; the
suite ships them through the test seam.
Proof (ship build, Apple M5 Pro / 48 GB, base 7a321ca):
- xxhash (redis 4f20cb489344, a clean copy), the field test's 174 audited
links, 110 of which had hit a rename macro before C1: every harvested one
now names the right entity (169 edges, 2 self-mentions: XXH_NAMESPACE's
own doc); the other 3 are @copydoc, which this leg does not harvest.
- redis: doxygen_ref 74 edges (179 mentions), see 25 (30); rows: graph_gap
50, missing 6, ambiguous 3, unparseable 1. The prose rule took the 75
rows of words like "for" and "details" out.
- pico-sdk 079c6f39: doxygen_ref 488 (730), see 199 (219); rows: graph_gap
142 (groups and pages), missing 94, ambiguous 68 (one type per chip,
rp2040 and rp2350), test_only_target 28 (assembly functions with only a
C test version), unparseable 5.
- libusb abba63ed: doxygen_ref 256 (284), see 39 (44); rows: graph_gap 62,
missing 18, unparseable 2, ambiguous 2. 46 of the edges are
Type::member references.
- libevent d82464a2: see 176 (230); rows: missing 9.
- a random sample of 24 edges (8 per corpus, pico-sdk, libusb, libevent)
read against their source lines: all correct, among them a header
prototype's doc linking to the definition in the .c file.
Finding outside the leg: libevent's event_assign has no node (its return
type and name are split by an #if block), so its references are missing.
Tests (doc_mentions_c): tokens with their lines and the file-level source
of a prototype's doc; C++ files out, headers in; the scope blob; every
resolution rule; incremental equals full (a doc edit and a body edit repair
one file, a definition made static is a full run); 60 modules give the same
edges and rows with one worker and several. Each rule red with it reverted.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…to its type PHP properties, class constants and enum cases have no graph node, so their doc blocks were never read: cakephp has 36 @see references there, symfony 21. The PHP leg now uses the driver's loose_docs hook: a /** */ block right above a property, constant or case is harvested with the type around it as the source (as the field test's prototype attached it), and resolved like any other reference written in that type (self:: is the type). The driver marks as the file's only what a hook pushes with the file stand-in (the C leg's prototype docs); a hook may push with a definition of the file instead. Proof (ship build, Apple M5 Pro / 48 GB, base 80e000a): - koel 04ed8beaec34: all 5 of the prototype's pairs bound alike (the fifth sits in a class constant's doc). - cakephp a75828db: 373 edge mentions + 44 rows = every one of the 417 non-URL references (was 381 of 417). - symfony 9917e115: 459 + 219 = 678 of 681 (the other 3 sit in blocks before code the census does not classify). Tests: doc_mentions_php resolves a property's doc block to an edge from its class; red with the hook's walk reverted, and red when the driver marks every token of the file pass as the file's. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
phpDocumentor reads `@see name()` as a function. Authors write it for the
documented class's own method: symfony has 97 such references that ended as
external rows (Command `@see setCode()`, ProgressBar `{@see resumeAll()}`),
and one that bound a global build-script function (ProcessHelper `@see
run()`, meaning its own run()). In the doc of a type or of one of its
members, a bare name() is now a method the type declares or inherits; a
`use function` import of the name still wins, and outside a type the
function rules stay. The ambiguity guard this replaces is gone.
Proof (ship build, Apple M5 Pro / 48 GB): symfony 9917e115 +91 edges
(external bare name() rows 97 -> 6), cakephp a75828db +6 (7 -> 1); a sample
of 14 new edges read against their lines: all correct, inherited methods
included (UploadedFile -> File::guessExtension).
Test: doc_mentions_php_current_class (the method wins over a global function
of the same name; the documented method itself is a self-mention), red with
the rule reverted.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…ackages A bare import specifier was always external. The TS resolver now asks the pipeline what it already knows for import resolution, without indexing package.json or tsconfig.json: the nearest tsconfig/jsconfig `paths` and `baseUrl` (the alias collection; the first target, as TypeScript tries it first), then the workspace package whose `name` the specifier is (the package map), bound to the package's entry module (`exports`, `main`, `module`) when the repository indexes it. Every other bare specifier, a package's subpath included, stays external. Incremental runs stay exact: a tsconfig change re-resolves the files under it, a package.json change is a manifest change. path_alias gets cbm_path_alias_resolve_into, which writes into the caller's buffer; cbm_path_alias_resolve now wraps it (two raw allocations fewer, the memory-core baseline lowered to match). Also fixed: a declaration in an index file has no `index` in its QN (fqn.c strips it from a symbol's QN, not from the module's), so a reference to one missed its node; the resolver now names a file's declarations with that prefix. Proof (ship build, Apple M5 Pro / 48 GB): the TypeScript compiler b465fdbfe175 unchanged (69 edges, 57 of the prototype's 61 pairs); discord.js 4dc1acc6 unchanged (no doc reference names a workspace import; its packages' entries are build output). Tests: a tsconfig alias, a workspace package's entry and an index file's declaration each bind, each red with its rule reverted; path_alias, pipeline, edge_imports, incremental and all doc suites pass (1298). Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Diagrams name the parts of a system and how they connect; an OpenAPI document names its endpoints and their handlers. Both now enter the graph. Diagrams: - a Diagram node per diagram: a fenced block of a Markdown file (under its Section), a directive of a reST file (`.. mermaid::`, `.. uml::`, `.. graphviz::`, Sphinx `.. digraph::`), an Asciidoctor Diagram block of an AsciiDoc file (`[plantuml]`, `[source,mermaid]`, ...), or a diagram file of its own, named by its title, else by its file; - a DiagramElement node per element, DEFINES from its Diagram, and a DIAGRAM_ARROW edge per arrow (label, style, line); - formats: Mermaid (flowchart, sequence, class, ER, state, C4, architecture), PlantUML, Graphviz DOT, D2, draw.io (plain, compressed, .drawio.svg) and Excalidraw (.excalidraw, .excalidraw.json, .excalidraw.svg); .drawio.svg and .excalidraw.svg are no longer dropped as images; - an element's explicit link (Mermaid click/link, PlantUML [[url]], url of and !include, draw.io and Excalidraw link, DOT URL/href, D2 link) is a doc link read as a Markdown link, MENTIONS when it resolves. OpenAPI: - each operation of an OpenAPI or Swagger document (openapi.json and swagger.json, now read with the JSON grammar but no node per key, and any YAML or JSON file whose root says openapi/swagger) is a Route, named by the same QN a route its handler registers in code gets (cbm_route_canon_path, moved into the extraction library); - its operationId is a doc link to the handler: a dotted one (Connexion, with x-openapi-router-controller) as a qualified code name, a bare one when exactly one function or method of the repository has that name. The eight new link families are held until their held-out audit passes. Read on real repositories, which shaped the rules: Excalidraw drawings put text over shapes and draw arrows up to them without binding, so loose text names the smallest box it sits in and a loose arrow end meets the smallest named box it touches (the drawing's frame only at its border); arrows bound to free text meet the text; D2 block strings and nested blocks; DOT line breaks and sentence-long ids; PlantUML kinds of classes inside packages and nested classes (`..+`, nested -> container, so they do not collide with the container's association). Connexion's 24 specs: 160 operationIds, all linked to their handlers. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…C, Perl The TS/JS, PHP, C and Perl doc-link layers keep a scope blob per file but had no scope_delta hook, so any change of a file's declarations made the incremental closure repair decline (doc_scope_changed) and the index rebuild in full: removing a TypeScript function forced a full run. cbm_doclinks_scope_delta_lines compares two blobs line by line in order, as C# does: a dropped record that declares one name is repaired file by file (the name is reported, so the files whose references named it are re-resolved); anything new or changed, and every record others resolve through, stays a full run. The records that declare one name: TS D (a top-level declaration), PHP F and K (a function, a member), C D of a function, variable, enum constant, field or macro and A (a Doxygen anchor), Perl S (a sub). Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A Markdown Section's docstring is its body collapsed and cut at 500 bytes. A diagram fence in that body put the format's syntax into it (`-->`, `participant`, `classDiagram`, `subgraph`), which names no code, and pushed the section's prose out of the cap. The doc -> code candidates are scored on that text. Each top-level diagram fence (mermaid, plantuml, puml, uml, dot, graphviz, d2) is now replaced in the section's text by the labels its diagram parser reads: the names of its elements, then its arrow labels, in source order. The parse runs into a scratch result, so the file's own Diagram and DiagramElement nodes are untouched. A section without such a fence keeps its text byte for byte; other fences stay as written. Measured before it was chosen, on held-out repositories (147 sections that embed diagrams, 503 section/candidate pairs, three blind reading rounds): fence as written 277 stored precision 0.45 42 sections with a correct candidate labels (this) 310 stored precision 0.54 56 sections with a correct candidate fence dropped 127 stored precision 0.54 29 sections with a correct candidate Labels gave 20 sections a correct candidate that the fence as written did not, and lost 6 (exact McNemar p = 0.009). Dropping the fence lost more than it gained. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
…udit
The held-out audit of the eight new languages is scored. Each tier is a
language and a reference form, read on a sample of 150 links (census below
150) from repositories never used to build or tune the resolvers. Three
blind reading rounds; bar: Wilson 95% lower bound >= 0.90 and point >= 0.95.
tier population judged correct Wilson low
go doc_link 5980 150 150 0.975
java link 23934 150 150 0.975
java linkplain 1372 150 150 0.975
java see 7711 150 150 0.975
java throws 650 150 150 0.975
java value 79 79 79 0.954
kotlin kdoc_link 3888 150 150 0.975
kotlin sample 279 150 150 0.975
kotlin see 369 150 150 0.975
kotlin throws 73 73 73 0.950
rust intra_doc 14119 150 149 0.963
rust link_def 1491 150 150 0.975
perl pod_L 2255 150 150 0.975
ts/js link 1222 150 150 0.975
php see 5171 150 150 0.975
c doxygen_ref 463 150 150 0.975
c see 509 150 145 0.924
These 17 families now ship: a resolved reference is a MENTIONS edge.
TS/JS {@linkcode} (10 held-out links) and @see (18) were all judged
correct, but are too few to reach the bar; they stay held, as do the
diagram and OpenAPI link families (3 links on 21 held-out repositories).
The Go ship-gate test turned its family off and restored only the held
families afterwards; with Go shipping it left Go off for the tests that
follow it. It restores the production gates first now.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
A Markdown section that embeds a diagram is about its candidate functions
more often than the Markdown curve says, by how much depends on the
diagram's kind. 553 candidates from such sections in 16 held-out
repositories, judged blind in three rounds:
0.20-0.30 0.30-0.40 0.40+ local extras
prose 0.24 0.28 0.45 0.275
structural 0.32 0.46 0.57 0.78 (9 items)
Structural is Mermaid sequence/class/ER/C4/architecture and PlantUML
C4/class/sequence/use-case/component; prose any other Mermaid or PlantUML
kind. A section takes the highest family of the Diagram nodes it defines;
its function candidates at or inside the doc's home and its local extras
carry the family's value, and the first band is now stored. Outside
functions, files, folders, other formats and sections without a diagram
keep the Markdown curve.
On kubernetes' apiserver folder the sequence-diagram section's
candidates move from 0.22/0.51 to 0.46/0.57, the flowchart sections gain
five first-band candidates at 0.24, other sections and the graph are
unchanged.
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
The Windows headers define far and near as empty macros, so 'const char *far = ...' became 'const char * = ...' on the CLANG64 leg. The variable is far_src now. Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Documentation names code. This PR brings three more kinds of it into the graph.
Doc-comment references in eight more languages. C# came first. A reference in a doc comment now becomes a
MENTIONSedge from the documented definition to the code it names, resolved by each language's own rules:[Name],[pkg.Name],[Recv.Method]{@link},{@linkplain},@see,@throws,{@value}[x],@see,@throws,@sampleL<>{@link}@see,{@see}@ref,@seeDiagrams. Mermaid, PlantUML, Graphviz DOT, D2, draw.io and Excalidraw get nodes. They count whether they are
fenced in Markdown, a reST directive, an AsciiDoc block, or a file of their own. Each one is a
Diagramnode with aDiagramElementper element (DEFINES) and aDIAGRAM_ARROWedge per arrow.OpenAPI operations. Each operation of an OpenAPI or Swagger document is a
Routeon the same qualified namea handler's route registration gets in code.
How the links were measured before shipping
Every new link family is gated (
doclink.h,ships). A family ships only after a pre-registered held-outaudit passes it:
tune the resolvers.
{@link}{@linkplain}@see@throws{@value}[x]@sample@see@throwsL<>{@link}@see@ref@see@see{@linkcode}The families that fail on size still resolve. Their links are stored as rows (
doc_link_unresolved, reasonbelow_bar_tier), not as edges.The diagram and OpenAPI link families stay held. These are Mermaid
click, PlantUML[[url]]/!include, thedraw.io/Excalidraw/DOT/D2 links and OpenAPI
operationId. On 21 held-out repositories they produced 3 links in all,too few to audit. A bare
operationIdlinks only when exactly one non-test function has that name. On the held-outspecs no such case occurred: the names matched nothing (31) or were ambiguous (24).
Diagram text in section candidates (experiment E)
A Markdown section embedding a diagram used to carry the diagram's syntax (
-->,participant) in its text. Threevariants were compared on 147 held-out sections that embed diagrams: 503 section/candidate pairs, judged blind.
The shipped variant gains 20 sections and loses 6 (exact McNemar p = 0.009).
How likely a diagram section is about its candidates
A section that embeds a diagram is about its candidate functions more often than the Markdown curve says. How much
more depends on the kind of diagram:
553 candidates from such sections in 16 held-out repositories were judged blind in three rounds. Each family now
carries its own p:
A section's family is the highest of the diagrams it defines. The first band is now stored for both families.
The structural local-extras value rests on all 9 such candidates (95% interval 0.45-0.94).
Graph diagrams (DOT, D2) did not occur in Markdown sections. Their sections, like every other section, keep the
Markdown curve.
Compatibility
DiagramandDiagramElementand the edge typeDIAGRAM_ARROWarenew; consumers that enumerate labels see them.
.drawio.svgand.excalidraw.svgare no longer dropped as images;openapi.jsonandswagger.jsonare read with the JSON grammar, but get no node per key.release rebuilds once on upgrade and gains all of this. An index built from
mainbetween Semantic relations with a judged p; doc sections linked to their code by format and position #2574 and this PRneeds one manual full re-index to pick up these changes for its unchanged files.
Verification
compared with the audited links. Every shipped link equals an audited link. The C# rows are identical, and so are all other unresolved rows apart from the
below_bar_tierrows of held families. In two TS/JS doc comments the shipped{@link}edge now counts one reference instead of two: the second is an@seeto the same target, a held family, so it is stored as abelow_bar_tierrow.apiserverfolder, a development corpus, was indexed with the binary beforeand after the diagram-section curve:
turns its test red.
uses, is clean on the 37 changed C files.