Repository navigation
Releases: Andersseen/doqs
Release list
@doqs/analog 0.13.0
Production hydration and onboarding reliability. Additive: no exported type, function, configuration key, frontmatter key, route or --host-docs-* token was removed or changed (pnpm verify:public-api passes against the 0.7 baseline; the report differs only in its version). The release is driven by the existing workflow after merge; nothing is published by hand. Verified against Angular 21.2.25 and 22 with @analogjs/* 2.9.2 (peer range unchanged: @analogjs/content ^2.9.2).
Highlights
doq doctor --buildno longer passes a build that cannot hydrate. A newbuild.aotfinding reads the built scripts and fails when a bundle contains Angular'sJIT compiler unavailablepath without the compiler (a component left uncompiled), warns when the runtime compiler is bundled on purpose, and passes otherwise. Spec 0021 recorded an initialized consumer whose build anddoq doctor --buildsucceeded and whose pages then never hydrated; both reported success.- The cause is upstream and still open.
@analogjs/vite-plugin-angular(2.9.0, 2.9.1 and 2.9.2, with or without Doqs) shares one compilation-output map between the concurrently running client and SSR builds and clears it when the first finishes; a module the other environment transforms afterwards is emitted with plain decorators, with exit code 0 and no warning. It is intermittent under load (2–3 of 24 parallel builds in the measured setups, none of 30 for a lighter Doqs-free host) and can be forced deterministically. Doqs does not work around it: rerun the build whenbuild.aotfails. Seedocs/specs/0022-production-hydration-reliability/. - Initialized consumers are verified in a real browser. The packed-tarball journeys now cover Angular 21 embedded, Angular 21 docs-first and Angular 22 embedded: hydration markers consumed, one application root and
<h1>, client-side navigation, Back/Forward, no Pagefind request with search off, and no browser error or warning.doq initsucceeding,doq doctorpassing andvite buildexiting 0 are three different claims from "the page hydrates".
Added and fixed
Added
build.aotindoq doctor --build(text and--json), Node-only and read-only like the rest of the CLI.
Known limitation recorded
- Documentation pages re-render instead of hydrating in place. The prerendered
<main class="doq-root">of a documentation page is discarded and rendered again on the client: the Markdown module is imported asynchronously, so the first client render is the loading placeholder. Markers are consumed and the final DOM is correct, but the prerendered content is replaced (no console message in production). Host pages and the documentation index reuse their nodes. Resolving the document before the component is created is a separate change, tracked as a 1.0 readiness item.
Repository tooling (not part of the package)
scripts/init-consumer.ts --analog=<version>builds a consumer against an exactly pinned Analog for diagnostics;scripts/aot-guard.tsstopsconsumer.ts,adoption.ts,adoption-routes.tsandadoption-volt.tswhen a build they produced is not AOT-compiled.- Extended browser CI. Linux Firefox/WebKit use the Playwright-maintained image pinned to
@playwright/test1.64.1, with GTK 4, Graphene and GStreamer runtime libraries and a non-root user for Firefox's sandbox. A focused production-browser Chromium suite runs onwindows-latest. Hosted Linux and Windows acceptance passed in CI run 43. - Accessibility test stability. The reduced-motion E2E check waits for the hydrated documentation root before reading computed styles. VoiceOver/Safari and NVDA/Windows remain NOT RUN; see the manual protocol.
- Windows test runner portability. The production E2E launcher invokes pnpm's JavaScript entrypoint through Node, so the Windows
.CMDshim works withspawnSync.
@doqs/analog 0.12.0
Multilingual documentation, accepted in production builds. Additive: no exported type, function, configuration key, frontmatter key, route or --host-docs-* token was removed or changed (pnpm verify:public-api passes against the 0.7 baseline). The release is driven by the existing workflow after merge; nothing is published by hand.
Highlights
- Locale-aware catalogs and routes.
DoqPaths.i18ndeclares independently authored Markdown directories per locale and version archive; the default locale keeps its URLs, other locales get locale-prefixed routes, and a missing translation is never inferred from another language. - Provider-neutral translation adapter.
provideDoqI18n()andDoqI18nAdapterconnect the host's own locale lifecycle (a signal in the host) to Doqs-owned text. Doqs does not ship a competing translation provider;ownsRoutingandownsHeadstate what the host owns. - Localized interface and playgrounds. Playground controls, validation, copy states, dialog labels and announcements use the same
DOQ_DEFAULT_MESSAGEScatalog. - Localized Pagefind. Locale and version filters compose; a locale-scoped query fails closed with a rebuild message when the index has no locale metadata.
- RTL and SEO ownership.
dir,lang, canonical andhreflangalternates are written by Doqs, or left to the host withownsHead. - Sticky table of contents. The sidebar and TOC stay below the host header and scroll internally on tall pages.
- Compatibility and adoption hardening. The packed tarball is proven outside the monorepo on Angular 21 and 22, with localized, unlocalized, docs-first, embedded, versioned, search-disabled, playground, API-reference and source-authoring consumers. Repository-only adoption proofs now pin their upstream revisions, separate onboarding of an unintegrated application from rebuilding an already integrated one, and run in an isolated extended CI job.
Added and fixed
Added
-
Multilingual production fixture. Showcase A now exercises isolated English, Spanish and Arabic documentation catalogs, a Spanish archive, a route-derived signal adapter and real Pagefind filtering. Production verification and the 0.12 release remain pending.
-
Playground localization. Playground-owned controls, validation feedback, copy states, dialog labels and live announcements now use the existing
DOQ_DEFAULT_MESSAGESadapter contract, so a host can translate the complete interactive surface without translating consumer-owned labels or code. -
Explicit route ownership.
DoqI18nAdapter.ownsRoutinglets a host state that it owns localized route composition independently of the number of locales configured for Doqs.
Fixed
-
Localized index and version links. Host-owned
/es/docsand/ar/docsindex routes now resolve the locale catalog from the active URL; version selectors omit archives a locale does not publish, and locale links keep their explicit target locale. Doqs-owned paths are prefixed once. No exported API changed. -
Localized search fails closed. A locale-scoped query now reports a rebuild message when Pagefind has no locale metadata or the requested locale is absent. Unlocalized sites keep searching legacy indexes without locale metadata.
-
Table-of-contents highlight during smooth scrolling. Following a fragment (TOC link, search result, deep link) pins the followed heading as active, but the pin was released while the page was still scrolling towards it when the host sets
scroll-behavior: smooth, so the previous section stayed highlighted (/docs/guides/rich-markdown#ruleslit "Titled code"). The pin is now held until the scroll ends (scrollend, with a 1.5 s fallback for engines without it) and only then checked against the viewport. No export, option, route or token changed.
Repository tooling (not part of the package)
pnpm verify:adoption:existingrebuilds Angular Movement, which already integrates Doqs, against the packed tarball and checks every Markdown route it derives from the real tree;verify:adoptionandverify:adoption:routesare pinned to the last pre-integration revision,verify:adoption:voltto a pinned Volt UI revision, each with an*_REFoverride.docs:checkand the static preview understandroute.htmloutput (prerender.autoSubfolderIndex: false).
Known limitations
- Live SSR status. Doqs sets
RESPONSE_INIT.status = 404for a documentation URL it claims, but Analog 2.9's server handler never reads it, so an Analog SSR server (including the dev server) answers 200 for a missing page. Prerendered output on a static host answers 404. Doqs does not simulate a status or ship a server. - Screen readers and browsers on Windows are untested; Zone.js applications, Vite < 8 and Analog > 2.9 are unverified.
- A real localized site grows its static Pagefind index with its content; that is not a runtime cost (the index is fetched only when search opens).
@doqs/analog 0.11.0
Real-world adoption and 1.0 contract hardening. Additive: no exported type, function, configuration key, frontmatter key, route or --host-docs-* token was removed or changed. The release is driven by two real adoption proofs (Angular Movement and Volt UI, built from the packed package) and fixes the generic blockers they exposed.
Added
@doqs/analog/config: a configuration-only entry point (defineDoqConfig,provideDoq,doqPrerenderRoutes,DOQ_CONFIG, the configuration types). Its compiled file imports only@angular/core; the main entry re-exports every name it exported before. Importing the main entry in plain Node (avite.config.ts, a script) fails without the Angular compiler; the config entry loads. In a Vite 8 production build of a host that loads the documentation lazily both entries produced identical initial JavaScript (pnpm bundle:impact), so the benefit is tooling contexts and builders that do not tree-shake, not a smaller bundle.DoqConfig.landmark('document'default,'host'): who renders the page'smain. Documentation index, document and not-found views render exactly onemainby default and none with'host'; the decision is configuration, never DOM inspection, so server HTML and hydrated DOM agree.DoqShellComponentrenders a plain container instead ofmainwhen a Doqs configuration owns the landmark (it used to nest a secondmainaround the index view), and has amainLandmarkinput to override that whenprovideDoqis scoped below the shell.DoqConfig.unmatched('not-found'default,'continue') and the same option fordoqRoutes(): with'continue'Doqs claims only URLs it has a document for, so host-owned pages below the same prefix keep working and unknown URLs reach the host's 404. The current version's bare base path is then left to the host. This is what lets a site migrate pages one at a time without changing a URL.--host-docs-primary-text(optional token) and an internal derived default: text in the primary colour on tinted surfaces (active navigation item, links, pressed toggles) is a slightly darker mix of the primary colour and the foreground, which brings medium brand colours (found with Volt UI's#3467f5, 3.96:1 to 4.24:1 before) to at least 4.5:1.public-api.stability.jsonclassifies every export of the browser entries as stable, advanced, internal or deprecated; a unit test keeps it in step withpublic-api.report.json.- Repository:
pnpm verify:adoption:routes(Angular Movement at its original URLs),pnpm verify:adoption:volt(Volt UI),pnpm verify:portable(CRLF, junction, path smoke, also run on Windows in CI),pnpm bundle:impact, a Zone.js consumer (scripts/consumer.ts --zone),docs/adoption/consumer-parity.md,docs/adoption/migration-findings.mdand a guide, Adopting Doqs in an existing library site.
Fixed
- Generated pages with Windows line endings.
doq content checkreported a page checked out with CRLF as "edited after it was generated", anddoq-apileaked\rfrom CRLF sources into the generated pages. Both generators now compare and render independently of the checkout's line endings. - Not-found views no longer replace the
mainrole withrole="status". - The public API report now lists every export of the root entry although the declarations moved to the config entry (
scripts/public-api.tsfollows re-exports between sibling entries).
Deprecated
DoqButtonDemoComponent: an example component of the pilot, not a Doqs feature. Register your own withDoqConfig.demos. It keeps working and is removed only in a major release.
Known limitations
- Localization: one content tree, English chrome, one search index. Pages migrated to Doqs lose their locale-prefixed variants (the prefixed URL falls through to Analog's own Markdown route). See
docs/adoption/consumer-parity.md. - Overlays that components append to
<body>can render beneath the expanded playground's top-layer<dialog>; use the inline preview. Seedocs/adoption/migration-findings.md. - Zone.js is verified on Angular 21 only. Windows is verified for the Node tooling in CI, not for browsers. Screen readers were not tested.
@doqs/analog 0.10.0
Advanced content authoring: source-backed code, reusable Markdown and links to the generated API reference, resolved at build time into ordinary Markdown. Additive and opt-in: no exported type, function, configuration key, frontmatter key, route or --host-docs-* token was removed or changed, nothing is added to the browser entry, and every 0.9 (and earlier) project builds and renders as before without any new file or step.
Added
doq content generate | check | watch(and@doqs/analog/content:generateContent,checkContent,buildContent,loadContentConfig,formatDiagnostic,doqContent()Vite plugin,DoqContentError,EXIT_CODES, typesDoqContentTarget,DoqContentOptions,DoqContentDiagnosticand results). Node-only, dependency-free, never executes or fetches anything. Configured bydoq.content.json(one target per documentation version).::source{file="…" region="…"}: a highlighted code block read from a real file, as a whole, a named region (// #region doqs:name,# …,/* … */,<!-- … -->; nesting allowed, markers removed) or a line range, withlang,titleand an optional "View source" link built fromsourceUrl/revision(never guessed). Fences are longer than any backtick run in the code, so a snippet cannot end its own block or become a directive.::include{file="…"}: Markdown fragments (a file or directory whose name starts with_, so never a route), nested up to five levels, cycles detected, no frontmatter, heading levels kept as written,/pathfrom the authoring root and other paths from the including file.[[api:Name]],[[api:Name|Label]],[[api:Name@target]]: links to the generated API page of a public symbol using the symbol indexdoq-apinow records in its manifest. A target resolves against its own index, so archived guides link archived pages and a missing symbol is an error, never a fallback to the current version.doq-apisymbol index:.doq-api.jsongainssymbols(public export → route, with collisions and--base-pathapplied by the generator). Regenerate once withdoq-api generate.doq-apialso documents an entry that is itself a declaration file (a.d.ts/.d.mtsentry).- Ownership like
doq-api: a manifest (.doq-content.jsonin the authoring directory) with SHA-256 hashes; hand-written or edited files are conflicts and never overwritten,checkwrites nothing, output has no timestamps or absolute paths. Diagnostics name the page, line, directive, reference, reason and fix; exit codes 1 stale, 2 configuration, 3 conflict, 4 invalid authoring. - Safety: only text files below the configured
sourceRoots, checked on real paths (traversal and symbolic links), nevernode_modules,.git, build output,.env*, keys, credential-like names, binaries, non-UTF-8 or files above 256 KiB. - Repository: authored pages in Showcase A (embedded, with a Volt UI playground next to its source), Showcase B (docs-first, nested routes), both archives and the official documentation (Content authoring, Content tooling and a generated Content tooling API reference); the Angular Movement adoption proof; tarball consumers with and without authoring.
Changed
doq-api's manifest has a newsymbolsmember;doq-api checkreports a manifest written by 0.9 as stale untildoq-api generateis run.- Budgets for content-proportional metrics of the showcases and the official site are raised for the added pages, with the reason in
perf-budgets.json. Initial JavaScript and stylesheet budgets are unchanged.
Known limitations
- Directives are line-level: they are not recognised inside block quotes, lists or tables (they stay literal). Source and include errors inside a fragment point at the fragment, not at the including page.
- Links inside a fragment are not rewritten; use absolute routes. A new authored page needs a
doq content generate(the Vite plugin does it on start and on change). - Archived documentation needs its own source snapshot and API index; Doqs never fetches an old tag.
watchand the plugin watch the files read by the last successful run.
@doqs/analog 0.9.0
Interactive component playgrounds. Additive: no exported type, function, configuration key, frontmatter key, route or --host-docs-* token was removed or changed, ::demo[id] and every 0.8 (and earlier) configuration build and render as before, and pnpm verify:public-api passes against the 0.7.0 baseline.
Added
::playground[id]Markdown directive, recognised like::demo[id](its own paragraph; literal inside code, lists, quotes, tables and tab bodies).DoqConfig.playgrounds: a registry of{ component, title?, description?, controls?, outputs?, code?, previewSizes? }.defineDoqConfigreports every problem in one readable error (duplicate controls, bad ids, selectinitialoutside the options, invalid ranges, required controls without an initial value…).DoqPlaygroundComponent(rendered for you):boolean,string,number(min,max,step) andselectcontrols; inputs are bound with Angular's publiccreateComponent({ bindings })by their public (alias) name, so signal inputs, required inputs, transforms and legacy@Inputwork and a control change never recreates the component; selectedoutput()/EventEmitter/modelchange events are listed (latest 20, safely formatted); Reset (restores controls, clears events, recreates the component); preview widths (Responsive, Mobile 320px, Tablet 768px; customisable orfalse); an Expand view in a native modal<dialog>that keeps the same component instance; code tabs with exact copy and a polite status message.- Helpers
formatDoqUsage()(template usage with correct escaping),formatDoqEventPayload(),validateDoqPlaygrounds(),parseDoqDocument()and the constantsDOQ_INLINE_PLAYGROUND_PATTERN,DOQ_DEFAULT_PREVIEW_SIZES,DOQ_PLAYGROUND_EVENT_LIMIT;DoqDocsComponent.parts. - Two optional tokens,
--host-docs-playground-surfaceand--host-docs-playground-preview;forced-colorsandprefers-reduced-motionrules. - Repository: playground fixtures in Showcase A (real Volt UI button), Showcase B (two independent SDK playgrounds), the official documentation (real Angular Movement) and the Angular Movement adoption proof; the Interactive playgrounds guide.
Fixed
- The 0.8.0 release could not run. The Release eligibility job executed
scripts/verification/package.ts(which imports TypeScript) before installing dependencies and failed withERR_MODULE_NOT_FOUND; npm still served 0.7.0. The job now installs the workspace first (--ignore-scripts, SHA-pinned action), with a regression test.
Changed
parseDoqContent,DoqRichSegmentandDoqDocsComponent.segmentsare deliberately unchanged (they never contain playgrounds); the document view rendersparts(parseDoqDocument).- Stylesheet +6.3 KB source / +0.9 KB gzip; budgets in
perf-budgets.jsonraised for exactly that, with the reason recorded. JavaScript budgets are unchanged.
Known limitations
- Overlays that a component appends to
<body>(CDK overlays, popovers outside the top layer) render below the Expand dialog. - Controls are written by hand; they are not inferred from
doq-apimetadata (planned for later). Object-graph inputs need a wrapper component. - Code examples are text you provide; importing source files into Markdown is planned for 0.10.
- The playground is client-interactive only after hydration; a component that cannot render on the server must guard browser APIs like any SSR component.
@doqs/analog 0.7.0
Production hardening. Additive: no exported type, configuration key, frontmatter key, route or --host-docs-* token changed, and every 0.6 (and 0.5-style) configuration builds and renders as before.
Added
@doqs/analog/vite→doqDeterministicMarkdown()(Node-only, opt-in).@analogjs/platformrenders each Markdown file in theloadhook of itsanalogjs-content-fileplugin; Vite runs those hooks concurrently, all of them share onemarkedinstance, andmarked-gfm-heading-idkeeps its slugger in module state. With an asynchronous marked step (Shiki or any async highlighter) two files interleave and receive each other's duplicate-heading suffixes (usage-2whereusage-1belongs), and the wrong ids are baked into the bundle. The plugin calls Analog's own hook through the resolved plugin list, one file at a time, so the output equals a sequential build. Nothing is patched or copied; it throws at config time when Analog's plugin is missing. Add it next toanalog()invite.config.ts. See Deterministic builds.- Static integrity check
pnpm docs:check(repository tool, not shipped): for every prerendered page it compares heading ids with a strictly sequential render of that page, rejects duplicate ids, empty pages, a missing or repeatedh1, table-of-contents links to missing ids, broken same-site links and fragments (navigation, version switcher, Markdown, generated API pages), several or foreign canonical links, Markdown sources without a route and documentation pages without a source. External links are never fetched. - Measured budgets
pnpm perf:check(initial JavaScript, all JavaScript, stylesheet, search index, page count, core CSS;perf-budgets.json) andpnpm perf:scale(generated 20/200/1000-document fixtures). - Compatibility matrix
pnpm verify:compat --angular=21|22: the packed tarball in a docs-first consumer on Angular 21.2 and on Angular 22.2 with TypeScript 6 (strict peers, no Zone.js), withdoq-api check,doq-search,docs:checkand an Angular-integration smoke suite. - Cross-browser matrix
pnpm test:e2e:browsers: the journeys that depend on the engine run in Firefox and WebKit on the production builds (the complete suite stays in Chromium).
Fixed
- Back/Forward in WebKit. WebKit restores the destination's scroll position before
popstate, so Doqs recorded the wrong position for the entry being left and Forward to a fragment entry kept the previous scroll. The position the reader is leaving from is now tracked from scroll events and frozen during a traversal. - Forced colors (high contrast). The selected tab and the current navigation, table-of-contents and version links were distinguishable only by colour and weight; they now also use
Highlightand an underline whenforced-colors: active.
Changed
- Tests: the copy tests read the clipboard back only where the engine can grant
clipboard-read(Chromium); Firefox and WebKit assert the visible confirmation. Keyboard tests use the engine's "visit everything" chord where Safari's default skips links (WebKit on macOS). Engine-specific wording of a legitimate 404 is accepted, nothing else. - The Angular Movement adoption proof builds once with
doqDeterministicMarkdown()and validates withdocs:checkinstead of rebuilding until the ids happened to be canonical.
Compatibility and limits
- Angular
^21.2.2 || ^22.0.0(unchanged). Verified: Angular 21.2.x (every suite) and Angular 22.2.x with TypeScript 6.0 (smoke suite), both zoneless. Not verified: applications that load Zone.js, Analog above 2.9.x, Vite below 8 with the new plugin. - Browsers verified on production builds: Chromium (complete suite), Firefox and WebKit (focused matrix). Clipboard read-back is verified in Chromium only.
- The first-loaded JavaScript grows by about 46–52 B (gzip) per document of any version: Analog bundles the frontmatter and a loader of every Markdown file, and there is no supported Analog API to defer it. Measured: 20 documents 186.8 KB, 200 documents 200.8 KB, 1,000 documents (+500 archived) 254.9 KB; navigation between documents stays at 14–39 ms.
- Accessibility is checked with axe and keyboard journeys; this is not a WCAG certification (see the README).
@doqs/analog 0.5.0
Angular API reference generation. Additive and opt-in: nothing changes for a project that does not run doq-api; no configuration option, route, frontmatter key read by the runtime or CSS token was added or changed, and the Angular entry point imports neither Node nor TypeScript.
Added
doq-api generate/doq-api check(Node-only CLI) and@doqs/analog/api-reference(generateApiReference,checkApiReference,buildApiReference,DoqApiError, typed inapi-reference.d.mts). They read a library's public entry point with the project's own TypeScript (optional peer^5.5.0 || ^6.0.0, resolved from the project, never bundled) and write deterministic Doqs Markdown: an index plus one page per public symbol, as tables and fenced code, with frontmatter (title,description,group,order,generated,category).- Angular-aware extraction: components, directives, pipes and services (selector,
exportAs, pipe name,providedIn); signalinput()/input.required()with aliases, defaults, transforms and both the accepted and the read type;model()with its change output;output(); legacy@Input()/@Output()withEventEmitter; public methods and properties. Computed metadata is reported, never guessed. - TypeScript extraction: functions with overloads, arrow-function constants, interfaces, type aliases, enums, classes, constants; readable signatures (generics, optional/rest parameters, unions, readonly arrays) without absolute paths; links to other documented symbols; JSDoc (
@param,@returns,@example,@deprecated,@since,@see,@stability,@experimental,{@link}) with HTML and Doqs directives neutralised. - Safe ownership: output only inside a sub-directory of the content directory, a
.doq-api.jsonmanifest with file hashes, no overwrite of hand-written or hand-edited files, removal only of unchanged generated files, nothing written when a conflict exists. - Check mode: exits 1 and names added, modified and removed pages when the committed reference is stale; never writes. Exit code 2 marks usage and configuration errors.
--strictfails on warnings and undocumented symbols. - Options:
--entry,--project,--out,--content-dir,--base-path,--group,--title,--order-start,--source-url,--include,--exclude,--strict,--cwd. - Showcase A documents a standalone Angular component and directive (
apps/showcase-a/vanta-ui); Showcase B documents a non-Angular SDK (apps/showcase-b/forge-sdk); both commit their generated pages and check them inpnpm verify:change/ CI (pnpm api:check). The disposable Angular Movement proof generates and verifies the reference of its real public API.
Fixed
- A long unbroken title (a generated API page named
VantaAlertComponent) overflowed a 375 px viewport on Linux fonts; document and index titles now wrap anywhere (overflow-wrap). - Release workflow:
verify-publishedwaited two minutes for npm to list a fresh version, but the registry took about six minutes to list@doqs/analog@0.4.0(published 09:51 UTC, visible 09:57 UTC on 2026-10-22), so the GitHub Releasev0.4.0was not created. The window is now ten minutes or more (PUBLISH_VISIBILITY, regression testUNIT-100). The missingv0.4.0release is not created retroactively; seedocs/operations/release-and-deployment.md.
Compatibility and limits
- Node
^20.19.0 || ^22.12.0 || >=24.0.0; tested with TypeScript 5.9 (this repository) and 6.0 (Angular Movement). No Angular peer range was widened. - Links inside Markdown are ordinary anchors (Analog does not intercept them), so following a reference link is a normal navigation to a prerendered page.
- Not included: a TypeDoc replacement, API versioning, template analysis, runtime reflection, a browser-side analyser.
@doqs/analog 0.2.0
See packages/doq/CHANGELOG.md