|
| 1 | +# CLAUDE.md |
| 2 | + |
| 3 | +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. |
| 4 | + |
| 5 | +## Project Overview |
| 6 | + |
| 7 | +XMOJ-Script is a browser userscript that enhances the XMOJ online judge platform (xmoj.tech). This repository consists of: |
| 8 | +- **Main userscript** (`XMOJ.user.js`): ~5000 line single-file userscript with all features. As this file is very large you should use the xmoj-code-navigator agent to help you whenever possible. |
| 9 | +- **Update/version management scripts** (`Update/`): Automation for version bumping and releases |
| 10 | +- **Metadata and documentation**: `Update.json` tracks version history, README and contributing guides |
| 11 | + |
| 12 | +The `backend/` directory is a git submodule pointing to https://github.com/XMOJ-Script-dev/XMOJ-bbs and should be modified in that repository, not here. |
| 13 | + |
| 14 | +## Development Workflow |
| 15 | + |
| 16 | +### Branch Structure and PR Requirements |
| 17 | + |
| 18 | +- `master`: Production branch - **DO NOT make PRs directly to master** |
| 19 | +- `dev`: Development branch - **ALL PRs must be based on and target this branch** |
| 20 | +- `extern-contrib`: External contributors must submit PRs to this branch |
| 21 | + |
| 22 | +**CRITICAL: All pull requests must:** |
| 23 | +1. Be based on the `dev` branch (branch off from `dev`) |
| 24 | +2. Target the `dev` branch (not `master`) |
| 25 | +3. Merge latest `dev` into your branch before submitting to resolve conflicts |
| 26 | + |
| 27 | +The workflow is: `dev` → (when ready) → `master` for releases. Direct PRs to `master` are not accepted. |
| 28 | +You should follow the PR template that can be found [here](https://raw.githubusercontent.com/XMOJ-Script-dev/.github/refs/heads/main/.github/PULL_REQUEST_TEMPLATE.md). |
| 29 | + |
| 30 | +### Version Management (CRITICAL - Fully Automated) |
| 31 | + |
| 32 | +Version updates are **fully automated** via GitHub Actions. When a PR to `dev` modifies `XMOJ.user.js`: |
| 33 | + |
| 34 | +1. The `UpdateVersion` workflow runs `Update/UpdateVersion.js` which automatically: |
| 35 | + - Bumps patch version in `package.json` |
| 36 | + - Updates `@version` in `XMOJ.user.js` metadata block |
| 37 | + - Adds/updates entry in `Update.json` with PR number, title, and timestamp |
| 38 | + - Commits changes back to the PR branch with `github-actions[bot]` |
| 39 | + |
| 40 | +2. Version sync is enforced between: |
| 41 | + - `package.json` → `"version": "x.y.z"` |
| 42 | + - `XMOJ.user.js` → `// @version x.y.z` (in metadata block) |
| 43 | + - `Update.json` → `UpdateHistory["x.y.z"]` (JSON key) |
| 44 | + |
| 45 | +**Never manually edit version numbers** - the automation handles this based on PR metadata. |
| 46 | + |
| 47 | +### Release Notes in PRs |
| 48 | + |
| 49 | +To add release notes to a PR that will appear in the release, include an HTML comment block in the PR description: |
| 50 | + |
| 51 | +```markdown |
| 52 | +<!-- release-notes |
| 53 | +Your release notes here in markdown format |
| 54 | +--> |
| 55 | +``` |
| 56 | + |
| 57 | +The `UpdateVersion.js` script extracts this and adds it to `Update.json` as the `Notes` field. |
| 58 | + |
| 59 | +### Bypassing Automation |
| 60 | + |
| 61 | +To prevent CI from touching your PR (e.g., during merge conflicts or debugging), add `//!ci-no-touch` anywhere in `Update.json`. The automation will remove it and exit without making other changes. |
| 62 | + |
| 63 | +### Release Process |
| 64 | + |
| 65 | +- **Pre-release**: Push to `dev` triggers a pre-release with `"Prerelease": true` in Update.json |
| 66 | +- **Release**: Merge `dev` to `master` triggers a production release |
| 67 | +- Releases are created by `Update/GetVersion.js` reading the version from XMOJ.user.js |
| 68 | +- Both workflows deploy to Cloudflare Pages and GitHub Pages |
| 69 | + |
| 70 | +## Code Structure |
| 71 | + |
| 72 | +### Main Userscript (`XMOJ.user.js`) |
| 73 | + |
| 74 | +A single-file userscript (~5000 lines) organized as: |
| 75 | + |
| 76 | +1. **Metadata block** (lines 1-50): Userscript headers |
| 77 | + - `@name`, `@version`, `@description`, `@author` |
| 78 | + - `@match` patterns for xmoj.tech and 116.62.212.172 |
| 79 | + - `@require` declarations for external libraries (CryptoJS, CodeMirror, FileSaver, marked, DOMPurify) |
| 80 | + - `@grant` permissions for GM APIs |
| 81 | + |
| 82 | +2. **Main script body**: Direct DOM manipulation and feature injection |
| 83 | + - Page detection and routing based on URL patterns |
| 84 | + - UI enhancements using Bootstrap classes |
| 85 | + - Feature implementations (auto-refresh, code checking, test data fetching, dark mode, etc.) |
| 86 | + - API calls to backend at `api.xmoj-bbs.tech` / `api.xmoj-bbs.me` |
| 87 | + |
| 88 | +Key classes/functions: |
| 89 | +- `compareVersions()` (line 112): Version comparison logic |
| 90 | +- `NavbarStyler` class (line 589): Navigation bar styling |
| 91 | +- `replaceMarkdownImages()` (line 715): Markdown image processing |
| 92 | + |
| 93 | +### Update Scripts (`Update/`) |
| 94 | + |
| 95 | +Node.js scripts run by GitHub Actions (not for local development): |
| 96 | + |
| 97 | +- **`UpdateVersion.js`**: Automated version bumping for PRs to `dev` |
| 98 | + - Reads PR number, title, body from command line args |
| 99 | + - Uses `gh` CLI to check out PR branch |
| 100 | + - Parses `<!-- release-notes -->` blocks from PR body |
| 101 | + - Updates version in all three locations |
| 102 | + - Pushes changes back to PR branch |
| 103 | + |
| 104 | +- **`GetVersion.js`**: Extracts current version from XMOJ.user.js for release workflows |
| 105 | + |
| 106 | +- **`UpdateToRelease.js`**: Changes `"Prerelease": false` when promoting to production |
| 107 | + |
| 108 | +- **`AutoLabel.js`**: Auto-labels PRs based on content |
| 109 | + |
| 110 | +These scripts directly manipulate `Update.json` and `XMOJ.user.js` using Node.js fs module. |
| 111 | + |
| 112 | +## Coding Standards |
| 113 | + |
| 114 | +### Style Guidelines (from CONTRIBUTING.md) |
| 115 | + |
| 116 | +- **Variables**: camelCase |
| 117 | +- **Functions**: PascalCase |
| 118 | +- **Classes**: TitleCase |
| 119 | +- **Line endings**: Unix (LF) |
| 120 | +- **Do NOT run code formatters** - maintain original formatting |
| 121 | +- **Use Bootstrap classes** instead of custom CSS |
| 122 | +- **No external libraries** without permission (script already includes many via `@require`) |
| 123 | + |
| 124 | +### Development Principles |
| 125 | + |
| 126 | +- **Stability before features**: Bug fixes take priority |
| 127 | +- Respect the original code style, even if inconsistent |
| 128 | +- New features require prior discussion in an issue |
| 129 | +- Before submitting PRs, merge `dev` into your branch and resolve conflicts |
| 130 | + |
| 131 | +## Testing |
| 132 | + |
| 133 | +No automated test suite exists. Manual testing workflow: |
| 134 | + |
| 135 | +1. Install the userscript in Tampermonkey/ScriptCat/Violentmonkey |
| 136 | +2. Navigate to xmoj.tech (or 116.62.212.172) |
| 137 | +3. Test features on relevant pages: |
| 138 | + - Problem lists |
| 139 | + - Problem detail pages |
| 140 | + - Status/submission pages |
| 141 | + - Contest pages |
| 142 | + - User profiles |
| 143 | + |
| 144 | +Observe browser console for errors and verify UI enhancements appear correctly. |
| 145 | + |
| 146 | +## Common Issues |
| 147 | + |
| 148 | +### Version Sync Errors |
| 149 | + |
| 150 | +If you see "XMOJ.user.js and Update.json have different patch versions": |
| 151 | +- The automation keeps these in sync normally |
| 152 | +- If manually editing (not recommended), update both files |
| 153 | +- Use `//!ci-no-touch` if you need to bypass automation temporarily |
| 154 | + |
| 155 | +### PR Requirements |
| 156 | + |
| 157 | +- **All PRs must be based on and target `dev` branch, not `master`** |
| 158 | +- Only PRs from the same repository (not forks) trigger auto-versioning |
| 159 | +- PRs must modify `XMOJ.user.js` to trigger version bumps |
| 160 | +- Must merge `dev` into your branch before submitting |
| 161 | +- External contributors must target `extern-contrib` branch |
| 162 | + |
| 163 | +### Single-File Architecture |
| 164 | + |
| 165 | +The entire userscript is intentionally in one file - do not split into modules. Userscript managers load it as a single file, with external dependencies via `@require` headers in the metadata block. |
0 commit comments