test: guard the published tarball, and index examples/ from the README - #24
Merged
Conversation
Both consumer-facing guards read the working tree, so neither consults
package.json "files": examples/ installs with `file:..`, which symlinks the
repo root rather than packing it, and type-tests/ resolves the package by
self-reference. A lib/ module left out of "files" resolves in both, passes
CI, and breaks only for a real consumer after publish.
package-exports.test.js does not close the gap either — `require('.')` from
inside lib/ lands on lib/index.js directly and never consults the root
"exports" map or any subpath.
This packs the tarball, extracts it, and requires all ten published subpaths
by name from a directory where the extracted copy is the installed
dependency, so resolution runs through "exports" as a consumer's would. The
package's own dependencies are symlinked from node_modules rather than
installed, keeping the test offline and under two seconds; the trade-off is
that an undeclared dependency would still resolve, so a separate assertion
reads the packed source for that.
Verified to fail on three mutations: types/ dropped from "files", an exports
subpath pointed at a missing file, and an undeclared require added to
runtime code.
Refs #23
examples/ holds 21 scripts, ~1,180 lines, all tracked in git, and the README never mentioned them once — `grep -n "examples/" README.md` returned nothing, so no reader was ever pointed at them and their documentation value was zero. Adds a "Runnable examples" section under Library API that links every script to what it demonstrates, grouped by command family. It also writes down the two conventions that make the directory navigable rather than a matrix of 21 similar filenames: `-audit` prints and writes nothing, `-save` writes JSON under results/. Prerequisites are stated per family — Chrome for lab, an API key for psi/crux/crux-history. Verified by running examples/crux-audit.js and examples/crux-save.js against the live API, and by checking every link resolves and every one of the 21 scripts appears exactly once.
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.
Closes #23.
type-tests/guards the published.d.tsat compile time;examples/is the only thing thatexercises the package at runtime. They are complementary — one never executes, the other never
type-checks — so this keeps both and fixes what was actually wrong with each.
lib/package-tarball.test.js— the tarball is now checkedBoth existing consumer guards read the working tree, so neither consults
package.json"files":examples/installs withfile:.., which symlinks the repo root rather than packing it(
examples/node_modules/@hugoer/web-perf-cli -> ../../..).type-tests/resolves the package through self-reference. That honours the "exports" map,but against the working tree, not a tarball.
lib/package-exports.test.jsdoes not cover it either:require('.')from insidelib/lands onlib/index.jsdirectly and never consults the root "exports" map or any subpath.So a
lib/module left out of "files" resolved everywhere, passed CI, and would have broken onlyfor a real consumer after
npm publish. The new test packs the tarball, extracts it, and requiresall ten published subpaths by name from a directory where the extracted copy is the installed
dependency, so resolution runs through "exports" as a consumer's would. It also asserts every
"exports"/"main"/"types"/"bin" target ships, and that every dependency the packed runtime code
requires is declared.
Dependencies are symlinked from
node_modulesrather than installed, which keeps it offline andat ~2s rather than a full network install. The trade-off is that an undeclared dependency would
still resolve at load time, which is why the declaration check reads the packed source separately.
It was verified to fail, not just to pass — three mutations, each caught:
types/dropped from"files"./variancepointed at a missing file…/varianceloadsrequire('left-pad')added tolib/logger.jsREADME —
examples/is reachable at last21 scripts, ~1,180 lines, all tracked in git, and
grep -n "examples/" README.mdreturnednothing. A new "Runnable examples" section under Library API links each script to what it
demonstrates, grouped by command family, and records the two conventions that make the directory
navigable:
-auditprints and writes nothing,-savewrites JSON underresults/.Behaviour changes
None. No
lib/source file is touched, no export, signature or return shape moves, and thegenerated
types/are unchanged (git diff --exit-code -- types/is clean after a regen). Thechange is one new test file, one new README section, and a paragraph in CLAUDE.md recording why
the tarball guard exists so it does not get deleted as redundant.
Verification
npm run lintclean;npm test578 passed across 16 files (13 new)npm run generate-typesproduces no drift;npm run check-typescompilesexamples/crux-audit.jsandexamples/crux-save.jsrun against the live CrUX API