javascript-doxygen

September 16, 2026 ยท View on GitHub

javascript-doxygen is a documentation-led Doxygen input-filter project for JavaScript. The long-term goal is to let JavaScript remain JavaScript-native, with JSDoc-style source documentation translated only where Doxygen needs help.

The maintained filter is doxygen-javascript.awk. It currently supports the canonical simple-parameter forms governed by ADR-013 and ADR-014, canonical typed @returns records governed by ADR-016, canonical typed-and-described @throws records governed by ADR-017, canonical typed @yields records governed by ADR-019, native-compatible @deprecated and @see records governed by ADR-020, canonical virtual @typedef records governed by ADR-021, canonical properties of those virtual typedefs governed by ADR-022, canonical named @callback contracts governed by ADR-023, and canonical @type annotations governed by ADR-024. ADR-018 exercises governed forms through Doxygen's JavaScript parser, ADR-025 establishes generated development, ordinary, and minified build artifacts with adjacent SHA-256 files, ADR-026 publishes those exact artifacts through the semantic-version release workflow, and ADR-027 normalizes generated, released, and vendored artifact names to the sibling doxygen-<language>.awk convention. Unsupported forms remain unchanged. The filter does not infer JavaScript semantics or claim complete JSDoc coverage.

Current capability

For newline-terminated JavaScript input, the filter preserves source records and translates supported JSDoc records inside conservatively recognized multi-line JSDoc blocks.

A required parameter:

@param {string} name - The name to greet.

is translated at the Doxygen boundary to:

@param name The name to greet. Type: string.

An optional parameter:

@param {string} [name] - The name to greet.

is translated to:

@param name The name to greet. Type: string. Optional.

An optional parameter with a compact documented default:

@param {string} [name=World] - The name to greet.

is translated to:

@param name The name to greet. Type: string. Optional. Default: World.

A typed return value:

@returns {Promise<Configuration>} Validated configuration owned by the caller.

is translated to:

@returns Validated configuration owned by the caller. Type: Promise<Configuration>.

A typed exception contract:

@throws {TypeError} If the identifier is not a string.

is translated to:

@throws TypeError If the identifier is not a string.

A typed generator-yield contract:

@yields {Record} Validated records in source order.

is translated to the generated Doxygen-facing command:

@jsyields Type: Record. Validated records in source order.

@jsyields is not maintained JSDoc. A consumer's Doxyfile must define the governed jsyields alias documented under Consumer Doxyfile setup. The alias introduces the logical paragraph break inside Doxygen while the filter continues to emit exactly one physical output line for the input @yields line.

Some canonical JSDoc requires no translation. ADR-020 establishes native-compatible pass-through for the currently proven forms:

@deprecated Use formatValue instead.
@see formatValue

Those records pass through unchanged because Doxygen already accepts the same commands with compatible semantics. Native-compatible support remains form-specific and evidence-driven; a similarly named JSDoc and Doxygen command is not automatically considered supported.

A named reusable virtual type:

@typedef {Object} User

is translated to a generated alias invocation on the same physical line:

@jstypedef{jsdocvirtualtypeuulslelr||User||Object}

The maintained source remains ordinary JSDoc. @jstypedef and the encoded page label are generated representation only. The consumer Doxyfile alias expands the record into a Doxygen related page titled User, preserves surrounding prose, and displays the maintained base type. The page provides a named Doxygen @ref target without fabricating a JavaScript class, struct, interface, typedef declaration, or other runtime symbol.

A canonical property following that supported typedef in the same JSDoc block:

@property {string} name - Display name shown to readers.

is translated on the same physical line to:

@jsproperty{string||name||Display name shown to readers.}

The consumer alias renders it as structured child documentation on the User virtual-type page. The property is not promoted to a fake JavaScript member or a separate generated entity. A property outside a governed virtual typedef block remains visibly unchanged.

A named reusable callback contract:

@callback Handler
@param {string} value - Normalized value supplied to the callback.
@returns {boolean} True when the value is accepted.

is represented as a second kind of virtual documentation page. The callback line becomes:

@jscallback{jsdocvirtualcallbackuhlalnldlllelr||Handler}

while the already-governed parameter and return records retain their existing translations. Doxygen renders those sections inside the Handler related page, so the callback remains a named, cross-referenceable interface without fabricating a JavaScript function declaration. Callback labels use a distinct generated namespace from typedef labels so equal maintained names cannot collide.

A canonical symbol type annotation:

@type {number}

passes through doxygen-javascript.awk unchanged. ADR-024 governs this as a consumer-configuration capability rather than an AWK translation. The consumer's Doxyfile defines:

ALIASES += type="@par Type^^"

Doxygen then renders the maintained expression, including its braces, as a symbol-local Type paragraph. The alias does not parse or validate the type and does not make the expression a native Doxygen or JavaScript semantic type.

The maintained JavaScript source remains unchanged. The filter preserves type and default text without interpreting either. Current default-token support requires non-empty text containing neither whitespace nor ]. Typed @throws support requires a compact exception type without whitespace plus a non-empty description. Virtual typedef, supported typedef-property, and supported callback names currently require simple JavaScript identifiers. Unsupported forms such as dotted property notation, singular @return, untyped @returns, description-only @throws, type-only @throws, description-only @yields, type-only @yields, dotted typedef names, untyped typedefs, standalone properties, complex property forms, and callback namepaths such as Requester~requestCallback continue to pass through unchanged.

All governed transformations preserve one output record for each input record. The TAP suite checks this invariant for every fixture. Supported pass-through forms, including ADR-024 @type, preserve the original record completely. That line correspondence is part of the Doxygen integration boundary because Doxygen associates filtered input with source locations and source-browser anchors.

Run the maintained filter directly with:

awk -f doxygen-javascript.awk -- path/to/source.js

Consumer Doxyfile setup

The downstream runtime model is deliberately the same as the sibling AWK, Bash, and Python Doxygen filters. A consuming repository uses bashdeps to pin one released JavaScript filter and materialize it beneath its own vendor/ directory, conventionally as:

vendor/doxygen-javascript.awk

The consuming repository owns its Doxyfile. Configure JavaScript parsing and the vendored filter there, together with the aliases required by the current governed representations:

EXTENSION_MAPPING = js=JavaScript
FILTER_PATTERNS   = *.js="awk -f vendor/doxygen-javascript.awk --"

ALIASES += jsyields="@par Yields^^"
ALIASES += jstypedef{3||}="@page \1 \2^^@par JSDoc virtual type^^Base type: \3."
ALIASES += jsproperty{3||}="@par Property: \2^^Type: \1.^^\3"
ALIASES += jscallback{2||}="@page \1 \2^^@par JSDoc callback"
ALIASES += type="@par Type^^"

The exact invocation may select a different AWK executable where required by the consumer, but the vendored JavaScript filter remains the one runtime dependency. The checked-in doxygen-javascript.conf file is the repository's canonical integration-test/reference copy of the alias definitions. Consumers do not fetch that file through bashdeps; they maintain the required alias configuration in their own Doxyfile.

Build artifacts

ADR-025 establishes a local deterministic build surface, with artifact naming normalized by ADR-027. awk-minifier is pinned in dependencies.txt and synchronized through bashdeps as vendor/awk-minifier.awk.

From an unprepared checkout, run:

make all

make all prepares the pinned build dependency and creates:

dist/doxygen-javascript.dev.awk
dist/doxygen-javascript.dev.awk.sha256
dist/doxygen-javascript.awk
dist/doxygen-javascript.awk.sha256
dist/doxygen-javascript.min.awk
dist/doxygen-javascript.min.awk.sha256

The development artifact contains the complete documented maintained filter plus comment-only build provenance. The ordinary artifact removes only the project's AWK Doxygen documentation records while preserving executable behavior and ordinary implementation comments. The minified artifact applies the pinned released AWK Minifier to the ordinary artifact body while regenerating provenance outside the minifier input.

For already prepared dependency state, make build is network-free. make deps-check verifies the pinned build dependency without repair. The generated artifacts and hashes are ignored build state and are not committed.

Validate generated artifact shape, checksums, and TAP parity with:

make test-dist AWK_BIN=mawk
make test-dist AWK_BIN=gawk

When Doxygen is available, exercise every generated artifact through the downstream integration suite with:

make test-dist-doxygen AWK_BIN=mawk
make test-dist-doxygen AWK_BIN=gawk

Releases

ADR-026 publishes the generated build outputs through the semantic-version workflow, with current asset naming normalized by ADR-027. The ordinary release asset:

doxygen-javascript.awk

is the canonical normal bashdeps consumer artifact. Releases also publish the .dev and .min variants for inspection or deliberate alternate use, together with one .sha256 file for each AWK artifact. Publishing those variants does not change the normal one-file runtime dependency model.

Release v0.0.3 remains historically valid with the earlier javascript-doxygen*.awk asset names. Releases governed by ADR-027 use only the normalized doxygen-javascript*.awk names; published historical assets are not renamed or replaced.

The release workflow calculates the prospective semantic version without creating a tag, validates maintained source plus all three generated filters under both mawk and GNU awk and through Doxygen, then creates the v<version> release at the exact validated commit. All six generated files are uploaded as release assets. A dependent post-publication canary downloads the public release assets, verifies all three hashes, and repeats TAP and Doxygen integration against every downloaded filter under both supported AWK implementations.

A normal consuming repository should pin a specific current release of doxygen-javascript.awk in its bashdeps manifest using the public release-asset URL and the digest from doxygen-javascript.awk.sha256. Consumers remaining on v0.0.3 continue to use that release's historical javascript-doxygen.awk filename. Consumers should not pin main, latest, or another moving reference.

Regression tests

Behavior-focused source fixtures live under:

test/fixtures/

Golden filtered output lives under:

test/expected/

The regression harness is:

test/run-tests.sh

It emits TAP version 13 output. Run the current suite with either supported AWK implementation:

make test AWK_BIN=mawk
make test AWK_BIN=gawk

The current suite proves nineteen behaviors: ordinary JavaScript passes through unchanged; canonical required parameters translate; optional parameters with and without compact documented defaults translate; unsupported dotted property notation remains visible unchanged; canonical typed @returns records translate; singular @return remains visible unchanged; canonical typed-and-described @throws records translate; unsupported description-only and type-only @throws forms remain unchanged; canonical typed @yields records translate; unsupported description-only and type-only @yields forms remain unchanged; native-compatible @deprecated and @see records pass through unchanged; canonical virtual @typedef records translate to related-page aliases; unsupported typedef forms remain unchanged; canonical properties following a governed virtual typedef translate to page paragraphs; standalone properties remain unchanged; canonical simple callbacks translate to virtual callback pages; unsupported callback namepaths remain unchanged; and canonical @type annotations pass through unchanged. Every fixture also proves that filtering preserves physical line count.

JavaScript/Doxygen integration

Filter-level golden output and downstream Doxygen interpretation are separate test surfaces. ADR-018 establishes test/doxygen/ as the integration surface and uses Doxygen's JavaScript parser rather than translating JavaScript into another source language. ADR-019 extends that integration surface to the alias-backed Yields representation, ADR-020 uses the same surface to prove native-compatible tag semantics, ADR-021 uses it to prove named virtual typedef pages and cross-reference resolution, ADR-022 proves that governed properties render on the corresponding virtual-type page, ADR-023 proves named callback pages with parameter and return sections, and ADR-024 proves consumer-alias rendering for byte-preserved @type annotations. ADR-025 additionally requires the generated artifacts to preserve that tested behavior, and ADR-026 reuses the same evidence against exact published release bytes.

Run the integration suite with either supported AWK implementation:

make test-doxygen AWK_BIN=mawk
make test-doxygen AWK_BIN=gawk

The repository integration Doxyfile applies the selected JavaScript filter through FILTER_PATTERNS, includes the repository-only doxygen-javascript.conf reference fragment, generates XML, and verifies semantic output structure for governed parameter, return, exception, yield, deprecation, see-also, virtual typedef, typedef-property, callback, and type-annotation forms. The yields assertions verify a dedicated Yields paragraph plus source-location evidence for the generator fixture. Native-tag assertions verify that unchanged @deprecated and @see records are interpreted by Doxygen rather than merely surviving the filter. The typedef assertions verify a named related page, retained source prose and base type, and a resolved Doxygen @ref to the generated virtual type. The property assertions verify the Property: name heading, documented type, and maintained description inside that virtual typedef page. Callback assertions verify the named related page, parameter and return sections inside that page, and a resolved Doxygen @ref to the generated callback label. Type-annotation assertions verify the documented JavaScript symbol, a Type paragraph attached to its documentation, and retention of the maintained JSDoc type expression. CI runs this surface separately from the TAP suite so a textual filter regression can be distinguished from a downstream Doxygen integration regression.

Generated integration output beneath test/doxygen/out/ is ephemeral and ignored by Git. Passing integration tests demonstrate only the explicitly exercised forms and configuration; they are not evidence of arbitrary JavaScript or JSDoc support.

Project reference documentation

Project self-documentation is separate from JavaScript/Doxygen integration. The maintained implementation is AWK, so doxygen-javascript.awk is documented with the pinned released awk-doxygen filter. The Bash TAP harness is documented with the pinned released bash-doxygen filter.

Prepare and generate the project reference documentation with:

make deps-docs
make deps-docs-check
make docs AWK_BIN=mawk

The generated ADR landing page lives at doc/adr/README.md, and Doxygen HTML is written beneath doc/reference/. Both outputs, together with the synchronized vendor/ dependencies, are generated state and are ignored by Git.

A documentation canary exercises this path in pull requests. Pushes to main generate the same reference documentation and publish doc/reference/ to GitHub Pages. ADR-015 governs this self-documentation boundary.

Deferred capabilities

The repository was initialized from python-doxygen, so some copied Python ADRs, tests, and historical references remain while the project is migrated. Their presence does not mean that javascript-doxygen implements Python behavior or that those interfaces are supported here. ADR-027 removes the copied root doxygen-python.awk implementation now that the JavaScript filter has its own complete build and release lifecycle.

The following capabilities remain deliberately deferred:

  • complex JSDoc parameter and property forms beyond the explicitly accepted contracts;
  • scoped or otherwise complex callback namepaths; and
  • automatic linking of arbitrary type expressions to virtual typedef or callback pages.

Those capabilities should be enabled only after their JavaScript-specific contracts are governed and tested. ADR-012 records the bootstrap boundary, ADR-013 governs required parameters, ADR-014 governs optional parameters, ADR-015 governs project self-documentation, ADR-016 governs canonical typed return translation, ADR-017 governs canonical typed exception translation, ADR-018 governs JavaScript/Doxygen integration testing, ADR-019 governs alias-backed typed yield translation, ADR-020 governs evidence-driven native-compatible tag pass-through, ADR-021 governs related-page representation for virtual typedefs, ADR-022 governs canonical child properties of those virtual typedefs, ADR-023 governs named virtual callback pages, ADR-024 governs byte-preserved canonical @type annotations rendered through consumer configuration, ADR-025 governs the local generated distribution build surface, ADR-026 governs semantic-version release publication and the exact-public-bytes canary, and ADR-027 governs the normalized Doxygen-first artifact and consumer filename convention.

Coding standards and governance

This repository adopts the pinned shared standards snapshot under doc/standards/. .codingstandardrc records the concrete upstream release and verified archive digest. Applicable imported standards are project requirements; accepted repository-specific ADRs and explicit local policy may refine them.

Do not edit files beneath doc/standards/ locally. Shared-standard changes belong upstream in wesley-dean/coding_standards; repository-specific decisions belong in this repository's ADRs.

Maintained JavaScript documentation is governed by doc/standards/javascript/documentation-standard.md. That standard establishes JSDoc as the maintained source language and defines the canonical authoring forms. Adopting the standard does not imply that every valid JSDoc construct is already translated or otherwise supported by doxygen-javascript.awk; filter capability remains limited to behavior supported by accepted local ADRs and executable regression tests.

Before changing parser boundaries, JSDoc translation behavior, native-compatible or consumer-alias support claims, test contracts, portability, documentation publication, consumer Doxygen configuration, virtual-type representation, build artifacts, or release interfaces, review AGENTS.md, the applicable imported standards, all ADRs in doc/adr/, and doc/decisions.md.

License

This project is licensed under the Creative Commons License 1.0 Universal License. See LICENSE for details.

Contributing

Contributions are welcome. See CONTRIBUTING.md and CODE_OF_CONDUCT.md.

Author

  • Wes Dean