Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.

Latest commit

 

History

History
179 lines (130 loc) · 9.91 KB

File metadata and controls

179 lines (130 loc) · 9.91 KB

Contributing to Muya

Thanks for your interest in improving Muya! This document covers everything you need to file a useful issue or land a pull request against @muyajs/core.

Muya is a web-based Markdown editor engine extracted from MarkText. The bulk of the source today lives in packages/core/.

Table of contents

Code of conduct

Be kind, assume good intent, and keep discussions on-topic. Personal attacks, harassment, and discriminatory language are not welcome. If you witness or experience a violation, you can report it through GitHub's abuse reporting flow or by emailing the maintainer listed under author in package.json.

Ways to contribute

  • Report a bug — open an issue with a clear title, a minimal reproduction (Markdown input + steps), and the muya / browser version. Search existing issues first to avoid duplicates.
  • Suggest an enhancement — open an issue tagged with enhancement and explain the use case. Larger proposals (new public API, new block type) benefit from a short design sketch before the PR.
  • Improve docs — README, CLAUDE.md, MIGRATION.md, docs/, and the per-package READMEs are all fair game.
  • Send a pull request — bug fixes, parser conformance improvements, new UI plugins, performance wins, tests, and CI hardening are all appreciated. See Commits and pull requests below.

Development setup

Prerequisites

  • Node.js ≥18 for everyday development. Releases require Node ≥20.19, ≥22.13, or ≥24 (the changelog plugin pins ^20.19.0 || ^22.13.0 || >=24.0.0).
  • pnpm ≥8.5. The repo is pinned to pnpm@10.22.0 via packageManager — install the matching version (e.g. corepack enable && corepack prepare pnpm@10.22.0 --activate).
  • A Chromium-based browser for the dev demo and Playwright E2E suite.

First-time setup

# 1. Fork on GitHub, then clone your fork.
git clone git@github.com:<your-user>/muya.git
cd muya

# 2. Add the upstream remote so you can keep master in sync.
git remote add upstream git@github.com:marktext/muya.git

# 3. Install dependencies (also wires up husky git hooks).
pnpm install

# 4. Boot the examples app to try your changes in a real editor.
pnpm dev

pnpm dev runs turbo dev:demo, which starts the Vite dev server in examples/ and serves @muyajs/core directly from packages/core/src/ — no rebuild step needed while iterating.

Repository layout

.
├── packages/
│   ├── core/         @muyajs/core — the editor library (all source today)
│   ├── facade/       README-only stub (no source yet)
│   └── findReplace/  README-only stub (no source yet)
├── examples/         Vite vanilla-TS demo, consumes core via workspace:*
├── e2e/              Playwright real-browser suite (self-contained host page)
├── docs/             Logo, ROADMAP, JSON state reference
├── CLAUDE.md         Architecture + conventions deep-dive (start here for big changes)
└── CHANGELOG.md      Generated by release-it (angular conventional-changelog preset)

CLAUDE.md documents the runtime architecture (Muya → Editor → JSONState, the block tree, plugin registration, state ↔ markdown round-trip) and is the fastest way to orient yourself before touching packages/core/src/.

Useful commands

Run from the repo root — Turbo fans tasks out across packages.

Command What it does
pnpm dev Boot the examples Vite dev server (turbo dev:demo).
pnpm build tsc && vite build in packages/core. Emits lib/{es,umd,cjs} and lib/types.
pnpm test Vitest unit tests (--passWithNoTests).
pnpm coverage Vitest with Istanbul coverage (@vitest/coverage-istanbul).
pnpm lint / pnpm lint:fix ESLint (antfu base) over packages/.
pnpm lint:types tsc --noEmit per package.
pnpm lint:css Stylelint over all CSS.
pnpm check-circular madge --circular packages/core/src/index.ts — CI enforces this.
pnpm e2e Playwright suite (Chromium, port 5174). See e2e/README.md.
pnpm e2e:ui Playwright UI mode for interactive debugging.

Scoped runs:

# Run one Vitest file in core.
pnpm --filter @muyajs/core exec vitest run path/to/file.test.ts

# Watch a single package while iterating.
pnpm --filter @muyajs/core test:watch

# Run only the CommonMark / GFM conformance fixtures (baseline locked by
# packages/core/test/spec/expected-failures.json).
pnpm --filter @muyajs/core test:spec:commonmark
pnpm --filter @muyajs/core test:spec:gfm

Coding conventions

ESLint and Stylelint enforce most of these — pnpm lint:fix is the source of truth — but a few are worth knowing up front:

  • TypeScript first. All new source goes in .ts. Public types belong in packages/core/src/types.ts.
  • 4-space indent, semicolons required. The antfu config in eslint.config.mjs configures this for the repo.
  • Interface names start with I followed by an uppercase letter or digit (e.g. IMuyaOptions, IPlugin). The @typescript-eslint/naming-convention rule flags violations.
  • Private class members are prefixed with _ (e.g. _uiPlugins, _activeContentBlock).
  • Complexity caps. complexity ≤ 20 and max-lines-per-function ≤ 200 are warnings for non-test TS. Refactor rather than disable.
  • No circular imports. pnpm check-circular runs in CI; adding a cycle into packages/core/src/index.ts fails the build.
  • Block registration. New block types must be registered in packages/core/src/block/index.ts::registerBlocks(). ScrollPage.loadBlock(name) returns undefined and warns otherwise.
  • No new code paths producing ILinkReferenceDefinitionState. Reference link/image definitions round-trip through paragraph state — see markdownToState.ts and CLAUDE.md.
  • Avoid backwards-compat shims (renaming unused vars to _var, leaving "removed" comments, re-exporting deleted types). Delete unused code outright.

CSS lives next to its consumer (*.css co-located with the .ts) and is linted with Stylelint.

Commits and pull requests

Conventional Commits are required. The husky commit-msg hook runs commitlint and rejects subjects that don't match. Allowed types:

build, ci, chore, docs, feat, fix, perf, refactor, revert, style, test

Examples:

feat(core): add reference-image rendering
fix(inline): preserve cursor after IME composition
docs: clarify Muya.use registration order
test(spec): widen GFM table fixture coverage

Scope is optional but encouraged for packages/core/ work (core, inline, state, ui, spec, …).

Before opening a PR

  1. Branch off master: git checkout -b fix/short-description.

  2. Make focused commits — bundle drive-by cleanups into separate commits or PRs.

  3. Run the quality gates locally:

    pnpm lint
    pnpm lint:types
    pnpm test
    pnpm check-circular
  4. If your change touches the UI or editing surface, run pnpm e2e and add coverage for the new behavior under e2e/tests/.

  5. If your change affects markdown parsing or HTML output, check the conformance baseline doesn't regress: pnpm --filter @muyajs/core test:spec. Conformance can only go up — see packages/core/test/spec/expected-failures.json.

  6. Update MIGRATION.md if you change a public API.

Opening the PR

  • Base branch is master (not main).
  • Use a Conventional-Commit-style title (it becomes the squash commit subject).
  • Describe the why in the body, not just the what — the diff already shows the what. Link related issues with Closes #123 / Refs #123.
  • Pre-commit, lint-staged runs eslint --fix on staged *.ts and stylelint --fix on staged *.css (see .lintstagedrc). If a hook fails, fix the issue and create a new commit — don't bypass with --no-verify unless a maintainer asks you to.

Maintainers will review and may ask for changes. PRs are merged via squash merge to keep master linear; your branch commits don't need to be individually clean.

Testing

  • Unit tests live next to their source in packages/core/src/**/__tests__/ or *.test.ts, run with Vitest. Vitest has no global environment set — tests run under the default Node environment by default, and DOM-dependent tests opt into happy-dom with a // @vitest-environment happy-dom directive at the top of the file. New parser logic, state transforms, and pure helpers should ship with unit coverage.
  • Conformance fixtures. pnpm --filter @muyajs/core test:spec runs the CommonMark 0.31 and GFM 0.29-gfm fixture suites against renderToStaticHTML(..., { sanitize: false }). The expected-failures list is locked — making a failing fixture pass requires removing it from the list in the same PR.
  • E2E tests. Playwright suite in e2e/. Real browser, real contenteditable. Use this for behaviors that depend on selection, IME, clipboard, or floating UI positioning — anything happy-dom can't fake. See e2e/README.md for the helper API and e2e/BACKLOG.md for what's still uncovered.

Where to ask questions

  • Usage or bug reports → open an issue. Search first; tag with enhancement if it's a feature request.
  • Architecture deep-divesCLAUDE.md is the canonical agent/human-readable map of the codebase.
  • Release toolingREADME.md (Publishing section) and .release-it.json.

Thanks again for contributing — every typo fix, parser improvement, and test counts.