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
@@ -11,9 +11,10 @@ import plist from "plist";
11
11
  * Source and parser for Apple `Info.plist` files.
12
12
  *
13
13
  * Handles three flavors of Info.plist:
14
- * - Standard Apple app/framework bundles (CFBundle* keys)
15
- * - Alfred workflow plists (name, createdby, bundleid, etc.)
16
- * - TextMate bundle plists (name, contactName, contactEmailRot13, etc.)
14
+ *
15
+ * - Standard Apple app/framework bundles (CFBundle* keys)
16
+ * - Alfred workflow plists (name, createdby, bundleid, etc.)
17
+ * - TextMate bundle plists (name, contactName, contactEmailRot13, etc.)
17
18
  *
18
19
  * Uses the `plist` npm package to parse XML plist format.
19
20
  */
@@ -23,23 +24,38 @@ const ALL_RIGHTS_RESERVED_REGEX = /\.\s*all\s+rights\s+reserved\.?/i;
23
24
  const TRAILING_PUNCTUATION_REGEX = /[.,;]+$/;
24
25
  const PROCESSOR_ARCH_REGEX = /^(?:arm|x86|i386)/i;
25
26
  const infoPlistSchema = z.object({
27
+ /** Application category (humanized from UTI). */
26
28
  applicationCategory: nonEmptyString,
29
+ /** Author / creator name. */
27
30
  author: nonEmptyString,
31
+ /** Author email (decoded from ROT13 for TextMate bundles). */
28
32
  authorEmail: nonEmptyString,
33
+ /** Copyright holder name. */
29
34
  copyrightHolder: nonEmptyString,
35
+ /** Copyright year. */
30
36
  copyrightYear: nonEmptyString,
37
+ /** Description / readme text. */
31
38
  description: nonEmptyString,
39
+ /** Bundle identifier (e.g. "com.example.app"). */
32
40
  identifier: nonEmptyString,
41
+ /** Display name of the app or bundle. */
33
42
  name: nonEmptyString,
43
+ /** Inferred operating systems. */
34
44
  operatingSystems: stringArray,
45
+ /** Processor architecture requirements (e.g. "armv7"). */
35
46
  processorRequirements: stringArray,
47
+ /** Homepage URL. */
36
48
  url: optionalUrl,
49
+ /** Version string. */
37
50
  version: nonEmptyString
38
51
  });
39
52
  /** Xcode build variable pattern: $(VAR) or ${VAR}. */
40
53
  const XCODE_VARIABLE_RE = /\$[({][^)}]+[)}]/;
54
+ /** XML comment, including malformed ones with `--` inside. */
55
+ const XML_COMMENT_RE = /<!--[\s\S]*?-->/g;
41
56
  /**
42
- * Map DTPlatformName / CFBundleSupportedPlatforms values to human-readable OS names.
57
+ * Map DTPlatformName / CFBundleSupportedPlatforms values to human-readable OS
58
+ * names.
43
59
  */
44
60
  const PLATFORM_NAME_MAP = {
45
61
  appletvos: "tvOS",
@@ -52,18 +68,12 @@ const PLATFORM_NAME_MAP = {
52
68
  xros: "visionOS"
53
69
  };
54
70
  /**
55
- * Parse an `Info.plist` content string into a structured object.
56
- * Returns undefined if the plist is malformed or not a dictionary.
71
+ * Parse an `Info.plist` content string into a structured object. Returns
72
+ * undefined if the plist is malformed or not a dictionary.
57
73
  */
58
74
  function parse(content) {
59
- let data;
60
- try {
61
- const parsed = plist.parse(content);
62
- if (!is.plainObject(parsed)) return;
63
- data = parsed;
64
- } catch {
65
- return;
66
- }
75
+ const data = tryParsePlist(content) ?? tryParsePlist(content.replaceAll(XML_COMMENT_RE, "").trimStart());
76
+ if (!data) return;
67
77
  const name = getString(data, "CFBundleDisplayName") ?? getString(data, "CFBundleName") ?? getString(data, "name");
68
78
  const description = getString(data, "description");
69
79
  const version = getString(data, "CFBundleShortVersionString") ?? getString(data, "version") ?? getString(data, "CFBundleVersion");
@@ -90,15 +100,27 @@ function parse(content) {
90
100
  });
91
101
  }
92
102
  /**
93
- * Get a string value from a plist dict, returning undefined for
94
- * empty strings, whitespace-only strings, and Xcode variable placeholders.
103
+ * Run `plist.parse` and return the result only if it is a plain-object dict.
104
+ * Returns undefined on any throw or non-dict root.
105
+ */
106
+ function tryParsePlist(content) {
107
+ try {
108
+ const parsed = plist.parse(content);
109
+ return is.plainObject(parsed) ? parsed : void 0;
110
+ } catch {
111
+ return;
112
+ }
113
+ }
114
+ /**
115
+ * Get a string value from a plist dict, returning undefined for empty strings,
116
+ * whitespace-only strings, and Xcode variable placeholders.
95
117
  */
96
118
  function getString(data, key) {
97
119
  const value = data[key];
98
- if (typeof value !== "string") return void 0;
120
+ if (typeof value !== "string") return;
99
121
  const trimmed = value.trim();
100
- if (trimmed.length === 0) return void 0;
101
- if (XCODE_VARIABLE_RE.test(trimmed)) return void 0;
122
+ if (trimmed.length === 0) return;
123
+ if (XCODE_VARIABLE_RE.test(trimmed)) return;
102
124
  return trimmed;
103
125
  }
104
126
  /**
@@ -111,8 +133,8 @@ function rot13(value) {
111
133
  });
112
134
  }
113
135
  /**
114
- * Convert an Apple UTI application category to a human-readable string.
115
- * e.g. "public.app-category.developer-tools" → "Developer Tools"
136
+ * Convert an Apple UTI application category to a human-readable string. e.g.
137
+ * "public.app-category.developer-tools" → "Developer Tools"
116
138
  */
117
139
  function humanizeCategory(uti) {
118
140
  if (!uti.startsWith("public.app-category.")) return uti;
@@ -123,11 +145,12 @@ function humanizeCategory(uti) {
123
145
  */
124
146
  function parseApplicationCategory(data) {
125
147
  const category = getString(data, "LSApplicationCategoryType");
126
- if (!category) return void 0;
148
+ if (!category) return;
127
149
  return humanizeCategory(category);
128
150
  }
129
151
  /**
130
- * Parse copyright information from NSHumanReadableCopyright or CFBundleGetInfoString.
152
+ * Parse copyright information from NSHumanReadableCopyright or
153
+ * CFBundleGetInfoString.
131
154
  */
132
155
  function parseCopyright(data) {
133
156
  const copyrightSource = getString(data, "NSHumanReadableCopyright") ?? getString(data, "CFBundleGetInfoString");
@@ -177,7 +200,8 @@ function parseOperatingSystems(data) {
177
200
  return results;
178
201
  }
179
202
  /**
180
- * Extract processor architecture requirements from UIRequiredDeviceCapabilities.
203
+ * Extract processor architecture requirements from
204
+ * UIRequiredDeviceCapabilities.
181
205
  */
182
206
  function parseProcessorRequirements(data) {
183
207
  const capabilities = data.UIRequiredDeviceCapabilities;
@@ -9,13 +9,14 @@ import { PBXNativeTarget, XCRemoteSwiftPackageReference, XcodeProject } from "@b
9
9
  /**
10
10
  * Source and parser for Xcode `.pbxproj` project files.
11
11
  *
12
- * Uses the `@bacons/xcode` package to parse the binary/ASCII plist format
13
- * and navigate the Xcode project object graph.
12
+ * Uses the `@bacons/xcode` package to parse the binary/ASCII plist format and
13
+ * navigate the Xcode project object graph.
14
14
  *
15
15
  * Extracts metadata from:
16
- * - Project-level attributes (organizationName)
17
- * - Build settings on the main app target (Release config preferred)
18
- * - Swift Package Manager dependencies
16
+ *
17
+ * - Project-level attributes (organizationName)
18
+ * - Build settings on the main app target (Release config preferred)
19
+ * - Swift Package Manager dependencies
19
20
  */
20
21
  const COPYRIGHT_YEAR_REGEX = /(?:©|\(c\)|copyright)\s*(\d{4})/i;
21
22
  const COPYRIGHT_HOLDER_REGEX = /(?:©|\(c\)|copyright)\s*\d{4}\s*(.+)/i;
@@ -23,14 +24,23 @@ const ALL_RIGHTS_RESERVED_REGEX = /\.\s*all\s+rights\s+reserved\.?/i;
23
24
  const TRAILING_PUNCTUATION_REGEX = /[.,;]+$/;
24
25
  const pbxprojDependencySchema = z.object({ url: z.string() });
25
26
  const pbxprojSchema = z.object({
27
+ /** Copyright holder name. */
26
28
  copyrightHolder: nonEmptyString,
29
+ /** Copyright year. */
27
30
  copyrightYear: nonEmptyString,
31
+ /** Swift Package Manager dependencies. */
28
32
  dependencies: z.array(pbxprojDependencySchema),
33
+ /** Bundle identifier (e.g. "com.example.app"). */
29
34
  identifier: nonEmptyString,
35
+ /** Display name of the app or target. */
30
36
  name: nonEmptyString,
37
+ /** Inferred operating systems with deployment targets. */
31
38
  operatingSystems: stringArray,
39
+ /** Organization name from project attributes. */
32
40
  organizationName: nonEmptyString,
41
+ /** Detected programming language (Swift or Objective-C). */
33
42
  programmingLanguage: nonEmptyString,
43
+ /** Marketing version string. */
34
44
  version: nonEmptyString
35
45
  });
36
46
  /** Xcode build variable pattern: $(VAR) or ${VAR}. */
@@ -71,8 +81,8 @@ const DEPLOYMENT_TARGETS = [
71
81
  }
72
82
  ];
73
83
  /**
74
- * Parse a `.pbxproj` file into a structured object.
75
- * Returns undefined if the file is malformed or cannot be parsed.
84
+ * Parse a `.pbxproj` file into a structured object. Returns undefined if the
85
+ * file is malformed or cannot be parsed.
76
86
  */
77
87
  function parse(filePath) {
78
88
  let project;
@@ -123,15 +133,15 @@ function parse(filePath) {
123
133
  });
124
134
  }
125
135
  /**
126
- * Get a string build setting, filtering out empty strings and unresolved
127
- * Xcode variable placeholders. Handles both string and numeric values.
136
+ * Get a string build setting, filtering out empty strings and unresolved Xcode
137
+ * variable placeholders. Handles both string and numeric values.
128
138
  */
129
139
  function cleanString(value) {
130
140
  if (typeof value === "number") return String(value);
131
- if (typeof value !== "string") return void 0;
141
+ if (typeof value !== "string") return;
132
142
  const trimmed = value.trim();
133
- if (trimmed.length === 0) return void 0;
134
- if (XCODE_VARIABLE_RE.test(trimmed)) return void 0;
143
+ if (trimmed.length === 0) return;
144
+ if (XCODE_VARIABLE_RE.test(trimmed)) return;
135
145
  return trimmed;
136
146
  }
137
147
  /**
@@ -2,11 +2,10 @@ import { Template } from "../metadata-types.js";
2
2
  //#region src/lib/templates/codemeta-json.d.ts
3
3
  type TemplateDataCodemetaJson = ReturnType<typeof codemetaJson>;
4
4
  /**
5
- * A JSON-friendly derivation of the `codemeta` template.
6
- * Produces the same aggregated metadata but parses it through a strict
7
- * schema,stripping JSON-LD artifacts (like `@context` and `@type`) to yield
8
- * plain JSON suitable for consumption by tools that don't care to understand
9
- * JSON-LD.
5
+ * A JSON-friendly derivation of the `codemeta` template. Produces the same
6
+ * aggregated metadata but parses it through a strict schema,stripping JSON-LD
7
+ * artifacts (like `@context` and `@type`) to yield plain JSON suitable for
8
+ * consumption by tools that don't care to understand JSON-LD.
10
9
  *
11
10
  * This template also provides a handy baseline normalization abstraction for
12
11
  * the other templates.
@@ -3,11 +3,10 @@ import { codeMetaJsonDataSchema } from "../sources/codemeta-json.js";
3
3
  import { codemeta } from "./codemeta.js";
4
4
  //#region src/lib/templates/codemeta-json.ts
5
5
  /**
6
- * A JSON-friendly derivation of the `codemeta` template.
7
- * Produces the same aggregated metadata but parses it through a strict
8
- * schema,stripping JSON-LD artifacts (like `@context` and `@type`) to yield
9
- * plain JSON suitable for consumption by tools that don't care to understand
10
- * JSON-LD.
6
+ * A JSON-friendly derivation of the `codemeta` template. Produces the same
7
+ * aggregated metadata but parses it through a strict schema,stripping JSON-LD
8
+ * artifacts (like `@context` and `@type`) to yield plain JSON suitable for
9
+ * consumption by tools that don't care to understand JSON-LD.
11
10
  *
12
11
  * This template also provides a handy baseline normalization abstraction for
13
12
  * the other templates.
@@ -13,14 +13,14 @@ import is from "@sindresorhus/is";
13
13
  * ## Cascade strategy
14
14
  *
15
15
  * For **ecosystem-derived fields** (name, version, description, author,
16
- * license, dependencies, keywords, …) the ecosystem manifest is canonical.
17
- * This keeps the output fresh when e.g. a new dependency is added to
18
- * package.json, and makes the round-trip stable: generate → save as
19
- * codemeta.json → regenerate → identical output.
16
+ * license, dependencies, keywords, …) the ecosystem manifest is canonical. This
17
+ * keeps the output fresh when e.g. a new dependency is added to package.json,
18
+ * and makes the round-trip stable: generate → save as codemeta.json →
19
+ * regenerate → identical output.
20
20
  *
21
21
  * For **codemeta-specific fields** that only exist in codemeta.json
22
- * (developmentStatus, funding, buildInstructions, …) the existing
23
- * codemeta.json is the source of truth.
22
+ * (developmentStatus, funding, buildInstructions, …) the existing codemeta.json
23
+ * is the source of truth.
24
24
  *
25
25
  * ## Software type inference
26
26
  *
@@ -287,7 +287,6 @@ const codemeta = defineTemplate(({ arduinoLibraryProperties, cinderCinderblockXm
287
287
  const releaseNotes = cm?.data.releaseNotes;
288
288
  const installUrl = cm?.data.installUrl;
289
289
  const relatedLink = cm?.data.relatedLink;
290
- const targetProduct = void 0;
291
290
  return stripUndefined({
292
291
  "@context": "https://w3id.org/codemeta/3.0",
293
292
  "@type": "SoftwareSourceCode",
@@ -325,15 +324,14 @@ const codemeta = defineTemplate(({ arduinoLibraryProperties, cinderCinderblockXm
325
324
  softwareHelp,
326
325
  softwareRequirements,
327
326
  softwareSuggestions,
328
- targetProduct,
327
+ targetProduct: void 0,
329
328
  url,
330
329
  version
331
330
  });
332
331
  });
333
332
  /**
334
- * Extract authors from a gemspec record.
335
- * Gemspec has `authors: string[]` and a separate `email: string | string[]`.
336
- * We pair them by index where possible.
333
+ * Extract authors from a gemspec record. Gemspec has `authors: string[]` and a
334
+ * separate `email: string | string[]`. We pair them by index where possible.
337
335
  */
338
336
  function gemspecAuthors(gem) {
339
337
  if (gem === void 0) return [];
@@ -344,9 +342,9 @@ function gemspecAuthors(gem) {
344
342
  }));
345
343
  }
346
344
  /**
347
- * Takes ecosystem persons (which may include undefined) and codemeta fallback persons.
348
- * Uses ecosystem if any are present, otherwise falls back.
349
- * Always deduplicates by name.
345
+ * Takes ecosystem persons (which may include undefined) and codemeta fallback
346
+ * persons. Uses ecosystem if any are present, otherwise falls back. Always
347
+ * deduplicates by name.
350
348
  */
351
349
  function resolvePersonsOrOrgs(ecosystemPersons, fallbackPersons) {
352
350
  const ecosystem = ecosystemPersons.filter((p) => p !== void 0);
@@ -389,11 +387,12 @@ function collectDevelopmentDeps(sources) {
389
387
  * Convert a Record<name, version> dependency map to CodemetaDependencyLd[].
390
388
  */
391
389
  function objectEntriesToDeps(deps) {
392
- if (deps === void 0) return void 0;
390
+ if (deps === void 0) return;
393
391
  return Object.entries(deps).map(([depName, depVersion]) => toDependencyLd(depName, depVersion));
394
392
  }
395
393
  /**
396
- * Parse a PEP 508 dependency string ("package>=1.0") into a CodemetaDependencyLd.
394
+ * Parse a PEP 508 dependency string ("package>=1.0") into a
395
+ * CodemetaDependencyLd.
397
396
  */
398
397
  function parsePep508Dep(dep) {
399
398
  const trimmed = dep.trim();
@@ -408,7 +407,7 @@ function parsePep508Dep(dep) {
408
407
  * Extract URL from package.json repository field (string or {url}).
409
408
  */
410
409
  function repositoryUrlFromPackageJson(repository) {
411
- if (repository === void 0) return void 0;
410
+ if (repository === void 0) return;
412
411
  if (typeof repository === "string") return repository;
413
412
  return repository.url;
414
413
  }
@@ -416,7 +415,7 @@ function repositoryUrlFromPackageJson(repository) {
416
415
  * Extract URL from package.json bugs field.
417
416
  */
418
417
  function bugsUrlFromPackageJson(bugs) {
419
- if (bugs === void 0) return void 0;
418
+ if (bugs === void 0) return;
420
419
  return bugs.url;
421
420
  }
422
421
  /**
@@ -427,11 +426,11 @@ function firstPomLicense(pom) {
427
426
  return pomLicense?.name ?? pomLicense?.url;
428
427
  }
429
428
  /**
430
- * Resolve Python pyproject.toml license field to a string.
431
- * Can be a string (SPDX ID) or `{ spdx?: string; text?: string; file?: string }`.
429
+ * Resolve Python pyproject.toml license field to a string. Can be a string
430
+ * (SPDX ID) or `{ spdx?: string; text?: string; file?: string }`.
432
431
  */
433
432
  function resolvePythonLicense(pythonLicense) {
434
- if (pythonLicense === void 0) return void 0;
433
+ if (pythonLicense === void 0) return;
435
434
  if (typeof pythonLicense === "string") return pythonLicense;
436
435
  return pythonLicense.spdx ?? pythonLicense.text;
437
436
  }
@@ -439,7 +438,7 @@ function resolvePythonLicense(pythonLicense) {
439
438
  * Resolve codemeta license field (string or string[]) to first string.
440
439
  */
441
440
  function resolveCmLicense(cmLicense) {
442
- if (cmLicense === void 0) return void 0;
441
+ if (cmLicense === void 0) return;
443
442
  return Array.isArray(cmLicense) ? cmLicense[0] : cmLicense;
444
443
  }
445
444
  /**
@@ -454,10 +453,11 @@ function deduplicateStrings(strings) {
454
453
  return [...seen.values()];
455
454
  }
456
455
  /**
457
- * Case-insensitive lookup in a string record (e.g. pyproject.toml `[project.urls]`).
456
+ * Case-insensitive lookup in a string record (e.g. pyproject.toml
457
+ * `[project.urls]`).
458
458
  */
459
459
  function caseInsensitiveLookup(record, key) {
460
- if (record === void 0) return void 0;
460
+ if (record === void 0) return;
461
461
  const lowerKey = key.toLowerCase();
462
462
  for (const [k, v] of Object.entries(record)) if (k.toLowerCase() === lowerKey) return v;
463
463
  }
@@ -466,7 +466,7 @@ function caseInsensitiveLookup(record, key) {
466
466
  * homepage URLs derived from repository URLs.
467
467
  */
468
468
  function stripReadmeFragment(url) {
469
- if (url === void 0) return void 0;
469
+ if (url === void 0) return;
470
470
  return url.endsWith("#readme") ? url.slice(0, -7) : url;
471
471
  }
472
472
  /**
@@ -474,19 +474,19 @@ function stripReadmeFragment(url) {
474
474
  * CodeMeta dates are `schema:Date`, not `schema:DateTime`.
475
475
  */
476
476
  function toDateOnly(value) {
477
- if (value === void 0) return void 0;
477
+ if (value === void 0) return;
478
478
  if (DATE_ONLY_REGEX.test(value)) return value;
479
479
  const match = DATETIME_DATE_REGEX.exec(value);
480
480
  if (match) return match[1];
481
481
  return value;
482
482
  }
483
483
  /**
484
- * Build a URL for the project's README.
485
- * Prefers a web URL on the remote service (e.g. GitHub blob link) when a
486
- * code repository URL is available, otherwise falls back to the local source path.
484
+ * Build a URL for the project's README. Prefers a web URL on the remote service
485
+ * (e.g. GitHub blob link) when a code repository URL is available, otherwise
486
+ * falls back to the local source path.
487
487
  */
488
488
  function readmeUrl(readmeRecord, repoUrl, defaultBranch, basePath) {
489
- if (readmeRecord === void 0) return void 0;
489
+ if (readmeRecord === void 0) return;
490
490
  const repoRelativePath = basePath === void 0 ? basename(readmeRecord.source) : relative(basePath, readmeRecord.source).replaceAll("\\", "/");
491
491
  if (is.nonEmptyStringAndNotWhitespace(repoUrl) && repoUrl.includes("github.com")) {
492
492
  const branch = defaultBranch ?? "main";
@@ -2,8 +2,8 @@ import { Template } from "../metadata-types.js";
2
2
  //#region src/lib/templates/metadata.d.ts
3
3
  type TemplateDataMetadata = ReturnType<typeof metadata>;
4
4
  /**
5
- * A minimal metadata template for populating a GitHub repository's
6
- * description, homepage, and topics via metadata.json / metadata.yaml.
5
+ * A minimal metadata template for populating a GitHub repository's description,
6
+ * homepage, and topics via metadata.json / metadata.yaml.
7
7
  *
8
8
  * Builds on the codemeta template for baseline values, then lets any
9
9
  * metadata.json source fields override the result.
@@ -6,15 +6,15 @@ import { codemetaJson } from "./codemeta-json.js";
6
6
  * Strip `git+` prefix and `.git` suffix from a URL.
7
7
  */
8
8
  function normalizeGitUrl(url) {
9
- if (url === void 0) return void 0;
9
+ if (url === void 0) return;
10
10
  let normalized = url;
11
11
  if (normalized.startsWith("git+")) normalized = normalized.slice(4);
12
12
  if (normalized.endsWith(".git")) normalized = normalized.slice(0, -4);
13
13
  return normalized;
14
14
  }
15
15
  /**
16
- * A minimal metadata template for populating a GitHub repository's
17
- * description, homepage, and topics via metadata.json / metadata.yaml.
16
+ * A minimal metadata template for populating a GitHub repository's description,
17
+ * homepage, and topics via metadata.json / metadata.yaml.
18
18
  *
19
19
  * Builds on the codemeta template for baseline values, then lets any
20
20
  * metadata.json source fields override the result.
@@ -2,8 +2,9 @@
2
2
  /**
3
3
  * Helpers for building codemeta JSON-LD objects.
4
4
  *
5
- * Provides type-safe constructors for Person/Organization and SoftwareApplication
6
- * dependency nodes, plus deduplication and license URL normalization.
5
+ * Provides type-safe constructors for Person/Organization and
6
+ * SoftwareApplication dependency nodes, plus deduplication and license URL
7
+ * normalization.
7
8
  */
8
9
  /**
9
10
  * An Organization node in codemeta JSON-LD.
@@ -3,12 +3,14 @@ import is from "@sindresorhus/is";
3
3
  /**
4
4
  * Helpers for building codemeta JSON-LD objects.
5
5
  *
6
- * Provides type-safe constructors for Person/Organization and SoftwareApplication
7
- * dependency nodes, plus deduplication and license URL normalization.
6
+ * Provides type-safe constructors for Person/Organization and
7
+ * SoftwareApplication dependency nodes, plus deduplication and license URL
8
+ * normalization.
8
9
  */
9
10
  /**
10
- * Build a codemeta JSON-LD Person or Organization from flexible inputs.
11
- * Returns undefined if no identifying information (name, givenName+familyName, or email) is present.
11
+ * Build a codemeta JSON-LD Person or Organization from flexible inputs. Returns
12
+ * undefined if no identifying information (name, givenName+familyName, or
13
+ * email) is present.
12
14
  *
13
15
  * Works with person shapes from any metascope source — the caller maps
14
16
  * source-specific field names into this common parameter object.
@@ -18,7 +20,7 @@ function toPersonOrOrgLd(options) {
18
20
  const hasGivenName = is.nonEmptyStringAndNotWhitespace(options.givenName);
19
21
  const hasFamilyName = is.nonEmptyStringAndNotWhitespace(options.familyName);
20
22
  const hasEmail = is.nonEmptyStringAndNotWhitespace(options.email);
21
- if (!hasName && !hasGivenName && !hasFamilyName && !hasEmail) return void 0;
23
+ if (!hasName && !hasGivenName && !hasFamilyName && !hasEmail) return;
22
24
  const person = { "@type": options.type ?? "Person" };
23
25
  if (is.nonEmptyStringAndNotWhitespace(options.id)) person["@id"] = options.id;
24
26
  if (hasName) person.name = options.name;
@@ -33,9 +35,9 @@ function toPersonOrOrgLd(options) {
33
35
  return person;
34
36
  }
35
37
  /**
36
- * Deduplicate persons by name (case-insensitive, trimmed).
37
- * Keeps the first occurrence, so callers should place higher-priority sources first.
38
- * Returns undefined if the result is empty.
38
+ * Deduplicate persons by name (case-insensitive, trimmed). Keeps the first
39
+ * occurrence, so callers should place higher-priority sources first. Returns
40
+ * undefined if the result is empty.
39
41
  */
40
42
  function deduplicatePersonsOrOrgs(persons) {
41
43
  const seen = /* @__PURE__ */ new Map();
@@ -60,8 +62,8 @@ function toDependencyLd(name, version, identifier, runtimePlatform) {
60
62
  return dep;
61
63
  }
62
64
  /**
63
- * Deduplicate dependencies by name (case-insensitive).
64
- * Keeps the first occurrence. Returns undefined if the result is empty.
65
+ * Deduplicate dependencies by name (case-insensitive). Keeps the first
66
+ * occurrence. Returns undefined if the result is empty.
65
67
  */
66
68
  function deduplicateDependencies(deps) {
67
69
  const seen = /* @__PURE__ */ new Map();
@@ -73,8 +75,8 @@ function deduplicateDependencies(deps) {
73
75
  return result.length > 0 ? result : void 0;
74
76
  }
75
77
  /**
76
- * Normalize a license identifier to an SPDX URL.
77
- * Handles bare SPDX IDs ("MIT") and existing SPDX URLs.
78
+ * Normalize a license identifier to an SPDX URL. Handles bare SPDX IDs ("MIT")
79
+ * and existing SPDX URLs.
78
80
  */
79
81
  function toSpdxLicenseUrl(spdxId) {
80
82
  return `https://spdx.org/licenses/${spdxId.replace("https://spdx.org/licenses/", "").replace("http://spdx.org/licenses/", "")}`;
@@ -1,8 +1,8 @@
1
1
  import { log } from "../log.js";
2
2
  //#region src/lib/utilities/fetch.ts
3
3
  /**
4
- * Fetch with automatic retries and exponential backoff.
5
- * Retries on network errors and 429/5xx responses.
4
+ * Fetch with automatic retries and exponential backoff. Retries on network
5
+ * errors and 429/5xx responses.
6
6
  */
7
7
  async function fetchWithRetry(url, options, maxRetries = 5) {
8
8
  let lastError;
@@ -3,9 +3,10 @@ import { relative } from "node:path";
3
3
  //#region src/lib/utilities/formatting.ts
4
4
  const URL_PROTOCOL_REGEX = /^[a-z]+:\/\//i;
5
5
  /**
6
- * Format an absolute path as either absolute or relative, based on the `absolute` option.
7
- * When relative, paths identical to `basePath` are returned as `'.'`.
8
- * Correctly handles Windows paths (normalizes to POSIX) and ignores URLs.
6
+ * Format an absolute path as either absolute or relative, based on the
7
+ * `absolute` option. When relative, paths identical to `basePath` are returned
8
+ * as `'.'`. Correctly handles Windows paths (normalizes to POSIX) and ignores
9
+ * URLs.
9
10
  */
10
11
  function formatPath(absolutePath, basePath, absolute = DEFAULT_GET_METADATA_OPTIONS.absolute) {
11
12
  if (URL_PROTOCOL_REGEX.test(absolutePath)) return absolutePath;
@@ -4,11 +4,11 @@ import gitUrlParse from "git-url-parse";
4
4
  * Shared GitHub utilities used across multiple sources.
5
5
  */
6
6
  /**
7
- * Extract a GitHub owner/repo from git config remote URLs.
8
- * Prefers the "origin" remote, falls back to the first GitHub remote found.
7
+ * Extract a GitHub owner/repo from git config remote URLs. Prefers the "origin"
8
+ * remote, falls back to the first GitHub remote found.
9
9
  */
10
10
  function getGitHubRemoteFromConfig(remotes) {
11
- if (!remotes) return void 0;
11
+ if (!remotes) return;
12
12
  const sorted = Object.entries(remotes).toSorted(([a], [b]) => {
13
13
  if (a === "origin") return -1;
14
14
  if (b === "origin") return 1;
@@ -15,7 +15,9 @@
15
15
  * - YAML front matter stripping
16
16
  */
17
17
  type LicenseMatch = {
18
- /** Dice coefficient confidence score (0–1). */confidence: number; /** SPDX license identifier (e.g. "MIT", "Apache-2.0"). */
18
+ /** Dice coefficient confidence score (0–1). */confidence: number; /** Full license name (e.g. "MIT License", "Apache License 2.0"). */
19
+ name: string; /** Whether the license is OSI approved. */
20
+ osiApproved: boolean; /** SPDX license identifier (e.g. "MIT", "Apache-2.0"). */
19
21
  spdxId: string; /** SPDX license URL. */
20
22
  spdxUrl: string;
21
23
  };