refactor: deepen four modules surfaced by the architecture review#100
Merged
Conversation
Acting on the candidates from /improve-codebase-architecture. Four refactors, each independently motivated but cohesive as a batch. == 1. Collapse the easter-egg scattering (the big one) == FingerprintPlayground.vue was 724 lines with each egg smeared across 6 locations: type union, EGGS array, EGG_DURATIONS, eggBackground switch, v-else-if template branch, and CSS block. Adding an egg meant editing all 6. Each egg is now a self-contained Vue SFC under src/components/vue/fingerprint/eggs/. The playground imports a single EGG_REGISTRY and renders the active egg via <component :is>. Adding an egg is now: create one .vue file + append one entry to registry.ts. src/components/vue/FingerprintPlayground.vue 724 → 247 lines src/components/vue/fingerprint/types.ts new (EggDef, EggProps) src/components/vue/fingerprint/registry.ts new (15 entries) src/components/vue/fingerprint/eggs/*.vue new (15 files) Each egg owns its template, script (including any reactive state — matrix tick, OTP XOR, Enigma rotors), style, and prefers-reduced-motion rule. The engine stays tiny: hash, watch input, dispatch events, render the active egg component. == 2. Surface the implicit rnp:* event bus == Five custom events were referenced as string literals at ~12 sites across SiteHeader, SiteSearch, FingerprintPlayground, EasterEggs, and HeroDecrypt. No central registry; rename was unsafe. src/lib/events.ts now exports RNP_EVENTS (and RNP_STORAGE for the session key) as `as const` maps plus a dispatch() helper. All senders and listeners import the same symbol; rename = one edit; typo = compile error. == 3. Deepen the vendor-source concept == RNP_VERSION was a hand-synced constant in content.config.ts that the comment warned to "bump together with docs_ref". The man-page paths were duplicated between fetch-sources.mjs (EXTRA_PATHS) and content.config.ts (include regex). src/lib/vendor-source.mjs now owns: - RNP_RELEASE_TAG (read from docs_ref in software/rnp.md) - RNP_VERSION (derived from the tag, stripping the leading 'v') - RNP_MAN_PAGES + RNP_EXTRA_SPARSE (shared sparse-checkout paths) content.config.ts and fetch-sources.mjs both import. The hand-sync is gone — bump docs_ref and RNP_VERSION follows. src/lib/frontmatter.mjs extracts the YAML-front-matter parser shared between asciidoc.ts (TS) and fetch-sources.mjs (Node). Kept in .mjs so the standalone script can import it without a TS compiler. == 4. Delete the duplicated helpers == decodeEntities was inlined verbatim inside renderAdoc (asciidoc.ts); docSort was duplicated verbatim in two software route files. Both pass the deletion test as pass-throughs. - renderAdoc now calls the existing decodeEntities function - docSort moves to src/lib/docs.ts; both routes import == Skipped: front-matter parsing seam == The original review claimed fetch-sources.mjs and asciidoc.ts both parse YAML front matter. Verifying on disk: fetch-sources.mjs doesn't parse front matter itself — it sparse-clones repos and reads each product's front matter via the shared parser now in frontmatter.mjs (already done above as part of #3). The "seam" never existed as described; nothing to do here. == Verification == - `npm run build` clean (no errors, no warnings) - HTTP 200 on /, /blog/, /software/rnp/, /advisories/ - node -e import vendor-source.mjs → RNP_VERSION '0.18.1' - dev server HMR picked up all new files; egg files all 200 EOF
5 tasks
ronaldtse
added a commit
that referenced
this pull request
Jul 23, 2026
…text) Regression introduced in PR #100 (the architecture refactor). When I extracted the YAML-front-matter parser to src/lib/frontmatter.mjs, I kept its interface as `parseFrontmatter(rawText)` — but in fetch-sources.mjs I called it as `parseFrontmatter(filePath)`. The regex matched nothing, every product's `docs_repo` came back undefined, every product hit the `continue`, and `vendor/` stayed empty. CI then built with no vendor checkout, so the `softwareDocs` and `manpages` collections were empty, ~970 internal doc/manpage links went missing, and lychee reported 8 broken internal links (the README and installation hrefs that had nothing to point at). The live site deployed from this broken build. Fix: readFileSync(join(softwareDir, file), 'utf8') before calling parseFrontmatter, matching what asciidoc.ts already does through its adocLoader. Verified locally: - parseFrontmatter(readFileSync('src/content/software/rnp.md', 'utf8')) returns docs_repo + docs_ref correctly - rm -rf vendor && npm run fetch-sources clones all 3 products - npm run build: no empty-collection warnings - npm run check:links: "OK — all internal href/src targets exist"
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.
Summary
Acting on the candidates from
/improve-codebase-architecture. Four refactors, each independently motivated but cohesive as a batch.1. Collapse the easter-egg scattering (the big one)
FingerprintPlayground.vuewas 724 lines with each egg smeared across 6 locations (type union + EGGS array + EGG_DURATIONS + eggBackground switch + v-else-if template branch + CSS block). Adding an egg meant editing all 6.Each egg is now a self-contained Vue SFC under
src/components/vue/fingerprint/eggs/. The playground imports a singleEGG_REGISTRYand renders the active egg via<component :is>.Each egg owns its template, script (including any reactive state — matrix tick, OTP XOR, Enigma rotors), style, and
prefers-reduced-motionrule. The engine stays tiny: hash, watch input, dispatch events, render the active egg component.2. Surface the implicit
rnp:*event busFive custom events were referenced as string literals at ~12 sites across
SiteHeader,SiteSearch,FingerprintPlayground,EasterEggs, andHeroDecrypt. No central registry; rename was unsafe.src/lib/events.tsnow exportsRNP_EVENTS(andRNP_STORAGEfor the session key) asas constmaps plus adispatch()helper. All senders and listeners import the same symbol — rename = one edit; typo = compile error.3. Deepen the vendor-source concept
RNP_VERSIONwas a hand-synced constant incontent.config.tsthat the comment warned to "bump together with docs_ref". The man-page paths were duplicated betweenfetch-sources.mjs(EXTRA_PATHS) andcontent.config.ts(includeregex).src/lib/vendor-source.mjsnow owns:RNP_RELEASE_TAG(read fromdocs_refinsoftware/rnp.md)RNP_VERSION(derived from the tag, stripping the leadingv)RNP_MAN_PAGES+RNP_EXTRA_SPARSE(shared sparse-checkout paths)content.config.tsandfetch-sources.mjsboth import. The hand-sync is gone — bumpdocs_refandRNP_VERSIONfollows.src/lib/frontmatter.mjsextracts the YAML-front-matter parser shared betweenasciidoc.ts(TS) andfetch-sources.mjs(Node). Kept in.mjsso the standalone script can import it without a TS compiler.4. Delete the duplicated helpers
decodeEntitieswas inlined verbatim insiderenderAdoc(asciidoc.ts);docSortwas duplicated verbatim in two software route files. Both pass the deletion test as pass-throughs.renderAdocnow calls the existingdecodeEntitiesfunctiondocSortmoves tosrc/lib/docs.ts; both routes importSkipped: front-matter parsing seam
The original review claimed
fetch-sources.mjsandasciidoc.tsboth parse YAML front matter. Verifying on disk:fetch-sources.mjsdoesn't parse front matter itself — it sparse-clones repos and reads each product's front matter via the shared parser now infrontmatter.mjs(already done above as part of #3). The "seam" never existed as described; nothing to do here.Test plan
npm run buildclean (no errors, no warnings)/,/blog/,/software/rnp/,/advisories/node -e "import('./src/lib/vendor-source.mjs')..."→RNP_VERSION: 0.18.1defineProps<{ input: string; hex: string }>signaturernp:event literals replaced —grep "rnp:" src/returns empty (excludingevents.tsand comments)matrix,dh,otp,enigma,phil) on a real screenhal/daveinput