Thanks for considering a contribution. This is a personal/hobby project, so response times may vary, but PRs and issues are genuinely welcome.
For anything beyond a small fix (typo, obvious bug), please open an issue first to discuss the change. This is especially true for:
- Adding a new language to the catalog (
src/lib/languages.ts) - there are a lot already, and additions should have a real execution path (see ARCHITECTURE.md), not just a catalog entry with no backend. - Changes to the execution sandboxing model (
src/lib/server/sandbox.ts)- these have security implications, see SECURITY.md.
- Anything touching the settings schema (
src/lib/settings.ts) - it's persisted to users' local storage, so changes need a sensible default and shouldn't break existing stored settings.
git clone <your fork>
cd PLInt
npm install
npm run devSee DEPLOY.md if you want to test the server-execution
backend against real interpreters locally - npm run dev uses the same
/api/execute route as production, so anything installed on your
machine's PATH will work.
- TypeScript, strict-ish - avoid
anywhere a real type is easy to write.typescriptis intentionally pinned to^5.7.3, not the newer TypeScript 7 native compiler -typescript-eslintdoesn't support TS7 yet (its peer range is>=4.8.4 <6.1.0, and installing past that with--force/--legacy-peer-depsmakes ESLint crash at runtime, not just at install time). Revisit this once typescript-eslint adds TS7 support. - Run
npm run lintbefore committing; CI runs ESLint on every push and PR (see.github/workflows/lint.yml). Also runnpm run format(Prettier) before committing, it's not currently enforced in CI (the codebase hasn't been run through it yet), but keeping new code formatted makes a futureprettier --checkCI gate a one-line addition instead of a giant diff. - Keep comments purposeful and short - explain why, not what the code obviously does.
- Match the existing patterns in a file rather than introducing a new
style locally (e.g., follow
asm()'s helper-function pattern when adding assembly languages, follow theNativeSpectable shape when adding a native-language runner).
- Add a
LanguageDefentry to the appropriate array insrc/lib/languages.ts(CORE,WEIRD,ESOTERIC, orASSEMBLY). - If Monaco doesn't ship syntax highlighting for it natively, add a
Monarch tokenizer in
src/lib/monaco-languages.ts. - Wire up execution:
- Fits in the browser (like CoffeeScript or Markdown)? Add a runner to
src/lib/runners/browser.tsand register it insrc/lib/runners/index.ts. - Needs a real system interpreter/compiler? Add an entry to
SPECSinsrc/lib/server/native.ts. - Genuinely esoteric with no standard package? Add an interpreter to
src/lib/server/esoteric.tsand register it insrc/lib/server/registry.ts.
- Fits in the browser (like CoffeeScript or Markdown)? Add a runner to
- Test it. Run the sample code you wrote through the real interpreter before opening a PR - several bugs have been found this way in both sample programs and interpreter logic during this project's history. If you're adding a hand-written interpreter, include a small test script or note in the PR description showing it against the bundled sample.
- Keep PRs focused - one language addition or one bug fix per PR is easier to review than a grab-bag.
- Describe what you tested and how, especially for anything touching code execution.
- Update relevant docs in
docs/if behavior changes.
Open a GitHub issue with:
- What you expected vs. what happened.
- The language involved, if applicable, and a minimal code sample.
- Whether it's a browser-side or server-side language (see ARCHITECTURE.md if you're not sure).
For security issues, see SECURITY.md instead of a public issue.
Participation in this project means agreeing to CODE_OF_CONDUCT.md.