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.
- package/dist/bin/cli.js +30426 -29237
- package/dist/bin/{jiti-DDHyYNLW.js → jiti-B26uDQuv.js} +2 -2
- package/dist/bin/renovate-CEC0BhMB.js +1 -0
- package/dist/bin/shared-Ch5JsD6s.js +8 -0
- package/dist/bin/shared2-Dhjk_Okb.js +1 -0
- package/dist/bin/web-tree-sitter.wasm +0 -0
- package/dist/lib/data/license-urls.js +2904 -0
- package/dist/lib/file-matching.js +5 -2
- package/dist/lib/log.d.ts +0 -1
- package/dist/lib/metadata-types.d.ts +16 -9
- package/dist/lib/metadata.d.ts +0 -1
- package/dist/lib/metadata.js +5 -5
- package/dist/lib/package.js +1 -1
- package/dist/lib/parsers/configparser-parser.js +14 -12
- package/dist/lib/parsers/gemspec-parser.js +41 -42
- package/dist/lib/parsers/go-mod-parser.js +51 -45
- package/dist/lib/parsers/makefile-config-parser.js +7 -6
- package/dist/lib/parsers/properties-parser.js +1 -1
- package/dist/lib/parsers/rfc822-header-parser.js +8 -6
- package/dist/lib/parsers/setup-py-parser.js +28 -24
- package/dist/lib/source.d.ts +6 -2
- package/dist/lib/sources/arduino-library-properties.d.ts +0 -1
- package/dist/lib/sources/arduino-library-properties.js +6 -7
- package/dist/lib/sources/cinder-cinderblock-xml.d.ts +0 -1
- package/dist/lib/sources/cinder-cinderblock-xml.js +5 -5
- package/dist/lib/sources/code-stats.d.ts +3 -2
- package/dist/lib/sources/codemeta-json.d.ts +0 -1
- package/dist/lib/sources/codemeta-json.js +21 -20
- package/dist/lib/sources/dependency-updates.d.ts +17 -8
- package/dist/lib/sources/dependency-updates.js +38 -34
- package/dist/lib/sources/file-stats.d.ts +7 -4
- package/dist/lib/sources/git-config.d.ts +0 -1
- package/dist/lib/sources/git-stats.d.ts +47 -24
- package/dist/lib/sources/git-stats.js +51 -33
- package/dist/lib/sources/github-actions.d.ts +0 -1
- package/dist/lib/sources/github-actions.js +4 -3
- package/dist/lib/sources/github.d.ts +156 -78
- package/dist/lib/sources/github.js +11 -8
- package/dist/lib/sources/go-go-mod.d.ts +0 -1
- package/dist/lib/sources/go-goreleaser-yaml.d.ts +0 -1
- package/dist/lib/sources/go-goreleaser-yaml.js +5 -3
- package/dist/lib/sources/java-pom-xml.d.ts +0 -1
- package/dist/lib/sources/java-pom-xml.js +12 -12
- package/dist/lib/sources/license-file.d.ts +0 -1
- package/dist/lib/sources/metadata-file.d.ts +0 -1
- package/dist/lib/sources/metadata-file.js +9 -10
- package/dist/lib/sources/metascope.d.ts +9 -5
- package/dist/lib/sources/node-npm-registry.d.ts +21 -11
- package/dist/lib/sources/node-npm-registry.js +12 -6
- package/dist/lib/sources/node-package-json.d.ts +0 -1
- package/dist/lib/sources/obsidian-plugin-manifest-json.d.ts +17 -9
- package/dist/lib/sources/obsidian-plugin-manifest-json.js +2 -2
- package/dist/lib/sources/obsidian-plugin-registry.d.ts +3 -2
- package/dist/lib/sources/obsidian-plugin-registry.js +2 -1
- package/dist/lib/sources/openframeworks-addon-config-mk.d.ts +0 -1
- package/dist/lib/sources/openframeworks-install-xml.d.ts +0 -1
- package/dist/lib/sources/openframeworks-install-xml.js +3 -3
- package/dist/lib/sources/processing-library-properties.d.ts +0 -1
- package/dist/lib/sources/processing-library-properties.js +9 -10
- package/dist/lib/sources/processing-sketch-properties.d.ts +0 -1
- package/dist/lib/sources/processing-sketch-properties.js +13 -20
- package/dist/lib/sources/publiccode-yaml.d.ts +0 -1
- package/dist/lib/sources/publiccode-yaml.js +61 -58
- package/dist/lib/sources/python-pkg-info.d.ts +0 -1
- package/dist/lib/sources/python-pkg-info.js +6 -5
- package/dist/lib/sources/python-pypi-registry.d.ts +21 -11
- package/dist/lib/sources/python-pypi-registry.js +23 -16
- package/dist/lib/sources/python-pyproject-toml.d.ts +0 -1
- package/dist/lib/sources/python-setup-cfg.d.ts +2 -3
- package/dist/lib/sources/python-setup-cfg.js +10 -9
- package/dist/lib/sources/python-setup-py.d.ts +0 -1
- package/dist/lib/sources/readme-file.d.ts +0 -1
- package/dist/lib/sources/readme-file.js +4 -3
- package/dist/lib/sources/ruby-gemspec.d.ts +0 -1
- package/dist/lib/sources/rust-cargo-toml.d.ts +0 -1
- package/dist/lib/sources/rust-cargo-toml.js +1 -1
- package/dist/lib/sources/xcode-info-plist.d.ts +0 -1
- package/dist/lib/sources/xcode-info-plist.js +29 -31
- package/dist/lib/sources/xcode-project-pbxproj.d.ts +0 -1
- package/dist/lib/sources/xcode-project-pbxproj.js +17 -16
- package/dist/lib/templates/codemeta-json.d.ts +1 -0
- package/dist/lib/templates/codemeta.d.ts +1 -0
- package/dist/lib/templates/codemeta.js +98 -89
- package/dist/lib/templates/frontmatter.d.ts +2 -1
- package/dist/lib/templates/frontmatter.js +1 -1
- package/dist/lib/templates/index.d.ts +2 -1
- package/dist/lib/templates/index.js +1 -1
- package/dist/lib/templates/metadata.d.ts +1 -0
- package/dist/lib/templates/project.d.ts +1 -0
- package/dist/lib/utilities/codemeta-helpers.js +14 -13
- package/dist/lib/utilities/fetch.js +5 -3
- package/dist/lib/utilities/formatting.js +1 -1
- package/dist/lib/utilities/github.js +2 -2
- package/dist/lib/utilities/license-identification.d.ts +9 -4
- package/dist/lib/utilities/license-identification.js +37 -23
- package/dist/lib/utilities/template-helpers.d.ts +7 -5
- package/dist/lib/utilities/template-helpers.js +15 -14
- package/dist/lib/utilities/tree-sitter-wasm.d.ts +0 -1
- package/dist/lib/utilities/tree-sitter-wasm.js +1 -1
- package/package.json +18 -17
- package/readme.md +13 -11
- package/dist/bin/renovate-CpDMbQZd.js +0 -1
- 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) =>
|
|
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
|
@@ -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;
|
|
127
|
-
|
|
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;
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
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. */
|
|
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. */
|
|
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 };
|
package/dist/lib/metadata.d.ts
CHANGED
|
@@ -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[];
|
package/dist/lib/metadata.js
CHANGED
|
@@ -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
|
|
209
|
-
for (const phase of
|
|
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, {
|
package/dist/lib/package.js
CHANGED
|
@@ -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
|
-
|
|
25
|
-
|
|
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)
|
|
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]
|
|
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
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
58
|
-
case "heredoc_body": return
|
|
59
|
-
case "simple_symbol": return
|
|
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(
|
|
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
|
|
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
|
-
|
|
85
|
-
|
|
86
|
-
const method =
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
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 (
|
|
93
|
-
if (
|
|
94
|
-
if (
|
|
95
|
-
|
|
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 (
|
|
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 (
|
|
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 (
|
|
125
|
-
const
|
|
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
|
-
|
|
130
|
-
|
|
131
|
-
|
|
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:
|
|
133
|
+
name: dependencyName,
|
|
134
134
|
requirements: argumentNodes.slice(1).map((element) => extractString(element)).filter((s) => s !== void 0),
|
|
135
|
-
type:
|
|
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 (
|
|
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
|
|
247
|
-
if (
|
|
248
|
-
if (Array.isArray(spec.dependencies)) spec.dependencies.push(
|
|
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 (
|
|
23
|
+
if (host === void 0 || host === "") return;
|
|
24
24
|
const needed = HOST_SEGMENTS[host];
|
|
25
|
-
if (
|
|
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
|
|
45
|
+
const [, module, rawVersion] = match;
|
|
46
|
+
if (module === void 0 || rawVersion === void 0) return;
|
|
46
47
|
return {
|
|
47
48
|
indirect,
|
|
48
|
-
module
|
|
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 (
|
|
63
|
+
if (from === void 0 || from === "" || right.length === 0) return;
|
|
63
64
|
const target = right[0];
|
|
64
|
-
if (
|
|
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
|
-
|
|
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
|
|
98
|
-
const
|
|
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("//")
|
|
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
|
-
|
|
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
|
|
134
|
-
if (
|
|
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)
|
|
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)
|
|
149
|
-
|
|
150
|
-
|
|
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(
|
|
158
|
+
data.dependencies = Object.entries(directDependencies).map(([module, version]) => ({
|
|
153
159
|
module,
|
|
154
160
|
version
|
|
155
161
|
}));
|
|
156
|
-
data.tool_dependencies =
|
|
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
|
|
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+)/
|
|
100
|
-
const value = quoted
|
|
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
|
}
|
|
@@ -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)
|
|
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
|
-
|
|
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
|
-
|
|
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 (
|
|
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
|