@anth0nycodes/license-generator 0.1.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 +21 -0
- package/README.md +93 -0
- package/dist/helpers.d.ts +3 -0
- package/dist/helpers.d.ts.map +1 -0
- package/dist/helpers.js +17 -0
- package/dist/helpers.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +81 -0
- package/dist/index.js.map +1 -0
- package/dist/license.d.ts +21 -0
- package/dist/license.d.ts.map +1 -0
- package/dist/license.js +57 -0
- package/dist/license.js.map +1 -0
- package/package.json +55 -0
- package/src/helpers.ts +17 -0
- package/src/index.ts +91 -0
- package/src/license.ts +87 -0
- package/tsconfig.json +23 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 anth0nycodes
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
# License Generator
|
|
2
|
+
|
|
3
|
+
An interactive CLI tool to quickly generate open-source licenses for your projects.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🚀 Interactive license selection from GitHub's license API
|
|
8
|
+
- 📝 Automatic copyright holder and year detection from git config
|
|
9
|
+
- ✨ Beautiful terminal UI powered by @clack/prompts and inquirer
|
|
10
|
+
- 🔄 Overwrite protection for existing LICENSE files
|
|
11
|
+
|
|
12
|
+
## Installation
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
pnpm install -g @anth0nycodes/license-generator
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Or using npm:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npm install -g @anth0nycodes/license-generator
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
## Usage
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
generate-license
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The CLI will guide you through:
|
|
31
|
+
|
|
32
|
+
1. **Select a license** - Choose from popular open-source licenses (MIT, Apache-2.0, GPL, etc.)
|
|
33
|
+
2. **Enter copyright holder** - Defaults to your git username
|
|
34
|
+
3. **Enter copyright year** - Defaults to the current year
|
|
35
|
+
4. **Confirm** - The LICENSE file will be created in your current directory
|
|
36
|
+
|
|
37
|
+
## Supported Licenses
|
|
38
|
+
|
|
39
|
+
This tool uses the GitHub Licenses API, which includes:
|
|
40
|
+
|
|
41
|
+
- GNU Affero General Public License v3.0
|
|
42
|
+
- Apache License 2.0
|
|
43
|
+
- BSD 2-Clause "Simplified" License
|
|
44
|
+
- BSD 3-Clause "New" or "Revised" License
|
|
45
|
+
- Boost Software License 1.0
|
|
46
|
+
- Creative Commons Zero v1.0 Universal
|
|
47
|
+
- Eclipse Public License 2.0
|
|
48
|
+
- GNU General Public License v2.0
|
|
49
|
+
- GNU General Public License v3.0
|
|
50
|
+
- GNU Lesser General Public License v2.1
|
|
51
|
+
- MIT License
|
|
52
|
+
- Mozilla Public License 2.0
|
|
53
|
+
- The Unlicense
|
|
54
|
+
|
|
55
|
+
## Requirements
|
|
56
|
+
|
|
57
|
+
- Node.js 20.x or higher
|
|
58
|
+
|
|
59
|
+
## Development
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Clone the repository
|
|
63
|
+
git clone https://github.com/anth0nycodes/license-generator.git
|
|
64
|
+
cd license-generator
|
|
65
|
+
|
|
66
|
+
# Install dependencies
|
|
67
|
+
pnpm install
|
|
68
|
+
|
|
69
|
+
# Run in development mode
|
|
70
|
+
pnpm dev
|
|
71
|
+
|
|
72
|
+
# Build
|
|
73
|
+
pnpm build
|
|
74
|
+
|
|
75
|
+
# Run built version
|
|
76
|
+
pnpm start
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Contributing
|
|
80
|
+
|
|
81
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
82
|
+
|
|
83
|
+
## Author
|
|
84
|
+
|
|
85
|
+
**Anthony Hoang**
|
|
86
|
+
|
|
87
|
+
- GitHub: [@anth0nycodes](https://github.com/anth0nycodes)
|
|
88
|
+
|
|
89
|
+
## Links
|
|
90
|
+
|
|
91
|
+
- [npm package](https://www.npmjs.com/package/@anth0nycodes/license-generator)
|
|
92
|
+
- [GitHub repository](https://github.com/anth0nycodes/license-generator)
|
|
93
|
+
- [Report issues](https://github.com/anth0nycodes/license-generator/issues)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAIA,wBAAgB,cAAc,WAG7B;AAED,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAO/D"}
|
package/dist/helpers.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
|
+
export function getGitUsername() {
|
|
5
|
+
const uncleanName = String(execSync("git config user.name"));
|
|
6
|
+
return uncleanName.replace(/\r?\n/g, "");
|
|
7
|
+
}
|
|
8
|
+
export async function fileExists(path) {
|
|
9
|
+
try {
|
|
10
|
+
await access(path, constants.F_OK);
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../src/helpers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,MAAM,UAAU,cAAc;IAC5B,MAAM,WAAW,GAAG,MAAM,CAAC,QAAQ,CAAC,sBAAsB,CAAC,CAAC,CAAC;IAC7D,OAAO,WAAW,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAY;IAC3C,IAAI,CAAC;QACH,MAAM,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { program } from "commander";
|
|
3
|
+
import { intro, select, isCancel, cancel } from "@clack/prompts";
|
|
4
|
+
import inquirer from "inquirer";
|
|
5
|
+
import { createLicense, getLicenseContent, getLicenses } from "./license.js";
|
|
6
|
+
import color from "picocolors";
|
|
7
|
+
import { getGitUsername } from "./helpers.js";
|
|
8
|
+
const main = async () => {
|
|
9
|
+
program
|
|
10
|
+
.name("License Generator")
|
|
11
|
+
.description("A CLI application that generates open-source licenses for your repositories.")
|
|
12
|
+
.version("0.1.0");
|
|
13
|
+
// TODO: Add options, so you can manually add a license flag like --license mit
|
|
14
|
+
program.parse();
|
|
15
|
+
intro(color.blueBright("License Generator"));
|
|
16
|
+
const BASE_URL = "https://api.github.com/licenses";
|
|
17
|
+
const licenses = await getLicenses();
|
|
18
|
+
// List all available licenses from github api
|
|
19
|
+
const licenseOption = await select({
|
|
20
|
+
message: "Select a license:",
|
|
21
|
+
options: licenses.map((license) => ({
|
|
22
|
+
value: license.key,
|
|
23
|
+
label: license.name,
|
|
24
|
+
})),
|
|
25
|
+
});
|
|
26
|
+
if (isCancel(licenseOption)) {
|
|
27
|
+
cancel("Operation cancelled.");
|
|
28
|
+
process.exit(0);
|
|
29
|
+
}
|
|
30
|
+
// Grab the inputs for name and year
|
|
31
|
+
let answers;
|
|
32
|
+
try {
|
|
33
|
+
answers = await inquirer.prompt([
|
|
34
|
+
{
|
|
35
|
+
type: "input",
|
|
36
|
+
name: "name",
|
|
37
|
+
message: "Enter name:",
|
|
38
|
+
default: getGitUsername(),
|
|
39
|
+
validate(value) {
|
|
40
|
+
if (value.length === 0)
|
|
41
|
+
return "Name is required";
|
|
42
|
+
return true;
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
type: "input",
|
|
47
|
+
name: "year",
|
|
48
|
+
message: "Enter year:",
|
|
49
|
+
default: String(new Date().getFullYear()),
|
|
50
|
+
validate(value) {
|
|
51
|
+
if (value.length === 0)
|
|
52
|
+
return "Year is required";
|
|
53
|
+
if (!/^\d{4}$/.test(value))
|
|
54
|
+
return "Please enter a valid year!";
|
|
55
|
+
return true;
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
]);
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
cancel("Operation cancelled.");
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
// Grab the content of the selected license
|
|
65
|
+
const licenseOptionContent = await getLicenseContent(`${BASE_URL}/${String(licenseOption)}`);
|
|
66
|
+
// Write LICENSE file
|
|
67
|
+
try {
|
|
68
|
+
await createLicense(licenseOptionContent, answers.year, answers.name);
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
console.error(`Error occurred in createLicense: ${error}`);
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
try {
|
|
76
|
+
main();
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
console.error(`Error in main: ${error}`);
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
interface LicenseShape {
|
|
2
|
+
key: string;
|
|
3
|
+
name: string;
|
|
4
|
+
spdx_id: string;
|
|
5
|
+
url: string;
|
|
6
|
+
node_id: string;
|
|
7
|
+
}
|
|
8
|
+
interface LicenseContentShape {
|
|
9
|
+
key: string;
|
|
10
|
+
name: string;
|
|
11
|
+
description: string;
|
|
12
|
+
permissions: string[];
|
|
13
|
+
conditions: string[];
|
|
14
|
+
limitations: string[];
|
|
15
|
+
body: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function getLicenses(): Promise<LicenseShape[]>;
|
|
18
|
+
export declare function getLicenseContent(url: string): Promise<LicenseContentShape>;
|
|
19
|
+
export declare function createLicense(content: LicenseContentShape, year: string, name: string): Promise<void>;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=license.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.d.ts","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"AAMA,UAAU,YAAY;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,mBAAmB;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAU3D;AAED,wBAAsB,iBAAiB,CACrC,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,mBAAmB,CAAC,CAgB9B;AAED,wBAAsB,aAAa,CACjC,OAAO,EAAE,mBAAmB,EAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,iBA2Bb"}
|
package/dist/license.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import color from "picocolors";
|
|
3
|
+
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { fileExists } from "./helpers.js";
|
|
5
|
+
import { cancel, confirm, spinner } from "@clack/prompts";
|
|
6
|
+
export async function getLicenses() {
|
|
7
|
+
try {
|
|
8
|
+
const { data } = await axios.get("https://api.github.com/licenses");
|
|
9
|
+
return data;
|
|
10
|
+
}
|
|
11
|
+
catch (error) {
|
|
12
|
+
console.error(`Error in getLicenses: ${error}`);
|
|
13
|
+
throw error;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function getLicenseContent(url) {
|
|
17
|
+
try {
|
|
18
|
+
const { data } = await axios.get(url);
|
|
19
|
+
return {
|
|
20
|
+
key: data.key,
|
|
21
|
+
name: data.name,
|
|
22
|
+
description: data.description,
|
|
23
|
+
permissions: data.permissions,
|
|
24
|
+
conditions: data.conditions,
|
|
25
|
+
limitations: data.limitations,
|
|
26
|
+
body: data.body,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
console.error(`Error in getLicenseContent: ${error}`);
|
|
31
|
+
throw error;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
export async function createLicense(content, year, name) {
|
|
35
|
+
let uncleanBody = content.body;
|
|
36
|
+
let body = uncleanBody
|
|
37
|
+
.replaceAll("[year]", year)
|
|
38
|
+
.replaceAll("[yyyy]", year)
|
|
39
|
+
.replaceAll("[fullname]", name)
|
|
40
|
+
.replaceAll("[name of copyright owner]", name)
|
|
41
|
+
.replaceAll("<year>", year)
|
|
42
|
+
.replaceAll("<name of author>", name);
|
|
43
|
+
if (await fileExists("LICENSE")) {
|
|
44
|
+
const shouldContinue = await confirm({
|
|
45
|
+
message: "LICENSE file already exists. Overwrite?",
|
|
46
|
+
});
|
|
47
|
+
if (!shouldContinue) {
|
|
48
|
+
cancel("Operation cancelled.");
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
const s = spinner();
|
|
53
|
+
s.start(color.yellow("Generating license..."));
|
|
54
|
+
await writeFile("LICENSE", body, "utf8");
|
|
55
|
+
s.stop(color.greenBright("License created!"));
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=license.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"license.js","sourceRoot":"","sources":["../src/license.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAC1B,OAAO,KAAK,MAAM,YAAY,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAC;AAoB1D,MAAM,CAAC,KAAK,UAAU,WAAW;IAC/B,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAA6B,MAAM,KAAK,CAAC,GAAG,CACxD,iCAAiC,CAClC,CAAC;QACF,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,KAAK,EAAE,CAAC,CAAC;QAChD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,GAAW;IAEX,IAAI,CAAC;QACH,MAAM,EAAE,IAAI,EAAE,GAAkC,MAAM,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACrE,OAAO;YACL,GAAG,EAAE,IAAI,CAAC,GAAG;YACb,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,UAAU,EAAE,IAAI,CAAC,UAAU;YAC3B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,IAAI,EAAE,IAAI,CAAC,IAAI;SAChB,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,+BAA+B,KAAK,EAAE,CAAC,CAAC;QACtD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,OAA4B,EAC5B,IAAY,EACZ,IAAY;IAEZ,IAAI,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAE/B,IAAI,IAAI,GAAG,WAAW;SACnB,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC;SAC1B,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC;SAC1B,UAAU,CAAC,YAAY,EAAE,IAAI,CAAC;SAC9B,UAAU,CAAC,2BAA2B,EAAE,IAAI,CAAC;SAC7C,UAAU,CAAC,QAAQ,EAAE,IAAI,CAAC;SAC1B,UAAU,CAAC,kBAAkB,EAAE,IAAI,CAAC,CAAC;IAExC,IAAI,MAAM,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAChC,MAAM,cAAc,GAAG,MAAM,OAAO,CAAC;YACnC,OAAO,EAAE,yCAAyC;SACnD,CAAC,CAAC;QAEH,IAAI,CAAC,cAAc,EAAE,CAAC;YACpB,MAAM,CAAC,sBAAsB,CAAC,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAED,MAAM,CAAC,GAAG,OAAO,EAAE,CAAC;IACpB,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,uBAAuB,CAAC,CAAC,CAAC;IAC/C,MAAM,SAAS,CAAC,SAAS,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,kBAAkB,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@anth0nycodes/license-generator",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "An open-source CLI tool to generate licenses for your repository.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"generate-license": "./dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [
|
|
11
|
+
"license",
|
|
12
|
+
"license-generator",
|
|
13
|
+
"license-cli",
|
|
14
|
+
"cli",
|
|
15
|
+
"open-source",
|
|
16
|
+
"oss",
|
|
17
|
+
"node",
|
|
18
|
+
"npm",
|
|
19
|
+
"npx",
|
|
20
|
+
"mit",
|
|
21
|
+
"apache-2.0",
|
|
22
|
+
"boilerplate",
|
|
23
|
+
"project-setup",
|
|
24
|
+
"scaffold"
|
|
25
|
+
],
|
|
26
|
+
"author": "Anthony Hoang",
|
|
27
|
+
"license": "ISC",
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "git+https://github.com/anth0nycodes/license-generator.git"
|
|
31
|
+
},
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/anth0nycodes/license-generator/issues"
|
|
34
|
+
},
|
|
35
|
+
"homepage": "https://github.com/anth0nycodes/license-generator#readme",
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@types/inquirer": "^9.0.9",
|
|
38
|
+
"@types/node": "^25.0.3",
|
|
39
|
+
"tsx": "^4.21.0",
|
|
40
|
+
"typescript": "^5.9.3"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@clack/prompts": "^0.11.0",
|
|
44
|
+
"axios": "^1.13.2",
|
|
45
|
+
"commander": "^14.0.2",
|
|
46
|
+
"inquirer": "^13.1.0",
|
|
47
|
+
"picocolors": "^1.1.1"
|
|
48
|
+
},
|
|
49
|
+
"scripts": {
|
|
50
|
+
"dev": "tsx src/index.ts",
|
|
51
|
+
"build": "tsc",
|
|
52
|
+
"start": "node dist/index.js",
|
|
53
|
+
"publish:npm": "pnpm publish --access public"
|
|
54
|
+
}
|
|
55
|
+
}
|
package/src/helpers.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { execSync } from "node:child_process";
|
|
2
|
+
import { constants } from "node:fs";
|
|
3
|
+
import { access } from "node:fs/promises";
|
|
4
|
+
|
|
5
|
+
export function getGitUsername() {
|
|
6
|
+
const uncleanName = String(execSync("git config user.name"));
|
|
7
|
+
return uncleanName.replace(/\r?\n/g, "");
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export async function fileExists(path: string): Promise<boolean> {
|
|
11
|
+
try {
|
|
12
|
+
await access(path, constants.F_OK);
|
|
13
|
+
return true;
|
|
14
|
+
} catch {
|
|
15
|
+
return false;
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
import { program } from "commander";
|
|
4
|
+
import { intro, select, isCancel, cancel } from "@clack/prompts";
|
|
5
|
+
import inquirer from "inquirer";
|
|
6
|
+
import { createLicense, getLicenseContent, getLicenses } from "./license.js";
|
|
7
|
+
import color from "picocolors";
|
|
8
|
+
import { getGitUsername } from "./helpers.js";
|
|
9
|
+
|
|
10
|
+
const main = async () => {
|
|
11
|
+
program
|
|
12
|
+
.name("License Generator")
|
|
13
|
+
.description(
|
|
14
|
+
"A CLI application that generates open-source licenses for your repositories.",
|
|
15
|
+
)
|
|
16
|
+
.version("0.1.0");
|
|
17
|
+
|
|
18
|
+
// TODO: Add options, so you can manually add a license flag like --license mit
|
|
19
|
+
|
|
20
|
+
program.parse();
|
|
21
|
+
|
|
22
|
+
intro(color.blueBright("License Generator"));
|
|
23
|
+
|
|
24
|
+
const BASE_URL = "https://api.github.com/licenses";
|
|
25
|
+
const licenses = await getLicenses();
|
|
26
|
+
|
|
27
|
+
// List all available licenses from github api
|
|
28
|
+
const licenseOption = await select({
|
|
29
|
+
message: "Select a license:",
|
|
30
|
+
options: licenses.map((license) => ({
|
|
31
|
+
value: license.key,
|
|
32
|
+
label: license.name,
|
|
33
|
+
})),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
if (isCancel(licenseOption)) {
|
|
37
|
+
cancel("Operation cancelled.");
|
|
38
|
+
process.exit(0);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Grab the inputs for name and year
|
|
42
|
+
let answers: { name: string; year: string };
|
|
43
|
+
|
|
44
|
+
try {
|
|
45
|
+
answers = await inquirer.prompt([
|
|
46
|
+
{
|
|
47
|
+
type: "input",
|
|
48
|
+
name: "name",
|
|
49
|
+
message: "Enter name:",
|
|
50
|
+
default: getGitUsername(),
|
|
51
|
+
validate(value) {
|
|
52
|
+
if (value.length === 0) return "Name is required";
|
|
53
|
+
return true;
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
type: "input",
|
|
58
|
+
name: "year",
|
|
59
|
+
message: "Enter year:",
|
|
60
|
+
default: String(new Date().getFullYear()),
|
|
61
|
+
validate(value) {
|
|
62
|
+
if (value.length === 0) return "Year is required";
|
|
63
|
+
if (!/^\d{4}$/.test(value)) return "Please enter a valid year!";
|
|
64
|
+
return true;
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
cancel("Operation cancelled.");
|
|
70
|
+
process.exit(0);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Grab the content of the selected license
|
|
74
|
+
const licenseOptionContent = await getLicenseContent(
|
|
75
|
+
`${BASE_URL}/${String(licenseOption)}`,
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Write LICENSE file
|
|
79
|
+
try {
|
|
80
|
+
await createLicense(licenseOptionContent, answers.year, answers.name);
|
|
81
|
+
} catch (error) {
|
|
82
|
+
console.error(`Error occurred in createLicense: ${error}`);
|
|
83
|
+
throw error;
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
main();
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error(`Error in main: ${error}`);
|
|
91
|
+
}
|
package/src/license.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import axios from "axios";
|
|
2
|
+
import color from "picocolors";
|
|
3
|
+
import { writeFile } from "node:fs/promises";
|
|
4
|
+
import { fileExists } from "./helpers.js";
|
|
5
|
+
import { cancel, confirm, spinner } from "@clack/prompts";
|
|
6
|
+
|
|
7
|
+
interface LicenseShape {
|
|
8
|
+
key: string;
|
|
9
|
+
name: string;
|
|
10
|
+
spdx_id: string;
|
|
11
|
+
url: string;
|
|
12
|
+
node_id: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
interface LicenseContentShape {
|
|
16
|
+
key: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
permissions: string[];
|
|
20
|
+
conditions: string[];
|
|
21
|
+
limitations: string[];
|
|
22
|
+
body: string;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export async function getLicenses(): Promise<LicenseShape[]> {
|
|
26
|
+
try {
|
|
27
|
+
const { data }: { data: LicenseShape[] } = await axios.get(
|
|
28
|
+
"https://api.github.com/licenses",
|
|
29
|
+
);
|
|
30
|
+
return data;
|
|
31
|
+
} catch (error) {
|
|
32
|
+
console.error(`Error in getLicenses: ${error}`);
|
|
33
|
+
throw error;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function getLicenseContent(
|
|
38
|
+
url: string,
|
|
39
|
+
): Promise<LicenseContentShape> {
|
|
40
|
+
try {
|
|
41
|
+
const { data }: { data: LicenseContentShape } = await axios.get(url);
|
|
42
|
+
return {
|
|
43
|
+
key: data.key,
|
|
44
|
+
name: data.name,
|
|
45
|
+
description: data.description,
|
|
46
|
+
permissions: data.permissions,
|
|
47
|
+
conditions: data.conditions,
|
|
48
|
+
limitations: data.limitations,
|
|
49
|
+
body: data.body,
|
|
50
|
+
};
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(`Error in getLicenseContent: ${error}`);
|
|
53
|
+
throw error;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export async function createLicense(
|
|
58
|
+
content: LicenseContentShape,
|
|
59
|
+
year: string,
|
|
60
|
+
name: string,
|
|
61
|
+
) {
|
|
62
|
+
let uncleanBody = content.body;
|
|
63
|
+
|
|
64
|
+
let body = uncleanBody
|
|
65
|
+
.replaceAll("[year]", year)
|
|
66
|
+
.replaceAll("[yyyy]", year)
|
|
67
|
+
.replaceAll("[fullname]", name)
|
|
68
|
+
.replaceAll("[name of copyright owner]", name)
|
|
69
|
+
.replaceAll("<year>", year)
|
|
70
|
+
.replaceAll("<name of author>", name);
|
|
71
|
+
|
|
72
|
+
if (await fileExists("LICENSE")) {
|
|
73
|
+
const shouldContinue = await confirm({
|
|
74
|
+
message: "LICENSE file already exists. Overwrite?",
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!shouldContinue) {
|
|
78
|
+
cancel("Operation cancelled.");
|
|
79
|
+
process.exit(0);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const s = spinner();
|
|
84
|
+
s.start(color.yellow("Generating license..."));
|
|
85
|
+
await writeFile("LICENSE", body, "utf8");
|
|
86
|
+
s.stop(color.greenBright("License created!"));
|
|
87
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ES2022",
|
|
5
|
+
"lib": ["ES2022"],
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"resolveJsonModule": true,
|
|
8
|
+
"allowJs": true,
|
|
9
|
+
"checkJs": false,
|
|
10
|
+
"outDir": "./dist",
|
|
11
|
+
"rootDir": "./src",
|
|
12
|
+
"strict": true,
|
|
13
|
+
"esModuleInterop": true,
|
|
14
|
+
"skipLibCheck": true,
|
|
15
|
+
"forceConsistentCasingInFileNames": true,
|
|
16
|
+
"declaration": true,
|
|
17
|
+
"declarationMap": true,
|
|
18
|
+
"sourceMap": true,
|
|
19
|
+
"types": ["node"]
|
|
20
|
+
},
|
|
21
|
+
"include": ["src/**/*", "license.ts"],
|
|
22
|
+
"exclude": ["node_modules", "dist"]
|
|
23
|
+
}
|