metascope 0.7.0 → 0.7.2

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 (80) hide show
  1. package/dist/bin/chunk-Bdh3yLIe.js +1 -0
  2. package/dist/bin/cli.js +308 -284
  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-DxDKd5Ft.js +1 -0
  6. package/dist/bin/shared-CTlQdTfh.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.d.ts +10 -10
  23. package/dist/lib/sources/arduino-library-properties.js +32 -15
  24. package/dist/lib/sources/cinder-cinderblock-xml.d.ts +11 -11
  25. package/dist/lib/sources/cinder-cinderblock-xml.js +21 -9
  26. package/dist/lib/sources/codemeta-json.d.ts +66 -66
  27. package/dist/lib/sources/codemeta-json.js +27 -23
  28. package/dist/lib/sources/git-stats.js +1 -1
  29. package/dist/lib/sources/github-actions.js +9 -2
  30. package/dist/lib/sources/github.js +1 -1
  31. package/dist/lib/sources/go-go-mod.d.ts +4 -4
  32. package/dist/lib/sources/go-goreleaser-yaml.d.ts +8 -8
  33. package/dist/lib/sources/go-goreleaser-yaml.js +5 -4
  34. package/dist/lib/sources/java-pom-xml.d.ts +12 -12
  35. package/dist/lib/sources/java-pom-xml.js +38 -19
  36. package/dist/lib/sources/metadata-file.d.ts +4 -4
  37. package/dist/lib/sources/metadata-file.js +15 -12
  38. package/dist/lib/sources/node-npm-registry.js +1 -1
  39. package/dist/lib/sources/openframeworks-addon-config-mk.d.ts +7 -7
  40. package/dist/lib/sources/openframeworks-addon-config-mk.js +7 -0
  41. package/dist/lib/sources/openframeworks-install-xml.d.ts +10 -10
  42. package/dist/lib/sources/openframeworks-install-xml.js +24 -14
  43. package/dist/lib/sources/processing-library-properties.d.ts +8 -8
  44. package/dist/lib/sources/processing-library-properties.js +25 -10
  45. package/dist/lib/sources/processing-sketch-properties.d.ts +16 -16
  46. package/dist/lib/sources/processing-sketch-properties.js +51 -7
  47. package/dist/lib/sources/publiccode-yaml.d.ts +23 -23
  48. package/dist/lib/sources/publiccode-yaml.js +37 -5
  49. package/dist/lib/sources/python-pkg-info.d.ts +18 -18
  50. package/dist/lib/sources/python-pkg-info.js +2 -2
  51. package/dist/lib/sources/python-setup-cfg.d.ts +14 -14
  52. package/dist/lib/sources/python-setup-cfg.js +2 -2
  53. package/dist/lib/sources/python-setup-py.d.ts +14 -14
  54. package/dist/lib/sources/readme-file.js +9 -2
  55. package/dist/lib/sources/ruby-gemspec.d.ts +22 -22
  56. package/dist/lib/sources/ruby-gemspec.js +1 -0
  57. package/dist/lib/sources/rust-cargo-toml.d.ts +14 -14
  58. package/dist/lib/sources/rust-cargo-toml.js +29 -10
  59. package/dist/lib/sources/xcode-info-plist.d.ts +12 -12
  60. package/dist/lib/sources/xcode-info-plist.js +48 -24
  61. package/dist/lib/sources/xcode-project-pbxproj.d.ts +8 -8
  62. package/dist/lib/sources/xcode-project-pbxproj.js +22 -12
  63. package/dist/lib/templates/codemeta-json.d.ts +4 -5
  64. package/dist/lib/templates/codemeta-json.js +4 -5
  65. package/dist/lib/templates/codemeta.js +30 -30
  66. package/dist/lib/templates/metadata.d.ts +2 -2
  67. package/dist/lib/templates/metadata.js +3 -3
  68. package/dist/lib/utilities/codemeta-helpers.d.ts +3 -2
  69. package/dist/lib/utilities/codemeta-helpers.js +14 -12
  70. package/dist/lib/utilities/fetch.js +2 -2
  71. package/dist/lib/utilities/formatting.js +4 -3
  72. package/dist/lib/utilities/github.js +3 -3
  73. package/dist/lib/utilities/license-identification.d.ts +3 -1
  74. package/dist/lib/utilities/license-identification.js +21 -25
  75. package/dist/lib/utilities/schema-primitives.js +16 -13
  76. package/dist/lib/utilities/template-helpers.js +3 -3
  77. package/package.json +14 -14
  78. package/readme.md +7 -3
  79. package/dist/.DS_Store +0 -0
  80. package/dist/bin/chunk-BjEoQXZ0.js +0 -1
@@ -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
  };
@@ -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,35 +5,38 @@ 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. The outer
15
+ * `.optional()` lets the field be absent in parent objects (zod 4.4+ no longer
16
+ * bubbles inner-schema optionality through `z.preprocess`).
15
17
  */
16
18
  const nonEmptyString = z.preprocess((value) => {
17
19
  if (typeof value !== "string") return;
18
20
  const trimmed = value.trim();
19
21
  return trimmed.length > 0 ? trimmed : void 0;
20
- }, z.string().optional());
22
+ }, z.string().optional()).optional();
21
23
  /**
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.
24
+ * A URL string that treats empty/whitespace as undefined. Does not reject
25
+ * invalid URLs — just ensures non-empty. Use z.url() in place of this if strict
26
+ * URL validation is desired.
25
27
  */
26
28
  const optionalUrl = nonEmptyString.describe("A URL string");
27
29
  /**
28
- * An array of strings, filtering out empty/whitespace-only elements.
30
+ * An array of strings, filtering out empty/whitespace-only elements. Defaults
31
+ * to `[]` so absent/non-array fields parse cleanly under zod 4.4+.
29
32
  */
30
33
  const stringArray = z.preprocess((value) => {
31
34
  if (!Array.isArray(value)) return [];
32
35
  return value.filter((item) => typeof item === "string" && item.trim().length > 0);
33
- }, z.array(z.string()));
36
+ }, z.array(z.string())).default([]);
34
37
  /**
35
- * Parse a JSON string into a plain object.
36
- * Returns `undefined` for malformed JSON or non-object values (arrays, primitives).
38
+ * Parse a JSON string into a plain object. Returns `undefined` for malformed
39
+ * JSON or non-object values (arrays, primitives).
37
40
  */
38
41
  function parseJsonRecord(content) {
39
42
  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.2",
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,45 +60,45 @@
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
- "tinyexec": "^1.1.1",
74
+ "tinyexec": "^1.1.2",
75
75
  "tinyglobby": "^0.2.16",
76
76
  "unified": "^11.0.5",
77
- "updates": "^17.14.0",
77
+ "updates": "^17.16.7",
78
78
  "web-tree-sitter": "^0.26.8",
79
79
  "yaml": "^2.8.3",
80
80
  "yargs": "^18.0.0",
81
- "zod": "^4.3.6"
81
+ "zod": "^4.4.1"
82
82
  },
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};