licenseguard-cli 1.2.2 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE CHANGED
@@ -1,7 +1,7 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2025 rfxlamia
4
- github.com/rfxlamia/licenseguard
3
+ Copyright (c) 2025 v
4
+
5
5
 
6
6
  Permission is hereby granted, free of charge, to any person obtaining a copy
7
7
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,66 +1,134 @@
1
1
  # LicenseGuard
2
2
 
3
- [![npm version](https://badge.fury.io/js/licenseguard-cli.svg)](https://badge.fury.io/js/licenseguard-cli)
4
- [![Build Status](https://github.com/your-username/licenseguard/workflows/Test/badge.svg)](https://github.com/your-username/licenseguard/actions)
5
- [![Coverage Status](https://codecov.io/gh/your-username/licenseguard/branch/main/graph/badge.svg)](https://codecov.io/gh/your-username/licenseguard)
3
+ [![npm version](https://badge.fury.io/js/licenseguard-cli.svg)](https://www.npmjs.com/package/licenseguard-cli)
6
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
5
 
8
- **License setup & compliance helper for developers**
6
+ > License setup & compliance guard for developers
9
7
 
10
- LicenseGuard is a CLI tool that helps you quickly set up open source licenses for your projects with automatic git hooks that notify your team about licensing requirements.
8
+ LicenseGuard helps you set up open source licenses and protects your project from license conflicts. It scans your dependencies for incompatible licenses and automatically notifies developers about licensing requirements - works with any language (Node.js, Python, Rust, Go, etc.).
9
+
10
+ ## Key Features
11
+
12
+ - **Dependency Scanning** - Scans npm dependencies for license conflicts during setup
13
+ - **Conflict Detection** - Detects incompatible licenses (e.g., GPL vs MIT) and blocks creation
14
+ - **SPDX Compatibility** - Industry-standard license compatibility checking
15
+ - **Scan Results** - Save scan results to `.licenseguardrc` for transparency
16
+ - **Automatic Notifications** - See license info immediately after `git clone`
17
+ - **Zero Effort** - Global hooks install once, work forever
18
+ - **Language Agnostic** - Works for Python, Rust, Go, Ruby, any project
19
+ - **Offline** - All license templates bundled, no internet required
20
+
21
+ ---
11
22
 
12
23
  ## Quick Start
13
24
 
25
+ ### For Developers (One-time Setup)
26
+
14
27
  ```bash
15
- # Step 1: Run the interactive setup
16
- npx licenseguard-cli --init
28
+ npm install -g licenseguard-cli
29
+ ```
30
+
31
+ That's it! Now every time you clone a repo with `.licenseguardrc`, you'll see:
32
+
33
+ ```bash
34
+ git clone https://github.com/some/project
35
+ # šŸ“œ This project uses MIT License by ProjectOwner
36
+ ```
37
+
38
+ ### For Project Owners
39
+
40
+ ```bash
41
+ cd your-project
42
+ licenseguard init
43
+ ```
17
44
 
18
- # Step 2: Answer the prompts (license type, owner name, year)
45
+ Follow the prompts, then commit:
19
46
 
20
- # Step 3: Done! Your LICENSE file and git hooks are ready
47
+ ```bash
48
+ git add LICENSE .licenseguardrc
49
+ git commit -m "Add license"
50
+ git push
21
51
  ```
22
52
 
23
- That's it! Your project now has:
24
- - A properly formatted LICENSE file
25
- - A `.licenseguardrc` configuration file
26
- - Git hooks that display license reminders (optional)
53
+ Anyone who has LicenseGuard installed globally will now see your license info when they clone.
54
+
55
+ ---
56
+
57
+ ## How It Works
58
+
59
+ ### Automatic Global Hooks
60
+
61
+ When you install LicenseGuard globally, it automatically:
62
+
63
+ 1. Creates git template directory at `~/.git-templates/hooks/`
64
+ 2. Installs self-contained hooks (only needs Node.js, not LicenseGuard)
65
+ 3. Configures git: `git config --global init.templateDir ~/.git-templates`
66
+
67
+ Now **every** `git clone` or `git init` copies these hooks automatically.
27
68
 
28
- ## Installation
69
+ The hooks check for `.licenseguardrc` and display license info if found:
29
70
 
30
- ### Using npx (Recommended)
31
71
  ```bash
32
- npx licenseguard-cli --init
72
+ git clone <any-repo>
73
+ # If .licenseguardrc exists:
74
+ # šŸ“œ This project uses MIT License by OwnerName
75
+
76
+ git checkout feature-branch
77
+ # šŸ“œ This project uses MIT License by OwnerName
78
+
79
+ git commit -m "changes"
80
+ # ā„¹ļø Reminder: This project is licensed under MIT
33
81
  ```
34
82
 
35
- ### Global Installation
83
+ ---
84
+
85
+ ## Installation Options
86
+
87
+ ### Global (Recommended)
88
+
36
89
  ```bash
37
90
  npm install -g licenseguard-cli
38
- licenseguard --init
39
91
  ```
40
92
 
41
- ### Local Installation
93
+ Enables automatic license notifications for all git operations.
94
+
95
+ ### Using npx (No install)
96
+
42
97
  ```bash
43
- npm install --save-dev licenseguard-cli
44
- npx licenseguard-cli --init
98
+ npx licenseguard-cli init
45
99
  ```
46
100
 
47
- ## Usage
101
+ One-time use without global install (no automatic notifications).
48
102
 
49
- ### Interactive Setup (`--init`)
103
+ ### Local Development Dependency
50
104
 
51
105
  ```bash
52
- licenseguard --init
106
+ npm install --save-dev licenseguard-cli
53
107
  ```
54
108
 
55
- This command guides you through:
56
- 1. Selecting a license type
57
- 2. Entering your copyright owner name
58
- 3. Setting the copyright year (defaults to current year)
59
- 4. Adding a project URL (optional)
60
- 5. Optionally initializing git if not already a repo
61
- 6. Installing git hooks for license notifications
109
+ For use in npm scripts (see Advanced Usage).
110
+
111
+ ---
112
+
113
+ ## Commands
62
114
 
63
- **Example Output:**
115
+ ### `init` - Interactive Setup
116
+
117
+ ```bash
118
+ licenseguard init
119
+ ```
120
+
121
+ Guides you through:
122
+ 1. Selecting license type (MIT, Apache 2.0, GPL 3.0, etc.)
123
+ 2. Copyright owner name
124
+ 3. Copyright year (defaults to current)
125
+ 4. Project URL (optional)
126
+ 5. Dependency scanning for license conflicts
127
+ 6. Option to save scan results
128
+ 7. Git initialization (if needed)
129
+ 8. Git hooks installation
130
+
131
+ Example (with clean dependencies):
64
132
  ```
65
133
  šŸ“œ LicenseGuard - Interactive License Setup
66
134
 
@@ -69,46 +137,91 @@ This command guides you through:
69
137
  ? Copyright year: 2025
70
138
  ? Project URL (optional): https://github.com/you/project
71
139
 
140
+ šŸ” Scanning dependencies for license conflicts...
141
+
142
+ āœ“ Scan complete - 150 dependencies checked
143
+ āœ“ 150 compatible
144
+ āœ“ 0 incompatible
145
+ āœ“ 0 unknown
146
+
147
+ ? Save scan results to .licenseguardrc? Yes
148
+
72
149
  āœ“ LICENSE file created
150
+ āœ“ Scan results saved to .licenseguardrc
73
151
  āœ“ Configuration saved to .licenseguardrc
74
152
  āœ“ Git hooks installed
75
153
 
76
154
  šŸ“„ Your project is now licensed under MIT
77
155
  ```
78
156
 
79
- ### Fast Setup (`--init-fast`)
157
+ Example (with conflicts):
158
+ ```
159
+ šŸ” Scanning dependencies for license conflicts...
160
+
161
+ āœ— Scan complete - 150 dependencies checked
162
+ āœ“ 147 compatible
163
+ āŒ 2 incompatible
164
+ āš ļø 1 unknown
165
+
166
+ āš ļø CONFLICTS DETECTED:
167
+
168
+ āŒ some-gpl-lib@2.0.0 (GPL-3.0)
169
+ Conflict: Copyleft incompatible with MIT
170
+ Location: node_modules/some-gpl-lib/package.json
171
+
172
+ āœ— LICENSE NOT created due to license conflicts.
173
+
174
+ Fix conflicts or use --force to proceed anyway:
175
+ licenseguard init --force
176
+ ```
177
+
178
+ **Flags:**
179
+ - `--force` - Create LICENSE despite conflicts (shows warnings)
180
+ - `--noscan` - Skip dependency scanning
181
+
182
+ ### `init --fast` - Non-Interactive Setup
80
183
 
81
184
  ```bash
82
- licenseguard --init-fast --license mit --owner "Your Name"
185
+ licenseguard init --fast --license mit --owner "Your Name"
83
186
  ```
84
187
 
85
- Non-interactive setup with flags. Perfect for CI/CD or scripting.
188
+ Perfect for CI/CD or scripting. Automatically scans dependencies and auto-saves clean results.
86
189
 
87
- **Available Flags:**
88
- - `--license <type>` (required) - License type to use
89
- - `--owner <name>` (optional) - Copyright owner (auto-detects from git config)
90
- - `--year <year>` (optional) - Copyright year (defaults to current year)
91
- - `--url <url>` (optional) - Project URL (auto-detects from git remote)
190
+ **Flags:**
191
+ - `--fast` - Enable non-interactive mode
192
+ - `--license <type>` (required) - License type
193
+ - `--owner <name>` (optional) - Auto-detects from git config
194
+ - `--year <year>` (optional) - Defaults to current year
195
+ - `--url <url>` (optional) - Auto-detects from git remote
196
+ - `--force` - Create LICENSE despite conflicts
197
+ - `--noscan` - Skip dependency scanning
92
198
 
93
- **Examples:**
199
+ **Auto-save behavior in fast mode:**
200
+ - Clean scan (no conflicts) → Automatically saves `scanResult`
201
+ - Conflicts detected → Does not save `scanResult`
202
+
203
+ Examples:
94
204
  ```bash
95
- # Minimal (auto-detects owner from git config)
96
- licenseguard --init-fast --license mit
205
+ # Minimal
206
+ licenseguard init --fast --license mit
97
207
 
98
- # Full specification
99
- licenseguard --init-fast --license apache2_0 --owner "Apache Corp" --year 2025 --url "https://apache.org"
208
+ # Skip scanning
209
+ licenseguard init --fast --license mit --noscan
100
210
 
101
- # GPL license
102
- licenseguard --init-fast --license gpl3_0 --owner "Free Software Foundation"
211
+ # Force creation despite conflicts
212
+ licenseguard init --fast --license mit --force
213
+
214
+ # Full specification
215
+ licenseguard init --fast --license apache2_0 --owner "Apache Corp" --year 2025
103
216
  ```
104
217
 
105
- ### List Available Licenses (`--ls`)
218
+ ### `ls` - List Available Licenses
106
219
 
107
220
  ```bash
108
- licenseguard --ls
221
+ licenseguard ls
109
222
  ```
110
223
 
111
- Displays all available license types:
224
+ Output:
112
225
  ```
113
226
  Available License Templates:
114
227
 
@@ -120,23 +233,36 @@ Available License Templates:
120
233
  āœ“ WTFPL - Do What The F*ck You Want To Public License (ultra-permissive)
121
234
  ```
122
235
 
123
- ## Available Licenses
236
+ ### `setup` - Setup Hooks Only
124
237
 
125
- | License Key | Display Name | Description |
126
- |-------------|--------------|-------------|
127
- | `mit` | MIT | MIT License (permissive, widely used) |
128
- | `apache2_0` | Apache 2.0 | Apache License 2.0 (permissive with patent grant) |
129
- | `gpl3_0` | GPL 3.0 | GNU General Public License 3.0 (copyleft) |
130
- | `bsd3clause` | BSD 3-Clause | BSD 3-Clause License (permissive with attribution) |
131
- | `isc` | ISC | ISC License (simpler MIT alternative) |
132
- | `wtfpl` | WTFPL | Do What The F*ck You Want To Public License (ultra-permissive) |
238
+ ```bash
239
+ licenseguard setup
240
+ ```
133
241
 
134
- Not sure which license to choose? Visit [choosealicense.com](https://choosealicense.com) for guidance.
242
+ Reads existing `.licenseguardrc` and installs hooks. Used in npm prepare scripts.
243
+
244
+ ---
245
+
246
+ ## Supported Licenses
247
+
248
+ | Key | Name | Description |
249
+ |-----|------|-------------|
250
+ | `mit` | MIT | Permissive, widely used |
251
+ | `apache2_0` | Apache 2.0 | Permissive with patent grant |
252
+ | `gpl3_0` | GPL 3.0 | Copyleft |
253
+ | `bsd3clause` | BSD 3-Clause | Permissive with attribution |
254
+ | `isc` | ISC | Simpler MIT alternative |
255
+ | `wtfpl` | WTFPL | Ultra-permissive |
256
+
257
+ Not sure which to choose? Visit [choosealicense.com](https://choosealicense.com).
258
+
259
+ ---
135
260
 
136
261
  ## Configuration
137
262
 
138
- LicenseGuard creates a `.licenseguardrc` file in your project root:
263
+ LicenseGuard creates `.licenseguardrc` in your project root.
139
264
 
265
+ **Basic format:**
140
266
  ```json
141
267
  {
142
268
  "license": "mit",
@@ -146,148 +272,184 @@ LicenseGuard creates a `.licenseguardrc` file in your project root:
146
272
  }
147
273
  ```
148
274
 
149
- This configuration is used by the git hooks to display license information.
150
-
151
- ## Git Hooks
152
-
153
- LicenseGuard installs two informational git hooks:
154
-
155
- ### Post-Checkout Hook
156
- Displays a notification after `git checkout` or branch switches:
157
- ```
158
- šŸ“œ This project uses MIT License by Your Name
275
+ **With scan results (optional):**
276
+ ```json
277
+ {
278
+ "license": "mit",
279
+ "owner": "Your Name",
280
+ "year": "2025",
281
+ "url": "https://github.com/you/project",
282
+ "scanResult": {
283
+ "timestamp": "2025-11-18T10:30:00.000Z",
284
+ "totalDependencies": 150,
285
+ "compatible": 150,
286
+ "incompatible": 0,
287
+ "unknown": 0,
288
+ "issues": []
289
+ }
290
+ }
159
291
  ```
160
292
 
161
- ### Pre-Commit Hook
162
- Displays a reminder before each commit:
163
- ```
164
- ā„¹ļø Reminder: This project is licensed under MIT
165
- ```
293
+ **Why save scan results?**
294
+ - **Transparency badge** - Shows your project has validated license compliance
295
+ - **Trust signal** - Like CI badges or test coverage badges
296
+ - **Audit trail** - Documents when dependencies were last checked
297
+ - **Open source best practice** - Demonstrates license awareness
166
298
 
167
- **Important:**
168
- - Hooks are **educational only** - they never block git operations
169
- - Hooks always exit with code 0 (success)
170
- - If `.licenseguardrc` is missing, hooks silently exit
299
+ This file **must be committed** to your repository so others can see your license info.
171
300
 
172
- ### Auto-Setup on Clone (npm projects)
301
+ ---
302
+
303
+ ## Advanced Usage
173
304
 
174
- Git hooks live in `.git/hooks/` which is **not tracked by git**. This means hooks are not copied when someone clones your repository.
305
+ ### For npm Projects (Alternative to Global Install)
175
306
 
176
- For npm projects, you can use the `prepare` script to automatically set up hooks when developers run `npm install`:
307
+ If you can't rely on developers having LicenseGuard installed globally, use npm prepare script:
177
308
 
178
- **Add to your package.json:**
179
309
  ```json
180
310
  {
181
311
  "devDependencies": {
182
- "licenseguard-cli": "^1.1.0"
312
+ "licenseguard-cli": "^2.0.0"
183
313
  },
184
314
  "scripts": {
185
- "prepare": "licenseguard --setup || true"
315
+ "prepare": "licenseguard setup || true"
186
316
  }
187
317
  }
188
318
  ```
189
319
 
190
- **What happens when someone clones your project:**
191
- ```bash
192
- git clone <your-repo> # Gets code + .licenseguardrc
193
- npm install # AUTOMATICALLY:
194
- # šŸ“œ "This project uses MIT License by Your Name"
195
- # āœ“ Git hooks installed
196
- git checkout feature # Notification appears (hooks active)
197
- git commit # Reminder appears (hooks active)
198
- ```
320
+ When developers run `npm install`, hooks are set up automatically.
199
321
 
200
- The `--setup` command:
201
- - Reads `.licenseguardrc` and displays license notification
202
- - Installs git hooks automatically
203
- - Always exits 0 (never breaks `npm install`)
204
- - Safe to run multiple times (idempotent)
322
+ ### Existing Git Hooks
205
323
 
206
- ### Existing Hooks
324
+ LicenseGuard **never overwrites** existing hooks. If conflicts exist:
207
325
 
208
- If you already have git hooks, LicenseGuard will NOT overwrite them. Instead, it creates variants:
209
- - `.git/hooks/licenseguard-pre-commit`
210
- - `.git/hooks/licenseguard-post-checkout`
326
+ - Creates `licenseguard-post-checkout` and `licenseguard-pre-commit`
327
+ - Shows warning with merge instructions
211
328
 
212
- You can manually merge these with your existing hooks if desired.
329
+ ### Non-Git Projects
213
330
 
214
- ### Without Git
331
+ LicenseGuard works without git:
332
+ - `init` offers to run `git init`
333
+ - `init --fast` creates LICENSE file only
334
+ - Hooks are skipped with warning
215
335
 
216
- If your project is not a git repository:
217
- - Interactive mode (`--init`) will offer to run `git init`
218
- - Fast mode (`--init-fast`) will skip hooks and warn you
219
- - `--setup` command will skip hooks with a warning
220
- - LICENSE file is always created regardless of git status
336
+ ---
221
337
 
222
338
  ## FAQ
223
339
 
224
- ### Does this work offline?
225
- Yes! LicenseGuard is completely offline. All license templates are bundled with the package.
340
+ ### What licenses are checked during scanning?
226
341
 
227
- ### Can I use custom licenses?
228
- Currently, LicenseGuard supports the 6 most common open source licenses. Custom license support may be added in future versions.
342
+ Scans **npm dependencies only** (reads `package.json` and `node_modules`). It checks:
343
+ - SPDX license identifiers (MIT, Apache-2.0, GPL-3.0, BSD-3-Clause, ISC, etc.)
344
+ - License compatibility using industry-standard rules
345
+ - Copyleft vs permissive conflicts (e.g., GPL incompatible with MIT)
229
346
 
230
- ### Does it work on Windows?
231
- Yes! LicenseGuard is fully cross-platform and works on Linux, macOS, and Windows.
347
+ For non-JavaScript projects, use `--noscan` flag.
232
348
 
233
- ### What if I already have a LICENSE file?
234
- Interactive mode will ask if you want to overwrite it. Fast mode will overwrite without asking.
349
+ ### How does SPDX compatibility work?
235
350
 
236
- ### How do I update my license?
237
- Run `licenseguard --init` again and it will regenerate your LICENSE file.
351
+ LicenseGuard uses [spdx-satisfies](https://www.npmjs.com/package/spdx-satisfies) for compatibility checking:
352
+ - **Permissive licenses** (MIT, Apache, BSD, ISC) - Compatible with most licenses
353
+ - **Copyleft licenses** (GPL-3.0) - Incompatible with permissive project licenses
354
+ - **Unknown licenses** - Generates warnings but doesn't block
355
+ - **Custom rules** - Fallback for non-SPDX licenses (WTFPL, proprietary)
238
356
 
239
- ### Can I disable the git hooks?
240
- The hooks are informational only and don't block anything. If you don't want them, simply delete the hook files from `.git/hooks/`.
357
+ ### What is the scanResult for?
241
358
 
242
- ### What Node.js versions are supported?
243
- LicenseGuard requires Node.js 18.x or 20.x (LTS versions).
359
+ `scanResult` is optional transparency data you can commit to show:
360
+ 1. Your project has validated license compliance
361
+ 2. When dependencies were last scanned
362
+ 3. What conflicts (if any) were detected
363
+ 4. Trust signal for users and contributors (like CI badges)
244
364
 
245
- ## Contributing
365
+ You choose whether to save it after each scan. Clean scans default to YES, conflicts default to NO.
246
366
 
247
- Contributions are welcome! Please feel free to submit a Pull Request.
367
+ ### Can I skip dependency scanning?
248
368
 
249
- 1. Fork the repository
250
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
251
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
252
- 4. Push to the branch (`git push origin feature/amazing-feature`)
253
- 5. Open a Pull Request
369
+ Yes! Use the `--noscan` flag:
370
+ ```bash
371
+ licenseguard init --noscan
372
+ ```
254
373
 
255
- ## Development
374
+ This is useful for:
375
+ - Non-JavaScript projects
376
+ - Projects without dependencies
377
+ - When you want manual license management
256
378
 
257
- ```bash
258
- # Clone the repository
259
- git clone https://github.com/your-username/licenseguard.git
260
- cd licenseguard
379
+ ### Does this work for non-JavaScript projects?
380
+
381
+ **Yes!** LicenseGuard works for any project:
382
+ - Python projects
383
+ - Rust/Cargo projects
384
+ - Go modules
385
+ - Ruby gems
386
+ - Any language
387
+
388
+ The hooks only need Node.js installed (which most developers have).
261
389
 
262
- # Install dependencies
263
- npm install
390
+ ### Do my contributors need to install LicenseGuard?
264
391
 
265
- # Run tests
266
- npm test
392
+ For automatic notifications: **Yes**, they need `npm install -g licenseguard-cli` once.
267
393
 
268
- # Run tests with coverage
269
- npm run test:coverage
394
+ Alternative: Use npm prepare script (see Advanced Usage) - then only project owner installs.
270
395
 
271
- # Lint code
272
- npm run lint
396
+ ### Does this work offline?
397
+
398
+ Yes! All license templates are bundled. No internet required.
273
399
 
274
- # Format code
275
- npm run format
400
+ ### Can I disable notifications?
276
401
 
277
- # Test locally
278
- npm link
279
- cd /tmp && mkdir test-project && cd test-project
280
- licenseguard --init
402
+ Delete hooks from `.git/hooks/`:
403
+ ```bash
404
+ rm .git/hooks/post-checkout .git/hooks/pre-commit
281
405
  ```
282
406
 
407
+ Or remove global hooks:
408
+ ```bash
409
+ rm -rf ~/.git-templates/hooks/
410
+ git config --global --unset init.templateDir
411
+ ```
412
+
413
+ ### What Node.js versions work?
414
+
415
+ Node.js 18.x or 20.x (LTS versions).
416
+
417
+ ### Does it work on Windows?
418
+
419
+ Yes! Fully cross-platform (Linux, macOS, Windows).
420
+
421
+ ---
422
+
423
+ ## Why LicenseGuard?
424
+
425
+ - **Not enforcing** - Unlike license scanners, we inform and educate
426
+ - **Zero friction** - One global install, automatic forever
427
+ - **Universal** - Works with any language/framework
428
+ - **Educational** - Raises awareness without blocking workflows
429
+ - **Open source** - MIT licensed, free forever
430
+
431
+ ---
432
+
433
+ ## Contributing
434
+
435
+ Contributions welcome!
436
+
437
+ 1. Fork the repository
438
+ 2. Create feature branch: `git checkout -b feature/amazing`
439
+ 3. Commit changes: `git commit -m 'Add feature'`
440
+ 4. Push: `git push origin feature/amazing`
441
+ 5. Open Pull Request
442
+
443
+ ---
444
+
283
445
  ## License
284
446
 
285
- This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
447
+ MIT License - see [LICENSE](LICENSE) file.
286
448
 
287
449
  ---
288
450
 
289
- **Links:**
290
- - [Choose a License](https://choosealicense.com) - Help choosing the right license
291
- - [Open Source Initiative](https://opensource.org/licenses) - OSI-approved licenses
292
- - [GitHub Repository](https://github.com/your-username/licenseguard) - Source code
293
- - [npm Package](https://www.npmjs.com/package/licenseguard-cli) - npm registry
451
+ ## Links
452
+
453
+ - [npm Package](https://www.npmjs.com/package/licenseguard-cli)
454
+ - [Choose a License](https://choosealicense.com)
455
+ - [Open Source Initiative](https://opensource.org/licenses)
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  const { program } = require('commander')
4
+ const chalk = require('chalk')
4
5
  const { version } = require('../package.json')
5
6
  const { runList } = require('../lib/commands/list')
6
7
  const { runInit } = require('../lib/commands/init')
@@ -9,44 +10,61 @@ const { setupCommand } = require('../lib/commands/setup')
9
10
 
10
11
  program
11
12
  .version(version)
12
- .description('License setup & compliance helper for developers')
13
+ .description('License setup & compliance guard for developers')
13
14
 
15
+ // Init command with subcommand-specific options
14
16
  program
15
- .option('--init', 'Interactive license setup wizard')
16
- .option('--init-fast', 'Non-interactive fast setup')
17
- .option('--license <type>', 'License type (for --init-fast)')
18
- .option('--owner <name>', 'Copyright owner name (for --init-fast)')
19
- .option('--year <year>', 'Copyright year (for --init-fast)')
20
- .option('--url <url>', 'Project URL (for --init-fast)')
21
- .option('--ls', 'List available license templates')
22
- .option(
23
- '--setup',
24
- 'Setup license notification and install git hooks (for npm prepare script)'
25
- )
26
- .parse(process.argv)
27
-
28
- const options = program.opts()
29
-
30
- if (options.init) {
31
- runInit().catch((err) => {
32
- console.error('Error:', err.message)
33
- process.exit(1)
34
- })
35
- } else if (options.initFast) {
36
- runInitFast(options).catch((err) => {
37
- console.error('Error:', err.message)
38
- process.exit(1)
17
+ .command('init')
18
+ .description('Interactive license setup with dependency scanning')
19
+ .option('--force', 'Create LICENSE despite conflicts')
20
+ .option('--noscan', 'Skip dependency scanning')
21
+ .option('--fast', 'Non-interactive mode with auto-detection')
22
+ .option('--license <type>', 'License type (for --fast mode)')
23
+ .option('--owner <name>', 'Copyright owner name (for --fast mode)')
24
+ .option('--year <year>', 'Copyright year (for --fast mode)')
25
+ .option('--url <url>', 'Project URL (for --fast mode)')
26
+ .action(async (options) => {
27
+ try {
28
+ if (options.fast) {
29
+ await runInitFast(options)
30
+ } else {
31
+ await runInit(options)
32
+ }
33
+ } catch (error) {
34
+ console.error(chalk.red('āœ— Error:'), error.message)
35
+ process.exit(1)
36
+ }
39
37
  })
40
- } else if (options.ls) {
41
- runList().catch((err) => {
42
- console.error('Error:', err.message)
43
- process.exit(1)
38
+
39
+ // List command
40
+ program
41
+ .command('ls')
42
+ .description('List available license templates')
43
+ .action(async () => {
44
+ try {
45
+ await runList()
46
+ } catch (error) {
47
+ console.error(chalk.red('āœ— Error:'), error.message)
48
+ process.exit(1)
49
+ }
44
50
  })
45
- } else if (options.setup) {
46
- setupCommand().catch((err) => {
47
- // Even on error, don't exit 1 - npm prepare compatibility
48
- console.error('Setup warning:', err.message)
51
+
52
+ // Setup command (kept for npm prepare script compatibility)
53
+ program
54
+ .command('setup')
55
+ .description('Setup license notification and install git hooks (for npm prepare script)')
56
+ .action(async () => {
57
+ try {
58
+ await setupCommand()
59
+ } catch (error) {
60
+ // Even on error, don't exit 1 - npm prepare compatibility
61
+ console.error(chalk.yellow('āš ļø Setup warning:'), error.message)
62
+ }
49
63
  })
50
- } else {
64
+
65
+ program.parse(process.argv)
66
+
67
+ // Show help if no command provided
68
+ if (!process.argv.slice(2).length) {
51
69
  program.help()
52
70
  }
@@ -5,6 +5,7 @@ const chalk = require('chalk')
5
5
  const { generateLicense, LICENSE_TEMPLATES } = require('../templates')
6
6
  const { writeConfig } = require('../utils/file-ops')
7
7
  const { isGitRepo, installHooks } = require('../utils/git-helpers')
8
+ const { scanDependencies, displayConflictReport } = require('../scanner')
8
9
 
9
10
  function getGitConfig(key) {
10
11
  try {
@@ -63,19 +64,85 @@ async function runInitFast(options) {
63
64
  if (url) console.log(chalk.gray(`URL: ${url}`))
64
65
  console.log()
65
66
 
67
+ // Scanner integration (Story 2.3) - Fast mode
68
+ let scanResult = null
69
+ if (!options.noscan) {
70
+ // Convert internal license format to SPDX identifier
71
+ const licenseToSPDX = {
72
+ 'mit': 'MIT',
73
+ 'apache2_0': 'Apache-2.0',
74
+ 'gpl3_0': 'GPL-3.0',
75
+ 'bsd3clause': 'BSD-3-Clause',
76
+ 'isc': 'ISC',
77
+ 'wtfpl': 'WTFPL'
78
+ }
79
+ const spdxLicense = licenseToSPDX[flags.license] || flags.license.toUpperCase()
80
+
81
+ try {
82
+ console.log(chalk.blue('šŸ” Scanning dependencies for license conflicts...\n'))
83
+
84
+ scanResult = await scanDependencies(spdxLicense)
85
+ const hasConflicts = displayConflictReport(scanResult, spdxLicense)
86
+
87
+ if (hasConflicts && !options.force) {
88
+ // Block LICENSE creation due to conflicts
89
+ console.error(chalk.red('\nāœ— LICENSE NOT created due to license conflicts.'))
90
+ console.log(chalk.yellow('\nFix conflicts or use --force to proceed anyway:'))
91
+ console.log(chalk.blue(' licenseguard init --fast --force --license ' + flags.license + '\n'))
92
+ process.exit(1)
93
+ }
94
+
95
+ if (hasConflicts && options.force) {
96
+ console.log(chalk.yellow('\nāš ļø Creating LICENSE despite conflicts (--force mode)\n'))
97
+ }
98
+ } catch (scanError) {
99
+ // If scanning fails (not process.exit), warn but don't block
100
+ if (scanError.message !== 'process.exit called') {
101
+ console.log(chalk.yellow(`\nāš ļø Dependency scanning failed: ${scanError.message}`))
102
+ console.log(chalk.yellow('Continuing with LICENSE creation...\n'))
103
+ } else {
104
+ // Re-throw process.exit errors
105
+ throw scanError
106
+ }
107
+ }
108
+ }
109
+
66
110
  // Generate license text
67
111
  const licenseContent = generateLicense(flags.license, owner, year, url)
68
112
 
69
113
  // Write LICENSE file directly (no prompt in fast mode)
70
114
  fs.writeFileSync('LICENSE', licenseContent, 'utf8')
71
115
 
72
- // Write config file
73
- writeConfig({
116
+ // Auto-save scan results in fast mode (Story 2.4: AC #1, #2)
117
+ // Default: YES for clean scans, NO for conflicts
118
+ const configData = {
74
119
  license: flags.license,
75
120
  owner: owner,
76
121
  year: year,
77
122
  url: url,
78
- })
123
+ }
124
+
125
+ if (scanResult) {
126
+ const hasConflicts = scanResult.incompatible > 0
127
+ const shouldSave = !hasConflicts // Auto-save if clean
128
+
129
+ if (shouldSave) {
130
+ configData.scanResult = scanResult
131
+ }
132
+ }
133
+
134
+ // Write config file
135
+ writeConfig(configData)
136
+
137
+ // Feedback for scan result save
138
+ if (scanResult) {
139
+ const hasConflicts = scanResult.incompatible > 0
140
+ if (!hasConflicts) {
141
+ console.log(chalk.green('āœ“ Scan results saved to .licenseguardrc'))
142
+ } else {
143
+ console.log(chalk.gray('Scan results not saved (conflicts detected)'))
144
+ }
145
+ }
79
146
 
80
147
  // Success messages
81
148
  console.log(chalk.green('āœ“ LICENSE file created'))
@@ -3,8 +3,9 @@ const chalk = require('chalk')
3
3
  const { generateLicense } = require('../templates')
4
4
  const { writeLicenseFile, writeConfig } = require('../utils/file-ops')
5
5
  const { isGitRepo, initGitRepo, installHooks } = require('../utils/git-helpers')
6
+ const { scanDependencies, displayConflictReport } = require('../scanner')
6
7
 
7
- async function runInit() {
8
+ async function runInit(options = {}) {
8
9
  try {
9
10
  console.log(chalk.blue('šŸ“œ LicenseGuard - Interactive License Setup\n'))
10
11
 
@@ -48,6 +49,49 @@ async function runInit() {
48
49
  },
49
50
  ])
50
51
 
52
+ // Scanner integration (Story 2.3)
53
+ let scanResult = null
54
+ if (!options.noscan) {
55
+ // Convert internal license format to SPDX identifier
56
+ const licenseToSPDX = {
57
+ 'mit': 'MIT',
58
+ 'apache2_0': 'Apache-2.0',
59
+ 'gpl3_0': 'GPL-3.0',
60
+ 'bsd3clause': 'BSD-3-Clause',
61
+ 'isc': 'ISC',
62
+ 'wtfpl': 'WTFPL'
63
+ }
64
+ const spdxLicense = licenseToSPDX[answers.license] || answers.license.toUpperCase()
65
+
66
+ try {
67
+ console.log(chalk.blue('\nšŸ” Scanning dependencies for license conflicts...\n'))
68
+
69
+ scanResult = await scanDependencies(spdxLicense)
70
+ const hasConflicts = displayConflictReport(scanResult, spdxLicense)
71
+
72
+ if (hasConflicts && !options.force) {
73
+ // Block LICENSE creation due to conflicts
74
+ console.error(chalk.red('\nāœ— LICENSE NOT created due to license conflicts.'))
75
+ console.log(chalk.yellow('\nFix conflicts or use --force to proceed anyway:'))
76
+ console.log(chalk.blue(' licenseguard init --force\n'))
77
+ process.exit(1)
78
+ }
79
+
80
+ if (hasConflicts && options.force) {
81
+ console.log(chalk.yellow('\nāš ļø Creating LICENSE despite conflicts (--force mode)\n'))
82
+ }
83
+ } catch (scanError) {
84
+ // If scanning fails (not process.exit), warn but don't block
85
+ if (scanError.message !== 'process.exit called') {
86
+ console.log(chalk.yellow(`\nāš ļø Dependency scanning failed: ${scanError.message}`))
87
+ console.log(chalk.yellow('Continuing with LICENSE creation...\n'))
88
+ } else {
89
+ // Re-throw process.exit errors
90
+ throw scanError
91
+ }
92
+ }
93
+ }
94
+
51
95
  // Generate license text
52
96
  const licenseContent = generateLicense(
53
97
  answers.license,
@@ -64,13 +108,47 @@ async function runInit() {
64
108
  process.exit(0)
65
109
  }
66
110
 
67
- // Write config file
68
- writeConfig({
111
+ // Prompt to save scan results (Story 2.4: AC #1, #2)
112
+ let saveScanResult = false
113
+ if (scanResult) {
114
+ // Determine default: YES for clean scans, NO for conflicts
115
+ const hasConflicts = scanResult.incompatible > 0
116
+ const defaultSave = !hasConflicts
117
+
118
+ const saveAnswer = await inquirer.prompt([
119
+ {
120
+ type: 'confirm',
121
+ name: 'saveScanResult',
122
+ message: 'Save scan results to .licenseguardrc?',
123
+ default: defaultSave,
124
+ },
125
+ ])
126
+
127
+ saveScanResult = saveAnswer.saveScanResult
128
+ }
129
+
130
+ // Write config file (Story 2.4: AC #3)
131
+ const configData = {
69
132
  license: answers.license,
70
133
  owner: answers.owner,
71
134
  year: answers.year,
72
135
  url: answers.url,
73
- })
136
+ }
137
+
138
+ if (saveScanResult && scanResult) {
139
+ configData.scanResult = scanResult
140
+ }
141
+
142
+ writeConfig(configData)
143
+
144
+ // Feedback for scan result save choice
145
+ if (scanResult) {
146
+ if (saveScanResult) {
147
+ console.log(chalk.green('āœ“ Scan results saved to .licenseguardrc'))
148
+ } else {
149
+ console.log(chalk.gray('Scan results not saved'))
150
+ }
151
+ }
74
152
 
75
153
  // Success messages
76
154
  console.log(chalk.green('\nāœ“ LICENSE file created'))
@@ -0,0 +1,114 @@
1
+ /**
2
+ * License compatibility checker
3
+ * Uses SPDX libraries for standard licenses + custom rules for non-SPDX
4
+ */
5
+
6
+ const satisfies = require('spdx-satisfies')
7
+ const parse = require('spdx-expression-parse')
8
+
9
+ /**
10
+ * Custom compatibility rules for non-SPDX licenses
11
+ * @type {Object}
12
+ */
13
+ const CUSTOM_COMPAT = {
14
+ wtfpl: {
15
+ type: 'permissive',
16
+ compatibleWith: '*', // Compatible with everything
17
+ description: 'Do What The F*ck You Want To Public License'
18
+ }
19
+ }
20
+
21
+ /**
22
+ * Permissive licenses that are generally compatible with each other
23
+ */
24
+ const PERMISSIVE_LICENSES = ['MIT', 'ISC', 'BSD-2-Clause', 'BSD-3-Clause', 'Apache-2.0', '0BSD']
25
+
26
+ /**
27
+ * Copyleft licenses that have restrictions
28
+ */
29
+ const COPYLEFT_LICENSES = ['GPL-2.0', 'GPL-3.0', 'AGPL-3.0', 'GPL-2.0-only', 'GPL-3.0-only', 'LGPL-2.1', 'LGPL-3.0']
30
+
31
+ /**
32
+ * Check if two licenses are compatible
33
+ * @param {string} projectLicense - The project's license
34
+ * @param {string} depLicense - The dependency's license
35
+ * @returns {{compatible: boolean, reason: string}} Compatibility result
36
+ */
37
+ function checkCompatibility(projectLicense, depLicense) {
38
+ // Handle unknown licenses
39
+ if (depLicense === 'UNKNOWN' || !depLicense) {
40
+ return {
41
+ compatible: false, // Warn but don't block (handled by caller)
42
+ reason: 'No license field found'
43
+ }
44
+ }
45
+
46
+ // Handle custom licenses (WTFPL, proprietary, etc.)
47
+ const depLowerCase = depLicense.toLowerCase()
48
+ if (CUSTOM_COMPAT[depLowerCase]) {
49
+ if (CUSTOM_COMPAT[depLowerCase].compatibleWith === '*') {
50
+ return { compatible: true, reason: 'Ultra-permissive license' }
51
+ }
52
+ }
53
+
54
+ // Validate SPDX expressions
55
+ try {
56
+ parse(projectLicense)
57
+ parse(depLicense)
58
+ } catch (error) {
59
+ // Invalid SPDX expression
60
+ return {
61
+ compatible: false,
62
+ reason: `Invalid SPDX expression: ${depLicense}`
63
+ }
64
+ }
65
+
66
+ // Same license is always compatible
67
+ if (projectLicense === depLicense) {
68
+ return { compatible: true, reason: 'Compatible' }
69
+ }
70
+
71
+ // Check if both are permissive licenses
72
+ const projectIsPermissive = PERMISSIVE_LICENSES.includes(projectLicense)
73
+ const depIsPermissive = PERMISSIVE_LICENSES.includes(depLicense)
74
+
75
+ // Permissive licenses are compatible with each other
76
+ if (projectIsPermissive && depIsPermissive) {
77
+ return { compatible: true, reason: 'Compatible' }
78
+ }
79
+
80
+ // Check for copyleft restrictions
81
+ const depIsCopyleft = COPYLEFT_LICENSES.some(lic => depLicense.includes(lic))
82
+
83
+ // Permissive project cannot use copyleft dependencies
84
+ if (projectIsPermissive && depIsCopyleft) {
85
+ return {
86
+ compatible: false,
87
+ reason: 'Copyleft incompatible with permissive license'
88
+ }
89
+ }
90
+
91
+ // Copyleft project can use permissive dependencies
92
+ const projectIsCopyleft = COPYLEFT_LICENSES.some(lic => projectLicense.includes(lic))
93
+ if (projectIsCopyleft && depIsPermissive) {
94
+ return { compatible: true, reason: 'Compatible' }
95
+ }
96
+
97
+ // For complex expressions, try spdx-satisfies
98
+ try {
99
+ const isCompatible = satisfies(depLicense, projectLicense)
100
+ if (isCompatible) {
101
+ return { compatible: true, reason: 'Compatible' }
102
+ }
103
+ } catch (error) {
104
+ // Fall through to default incompatible
105
+ }
106
+
107
+ // Default: incompatible
108
+ return {
109
+ compatible: false,
110
+ reason: `License ${depLicense} incompatible with ${projectLicense}`
111
+ }
112
+ }
113
+
114
+ module.exports = { checkCompatibility, CUSTOM_COMPAT }
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Dependency License Scanner
3
+ * Scans node_modules for license conflicts
4
+ */
5
+
6
+ const fs = require('fs')
7
+ const path = require('path')
8
+ const chalk = require('chalk')
9
+ const { checkCompatibility } = require('./compat-checker')
10
+ const { showProgress } = require('./progress')
11
+
12
+ /**
13
+ * Parse package.json to get dependencies
14
+ * @returns {{deps: string[], packageJson: Object}} Dependency list and package.json
15
+ */
16
+ function parsePackageJson() {
17
+ try {
18
+ const content = fs.readFileSync('package.json', 'utf8')
19
+ const packageJson = JSON.parse(content)
20
+
21
+ // Only scan production dependencies
22
+ const deps = Object.keys(packageJson.dependencies || {})
23
+
24
+ return { deps, packageJson }
25
+ } catch (error) {
26
+ throw new Error('Failed to read package.json: ' + error.message)
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Extract license info from a dependency
32
+ * @param {string} depName - Dependency name
33
+ * @returns {{name: string, version: string, license: string, path: string}} License info
34
+ */
35
+ function extractLicense(depName) {
36
+ const depPath = path.join('node_modules', depName, 'package.json')
37
+
38
+ if (!fs.existsSync(depPath)) {
39
+ return {
40
+ name: depName,
41
+ version: 'unknown',
42
+ license: 'NOT_INSTALLED',
43
+ path: depPath
44
+ }
45
+ }
46
+
47
+ try {
48
+ const content = fs.readFileSync(depPath, 'utf8')
49
+ const depPackageJson = JSON.parse(content)
50
+
51
+ return {
52
+ name: depName,
53
+ version: depPackageJson.version || 'unknown',
54
+ license: depPackageJson.license || 'UNKNOWN',
55
+ path: depPath
56
+ }
57
+ } catch (error) {
58
+ return {
59
+ name: depName,
60
+ version: 'unknown',
61
+ license: 'PARSE_ERROR',
62
+ path: depPath
63
+ }
64
+ }
65
+ }
66
+
67
+ /**
68
+ * Scan all dependencies for license compatibility
69
+ * @param {string} projectLicense - The project's license
70
+ * @returns {Promise<Object>} Scan results
71
+ */
72
+ async function scanDependencies(projectLicense) {
73
+ // 1. Read project package.json
74
+ const { deps } = parsePackageJson()
75
+
76
+ const results = {
77
+ timestamp: new Date().toISOString(),
78
+ totalDependencies: deps.length,
79
+ compatible: 0,
80
+ incompatible: 0,
81
+ unknown: 0,
82
+ issues: []
83
+ }
84
+
85
+ // 2. Scan each dependency
86
+ for (let i = 0; i < deps.length; i++) {
87
+ showProgress(i + 1, deps.length)
88
+
89
+ const depName = deps[i]
90
+ const depInfo = extractLicense(depName)
91
+
92
+ // Skip if not installed
93
+ if (depInfo.license === 'NOT_INSTALLED') {
94
+ continue
95
+ }
96
+
97
+ // Handle parse errors as unknown
98
+ if (depInfo.license === 'PARSE_ERROR') {
99
+ results.unknown++
100
+ results.issues.push({
101
+ package: `${depName}@${depInfo.version}`,
102
+ license: 'UNKNOWN',
103
+ type: 'warning',
104
+ reason: 'Failed to parse package.json',
105
+ location: depInfo.path
106
+ })
107
+ continue
108
+ }
109
+
110
+ // 3. Check compatibility
111
+ const compatResult = checkCompatibility(projectLicense, depInfo.license)
112
+
113
+ if (!compatResult.compatible) {
114
+ const isUnknown = depInfo.license === 'UNKNOWN'
115
+
116
+ if (isUnknown) {
117
+ results.unknown++
118
+ } else {
119
+ results.incompatible++
120
+ }
121
+
122
+ results.issues.push({
123
+ package: `${depName}@${depInfo.version}`,
124
+ license: depInfo.license,
125
+ type: isUnknown ? 'warning' : 'conflict',
126
+ reason: compatResult.reason,
127
+ location: depInfo.path
128
+ })
129
+ } else {
130
+ results.compatible++
131
+ }
132
+ }
133
+
134
+ return results
135
+ }
136
+
137
+ /**
138
+ * Display conflict report to console
139
+ * @param {Object} scanResult - Scan results
140
+ * @param {string} projectLicense - The project's license
141
+ * @returns {boolean} True if conflicts found (incompatible licenses), false otherwise
142
+ */
143
+ function displayConflictReport(scanResult, projectLicense) {
144
+ if (scanResult.incompatible === 0 && scanResult.unknown === 0) {
145
+ console.log(chalk.green(`\nāœ… All ${scanResult.totalDependencies} dependencies compatible with ${projectLicense.toUpperCase()}!`))
146
+ return false // No conflicts
147
+ }
148
+
149
+ const issueCount = scanResult.incompatible + scanResult.unknown
150
+ const hasConflicts = scanResult.incompatible > 0
151
+
152
+ if (hasConflicts) {
153
+ console.log(chalk.red(`\nāŒ ${issueCount} issue(s) found:\n`))
154
+ } else {
155
+ // Only warnings, no conflicts
156
+ console.log(chalk.yellow(`\nāš ļø ${issueCount} warning(s) found:\n`))
157
+ }
158
+
159
+ for (const issue of scanResult.issues) {
160
+ if (issue.type === 'conflict') {
161
+ console.log(chalk.red(`āŒ ${issue.package} (${issue.license})`))
162
+ } else {
163
+ console.log(chalk.yellow(`āš ļø ${issue.package} (${issue.license})`))
164
+ }
165
+ console.log(chalk.gray(` ${issue.reason}`))
166
+ console.log(chalk.gray(` Location: ${issue.location}\n`))
167
+ }
168
+
169
+ // Only return true if there are actual conflicts (incompatible licenses)
170
+ // Warnings (unknown licenses) should not block
171
+ return hasConflicts
172
+ }
173
+
174
+ module.exports = {
175
+ scanDependencies,
176
+ parsePackageJson,
177
+ extractLicense,
178
+ displayConflictReport
179
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Progress indicator for dependency scanning
3
+ * Displays "Scanning dependencies... N/total" with in-place updates
4
+ */
5
+
6
+ /**
7
+ * Show scanning progress indicator
8
+ * @param {number} current - Current dependency count
9
+ * @param {number} total - Total dependencies to scan
10
+ */
11
+ function showProgress(current, total) {
12
+ // Clear current line and write progress
13
+ // \r returns to start of line without newline
14
+ process.stdout.write(`\rScanning dependencies... ${current}/${total}`)
15
+
16
+ // Newline when complete
17
+ if (current === total) {
18
+ process.stdout.write('\n')
19
+ }
20
+ }
21
+
22
+ module.exports = { showProgress }
@@ -34,7 +34,24 @@ async function writeLicenseFile(content) {
34
34
 
35
35
  function writeConfig(config) {
36
36
  try {
37
- const configContent = JSON.stringify(config, null, 2)
37
+ let finalConfig = config
38
+
39
+ // If .licenseguardrc exists, preserve existing fields when updating
40
+ if (fs.existsSync('.licenseguardrc')) {
41
+ try {
42
+ const existingContent = fs.readFileSync('.licenseguardrc', 'utf8')
43
+ const existingConfig = JSON.parse(existingContent)
44
+
45
+ // Merge: new config overwrites matching fields (including scanResult)
46
+ // But existing fields not in new config are preserved
47
+ finalConfig = { ...existingConfig, ...config }
48
+ } catch (parseError) {
49
+ // If existing file is malformed, just use new config
50
+ console.log(chalk.yellow('āš ļø Existing .licenseguardrc malformed, overwriting'))
51
+ }
52
+ }
53
+
54
+ const configContent = JSON.stringify(finalConfig, null, 2)
38
55
  fs.writeFileSync('.licenseguardrc', configContent, 'utf8')
39
56
  return true
40
57
  } catch (error) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "licenseguard-cli",
3
- "version": "1.2.2",
4
- "description": "License setup & compliance helper for developers",
3
+ "version": "2.0.0",
4
+ "description": "License setup & compliance guard for developers",
5
5
  "bin": {
6
6
  "licenseguard": "./bin/licenseguard.js"
7
7
  },
@@ -9,15 +9,24 @@
9
9
  "doc": "docs"
10
10
  },
11
11
  "scripts": {
12
+ "test": "jest",
13
+ "test:watch": "jest --watch",
14
+ "test:coverage": "jest --coverage",
15
+ "lint": "eslint .",
16
+ "format": "prettier --write .",
12
17
  "postinstall": "node lib/postinstall.js"
13
18
  },
14
19
  "keywords": [
15
20
  "license",
16
21
  "compliance",
22
+ "scanning",
23
+ "spdx",
24
+ "dependencies",
17
25
  "MIT",
18
26
  "Apache",
19
27
  "GPL",
20
- "developer-tools"
28
+ "developer-tools",
29
+ "license-checker"
21
30
  ],
22
31
  "author": "v",
23
32
  "license": "MIT",
@@ -25,6 +34,13 @@
25
34
  "chalk": "^4.1.2",
26
35
  "commander": "^11.1.0",
27
36
  "inquirer": "^8.2.5",
28
- "licenseguard-cli": "^1.2.0"
37
+ "spdx-expression-parse": "^4.0.0",
38
+ "spdx-satisfies": "^6.0.0"
39
+ },
40
+ "devDependencies": {
41
+ "eslint": "^8.54.0",
42
+ "jest": "^29.7.0",
43
+ "mock-fs": "^5.2.0",
44
+ "prettier": "^3.1.0"
29
45
  }
30
46
  }