{"id":13447807,"url":"https://github.com/Cykelero/tasklemon","last_synced_at":"2025-03-22T01:31:24.582Z","repository":{"id":51312599,"uuid":"151884795","full_name":"Cykelero/tasklemon","owner":"Cykelero","description":"Painless automation in JavaScript.","archived":false,"fork":false,"pushed_at":"2023-10-19T10:52:45.000Z","size":1302,"stargazers_count":80,"open_issues_count":2,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-10-20T00:25:52.931Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://cykelero.github.io/tasklemon/api/","language":"JavaScript","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/Cykelero.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}},"created_at":"2018-10-06T21:53:56.000Z","updated_at":"2024-03-28T08:56:45.000Z","dependencies_parsed_at":"2024-01-19T10:11:56.994Z","dependency_job_id":null,"html_url":"https://github.com/Cykelero/tasklemon","commit_stats":{"total_commits":370,"total_committers":3,"mean_commits":"123.33333333333333","dds":0.08378378378378382,"last_synced_commit":"cb061efebb4723e08ec912d03ad75c2b53683ed2"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cykelero%2Ftasklemon","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cykelero%2Ftasklemon/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cykelero%2Ftasklemon/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Cykelero%2Ftasklemon/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Cykelero","download_url":"https://codeload.github.com/Cykelero/tasklemon/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221779956,"owners_count":16879036,"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":[],"created_at":"2024-07-31T05:01:27.303Z","updated_at":"2024-10-28T11:30:50.501Z","avatar_url":"https://github.com/Cykelero.png","language":"JavaScript","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"readme":"# \u003cimg alt=\"Tasklemon\" src=\"docs/readme-logo.png\" width=254 height=42\u003e\n\u003csup\u003e🛠 \u003c/sup\u003e[\u003csup\u003eUsage\u003c/sup\u003e](#-usage)\u003csup\u003e   📚 \u003c/sup\u003e[\u003csup\u003eLearning\u003c/sup\u003e](#-learning)\u003csup\u003e   ☀️ \u003c/sup\u003e[\u003csup\u003eSamples\u003c/sup\u003e](#%EF%B8%8F-samples)\u003csup\u003e   💬 \u003c/sup\u003e[\u003csup\u003eCaveats\u003c/sup\u003e](#-caveats)\u003csup\u003e   👩🏿‍💻 \u003c/sup\u003e[\u003csup\u003eContributing\u003c/sup\u003e](#-contributing)\u003csup\u003e   ❤️ \u003c/sup\u003e[\u003csup\u003eThanks\u003c/sup\u003e](#%EF%B8%8F-thanks)\u003csup\u003e\u003c/sup\u003e\n\nWrite scripts that manipulate files, make network requests, get user input, all with a delightfully clear API and exceptional documentation. If you want to script things but don't want to use Bash, Tasklemon is what you've been wishing for all along! ✨\n\nHere's a simple script, written in both Tasklemon and in vanilla Node:\n\n\u003ctable\u003e\n\t\u003cthead\u003e\n\t\t\u003cth\u003e\n\t\t\t🍋 Tasklemon\n\t\t\u003c/th\u003e\n\t\t\u003cth\u003e\n\t\t\t✳️ Node.js\n\t\t\u003c/th\u003e\n\t\u003c/thead\u003e\n\t\u003ctr\u003e\n\t\t\u003ctd\u003e\n\u003cpre lang=\"javascript\"\u003e\nhome.children.forEach(child =\u003e {\n    if (child.extension === 'tmp') child.delete();\n});\n \n \n \n \n \n \n \n \n\u003c/pre\u003e\n\t\t\u003c/td\u003e\n\t\t\u003ctd\u003e\n\u003cpre lang=\"javascript\"\u003e\nconst fs = require('fs');\nconst os = require('os');\nconst path = require('path');\n \nconst homePath = os.homedir();\nfs.readdirSync(homePath).forEach(childName =\u003e {\n    if (path.parse(childName).ext === '.tmp') {\n        const absolutePath = path.join(homePath, childName);\n        fs.unlinkSync(absolutePath);\n    }\n});\n\u003c/pre\u003e\n\t\t\u003c/td\u003e\n\t\u003c/tr\u003e\n\u003c/table\u003e\n\n\nAnd with Tasklemon installed, you can just save this code into a file (say, `clean.js`) and run it in a single command; no imports, no preprocessing:\n\n```bash\n$ lemon clean.js\n```\n\n(you can also give the appropriate permissions to your scripts to make them directly executable, if you want; see below in [Shebang and runtime pinning](#shebang-and-runtime-pinning))\n\n## 🛠 Usage\n\n### Installing Tasklemon\n\nWith [Node.js](https://nodejs.org/) present, install Tasklemon globally by running `npm install -g tasklemon`. This will make it available as `lemon` on the command\u0026nbsp;line.\n\nTasklemon supports macOS, Linux, and (with a few caveats) Windows.\n\n### Writing and running a script\n\nTo use Tasklemon, write a script and save it into a file, then execute it by running `lemon your-script.js`.  \nAt runtime, Tasklemon exposes its entry points to your script, so you don't have to import anything. It also wraps all your code in an `async` function call, so that you can `await` promises wherever.  \nTo get a feel of what's possible, have a look at [the examples](#%EF%B8%8F-samples) below.\n\n### Debugging a script\n\nNode.js supports debugging through V8's inspector protocol. To debug a Tasklemon script:\n\n1. Run the script with the `--inspect-brk` flag specified.  \nMake sure the flag is before the script's name, so that it is consumed by Tasklemon itself: `lemon --inspect-brk your-script.js`\n2. Open [a compatible client](https://nodejs.org/en/docs/guides/debugging-getting-started/#inspector-clients), such as Google Chrome's DevTools, or Visual Studio Code, and connect to the Node process.  \nFor instance, in Google Chrome, this means navigating to `chrome://inspect`, then clicking “inspect” under “Remote Target”.\n\n### Shebang and runtime pinning\n\nWhen you run a script for the first time, Tasklemon will insert two lines at the top:\n\n- A shebang, which makes the script executable directly, once it has the proper permissions.  \n\tApply the permissions using `chmod u+x your-script.js`, and you will be able to execute the script by running `./your-script.js` directly.\n- A version header, with the current version number of Tasklemon: this makes sure your script can be properly executed by future versions of the runtime.\n\n## 📚 Learning\n\nAfter you've [installed Tasklemon](#-usage), I recommend you look at [the examples](#%EF%B8%8F-samples) below. They'll give you a good idea of the main features you'll want to use.\n\nAfter that, you can use the [API reference](http://cykelero.github.io/tasklemon/api/) to find what you need. The reference is approachable, straightforward, and replete with clear examples. Here's a sample of what it looks like:\n\n\u003ca href=\"https://cykelero.github.io/tasklemon/api/latest/File.html#appendLine\"\u003e\u003cimg src=\"docs/readme-api-reference-screenshot.png\" alt width=838\u003e\u003c/a\u003e\n\n## ☀️ Samples\n\n### Write and read files\n\nAdd some text to a log file in the current working directory:\n\n```js\nhere.file('events.log').appendLine('Operation complete.');\n```\n\nRead JSON from a file:\n\n```js\nconst packageInfo = here.file('package.json').getContentAsJSON();\ncli.tell(`The current project is ${packageInfo.name}.`);\n```\n\nUse an absolute path:\n\n```js\nconst directXLog = File('C:/Windows/DirectX.log'); // on Windows, drive letter can be specified\nconst lastLogDate = directXLog.dateModified;\n\ncli.tell('The last DirectX install happened ' + format.date.relative(lastLogDate) + '.');\n```\n\n### Declare script parameters, get the values\n\n```js\ncli.accept({\n    username: ['--name', String, 'Name of user to add'],\n    isAdmin: ['-a', Boolean, 'Make user an admin']\n});\n\nconsole.log(cli.args); // will be {username: 'Rose', isAdmin: true}\n```\n\nThen, run the script:\n\n```bash\n$ lemon adduser.js -a --name=Rose\n```\n\n### Format data for display\n\nDisplay a relative timestamp:\n\n```js\nconst logDate = here.file('log.txt').dateModified;\ncli.tell(format.date.relative(logDate)); // “3 minutes ago”\n```\n\nDisplay a number and pluralize its unit:\n\n```js\ncli.tell(format.number(1, 'carrot')); // “1.00 carrot”\ncli.tell(format.number(4528.5, 'carrot')); // “4,528.50 carrots”\n```\n\n### Get JSON from a URL\n\nYou can use `await` at the top level of your scripts.\n\n```js\nconst tasklemonNpmDetails = await net.getJSON('https://registry.npmjs.org/tasklemon');\nconst lastReleaseDate = tasklemonNpmDetails.time.modified;\n\ncli.tell('Last Tasklemon release was ' + format.date.relative(lastReleaseDate) + '.');\n```\n\n### Use the `dedupe` npm package\n\nThere is no need to ever install, or even import packages prior to using them.\n\n```js\nconst friendNames = await cli.ask('What are your friends called?', Array);\nconst uniqueFriendNames = npm.dedupe(friendNames);\n\ncli.tell('Total count of unique friend names: ' + uniqueFriendNames.length);\n```\n\n## 💬 Caveats\n\nI really want Tasklemon to be terrific, but here are a few ways in which it's not.\n\n- By design, file operations are synchronous—just like in bash scripting, for example. That's great for usability, but you're not going to write concurrent server stuff this way.\n- Symlinks aren't very well-supported yet. Just traversing them should be fine, but directly manipulating them will be weird.\n- On Windows, a few features are missing, such as permission manipulation.\n\n## 👩🏿‍💻 Contributing\n\nWant to help build Tasklemon? That'd be lovely!  \nThe simplest way to help is give feedback on what it's like to use Tasklemon. All comments are greatly appreciated! You can [open an issue](https://github.com/cykelero/tasklemon/issues/new) on GitHub, or maybe just drop me a note [on Mastodon](https://mas.to/@Cykelero).\n\nTo go one step further, you can directly work on the code.  \nClone Tasklemon from Github and run `npm install`. You can then:\n\n- **try out your version of Tasklemon** by running `source/tasklemon.js some-script.js`\n- **run the tests** using `npm run test` (or `npm run watch:test` for automatic runs)\n- **build the api docs** using `npm run build-docs` (or `npm run watch:build-docs` for automatic builds)\n\nOnce you've built something nice, [submit it as a pull request](https://github.com/cykelero/tasklemon/compare) to make it public.\n\n## ❤️ Thanks\n\nThanks to [Fabien Bérini](https://fabien-berini.fr), for his help with making the unix-y parts reasonably sane :)  \nThanks to [Benoît Zugmeyer](https://github.com/BenoitZugmeyer), for his input on API design and npm support :)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCykelero%2Ftasklemon","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FCykelero%2Ftasklemon","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FCykelero%2Ftasklemon/lists"}