metascope 0.8.4 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/dist/bin/cli.js +30426 -29237
  2. package/dist/bin/{jiti-DDHyYNLW.js → jiti-B26uDQuv.js} +2 -2
  3. package/dist/bin/renovate-CEC0BhMB.js +1 -0
  4. package/dist/bin/shared-Ch5JsD6s.js +8 -0
  5. package/dist/bin/shared2-Dhjk_Okb.js +1 -0
  6. package/dist/bin/web-tree-sitter.wasm +0 -0
  7. package/dist/lib/data/license-urls.js +2904 -0
  8. package/dist/lib/file-matching.js +5 -2
  9. package/dist/lib/log.d.ts +0 -1
  10. package/dist/lib/metadata-types.d.ts +16 -9
  11. package/dist/lib/metadata.d.ts +0 -1
  12. package/dist/lib/metadata.js +5 -5
  13. package/dist/lib/package.js +1 -1
  14. package/dist/lib/parsers/configparser-parser.js +14 -12
  15. package/dist/lib/parsers/gemspec-parser.js +41 -42
  16. package/dist/lib/parsers/go-mod-parser.js +51 -45
  17. package/dist/lib/parsers/makefile-config-parser.js +7 -6
  18. package/dist/lib/parsers/properties-parser.js +1 -1
  19. package/dist/lib/parsers/rfc822-header-parser.js +8 -6
  20. package/dist/lib/parsers/setup-py-parser.js +28 -24
  21. package/dist/lib/source.d.ts +6 -2
  22. package/dist/lib/sources/arduino-library-properties.d.ts +0 -1
  23. package/dist/lib/sources/arduino-library-properties.js +6 -7
  24. package/dist/lib/sources/cinder-cinderblock-xml.d.ts +0 -1
  25. package/dist/lib/sources/cinder-cinderblock-xml.js +5 -5
  26. package/dist/lib/sources/code-stats.d.ts +3 -2
  27. package/dist/lib/sources/codemeta-json.d.ts +0 -1
  28. package/dist/lib/sources/codemeta-json.js +21 -20
  29. package/dist/lib/sources/dependency-updates.d.ts +17 -8
  30. package/dist/lib/sources/dependency-updates.js +38 -34
  31. package/dist/lib/sources/file-stats.d.ts +7 -4
  32. package/dist/lib/sources/git-config.d.ts +0 -1
  33. package/dist/lib/sources/git-stats.d.ts +47 -24
  34. package/dist/lib/sources/git-stats.js +51 -33
  35. package/dist/lib/sources/github-actions.d.ts +0 -1
  36. package/dist/lib/sources/github-actions.js +4 -3
  37. package/dist/lib/sources/github.d.ts +156 -78
  38. package/dist/lib/sources/github.js +11 -8
  39. package/dist/lib/sources/go-go-mod.d.ts +0 -1
  40. package/dist/lib/sources/go-goreleaser-yaml.d.ts +0 -1
  41. package/dist/lib/sources/go-goreleaser-yaml.js +5 -3
  42. package/dist/lib/sources/java-pom-xml.d.ts +0 -1
  43. package/dist/lib/sources/java-pom-xml.js +12 -12
  44. package/dist/lib/sources/license-file.d.ts +0 -1
  45. package/dist/lib/sources/metadata-file.d.ts +0 -1
  46. package/dist/lib/sources/metadata-file.js +9 -10
  47. package/dist/lib/sources/metascope.d.ts +9 -5
  48. package/dist/lib/sources/node-npm-registry.d.ts +21 -11
  49. package/dist/lib/sources/node-npm-registry.js +12 -6
  50. package/dist/lib/sources/node-package-json.d.ts +0 -1
  51. package/dist/lib/sources/obsidian-plugin-manifest-json.d.ts +17 -9
  52. package/dist/lib/sources/obsidian-plugin-manifest-json.js +2 -2
  53. package/dist/lib/sources/obsidian-plugin-registry.d.ts +3 -2
  54. package/dist/lib/sources/obsidian-plugin-registry.js +2 -1
  55. package/dist/lib/sources/openframeworks-addon-config-mk.d.ts +0 -1
  56. package/dist/lib/sources/openframeworks-install-xml.d.ts +0 -1
  57. package/dist/lib/sources/openframeworks-install-xml.js +3 -3
  58. package/dist/lib/sources/processing-library-properties.d.ts +0 -1
  59. package/dist/lib/sources/processing-library-properties.js +9 -10
  60. package/dist/lib/sources/processing-sketch-properties.d.ts +0 -1
  61. package/dist/lib/sources/processing-sketch-properties.js +13 -20
  62. package/dist/lib/sources/publiccode-yaml.d.ts +0 -1
  63. package/dist/lib/sources/publiccode-yaml.js +61 -58
  64. package/dist/lib/sources/python-pkg-info.d.ts +0 -1
  65. package/dist/lib/sources/python-pkg-info.js +6 -5
  66. package/dist/lib/sources/python-pypi-registry.d.ts +21 -11
  67. package/dist/lib/sources/python-pypi-registry.js +23 -16
  68. package/dist/lib/sources/python-pyproject-toml.d.ts +0 -1
  69. package/dist/lib/sources/python-setup-cfg.d.ts +2 -3
  70. package/dist/lib/sources/python-setup-cfg.js +10 -9
  71. package/dist/lib/sources/python-setup-py.d.ts +0 -1
  72. package/dist/lib/sources/readme-file.d.ts +0 -1
  73. package/dist/lib/sources/readme-file.js +4 -3
  74. package/dist/lib/sources/ruby-gemspec.d.ts +0 -1
  75. package/dist/lib/sources/rust-cargo-toml.d.ts +0 -1
  76. package/dist/lib/sources/rust-cargo-toml.js +1 -1
  77. package/dist/lib/sources/xcode-info-plist.d.ts +0 -1
  78. package/dist/lib/sources/xcode-info-plist.js +29 -31
  79. package/dist/lib/sources/xcode-project-pbxproj.d.ts +0 -1
  80. package/dist/lib/sources/xcode-project-pbxproj.js +17 -16
  81. package/dist/lib/templates/codemeta-json.d.ts +1 -0
  82. package/dist/lib/templates/codemeta.d.ts +1 -0
  83. package/dist/lib/templates/codemeta.js +98 -89
  84. package/dist/lib/templates/frontmatter.d.ts +2 -1
  85. package/dist/lib/templates/frontmatter.js +1 -1
  86. package/dist/lib/templates/index.d.ts +2 -1
  87. package/dist/lib/templates/index.js +1 -1
  88. package/dist/lib/templates/metadata.d.ts +1 -0
  89. package/dist/lib/templates/project.d.ts +1 -0
  90. package/dist/lib/utilities/codemeta-helpers.js +14 -13
  91. package/dist/lib/utilities/fetch.js +18 -2
  92. package/dist/lib/utilities/formatting.js +1 -1
  93. package/dist/lib/utilities/github.js +2 -2
  94. package/dist/lib/utilities/license-identification.d.ts +9 -4
  95. package/dist/lib/utilities/license-identification.js +37 -23
  96. package/dist/lib/utilities/template-helpers.d.ts +7 -5
  97. package/dist/lib/utilities/template-helpers.js +15 -14
  98. package/dist/lib/utilities/tree-sitter-wasm.d.ts +0 -1
  99. package/dist/lib/utilities/tree-sitter-wasm.js +1 -1
  100. package/package.json +18 -17
  101. package/readme.md +13 -11
  102. package/dist/bin/renovate-CpDMbQZd.js +0 -1
  103. package/dist/bin/shared-Dix5HPlG.js +0 -6
@@ -1,17 +1,27 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
-
3
2
  //#region src/lib/sources/python-pypi-registry.d.ts
4
3
  type PythonPypiRegistryInfo = {
5
- /** Total downloads over the last 180 days. */downloads180Days?: number; /** Downloads in the last day. */
6
- downloadsDaily?: number; /** Downloads in the last month. */
7
- downloadsMonthly?: number; /** Downloads in the last week. */
8
- downloadsWeekly?: number; /** ISO 8601 date the package was last published. */
9
- publishDateLatest?: string; /** Total number of releases on PyPI. */
10
- releaseCount?: number; /** Size in bytes of the latest release artifact. */
11
- sizeBytes?: number; /** PyPI project URL. */
12
- url?: string; /** Latest published version string. */
13
- versionLatest?: string; /** Whether the latest version has been yanked. */
14
- yanked?: boolean; /** Reason the version was yanked, if provided. */
4
+ /** Total downloads over the last 180 days. */
5
+ downloads180Days?: number;
6
+ /** Downloads in the last day. */
7
+ downloadsDaily?: number;
8
+ /** Downloads in the last month. */
9
+ downloadsMonthly?: number;
10
+ /** Downloads in the last week. */
11
+ downloadsWeekly?: number;
12
+ /** ISO 8601 date the package was last published. */
13
+ publishDateLatest?: string;
14
+ /** Total number of releases on PyPI. */
15
+ releaseCount?: number;
16
+ /** Size in bytes of the latest release artifact. */
17
+ sizeBytes?: number;
18
+ /** PyPI project URL. */
19
+ url?: string;
20
+ /** Latest published version string. */
21
+ versionLatest?: string;
22
+ /** Whether the latest version has been yanked. */
23
+ yanked?: boolean;
24
+ /** Reason the version was yanked, if provided. */
15
25
  yankedReason?: string;
16
26
  };
17
27
  type PythonPypiRegistryData = OneOrMany<SourceRecord<PythonPypiRegistryInfo>> | undefined;
@@ -35,8 +35,7 @@ const pythonPypiRegistrySource = defineSource({
35
35
  log.debug("Skipping Python PyPI registry data source since we're in offline mode");
36
36
  return [];
37
37
  }
38
- let packageNames = [];
39
- packageNames = ensureArray(context.metadata?.pythonPyprojectToml).filter((value) => !hasPrivateClassifier(value.data.project?.classifiers, value.data.project?.name, context.options.path)).map((value) => value.data.project?.name).filter((value) => value !== void 0);
38
+ let packageNames = ensureArray(context.metadata?.pythonPyprojectToml).filter((value) => !hasPrivateClassifier(value.data.project?.classifiers, value.data.project?.name, context.options.path)).map((value) => value.data.project?.name).filter((value) => value !== void 0);
40
39
  if (packageNames.length === 0) packageNames = ensureArray(context.metadata?.pythonSetupCfg).filter((value) => !hasPrivateClassifier(value.data.classifiers, value.data.name, context.options.path)).map((value) => value.data.name).filter((value) => value !== void 0);
41
40
  if (packageNames.length === 0) packageNames = ensureArray(context.metadata?.pythonSetupPy).filter((value) => !hasPrivateClassifier(value.data.classifiers, value.data.name, context.options.path)).map((value) => value.data.name).filter((value) => value !== void 0);
42
41
  if (packageNames.length === 0) packageNames = ensureArray(context.metadata?.pythonPkgInfo).filter((value) => !hasPrivateClassifier(value.data.classifiers, value.data.name, context.options.path)).map((value) => value.data.name).filter((value) => value !== void 0);
@@ -61,18 +60,9 @@ const pythonPypiRegistrySource = defineSource({
61
60
  log.debug("Extracting PyPI metadata...");
62
61
  const name = input;
63
62
  const [pypiResult, pypistatsRecentResult, pypistatsOverallResult] = await Promise.all([
64
- fetchWithRetry(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`).then(async (response) => {
65
- if (!response.ok) return;
66
- return pypiResponseSchema.parse(await response.json());
67
- }).catch(() => void 0),
68
- fetchWithRetry(`https://pypistats.org/api/packages/${encodeURIComponent(name)}/recent`).then(async (response) => {
69
- if (!response.ok) return;
70
- return pypistatsRecentSchema.parse(await response.json());
71
- }).catch(() => void 0),
72
- fetchWithRetry(`https://pypistats.org/api/packages/${encodeURIComponent(name)}/overall?mirrors=false`).then(async (response) => {
73
- if (!response.ok) return;
74
- return pypistatsOverallSchema.parse(await response.json());
75
- }).catch(() => void 0)
63
+ fetchJson(`https://pypi.org/pypi/${encodeURIComponent(name)}/json`, pypiResponseSchema),
64
+ fetchJson(`https://pypistats.org/api/packages/${encodeURIComponent(name)}/recent`, pypistatsRecentSchema),
65
+ fetchJson(`https://pypistats.org/api/packages/${encodeURIComponent(name)}/overall?mirrors=false`, pypistatsOverallSchema)
76
66
  ]);
77
67
  if (!pypiResult) return;
78
68
  const latestUploadTime = pypiResult.urls[0]?.upload_time_iso_8601;
@@ -86,14 +76,18 @@ const pythonPypiRegistrySource = defineSource({
86
76
  };
87
77
  if (pypiResult.info.yanked) {
88
78
  info.yanked = true;
89
- if (pypiResult.info.yanked_reason) info.yankedReason = pypiResult.info.yanked_reason;
79
+ const yankedReason = pypiResult.info.yanked_reason;
80
+ if (yankedReason !== null && yankedReason !== void 0 && yankedReason !== "") info.yankedReason = yankedReason;
90
81
  }
91
82
  if (pypistatsRecentResult) {
92
83
  info.downloadsDaily = pypistatsRecentResult.data.last_day;
93
84
  info.downloadsMonthly = pypistatsRecentResult.data.last_month;
94
85
  info.downloadsWeekly = pypistatsRecentResult.data.last_week;
95
86
  }
96
- if (pypistatsOverallResult) info.downloads180Days = pypistatsOverallResult.data.reduce((sum, entry) => sum + entry.downloads, 0) || void 0;
87
+ if (pypistatsOverallResult) {
88
+ const downloads180Days = pypistatsOverallResult.data.reduce((sum, entry) => sum + entry.downloads, 0);
89
+ info.downloads180Days = downloads180Days === 0 || Number.isNaN(downloads180Days) ? void 0 : downloads180Days;
90
+ }
97
91
  return {
98
92
  data: info,
99
93
  source: `https://pypi.org/project/${encodeURIComponent(name)}/`
@@ -102,6 +96,19 @@ const pythonPypiRegistrySource = defineSource({
102
96
  phase: 2
103
97
  });
104
98
  /**
99
+ * Fetch a URL and parse its JSON body with a Zod schema. Returns undefined when
100
+ * the request fails, the response is not OK, or the body doesn't validate.
101
+ */
102
+ async function fetchJson(url, schema) {
103
+ try {
104
+ const response = await fetchWithRetry(url);
105
+ if (!response.ok) return;
106
+ return schema.parse(await response.json());
107
+ } catch {
108
+ return;
109
+ }
110
+ }
111
+ /**
105
112
  * Check if classifiers contain a "Private ::" prefix, which signals that the
106
113
  * package is not intended for publication on PyPI. PyPI itself rejects uploads
107
114
  * with this classifier.
@@ -1,6 +1,5 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { PyprojectData } from "read-pyproject";
3
-
4
3
  //#region src/lib/sources/python-pyproject-toml.d.ts
5
4
  type PythonPyprojectTomlData = OneOrMany<SourceRecord<PyprojectData>> | undefined;
6
5
  //#endregion
@@ -1,8 +1,7 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/lib/sources/python-setup-cfg.d.ts
5
- declare const setupCfgDataSchema: z.ZodObject<{
4
+ declare const setupConfigDataSchema: z.ZodObject<{
6
5
  author: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodString>>>;
7
6
  author_email: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodString>>>;
8
7
  classifiers: z.ZodDefault<z.ZodPreprocess<z.ZodArray<z.ZodString>>>;
@@ -22,7 +21,7 @@ declare const setupCfgDataSchema: z.ZodObject<{
22
21
  version: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodString>>>;
23
22
  }, z.core.$strip>;
24
23
  /** Parsed setup.cfg metadata */
25
- type SetupCfg = z.infer<typeof setupCfgDataSchema>;
24
+ type SetupCfg = z.infer<typeof setupConfigDataSchema>;
26
25
  type PythonSetupCfgData = OneOrMany<SourceRecord<SetupCfg>> | undefined;
27
26
  //#endregion
28
27
  export { PythonSetupCfgData, SetupCfg };
@@ -5,9 +5,10 @@ import { splitCommaSeparated } from "../utilities/template-helpers.js";
5
5
  import { parseConfigparser, splitMultiline } from "../parsers/configparser-parser.js";
6
6
  import { readFile } from "node:fs/promises";
7
7
  import { resolve } from "node:path";
8
+ import is from "@sindresorhus/is";
8
9
  import { z } from "zod";
9
10
  //#region src/lib/sources/python-setup-cfg.ts
10
- const setupCfgDataSchema = z.object({
11
+ const setupConfigDataSchema = z.object({
11
12
  author: nonEmptyString,
12
13
  author_email: nonEmptyString,
13
14
  classifiers: stringArray,
@@ -71,23 +72,23 @@ function parse(source) {
71
72
  };
72
73
  for (const key of STRING_ATTRS) {
73
74
  const value = metadata[key];
74
- if (value) Object.assign(data, { [key]: value });
75
+ if (is.nonEmptyString(value)) Object.assign(data, { [key]: value });
75
76
  }
76
- if (metadata.classifiers) data.classifiers = splitMultiline(metadata.classifiers);
77
- if (metadata.keywords) data.keywords = splitCommaSeparated(metadata.keywords);
78
- if (metadata.project_urls) for (const line of splitMultiline(metadata.project_urls)) {
77
+ if (is.nonEmptyString(metadata.classifiers)) data.classifiers = splitMultiline(metadata.classifiers);
78
+ if (is.nonEmptyString(metadata.keywords)) data.keywords = splitCommaSeparated(metadata.keywords);
79
+ if (is.nonEmptyString(metadata.project_urls)) for (const line of splitMultiline(metadata.project_urls)) {
79
80
  const eqIndex = line.indexOf("=");
80
81
  if (eqIndex > 0) {
81
82
  const label = line.slice(0, eqIndex).trim();
82
83
  const url = line.slice(eqIndex + 1).trim();
83
- if (url) data.project_urls[label] = url;
84
+ if (url !== "") data.project_urls[label] = url;
84
85
  }
85
86
  }
86
- if (options.install_requires) data.install_requires = splitMultiline(options.install_requires);
87
- if (options.python_requires) data.python_requires = options.python_requires;
87
+ if (is.nonEmptyString(options.install_requires)) data.install_requires = splitMultiline(options.install_requires);
88
+ if (is.nonEmptyString(options.python_requires)) data.python_requires = options.python_requires;
88
89
  const extrasSection = sections["options.extras_require"];
89
90
  if (extrasSection) for (const [key, value] of Object.entries(extrasSection)) data.extras_require[key] = splitMultiline(value);
90
- return setupCfgDataSchema.parse(data);
91
+ return setupConfigDataSchema.parse(data);
91
92
  }
92
93
  const pythonSetupCfgSource = defineSource({
93
94
  async discover(context) {
@@ -1,6 +1,5 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/lib/sources/python-setup-py.d.ts
5
4
  /** Parsed setup.py metadata */
6
5
  declare const setupPyDataSchema: z.ZodObject<{
@@ -1,6 +1,5 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/lib/sources/readme-file.d.ts
5
4
  declare const readmeSchema: z.ZodObject<{
6
5
  frontmatter: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
@@ -33,7 +33,8 @@ const markdownParser = unified().use(remarkParse);
33
33
  */
34
34
  function extractFirstH1(markdown) {
35
35
  const tree = markdownParser.parse(markdown);
36
- for (const node of tree.children) if (node.type === "heading" && node.depth === 1) {
36
+ for (const node of tree.children) {
37
+ if (node.type !== "heading" || node.depth !== 1) continue;
37
38
  const text = extractText(node.children);
38
39
  if (text.length > 0) return text;
39
40
  }
@@ -48,7 +49,7 @@ function extractFirstH1(markdown) {
48
49
  function parse(content) {
49
50
  const { content: markdown, data } = matter(content);
50
51
  const name = extractFirstH1(markdown);
51
- if (!name) return;
52
+ if (name === void 0 || name === "") return;
52
53
  return readmeSchema.parse({
53
54
  frontmatter: Object.keys(data).length > 0 ? data : void 0,
54
55
  name
@@ -61,7 +62,7 @@ const readmeFileSource = defineSource({
61
62
  key: "readmeFile",
62
63
  async parse(input, context) {
63
64
  const data = parse(await readFile(resolve(context.options.path, input), "utf8"));
64
- if (data !== void 0) return {
65
+ return data === void 0 ? void 0 : {
65
66
  data,
66
67
  source: input
67
68
  };
@@ -1,6 +1,5 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/lib/sources/ruby-gemspec.d.ts
5
4
  /** @public */
6
5
  declare const gemSpecSchema: z.ZodObject<{
@@ -1,6 +1,5 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/lib/sources/rust-cargo-toml.d.ts
5
4
  declare const cargoTomlSchema: z.ZodObject<{
6
5
  authors: z.ZodArray<z.ZodObject<{
@@ -167,7 +167,7 @@ const rustCargoTomlSource = defineSource({
167
167
  key: "rustCargoToml",
168
168
  async parse(input, context) {
169
169
  const data = parse$1(await readFile(resolve(context.options.path, input), "utf8"));
170
- if (data !== void 0) return {
170
+ return data === void 0 ? void 0 : {
171
171
  data,
172
172
  source: input
173
173
  };
@@ -1,6 +1,5 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/lib/sources/xcode-info-plist.d.ts
5
4
  declare const infoPlistSchema: z.ZodObject<{
6
5
  applicationCategory: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodString>>>;
@@ -18,11 +18,11 @@ import { parse } from "plist";
18
18
  *
19
19
  * Uses the `plist` npm package to parse XML plist format.
20
20
  */
21
- const COPYRIGHT_YEAR_REGEX = /(?:©|\(c\)|copyright)\s*(\d{4})/i;
22
- const COPYRIGHT_HOLDER_REGEX = /(?:©|\(c\)|copyright)\s*\d{4}\s*(.+)/i;
23
- const ALL_RIGHTS_RESERVED_REGEX = /\.\s*all\s+rights\s+reserved\.?/i;
24
- const TRAILING_PUNCTUATION_REGEX = /[.,;]+$/;
25
- const PROCESSOR_ARCH_REGEX = /^(?:arm|x86|i386)/i;
21
+ const COPYRIGHT_YEAR_REGEX = /(?:©|\(c\)|copyright)\s*(\d{4})/iv;
22
+ const COPYRIGHT_HOLDER_REGEX = /(?:©|\(c\)|copyright)\s*\d{4}\s*(.+)/iv;
23
+ const ALL_RIGHTS_RESERVED_REGEX = /\.\s*all\s+rights\s+reserved\.?/iv;
24
+ const TRAILING_PUNCTUATION_REGEX = /[.,;]+$/v;
25
+ const PROCESSOR_ARCH_REGEX = /^(?:arm|x86|i386)/iv;
26
26
  const infoPlistSchema = z.object({
27
27
  /** Application category (humanized from UTI). */
28
28
  applicationCategory: nonEmptyString,
@@ -50,9 +50,9 @@ const infoPlistSchema = z.object({
50
50
  version: nonEmptyString
51
51
  });
52
52
  /** Xcode build variable pattern: $(VAR) or ${VAR}. */
53
- const XCODE_VARIABLE_RE = /\$[({][^)}]+[)}]/;
53
+ const XCODE_VARIABLE_RE = /\$[\(\{][^\)\}]+[\)\}]/v;
54
54
  /** XML comment, including malformed ones with `--` inside. */
55
- const XML_COMMENT_RE = /<!--[\s\S]*?-->/g;
55
+ const XML_COMMENT_RE = /<!--[\s\S]*?-->/gv;
56
56
  /**
57
57
  * Map DTPlatformName / CFBundleSupportedPlatforms values to human-readable OS
58
58
  * names.
@@ -81,11 +81,11 @@ function parse$1(content) {
81
81
  const { copyrightHolder, copyrightYear } = parseCopyright(data);
82
82
  const authorName = getString(data, "createdby") ?? getString(data, "contactName");
83
83
  const authorEmailRot13 = getString(data, "contactEmailRot13");
84
- const authorEmail = authorEmailRot13 ? rot13(authorEmailRot13) : void 0;
84
+ const authorEmail = authorEmailRot13 === void 0 ? void 0 : rot13(authorEmailRot13);
85
85
  const url = getString(data, "webaddress");
86
- const applicationCategory = parseApplicationCategory(data);
86
+ const appCategory = parseAppCategory(data);
87
87
  return infoPlistSchema.parse({
88
- applicationCategory,
88
+ applicationCategory: appCategory,
89
89
  author: authorName,
90
90
  authorEmail,
91
91
  copyrightHolder,
@@ -127,7 +127,7 @@ function getString(data, key) {
127
127
  * ROT13-decode a string (used by TextMate bundles for obfuscated emails).
128
128
  */
129
129
  function rot13(value) {
130
- return value.replaceAll(/[a-z]/gi, (c) => {
130
+ return value.replaceAll(/[a-z]/giv, (c) => {
131
131
  const base = c <= "Z" ? 65 : 97;
132
132
  return String.fromCodePoint((c.codePointAt(0) - base + 13) % 26 + base);
133
133
  });
@@ -143,9 +143,9 @@ function humanizeCategory(uti) {
143
143
  /**
144
144
  * Parse application category from LSApplicationCategoryType.
145
145
  */
146
- function parseApplicationCategory(data) {
146
+ function parseAppCategory(data) {
147
147
  const category = getString(data, "LSApplicationCategoryType");
148
- if (!category) return;
148
+ if (category === void 0) return;
149
149
  return humanizeCategory(category);
150
150
  }
151
151
  /**
@@ -154,12 +154,12 @@ function parseApplicationCategory(data) {
154
154
  */
155
155
  function parseCopyright(data) {
156
156
  const copyrightSource = getString(data, "NSHumanReadableCopyright") ?? getString(data, "CFBundleGetInfoString");
157
- if (!copyrightSource) return {};
157
+ if (copyrightSource === void 0) return {};
158
158
  const copyrightYear = COPYRIGHT_YEAR_REGEX.exec(copyrightSource)?.[1];
159
- const holderMatch = COPYRIGHT_HOLDER_REGEX.exec(copyrightSource);
159
+ const holderText = COPYRIGHT_HOLDER_REGEX.exec(copyrightSource)?.[1];
160
160
  let copyrightHolder;
161
- if (holderMatch) {
162
- copyrightHolder = holderMatch[1].replace(ALL_RIGHTS_RESERVED_REGEX, "").replace(TRAILING_PUNCTUATION_REGEX, "").trim();
161
+ if (holderText !== void 0) {
162
+ copyrightHolder = holderText.replace(ALL_RIGHTS_RESERVED_REGEX, "").replace(TRAILING_PUNCTUATION_REGEX, "").trim();
163
163
  if (copyrightHolder.length === 0) copyrightHolder = void 0;
164
164
  }
165
165
  return {
@@ -174,27 +174,25 @@ function parseOperatingSystems(data) {
174
174
  const results = [];
175
175
  const seen = /* @__PURE__ */ new Set();
176
176
  function add(value) {
177
- if (!seen.has(value)) {
178
- seen.add(value);
179
- results.push(value);
180
- }
177
+ if (seen.has(value)) return;
178
+ seen.add(value);
179
+ results.push(value);
181
180
  }
182
181
  const minMacOS = getString(data, "LSMinimumSystemVersion");
183
- if (minMacOS) add(`macOS >= ${minMacOS}`);
182
+ if (minMacOS !== void 0) add(`macOS >= ${minMacOS}`);
184
183
  const minIOS = getString(data, "MinimumOSVersion");
185
- if (minIOS) add(`iOS >= ${minIOS}`);
184
+ if (minIOS !== void 0) add(`iOS >= ${minIOS}`);
186
185
  if (results.length > 0) return results;
187
186
  const platformName = getString(data, "DTPlatformName");
188
- if (platformName) {
187
+ if (platformName !== void 0) {
189
188
  const os = PLATFORM_NAME_MAP[platformName.toLowerCase()];
190
- if (os) add(os);
189
+ if (os !== void 0) add(os);
191
190
  }
192
191
  const supportedPlatforms = data.CFBundleSupportedPlatforms;
193
- if (Array.isArray(supportedPlatforms)) {
194
- for (const p of supportedPlatforms) if (typeof p === "string") {
195
- const os = PLATFORM_NAME_MAP[p.toLowerCase()];
196
- if (os) add(os);
197
- }
192
+ if (Array.isArray(supportedPlatforms)) for (const p of supportedPlatforms) {
193
+ if (typeof p !== "string") continue;
194
+ const os = PLATFORM_NAME_MAP[p.toLowerCase()];
195
+ if (os !== void 0) add(os);
198
196
  }
199
197
  if (data.LSRequiresIPhoneOS === true && !seen.has("iOS")) add("iOS");
200
198
  return results;
@@ -217,7 +215,7 @@ const xcodeInfoPlistSource = defineSource({
217
215
  key: "xcodeInfoPlist",
218
216
  async parse(input, context) {
219
217
  const data = parse$1(await readFile(resolve(context.options.path, input), "utf8"));
220
- if (data !== void 0) return {
218
+ return data === void 0 ? void 0 : {
221
219
  data,
222
220
  source: input
223
221
  };
@@ -1,6 +1,5 @@
1
1
  import { OneOrMany, SourceRecord } from "../source.js";
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/lib/sources/xcode-project-pbxproj.d.ts
5
4
  declare const pbxprojSchema: z.ZodObject<{
6
5
  copyrightHolder: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodString>>>;
@@ -22,10 +22,10 @@ import { PBXNativeTarget, XCRemoteSwiftPackageReference, XcodeProject } from "@m
22
22
  * - Build settings on the main app target (Release config preferred)
23
23
  * - Swift Package Manager dependencies
24
24
  */
25
- const COPYRIGHT_YEAR_REGEX = /(?:©|\(c\)|copyright)\s*(\d{4})/i;
26
- const COPYRIGHT_HOLDER_REGEX = /(?:©|\(c\)|copyright)\s*\d{4}\s*(.+)/i;
27
- const ALL_RIGHTS_RESERVED_REGEX = /\.\s*all\s+rights\s+reserved\.?/i;
28
- const TRAILING_PUNCTUATION_REGEX = /[.,;]+$/;
25
+ const COPYRIGHT_YEAR_REGEX = /(?:©|\(c\)|copyright)\s*(\d{4})/iv;
26
+ const COPYRIGHT_HOLDER_REGEX = /(?:©|\(c\)|copyright)\s*\d{4}\s*(.+)/iv;
27
+ const ALL_RIGHTS_RESERVED_REGEX = /\.\s*all\s+rights\s+reserved\.?/iv;
28
+ const TRAILING_PUNCTUATION_REGEX = /[.,;]+$/v;
29
29
  const pbxprojDependencySchema = z.object({ url: z.string() });
30
30
  const pbxprojSchema = z.object({
31
31
  /** Copyright holder name. */
@@ -48,7 +48,7 @@ const pbxprojSchema = z.object({
48
48
  version: nonEmptyString
49
49
  });
50
50
  /** Xcode build variable pattern: $(VAR) or ${VAR}. */
51
- const XCODE_VARIABLE_RE = /\$[({][^)}]+[)}]/;
51
+ const XCODE_VARIABLE_RE = /\$[\(\{][^\)\}]+[\)\}]/v;
52
52
  /**
53
53
  * Map SDKROOT values to human-readable OS names.
54
54
  */
@@ -122,8 +122,9 @@ function parse(filePath) {
122
122
  const { copyrightHolder, copyrightYear } = parseCopyrightString(getSetting(targetSettings, projectSettings, "INFOPLIST_KEY_NSHumanReadableCopyright"));
123
123
  const swiftVersion = getSetting(targetSettings, projectSettings, "SWIFT_VERSION");
124
124
  let programmingLanguage;
125
- if (swiftVersion) programmingLanguage = "Swift";
126
- else if (getSetting(targetSettings, projectSettings, "GCC_C_LANGUAGE_STANDARD")) programmingLanguage = "Objective-C";
125
+ if (swiftVersion === void 0) {
126
+ if (getSetting(targetSettings, projectSettings, "GCC_C_LANGUAGE_STANDARD") !== void 0) programmingLanguage = "Objective-C";
127
+ } else programmingLanguage = "Swift";
127
128
  return pbxprojSchema.parse({
128
129
  copyrightHolder,
129
130
  copyrightYear,
@@ -171,12 +172,12 @@ function getResolvedSetting(config, targetSettings, projectSettings, key) {
171
172
  * Parse copyright information from a copyright string.
172
173
  */
173
174
  function parseCopyrightString(copyrightSource) {
174
- if (!copyrightSource) return {};
175
+ if (copyrightSource === void 0) return {};
175
176
  const copyrightYear = COPYRIGHT_YEAR_REGEX.exec(copyrightSource)?.[1];
176
- const holderMatch = COPYRIGHT_HOLDER_REGEX.exec(copyrightSource);
177
+ const holderText = COPYRIGHT_HOLDER_REGEX.exec(copyrightSource)?.[1];
177
178
  let copyrightHolder;
178
- if (holderMatch) {
179
- copyrightHolder = holderMatch[1].replace(ALL_RIGHTS_RESERVED_REGEX, "").replace(TRAILING_PUNCTUATION_REGEX, "").trim();
179
+ if (holderText !== void 0) {
180
+ copyrightHolder = holderText.replace(ALL_RIGHTS_RESERVED_REGEX, "").replace(TRAILING_PUNCTUATION_REGEX, "").trim();
180
181
  if (copyrightHolder.length === 0) copyrightHolder = void 0;
181
182
  }
182
183
  return {
@@ -192,7 +193,7 @@ function parseOperatingSystems(targetSettings, projectSettings) {
192
193
  const seen = /* @__PURE__ */ new Set();
193
194
  for (const { key, os } of DEPLOYMENT_TARGETS) {
194
195
  const version = getSetting(targetSettings, projectSettings, key);
195
- if (version) {
196
+ if (version !== void 0) {
196
197
  const value = `${os} >= ${version}`;
197
198
  if (!seen.has(value)) {
198
199
  seen.add(value);
@@ -202,9 +203,9 @@ function parseOperatingSystems(targetSettings, projectSettings) {
202
203
  }
203
204
  if (results.length === 0) {
204
205
  const sdkroot = getSetting(targetSettings, projectSettings, "SDKROOT");
205
- if (sdkroot && sdkroot !== "auto") {
206
+ if (sdkroot !== void 0 && sdkroot !== "auto") {
206
207
  const os = SDKROOT_MAP[sdkroot];
207
- if (os) results.push(os);
208
+ if (os !== void 0) results.push(os);
208
209
  }
209
210
  }
210
211
  return results;
@@ -218,7 +219,7 @@ function parseDependencies(root) {
218
219
  for (const packageReference of packageReferences) {
219
220
  if (!XCRemoteSwiftPackageReference.is(packageReference)) continue;
220
221
  const url = cleanString(packageReference.props.repositoryURL);
221
- if (url) results.push({ url });
222
+ if (url !== void 0) results.push({ url });
222
223
  }
223
224
  return results;
224
225
  }
@@ -229,7 +230,7 @@ const xcodeProjectPbxprojSource = defineSource({
229
230
  key: "xcodeProjectPbxproj",
230
231
  async parse(input, context) {
231
232
  const data = parse(resolve(context.options.path, input));
232
- if (data !== void 0) return {
233
+ return data === void 0 ? void 0 : {
233
234
  data,
234
235
  source: input
235
236
  };
@@ -1,4 +1,5 @@
1
1
  import { Template } from "../metadata-types.js";
2
+ import "../index.js";
2
3
  //#region src/lib/templates/codemeta-json.d.ts
3
4
  type TemplateDataCodemetaJson = ReturnType<typeof codemetaJson>;
4
5
  /**
@@ -1,5 +1,6 @@
1
1
  import { Template } from "../metadata-types.js";
2
2
  import { CodemetaDependencyLd, CodemetaPersonOrOrgLd } from "../utilities/codemeta-helpers.js";
3
+ import "../index.js";
3
4
  //#region src/lib/templates/codemeta.d.ts
4
5
  type TemplateDataCodemeta = ReturnType<typeof codemeta>;
5
6
  declare const codemeta: Template<{