metascope 0.8.5 → 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 +5 -3
  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
@@ -147,7 +147,7 @@ async function getMatches(options, patterns, patternsRecursive) {
147
147
  if (resolved.recursive) effectivePatterns = patternsRecursive ?? patterns.map((p) => `**/${p}`);
148
148
  else {
149
149
  effectivePatterns = [...patterns];
150
- if (resolved.workspaces) {
150
+ if (resolved.workspaces !== false) {
151
151
  const workspacePaths = getWorkspaces(resolved.path, resolved.workspaces);
152
152
  for (const workspace of workspacePaths) {
153
153
  const relativeWorkspace = relative(resolved.path, workspace).replaceAll("\\", "/");
@@ -162,7 +162,10 @@ async function getMatches(options, patterns, patternsRecursive) {
162
162
  depth: p.split(sep).length,
163
163
  path: p
164
164
  }));
165
- decorated.sort((a, b) => a.depth - b.depth || a.path.localeCompare(b.path));
165
+ decorated.sort((a, b) => {
166
+ const depthDelta = a.depth - b.depth;
167
+ return depthDelta === 0 ? a.path.localeCompare(b.path) : depthDelta;
168
+ });
166
169
  return decorated.map((d) => d.path);
167
170
  }
168
171
  //#endregion
package/dist/lib/log.d.ts CHANGED
@@ -1,5 +1,4 @@
1
1
  import { ILogBasic, ILogLayer } from "lognow";
2
-
3
2
  //#region src/lib/log.d.ts
4
3
  /**
5
4
  * Set the logger instance for the module. Export this for library consumers to
@@ -33,7 +33,6 @@ import { RubyGemspecData } from "./sources/ruby-gemspec.js";
33
33
  import { RustCargoTomlData } from "./sources/rust-cargo-toml.js";
34
34
  import { XcodeInfoPlistData } from "./sources/xcode-info-plist.js";
35
35
  import { XcodeProjectPbxprojData } from "./sources/xcode-project-pbxproj.js";
36
-
37
36
  //#region src/lib/metadata-types.d.ts
38
37
  /**
39
38
  * The complete metadata context assembled from all sources. Each key
@@ -123,17 +122,23 @@ type GetMetadataBaseOptions = {
123
122
  * workspaceDirectories, etc.) are absolute. When false, paths are relative to
124
123
  * the project directory.
125
124
  */
126
- absolute?: boolean; /** API credentials for remote sources. */
127
- credentials?: Credentials; /** Skip web sources (npm registry, GitHub API, PyPI, etc.). */
125
+ absolute?: boolean;
126
+ /** API credentials for remote sources. */
127
+ credentials?: Credentials;
128
+ /** Skip web sources (npm registry, GitHub API, PyPI, etc.). */
128
129
  offline?: boolean;
129
130
  /**
130
131
  * Project directory path. Defaults to `'.'` (resolved to `process.cwd()` via
131
132
  * `path.resolve`).
132
133
  */
133
- path: string; /** Search for metadata files recursively in subdirectories. Defaults to false. */
134
- recursive?: boolean; /** Ignore files specified .gitignore in the file tree. Defaults to true. */
135
- respectIgnored?: boolean; /** Only run these specific sources. Defaults to all sources when undefined. */
136
- sources?: SourceName[]; /** User-supplied data passed to templates. */
134
+ path: string;
135
+ /** Search for metadata files recursively in subdirectories. Defaults to false. */
136
+ recursive?: boolean;
137
+ /** Ignore files specified .gitignore in the file tree. Defaults to true. */
138
+ respectIgnored?: boolean;
139
+ /** Only run these specific sources. Defaults to all sources when undefined. */
140
+ sources?: SourceName[];
141
+ /** User-supplied data passed to templates. */
137
142
  templateData?: TemplateData;
138
143
  /**
139
144
  * Directories to any monorepo workspaces... only supports yarn, npm, pnpm,
@@ -152,14 +157,16 @@ declare const DEFAULT_GET_METADATA_OPTIONS: Required<Omit<GetMetadataBaseOptions
152
157
  * `MetadataContext`).
153
158
  */
154
159
  type GetMetadataOptions = GetMetadataBaseOptions & {
155
- /** Built-in template name or omit for full output. */template?: 'frontmatter' | 'metadata' | 'project' | (string & {});
160
+ /** Built-in template name or omit for full output. */
161
+ template?: 'frontmatter' | 'metadata' | 'project' | (string & {});
156
162
  };
157
163
  /**
158
164
  * Options for `getMetadata` with a template function (returns the template's
159
165
  * return type).
160
166
  */
161
167
  type GetMetadataTemplateOptions<T> = GetMetadataBaseOptions & {
162
- /** Template function that transforms MetadataContext into a custom shape. */template: Template<T>;
168
+ /** Template function that transforms MetadataContext into a custom shape. */
169
+ template: Template<T>;
163
170
  };
164
171
  //#endregion
165
172
  export { Credentials, DEFAULT_GET_METADATA_OPTIONS, GetMetadataBaseOptions, GetMetadataOptions, GetMetadataTemplateOptions, MetadataContext, SourceName, Template, TemplateData, defineTemplate };
@@ -1,6 +1,5 @@
1
1
  import { GetMetadataOptions, GetMetadataTemplateOptions, MetadataContext, SourceName } from "./metadata-types.js";
2
2
  import { TemplateMap, TemplateName } from "./templates/index.js";
3
-
4
3
  //#region src/lib/metadata.d.ts
5
4
  /** All available source key names, for runtime use (e.g. CLI choices). */
6
5
  declare const sourceNames: SourceName[];
@@ -95,16 +95,16 @@ const sourceNames = sources.map((s) => s.key);
95
95
  * Resolve GitHub token from multiple sources, in precedence order.
96
96
  */
97
97
  async function resolveCredentials(credentials) {
98
- if (credentials?.githubToken) return credentials;
98
+ if (credentials?.githubToken !== void 0 && credentials.githubToken !== "") return credentials;
99
99
  const environmentToken = process.env.GITHUB_TOKEN;
100
- if (environmentToken) return {
100
+ if (environmentToken !== void 0 && environmentToken !== "") return {
101
101
  ...credentials,
102
102
  githubToken: environmentToken
103
103
  };
104
104
  try {
105
105
  const { stdout } = await execFileAsync("gh", ["auth", "token"]);
106
106
  const token = stdout.trim();
107
- if (token) return {
107
+ if (token !== "") return {
108
108
  ...credentials,
109
109
  githubToken: token
110
110
  };
@@ -205,8 +205,8 @@ async function getMetadata(options) {
205
205
  };
206
206
  const activeSources = resolvedOptions.sources ? sources.filter((s) => resolvedOptions.sources.includes(s.key)) : sources;
207
207
  const completedSources = /* @__PURE__ */ new Set();
208
- const phases = new Set(activeSources.map((s) => s.phase));
209
- for (const phase of [...phases].toSorted((a, b) => a - b)) {
208
+ const sortedPhases = [...new Set(activeSources.map((s) => s.phase))].toSorted((a, b) => a - b);
209
+ for (const phase of sortedPhases) {
210
210
  const phaseSources = activeSources.filter((s) => s.phase === phase);
211
211
  log.debug(`Phase ${phase}: Running ${phaseSources.length} sources...`);
212
212
  await runSources(phaseSources, {
@@ -1,5 +1,5 @@
1
1
  //#region package.json
2
2
  var name = "metascope";
3
- var version = "0.8.5";
3
+ var version = "0.9.0";
4
4
  //#endregion
5
5
  export { name, version };
@@ -1,7 +1,7 @@
1
1
  //#region src/lib/parsers/configparser-parser.ts
2
- const SECTION_HEADER_REGEX = /^\[([^\]]+)\]/;
3
- const LEADING_WHITESPACE_REGEX = /^\s/;
4
- const KEY_VALUE_PAIR_REGEX = /^([^=:]+)[=:](.*)$/;
2
+ const SECTION_HEADER_REGEX = /^\[([^\]]+)\]/v;
3
+ const LEADING_WHITESPACE_REGEX = /^\s/v;
4
+ const KEY_VALUE_PAIR_REGEX = /^([^=:]+)[=:](.*)$/v;
5
5
  /**
6
6
  * Parse a ConfigParser-style INI file into sections with key-value pairs.
7
7
  * Handles Python ConfigParser conventions: multi-line values via indented
@@ -16,23 +16,25 @@ function parseConfigparser(content) {
16
16
  if (trimmed === "" || trimmed.startsWith("#") || trimmed.startsWith(";")) continue;
17
17
  const sectionMatch = SECTION_HEADER_REGEX.exec(trimmed);
18
18
  if (sectionMatch) {
19
- currentSection = sectionMatch[1];
19
+ currentSection = sectionMatch[1] ?? "";
20
20
  sections[currentSection] ??= {};
21
21
  lastKey = "";
22
22
  continue;
23
23
  }
24
- if (LEADING_WHITESPACE_REGEX.test(line) && lastKey && currentSection) {
25
- const existing = sections[currentSection][lastKey];
24
+ const continuationSection = sections[currentSection];
25
+ if (lastKey !== "" && currentSection !== "" && continuationSection !== void 0 && LEADING_WHITESPACE_REGEX.test(line)) {
26
+ const existing = continuationSection[lastKey];
26
27
  const continuation = trimmed.trim();
27
- if (continuation) sections[currentSection][lastKey] = existing ? `${existing}\n${continuation}` : continuation;
28
+ if (continuation !== "") continuationSection[lastKey] = existing !== void 0 && existing !== "" ? `${existing}\n${continuation}` : continuation;
28
29
  continue;
29
30
  }
30
31
  const kvMatch = KEY_VALUE_PAIR_REGEX.exec(trimmed);
31
- if (kvMatch && currentSection) {
32
- const key = kvMatch[1].trim();
33
- const value = kvMatch[2].trim();
34
- sections[currentSection] ??= {};
35
- sections[currentSection][key] = value;
32
+ if (kvMatch && currentSection !== "") {
33
+ const key = (kvMatch[1] ?? "").trim();
34
+ const value = (kvMatch[2] ?? "").trim();
35
+ const section = sections[currentSection] ?? {};
36
+ sections[currentSection] = section;
37
+ section[key] = value;
36
38
  lastKey = key;
37
39
  }
38
40
  }
@@ -1,7 +1,7 @@
1
1
  import { getRubyLanguage, initParser } from "../utilities/tree-sitter-wasm.js";
2
2
  import is from "@sindresorhus/is";
3
3
  //#region src/lib/parsers/gemspec-parser.ts
4
- const LEADING_COLON_REGEX = /^:/;
4
+ const LEADING_COLON_REGEX = /^:/v;
5
5
  function emptySpec() {
6
6
  return {
7
7
  authors: [],
@@ -44,24 +44,23 @@ const IDENTITY_METHODS = /* @__PURE__ */ new Set([
44
44
  ]);
45
45
  /** Extract the raw string value from a tree-sitter string/symbol node. */
46
46
  function extractString(node) {
47
- switch (node.type) {
48
- case "call": {
49
- const method = node.childForFieldName("method");
50
- if (method && IDENTITY_METHODS.has(method.text)) {
51
- const receiver = node.childForFieldName("receiver");
52
- if (receiver) return extractString(receiver);
53
- }
54
- return;
55
- }
47
+ let current = node;
48
+ while (current.type === "call") {
49
+ const method = current.childForFieldName("method");
50
+ const receiver = method && IDENTITY_METHODS.has(method.text) ? current.childForFieldName("receiver") : void 0;
51
+ if (!receiver) return;
52
+ current = receiver;
53
+ }
54
+ switch (current.type) {
56
55
  case "float":
57
- case "integer": return node.text;
58
- case "heredoc_body": return node.text.trim();
59
- case "simple_symbol": return node.text.replace(LEADING_COLON_REGEX, "");
56
+ case "integer": return current.text;
57
+ case "heredoc_body": return current.text.trim();
58
+ case "simple_symbol": return current.text.replace(LEADING_COLON_REGEX, "");
60
59
  case "string":
61
60
  case "string_content": {
62
- const parts = children(node).filter((c) => c.type === "string_content");
61
+ const parts = children(current).filter((c) => c.type === "string_content");
63
62
  if (parts.length > 0) return parts.map((p) => p.text).join("");
64
- return node.text.replaceAll(/^["']|["']$/g, "");
63
+ return current.text.replaceAll(/^["']|["']$/gv, "");
65
64
  }
66
65
  default: return;
67
66
  }
@@ -81,18 +80,18 @@ function extractStringArray(node) {
81
80
  * Evaluate (method calls, constants, etc.).
82
81
  */
83
82
  function extractValue(node) {
84
- if (node.type === "array" || node.type === "string_array") return extractStringArray(node);
85
- if (node.type === "call") {
86
- const method = node.childForFieldName("method");
87
- if (method && IDENTITY_METHODS.has(method.text)) {
88
- const receiver = node.childForFieldName("receiver");
89
- if (receiver) return extractValue(receiver);
90
- }
83
+ let current = node;
84
+ while (current.type === "call") {
85
+ const method = current.childForFieldName("method");
86
+ const receiver = method && IDENTITY_METHODS.has(method.text) ? current.childForFieldName("receiver") : void 0;
87
+ if (!receiver) break;
88
+ current = receiver;
91
89
  }
92
- if (node.type === "true") return "true";
93
- if (node.type === "false") return "false";
94
- if (node.type === "nil") return;
95
- return extractString(node);
90
+ if (current.type === "array" || current.type === "string_array") return extractStringArray(current);
91
+ if (current.type === "true") return "true";
92
+ if (current.type === "false") return "false";
93
+ if (current.type === "nil") return;
94
+ return extractString(current);
96
95
  }
97
96
  /** Resolve the attribute name from the LHS of `spec.foo = ...` */
98
97
  function resolveAttribute(node) {
@@ -109,30 +108,31 @@ function tryParseDependency(node) {
109
108
  if (!methodNode) return;
110
109
  let methodName;
111
110
  if (methodNode.type === "call") methodName = methodNode.childForFieldName("method")?.text ?? void 0;
112
- else if (methodNode.type === "identifier") methodName = methodNode.text;
113
111
  else methodName = methodNode.text;
114
- if (!methodName) {
112
+ if (methodName === void 0 || methodName === "") {
115
113
  const topMethod = node.childForFieldName("method");
116
114
  if (topMethod?.type === "identifier") methodName = topMethod.text;
117
115
  }
118
- if (!methodName || !DEP_METHODS[methodName]) {
116
+ if (methodName === void 0 || methodName === "" || DEP_METHODS[methodName] === void 0) {
119
117
  for (const m of Object.keys(DEP_METHODS)) if (node.text.includes(`.${m}`)) {
120
118
  methodName = m;
121
119
  break;
122
120
  }
123
121
  }
124
- if (!methodName || !DEP_METHODS[methodName]) return;
125
- const depType = DEP_METHODS[methodName];
122
+ if (methodName === void 0 || methodName === "") return;
123
+ const dependencyType = DEP_METHODS[methodName];
124
+ if (dependencyType === void 0) return;
126
125
  const arguments_ = node.childForFieldName("arguments");
127
126
  if (!arguments_) return;
128
127
  const argumentNodes = children(arguments_);
129
- if (argumentNodes.length === 0) return;
130
- const depName = extractString(argumentNodes[0]);
131
- if (!depName) return;
128
+ const firstArgument = argumentNodes[0];
129
+ if (firstArgument === void 0) return;
130
+ const dependencyName = extractString(firstArgument);
131
+ if (dependencyName === void 0 || dependencyName === "") return;
132
132
  return {
133
- name: depName,
133
+ name: dependencyName,
134
134
  requirements: argumentNodes.slice(1).map((element) => extractString(element)).filter((s) => s !== void 0),
135
- type: depType
135
+ type: dependencyType
136
136
  };
137
137
  }
138
138
  function extractHash(node) {
@@ -145,7 +145,7 @@ function extractHash(node) {
145
145
  if (!key || !value) continue;
146
146
  const k = extractString(key);
147
147
  const v = extractString(value);
148
- if (k && v) result[k] = v;
148
+ if (k !== void 0 && k !== "" && v !== void 0 && v !== "") result[k] = v;
149
149
  }
150
150
  return result;
151
151
  }
@@ -209,7 +209,7 @@ async function parseGemspec(source) {
209
209
  return;
210
210
  }
211
211
  const attribute = resolveAttribute(lhs);
212
- if (!attribute) {
212
+ if (attribute === void 0 || attribute === "") {
213
213
  visitChildren(node);
214
214
  return;
215
215
  }
@@ -243,13 +243,12 @@ async function parseGemspec(source) {
243
243
  return;
244
244
  }
245
245
  if (node.type === "call" || node.type === "method_call") {
246
- const dep = tryParseDependency(node);
247
- if (dep) {
248
- if (Array.isArray(spec.dependencies)) spec.dependencies.push(dep);
246
+ const dependency = tryParseDependency(node);
247
+ if (dependency) {
248
+ if (Array.isArray(spec.dependencies)) spec.dependencies.push(dependency);
249
249
  return;
250
250
  }
251
251
  }
252
- if (node.type === "element_assignment" || node.type === "indexing") {}
253
252
  visitChildren(node);
254
253
  }
255
254
  function visitChildren(node) {
@@ -1,9 +1,9 @@
1
1
  //#region src/lib/parsers/go-mod-parser.ts
2
- const MAJOR_VERSION_SUFFIX_REGEX = /\/v\d+$/;
3
- const INDIRECT_COMMENT_REGEX = /\/\/\s*indirect/;
4
- const MODULE_VERSION_REGEX = /^(\S+)\s+(\S+)/;
5
- const INCOMPATIBLE_SUFFIX_REGEX = /\+incompatible$/;
6
- const WHITESPACE_REGEX = /\s+/;
2
+ const MAJOR_VERSION_SUFFIX_REGEX = /\/v\d+$/v;
3
+ const INDIRECT_COMMENT_REGEX = /\/\/\s*indirect/v;
4
+ const MODULE_VERSION_REGEX = /^(\S+)\s+(\S+)/v;
5
+ const INCOMPATIBLE_SUFFIX_REGEX = /\+incompatible$/v;
6
+ const WHITESPACE_REGEX = /\s+/v;
7
7
  /**
8
8
  * Known source-repo hosts and the number of path segments that make a repo URL.
9
9
  * e.g. github.com/owner/repo → 3 segments.
@@ -20,9 +20,9 @@ const HOST_SEGMENTS = {
20
20
  function moduleToRepoUrl(modulePath) {
21
21
  const segments = modulePath.split("/");
22
22
  const host = segments[0];
23
- if (!host) return;
23
+ if (host === void 0 || host === "") return;
24
24
  const needed = HOST_SEGMENTS[host];
25
- if (!needed || segments.length < needed) return;
25
+ if (needed === void 0 || needed === 0 || segments.length < needed) return;
26
26
  let repoPath = segments.slice(0, needed).join("/");
27
27
  repoPath = repoPath.replace(MAJOR_VERSION_SUFFIX_REGEX, "");
28
28
  return `https://${repoPath}`;
@@ -42,11 +42,12 @@ function parseRequireLine(line) {
42
42
  const clean = stripComment(line);
43
43
  const match = MODULE_VERSION_REGEX.exec(clean);
44
44
  if (!match) return;
45
- const version = match[2].replace(INCOMPATIBLE_SUFFIX_REGEX, "");
45
+ const [, module, rawVersion] = match;
46
+ if (module === void 0 || rawVersion === void 0) return;
46
47
  return {
47
48
  indirect,
48
- module: match[1],
49
- version
49
+ module,
50
+ version: rawVersion.replace(INCOMPATIBLE_SUFFIX_REGEX, "")
50
51
  };
51
52
  }
52
53
  /**
@@ -56,12 +57,12 @@ function parseRequireLine(line) {
56
57
  function parseReplaceLine(line) {
57
58
  const parts = stripComment(line).split("=>");
58
59
  if (parts.length !== 2) return;
59
- const left = parts[0].trim().split(WHITESPACE_REGEX);
60
- const right = parts[1].trim().split(WHITESPACE_REGEX);
60
+ const left = (parts[0] ?? "").trim().split(WHITESPACE_REGEX);
61
+ const right = (parts[1] ?? "").trim().split(WHITESPACE_REGEX);
61
62
  const from = left[0];
62
- if (!from || right.length === 0) return;
63
+ if (from === void 0 || from === "" || right.length === 0) return;
63
64
  const target = right[0];
64
- if (!target) return;
65
+ if (target === void 0 || target === "") return;
65
66
  if (target.startsWith("./") || target.startsWith("../") || target.startsWith("/")) return {
66
67
  from,
67
68
  to: "local"
@@ -78,7 +79,8 @@ function parseReplaceLine(line) {
78
79
  function parseToolLine(line) {
79
80
  const clean = stripComment(line).trim();
80
81
  if (clean.length === 0) return;
81
- return clean.split(WHITESPACE_REGEX)[0] || void 0;
82
+ const first = clean.split(WHITESPACE_REGEX)[0];
83
+ return first === void 0 || first === "" ? void 0 : first;
82
84
  }
83
85
  /**
84
86
  * Parse a go.mod file and return structured metadata.
@@ -94,44 +96,47 @@ function parseGoMod(source) {
94
96
  repository_url: void 0,
95
97
  tool_dependencies: []
96
98
  };
97
- const directDeps = {};
98
- const toolDeps = [];
99
+ const directDependencies = {};
100
+ const toolDependencies = [];
99
101
  const replacements = /* @__PURE__ */ new Map();
100
102
  let blockState = "none";
103
+ function handleBlockLine(state, blockLine) {
104
+ switch (state) {
105
+ case "replace": {
106
+ const rep = parseReplaceLine(blockLine);
107
+ if (rep) replacements.set(rep.from, rep.to);
108
+ break;
109
+ }
110
+ case "require": {
111
+ const dependency = parseRequireLine(blockLine);
112
+ if (dependency && !dependency.indirect) directDependencies[dependency.module] = dependency.version;
113
+ break;
114
+ }
115
+ case "skip": break;
116
+ case "tool": {
117
+ const tool = parseToolLine(blockLine);
118
+ if (tool !== void 0 && tool !== "") toolDependencies.push(tool);
119
+ break;
120
+ }
121
+ }
122
+ }
101
123
  for (const rawLine of source.split("\n")) {
102
124
  const line = rawLine.trim();
103
- if (line === "" || line.startsWith("//") && blockState === "none") continue;
125
+ if (line === "" || blockState === "none" && line.startsWith("//")) continue;
104
126
  if (line === ")" || line.startsWith(")")) {
105
127
  blockState = "none";
106
128
  continue;
107
129
  }
108
130
  if (blockState !== "none") {
109
- switch (blockState) {
110
- case "replace": {
111
- const rep = parseReplaceLine(line);
112
- if (rep) replacements.set(rep.from, rep.to);
113
- break;
114
- }
115
- case "require": {
116
- const dep = parseRequireLine(line);
117
- if (dep && !dep.indirect) directDeps[dep.module] = dep.version;
118
- break;
119
- }
120
- case "skip": break;
121
- case "tool": {
122
- const tool = parseToolLine(line);
123
- if (tool) toolDeps.push(tool);
124
- break;
125
- }
126
- }
131
+ handleBlockLine(blockState, line);
127
132
  continue;
128
133
  }
129
134
  if (line.startsWith("module ")) data.module = line.slice(7).trim();
130
135
  else if (line.startsWith("go ")) data.go_version = line.slice(3).trim();
131
136
  else if (line.startsWith("require ")) if (line.includes("(")) blockState = "require";
132
137
  else {
133
- const dep = parseRequireLine(line.slice(8));
134
- if (dep && !dep.indirect) directDeps[dep.module] = dep.version;
138
+ const dependency = parseRequireLine(line.slice(8));
139
+ if (dependency && !dependency.indirect) directDependencies[dependency.module] = dependency.version;
135
140
  }
136
141
  else if (line.startsWith("replace ")) if (line.includes("(")) blockState = "replace";
137
142
  else {
@@ -141,20 +146,21 @@ function parseGoMod(source) {
141
146
  else if (line.startsWith("tool ")) if (line.includes("(")) blockState = "tool";
142
147
  else {
143
148
  const tool = parseToolLine(line.slice(5));
144
- if (tool) toolDeps.push(tool);
149
+ if (tool !== void 0 && tool !== "") toolDependencies.push(tool);
145
150
  }
146
151
  else if ((line.startsWith("exclude ") || line.startsWith("retract ") || line.startsWith("godebug ") || line.startsWith("toolchain ")) && line.includes("(")) blockState = "skip";
147
152
  }
148
- for (const [from, to] of replacements) if (from in directDeps) {
149
- delete directDeps[from];
150
- if (to !== "local") directDeps[to.module] = to.version;
153
+ for (const [from, to] of replacements) {
154
+ if (!Object.hasOwn(directDependencies, from)) continue;
155
+ delete directDependencies[from];
156
+ if (to !== "local") directDependencies[to.module] = to.version;
151
157
  }
152
- data.dependencies = Object.entries(directDeps).map(([module, version]) => ({
158
+ data.dependencies = Object.entries(directDependencies).map(([module, version]) => ({
153
159
  module,
154
160
  version
155
161
  }));
156
- data.tool_dependencies = toolDeps;
157
- if (data.module) data.repository_url = moduleToRepoUrl(data.module);
162
+ data.tool_dependencies = toolDependencies;
163
+ if (data.module !== void 0 && data.module !== "") data.repository_url = moduleToRepoUrl(data.module);
158
164
  return data;
159
165
  }
160
166
  //#endregion
@@ -11,14 +11,14 @@
11
11
  * no conditionals. It mirrors the line-by-line algorithm used by the
12
12
  * openFrameworks Project Generator.
13
13
  */
14
- const INLINE_COMMENT_REGEX = /#.*$/;
14
+ const INLINE_COMMENT_REGEX = /#.*$/v;
15
15
  /**
16
16
  * Section header pattern: a word (with optional hyphens/slashes) followed by a
17
17
  * colon.
18
18
  */
19
- const SECTION_RE = /^[\w/][\w/-]*:$/;
19
+ const SECTION_RE = /^[\w\/][\w\/\-]*:$/v;
20
20
  /** Variable assignment pattern: VARNAME = value or VARNAME += value */
21
- const ASSIGNMENT_RE = /^(\w+)\s*(\+?=)\s*(.*)/;
21
+ const ASSIGNMENT_RE = /^(\w+)\s*(\+?=)\s*(.*)/v;
22
22
  /**
23
23
  * Sections that are not platform-specific and should be excluded from
24
24
  * operatingSystem inference.
@@ -49,6 +49,7 @@ function parseMakefileConfig(content) {
49
49
  const match = ASSIGNMENT_RE.exec(line);
50
50
  if (!match) continue;
51
51
  const [, variableName, operator, rawValue] = match;
52
+ if (variableName === void 0 || rawValue === void 0) continue;
52
53
  currentSectionHasAssignment = true;
53
54
  if (currentSection === "meta") {
54
55
  const values = tokenizeValues(rawValue);
@@ -96,9 +97,9 @@ function tokenizeValues(raw) {
96
97
  const trimmed = raw.trim();
97
98
  if (trimmed.length === 0) return [];
98
99
  const values = [];
99
- for (const [, quoted, bare] of trimmed.matchAll(/"([^"]+)"|(\S+)/g)) {
100
- const value = quoted || bare;
101
- if (value.length > 0) values.push(value);
100
+ for (const [, quoted, bare] of trimmed.matchAll(/"([^"]+)"|(\S+)/gv)) {
101
+ const value = quoted ?? bare;
102
+ if (value !== void 0 && value.length > 0) values.push(value);
102
103
  }
103
104
  return values;
104
105
  }
@@ -11,7 +11,7 @@
11
11
  *
12
12
  * See https://en.wikipedia.org/wiki/.properties
13
13
  */
14
- const LINE_BREAK_REGEX = /\r?\n/;
14
+ const LINE_BREAK_REGEX = /\r?\n/v;
15
15
  /**
16
16
  * Parse a `*.properties` content string into raw key-value pairs.
17
17
  */
@@ -1,5 +1,5 @@
1
1
  //#region src/lib/parsers/rfc822-header-parser.ts
2
- const LEADING_WHITESPACE_REGEX = /^\s/;
2
+ const LEADING_WHITESPACE_REGEX = /^\s/v;
3
3
  /** Multi-value headers that can appear multiple times. */
4
4
  const MULTI_VALUE_HEADERS = /* @__PURE__ */ new Set([
5
5
  "Classifier",
@@ -19,16 +19,17 @@ function parseRfc822Headers(content) {
19
19
  let lastKey = "";
20
20
  for (const line of content.split("\n")) {
21
21
  if (line.trim() === "") break;
22
- if (LEADING_WHITESPACE_REGEX.test(line) && lastKey) {
22
+ if (lastKey !== "" && LEADING_WHITESPACE_REGEX.test(line)) {
23
23
  const continuation = line.trim();
24
- if (continuation) headers[lastKey] = `${headers[lastKey]}\n${continuation}`;
24
+ if (continuation !== "") headers[lastKey] = `${headers[lastKey]}\n${continuation}`;
25
25
  continue;
26
26
  }
27
27
  const colonIndex = line.indexOf(": ");
28
28
  if (colonIndex > 0) {
29
29
  const key = line.slice(0, colonIndex);
30
30
  const value = line.slice(colonIndex + 2).trim();
31
- headers[key] = MULTI_VALUE_HEADERS.has(key) && headers[key] ? `${headers[key]}\n${value}` : value;
31
+ const previous = headers[key];
32
+ headers[key] = previous !== void 0 && previous !== "" && MULTI_VALUE_HEADERS.has(key) ? `${previous}\n${value}` : value;
32
33
  lastKey = key;
33
34
  }
34
35
  }
@@ -38,11 +39,12 @@ function parseRfc822Headers(content) {
38
39
  function extractRfc822Body(content) {
39
40
  const blankIndex = content.indexOf("\n\n");
40
41
  if (blankIndex === -1) return;
41
- return content.slice(blankIndex + 2).trim() || void 0;
42
+ const body = content.slice(blankIndex + 2).trim();
43
+ return body === "" ? void 0 : body;
42
44
  }
43
45
  /** Split newline-separated multi-value into array. */
44
46
  function splitMultiValues(value) {
45
- if (!value) return [];
47
+ if (value === void 0 || value === "") return [];
46
48
  return value.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
47
49
  }
48
50
  //#endregion