{"id":13469728,"url":"https://github.com/rsify/jay","last_synced_at":"2025-04-13T04:16:45.843Z","repository":{"id":34943006,"uuid":"187022701","full_name":"rsify/jay","owner":"rsify","description":"😎 Supercharged JavaScript REPL","archived":false,"fork":false,"pushed_at":"2023-01-03T23:59:15.000Z","size":547,"stargazers_count":985,"open_issues_count":24,"forks_count":19,"subscribers_count":12,"default_branch":"master","last_synced_at":"2025-04-13T04:16:30.961Z","etag":null,"topics":["await","cli","eager","javascript","modern","nodejs","readline","repl"],"latest_commit_sha":null,"homepage":"","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/rsify.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}},"created_at":"2019-05-16T12:23:17.000Z","updated_at":"2025-02-13T09:14:26.000Z","dependencies_parsed_at":"2023-01-15T10:49:43.767Z","dependency_job_id":null,"html_url":"https://github.com/rsify/jay","commit_stats":null,"previous_names":["nikersify/jay"],"tags_count":7,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsify%2Fjay","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsify%2Fjay/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsify%2Fjay/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rsify%2Fjay/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rsify","download_url":"https://codeload.github.com/rsify/jay/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248661715,"owners_count":21141451,"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":["await","cli","eager","javascript","modern","nodejs","readline","repl"],"created_at":"2024-07-31T15:01:53.162Z","updated_at":"2025-04-13T04:16:45.712Z","avatar_url":"https://github.com/rsify.png","language":"TypeScript","readme":"# Jay [![Build Status](https://travis-ci.com/nikersify/jay.svg?token=c7oPsWTPpETijSnB7xF2\u0026branch=master)](https://travis-ci.com/nikersify/jay) [![npm](https://img.shields.io/npm/v/jay-repl.svg)](https://npmjs.com/package/jay-repl)\n\n\u003e Supercharged JavaScript REPL :sunglasses:\n\nJay is a terminal-based JavaScript REPL focused on increasing prototyping speed and productivity. It's packed with modern REPL features, whilst also striving to maintain a familiar REPL vibe.\n\nHere are the most important features that differentiate Jay from other REPL's:\n\n- `require` modules directly from the registry\n- Eager eval (requires `node \u003e= 12.3.0`)\n- Top level `await`\n- Typeahead + dropdown menu-style completion\n\nPlus some necessities:\n\n- Colored input\n- Bracket/quote pair completion\n- Fresh `require`\n- Full [readline](https://nodejs.org/api/readline.html) keybindings support\n- Lazy loaded built-in modules\n- `_` variable\n\n\n# Why\n\nJay was created with two goals in mind:\n1. To bring modern JavaScript REPL features to the terminal, like eager eval, top level `await` and typeahead code completion\n2. To create a super quick environment for prototyping/running npm dependent JavaScript code.\n\nIt would probably make sense to split Jay into separate packages (just the REPL into one, and the smart `require` into another) in the future, to allow better reusability of the REPL components.\n\n\n# Examples\n\n## Basic web scraping\n\nLet's say that for some reason we want to scrape all of the titles and links from the [hacker news](https://news.ycombinator.com) front page.\n\nTo accomplish that, we can use Jay (obviously), [got](https://github.com/sindresorhus/got) (http client) and [cheerio](https://cheerio.js.org) (jQuery-esque API for server-side).\n\nLet's begin by running Jay and getting the necessary dependencies:\n\n```bash\n$ jay\n```\n\n```js\n\u003e const got = require('got')\n\u003e const cheerio = require('cheerio')\n```\n\nThen, we download the page and load the HTML into cheerio:\n\n```js\n\u003e const {body} = await got('https://news.ycombinator.com')\n\u003e const $ = cheerio.load(body)\n```\n\n`$` behaves pretty much like jQuery, we can use the following simple one-liner to get our result:\n```js\n\u003e $('a.storylink').map((i, el) =\u003e ({text: $(el).text(), link: $(el).attr('href')})).get()\n```\n```js\n[\n\t{\n\t\ttext: 'National Park Typeface',\n\t\tlink: 'https://nationalparktypeface.com'\n\t},\n\t...\n]\n```\n\nAfter running the previous line, we can store the result in a named variable via `_` - which caches the result of the last evaluation - as follows:\n\n```js\n\u003e const result = _\n\u003e result.length // 30\n```\n\n\u003chr\u003e\n\nIf you find an interesting example to put in this section, a PR is more than welcome!\n\n\n# Install\n\nJay expects itself to be installed globally:\n\n```sh\n$ npm install -g jay-repl\n```\n\nThen simply run it by typing `jay` in the terminal:\n\n```sh\n$ jay\n```\n\nAlternatively, Jay can be directly run with Node builtin `npx`:\n\n```sh\n$ npx -p jay-repl jay\n```\n\n\n# FAQ\n\n## How does the smart `require` function work?\n\nAfter pressing \u003ckbd\u003eenter\u003c/kbd\u003e in the prompt, Jay parses the entered input into an AST using [acorn](https://github.com/acornjs/acorn) and looks for all `CallExpression`'s whose names are equal to `require`.\n\nThis triggers the \"asker\" system to ask the user whether they actually want to install a given `require`'d module. If the user decides to install the module, Jay starts a \"global\" `npm` install in its cache directory. If they don't, nothing happens and the evaluation will most likely result in an \"module not found\" error.\n\nEither way, after all of the above is complete, the control is handed back to the evaluator which only now actually executes the entered line.\n\n## How does Jay's `require` differ from the normal one?\n\nThe normal `require` only looks for modules within two places:\n- locally, if the module id is prefixed with things like `.` or `../` - e.g. `require('./index.js')`\n- in `node_modules` - e.g. `require('express')`\n\nJay's `require` in addition to the above also looks within its global cache (but only if the local \u0026 `node_modules` resolutions fail). This, in addition to parsing the input and looking for `require` calls, allows for importing any module that's on the registry, automatically installing it if needed.\n\nThe `require` also is also a \"fresh `require`\".\n\n## What does \"fresh `require`\" mean?\n\nThe `require` function in Jay doesn't use the standard node's cache and always reads the files from disk upon importing them. Consider the following example:\n\nLet's say we have a file called `greet.js` with the following contents:\n\n```js\nmodule.exports = x =\u003e 'hello '.repeat(x)\n```\n\nStart up `node`'s repl, require it, and we get the expected output:\n```bash\n$ node\n```\n```js\n\u003e greet = require('./greet')\n\u003e greet(2)\n// 'hello hello '\n```\n\nNow, without closing the session, we change the file into:\n```diff\n-module.exports = x =\u003e 'hello '.repeat(x)\n+module.exports = x =\u003e 'hi '.repeat(x)\n```\n\nRequiring the file again will, unfortunately, not change the output:\n```js\n\u003e greet = require('./greet')\n\u003e greet(3)\n// 'hello hello hello '\n```\n\nJay, as beforementioned, doesn't cache modules. Repeating the steps yields the result we actually want in this case:\n```bash\n$ jay\n$ echo \"module.exports = x =\u003e 'hello '.repeat(x) \u003e greet.js\"\n```\n```js\n\u003e greet = require('./greet')\n\u003e greet(2)\n// 'hello hello '\n```\n```bash\n$ sed -i 's/hello/hi/' greet.js\n```\n```js\n// (in the same Jay session)\n\u003e greet = require('./greet')\n\u003e greet(3)\n// 'hi hi hi '\n```\n\nThis also works analogically with modules in `node_modules`, Jay's cache, JSON files, etc.\n\n## Where does Jay store the cached modules?\n\nJay uses [env-paths](https://github.com/sindresorhus/env-paths) to determine the cache's location:\n\n- MacOS - `~/Library/Caches/jay-repl-nodejs/packages`\n- Linux - `~/.cache/jay-repl-nodejs`\n- Windows - `~/`\n\nYou can see the exact location of the cache by simply running the following line in Jay:\n\n```js\n\u003e require('env-paths')('jay-repl').cache\n```\n\n\n# Contributing\n\n1. Fork \u0026 clone the repository\n2. Start the Typescript watch script:\n\n```bash\n$ npm run build:watch\n```\n\n3. Make your changes\n4. Try out your changes on your local build\n\n```bash\n$ node dist/cli.js\n```\n\n5. Run the tests:\n\n```bash\n$ npm test\n```\n\n6. Commit \u0026 PR!\n\nThis repository uses Git LFS for storing readme's gifs, if you want to view them locally you will need to install and set up the [Git LFS](https://git-lfs.github.com) extension on your machine.\n\n# License\n\nMIT © [nikersify](https://nikerino.com)\n","funding_links":[],"categories":["TypeScript","cli"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsify%2Fjay","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frsify%2Fjay","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frsify%2Fjay/lists"}