{"id":41361953,"url":"https://github.com/ecowden/pluto-path","last_synced_at":"2026-01-23T07:49:47.934Z","repository":{"id":30669588,"uuid":"34225371","full_name":"ecowden/pluto-path","owner":"ecowden","description":"Create a Pluto dependency injection module from files in a path or paths","archived":false,"fork":false,"pushed_at":"2023-03-13T18:14:04.000Z","size":451,"stargazers_count":6,"open_issues_count":7,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-20T13:27:09.522Z","etag":null,"topics":["dependency-injection","javascript","javascript-dependency-injection","pluto","testing"],"latest_commit_sha":null,"homepage":null,"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/ecowden.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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}},"created_at":"2015-04-19T21:35:12.000Z","updated_at":"2023-01-31T16:37:33.000Z","dependencies_parsed_at":"2024-10-06T12:33:21.072Z","dependency_job_id":"5c3e688c-a1a6-44ea-9602-5fd8cbeb9ab6","html_url":"https://github.com/ecowden/pluto-path","commit_stats":{"total_commits":29,"total_committers":2,"mean_commits":14.5,"dds":"0.10344827586206895","last_synced_commit":"efcdd1a6f98d3b90d2c791220e2579160d0cdc1f"},"previous_names":[],"tags_count":2,"template":false,"template_full_name":null,"purl":"pkg:github/ecowden/pluto-path","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecowden%2Fpluto-path","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecowden%2Fpluto-path/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecowden%2Fpluto-path/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecowden%2Fpluto-path/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ecowden","download_url":"https://codeload.github.com/ecowden/pluto-path/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ecowden%2Fpluto-path/sbom","scorecard":{"id":365778,"data":{"date":"2025-08-11","repo":{"name":"github.com/ecowden/pluto-path","commit":"efcdd1a6f98d3b90d2c791220e2579160d0cdc1f"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2,"checks":[{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 1/29 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Branch-Protection","score":-1,"reason":"internal error: error during branchesHandler.setup: internal error: githubv4.Query: Resource not accessible by integration","details":null,"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 7 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Vulnerabilities","score":0,"reason":"55 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: GHSA-v88g-cgmw-v5xw","Warn: Project is vulnerable to: GHSA-67hx-6x53-jw92","Warn: Project is vulnerable to: GHSA-v6h2-p8h4-qcjw","Warn: Project is vulnerable to: GHSA-cwfw-4gq5-mrqx","Warn: Project is vulnerable to: GHSA-g95f-p29q-9xw4","Warn: Project is vulnerable to: GHSA-grv7-fg5c-xmjg","Warn: Project is vulnerable to: GHSA-3xgq-45jj-v275","Warn: Project is vulnerable to: GHSA-9vvw-cc9w-f27h","Warn: Project is vulnerable to: GHSA-gxpj-cx7g-858c","Warn: Project is vulnerable to: GHSA-w573-4hg7-7wgq","Warn: Project is vulnerable to: GHSA-ff7x-qrg7-qggm","Warn: Project is vulnerable to: GHSA-4gmj-3p3h-gm8h","Warn: Project is vulnerable to: GHSA-fjxv-7rqg-78g4","Warn: Project is vulnerable to: GHSA-pfrx-2q88-qq97","Warn: Project is vulnerable to: GHSA-q42p-pg8m-cqh6","Warn: Project is vulnerable to: GHSA-w457-6q6x-cgp9","Warn: Project is vulnerable to: GHSA-62gr-4qp9-h98f","Warn: Project is vulnerable to: GHSA-f52g-6jhx-586p","Warn: Project is vulnerable to: GHSA-2cf5-4w76-r9qv","Warn: Project is vulnerable to: GHSA-3cqr-58rm-57f8","Warn: Project is vulnerable to: GHSA-g9r4-xpmj-mj65","Warn: Project is vulnerable to: GHSA-q2c6-c6pm-g3gh","Warn: Project is vulnerable to: GHSA-765h-qjxv-5f44","Warn: Project is vulnerable to: GHSA-f2jv-r9rf-7988","Warn: Project is vulnerable to: GHSA-44pw-h2cw-w3vq","Warn: Project is vulnerable to: GHSA-jp4x-w63m-7wgm","Warn: Project is vulnerable to: GHSA-c429-5p7v-vgjp","Warn: Project is vulnerable to: GHSA-43f8-2h32-f4cj","Warn: Project is vulnerable to: GHSA-2pr6-76vf-7546","Warn: Project is vulnerable to: GHSA-8j8c-7jfh-h6hx","Warn: Project is vulnerable to: GHSA-9c47-m6qq-7p4h","Warn: Project is vulnerable to: GHSA-fvqr-27wr-82fm","Warn: Project is vulnerable to: GHSA-4xc9-xhrj-v574","Warn: Project is vulnerable to: GHSA-x5rq-j2xg-h7qm","Warn: Project is vulnerable to: GHSA-jf85-cpcp-j695","Warn: Project is vulnerable to: GHSA-p6mc-m468-83gw","Warn: Project is vulnerable to: GHSA-29mw-wpgm-hmr9","Warn: Project is vulnerable to: GHSA-35jh-r3h4-6jhm","Warn: Project is vulnerable to: GHSA-952p-6rrq-rcjv","Warn: Project is vulnerable to: GHSA-f8q6-p94x-37v3","Warn: Project is vulnerable to: GHSA-vh95-rmgr-6w4m","Warn: Project is vulnerable to: GHSA-xvch-5gv4-984h","Warn: Project is vulnerable to: GHSA-w9mr-4mfr-499f","Warn: Project is vulnerable to: GHSA-hj48-42vr-x3v9","Warn: Project is vulnerable to: GHSA-6g33-f262-xjp4","Warn: Project is vulnerable to: GHSA-p8p7-x288-28g6","Warn: Project is vulnerable to: GHSA-c2qf-rxjj-qqgw","Warn: Project is vulnerable to: GHSA-4rq4-32rv-6wp6","Warn: Project is vulnerable to: GHSA-64g7-mvw6-v9qj","Warn: Project is vulnerable to: GHSA-72xf-g2v4-qvf3","Warn: Project is vulnerable to: GHSA-7p7h-4mm5-852v","Warn: Project is vulnerable to: GHSA-xc7v-wxcw-j472","Warn: Project is vulnerable to: GHSA-j8xg-fqg3-53r7","Warn: Project is vulnerable to: GHSA-c4w7-xm78-47vh","Warn: Project is vulnerable to: GHSA-p9pc-299p-vxgp"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}}]},"last_synced_at":"2025-08-18T11:48:36.420Z","repository_id":30669588,"created_at":"2025-08-18T11:48:36.420Z","updated_at":"2025-08-18T11:48:36.420Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28683997,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T05:48:07.525Z","status":"ssl_error","status_checked_at":"2026-01-23T05:48:07.129Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":["dependency-injection","javascript","javascript-dependency-injection","pluto","testing"],"created_at":"2026-01-23T07:49:47.825Z","updated_at":"2026-01-23T07:49:47.923Z","avatar_url":"https://github.com/ecowden.png","language":"JavaScript","readme":"# pluto-path\n\nCreate and bootstrap an app from files in a path or paths using the [Pluto](https://github.com/ecowden/pluto.js) dependency injection package.\n\n| Branch        | Status        |\n| ------------- |:------------- |\n| Master        | [![Build Status](https://travis-ci.org/ecowden/pluto-path.png?branch=master)](https://travis-ci.org/ecowden/pluto-path) [![Coverage Status](https://coveralls.io/repos/github/ecowden/pluto-path/badge.svg?branch=master)](https://coveralls.io/github/ecowden/pluto-path?branch=master) [![NSP Status](https://nodesecurity.io/orgs/ecowden/projects/5cff7ae1-a34a-49f7-bf18-f2b816180930/badge)](https://nodesecurity.io/orgs/ecowden/projects/5cff7ae1-a34a-49f7-bf18-f2b816180930) |\n| All           | [![Build Status](https://travis-ci.org/ecowden/pluto-path.png)](https://travis-ci.org/ecowden/pluto-path) |\n\n**Why?**\n\nThis package aims to solve two problems:\n\n1. **Bootstrapping**. There are many example Express/Hapi/etc. applications where a chain of `index.js` files require a bunch of routes and other bits. I find this annoying. When I create a new part of my app, I want it to Just Work without extra boilerplate.\n1. **Testing**. The key to good testing isn't writing tests: it's writing good, testable code. When unit testing, in particular, we want to test one thing at a time. But what about when our one thing uses other things? By injecting those other things, often called _collaborators_, we can pass mocks or fakes to our code under test.\n\n## Usage\n\n### Simplified Options\n\n```js\n'use strict'\n\nconst path = require('path')\nconst plutoPath = require('pluto-path')\n\nplutoPath(path.join(__dirname, 'my-directory')) // you can pass a single search path or array of them\n  .then(function (app) {\n    // `app` holds a Map from filenames to their components.\n    // It's created by calling pluto's `bootstrap(...)` function.\n    // Use it if you want to do interact with components after they're\n    // wired together.\n  })\n  // Don't forget about errors!\n  .catch(err =\u003e {\n    console.error(err.stack) // eslint-disable-line no-console\n    process.exitCode = 1\n  })\n```\n\n### Binding Types\n\nThis module will instantiate components in different ways:\n\n| Binding          | Used When | Meaning |\n| ---------------- | --------- | ------- |\n| Factory Function | File exports a `function`, and starts with a lower-case letter. | The module's export will be called as a regular function, and the result will be bound to the file name. |\n| Constructor      | File exports a `function`, and starts with a capital letter | The module's export will be bound as a constructor with `new`, and the result will be bound to the file name. |\n| Instance         | File does not export a `function` | The module's export will be used as-is. |\n\nSee the [Pluto Documentation](https://github.com/ecowden/pluto.js) for more details.\n\n### Full Options\n\nSince the default include and exclude options work for most projects and the path is often the only meaningful property, you can pass a `string` or `array` of strings for the path property instead of a full options object, as above. Alternately\n\n| Property | Description |\n| -------- | ----------- |\n| path     | _string_ or _array_ of absolute paths to search for files. Default: `.`. |\n| include  | _string_ or _array_ of [minimatch](https://github.com/isaacs/minimatch) patterns. A file in the path(s) that match at least one pattern will be `require(...)`'d unless the file also matches an exclusion pattern. Default: `['**/*.js', '**/*.json']`.|\n| exclude  | _string_ or _array_ of [minimatch](https://github.com/isaacs/minimatch) patterns. Files in the path(s) that match at least one pattern will be excluded. Default: `['**/*Spec.js']`. |\n| extraBindings | A function given the standard pluto `bind` object. Use when\nyou'd like to specify additional options beyond what pluto-path can find on the\nfilesystem. |\n\n```js\n'use strict'\n\nconst path = require('path')\nconst plutoPath = require('pluto-path')\n\nplutoPath({\n    path: path.join(__dirname, 'my-directory'),\n    include: ['**/*.js', '**/*.json'],\n    exclude: ['**/*Spec.js'],\n    extraBindings: (bind) =\u003e {\n      bind('meaningOfLife').toInstance(42)\n    }\n  })\n  .then(function (app) {\n    // `app` holds a Map from filenames to their components.\n    // It's created by calling pluto's `bootstrap(...)` function.\n  })\n  // Don't forget about errors!\n  .catch(err =\u003e {\n    console.error(err.stack) // eslint-disable-line no-console\n    process.exitCode = 1\n  })\n```\n\n## Humble Opinionated Recommendations\n\n### Project Organization\n\nThere's usually two different kinds of files in an app:\n\n1. Long-lived components, like route handlers and server configuration. These need to be run exactly once and become a part of your app. Place these in an `app` folder.\n1. Utilities and such that don't have a life of their own, and which you don't want subject to dependency injection. Place these in a `lib` folder.\n\n```\n/\n  /app        Bootstrap long-lived components\n  /lib        Utilities and such you don't want to dependency-inject\n  index.js    `main` file with initial bootstrapping\n```\n\nInstruct `pluto-path` to bootstrap the `app` folder and leave the `lib` folder alone. If you're not doing any fancy startup stuff and you're fine with other defaults, your `index.js` file might look like:\n\n```js\n'use strict'\n\nconst path = require('path')\nconst plutoPath = require('pluto-path')\n\nplutoPath(path.join(__dirname, 'app'))\n  // Don't forget about errors!\n  .catch(err =\u003e {\n    console.error(err.stack) // eslint-disable-line no-console\n    process.exitCode = 1\n  })\n```\n\n### Tests\n\nYou might notice that there's not test path, event though one of the main motivations for dependency injection is testability. Rather than use a separate `test` tree, I like to put my tests right next to the thing they're testing, with a `Spec` suffix, like:\n\n```\n/\n  /app\n    myThing.js\n    myThingSpec.js\n```\n\nI am highly influenced by Uncle Bob's [Principles of Object Oriented Design](http://butunclebob.com/ArticleS.UncleBob.PrinciplesOfOod). In this case:\n\n* **Common Closure Principle**: Things that change together should be packaged together.\n\nWhen it comes to unit testing, a test and the thing it tests unsurprisingly tend to change together, so I like to put them next to each other. Stepping back, this makes logical sense, too: why hunt deep down through two separate directory trees just to get to the two files you want to change? Putting tests next to the code they test reduces friction when writing tests and just makes life easier.\n\nThe default arguments to `pluto-path` assume this kind of organization. If you want to do something else, change the `include` and `exclude` options as you see fit.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fecowden%2Fpluto-path","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fecowden%2Fpluto-path","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fecowden%2Fpluto-path/lists"}