Skip to content
This repository was archived by the owner on May 29, 2026. It is now read-only.
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 151 additions & 60 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -1,88 +1,179 @@
Contributing to Muya
---
# Contributing to Muya

First, thank you for considering a contribution to Muya! It's people like you that make Muya a
better tool for everyone.
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, originally part of *
*[MarkText](https://github.com/marktext/marktext)**. We are excited to have you help us improve its
performance, stability, and feature set.
Muya is a web-based Markdown editor engine extracted from [MarkText](https://github.com/marktext/marktext). The bulk of the source today lives in `packages/core/`.

# Table of Contents
## Table of contents

* Code of Conduct
* How Can I Contribute?
* Development Setup
* Pull Request Process
* Style Guide
- [Code of conduct](#code-of-conduct)
- [Ways to contribute](#ways-to-contribute)
- [Development setup](#development-setup)
- [Repository layout](#repository-layout)
- [Useful commands](#useful-commands)
- [Coding conventions](#coding-conventions)
- [Commits and pull requests](#commits-and-pull-requests)
- [Testing](#testing)
- [Where to ask questions](#where-to-ask-questions)

# Code of Conduct
## Code of conduct

By participating in this project, you agree to abide by our code of conduct. We expect all
contributors to be kind, treat each other with respect, and forgive mistakes.
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](https://github.com/contact/report-abuse) or by emailing the maintainer listed under `author` in [`package.json`](./package.json).

# How Can I Contribute?
## Ways to contribute

# Reporting Bugs
- **Report a bug** — open an issue with a clear title, a minimal reproduction (Markdown input + steps), and the muya / browser version. Search [existing issues](https://github.com/marktext/muya/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](#commits-and-pull-requests) below.

* Check the Issue Tracker to ensure the bug hasn't already been reported.
* If you find a new bug, please open a new issue. Include a clear title, a description of the
problem, and steps to reproduce the bug.
## Development setup

# Suggesting Enhancements
**Prerequisites**

* We welcome feature requests! Please open an issue and label it as an `enhancement`.
* Provide as much context as possible about why the feature would be useful.
- 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](https://pnpm.io/) ≥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.

# Improving Documentation
**First-time setup**

* Documentation is vital for Muya's success. Whether it's fixing a typo or writing new guides, your
help is valued.
```sh
# 1. Fork on GitHub, then clone your fork.
git clone git@github.com:<your-user>/muya.git
cd muya

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

To start developing on Muya, follow these steps:
# 3. Install dependencies (also wires up husky git hooks).
pnpm install

1. **Fork the repository** to your own GitHub account.
2. **Clone the fork** to your local machine:
# 4. Boot the examples app to try your changes in a real editor.
pnpm dev
```

```bash
git clone [your-fork-repo-url]
```
`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.

3. **Install dependencies**:
## Repository layout

```bash
npm install

```
```
.
├── 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:

```sh
# 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:

4. **Run the project locally**:
- **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.

```bash
npm run dev

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:

```sh
pnpm lint
pnpm lint:types
pnpm test
pnpm check-circular
```

# Pull Request Process
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.

1. **Create a new branch** for your changes: `git checkout -b feature/your-feature-name`.
2. **Make your changes** and ensure they follow the Style Guide.
3. **Run tests** to ensure no regressions: `npm test`.
4. **Commit your changes** with descriptive messages.
5. **Push to your fork** and open a Pull Request against the `main` branch.
6. Wait for a maintainer to review your PR. Be prepared to make requested changes.
## Testing

# Style Guide
- **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.

* **JavaScript**: Follow standard linting rules provided in the project.
* **Markdown**: Muya is a Markdown editor; ensure any documentation follows clear, standard Markdown
formatting.
## Where to ask questions

---
- **Usage or bug reports** → open an [issue](https://github.com/marktext/muya/issues). Search first; tag with `enhancement` if it's a feature request.
- **Architecture deep-dives** → `CLAUDE.md` is the canonical agent/human-readable map of the codebase.
- **Release tooling** → `README.md` (Publishing section) and `.release-it.json`.

# Useful Links
- [Muya Repository](https://github.com/marktext/muya)
- MarkText Website
- [GitHub Documentation on Contributing](https://docs.github.com/en/get-started/exploring-projects-on-github/contributing-to-open-source)

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