{"id":13485153,"url":"https://github.com/srackham/drake","last_synced_at":"2025-05-03T06:30:35.211Z","repository":{"id":45690767,"uuid":"243682001","full_name":"srackham/drake","owner":"srackham","description":"Drake is a make-like task runner for Deno.","archived":false,"fork":false,"pushed_at":"2024-02-06T21:25:11.000Z","size":404,"stargazers_count":101,"open_issues_count":5,"forks_count":7,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-28T00:14:33.604Z","etag":null,"topics":["deno","drake","jake","make","rake","typescript"],"latest_commit_sha":null,"homepage":null,"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/srackham.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","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}},"created_at":"2020-02-28T04:58:43.000Z","updated_at":"2025-04-07T19:18:43.000Z","dependencies_parsed_at":"2024-01-16T07:22:21.764Z","dependency_job_id":"8ad1a384-fd51-497d-adfe-ba478519cf4e","html_url":"https://github.com/srackham/drake","commit_stats":{"total_commits":517,"total_committers":2,"mean_commits":258.5,"dds":"0.0019342359767892114","last_synced_commit":"0a7e65dd1ff3d211fe6bb0ea9f9397cb62125950"},"previous_names":[],"tags_count":54,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srackham%2Fdrake","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srackham%2Fdrake/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srackham%2Fdrake/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/srackham%2Fdrake/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/srackham","download_url":"https://codeload.github.com/srackham/drake/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252154732,"owners_count":21702982,"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":["deno","drake","jake","make","rake","typescript"],"created_at":"2024-07-31T17:01:48.155Z","updated_at":"2025-05-03T06:30:34.904Z","avatar_url":"https://github.com/srackham.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"# Drake \u0026mdash; a task runner for Deno\n\n[Drake](https://github.com/srackham/drake) is a Make-like task runner for\n[Deno](https://deno.land/) inspired by\n[Make](https://en.wikipedia.org/wiki/Make_(software)),\n[Rake](https://github.com/ruby/rake) and [Jake](https://github.com/jakejs/jake).\n\n- Drakefiles (c.f. Makefiles) are Deno TypeScript modules.\n- Optional task prerequisites (dependencies).\n- File tasks and non-file tasks.\n- Drake API functions for defining, registering and running tasks.\n- Drake uses conditionally cached file properties to determine whether or not a\n  file task is out of date (see [Task Execution](#task-execution)). This\n  eliminates the dependency errors that programs such as `make` encounter when\n  file system _mtimes_ are used directly (see\n  [mtime comparison considered harmful](https://apenwarr.ca/log/20181113)).\n\n**Status**: Tested with Deno 1.40.3 running on Github CI the following\nplatforms: `ubuntu-latest`, `macos-latest`, `windows-latest`. See also the\n[changelog](CHANGELOG.md).\n\n## Drakefiles\n\nA drakefile is a TypeScript module that:\n\n1. Imports the Drake module.\n2. Defines and registers tasks.\n3. Runs tasks.\n\n### Example drakefile\n\n```typescript\nimport { desc, run, task } from \"https://deno.land/x/drake@v1.7.0/mod.ts\";\n\ndesc(\"Minimal Drake task\");\ntask(\"hello\", [], function () {\n  console.log(\"Hello World!\");\n});\n\nrun();\n```\n\nTo run the above example, copy and paste it into a file and run it with Deno.\nFor example:\n\n```\n$ deno run -A minimal-drakefile.ts hello\nhello started\nHello World!\nhello finished (0ms)\n```\n\nThe `desc()` and `task()` APIs define and register tasks. The `run()` API\nexecutes the tasks that were specified on the command-line along with their\nprerequisite tasks. `run()` is normally the last statement in the drakefile.\nTasks are executed in the correct dependency order.\n\n- Use the Drake `--help` option to list\n  [Drake command-line options](#drakefile-execution). For example:\n\n      deno run -A minimal-drakefile.ts --help\n\n- By convention, a project's drakefile is named `Drakefile.ts` and resides in\n  the project's root directory.\n\nHere are some of real-world drakefiles:\n\n- https://github.com/srackham/drake/blob/master/Drakefile.ts\n- https://github.com/srackham/rimu/blob/master/Drakefile.ts\n\n### Importing Drake\n\nA Drakefile uses Drake APIs imported from the Drake `mod.ts` module file. The\nmodule can be imported from:\n\n- [deno.land](https://deno.land/x/drake) (Deno's third party modules registry).\n  For example:\n\n      import { desc, run, task } from \"https://deno.land/x/drake@v1.7.0/mod.ts\";\n\n- [nest.land](https://nest.land/package/drake) (a blockchain based Deno modules\n  registry).\\\n  **NOTE**: Drake version numbers in `nest.land` URLs are not prefixed with a\n  'v' character:\n\n      import { desc, run, task } from \"https://x.nest.land/drake@1.7.0/mod.ts\";\n\nSome Drake APIs are useful in non-drakefiles, use `lib.ts` (not `mod.ts`) to\nimport them into non-drakefile modules.\n\n## Tasks\n\n### Task types\n\nThere are two types of task:\n\n**Normal task**: A _normal task_ executes unconditionally.\n\n**File task**: A _file task_ is only executed if it is out of date.\n\nTask types are distinguished by their names. _Normal task_ names can only\ncontain alphanumeric, underscore and hyphen characters and cannot start with a\nhyphen e.g. `test`, `hello-world`. _File task_ names are valid file paths. In\ncases of ambiguity a _file task_ name should be prefixed with a period and a\npath separator e.g. `./hello-world`.\n\n### Task properties\n\n**name**: A unique task name.\n\n**desc**: An optional task description that is set by the `desc()` API. Tasks\nwithout a description are not displayed by the `--list-tasks` command-line\noption (use the `-L` option to include hidden tasks and task prerequisites in\nthe tasks list).\n\n**prereqs**: An array of prerequisite task names i.e. the names of tasks to be\nrun prior to executing the task action function. Prerequisites can be normal\ntask names, file task names, file paths or globs (wildcards).\n\n**action**: An optional function that is run if the task is selected for\nexecution. The `action` function is bound to the parent task object i.e. the\nparent task properties are accessible inside the action function through the\n`this` object e.g. `this.prereqs` returns the task's prerequisite names array.\n\n### Task execution\n\nTask execution is ordered such that prerequisite tasks (direct and indirect) are\nexecuted prior to their parent task. The same task is never run twice.\n\n- The execution directory defaults to the current working directory (this can be\n  changed using the Drake `--directory` command-line option).\n\n- Task name and prerequisite file paths are normalized at task registration.\n\n- Prerequisite globs are expanded when the task is registered.\n\n- Prerequisites are resolved at the time the task is run.\n\n- All prerequisite files must exist by the time the task executes. An error is\n  thrown if any are missing.\n\n- A file task is considered to be out of date if:\n\n  - The target file does not exist.\n  - The target file or any of the prerequisite files have changed since the task\n    was last executed successfully.\n  - The Drake version or the operating system has changed since the task was\n    last executed successfully.\n\n- A file is considered to have changed if it's current modification time or size\n  no longer matches those recorded immediately after the task last executed\n  successfully.\n\n- Before exiting Drake saves the target and prerequisite file properties of the\n  tasks that successfully executed:\n\n  - File properties are saved to a file named `.drake.cache.json` in the\n    drakefile execution directory (this file path can be changed using the Drake\n    `--cache` command-line option).\n  - Task target and prerequisite file properties are recorded immediately after\n    successful task execution (if a task fails its properties are not updated).\n  - A cache file will not be created until at least one file task has\n    successfully executed.\n\n### Asynchronous task actions\n\nNormally you will want tasks to execute sequentially i.e. the next task should\nnot start until the current task has finished. To ensure this happens action\nfunctions that call asynchronous functions should:\n\n1. Be declared `async`.\n2. Call asynchronous functions with the `await` operator.\n\nFor example, the following task does not return until the shell command has\nsuccessfully executed:\n\n```typescript\ntask(\"shell\", [], async function () {\n  await sh(\"echo Hello World\");\n});\n```\n\nWithout the `await` operator `sh(\"echo Hello World\")` will return immediately\nand the action function will exit before the shell command has even started.\n\nOf course you are free to eschew `await` and use the promises returned by\nasynchronous functions in any way that makes sense.\n\n### Drakefile execution\n\nA drakefile is executed from the command-line. Use the `--help` option to view\nDrake command-line options and syntax. For example:\n\n```\n$ deno run -A Drakefile.ts --help\n\nNAME\n  drake - a make-like task runner for Deno.\n\nSYNOPSIS\n  deno run -A DRAKEFILE [OPTION|VARIABLE|TASK]...\n\nDESCRIPTION\n  The Drake TypeScript module provides functions for defining and executing\n  build TASKs on the Deno runtime.\n\n  A DRAKEFILE is a TypeScript module file containing Drake task definitions.\n  Drakefiles are run with the Deno 'run' command.\n\n  A Drake VARIABLE is a named string value e.g. 'vers=0.1.0'.  Variables are\n  accessed using the Drake 'env' API e.g. 'env(\"vers\").\n\nOPTIONS\n  -a, --always-make     Unconditionally execute tasks.\n  --cache FILE          Set Drake cache file path to FILE.\n  -d, --directory DIR   Change to directory DIR before running drakefile.\n  -D, --debug           Write debug information to stderr.\n  -h, --help            Display this help message.\n  -l, -L, --list-tasks  List tasks (-L for hidden tasks and prerequisites).\n  -n, --dry-run         Skip task execution.\n  -q, --quiet           Do not log drake messages to standard output.\n  -v, --verbose         Increase verbosity.\n  --version             Display the drake version.\n\nENVIRONMENT VARIABLES\n  NO_COLOR              Set to disable color (see https://no-color.org/).\n\nSEE ALSO\n  The Drake user guide: https://github.com/srackham/drake\n```\n\nThe `--directory` option sets the drakefile execution directory and defaults to\nthe current working directory. The `--directory` option allows a single\ndrakefile to be used to build multiple project directories.\n\nIf no command-line tasks are given the default task is run (specified by setting\nthe `env` API `\"--default-task\"` value).\n\nA Drake command-line variable is a named string value that is made available to\nthe drakefile. Variables are formatted like `\u003cname\u003e=\u003cvalue\u003e` e.g. `vers=0.1.0`.\nVariables are accessed within a drakefile using the `env` API e.g.\n`env(\"vers\")`. Variable names can only contain alphanumeric or underscore\ncharacters and must start with an alpha character.\n\n## Drake API\n\nThe Drake library module exports the following functions:\n\n### abort\n\n```typescript\nfunction abort(message: string): void;\n```\n\nWrite an error message to `stderr` and terminate execution.\n\n- If the `\"--abort-exits\"` environment option is `false` throw a `DrakeError`.\n- If the `\"--debug\"` environment option is `true` include the stack trace in the\n  error message.\n\n### debug\n\n```typescript\nfunction debug(title: string, message?: any): void;\n```\n\nWrite the `title` and `message` to stderr if it is a TTY and the `--debug`\ncommand-line option was specified or the `DRAKE_DEBUG` shell environment\nvariable is set.\n\n### desc\n\n```typescript\nfunction desc(description: string): void;\n```\n\nSet description of next registered task. If a task has no description then it\nwon't be displayed in the tasks list unless the `-L` option is used.\n\n### env\n\n```typescript\nfunction env(name?: string, value?: EnvValue): any;\n```\n\nThe Drake `env` API function gets and optionally sets the command-line options,\ntask names and variables.\n\nOptions are keyed by their long option name e.g. `env(\"--dry-run\")`.\nCommand-line flag options return a boolean; the `--cache` and `--directory`\noptions return a string.\n\nCommand-line variables are keyed by name. For example `vers=1.0.1` on the\ncommand-line sets the `vers` value to `\"1.0.1\"`.\n\nCommand-line tasks are stored in the `--tasks` string array.\n\nExamples:\n\n```typescript\nenv(\"--abort-exits\", false);\nenv(\"--default-task\", \"test\");\nconsole.log(`version: ${env(\"vers\")}`);\nif (!env(\"--quiet\")) console.log(message);\n```\n\n### execute\n\n```typescript\nasync function execute(...taskNames: string[]);\n```\n\nExecute task action functions. First the non-async actions are executed\nsynchronously then the async actions are exectuted asynchronously. Silently skip\ntasks that have no action function.\n\n### glob\n\n```typescript\nfunction glob(...patterns: string[]): string[];\n```\n\nReturn a sorted array of normalized file names matching the wildcard patterns.\n\n- Does not return directory names.\n- Valid glob patterns are those supported by Deno's `path` library.\n\nExample: `glob(\"tmp/*.ts\", \"lib/**/*.ts\", \"mod.ts\");`\n\n### log\n\n```typescript\nfunction log(message: string): void;\n```\n\nLog a message to stdout. Do not log the message if the `--quiet` command-line\noption is set.\n\n### makeDir\n\n```typescript\nfunction makeDir(dir: string): boolean;\n```\n\nCreate directory.\n\n- Missing parent directory paths are created.\n- Returns `true` if a new directory was created.\n- Returns `false` if the directory already exists.\n\n### quote\n\n```typescript\nfunction quote(values: string[], sep = \" \"): string;\n```\n\nReturn a string of double-quoted array values joined by a separator.\n\n- Double-quote characters are escaped with a backspace.\n- The separator defaults to a space character.\n\nExamples:\n\n- `quote([\"foo bar\", \"baz\"])` returns `\"foo bar\" \"baz\"`\n- `quote([\"foo bar\", \"baz\"], \",\")` returns `\"foo bar\",\"baz\"`\n- `quote([\"foo bar\", '\"baz\"'])` returns `\"foo bar\" \"\\\"baz\\\"\"`\n\n### readFile\n\n```typescript\nfunction readFile(filename: string): string;\n```\n\nRead the entire contents of a file synchronously to a UTF-8 string.\n\n### remove\n\n```typescript\nfunction remove(...patterns: string[]): void;\n```\n\nSynchronously delete files matching the wildcard glob patterns.\n\n- Does not remove directories.\n- Valid glob patterns are those supported by Deno's `path` library.\n\nExample: `remove(\"tmp/*.ts\", \"lib/*.ts\", \"mod.ts\");`\n\n### run\n\n```typescript\nasync function run(...taskNames: string[]);\n```\n\nExecute named tasks along with their prerequisite tasks (direct and indirect).\nIf no task names are specified then the command-line tasks are run. If no\ncommand-line tasks were specified the default task is run (specified by setting\nthe `env` API `\"--default-task\"` value).\n\nTask execution is ordered such that prerequisite tasks are executed prior to\ntheir parent task. The same task is never run twice.\n\n### sh\n\n```typescript\nasync function sh(commands: string | string[], opts: ShOpts = {});\n```\n\nExecute commands in the command shell.\n\n- If `commands` is a string execute it.\n- If `commands` is an array of commands execute them asynchronously.\n- If any command fails throw an error.\n- If `opts.stdout` or `opts.stderr` is set to `\"null\"` then the respective\n  outputs are suppressed.\n- `opts.cwd` sets the shell current working directory (defaults to the parent\n  process working directory).\n- The `opts.env` mapping passes additional environment variables to the shell.\n\nOn MS Windows run `PowerShell.exe -Command \u003ccmd\u003e`. On other platforms run\n`$SHELL -c \u003ccmd\u003e` (if `SHELL` is not defined use `/bin/bash`).\n\nExamples:\n\n```typescript\nawait sh(\"echo Hello World\");\nawait sh([\"echo Hello 1\", \"echo Hello 2\", \"echo Hello 3\"]);\nawait sh(\"echo Hello World\", { stdout: \"null\" });\n```\n\n### shCapture\n\n```typescript\nasync function shCapture(\n  command: string,\n  opts: ShCaptureOpts = {},\n): Promise\u003cShOutput\u003e;\n```\n\nExecute `command` in the command shell and return a promise for\n`{code, output, error}` (the exit code, the stdout output and the stderr\noutput).\n\n- If the `opts.input` string has been assigned then it is piped to the shell\n  `stdin`.\n- `opts.cwd` sets the shell current working directory (defaults to the parent\n  process working directory).\n- The `opts.env` mapping passes additional environment variables to the shell.\n- `opts.stdout` and `opts.stderr` have `Deno.RunOptions` semantics.\n  `opts.stdout` defaults to `\"piped\"`. `opts.stderr` defaults to `\"inherit\"` (to\n  capture stderr set `opts.stderr` to `\"piped\"`).\n\nExamples:\n\n```typescript\nconst { code, output } = await shCapture(\"echo Hello\");\nconst { code, output, error } = await shCapture(\"mkdir tmpdir\", {\n  stderr: \"piped\",\n});\nconst vers = (await shCapture(\"make version\")).output.trim();\n```\n\n### stat\n\n```typescript\nfunction stat(path: string): Deno.FileInfo | null;\n```\n\nReturns `path` [file information](https://doc.deno.land/deno/stable/~/Deno.FileInfo)\nor `null` if the file does not exist.\n\nExamples:\n\n```typescript\nif (stat(path)) { /* `path` exists */ }\nif (stat(path)?.isFile) { /* `path` is a regular file */ }\nconst timeStamp  = stat(path)?.mtime; // Date | null | undefined\nconst fileSize  = stat(path)?.size;   // number | undefined\n```\n\n### task\n\n```typescript\nfunction task(name: string, prereqs?: string[], action?: Action): Task;\n```\n\nCreate and register a task. Returns the task object.\n\n- `name` is a unique task name.\n- `prereqs` is an array of prerequisite task names. Prerequisites can be normal\n  task names, file task names, file paths or globs (wildcards).\n- `action` is an optional function that is run if the task is selected for\n  execution (`type Action = (this: Task) =\u003e any;`).\n- To fetch an existing task omit both the `prereqs` and `action` parameters.\n\n### writeFile\n\n```typescript\nfunction writeFile(filename: string, text: string): boolean;\n```\n\nWrite text to a file synchronously. If the file exists it will be overwritten.\nReturns `true` if a new file was created; returns `false` if the file already\nexists.\n\n### updateFile\n\n```typescript\nfunction updateFile(filename: string, find: RegExp, replace: string): boolean;\n```\n\nFind and replace in text file synchronously. If the file contents is unchanged\nreturn `false`. If the contents have changed update the file and return `true`.\n\n### vers\n\n```typescript\nfunction vers(): string;\n```\n\nReturns the Drake version number string.\n\n## Tips for using Drake\n\n- A shell alias shortcut can be set to run the default drakefile:\n\n      alias drake=\"deno run -A Drakefile.ts\"\n\n- Use shell quoting and escapes to pass Drake command-line variable values that\n  contain spaces or special characters e.g. `\"title=Foo \u0026 bar\"`.\n\n- Don't forget to use `await` when calling `async` functions.\n\n- Task path name prerequisites can be glob wildcards.\n\n- Task name and prerequisite file paths can refer to any file type (not just\n  regular files).\n\n- The Drake `sh` API can be used to run multiple shell commands asynchronously.\n  The following example starts two shell commands then waits for both to finish\n  before continuing:\n\n      await sh([\"echo foo\", \"echo bar\"]);\n\n- The Drake `sh` API can be used to run multi-line template string scripts e.g.\n\n  ```sh\n  await sh(`set -e  # Exit immediately on error.\n      echo Hello World\n      if [ \"$EUID\" -eq 0 ]; then\n          echo \"Running as root\"\n      else\n          echo \"Running as $USER\"\n      fi\n      ls\n      wc Drakefile.ts`);\n  ```\n\n- Tasks can be created dynamically at runtime. The following example is from\n  [examples/dynamic-tasks.ts](https://github.com/srackham/drake/blob/master/examples/dynamic-tasks.ts):\n\n  ```typescript\n  for (const prereq of glob(\"*.md\")) {\n    const target = `${path.basename(prereq, \".md\")}.html`;\n    task(target, [prereq], async function () {\n      await sh(`markdown \"${prereq}\" \u003e \"${target}\"`);\n    });\n  }\n  ```\n\n- Task actions can be run asynchronously using the `execute` API. The following\n  example is from\n  [examples/dynamic-tasks.ts](https://github.com/srackham/drake/blob/master/examples/dynamic-tasks.ts):\n\n  ```typescript\n  await execute(...tasks); // 'tasks' is a list of tasks with asynchronous action functions.\n  ```\n\n- When running multiple tasks asynchronously, for example using the `execute`\n  API, take care that there are no mutual dependencies that could cause race\n  conditions.\n\n- More meaningful file task names can be created with a dummy normal task. In\n  the following example the `build-docs` task executes the `./docs/index.html`\n  task. The `./docs/index.html` task will be hidden from the `--list-tasks`\n  command because it has not been assigned a description.\n\n  ```typescript\n  desc(\"Build documents\");\n  task(\"build-docs\", [\"./docs/index.html\"]);\n  task(\"./docs/index.html\", [...]) {\n    ...\n  });\n  ```\n\n- When executing in a drakefile, Drake functions manifest errors by printing an\n  error message and exiting with a non-zero exit code. You can change this\n  behavior so that errors throw a `DrakeError` exception by setting\n  `env(\"--abort-exits\", false)`. In non-drakefiles errors throw a `DrakeError`\n  exception by default.\n\n- Selected sections of code can be \"debugged\" by bracketing with\n  `env(\"--debug\",true)` and `env(\"--debug\",false)` statements.\n\n- Drake API debug messages will be emitted if the `DRAKE_DEBUG` shell\n  environment variable is set. This can be useful in conjunction with the\n  `debug` API in non-drakefiles (in lieu of the Drake `--debug` command-line\n  option).\n\n- The Deno `run` command automatically compiles updated source and writes\n  compilation messages to `stderr`. This can interfere with tests that capture\n  Deno `run` command outputs. Use the Deno `--quiet` option to eliminate this\n  problem.\n\n- In addition to the command-line `--cache FILE` option you can also set a\n  custom cache file path from within a Drakefile before calling the `run` API.\n  For example:\n\n  ```typescript\n  env(\"--cache\", path.join(env(\"--directory\"), \"my-cache.json\"));\n  ```\n\n- Set the `--cache` option value to a blank string to restore the default cache\n  file path:\n\n  ```typescript\n  env(\"--cache\", \"\");\n  ```\n\n- Wildcard `VARIABLE` arguments should be quoted to ensure they aren't expanded\n  by the shell. For example:\n\n      mdfiles=$HOME'/docs/*.md'     # Correct\n      mdfiles=~/docs/*.md           # Incorrect (the zsh shell attempts expansion)\n\n- Regarding Drake `sh` and `shCapture` APIs: To execute them using a different\n  shell (to the login shell) the shell needs to be explicitly specified. For\n  example:\n\n      sh('/usr/bin/bash -c ls')                     // Run ls in the bash shell\n      SHELL=/usr/bin/bash deno run -A Drakefile.ts  # Use the bash shell throughout\n\n  The `SHELL` shell environment variable reflects the login shell specified in\n  the password database (`/etc/passwd`) and not the shell that you are currently\n  using.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrackham%2Fdrake","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsrackham%2Fdrake","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsrackham%2Fdrake/lists"}