fix(generator)+feat(code): page anchor once per file; Code infers lexer from filename
Merged
MH
2mo ago+139+139+012345678901234567890123456789-17-17-01234567890123456789
Closes #77
Summary
docs_kit:pageinjected the registry line once per group.#registry_anchorreturned a Regexp (pageline not followed by apageline), and Thor'sinject_into_filereplaces every match of a Regexpafter:— so a grouped registry got one copy per group. The anchor is now the file's lastpageline as a String: one match, end of the last group.DocsUI::Codeinfers the lexer fromfilename:.lexer:now defaults tonil; resolution is explicitlexer:→ guess from the filename via Rouge's globs → ruby.config/deploy.yml→ yaml,Dockerfile→ docker,*.sh→ shell. Unguessable filename / no filename → ruby as before.- Docs: README authoring convention, the Authoring + Components pages, the generated
AGENTS.mdtemplate, and CHANGELOG.
Test plan
spec/generators/page_generator_spec.rb— grouped fixture (two groups, blank line + comment): exactly one line added after the lastpageline of the file; second run idempotent.spec/docs_ui/code_spec.rb—.yml→data-md-lang="yaml"with noerrspans;Dockerfile→ docker; explicitlexer:wins over the filename; unguessable filename → ruby; no args → ruby.-
bundle exec rspec— 953 examples, 0 failures (94.7% line coverage) -
bundle exec rubocop— no offenses - Manual (post-merge, dash
docs/with a path gem):bin/rails g docs_kit:page "Scratch" --group=Deployingtwice → one line at the end of the last group
Deviations & judgment calls
Rouge::Lexer.guessesinstead ofRouge::Lexer.guess. The issue namedguess(filename:)with anAmbiguousrescue, butguessanswersPlainTexton a no-match (e.g.filename: "notes"), which is indistinguishable from a real guess and would have turned unguessable filenames into plaintext instead of the required ruby fallback.guessesreturns an array — exactly one hit is a guess, zero or several is nil — and needs no rescue.- No
code_filename_lexersconfig knob. The issue floated it as a possible follow-up for extension-less files (.dash/secrets); those still work with an explicitlexer:, so I didn't add config surface nobody has asked for yet. - No
--syncmigration. TheAGENTS.mdtemplate change is a content edit an existing site picks up via the normal install/sync path; nothing new to install.
https://claude.ai/code/session_01KsqvKPn1c1hWu6NSEQHy1W
Summary by cubic
Fixes the docs_kit:page generator adding a registry entry once per group instead of once per file, and makes DocsUI::Code infer the lexer from filename: when no lexer: is given.
Bug Fixes
docs_kit:pagenow anchors on the file's lastpageline as a string, so grouped registries get exactly one new entry per run.- A second run is idempotent — no duplicate entries are added.
New Features
DocsUI::Coderesolves the lexer as explicitlexer:→ filename guess via Rouge → ruby; unguessable filenames and no filename stay ruby.- Explicit
lexer:always overrides the filename guess. - Docs, README, and the generated
AGENTS.mdtemplate now describe the new behavior; no migration step is needed—existing sites pick up the template change via the normal install/sync path.
Closes #77.