Skip to content

Refresh Project#527

Open
kadamwhite wants to merge 18 commits into
masterfrom
main
Open

Refresh Project#527
kadamwhite wants to merge 18 commits into
masterfrom
main

Conversation

@kadamwhite

Copy link
Copy Markdown
Collaborator

No description provided.

kadamwhite and others added 18 commits July 13, 2026 12:37
Companion to modernization-plan.md (the vision): a concrete, sequenced
execution plan broken into independently-mergeable phases, each with its
own regression net. Records the decisions made during planning.

Locked decisions:
- Bundler: tsdown (Rolldown), replacing webpack + Grunt + Babel
- Native fetch as the default transport; Node 18+; drop IE11
- Remove superagent entirely (no legacy adapter)
- Batteries-included main export (restores v1.x ergonomics)
- Build-time pre-parsed route tree to cut startup parsing

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The integration suite asserts against the classic "Theme Unit Test" dataset,
previously supplied by a separate Chassis VM (kadamwhite/wpapi.local). Replace
that with a reproducible wp-env seed:

- Commit the WXR as a fixture (tests/fixtures/theme-unit-test-data.xml).
- Add `npm run env:seed`: empties the site (drops the default "Hello world!"
  post and "Sample Page" for determinism), then imports the WXR.
- Install the WP-API/Basic-Auth plugin via .wp-env.json so authenticated tests
  work -- modern WP core rejects plain username/password over REST.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Two coupled changes across the integration suite:

- Endpoint is no longer hardcoded to http://wpapi.local/wp-json. It comes from
  tests/helpers/constants.js, which reads WPAPI_HOST (default the wp-env address
  http://localhost:2747) and derives the /wp-json endpoint. Pagination and
  upload-URL assertions build off the same constants.

- Expected data values updated to match modern WordPress. The WXR "Scheduled"
  post was future-dated when these tests were written; today it is published,
  which grows the post set 38 -> 39 and shifts pagination and date-filter
  results. Modern WP also exposes more settings keys and defaults to an empty
  tagline. Only expected values changed; every assertion still verifies the same
  behavior (pagination, filtering, ordering, CRUD round-trips).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
WPAPI.discover() read the API root's _links.self as a bare string, but current
WordPress returns an array of link objects ([ { href } ]). Accept either shape.

discover() still cannot bootstrap fully against modern WP: it builds a route
tree from the live route list, which now includes routes whose named groups
contain nested patterns (e.g. wp/v2/templates/(?P<id>...)), and the route-tree
regex parser throws "Unterminated group". That parser work is scoped to phase 5,
so the discover suite is skipped with a TODO. Its beforeAll .catch()es the
rejection so the skipped-but-still-executed hook can't leak into other suites.

Default-mode instances are unaffected -- they use the bundled default-routes.json.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- handoff.md: living status doc; records the Phase 0 baseline, the deferred
  discover/route-parser gap, and the dev workflow.
- modernization-plan.md: backlog note to add a secondary block/FSE-oriented seed
  in phase 5 (the classic WXR predates the block editor), kept separate from the
  classic dataset that guards the wp/v2 regression net.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Establishes a reproducible local integration environment (wp-env + seeded Theme
Unit Test data + Basic-Auth) and gets the full suite green on modern WordPress:
805 passed, 16 skipped (discover, deferred to phase 5), 0 failed.

No request/library logic changed except an isolated discover() self-link
compatibility fix.
Call out moving all automation to GitHub Actions as a first-class concern: ci.yml
(phase 1), docs.yml deploy (phase 6), and release.yml publish. Replaces Travis
and the hand-run docs/release scripts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Swaps the browser/Node build entirely for tsdown (Rolldown-based): dual
ESM+CJS for the `index`/`fetch`/`superagent` entries plus a browser UMD
bundle per transport, with generated .d.ts and package.json `exports` map.

Each Node entry gets its own independent tsdown config rather than one
shared multi-entry config, because `fetch`/`superagent` both `require`
`wpapi.js`: sharing a chunk across entries breaks rolldown's CJS
`module.exports` codegen (it emits multiple sequential `module.exports =`
assignments into one file, so only the last one takes effect). Bundling
each entry's full dependency closure independently avoids that.

The browser UMD builds alias `node-fetch`/`form-data`/`fs` to thin stubs
in build/browser-shims/ that resolve to the native browser globals,
mirroring the old webpack `externals`/`node.fs` config; tsdown's default
auto-externalization of package.json dependencies is overridden for the
browser build so those aliases (and plain bundling of qs/li/superagent)
actually take effect.

.d.ts generation needs tsconfig.json's `module: "commonjs"` (the source
is plain CJS) and TypeScript's classic `tsc` generator. Two JSDoc
`@returns {WPRequest}` annotations in wpapi.js are widened to `{Object}`:
rolldown-plugin-dts can't bundle the cross-file CJS-shaped declaration
that annotation forces, and richer per-route typing is Phase 3's job
anyway.

Deletes webpack.config*.js, Gruntfile.js, and build/grunt/ (docs-only
Grunt tasks; Phase 6 replaces the whole docs pipeline).
vitest.config.js sets `globals: true` (Jest-compatible describe/it/expect
globals) and a setup file aliasing the `jest` global to `vi`, so the
~30 existing jest.fn()/jest.spyOn() call sites across the suite port
without any changes.

tests/unit/wpapi.js required the package root (`require('../../')`),
which resolves through package.json's `main` field. That field now
points at the tsdown-built dist/index.cjs instead of source wpapi.js,
so the WPRequest class that test imports directly no longer matched
the one used inside the WPAPI instance it was constructing, breaking
an `instanceof` assertion. Fixed by requiring `../../wpapi` directly,
which also decouples this suite from wherever `main` happens to point
(relevant again once Phase 2 rebinds `main` to the fetch-bound export).
eslint.config.js carries forward the exact same custom rules as the old
.eslintrc.js (and its per-directory overrides for tests/, build/, and
lib/data/), including the project's space-inside-parens/brackets/braces
convention.

Prettier is added (.prettierrc.json: tabs, single quotes) but deliberately
NOT run across the existing codebase or wired into `lint`/CI: Prettier
has no option to reproduce that bracket-spacing convention, and running
it would fight the ESLint rules that enforce it on every file it
touches. It's available via `npm run format`/`format:check` for new
code or a future full-codebase decision.

Deletes .eslintrc.js, .eslintignore, and the per-directory .eslintrc.js
overrides, all superseded by the flat config.
Mechanical comma-dangle fixes across files not previously covered by
the old eslint script's target list (it never linted fetch/ or
superagent/ directly), applied via `eslint --fix`.

ESLint 9's eslint:recommended also added two rules the old ESLint 4
didn't have, surfacing two pre-existing, harmless-but-worth-fixing
issues: no-prototype-builtins (two `.hasOwnProperty()` calls, now
`Object.prototype.hasOwnProperty.call(...)`) and no-unused-vars (one
unused `catch (e)` binding, now an optional catch binding).
package.json: engines.node >=18, drop browserslist/IE11 support, drop
the Jest config block (superseded by vitest.config.js). Scripts:
jest -> vitest across the board; eslint invocation updated for the
flat config; a `typecheck` script is added (`tsc --noEmit`; not yet
meaningful since checkJs is off until Phase 3); `docs` no longer
depends on the now-deleted Grunt (runs jsdoc directly); the `zip`
script (grunt-zip against the old browser/ output) is dropped.
Removes the corresponding webpack/Grunt/Babel/ESLint4/Jest
devDependencies.

package-lock.json is now committed. The old "consuming applications
maintain their own lockfile" rationale doesn't hold once this repo has
its own CI: actions/setup-node's `cache: npm` and `npm ci` both need
one checked in for reproducible builds.

Deletes .travis.yml, replaced by GitHub Actions.
ci.yml has three jobs, not a flat 18/20/latest matrix: the toolchain
itself doesn't support that range (tsdown/rolldown need Node >=22.18,
vitest needs >=20). `test` (Node 22/24/latest) runs lint, typecheck,
build, and unit tests, and uploads dist/ as an artifact from the
`latest` leg. `dist-smoke` (Node 18/20) downloads that artifact and
just requires the pre-built CJS/ESM entries, checking the published
`engines.node: >=18` promise against the actual output without needing
the build tooling to run on old Node. `integration` (Node 22) boots
@wordpress/env and runs test:integration; note `wp-env logs` defaults
to `--watch: true` and never exits, so it's invoked directly with
`--no-watch` rather than through the `env:logs` dev-convenience script.

release.yml is scaffolded per the plan (build, test, `npm publish
--provenance` on a GitHub Release) but inert until an NPM_TOKEN secret
is added and publishing resumes.
Replaces webpack + Grunt + Babel with tsdown (dual ESM+CJS+UMD+.d.ts,
generated exports map), Jest with Vitest, ESLint 4 with ESLint 9 flat
config + Prettier scaffold, sets Node 18+ / drops IE11, and stands up
GitHub Actions CI (ci.yml) with a release.yml scaffold, replacing
.travis.yml.

No library behavior changed. Full suite green against wp-env:
805 passed, 16 skipped, 0 failed — identical to the Phase 0 baseline.
See handoff.md for the tricky decisions and workarounds this phase
required.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant