- Contributing to JavaScript/TypeScript/Node Packages
- First-Time Setup
- Overall Repo Structure Model
- Build Pipeline
- Package Naming Policy
- Development and Release Engineering Workflows
- Packaging and Release Workflow Details
- Versioning Tiers
- Handling
changeset statusErrors - Development Flow
- How the Automated Release Pipeline Works
- Verifying a Release
- Rules
- Publishing as NPM Packages
- Sideways Version Bump Policy
- Design Principles
This guide is targeted to project contributors and covers first-time setup, day-to-day development, and release engineering
for the packages in the javascript/ workspace.
For the top-level contributor entry point see: CONTRIBUTING.md
mkdir -p ~/workspace && cd ~/workspace
git clone git@github.com:doikayt/build-tools.git
cd build-tools/javascript
npm ci
npx nx run-many -t build,test --skip-nx-cacheThis repo has three layers:
- The repository root, which contains CI configuration and
resides one level up from the
javascriptfolder. - The secondary (platform) level where the
javascript/folder lives. Each folder at this level is specific to some given platform (e.g.: JVM, Javascript, Python, etc.) and contains appropriate release packaging and publishing configuration for that platform. - The lowest level consists of individually consumable packages for plugins and tools.
Repo Root ← CI configuration
│
├── javascript/ ← npm workspace + Changesets control plane
│ ├── update-markdown-toc/
│ ├── nx-graph-to-mermaid/
│ └── autogen-markdown-doc/
│
├── jvm/ ← possible future JVM workspace
│
└── python/ ← possible future Python workspace
This workspace uses NX (See: https://nx.dev/) to orchestrate builds and tests across packages.
NX owns the full execution graph — do not use npm run build or npm test at the workspace
root to drive builds. Use NX directly:
npx nx run-many -t build,test --skip-nx-cacheDependency ordering is declared in each package's project.json via dependsOn.
- Intellij
- Install the Nx Console plugin to obtain a graphical overview of this mono-repo as well as a hierarchical navivation tree that lets you select and execute build targets in IDEA.
- Other IDEs
- This is an excercise for the reader (but please contribut a documentation PR if you find something good!)
Every publishable package under javascript/ must use the @doikayt/ scope as its name —
consistently in both package.json (name) and project.json (name). For example:
@doikayt/update-markdown-toc.
Exception: the top-level orchestrating workspace (javascript/ itself) is unscoped:
package.jsonname:build-toolsproject.jsonname:build-tools-workspace
Rationale:
- The
@doikayt/scope identifies packages that are actually published to npm. The workspace root is never published — it only orchestrates builds, tests, and releases for the packages beneath it — so giving it a scoped name would misleadingly imply it's a consumable artifact. - Keeping
package.jsonandproject.jsonnames identical for each package avoids ambiguity in NX target references (e.g.dependsOnentries,prepackscripts). A mismatch between the two means some commands must reference the package by its unscoped NX project name while others must use the scoped npm name — an easy source of brokendependsOngraphs and copy-paste errors when authoring new targets.
Work from inside the individual package folder:
cd javascript/nx-graph-to-mermaid # or whichever package you're working onTypical workflow:
# 1. Edit source files, then build and test — only changed projects rebuild
npx nx run-many -t build,test
# Force a full rebuild of everything (e.g. after a branch switch):
npx nx run-many -t build,test --skip-nx-cache
# 2. Regenerate docs and reformat code before committing
cd javascript # must run from workspace root
npx nx run build-tools-workspace:update-all-format
# 3. Stage and commit
git add .
git commit -m "fix(my-package): what changed and why"
# 4. Verify everything passes before pushing (catches lint, types, format drift)
npx nx run build-tools-workspace:check-all
# 5. Pull any CI-generated version bump commits before pushing
git pull --rebase
git pushWhy
git pull --rebasebefore push? The release pipeline commits version bumps back tomain(chore: release [skip ci]). If a release ran since your last pull, your local branch is behind and git will reject the push.--rebasekeeps history linear and avoids noisy merge commits.
update-all-formatvscheck-all:update-all-formatauto-fixes docs and formatting — run it before committing.check-allvalidates everything including lint (which cannot be auto-fixed) — run it before pushing. Lint errors must be fixed manually.
Cross-package testing lives inside:
javascript/autogen-markdown-doc
The wrapper package is the integration boundary. It imports and composes the base plugins, and adds a little bit of its own functionality.
Cross-package tests belong there — not at workspace root.
Release mechanics must run from:
cd javascript
Because that is where we have:
package.json(with"workspaces").changeset/- release configuration
Release commands:
npx changesetnpx changeset versionnpx changeset publish
git status
There should be no uncommitted changes.
cd javascript
npx nx run-many -t build,test --skip-nx-cacheSTOP if any test fails.
npx changeset
You will be prompted to:
- Select affected packages (use up/down arrow to choose and spacebar to (un)select)
- Choose semver bump (patch / minor / major)
- Provide release summary
Commit:
git add .changeset
git commit -m "chore: add changeset" .
Commit your changes and push:
git add .
git commit -m "fix(my-package): description of what changed"
git push origin mainCI will automatically:
- Inspect the git log since the last release tag and derive the semver bump from your commit prefix (see Versioning tiers below)
- Run
npx changeset version(bumps all package versions, updates changelogs) - Commit the version bumps back to main with
[skip ci] - Run
npx changeset publishto publish all packages to npm
You can follow progress in GitHub Actions.
After the workflow completes, confirm:
- GitHub Actions run succeeded
- Packages appear on npm
- Versions match expected coordinated bump
All packages in this workspace version together in lockstep (see
Sideways Version Bump Policy); the bump level is derived from
conventional commit prefixes by scripts/auto-changeset.sh. The tier definitions and the
commit-prefix → bump mapping are canonical policy — see Versioning Tiers.
Run npx changeset from javascript/ before pushing — the auto-generation script defers to a
handwritten changeset. Details: Forcing a Specific Bump Level.
Run npx changeset add --empty from javascript/ and commit the empty changeset.
Details: Suppressing a Release.
The error, what it means, and both resolution paths (real vs empty changeset) are canonical
policy — see Handling changeset status Errors. In build-tools, run all
changeset commands from javascript/ (the Changesets control plane).
cd javascript/nx-graph-to-mermaid
edit files
npx nx run-many -t build,test
cd javascript && npx nx run build-tools-workspace:update-all-format
git add . && git commit -m "fix(scope): ..."
npx nx run build-tools-workspace:check-all
git pull --rebase && git push # why pull? The CI job commits new changeset when it publishes
RELEASE FLOW
cd javascript
DEVELOPER CI (https://github.com/doikayt/build-tools/actions)
npx changeset
git commit .
git push ───────────────────► build job passes
changeset version (bumps versions, commits [skip ci])
changeset publish (publishes to npm)
The pipeline (auto-changeset → changeset version + [skip ci] commit-back →
changeset publish + tag) is canonical policy — see
How the Automated Release Pipeline Works. One build-tools addition: after
publish, a smoke test installs @doikayt/autogen-markdown-doc at the just-published
version from the npm registry and runs it end-to-end against the math-cli-nx fixture.
Where release evidence appears (Actions log, git log/git tag, changelogs, npm registry)
is canonical policy — see Verifying a Release. For build-tools, check
npm view @doikayt/autogen-markdown-doc versions and each package's CHANGELOG.md.
Maintainer rules (never hand-edit versions, all releases from committed changesets, no
npm publish from package directories) are canonical — see Rules.
Build-tools-specific: the workspace root (javascript/) orchestrates only — it contains
no product logic.
The packages in this workspace are versioned and published all together, as a single unit, to the public npm registry.
We enforce a semantic versioning policy via Changesets rather than relying on manual update and synchronization of version numbers and changelog entries across packages.
The five publishable packages are pinned to a single version via the fixed group in our
Changesets configuration: any bump moves every package to the
same version, even without source changes or dependency relationships between them. For the
rationale, see Coordinated (Sideways) Version Bumps.
For the reasoning behind structural and architectural decisions that shaped the implementation of all current plug-ins (and which should be followed going forward), refer to this document
