Skip to content

Latest commit

 

History

History
112 lines (77 loc) · 9.32 KB

CONTRIBUTING.md

File metadata and controls

112 lines (77 loc) · 9.32 KB

Contributing

English | 日本語

Thanks for your interest in improving Kiritan! This guide gets you set up and explains how the project is put together. If anything here is unclear, opening an issue to ask is welcome.

Getting set up

You'll need Node.js >= 22.7. Then install the dependencies:

npm install

Commit the lockfile generated by your package manager (npm).

Project layout

This is an npm workspaces monorepo (see docs/DESIGN.md chapter 2.1):

Package Path What it is
kiritan packages/kiritan The CLI + build pipeline (config, stores, renderers, translate middlewares)
@kiritan/runtime packages/runtime The minimal t(key, params) runtime, with no build-time dependencies
@kiritan/deepl packages/deepl A DeepL translate middleware for translate.middlewares
@kiritan/google-translate packages/google-translate A Google Cloud Translation middleware for translate.middlewares
@kiritan/middleware packages/middleware A layer that turns any translate function into a translate middleware
@kiritan/free-translate packages/free-translate Translate middlewares that need no API key, including self-hosted ones (LibreTranslate, Google Apps Script)
otoneko1102.kiritan extensions/vscode VS Code extension (syntax highlighting for :::kiritan{...} blocks). Not an npm workspace member — see "Releasing" below.
— extensions/vim Vim/Neovim plugin (the same directive highlighting, plus *.kiritanconfig filetype detection). Not published anywhere — installed directly from this repo via a plugin manager's rtp option.

The design and rationale for everything above live in docs/DESIGN.md — read it before making a structural change.

Generated docs

The root README/CONTRIBUTING/DESIGN docs, and each package's README, are generated by Kiritan itself from a base/*.base.md source (e.g. base/README.base.md, packages/kiritan/base/README.base.md) — see docs/DESIGN.md chapter 4.2 for the :::kiritan{locale=...} block syntax used inside them. When you edit a base/*.base.md file, regenerate the outputs and commit them along with your change:

npm run docs:build

npm run docs:check reports any source that's missing a translation or has gone stale (i.e. the source changed after the last generation) without writing anything — useful to run before committing. Generation also happens automatically as part of the release workflow (below), so a base/*.base.md change that ships alongside a version bump doesn't strictly need a manual regeneration first — but running it yourself keeps your PR's diff accurate and reviewable.

Scripts

Command What it does
npm run build Bundle ESM/CJS + type declarations with tsdown
npm run test Run the tests once with vitest (npm run test:watch to keep them running)
npm run test:coverage Run the tests with a coverage report
npm run typecheck Type-check with tsc --noEmit
npm run format Format the code, writing the fixes (Prettier)
npm run format:check Check formatting without writing (Prettier)
npm run lint Lint the code without writing fixes (ESLint)
npm run lint:fix Lint the code, writing the fixes (ESLint)
npm run check Format and lint, writing the fixes (Prettier + ESLint)
npm run ci The same checks without writing — what CI runs
npm run docs:build Regenerate every base/*.base.md-derived doc (see Generated docs above)
npm run docs:check Report missing/stale generated docs without writing anything
npm run docs:verify Check that every generated doc matches what docs:build would write (by hash), without writing anything

build and typecheck fan out to every package under packages/*; test/format/lint already run across the whole workspace from the root.

Before opening a pull request, make sure the full set passes:

npm run ci && npm run typecheck && npm run test && npm run build

Conventions

  • Formatting is Prettier (default settings, no overrides) and linting is ESLint (eslint.config.js — typescript-eslint's recommended rules, with eslint-config-prettier disabling any ESLint rule that would conflict with Prettier's formatting). Running npm run check before you commit handles both.
  • Tests live next to the code as *.test.ts and run with vitest.
  • Comments and docs are in English and kept brief.
  • Type-only imports use import type (verbatimModuleSyntax is on).
  • Prefer a maintained library to hand-written logic, and keep the dependency ESM/CJS-dual. Anything a consumer loads through the package's API (kiritan's API, @kiritan/runtime, @kiritan/middleware and the provider packages) must be a library whose latest release ships both ESM and CJS, so require() and import both work without bundling tricks; check the latest version's exports before adding one. The CLI is the exception, and may use ESM-only libraries such as yargs. The one standing exception in the API is the unified/remark-* stack in kiritan: it is ESM-only with no dual-format equivalent that can also stringify Markdown, so it is bundled into dist/ (see tsdown.config.ts) and CJS consumers are unaffected. It stays until such an equivalent exists.

Pull requests

Keep each change focused and add tests for any new behaviour. There's no changeset or similar file to add — versioning happens entirely at release time (see below), not per PR.

Releasing (maintainers)

Every npm package (kiritan, @kiritan/runtime, @kiritan/deepl, @kiritan/google-translate, @kiritan/middleware, @kiritan/free-translate) has its own workflow_dispatch GitHub Actions workflow — release.yml, release-runtime.yml, release-deepl.yml, release-google-translate.yml, release-middleware.yml, release-free-translate.yml — so releasing one package can never accidentally touch another. Each is a thin wrapper around a shared reusable workflow (_release-package.yml, not runnable on its own) that does the actual work.

From the Actions tab, run the package's workflow (e.g. release-runtime) with two inputs:

  • version: a semver bump (patch / minor / major / prerelease) or an explicit version (e.g. 0.2.0), passed straight to npm version.
  • dist_tag: the npm dist-tag to publish under. Leave empty to auto-detect — the prerelease identifier (e.g. beta from 0.2.0-beta.0), or latest for a stable version.

The workflow bumps that package's package.json (no changelog file — GitHub's auto-generated release notes, from merged PRs, are used instead), regenerates every base/*.base.md-derived doc (kiritan build, folded into the same commit), publishes to npm with provenance via trusted publishing (OIDC — no NPM_TOKEN needed), pushes the version commit and a <package>@<version> tag, and creates a GitHub Release.

Trusted publishing must be configured once per package on npmjs.com: package Settings → Publishing access → Trusted publishers → GitHub, pointing at that package's own workflow file (e.g. release.yml for kiritan, release-deepl.yml for @kiritan/deepl).

Since kiritan depends on @kiritan/runtime (currently ^0.1.0), bumping runtime's minor or major version doesn't automatically update Kiritan's dependency range — that's a manual follow-up PR when it happens, on purpose, so releasing runtime alone never touches Kiritan's package.json.

The VS Code extension (extensions/vscode) has its own release-vscode.yml instead, since it doesn't publish to npm — it takes only version, packages a .vsix via vsce, tags the release as kiritan-vscode@<version> and creates a GitHub Release with the .vsix attached, and additionally publishes to the VS Code Marketplace only if a VSCE_PAT repository secret is configured (Marketplace publishing isn't set up yet, so today this just produces a downloadable .vsix).

extensions/vscode lives outside packages/ and so is never picked up by the root "workspaces": ["packages/*"] glob — its package.json "name" is "kiritan", which would otherwise collide with the CLI package of the same name (an npm workspace can't have two packages sharing a name). Its build/test tooling (@vscode/vsce, vscode-textmate, vscode-oniguruma) lives in the root package.json's devDependencies instead, resolved the normal Node.js way when tsc/vitest/vsce run against it — no separate npm install step is needed for it.

The Vim/Neovim plugin (extensions/vim) has nothing to build or publish — users install it directly from this repo via a plugin manager's rtp option, so release-vim.yml only runs the test suite and then tags the commit as kiritan-vim@<version> and creates a GitHub Release (no attached asset), for anyone who wants to pin to a specific version instead of tracking main. There's no package.json here to hold a current version to bump from, so it finds the latest existing kiritan-vim@* tag and reuses npm version's own semver logic against a throwaway package.json — the same patch/minor/major/prerelease keyword or explicit-version version input as release.yml.

License

By contributing, you agree that your contributions are licensed under the WTFPL License.