metascope 0.7.0 → 0.7.1

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 (61) hide show
  1. package/dist/bin/chunk-Bdh3yLIe.js +1 -0
  2. package/dist/bin/cli.js +271 -272
  3. package/dist/bin/dns-CUigd8AG.js +1 -0
  4. package/dist/bin/{jiti-D2Njwwqq.js → jiti-BTBDwj9g.js} +2 -2
  5. package/dist/bin/renovate-DecR7mby.js +1 -0
  6. package/dist/bin/shared-C_yS1qGF.js +5 -0
  7. package/dist/lib/file-matching.js +20 -13
  8. package/dist/lib/log.d.ts +6 -4
  9. package/dist/lib/log.js +5 -3
  10. package/dist/lib/metadata-types.d.ts +33 -21
  11. package/dist/lib/metadata-types.js +8 -9
  12. package/dist/lib/metadata.js +7 -7
  13. package/dist/lib/package.js +1 -1
  14. package/dist/lib/parsers/gemspec-parser.js +16 -14
  15. package/dist/lib/parsers/go-mod-parser.js +13 -10
  16. package/dist/lib/parsers/makefile-config-parser.js +20 -17
  17. package/dist/lib/parsers/properties-parser.js +3 -3
  18. package/dist/lib/parsers/rfc822-header-parser.js +4 -4
  19. package/dist/lib/parsers/setup-py-parser.js +3 -4
  20. package/dist/lib/source.d.ts +1 -0
  21. package/dist/lib/source.js +5 -4
  22. package/dist/lib/sources/arduino-library-properties.js +32 -15
  23. package/dist/lib/sources/cinder-cinderblock-xml.js +21 -9
  24. package/dist/lib/sources/codemeta-json.js +24 -20
  25. package/dist/lib/sources/git-stats.js +1 -1
  26. package/dist/lib/sources/github-actions.js +9 -2
  27. package/dist/lib/sources/github.js +1 -1
  28. package/dist/lib/sources/go-goreleaser-yaml.js +5 -4
  29. package/dist/lib/sources/java-pom-xml.js +38 -19
  30. package/dist/lib/sources/metadata-file.js +15 -12
  31. package/dist/lib/sources/node-npm-registry.js +1 -1
  32. package/dist/lib/sources/openframeworks-addon-config-mk.js +7 -0
  33. package/dist/lib/sources/openframeworks-install-xml.js +24 -14
  34. package/dist/lib/sources/processing-library-properties.js +25 -10
  35. package/dist/lib/sources/processing-sketch-properties.js +51 -7
  36. package/dist/lib/sources/publiccode-yaml.js +37 -5
  37. package/dist/lib/sources/python-pkg-info.js +2 -2
  38. package/dist/lib/sources/python-setup-cfg.js +2 -2
  39. package/dist/lib/sources/readme-file.js +9 -2
  40. package/dist/lib/sources/ruby-gemspec.js +1 -0
  41. package/dist/lib/sources/rust-cargo-toml.js +29 -10
  42. package/dist/lib/sources/xcode-info-plist.js +48 -24
  43. package/dist/lib/sources/xcode-project-pbxproj.js +22 -12
  44. package/dist/lib/templates/codemeta-json.d.ts +4 -5
  45. package/dist/lib/templates/codemeta-json.js +4 -5
  46. package/dist/lib/templates/codemeta.js +30 -30
  47. package/dist/lib/templates/metadata.d.ts +2 -2
  48. package/dist/lib/templates/metadata.js +3 -3
  49. package/dist/lib/utilities/codemeta-helpers.d.ts +3 -2
  50. package/dist/lib/utilities/codemeta-helpers.js +14 -12
  51. package/dist/lib/utilities/fetch.js +2 -2
  52. package/dist/lib/utilities/formatting.js +4 -3
  53. package/dist/lib/utilities/github.js +3 -3
  54. package/dist/lib/utilities/license-identification.d.ts +3 -1
  55. package/dist/lib/utilities/license-identification.js +21 -25
  56. package/dist/lib/utilities/schema-primitives.js +11 -10
  57. package/dist/lib/utilities/template-helpers.js +3 -3
  58. package/package.json +12 -12
  59. package/readme.md +7 -3
  60. package/dist/.DS_Store +0 -0
  61. package/dist/bin/chunk-BjEoQXZ0.js +0 -1
@@ -29,31 +29,36 @@ function identifyLicense(text) {
29
29
  const headerMatch = identifyByHeader(text);
30
30
  if (headerMatch) return headerMatch;
31
31
  const normalizedInput = normalizeInput(text);
32
- if (normalizedInput.length < 2) return void 0;
32
+ if (normalizedInput.length < 2) return;
33
33
  const inputBigramsMap = computeBigrams(normalizedInput);
34
34
  const inputTotal = normalizedInput.length - 1;
35
35
  let bestMatch;
36
36
  let bestScore = 0;
37
- for (const { bigramsMap, normalized, spdxId, spdxUrl, totalBigrams } of getNormalizedLicenses()) {
38
- if (normalizedInput === normalized) return {
39
- confidence: 1,
40
- spdxId,
41
- spdxUrl
42
- };
37
+ for (const { bigramsMap, normalized, spdxId, totalBigrams } of getNormalizedLicenses()) {
38
+ if (normalizedInput === normalized) return buildMatch(spdxId, 1);
43
39
  const score = diceCoefficientCached(inputBigramsMap, inputTotal, bigramsMap, totalBigrams);
44
40
  if (score > bestScore) {
45
41
  bestScore = score;
46
- bestMatch = {
47
- confidence: score,
48
- spdxId,
49
- spdxUrl
50
- };
42
+ bestMatch = buildMatch(spdxId, score);
51
43
  if (bestScore > .98) break;
52
44
  }
53
45
  }
54
46
  if (bestMatch && bestMatch.confidence >= CONFIDENCE_THRESHOLD) return bestMatch;
55
47
  }
56
48
  /**
49
+ * Build a LicenseMatch for the given SPDX ID with the supplied confidence.
50
+ */
51
+ function buildMatch(spdxId, confidence) {
52
+ const entry = spdxLicenseList[spdxId];
53
+ return {
54
+ confidence,
55
+ name: entry.name,
56
+ osiApproved: entry.osiApproved,
57
+ spdxId,
58
+ spdxUrl: getLicenseUrl(spdxId)
59
+ };
60
+ }
61
+ /**
57
62
  * Convert an SPDX license identifier to its canonical SPDX URL.
58
63
  */
59
64
  function spdxIdToUrl(spdxId) {
@@ -111,7 +116,6 @@ function getNormalizedLicenses() {
111
116
  bigramsMap: computeBigrams(normalized),
112
117
  normalized,
113
118
  spdxId,
114
- spdxUrl: getLicenseUrl(spdxId),
115
119
  totalBigrams: normalized.length - 1
116
120
  };
117
121
  });
@@ -155,11 +159,7 @@ const HEADER_PATTERNS = [
155
159
  ];
156
160
  function identifyByHeader(text) {
157
161
  const header = text.slice(0, 500);
158
- for (const { pattern, spdxId } of HEADER_PATTERNS) if (pattern.test(header)) return {
159
- confidence: 1,
160
- spdxId,
161
- spdxUrl: getLicenseUrl(spdxId)
162
- };
162
+ for (const { pattern, spdxId } of HEADER_PATTERNS) if (pattern.test(header)) return buildMatch(spdxId, 1);
163
163
  }
164
164
  /**
165
165
  * Extracts `http(s)://...` URLs from the raw text, stripping trailing
@@ -187,7 +187,7 @@ function normalizeUrl(url) {
187
187
  } catch {
188
188
  return;
189
189
  }
190
- if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return void 0;
190
+ if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return;
191
191
  const host = parsed.hostname.toLowerCase().replace(WWW_PREFIX_REGEX, "");
192
192
  let path = parsed.pathname.toLowerCase().replace(LEGALCODE_SUFFIX_REGEX, "");
193
193
  path = path.replace(TRAILING_SLASH_REGEX, "");
@@ -232,17 +232,13 @@ function getUrlIndex() {
232
232
  }
233
233
  function identifyByUrl(text) {
234
234
  const matches = text.match(URL_REGEX);
235
- if (!matches) return void 0;
235
+ if (!matches) return;
236
236
  const index = getUrlIndex();
237
237
  for (const raw of matches) {
238
238
  const normalized = normalizeUrl(raw.replace(TRAILING_PUNCTUATION_REGEX, ""));
239
239
  if (!normalized) continue;
240
240
  const spdxId = index.get(normalized);
241
- if (spdxId) return {
242
- confidence: 1,
243
- spdxId,
244
- spdxUrl: getLicenseUrl(spdxId)
245
- };
241
+ if (spdxId) return buildMatch(spdxId, 1);
246
242
  }
247
243
  }
248
244
  //#endregion
@@ -5,13 +5,14 @@ import { z } from "zod";
5
5
  * Shared Zod schema primitives for parser schemas.
6
6
  *
7
7
  * These handle common coercions:
8
- * - Empty/whitespace-only strings → undefined
9
- * - URL validation with empty → undefined fallback
10
- * - String arrays with empty-element filtering
8
+ *
9
+ * - Empty/whitespace-only strings → undefined
10
+ * - URL validation with empty → undefined fallback
11
+ * - String arrays with empty-element filtering
11
12
  */
12
13
  /**
13
- * A string that treats empty or whitespace-only values as undefined.
14
- * Use `.optional()` on the result for optional fields.
14
+ * A string that treats empty or whitespace-only values as undefined. Use
15
+ * `.optional()` on the result for optional fields.
15
16
  */
16
17
  const nonEmptyString = z.preprocess((value) => {
17
18
  if (typeof value !== "string") return;
@@ -19,9 +20,9 @@ const nonEmptyString = z.preprocess((value) => {
19
20
  return trimmed.length > 0 ? trimmed : void 0;
20
21
  }, z.string().optional());
21
22
  /**
22
- * A URL string that treats empty/whitespace as undefined.
23
- * Does not reject invalid URLs — just ensures non-empty.
24
- * Use z.url() in place of this if strict URL validation is desired.
23
+ * A URL string that treats empty/whitespace as undefined. Does not reject
24
+ * invalid URLs — just ensures non-empty. Use z.url() in place of this if strict
25
+ * URL validation is desired.
25
26
  */
26
27
  const optionalUrl = nonEmptyString.describe("A URL string");
27
28
  /**
@@ -32,8 +33,8 @@ const stringArray = z.preprocess((value) => {
32
33
  return value.filter((item) => typeof item === "string" && item.trim().length > 0);
33
34
  }, z.array(z.string()));
34
35
  /**
35
- * Parse a JSON string into a plain object.
36
- * Returns `undefined` for malformed JSON or non-object values (arrays, primitives).
36
+ * Parse a JSON string into a plain object. Returns `undefined` for malformed
37
+ * JSON or non-object values (arrays, primitives).
37
38
  */
38
39
  function parseJsonRecord(content) {
39
40
  try {
@@ -53,7 +53,7 @@ const casePoliceDict = {
53
53
  * regardless of cardinality.
54
54
  */
55
55
  function firstOf(value) {
56
- if (value === void 0) return void 0;
56
+ if (value === void 0) return;
57
57
  return Array.isArray(value) ? value[0] : value;
58
58
  }
59
59
  /**
@@ -104,7 +104,7 @@ function splitCommaSeparated(value) {
104
104
  * Join an array of strings with a delimiter, filtering out undefined values.
105
105
  */
106
106
  function toDelimitedString(source, delimiter = ", ") {
107
- if (source === void 0) return void 0;
107
+ if (source === void 0) return;
108
108
  if (Array.isArray(source)) {
109
109
  const filtered = source.filter((s) => s !== void 0);
110
110
  return filtered.length > 0 ? filtered.join(delimiter) : void 0;
@@ -213,7 +213,7 @@ function stripUndefined(value) {
213
213
  hasKeys = true;
214
214
  }
215
215
  }
216
- if (!hasKeys) return void 0;
216
+ if (!hasKeys) return;
217
217
  return result;
218
218
  }
219
219
  return value;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "metascope",
3
- "version": "0.7.0",
3
+ "version": "0.7.1",
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",
@@ -49,9 +49,9 @@
49
49
  "@types/node": "~22.17.2",
50
50
  "@types/plist": "^3.0.5",
51
51
  "@types/yargs": "^17.0.35",
52
- "case-police": "^2.2.0",
52
+ "case-police": "^2.2.1",
53
53
  "defu": "^6.1.7",
54
- "fast-xml-parser": "^5.5.11",
54
+ "fast-xml-parser": "^5.7.2",
55
55
  "find-workspaces": "^0.3.1",
56
56
  "git-url-parse": "^16.1.0",
57
57
  "gray-matter-es": "^0.2.1",
@@ -60,21 +60,21 @@
60
60
  "octokit": "^5.0.5",
61
61
  "package-json": "^10.0.1",
62
62
  "picomatch": "^4.0.4",
63
- "pkg-types": "^2.3.0",
64
- "plist": "^3.1.0",
63
+ "pkg-types": "^2.3.1",
64
+ "plist": "^3.1.1",
65
65
  "pretty-ms": "^9.3.0",
66
66
  "read-pkg": "^10.1.0",
67
67
  "read-pyproject": "^0.3.2",
68
68
  "remark-parse": "^11.0.0",
69
69
  "semver": "^7.7.4",
70
- "simple-git": "^3.35.2",
70
+ "simple-git": "^3.36.0",
71
71
  "smol-toml": "^1.6.1",
72
72
  "spdx-license-list": "^6.11.0",
73
73
  "string-ts": "^2.3.1",
74
74
  "tinyexec": "^1.1.1",
75
75
  "tinyglobby": "^0.2.16",
76
76
  "unified": "^11.0.5",
77
- "updates": "^17.14.0",
77
+ "updates": "^17.16.6",
78
78
  "web-tree-sitter": "^0.26.8",
79
79
  "yaml": "^2.8.3",
80
80
  "yargs": "^18.0.0",
@@ -83,22 +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.3.0",
86
+ "@kitschpatrol/shared-config": "^7.5.2",
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.2",
92
+ "mdat-plugin-cli-help": "^3.0.0",
93
93
  "msw": "2.12.14",
94
94
  "publint": "^0.3.18",
95
95
  "shx": "^0.4.0",
96
96
  "tree-sitter-python": "^0.25.0",
97
97
  "tree-sitter-ruby": "^0.23.1",
98
- "tsdown": "^0.21.7",
98
+ "tsdown": "^0.21.10",
99
99
  "tsx": "^4.21.0",
100
- "typescript": "~6.0.2",
101
- "vitest": "^4.1.4"
100
+ "typescript": "~6.0.3",
101
+ "vitest": "^4.1.5"
102
102
  },
103
103
  "engines": {
104
104
  "node": ">=22.17.0"
package/readme.md CHANGED
@@ -583,7 +583,7 @@ The architecture and non-boilerplate parts of the documentation were human-drive
583
583
 
584
584
  ## Maintainers
585
585
 
586
- [@kitschpatrol](https://github.com/kitschpatrol)
586
+ [kitschpatrol](https://github.com/kitschpatrol)
587
587
 
588
588
  ## Acknowledgments
589
589
 
@@ -595,7 +595,11 @@ Jacob Peddicord's [askalono](https://github.com/jpeddicord/askalono) project ins
595
595
 
596
596
  ## Contributing
597
597
 
598
- [Issues](https://github.com/kitschpatrol/metascope/issues) and pull requests are welcome.
598
+ [Issues](https://github.com/kitschpatrol/metascope/issues) are welcome and appreciated.
599
+
600
+ Please open an issue to discuss changes before submitting a pull request. Unsolicited PRs (especially AI-generated ones) are unlikely to be merged.
601
+
602
+ This repository uses [@kitschpatrol/shared-config](https://github.com/kitschpatrol/shared-config) (via its `ksc` CLI) for linting and formatting, plus [MDAT](https://github.com/kitschpatrol/mdat) for readme placeholder expansion.
599
603
 
600
604
  <!-- /contributing -->
601
605
 
@@ -603,6 +607,6 @@ Jacob Peddicord's [askalono](https://github.com/jpeddicord/askalono) project ins
603
607
 
604
608
  ## License
605
609
 
606
- [MIT](license.txt) © Eric Mika
610
+ [MIT](license.txt) © [Eric Mika](https://ericmika.com)
607
611
 
608
612
  <!-- /license -->
package/dist/.DS_Store DELETED
Binary file
@@ -1 +0,0 @@
1
- import{createRequire as e}from"node:module";var t=Object.create,n=Object.defineProperty,r=Object.getOwnPropertyDescriptor,i=Object.getOwnPropertyNames,a=Object.getPrototypeOf,o=Object.prototype.hasOwnProperty,s=(e,t)=>()=>(e&&(t=e(e=0)),t),c=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),l=(e,t)=>{let r={};for(var i in e)n(r,i,{get:e[i],enumerable:!0});return t||n(r,Symbol.toStringTag,{value:`Module`}),r},u=(e,t,a,s)=>{if(t&&typeof t==`object`||typeof t==`function`)for(var c=i(t),l=0,u=c.length,d;l<u;l++)d=c[l],!o.call(e,d)&&d!==a&&n(e,d,{get:(e=>t[e]).bind(null,d),enumerable:!(s=r(t,d))||s.enumerable});return e},d=(e,r,i)=>(i=e==null?{}:t(a(e)),u(r||!e||!e.__esModule?n(i,`default`,{value:e,enumerable:!0}):i,e)),f=e=>o.call(e,`module.exports`)?e[`module.exports`]:u(n({},`__esModule`,{value:!0}),e),p=e(import.meta.url);export{f as a,p as i,s as n,d as o,l as r,c as t};