license-checker-plugin 1.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.
Files changed (45) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +239 -0
  3. package/dist/LicensePluginCore.d.ts +84 -0
  4. package/dist/LicensePluginCore.js +148 -0
  5. package/dist/LicenseWebpackPlugin.d.ts +11 -0
  6. package/dist/LicenseWebpackPlugin.js +53 -0
  7. package/dist/Recorder.d.ts +14 -0
  8. package/dist/Recorder.js +46 -0
  9. package/dist/ViteLicensePlugin.d.ts +16 -0
  10. package/dist/ViteLicensePlugin.js +54 -0
  11. package/dist/checker/BuiltInLicenseChecker.d.ts +27 -0
  12. package/dist/checker/BuiltInLicenseChecker.js +311 -0
  13. package/dist/checker/LicenseCache.d.ts +9 -0
  14. package/dist/checker/LicenseCache.js +22 -0
  15. package/dist/checker/LicenseDatabase.d.ts +8 -0
  16. package/dist/checker/LicenseDatabase.js +52 -0
  17. package/dist/formatter/Formatter.d.ts +4 -0
  18. package/dist/formatter/Formatter.js +2 -0
  19. package/dist/formatter/HtmlFormatter.d.ts +6 -0
  20. package/dist/formatter/HtmlFormatter.js +53 -0
  21. package/dist/formatter/JsonFormatter.d.ts +5 -0
  22. package/dist/formatter/JsonFormatter.js +17 -0
  23. package/dist/formatter/MarkdownFormatter.d.ts +5 -0
  24. package/dist/formatter/MarkdownFormatter.js +18 -0
  25. package/dist/formatter/TxtFormatter.d.ts +12 -0
  26. package/dist/formatter/TxtFormatter.js +49 -0
  27. package/dist/index.d.ts +11 -0
  28. package/dist/index.js +13 -0
  29. package/dist/model/LicenseBuildReport.d.ts +4 -0
  30. package/dist/model/LicenseBuildReport.js +2 -0
  31. package/dist/model/LicenseInfo.d.ts +17 -0
  32. package/dist/model/LicenseInfo.js +2 -0
  33. package/dist/model/PackageInfo.d.ts +13 -0
  34. package/dist/model/PackageInfo.js +2 -0
  35. package/dist/scanner/PackageResolver.d.ts +4 -0
  36. package/dist/scanner/PackageResolver.js +102 -0
  37. package/dist/scanner/PackageScanner.d.ts +9 -0
  38. package/dist/scanner/PackageScanner.js +56 -0
  39. package/dist/utils/fs.d.ts +3 -0
  40. package/dist/utils/fs.js +61 -0
  41. package/dist/utils/hash.d.ts +1 -0
  42. package/dist/utils/hash.js +7 -0
  43. package/dist/utils/path.d.ts +3 -0
  44. package/dist/utils/path.js +64 -0
  45. package/package.json +58 -0
@@ -0,0 +1,27 @@
1
+ export interface LicenseCheckerOptions {
2
+ start: string;
3
+ excludePrivatePackages?: boolean;
4
+ customFormat?: Record<string, unknown>;
5
+ }
6
+ export interface PackageLicenseInfo {
7
+ name?: string;
8
+ version?: string;
9
+ licenses?: string | string[];
10
+ licenseFile?: string;
11
+ licenseText?: string;
12
+ repository?: string;
13
+ publisher?: string;
14
+ email?: string;
15
+ url?: string;
16
+ homepage?: string;
17
+ private?: boolean;
18
+ path?: string;
19
+ copyright?: string;
20
+ }
21
+ export declare function normalizeLicense(license: string): string;
22
+ export declare function normalizeRepositoryUrl(repo: string): string;
23
+ export declare function parseAuthor(author: string | object | undefined): {
24
+ name?: string;
25
+ email?: string;
26
+ };
27
+ export declare function builtInLicenseChecker(options: LicenseCheckerOptions): Promise<Record<string, PackageLicenseInfo>>;
@@ -0,0 +1,311 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.normalizeLicense = normalizeLicense;
40
+ exports.normalizeRepositoryUrl = normalizeRepositoryUrl;
41
+ exports.parseAuthor = parseAuthor;
42
+ exports.builtInLicenseChecker = builtInLicenseChecker;
43
+ const promises_1 = require("fs/promises");
44
+ const path = __importStar(require("path"));
45
+ const spdx_expression_parse_1 = __importDefault(require("spdx-expression-parse"));
46
+ const LICENSE_BASENAMES = [
47
+ /^LICENSE$/i,
48
+ /^LICENSE\-\w+$/i,
49
+ /^LICENCE$/i,
50
+ /^LICENCE\-\w+$/i,
51
+ /^MIT-LICENSE$/i,
52
+ /^COPYING$/i,
53
+ /^COPYRIGHT$/i,
54
+ ];
55
+ const LICENSE_PATTERNS = [
56
+ [/permission is hereby granted, free of charge, to any person obtaining a copy of this software/i, 'MIT*'],
57
+ [/redistribution and use in source and binary forms, with or without modification, are permitted/i, 'BSD*'],
58
+ [/licensed under the apache license, version 2\.0/i, 'Apache-2.0*'],
59
+ [/apache license[\s\n]+version[\s\n]+2/i, 'Apache-2.0*'],
60
+ [/the isc license/i, 'ISC*'],
61
+ [/\bMIT\b/, 'MIT*'],
62
+ [/\bApache(?:\s+License)?\b/i, 'Apache*'],
63
+ [/\bBSD\b/, 'BSD*'],
64
+ [/\bISC\b/, 'ISC*'],
65
+ [/gnu general public license/i, 'GPL*'],
66
+ [/gnu lesser\/library general public license/i, 'LGPL*'],
67
+ [/cc0 1\.0 universal/i, 'CC0-1.0*'],
68
+ [/public domain/i, 'Public Domain'],
69
+ [/do what the f\*ck you want to public license/i, 'WTFPL*'],
70
+ ];
71
+ const COPYRIGHT_PATTERNS = [
72
+ /©?\s*copyright\s+(?:\(c\)\s*)?(\d{4}(?:\s*-\s*\d{4})?)\s+([^\n\r]+)/gi,
73
+ /©\s*(\d{4}(?:\s*-\s*\d{4})?)\s+([^\n\r]+)/gi,
74
+ ];
75
+ function normalizeLicense(license) {
76
+ try {
77
+ (0, spdx_expression_parse_1.default)(license);
78
+ return license;
79
+ }
80
+ catch {
81
+ return 'Custom';
82
+ }
83
+ }
84
+ function extractCopyright(content) {
85
+ const copyrightLines = [];
86
+ for (const pattern of COPYRIGHT_PATTERNS) {
87
+ let match;
88
+ while ((match = pattern.exec(content)) !== null) {
89
+ let copyright = match[0];
90
+ copyright = copyright.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
91
+ if (!copyrightLines.includes(copyright)) {
92
+ copyrightLines.push(copyright);
93
+ }
94
+ }
95
+ pattern.lastIndex = 0;
96
+ }
97
+ if (copyrightLines.length > 0) {
98
+ return copyrightLines[0];
99
+ }
100
+ return undefined;
101
+ }
102
+ async function findLicenseFile(packageDir) {
103
+ try {
104
+ const files = await (0, promises_1.readdir)(packageDir);
105
+ const candidates = [];
106
+ for (const file of files) {
107
+ const fullPath = path.join(packageDir, file);
108
+ try {
109
+ if (!(await (0, promises_1.stat)(fullPath)).isFile())
110
+ continue;
111
+ }
112
+ catch {
113
+ continue;
114
+ }
115
+ for (let i = 0; i < LICENSE_BASENAMES.length; i++) {
116
+ if (LICENSE_BASENAMES[i].test(file)) {
117
+ candidates.push({ file: fullPath, order: i });
118
+ break;
119
+ }
120
+ }
121
+ }
122
+ candidates.sort((a, b) => a.order - b.order);
123
+ return candidates.length > 0 ? candidates[0].file : null;
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
129
+ async function readPackageJson(packageJsonPath) {
130
+ try {
131
+ const content = await (0, promises_1.readFile)(packageJsonPath, 'utf-8');
132
+ return JSON.parse(content);
133
+ }
134
+ catch {
135
+ return null;
136
+ }
137
+ }
138
+ function getLicenseString(license) {
139
+ if (!license)
140
+ return undefined;
141
+ if (typeof license === 'string')
142
+ return license;
143
+ if (typeof license === 'object' && 'type' in license) {
144
+ return String(license.type);
145
+ }
146
+ return undefined;
147
+ }
148
+ function normalizeRepositoryUrl(repo) {
149
+ return repo
150
+ .replace(/^git\+https:\/\//, 'https://')
151
+ .replace(/^git:\/\//, 'https://')
152
+ .replace(/^git\+ssh:\/\/git@/, 'https://')
153
+ .replace(/^git\+ssh:\/\//, 'https://')
154
+ .replace(/\.git$/, '');
155
+ }
156
+ function getRepositoryUrl(repository) {
157
+ if (!repository)
158
+ return undefined;
159
+ if (typeof repository === 'string') {
160
+ let url = normalizeRepositoryUrl(repository);
161
+ const scpMatch = url.match(/^https:\/\/([^:/]+):(.+)$/);
162
+ if (scpMatch) {
163
+ url = `https://${scpMatch[1]}/${scpMatch[2]}`;
164
+ }
165
+ return url;
166
+ }
167
+ if (typeof repository === 'object' && 'url' in repository) {
168
+ return getRepositoryUrl(repository.url);
169
+ }
170
+ return undefined;
171
+ }
172
+ function parseAuthor(author) {
173
+ if (!author)
174
+ return {};
175
+ if (typeof author === 'string') {
176
+ const match = author.match(/^(.+?)(?:\s*<([^>]+)>)?$/);
177
+ if (match) {
178
+ return { name: match[1].trim(), email: match[2] };
179
+ }
180
+ return { name: author };
181
+ }
182
+ if (typeof author === 'object' && 'name' in author) {
183
+ const a = author;
184
+ return { name: a.name, email: a.email };
185
+ }
186
+ return {};
187
+ }
188
+ async function findPackages(startPath) {
189
+ const packages = [];
190
+ const nodeModulesPath = path.join(startPath, 'node_modules');
191
+ try {
192
+ await (0, promises_1.stat)(nodeModulesPath);
193
+ }
194
+ catch {
195
+ return packages;
196
+ }
197
+ try {
198
+ const entries = await (0, promises_1.readdir)(nodeModulesPath, { withFileTypes: true });
199
+ for (const entry of entries) {
200
+ if (!entry.isDirectory())
201
+ continue;
202
+ if (entry.name.startsWith('.'))
203
+ continue;
204
+ if (entry.name.startsWith('@')) {
205
+ const scopeDir = path.join(nodeModulesPath, entry.name);
206
+ try {
207
+ const scopeEntries = await (0, promises_1.readdir)(scopeDir, { withFileTypes: true });
208
+ for (const scopeEntry of scopeEntries) {
209
+ if (!scopeEntry.isDirectory())
210
+ continue;
211
+ const pkgPath = path.join(scopeDir, scopeEntry.name);
212
+ try {
213
+ await (0, promises_1.stat)(path.join(pkgPath, 'package.json'));
214
+ packages.push(pkgPath);
215
+ }
216
+ catch {
217
+ // Skip packages without package.json
218
+ }
219
+ }
220
+ }
221
+ catch {
222
+ // Ignore errors
223
+ }
224
+ }
225
+ else {
226
+ const pkgPath = path.join(nodeModulesPath, entry.name);
227
+ try {
228
+ await (0, promises_1.stat)(path.join(pkgPath, 'package.json'));
229
+ packages.push(pkgPath);
230
+ }
231
+ catch {
232
+ // Skip packages without package.json
233
+ }
234
+ }
235
+ }
236
+ }
237
+ catch {
238
+ // Ignore errors
239
+ }
240
+ return packages;
241
+ }
242
+ async function processPackage(packagePath, options) {
243
+ const packageJson = await readPackageJson(path.join(packagePath, 'package.json'));
244
+ if (!packageJson)
245
+ return null;
246
+ if (options.excludePrivatePackages && packageJson.private === true) {
247
+ return null;
248
+ }
249
+ let licenses;
250
+ if (packageJson.license) {
251
+ licenses = getLicenseString(packageJson.license);
252
+ }
253
+ else if (packageJson.licenses) {
254
+ if (Array.isArray(packageJson.licenses)) {
255
+ licenses = packageJson.licenses.map((l) => getLicenseString(l) || 'UNKNOWN').filter(Boolean);
256
+ }
257
+ else {
258
+ licenses = getLicenseString(packageJson.licenses);
259
+ }
260
+ }
261
+ const licenseFile = await findLicenseFile(packagePath);
262
+ let licenseText;
263
+ let copyright;
264
+ if (licenseFile && options.customFormat?.licenseText) {
265
+ try {
266
+ licenseText = await (0, promises_1.readFile)(licenseFile, 'utf-8');
267
+ copyright = extractCopyright(licenseText);
268
+ }
269
+ catch {
270
+ // Ignore errors
271
+ }
272
+ }
273
+ const authorInfo = parseAuthor(packageJson.author);
274
+ const name = packageJson.name || path.basename(packagePath);
275
+ const version = packageJson.version || '0.0.0';
276
+ return [
277
+ `${name}@${version}`,
278
+ {
279
+ name,
280
+ version,
281
+ licenses,
282
+ licenseFile: licenseFile || undefined,
283
+ licenseText,
284
+ copyright,
285
+ repository: getRepositoryUrl(packageJson.repository),
286
+ publisher: authorInfo.name,
287
+ email: authorInfo.email,
288
+ url: packageJson.homepage,
289
+ private: packageJson.private === true,
290
+ path: packagePath,
291
+ },
292
+ ];
293
+ }
294
+ async function builtInLicenseChecker(options) {
295
+ const startPath = path.resolve(options.start);
296
+ try {
297
+ await (0, promises_1.stat)(startPath);
298
+ }
299
+ catch {
300
+ throw new Error(`Path does not exist: ${startPath}`);
301
+ }
302
+ const packagePaths = await findPackages(startPath);
303
+ const results = await Promise.all(packagePaths.map((pkgPath) => processPackage(pkgPath, options)));
304
+ const packages = {};
305
+ for (const result of results) {
306
+ if (result) {
307
+ packages[result[0]] = result[1];
308
+ }
309
+ }
310
+ return packages;
311
+ }
@@ -0,0 +1,9 @@
1
+ import { LicenseInfo } from '../model/LicenseInfo';
2
+ export declare class LicenseCache {
3
+ private readonly cache;
4
+ set(packageKey: string, info: LicenseInfo): void;
5
+ get(packageKey: string): LicenseInfo | undefined;
6
+ has(packageKey: string): boolean;
7
+ getAll(): Map<string, LicenseInfo>;
8
+ clear(): void;
9
+ }
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LicenseCache = void 0;
4
+ class LicenseCache {
5
+ cache = new Map();
6
+ set(packageKey, info) {
7
+ this.cache.set(packageKey, info);
8
+ }
9
+ get(packageKey) {
10
+ return this.cache.get(packageKey);
11
+ }
12
+ has(packageKey) {
13
+ return this.cache.has(packageKey);
14
+ }
15
+ getAll() {
16
+ return new Map(this.cache);
17
+ }
18
+ clear() {
19
+ this.cache.clear();
20
+ }
21
+ }
22
+ exports.LicenseCache = LicenseCache;
@@ -0,0 +1,8 @@
1
+ import { LicenseInfo } from '../model/LicenseInfo';
2
+ export declare class LicenseDatabase {
3
+ private readonly cache;
4
+ private initialized;
5
+ private initializedPath;
6
+ initialize(startPath: string): Promise<void>;
7
+ getLicense(packageName: string, packageVersion: string): LicenseInfo;
8
+ }
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LicenseDatabase = void 0;
4
+ const BuiltInLicenseChecker_1 = require("./BuiltInLicenseChecker");
5
+ const LicenseCache_1 = require("./LicenseCache");
6
+ class LicenseDatabase {
7
+ cache = new LicenseCache_1.LicenseCache();
8
+ initialized = false;
9
+ initializedPath = null;
10
+ async initialize(startPath) {
11
+ if (this.initialized && this.initializedPath === startPath) {
12
+ return;
13
+ }
14
+ this.cache.clear();
15
+ this.initialized = false;
16
+ const packages = await (0, BuiltInLicenseChecker_1.builtInLicenseChecker)({
17
+ start: startPath,
18
+ excludePrivatePackages: false,
19
+ customFormat: {
20
+ licenseText: true,
21
+ },
22
+ });
23
+ for (const [key, info] of Object.entries(packages ?? {})) {
24
+ let licenseStr = 'UNKNOWN';
25
+ if (info.licenses) {
26
+ if (Array.isArray(info.licenses)) {
27
+ const joined = info.licenses.join(' AND ');
28
+ licenseStr = (0, BuiltInLicenseChecker_1.normalizeLicense)(joined);
29
+ }
30
+ else {
31
+ licenseStr = info.licenses;
32
+ if (licenseStr !== 'UNKNOWN') {
33
+ licenseStr = (0, BuiltInLicenseChecker_1.normalizeLicense)(licenseStr);
34
+ }
35
+ }
36
+ }
37
+ const licenseText = typeof info.licenseText === 'string' && info.licenseText.length > 0 ? info.licenseText : undefined;
38
+ const licenseInfo = {
39
+ license: licenseStr,
40
+ licenseFile: info.licenseFile,
41
+ licenseText,
42
+ };
43
+ this.cache.set(key, licenseInfo);
44
+ }
45
+ this.initialized = true;
46
+ this.initializedPath = startPath;
47
+ }
48
+ getLicense(packageName, packageVersion) {
49
+ return this.cache.get(`${packageName}@${packageVersion}`) || { license: 'UNKNOWN' };
50
+ }
51
+ }
52
+ exports.LicenseDatabase = LicenseDatabase;
@@ -0,0 +1,4 @@
1
+ import { OutputItem } from '../model/LicenseInfo';
2
+ export interface Formatter {
3
+ generate(items: OutputItem[]): string;
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,6 @@
1
+ import { OutputItem } from '../model/LicenseInfo';
2
+ import { Formatter } from './Formatter';
3
+ export declare class HtmlFormatter implements Formatter {
4
+ generate(items: OutputItem[]): string;
5
+ private escape;
6
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.HtmlFormatter = void 0;
4
+ class HtmlFormatter {
5
+ generate(items) {
6
+ const rows = items
7
+ .map((item) => {
8
+ const name = this.escape(item.package.name);
9
+ const version = this.escape(item.package.version);
10
+ const license = this.escape(item.license.license);
11
+ const licenseText = item.license.licenseText
12
+ ? `<details><summary>View License</summary><pre>${this.escape(item.license.licenseText)}</pre></details>`
13
+ : '';
14
+ return ` <tr>\n <td>${name}</td>\n <td>${version}</td>\n <td>${license}</td>\n <td>${licenseText}</td>\n </tr>`;
15
+ })
16
+ .join('\n');
17
+ return `<!DOCTYPE html>
18
+ <html lang="en">
19
+ <head>
20
+ <meta charset="UTF-8">
21
+ <title>Third Party Licenses</title>
22
+ <style>
23
+ body { font-family: sans-serif; margin: 2em; }
24
+ table { border-collapse: collapse; width: 100%; }
25
+ th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }
26
+ th { background: #f5f5f5; }
27
+ pre { white-space: pre-wrap; word-break: break-word; max-height: 200px; overflow-y: auto; }
28
+ </style>
29
+ </head>
30
+ <body>
31
+ <h1>Third Party Licenses</h1>
32
+ <table>
33
+ <thead>
34
+ <tr><th>Package</th><th>Version</th><th>License</th><th>License Text</th></tr>
35
+ </thead>
36
+ <tbody>
37
+ ${rows}
38
+ </tbody>
39
+ </table>
40
+ </body>
41
+ </html>
42
+ `;
43
+ }
44
+ escape(str) {
45
+ return str
46
+ .replace(/&/g, '&amp;')
47
+ .replace(/</g, '&lt;')
48
+ .replace(/>/g, '&gt;')
49
+ .replace(/"/g, '&quot;')
50
+ .replace(/'/g, '&#039;');
51
+ }
52
+ }
53
+ exports.HtmlFormatter = HtmlFormatter;
@@ -0,0 +1,5 @@
1
+ import { OutputItem } from '../model/LicenseInfo';
2
+ import { Formatter } from './Formatter';
3
+ export declare class JsonFormatter implements Formatter {
4
+ generate(items: OutputItem[]): string;
5
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.JsonFormatter = void 0;
4
+ class JsonFormatter {
5
+ generate(items) {
6
+ const result = items.map((item) => ({
7
+ name: item.package.name,
8
+ version: item.package.version,
9
+ license: item.license.license,
10
+ repository: item.package.repository,
11
+ homepage: item.package.homepage,
12
+ author: item.package.author,
13
+ }));
14
+ return JSON.stringify(result, null, 2);
15
+ }
16
+ }
17
+ exports.JsonFormatter = JsonFormatter;
@@ -0,0 +1,5 @@
1
+ import { OutputItem } from '../model/LicenseInfo';
2
+ import { Formatter } from './Formatter';
3
+ export declare class MarkdownFormatter implements Formatter {
4
+ generate(items: OutputItem[]): string;
5
+ }
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MarkdownFormatter = void 0;
4
+ class MarkdownFormatter {
5
+ generate(items) {
6
+ const lines = [
7
+ '# Third Party Licenses',
8
+ '',
9
+ '| Package | Version | License |',
10
+ '|---------|---------|---------|',
11
+ ];
12
+ for (const item of items) {
13
+ lines.push(`| ${item.package.name} | ${item.package.version} | ${item.license.license} |`);
14
+ }
15
+ return `${lines.join('\n')}\n`;
16
+ }
17
+ }
18
+ exports.MarkdownFormatter = MarkdownFormatter;
@@ -0,0 +1,12 @@
1
+ import { OutputItem } from '../model/LicenseInfo';
2
+ import { Formatter } from './Formatter';
3
+ export interface TxtFormatterOptions {
4
+ includeLicenseText?: boolean;
5
+ }
6
+ export declare class TxtFormatter implements Formatter {
7
+ private readonly options;
8
+ constructor(options?: TxtFormatterOptions);
9
+ generate(items: OutputItem[]): string;
10
+ private formatField;
11
+ private formatAuthor;
12
+ }
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TxtFormatter = void 0;
4
+ class TxtFormatter {
5
+ options;
6
+ constructor(options = {}) {
7
+ this.options = options;
8
+ }
9
+ generate(items) {
10
+ const lines = ['# THIRD-PARTY LICENSES', ''];
11
+ const labelWidth = 'Package Name'.length;
12
+ items.forEach((item, index) => {
13
+ // Keep labels aligned to improve readability in plain text outputs and diffs.
14
+ lines.push(this.formatField('Package Name', item.package.name, labelWidth));
15
+ lines.push(this.formatField('Version', item.package.version, labelWidth));
16
+ lines.push(this.formatField('License', item.license.license, labelWidth));
17
+ if (item.package.repository) {
18
+ lines.push(this.formatField('Repository', item.package.repository, labelWidth));
19
+ }
20
+ if (item.package.author) {
21
+ lines.push(this.formatField('Author', this.formatAuthor(item.package.author), labelWidth));
22
+ }
23
+ if (this.options.includeLicenseText !== false && item.license.licenseText) {
24
+ lines.push('');
25
+ // Keep license bodies in a separate block because they are multi-line and don't fit label-value alignment.
26
+ lines.push('License Text:');
27
+ lines.push(item.license.licenseText);
28
+ }
29
+ if (index < items.length - 1) {
30
+ lines.push('');
31
+ lines.push('---');
32
+ lines.push('');
33
+ }
34
+ });
35
+ return `${lines.join('\n')}\n`;
36
+ }
37
+ formatField(label, value, width) {
38
+ return `${label.padEnd(width)} : ${value}`;
39
+ }
40
+ formatAuthor(author) {
41
+ const match = author.match(/^(.*)\s*<([^>]+)>$/);
42
+ if (!match)
43
+ return author.trim();
44
+ const name = match[1].trim();
45
+ const email = match[2].trim();
46
+ return name ? `${name} <a>${email}</a>` : `<a>${email}</a>`;
47
+ }
48
+ }
49
+ exports.TxtFormatter = TxtFormatter;
@@ -0,0 +1,11 @@
1
+ export { LicenseWebpackPlugin } from './LicenseWebpackPlugin';
2
+ export { LicensePluginCore } from './LicensePluginCore';
3
+ export { viteLicensePlugin } from './ViteLicensePlugin';
4
+ export { normalizeLicense } from './checker/BuiltInLicenseChecker';
5
+ export type { LicensePluginOptions, OutputFormat, LicensePluginContext } from './LicensePluginCore';
6
+ export type { LicenseWebpackPluginOptions, OutputFormat as WebpackOutputFormat } from './LicenseWebpackPlugin';
7
+ export type { PackageInfo } from './model/PackageInfo';
8
+ export type { LicenseInfo, OutputItem } from './model/LicenseInfo';
9
+ export type { LicenseBuildReport } from './model/LicenseBuildReport';
10
+ export type { Recorder } from './Recorder';
11
+ export { DefaultRecorder } from './Recorder';
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DefaultRecorder = exports.normalizeLicense = exports.viteLicensePlugin = exports.LicensePluginCore = exports.LicenseWebpackPlugin = void 0;
4
+ var LicenseWebpackPlugin_1 = require("./LicenseWebpackPlugin");
5
+ Object.defineProperty(exports, "LicenseWebpackPlugin", { enumerable: true, get: function () { return LicenseWebpackPlugin_1.LicenseWebpackPlugin; } });
6
+ var LicensePluginCore_1 = require("./LicensePluginCore");
7
+ Object.defineProperty(exports, "LicensePluginCore", { enumerable: true, get: function () { return LicensePluginCore_1.LicensePluginCore; } });
8
+ var ViteLicensePlugin_1 = require("./ViteLicensePlugin");
9
+ Object.defineProperty(exports, "viteLicensePlugin", { enumerable: true, get: function () { return ViteLicensePlugin_1.viteLicensePlugin; } });
10
+ var BuiltInLicenseChecker_1 = require("./checker/BuiltInLicenseChecker");
11
+ Object.defineProperty(exports, "normalizeLicense", { enumerable: true, get: function () { return BuiltInLicenseChecker_1.normalizeLicense; } });
12
+ var Recorder_1 = require("./Recorder");
13
+ Object.defineProperty(exports, "DefaultRecorder", { enumerable: true, get: function () { return Recorder_1.DefaultRecorder; } });
@@ -0,0 +1,4 @@
1
+ import { OutputItem } from './LicenseInfo';
2
+ export interface LicenseBuildReport {
3
+ items: OutputItem[];
4
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,17 @@
1
+ import { PackageInfo } from './PackageInfo';
2
+ /** License metadata for a single package. */
3
+ export interface LicenseInfo {
4
+ /** SPDX license identifier(s) joined by ` AND ` for multiple licenses. */
5
+ license: string;
6
+ /** Path to the license file on disk, if found. */
7
+ licenseFile?: string;
8
+ /** Full license text content, if available and requested. */
9
+ licenseText?: string;
10
+ }
11
+ /** A single entry in the final license report. */
12
+ export interface OutputItem {
13
+ /** Package identity and metadata discovered by the bundler scanner. */
14
+ package: PackageInfo;
15
+ /** License information resolved from the package's `node_modules` entry. */
16
+ license: LicenseInfo;
17
+ }