metascope 0.6.3 → 0.7.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/dist/.DS_Store +0 -0
- package/dist/bin/cli.js +283 -281
- package/dist/lib/package.js +1 -1
- package/dist/lib/sources/dependency-updates.js +12 -23
- package/dist/lib/sources/license-file.d.ts +1 -4
- package/dist/lib/sources/license-file.js +1 -4
- package/dist/lib/templates/frontmatter.d.ts +1 -1
- package/dist/lib/templates/index.d.ts +1 -1
- package/dist/lib/utilities/license-identification.d.ts +23 -0
- package/dist/lib/utilities/license-identification.js +127 -20
- package/package.json +14 -13
- package/readme.md +16 -16
package/dist/lib/package.js
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import { log } from "../log.js";
|
|
2
2
|
import { defineSource } from "../source.js";
|
|
3
|
-
import { exec } from "tinyexec";
|
|
4
3
|
import { z } from "zod";
|
|
5
|
-
import { fileURLToPath } from "node:url";
|
|
6
4
|
import { coerce, diff } from "semver";
|
|
5
|
+
import { updates } from "updates";
|
|
7
6
|
//#region src/lib/sources/dependency-updates.ts
|
|
8
7
|
const AGE_VALUE_UNIT_REGEX = /^(\d+)\s+(\w+)$/;
|
|
9
8
|
const depSchema = z.object({
|
|
@@ -14,19 +13,11 @@ const depSchema = z.object({
|
|
|
14
13
|
});
|
|
15
14
|
const updatesOutputSchema = z.object({ results: z.record(z.string(), z.record(z.string(), z.record(z.string(), depSchema))) });
|
|
16
15
|
/**
|
|
17
|
-
*
|
|
16
|
+
* Parse an age string from the `updates` CLI (via the `timerel` library) into
|
|
17
|
+
* fractional years.
|
|
18
18
|
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*/
|
|
22
|
-
function resolveUpdatesBinary() {
|
|
23
|
-
return fileURLToPath(import.meta.resolve("updates/dist/index.js"));
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* Parse an age string from the `updates` CLI (via the `timerel` library) into fractional years.
|
|
27
|
-
*
|
|
28
|
-
* Possible formats: "now", "<n> sec(s)", "<n> min(s)", "<n> hour(s)",
|
|
29
|
-
* "<n> day(s)", "<n> week(s)", "<n> month(s)", "<n> year(s)"
|
|
19
|
+
* Possible formats: "now", "<n> sec(s)", "<n> min(s)", "<n> hour(s)", "<n>
|
|
20
|
+
* day(s)", "<n> week(s)", "<n> month(s)", "<n> year(s)"
|
|
30
21
|
*/
|
|
31
22
|
function parseAgeToYears(age) {
|
|
32
23
|
if (age === "now") return 0;
|
|
@@ -52,8 +43,8 @@ function parseAgeToYears(age) {
|
|
|
52
43
|
}
|
|
53
44
|
}
|
|
54
45
|
/**
|
|
55
|
-
* Classify a version bump as major, minor, or patch using semver.
|
|
56
|
-
*
|
|
46
|
+
* Classify a version bump as major, minor, or patch using semver. Falls back to
|
|
47
|
+
* 'major' for non-semver versions (e.g. GitHub Actions tags).
|
|
57
48
|
*/
|
|
58
49
|
function classifyBump(oldVersion, newVersion) {
|
|
59
50
|
const oldSemver = coerce(oldVersion);
|
|
@@ -72,15 +63,13 @@ const dependencyUpdatesSource = defineSource({
|
|
|
72
63
|
key: "dependencyUpdates",
|
|
73
64
|
async parse(input) {
|
|
74
65
|
log.debug("Extracting dependency update information via updates...");
|
|
75
|
-
const result = await
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
"--json"
|
|
80
|
-
]);
|
|
66
|
+
const result = await updates({
|
|
67
|
+
files: [input],
|
|
68
|
+
json: true
|
|
69
|
+
});
|
|
81
70
|
let parsed;
|
|
82
71
|
try {
|
|
83
|
-
parsed = updatesOutputSchema.parse(
|
|
72
|
+
parsed = updatesOutputSchema.parse(result);
|
|
84
73
|
} catch {
|
|
85
74
|
log.debug("No dependency files found for updates analysis.");
|
|
86
75
|
return;
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import { OneOrMany, SourceRecord } from "../source.js";
|
|
2
|
+
import { LicenseMatch } from "../utilities/license-identification.js";
|
|
2
3
|
|
|
3
4
|
//#region src/lib/sources/license-file.d.ts
|
|
4
|
-
type LicenseMatch = {
|
|
5
|
-
/** Match confidence between 0 and 1. */confidence: number; /** SPDX license identifier (e.g. "MIT"). */
|
|
6
|
-
spdxId: string;
|
|
7
|
-
};
|
|
8
5
|
type LicenseFileData = OneOrMany<SourceRecord<LicenseMatch>> | undefined;
|
|
9
6
|
//#endregion
|
|
10
7
|
export { LicenseFileData };
|
|
@@ -13,10 +13,7 @@ const licenseFileSource = defineSource({
|
|
|
13
13
|
const match = identifyLicense(await readFile(resolve(context.options.path, input), "utf8"));
|
|
14
14
|
if (!match) return;
|
|
15
15
|
return {
|
|
16
|
-
data:
|
|
17
|
-
confidence: match.confidence,
|
|
18
|
-
spdxId: match.spdxId
|
|
19
|
-
},
|
|
16
|
+
data: match,
|
|
20
17
|
source: input
|
|
21
18
|
};
|
|
22
19
|
},
|
|
@@ -18,7 +18,7 @@ declare const frontmatter: Template<{
|
|
|
18
18
|
Public: boolean;
|
|
19
19
|
Fork: boolean;
|
|
20
20
|
Published: boolean;
|
|
21
|
-
Status: "
|
|
21
|
+
Status: "unknown" | "maintainer" | "author" | "observer";
|
|
22
22
|
Tags: string[] | null;
|
|
23
23
|
Aliases: (string | null | undefined)[] | null;
|
|
24
24
|
License: string[] | null;
|
|
@@ -157,7 +157,7 @@ declare const templates: {
|
|
|
157
157
|
Public: boolean;
|
|
158
158
|
Fork: boolean;
|
|
159
159
|
Published: boolean;
|
|
160
|
-
Status: "
|
|
160
|
+
Status: "unknown" | "maintainer" | "author" | "observer";
|
|
161
161
|
Tags: string[] | null;
|
|
162
162
|
Aliases: (string | null | undefined)[] | null;
|
|
163
163
|
License: string[] | null;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/lib/utilities/license-identification.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* License identification using Dice coefficient on bigrams.
|
|
4
|
+
*
|
|
5
|
+
* Compares plain-text license file content against the full SPDX license list
|
|
6
|
+
* to identify the best-matching SPDX license identifier. Returns a standard
|
|
7
|
+
* SPDX license URL (e.g. "https://spdx.org/licenses/MIT").
|
|
8
|
+
*
|
|
9
|
+
* Handles:
|
|
10
|
+
*
|
|
11
|
+
* - Canonical SPDX / vendor URLs embedded in pointer-style license files
|
|
12
|
+
* - Standard license texts (MIT, BSD, Apache, etc.)
|
|
13
|
+
* - GNU family licenses via header pattern matching (LGPL, AGPL)
|
|
14
|
+
* - Markdown-formatted license files (strips headings, tables, links)
|
|
15
|
+
* - YAML front matter stripping
|
|
16
|
+
*/
|
|
17
|
+
type LicenseMatch = {
|
|
18
|
+
/** Dice coefficient confidence score (0–1). */confidence: number; /** SPDX license identifier (e.g. "MIT", "Apache-2.0"). */
|
|
19
|
+
spdxId: string; /** SPDX license URL. */
|
|
20
|
+
spdxUrl: string;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { LicenseMatch };
|
|
@@ -8,19 +8,24 @@ import spdxLicenseList from "spdx-license-list/full.js";
|
|
|
8
8
|
* SPDX license URL (e.g. "https://spdx.org/licenses/MIT").
|
|
9
9
|
*
|
|
10
10
|
* Handles:
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
*
|
|
12
|
+
* - Canonical SPDX / vendor URLs embedded in pointer-style license files
|
|
13
|
+
* - Standard license texts (MIT, BSD, Apache, etc.)
|
|
14
|
+
* - GNU family licenses via header pattern matching (LGPL, AGPL)
|
|
15
|
+
* - Markdown-formatted license files (strips headings, tables, links)
|
|
16
|
+
* - YAML front matter stripping
|
|
15
17
|
*/
|
|
18
|
+
const SPDX_BASE_URL = "https://spdx.org/licenses/";
|
|
16
19
|
/** Minimum similarity score to consider a match. */
|
|
17
20
|
const CONFIDENCE_THRESHOLD = .75;
|
|
18
21
|
/**
|
|
19
|
-
* Identify the SPDX license that best matches the given text.
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
+
* Identify the SPDX license that best matches the given text. Returns the best
|
|
23
|
+
* match with confidence score, or undefined if no match exceeds the confidence
|
|
24
|
+
* threshold.
|
|
22
25
|
*/
|
|
23
26
|
function identifyLicense(text) {
|
|
27
|
+
const urlMatch = identifyByUrl(text);
|
|
28
|
+
if (urlMatch) return urlMatch;
|
|
24
29
|
const headerMatch = identifyByHeader(text);
|
|
25
30
|
if (headerMatch) return headerMatch;
|
|
26
31
|
const normalizedInput = normalizeInput(text);
|
|
@@ -29,17 +34,19 @@ function identifyLicense(text) {
|
|
|
29
34
|
const inputTotal = normalizedInput.length - 1;
|
|
30
35
|
let bestMatch;
|
|
31
36
|
let bestScore = 0;
|
|
32
|
-
for (const { bigramsMap, normalized, spdxId, totalBigrams } of getNormalizedLicenses()) {
|
|
37
|
+
for (const { bigramsMap, normalized, spdxId, spdxUrl, totalBigrams } of getNormalizedLicenses()) {
|
|
33
38
|
if (normalizedInput === normalized) return {
|
|
34
39
|
confidence: 1,
|
|
35
|
-
spdxId
|
|
40
|
+
spdxId,
|
|
41
|
+
spdxUrl
|
|
36
42
|
};
|
|
37
43
|
const score = diceCoefficientCached(inputBigramsMap, inputTotal, bigramsMap, totalBigrams);
|
|
38
44
|
if (score > bestScore) {
|
|
39
45
|
bestScore = score;
|
|
40
46
|
bestMatch = {
|
|
41
47
|
confidence: score,
|
|
42
|
-
spdxId
|
|
48
|
+
spdxId,
|
|
49
|
+
spdxUrl
|
|
43
50
|
};
|
|
44
51
|
if (bestScore > .98) break;
|
|
45
52
|
}
|
|
@@ -47,6 +54,21 @@ function identifyLicense(text) {
|
|
|
47
54
|
if (bestMatch && bestMatch.confidence >= CONFIDENCE_THRESHOLD) return bestMatch;
|
|
48
55
|
}
|
|
49
56
|
/**
|
|
57
|
+
* Convert an SPDX license identifier to its canonical SPDX URL.
|
|
58
|
+
*/
|
|
59
|
+
function spdxIdToUrl(spdxId) {
|
|
60
|
+
return `${SPDX_BASE_URL}${spdxId}`;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Resolve the canonical URL for an SPDX license ID. Prefers the upstream URL
|
|
64
|
+
* recorded in the SPDX list (e.g. `https://opensource.org/license/mit/`) and
|
|
65
|
+
* falls back to the SPDX registry URL for the handful of entries whose upstream
|
|
66
|
+
* URL is missing at runtime.
|
|
67
|
+
*/
|
|
68
|
+
function getLicenseUrl(spdxId) {
|
|
69
|
+
return spdxLicenseList[spdxId]?.url ?? spdxIdToUrl(spdxId);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
50
72
|
* Strip YAML front matter (--- delimited blocks at the start of a file).
|
|
51
73
|
*/
|
|
52
74
|
function stripFrontMatter(text) {
|
|
@@ -57,16 +79,15 @@ function stripFrontMatter(text) {
|
|
|
57
79
|
return text;
|
|
58
80
|
}
|
|
59
81
|
/**
|
|
60
|
-
* Normalize license text for comparison.
|
|
61
|
-
*
|
|
62
|
-
* remove URLs, lowercase.
|
|
82
|
+
* Normalize license text for comparison. Follows SPDX matching guidelines:
|
|
83
|
+
* collapse whitespace, strip copyright lines, remove URLs, lowercase.
|
|
63
84
|
*/
|
|
64
85
|
function normalizeText(text) {
|
|
65
86
|
return text.replaceAll(/^#+\s+/gm, "").replaceAll(/^copyright.*$/gim, "").replaceAll(/^\|.*\|$/gm, "").replaceAll(/^[-|:\s]+$/gm, "").replaceAll(/https?:\/\/\S+/g, "").replaceAll(/\S+@\S+/g, "").replaceAll(/[[\]()]/g, " ").replaceAll(/\s+/g, " ").trim().toLowerCase();
|
|
66
87
|
}
|
|
67
88
|
/**
|
|
68
|
-
* Normalize input text (user-provided license file).
|
|
69
|
-
*
|
|
89
|
+
* Normalize input text (user-provided license file). Applies additional cleanup
|
|
90
|
+
* beyond what reference texts need.
|
|
70
91
|
*/
|
|
71
92
|
function normalizeInput(text) {
|
|
72
93
|
return normalizeText(stripFrontMatter(text));
|
|
@@ -90,6 +111,7 @@ function getNormalizedLicenses() {
|
|
|
90
111
|
bigramsMap: computeBigrams(normalized),
|
|
91
112
|
normalized,
|
|
92
113
|
spdxId,
|
|
114
|
+
spdxUrl: getLicenseUrl(spdxId),
|
|
93
115
|
totalBigrams: normalized.length - 1
|
|
94
116
|
};
|
|
95
117
|
});
|
|
@@ -108,10 +130,10 @@ function diceCoefficientCached(inputBigrams, inputTotal, referenceBigrams, refer
|
|
|
108
130
|
}
|
|
109
131
|
/**
|
|
110
132
|
* Title-based identification for GNU licenses whose SPDX templates embed
|
|
111
|
-
* combined texts (e.g. LGPL-3.0-only = LGPL supplement + full GPL), making
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
133
|
+
* combined texts (e.g. LGPL-3.0-only = LGPL supplement + full GPL), making Dice
|
|
134
|
+
* coefficient unreliable against real-world standalone files. Only checks the
|
|
135
|
+
* first 500 characters to avoid matching references in unrelated license texts
|
|
136
|
+
* (e.g. CeCILL-2.1 mentions AGPL in its body).
|
|
115
137
|
*/
|
|
116
138
|
const HEADER_PATTERNS = [
|
|
117
139
|
{
|
|
@@ -135,8 +157,93 @@ function identifyByHeader(text) {
|
|
|
135
157
|
const header = text.slice(0, 500);
|
|
136
158
|
for (const { pattern, spdxId } of HEADER_PATTERNS) if (pattern.test(header)) return {
|
|
137
159
|
confidence: 1,
|
|
138
|
-
spdxId
|
|
160
|
+
spdxId,
|
|
161
|
+
spdxUrl: getLicenseUrl(spdxId)
|
|
139
162
|
};
|
|
140
163
|
}
|
|
164
|
+
/**
|
|
165
|
+
* Extracts `http(s)://...` URLs from the raw text, stripping trailing
|
|
166
|
+
* punctuation that commonly follows a URL in prose (`.`, `,`, `)`, `]`, etc.)
|
|
167
|
+
* but is not part of the URL itself.
|
|
168
|
+
*/
|
|
169
|
+
const URL_REGEX = /https?:\/\/[^\s<>"')\]}]+/gi;
|
|
170
|
+
/** Leading `www.` subdomain. */
|
|
171
|
+
const WWW_PREFIX_REGEX = /^www\./;
|
|
172
|
+
/** Trailing `/legalcode` or `/legalcode.<ext>` on Creative Commons URLs. */
|
|
173
|
+
const LEGALCODE_SUFFIX_REGEX = /\/legalcode(?:\.[a-z]+)?$/;
|
|
174
|
+
/** Trailing slashes. */
|
|
175
|
+
const TRAILING_SLASH_REGEX = /\/+$/;
|
|
176
|
+
/** Trailing prose punctuation after a URL extracted from text. */
|
|
177
|
+
const TRAILING_PUNCTUATION_REGEX = /[.,;:!?]+$/;
|
|
178
|
+
/**
|
|
179
|
+
* Normalize a URL for comparison: lowercase host+path, drop scheme, strip
|
|
180
|
+
* `www.`, strip trailing slashes, and strip trailing `/legalcode(.ext)?`
|
|
181
|
+
* suffixes used by Creative Commons canonical URLs.
|
|
182
|
+
*/
|
|
183
|
+
function normalizeUrl(url) {
|
|
184
|
+
let parsed;
|
|
185
|
+
try {
|
|
186
|
+
parsed = new URL(url.trim());
|
|
187
|
+
} catch {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
|
|
191
|
+
const host = parsed.hostname.toLowerCase().replace(WWW_PREFIX_REGEX, "");
|
|
192
|
+
let path = parsed.pathname.toLowerCase().replace(LEGALCODE_SUFFIX_REGEX, "");
|
|
193
|
+
path = path.replace(TRAILING_SLASH_REGEX, "");
|
|
194
|
+
return `${host}${path}`;
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Rank an SPDX ID by how "current" its form is, higher is preferred. Used to
|
|
198
|
+
* break ties when multiple IDs share a canonical URL.
|
|
199
|
+
*/
|
|
200
|
+
function scoreSpdxId(id) {
|
|
201
|
+
if (id.endsWith("+")) return 0;
|
|
202
|
+
if (id.endsWith("-only")) return 3;
|
|
203
|
+
if (id.endsWith("-or-later")) return 2;
|
|
204
|
+
return 1;
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* When multiple SPDX IDs share a canonical URL (typically deprecated legacy
|
|
208
|
+
* forms alongside current `-only` / `-or-later` variants), pick the current
|
|
209
|
+
* non-deprecated form.
|
|
210
|
+
*/
|
|
211
|
+
function preferSpdxId(a, b) {
|
|
212
|
+
const sa = scoreSpdxId(a);
|
|
213
|
+
const sb = scoreSpdxId(b);
|
|
214
|
+
if (sa !== sb) return sa > sb ? a : b;
|
|
215
|
+
return a < b ? a : b;
|
|
216
|
+
}
|
|
217
|
+
/** Lazy index of normalized URL → preferred SPDX ID. */
|
|
218
|
+
let urlIndex;
|
|
219
|
+
function getUrlIndex() {
|
|
220
|
+
if (urlIndex) return urlIndex;
|
|
221
|
+
const index = /* @__PURE__ */ new Map();
|
|
222
|
+
for (const [spdxId, entry] of Object.entries(spdxLicenseList)) {
|
|
223
|
+
index.set(`spdx.org/licenses/${spdxId.toLowerCase()}`, spdxId);
|
|
224
|
+
if (!entry.url) continue;
|
|
225
|
+
const normalized = normalizeUrl(entry.url);
|
|
226
|
+
if (!normalized) continue;
|
|
227
|
+
const existing = index.get(normalized);
|
|
228
|
+
index.set(normalized, existing ? preferSpdxId(existing, spdxId) : spdxId);
|
|
229
|
+
}
|
|
230
|
+
urlIndex = index;
|
|
231
|
+
return index;
|
|
232
|
+
}
|
|
233
|
+
function identifyByUrl(text) {
|
|
234
|
+
const matches = text.match(URL_REGEX);
|
|
235
|
+
if (!matches) return void 0;
|
|
236
|
+
const index = getUrlIndex();
|
|
237
|
+
for (const raw of matches) {
|
|
238
|
+
const normalized = normalizeUrl(raw.replace(TRAILING_PUNCTUATION_REGEX, ""));
|
|
239
|
+
if (!normalized) continue;
|
|
240
|
+
const spdxId = index.get(normalized);
|
|
241
|
+
if (spdxId) return {
|
|
242
|
+
confidence: 1,
|
|
243
|
+
spdxId,
|
|
244
|
+
spdxUrl: getLicenseUrl(spdxId)
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
141
248
|
//#endregion
|
|
142
249
|
export { identifyLicense };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "metascope",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "A CLI tool and TypeScript library to easily extract metadata from all kinds of software repositories.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"metadata",
|
|
@@ -44,14 +44,14 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@bacons/xcode": "1.0.0-alpha.33",
|
|
46
46
|
"@kitschpatrol/tokei": "^2.0.1",
|
|
47
|
-
"@sindresorhus/is": "^
|
|
47
|
+
"@sindresorhus/is": "^8.0.0",
|
|
48
48
|
"@types/mdast": "^4.0.4",
|
|
49
49
|
"@types/node": "~22.17.2",
|
|
50
50
|
"@types/plist": "^3.0.5",
|
|
51
51
|
"@types/yargs": "^17.0.35",
|
|
52
52
|
"case-police": "^2.2.0",
|
|
53
|
-
"defu": "^6.1.
|
|
54
|
-
"fast-xml-parser": "^5.5.
|
|
53
|
+
"defu": "^6.1.7",
|
|
54
|
+
"fast-xml-parser": "^5.5.11",
|
|
55
55
|
"find-workspaces": "^0.3.1",
|
|
56
56
|
"git-url-parse": "^16.1.0",
|
|
57
57
|
"gray-matter-es": "^0.2.1",
|
|
@@ -71,10 +71,10 @@
|
|
|
71
71
|
"smol-toml": "^1.6.1",
|
|
72
72
|
"spdx-license-list": "^6.11.0",
|
|
73
73
|
"string-ts": "^2.3.1",
|
|
74
|
-
"tinyexec": "^1.
|
|
75
|
-
"tinyglobby": "^0.2.
|
|
74
|
+
"tinyexec": "^1.1.1",
|
|
75
|
+
"tinyglobby": "^0.2.16",
|
|
76
76
|
"unified": "^11.0.5",
|
|
77
|
-
"updates": "^17.
|
|
77
|
+
"updates": "^17.14.0",
|
|
78
78
|
"web-tree-sitter": "^0.26.8",
|
|
79
79
|
"yaml": "^2.8.3",
|
|
80
80
|
"yargs": "^18.0.0",
|
|
@@ -83,21 +83,22 @@
|
|
|
83
83
|
"devDependencies": {
|
|
84
84
|
"@arethetypeswrong/core": "^0.18.2",
|
|
85
85
|
"@fast-csv/parse": "^5.0.5",
|
|
86
|
-
"@kitschpatrol/shared-config": "^7.
|
|
86
|
+
"@kitschpatrol/shared-config": "^7.3.0",
|
|
87
87
|
"@types/jsonld": "^1.5.15",
|
|
88
88
|
"@types/picomatch": "^4.0.3",
|
|
89
89
|
"@types/semver": "^7.7.1",
|
|
90
90
|
"bumpp": "^11.0.1",
|
|
91
91
|
"jsonld": "^9.0.0",
|
|
92
|
-
"mdat-plugin-cli-help": "^2.1.
|
|
92
|
+
"mdat-plugin-cli-help": "^2.1.2",
|
|
93
93
|
"msw": "2.12.14",
|
|
94
94
|
"publint": "^0.3.18",
|
|
95
|
+
"shx": "^0.4.0",
|
|
95
96
|
"tree-sitter-python": "^0.25.0",
|
|
96
97
|
"tree-sitter-ruby": "^0.23.1",
|
|
97
98
|
"tsdown": "^0.21.7",
|
|
98
99
|
"tsx": "^4.21.0",
|
|
99
|
-
"typescript": "~
|
|
100
|
-
"vitest": "^4.1.
|
|
100
|
+
"typescript": "~6.0.2",
|
|
101
|
+
"vitest": "^4.1.4"
|
|
101
102
|
},
|
|
102
103
|
"engines": {
|
|
103
104
|
"node": ">=22.17.0"
|
|
@@ -112,11 +113,11 @@
|
|
|
112
113
|
"bench": "vitest bench --run --no-file-parallelism --compare test/benchmarks/baseline.json",
|
|
113
114
|
"bench:baseline": "vitest bench --run --no-file-parallelism --outputJson test/benchmarks/baseline.json",
|
|
114
115
|
"build": "tsdown",
|
|
115
|
-
"clean": "
|
|
116
|
+
"clean": "shx rm -f pnpm-lock.yaml && git clean -fdX -e !.claude/",
|
|
116
117
|
"docs": "tsx ./scripts/generate-examples.ts && ksc-prettier fix ./docs",
|
|
117
118
|
"fix": "ksc fix",
|
|
118
119
|
"lint": "ksc lint",
|
|
119
|
-
"release": "bumpp --commit 'Release: %s' && pnpm
|
|
120
|
+
"release": "bumpp --commit 'Release: %s' && pnpm build && NPM_AUTH_TOKEN=$(op read 'op://Personal/npm/token') && pnpm publish",
|
|
120
121
|
"pretest": "tsx scripts/copy-grammars.ts",
|
|
121
122
|
"test": "vitest run",
|
|
122
123
|
"test:live": "METASCOPE_TEST_MOCK=false vitest run"
|
package/readme.md
CHANGED
|
@@ -108,21 +108,21 @@ metascope [path]
|
|
|
108
108
|
| ------------------- | ---------------------- | -------- | ------- |
|
|
109
109
|
| `path` | Project directory path | `string` | `"."` |
|
|
110
110
|
|
|
111
|
-
| Option | Description
|
|
112
|
-
| ---------------------- |
|
|
113
|
-
| `--template`<br>`-t` | Built-in template name (`codemeta`, `codemetaJson`, `frontmatter`, `metadata`, `project`) or path to a custom template file
|
|
114
|
-
| `--github-token` | GitHub API token (or set `$GITHUB_TOKEN`)
|
|
115
|
-
| `--author-name` | Optional author name(s) for ownership checks in templates
|
|
116
|
-
| `--github-account` | Optional GitHub account name(s) for ownership checks in templates
|
|
117
|
-
| `--absolute` | Output absolute paths. Use `--no-absolute` for relative paths.
|
|
118
|
-
| `--offline` | Skip sources requiring network requests
|
|
119
|
-
| `--sources`<br>`-s` | Only run specific metadata sources (defaults to all
|
|
120
|
-
| `--no-ignore` | Include files ignored by .gitignore in the file tree
|
|
121
|
-
| `--recursive`<br>`-r` | Search for metadata files recursively in subdirectories
|
|
122
|
-
| `--workspaces`<br>`-w` | Include workspace-specific metadata in monorepos; pass a `boolean` to enable or disable auto-detection, or pass one or more `string`s to explicitly define workspace paths
|
|
123
|
-
| `--verbose` | Run with verbose logging
|
|
124
|
-
| `--help`<br>`-h` | Show help
|
|
125
|
-
| `--version`<br>`-v` | Show version number
|
|
111
|
+
| Option | Description | Type | Default |
|
|
112
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------- | ------- |
|
|
113
|
+
| `--template`<br>`-t` | Built-in template name (`codemeta`, `codemetaJson`, `frontmatter`, `metadata`, `project`) or path to a custom template file | `string` | |
|
|
114
|
+
| `--github-token` | GitHub API token (or set `$GITHUB_TOKEN`) | `string` | |
|
|
115
|
+
| `--author-name` | Optional author name(s) for ownership checks in templates | `array` | |
|
|
116
|
+
| `--github-account` | Optional GitHub account name(s) for ownership checks in templates | `array` | |
|
|
117
|
+
| `--absolute` | Output absolute paths. Use `--no-absolute` for relative paths. | `boolean` | `true` |
|
|
118
|
+
| `--offline` | Skip sources requiring network requests | `boolean` | `false` |
|
|
119
|
+
| `--sources`<br>`-s` | Only run specific metadata sources (`arduino-library-properties`, `cinder-cinderblock-xml`, `codemeta-json`, `git-config`, `go-go-mod`, `go-goreleaser-yaml`, `java-pom-xml`, `license-file`, `metadata-file`, `metascope`, `node-package-json`, `obsidian-plugin-manifest-json`, `openframeworks-addon-config-mk`, `openframeworks-install-xml`, `processing-library-properties`, `processing-sketch-properties`, `publiccode-yaml`, `python-pkg-info`, `python-pyproject-toml`, `python-setup-cfg`, `python-setup-py`, `readme-file`, `ruby-gemspec`, `rust-cargo-toml`, `xcode-info-plist`, `xcode-project-pbxproj`, `github-actions`, `code-stats`, `dependency-updates`, `file-stats`, `git-stats`, `github`, `node-npm-registry`, `obsidian-plugin-registry`, `python-pypi-registry`); defaults to all | `array` | |
|
|
120
|
+
| `--no-ignore` | Include files ignored by .gitignore in the file tree | `boolean` | `false` |
|
|
121
|
+
| `--recursive`<br>`-r` | Search for metadata files recursively in subdirectories | `boolean` | `false` |
|
|
122
|
+
| `--workspaces`<br>`-w` | Include workspace-specific metadata in monorepos; pass a `boolean` to enable or disable auto-detection, or pass one or more `string`s to explicitly define workspace paths | | `true` |
|
|
123
|
+
| `--verbose` | Run with verbose logging | `boolean` | `false` |
|
|
124
|
+
| `--help`<br>`-h` | Show help | `boolean` | |
|
|
125
|
+
| `--version`<br>`-v` | Show version number | `boolean` | |
|
|
126
126
|
|
|
127
127
|
<!-- /cli-help -->
|
|
128
128
|
|
|
@@ -193,7 +193,7 @@ export default defineTemplate(({ codemetaJson, github, gitStats }) => {
|
|
|
193
193
|
Extract metadata from only the sources you need, skipping everything else for faster results:
|
|
194
194
|
|
|
195
195
|
```sh
|
|
196
|
-
metascope --sources
|
|
196
|
+
metascope --sources node-package-json git-stats
|
|
197
197
|
```
|
|
198
198
|
|
|
199
199
|
##### Pipe compact JSON to another tool
|