attribution-artisan
v0.1.2
Published
Generate THIRD_PARTY_NOTICES.md and JSON from installed dependencies. Zero-dep CLI + GitHub Action.
Maintainers
Readme
Attribution Artisan
Zero‑dep CLI + GitHub Action that generates THIRD_PARTY_NOTICES.md from your installed dependencies and (optionally) embeds license texts for MIT/BSD, etc. Pairs perfectly with License Lens.
Table of contents
- Overview
- Quick start
- Usage
- Configuration
- Output format
- CI (GitHub Actions)
- Notes & limitations
- Security
- Contributing
- License
- Roadmap
- FAQ
Overview
Attribution Artisan walks node_modules/ (including nested deps), collects each dependency’s name@version, license, and homepage/repository, then writes a clean THIRD_PARTY_NOTICES.md. You control whether to embed full license texts for select SPDX identifiers (e.g., MIT, BSD-2-Clause, BSD-3-Clause).
- Zero dependencies; Node ≥ 18
- No registry calls — reads local
package.jsonand license files - Optional JSON output for auditing
- Works with npm, pnpm, yarn
Quick start
# ensure you have node_modules (in CI: npm ci / pnpm i / yarn install)
npx attribution-artisan generateCreate a config for policy:
cat > attribution-artisan.config.json <<'JSON'
{
"includeTexts": ["MIT","BSD-2-Clause","BSD-3-Clause"],
"exclude": ["@types/*"],
"sort": "name" // or "license"
}
JSON
# generate
npx attribution-artisan generateUsage
# Markdown (default: THIRD_PARTY_NOTICES.md)
npx attribution-artisan generate
# JSON only
npx attribution-artisan generate --format json
# both Markdown + JSON
npx attribution-artisan generate --format both
# custom output file
npx attribution-artisan generate --out NOTICE.md
# override includeTexts via CLI
npx attribution-artisan generate --include-texts MIT,BSD-3-ClauseExit codes
0— success2— runtime error (e.g., nonode_modules/)
Configuration
Create attribution-artisan.config.json at repo root (all optional):
{
"includeTexts": ["MIT","BSD-2-Clause","BSD-3-Clause"],
"exclude": ["@types/*"],
"sort": "name"
}includeTexts— SPDX ids whose license texts should be embedded (if found in the package or templates).exclude— glob patterns on package name to skip (supports*and scopes like@types/*).sort—name(default) orlicense.
Output format
Markdown (THIRD_PARTY_NOTICES.md)
- Intro block with timestamp & policy
- Per‑license sections: packages listed as
- name@version — homepage/repo - Optional appended license texts for
includeTexts
JSON (third_party_notices.json)
{
"generatedAt": "2025-08-14T12:00:00.000Z",
"packages": [
{ "name": "left-pad", "version": "1.3.0", "license": "MIT", "homepage": "https://...", "repository": "https://..." }
],
"embeddedTexts": { "MIT": "..." }
}CI (GitHub Actions)
Minimal check
name: attribution-artisan
on: [push, pull_request]
jobs:
generate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20 }
- run: npm ci
- run: npx attribution-artisan generateComposite Action usage (after you publish)
- uses: hunt3r157/attribution-artisan@v1Notes & limitations
- Reads installed package metadata. Ensure
node_modules/exists first. - License detection:
package.json.license(string or{ type: "..." }), elselicenses[]- Falls back to
UNKNOWNif absent - For embedded texts: Artisan searches package license files (LICENSE, COPYING, etc.) then uses simple built‑in templates for common SPDX ids.
Security
No telemetry, no network calls, local file reads only.
Contributing
PRs welcome! Keep runtime dependency‑free. Add new SPDX templates under templates/licenses/ when useful.
License
MIT © Attribution Artisan contributors
Roadmap
- [ ] More SPDX templates
- [ ] HTML export
- [ ] Support non-Node ecosystems via manifest inputs
- [ ] Option to inline license snippets per package
FAQ
Why not parse lockfiles?
License fields aren’t in lockfiles. Installed package metadata is the most accurate without network calls.
Will it support monorepos/workspaces?
Yes. It follows nested node_modules/ directories and scopes (e.g., @scope/*).
Can I exclude dev dependencies?
First release lists everything installed. We can add --prod-only in future releases if needed.
