{"id":26221684,"url":"https://github.com/snowflyt/repl","last_synced_at":"2025-10-29T05:32:58.271Z","repository":{"id":279153386,"uuid":"937863965","full_name":"Snowflyt/repl","owner":"Snowflyt","description":"An Online REPL for JavaScript/TypeScript","archived":false,"fork":false,"pushed_at":"2025-04-13T09:30:50.000Z","size":25321,"stargazers_count":39,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-04-13T09:42:42.194Z","etag":null,"topics":["browser","javascript","online","repl","typescript"],"latest_commit_sha":null,"homepage":"https://repl.js.org/","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Snowflyt.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-02-24T03:07:28.000Z","updated_at":"2025-04-13T09:30:17.000Z","dependencies_parsed_at":"2025-02-24T04:30:54.607Z","dependency_job_id":"fb5da744-6927-47c2-b26e-b741c40ff092","html_url":"https://github.com/Snowflyt/repl","commit_stats":null,"previous_names":["snowflyt/repl"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Frepl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Frepl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Frepl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Snowflyt%2Frepl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Snowflyt","download_url":"https://codeload.github.com/Snowflyt/repl/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249326666,"owners_count":21251754,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["browser","javascript","online","repl","typescript"],"created_at":"2025-03-12T16:29:12.117Z","updated_at":"2025-10-29T05:32:58.263Z","avatar_url":"https://github.com/Snowflyt.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003eJS/TS REPL\u003c/h1\u003e\n\n\u003cp align=\"center\"\u003e\n  An online \u003cstrong\u003eREPL\u003c/strong\u003e for \u003cstrong\u003eJavaScript/TypeScript\u003c/strong\u003e.\n\u003c/p\u003e\n\n![screenshot](./screenshots/screenshot.png)\n\n## Features\n\n- **Interactively** execute \u003cdel\u003eany\u003c/del\u003e [almost any](#limitations) JavaScript/TypeScript code directly in your browser.\n- _(Type annotations are stripped before execution, and no type checking is performed.)_\n- Beautiful output with **syntax highlighting** (powered by [highlight.js](https://github.com/highlightjs/highlight.js)) and **pretty-printing** (enabled by [showify](https://github.com/Snowflyt/showify)).\n- **Import any NPM package** directly with `import` statements (powered by [esm.sh](https://esm.sh/)).\n- **Auto-completion (intellisense)** powered by the TypeScript language service running in a Web Worker. Third-party type definitions are automatically fetched when importing NPM packages (powered by [@typescript/ata](https://www.npmjs.com/package/@typescript/ata)).\n- **Shareable** links to your REPL, with history encoded in the URL.\n- **Rich content output** for HTML (including plots/charts), Markdown, SVG, images, and more. See details in [Rich Content Output](#rich-content-output).\n- **Top-level `await`** is supported, and can be cancelled using \u003ckbd\u003eCtrl\u003c/kbd\u003e + \u003ckbd\u003eC\u003c/kbd\u003e.\n- Conveniently **copy** and **jump to previous inputs** using the buttons on the right side of the input field, and easily **navigate through your history** with the \u003ckbd\u003e↑\u003c/kbd\u003e and \u003ckbd\u003e↓\u003c/kbd\u003e keys.\n- **REPL commands** for extra functionality:\n  - `:check \u003ccode\u003e` or `:c \u003ccode\u003e` to get the type of an expression without executing it.\n  - `:type \u003cTypeExpr\u003e` or `:t \u003cTypeExpr\u003e` to get the evaluated type of a TypeScript type expression.\n- **Clear history** with `clear()` or `console.clear()`.\n- Full support for the **`console` API**, including methods like `console.dir()`, `console.group()`, `console.table()`, `console.time()`, etc.\n- **Responsive** layout, optimized for mobile devices.\n\n## Rich Content Output\n\nThis REPL can render Jupyter-style rich outputs by choosing the “richest” MIME type it supports. You can return:\n\n- A regular output value (string, number, object, etc.), which will be pretty-printed.\n- A DOM node (HTMLElement or DocumentFragment), which will be mounted live.\n- A “MIME bundle” object keyed by MIME types (for example `text/html`, `text/markdown`, `image/png`).\n\nThe easiest way is to return an object that implements the special method `[Symbol.for(\"Jupyter.display\")]`, similar to [Jupyter Kernel for Deno](https://docs.deno.com/runtime/reference/cli/jupyter/). The method should return an object that maps a MIME type to the value to display.\n\n```javascript\n({\n  [Symbol.for(\"Jupyter.display\")]() {\n    return {\n      \"text/plain\": \"Hello, world!\",\n      \"text/html\": \"\u003ch1\u003eHello, world!\u003c/h1\u003e\",\n    };\n  },\n});\n```\n\n![Rich content output example](screenshots/rich-output-special-method.png)\n\n\u003e [!TIP]\n\u003e\n\u003e You can also use `Rich.$display` instead of typing `Symbol.for(\"Jupyter.display\")`.\n\nThis REPL provides a set of helpers under the global `Rich` namespace:\n\n- `Rich.html` — tagged template to render HTML\n- `Rich.md` — tagged template to render Markdown\n- `Rich.mdBlock` — like `Rich.md` but hides the input (Markdown cell)\n- `Rich.svg` — tagged template to render SVG markup\n- `Rich.image(input)` — render an image from a URL (http/https/data/blob) or bytes (Uint8Array/ArrayBuffer)\n\nExamples:\n\n```javascript\nRich.html`\u003ch1\u003eHello\u003c/h1\u003e\u003cp\u003eFrom the REPL\u003c/p\u003e`;\n\nRich.md`# Heading\\n\\nSome **markdown** with an ![image](https://picsum.photos/64)`;\n\nRich.svg`\u003csvg viewBox=\"0 0 100 100\" xmlns=\"http://www.w3.org/2000/svg\"\u003e\n  \u003ccircle cx=\"50\" cy=\"50\" r=\"40\" stroke=\"green\" stroke-width=\"4\" fill=\"yellow\" /\u003e\n\u003c/svg\u003e`;\n\nRich.image(\"https://picsum.photos/536/354\");\n\n// You can also provide bytes with an explicit MIME\nconst bytes = new Uint8Array(/* ... */);\nRich.image(bytes, \"image/png\"); // If MIME is not provided, it will be inferred\n```\n\n![Rich content output helpers](screenshots/rich-output-helpers.png)\n\nReturning a DOM node is also supported:\n\n```javascript\nconst el = document.createElement(\"div\");\nel.innerHTML = \"\u003cstrong\u003eLive node\u003c/strong\u003e\";\nel.style.width = \"fit-content\";\nel.style.padding = \"8px\";\nel.style.border = \"2px dashed gray\";\nel.style.borderRadius = \"6px\";\nel;\n```\n\n![Rich content output live node](screenshots/rich-output-dom.png)\n\nYou can even render a plot using third-party libraries like [Observable Plot](https://observablehq.com/plot/):\n\n```javascript\nimport csv from \"csvtojson\";\nimport * as Plot from \"@observablehq/plot\";\n\nconst raw = await fetch(\n  \"https://raw.githubusercontent.com/juba/pyobsplot/main/doc/data/penguins.csv\",\n).then((res) =\u003e res.text());\nconst penguins = await csv({\n  checkType: true,\n  colParser: { \"*\": (v) =\u003e (v === \"NaN\" ? NaN : v) },\n}).fromString(raw);\n\nPlot.plot({\n  color: { legend: true },\n  marks: [\n    Plot.dot(penguins, {\n      x: \"culmen_depth_mm\",\n      y: \"culmen_length_mm\",\n      fill: \"species\",\n    }),\n  ],\n});\n```\n\nTry it in [this REPL](http://repl.js.org/?rerun=\u0026history=GoJglgAAYmC2AOB7ATgFwAQGMDOA3dAZsorOgEQ66qIBW2iAdmQFBxJroBU6AhtugAUANogxES5AAKIARtgCmyXDxlD5ACwCOAengjUZSACfMjbBmQ8A7ugC8vKzzBj5qTOoAUZdalTxsAFza2pZWAHQA5s7qAK4yMQrIpgyo8ilhprDaNHE8ugCesth6otqwTgzaACaImNU8qHnwaRExYAzYGXhkAJRhqOppHh7I8tg9dgB86KOdqQAeqB49PczJ5ujNDK3t-PbWThiUHgDeWIOYANYAKvnNAeioyDHyADRYiEICPMiJD2dkThkB4eXATWzTfC2aHkAByPFhZHQAH50PDYegHvgAL7obF9cSwADKT3aERG1h6kAA5cJRGESksTsx0B8RMh-ug1BE0lUHk8XnjXiz0OVkJdAugANoi1l01BhGpLLY7DrvZmszXoeYPCgxISwNIAfSq8ngAyNsFgZGFWtZ%2BV1mH1hoYRrU2wtVptss1BDAQiEuuK8kwYDGLC1%2BJFAF1mPjIIAX4EwQj4-GAIeoyBAABF0BqPh0BZhMyN5DwagwhPltQ8GDFYDJFO9RuXGFX0A70HWG4oJidscwRVKifkG58wgQUF4AFIxeD5VLIRVgYop-K9aPLPM%2B4LoADCPCETpTqXQuDDVhkiHm6GwYAAXvJ0DI%2BPIquhGGeMyhRTwIgxnBiU0fXWDByn-QDTTsdAAFkGnUMJsE0NAPAGFcwhvThuBAdAAGpHnUdDqyw9AQFWLVQLPC8r3mIkHyfew4IGMJynmDwAEYAAZOPeHDuHAgDUCA%2BRyM1SjMDSRdoPPeRL2vOjH3QbRSJ9VkQLMI5Ph-ewyAAYnYgBWAAOTiAGYqhYH1RiE5AGG3O1yAWVBdBTdpgXQAADdNixQHMPB1dAABITjQzp5mxd5O2C0KwnyfEPNtO1DHA%2BRtDwCJcPmWAhHcjzVM1AAedL0EGMAIh8WwyGCmS5No%2BjsSRKwwCqAZKuq6j5PqpEaoAIWvSrOPQQb2tkmiFPkXERtq8aGsmfKtQK00CGwOaHIcgqxUuRR0GayqfmIKxBnLJFNsUAB1ZrWrIAyTp%2BLbkAACXkMqKuuiM1o%2BrVRgIAANSqbpmeQCAATUqkAwgBlAwxSPaYmoMhVs%2BhakCrCJPyQdpUGwAahveAzSIh95BoBv0Azak5THZBqlMRpGCrKO7FFptb6aWlbBzpoR2ifeZ2PJiSUkUan8j5qqKckoWkXmEB%2BYl5A8II9DwqRfIZbFgWpIAWkVzo4vej7zHyNRKvMYgtoCYLKZQbEAG5TcQLbNaalr1ACEBbvFRRNd5SqYmQIQPF0-bEEOssqh6JFtGZha0twCJo88n0B1ZAdsUgAA0BhZPQbzMz8wyePQLjOJ6IA)!\n\n![Rich content output plot](screenshots/rich-output-plot.png)\n\nAdditionally, you can include an `\"application/x.repl-hide-input\"` key in the MIME bundle to hide the input line for that cell. For example:\n\n```javascript\n({\n  [Symbol.for(\"Jupyter.display\")]() {\n    return {\n      \"application/x.repl-hide-input\": true,\n      \"text/markdown\": \"# This input is hidden\\n\\nUsing a special MIME type.\",\n    };\n  },\n});\n```\n\nWith this approach, you can create Markdown cells like in Jupyter notebooks. We provide a convenience method for that as well:\n\n```javascript\nRich.mdBlock`# Title\\n\\nThis input is hidden.`;\n```\n\nTry it in [this REPL](http://repl.js.org/?history=GoJglgAApASmDGALAdAWwCYCEA2B7eA1gAYDEABACpgAu2ApgDoB2zAIrmQM66p3WJgmAcyKIAVhACw1OgA9qAelQBDAE4F0uAO5MAyhACo5KrToAoM%2By48%2BA4REhQFCsrptl4udHTJzlqAAd6TjNPJm56ZDwhAAoAFhAASlwIABgAbABtAGZs1ASs7IBOVEhMOCQ0LDxCIgBRWSDlQTIAHgBXAD5%2BOlaFLrIAKkHcduoAseGyLRpEMmUyFXVNHTIAIxqCZFEJaTlFJY1tPQg4hqaWju7EXv7OoZGxieopmf55xbUj1Y38LYcIABqZyudy4HqqDxeHx%2BQLBUK4cK4SLReLZZJpQp5OLZQolSAAeQqKAwOD%2B9Ua2GaTDaXR6fQGw1G40mg2ms1pnWUTHBN1UDPuhxWNN%2BhG24ikMnkSi%2Bwv0AEFzlTLnSbgKHsznq8OVduby6Py7p9lsd1ptkBAgA)!\n\n![Rich content output hidden input example](screenshots/rich-output-hidden-input.png)\n\nYou can also display something immediately (as a side-effect) using the `display(value)` function, which returns a Promise. The value is rendered as follows:\n\n- Strings: stringified with quotes and escaping (like `JSON.stringify`).\n- DOM nodes: mounted live with a persisted snapshot.\n- Objects implementing `Symbol.for(\"Jupyter.display\")`: rendered as rich MIME bundles.\n- Other values: stringified like `console.log`.\n\n```javascript\nawait display(\"Hello, world!\");\n\n// Display a rich HTML figure immediately\nawait display(Rich.html`\u003ch1\u003eHello\u003c/h1\u003e\u003cp\u003eFrom the REPL\u003c/p\u003e`);\n\n// Display markdown immediately and hide the input line (Jupyter-style)\nawait display(Rich.mdBlock`# Title\\n\\nThis input is hidden.`);\n```\n\n## Limitations\n\n### Simulated Global Scope\n\nThis REPL simulates rather than implements a true global scope, which affects how closures work between separate evaluations. For example:\n\n```javascript\nconst f = () =\u003e value; // First evaluation\nconst value = 42; // Second evaluation\nf(); // Third evaluation - ReferenceError!\n```\n\n**Behavior explanation:**\n\n- When pasted as a single block, this code works as expected because it’s evaluated together.\n- When run line-by-line, it fails because each line is evaluated in its own isolated context.\n\n**Technical details:** Each code snippet is processed as follows:\n\n- The TypeScript compiler API analyzes the code.\n- Top-level variables are extracted to a shared context object.\n- This context is passed to subsequent evaluations.\n\nThis effectively transforms the above example into something like:\n\n```javascript\nconst context = {};\n\nconst updateContext = (obj) =\u003e {\n  for (const key in obj) {\n    context[key] = obj[key];\n  }\n};\n\nupdateContext(\n  new Function(\n    ...Object.keys(context),\n    `\n      const f = () =\u003e value;\n      return { f };\n    `,\n  )(...Object.values(context)),\n);\n\nupdateContext(\n  new Function(\n    ...Object.keys(context),\n    `\n      const value = 42;\n      return { value };\n    `,\n  )(...Object.values(context)),\n);\n\nupdateContext(\n  new Function(\n    ...Object.keys(context),\n    `\n      const __repl_result___ = f();\n      return { __repl_result___ };\n    `,\n  )(...Object.values(context)),\n);\nconsole.log(context.__repl_result___);\n```\n\nSince the `value` variable is not defined in the first snippet of code, the `f` function will throw a ReferenceError when it’s called.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnowflyt%2Frepl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsnowflyt%2Frepl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsnowflyt%2Frepl/lists"}