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.
- 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 +18 -2
- 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
|
@@ -44,14 +44,14 @@ function parse$1(content, format) {
|
|
|
44
44
|
return;
|
|
45
45
|
}
|
|
46
46
|
if (data === void 0) return;
|
|
47
|
-
const
|
|
48
|
-
const homepage = nonEmpty(data.homepage) ?? nonEmpty(data.url) ??
|
|
47
|
+
const repo = isString(data.repository) ? normalizeRepoUrl(data.repository) : void 0;
|
|
48
|
+
const homepage = nonEmpty(data.homepage) ?? nonEmpty(data.url) ?? repo ?? nonEmpty(data.website);
|
|
49
49
|
const keywords = parseKeywords(data.keywords) ?? parseKeywords(data.tags) ?? parseKeywords(data.topics) ?? [];
|
|
50
50
|
return metadataSchema.parse({
|
|
51
51
|
description: data.description,
|
|
52
52
|
homepage,
|
|
53
53
|
keywords,
|
|
54
|
-
repository
|
|
54
|
+
repository: repo
|
|
55
55
|
});
|
|
56
56
|
}
|
|
57
57
|
/** Return a trimmed string if the value is a non-empty string, else undefined. */
|
|
@@ -98,13 +98,12 @@ const metadataFileSource = defineSource({
|
|
|
98
98
|
key: "metadataFile",
|
|
99
99
|
async parse(input, context) {
|
|
100
100
|
const format = getFormat(input);
|
|
101
|
-
if (format
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
101
|
+
if (format === void 0) return;
|
|
102
|
+
const data = parse$1(await readFile(resolve(context.options.path, input), "utf8"), format);
|
|
103
|
+
return data === void 0 ? void 0 : {
|
|
104
|
+
data,
|
|
105
|
+
source: input
|
|
106
|
+
};
|
|
108
107
|
},
|
|
109
108
|
phase: 1
|
|
110
109
|
});
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { SourceRecord } from "../source.js";
|
|
2
2
|
import { GetMetadataBaseOptions } from "../metadata-types.js";
|
|
3
|
-
|
|
4
3
|
//#region src/lib/sources/metascope.d.ts
|
|
5
4
|
type MetascopeInfo = {
|
|
6
|
-
/** Total scan duration in milliseconds. */
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
/** Total scan duration in milliseconds. */
|
|
6
|
+
durationMs: number;
|
|
7
|
+
/** Resolved options used for this scan (credentials excluded). */
|
|
8
|
+
options: Omit<GetMetadataBaseOptions, 'credentials'>;
|
|
9
|
+
/** ISO 8601 timestamp of when the scan was performed. */
|
|
10
|
+
scannedAt: string;
|
|
11
|
+
/** Version of the metascope library used. */
|
|
12
|
+
version: string;
|
|
13
|
+
/** Workspaces Resolved */
|
|
10
14
|
workspaceDirectories: string[];
|
|
11
15
|
};
|
|
12
16
|
type MetascopeData = SourceRecord<MetascopeInfo> | undefined;
|
|
@@ -1,17 +1,27 @@
|
|
|
1
1
|
import { OneOrMany, SourceRecord } from "../source.js";
|
|
2
|
-
|
|
3
2
|
//#region src/lib/sources/node-npm-registry.d.ts
|
|
4
3
|
type NodeNpmRegistryInfo = {
|
|
5
|
-
/** Deprecation message, if the package is deprecated. */
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
/** Deprecation message, if the package is deprecated. */
|
|
5
|
+
deprecated?: string;
|
|
6
|
+
/** Downloads in the last month. */
|
|
7
|
+
downloadsMonthly?: number;
|
|
8
|
+
/** All-time total downloads. */
|
|
9
|
+
downloadsTotal?: number;
|
|
10
|
+
/** Downloads in the last week. */
|
|
11
|
+
downloadsWeekly?: number;
|
|
12
|
+
/** Downloads in the last year. */
|
|
13
|
+
downloadsYearly?: number;
|
|
14
|
+
/** Number of files in the published package. */
|
|
15
|
+
fileCount?: number;
|
|
16
|
+
/** Whether the package exposes TypeScript types. */
|
|
17
|
+
hasTypes?: boolean;
|
|
18
|
+
/** ISO 8601 date the package was last published. */
|
|
19
|
+
publishDateLatest?: string;
|
|
20
|
+
/** Unpacked size of the published package in bytes. */
|
|
21
|
+
unpackedSizeBytes?: number;
|
|
22
|
+
/** The npmjs.com URL for the package. */
|
|
23
|
+
url?: string;
|
|
24
|
+
/** Latest published version string. */
|
|
15
25
|
versionLatest?: string;
|
|
16
26
|
};
|
|
17
27
|
type NodeNpmRegistryData = OneOrMany<SourceRecord<NodeNpmRegistryInfo>> | undefined;
|
|
@@ -18,20 +18,26 @@ const nodeNpmRegistrySource = defineSource({
|
|
|
18
18
|
log.debug(`Missing nodePackageJson in source context metadata for ${context.options.path}, extracting it now...`);
|
|
19
19
|
packages = ensureArray(await nodePackageJsonSource.extract(context));
|
|
20
20
|
}
|
|
21
|
-
return packages.filter((
|
|
22
|
-
if (
|
|
23
|
-
log.debug(`Skipping NPM registry lookup for "${
|
|
21
|
+
return packages.filter((package_) => {
|
|
22
|
+
if (package_.data.private === true || package_.data.publishConfig?.access === "restricted") {
|
|
23
|
+
log.debug(`Skipping NPM registry lookup for "${package_.data.name}" in "${context.options.path}" because it is a private package`);
|
|
24
24
|
return false;
|
|
25
25
|
}
|
|
26
26
|
return true;
|
|
27
|
-
}).map((
|
|
27
|
+
}).map((package_) => package_.data.name);
|
|
28
28
|
},
|
|
29
29
|
key: "nodeNpmRegistry",
|
|
30
30
|
async parse(input) {
|
|
31
31
|
log.debug("Extracting npm metadata...");
|
|
32
32
|
const name = input;
|
|
33
33
|
const [metadata, downloadsWeekly, downloadsMonthly, downloadsYearly, downloadsTotal] = await Promise.all([
|
|
34
|
-
|
|
34
|
+
(async () => {
|
|
35
|
+
try {
|
|
36
|
+
return await packageJson(name, { fullMetadata: true });
|
|
37
|
+
} catch {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
})(),
|
|
35
41
|
fetchDownloads(name, "last-week"),
|
|
36
42
|
fetchDownloads(name, "last-month"),
|
|
37
43
|
fetchDownloads(name, "last-year"),
|
|
@@ -45,7 +51,7 @@ const nodeNpmRegistrySource = defineSource({
|
|
|
45
51
|
data: {
|
|
46
52
|
deprecated: typeof metadata.deprecated === "string" ? metadata.deprecated : void 0,
|
|
47
53
|
downloadsMonthly,
|
|
48
|
-
downloadsTotal: downloadsTotal || void 0,
|
|
54
|
+
downloadsTotal: downloadsTotal === void 0 || downloadsTotal === 0 ? void 0 : downloadsTotal,
|
|
49
55
|
downloadsWeekly,
|
|
50
56
|
downloadsYearly,
|
|
51
57
|
fileCount: typeof distribution?.fileCount === "number" ? distribution.fileCount : void 0,
|
|
@@ -1,15 +1,23 @@
|
|
|
1
1
|
import { OneOrMany, SourceRecord } from "../source.js";
|
|
2
|
-
|
|
3
2
|
//#region src/lib/sources/obsidian-plugin-manifest-json.d.ts
|
|
4
3
|
type ObsidianManifest = {
|
|
5
|
-
/** Plugin author name. */
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
/** Plugin author name. */
|
|
5
|
+
author?: string;
|
|
6
|
+
/** URL for the plugin author. */
|
|
7
|
+
authorUrl?: string;
|
|
8
|
+
/** Plugin description. */
|
|
9
|
+
description?: string;
|
|
10
|
+
/** URL for funding or sponsorship. */
|
|
11
|
+
fundingUrl?: string;
|
|
12
|
+
/** Unique plugin identifier. */
|
|
13
|
+
id: string;
|
|
14
|
+
/** Whether the plugin is desktop-only. */
|
|
15
|
+
isDesktopOnly?: boolean;
|
|
16
|
+
/** Minimum Obsidian app version required. */
|
|
17
|
+
minAppVersion?: string;
|
|
18
|
+
/** Display name of the plugin. */
|
|
19
|
+
name?: string;
|
|
20
|
+
/** Plugin version string. */
|
|
13
21
|
version?: string;
|
|
14
22
|
};
|
|
15
23
|
type ObsidianPluginManifestJsonData = OneOrMany<SourceRecord<ObsidianManifest>> | undefined;
|
|
@@ -23,10 +23,10 @@ const obsidianPluginManifestJsonSource = defineSource({
|
|
|
23
23
|
async parse(input, context) {
|
|
24
24
|
const content = await readFile(resolve(context.options.path, input), "utf8");
|
|
25
25
|
const parsed = manifestSchema.safeParse(JSON.parse(content));
|
|
26
|
-
|
|
26
|
+
return parsed.success ? {
|
|
27
27
|
data: parsed.data,
|
|
28
28
|
source: input
|
|
29
|
-
};
|
|
29
|
+
} : void 0;
|
|
30
30
|
},
|
|
31
31
|
phase: 1
|
|
32
32
|
});
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { OneOrMany, SourceRecord } from "../source.js";
|
|
2
|
-
|
|
3
2
|
//#region src/lib/sources/obsidian-plugin-registry.d.ts
|
|
4
3
|
type ObsidianPluginRegistryInfo = {
|
|
5
|
-
/** Total community download count. */
|
|
4
|
+
/** Total community download count. */
|
|
5
|
+
downloadCount?: number;
|
|
6
|
+
/** Obsidian plugin directory URL. */
|
|
6
7
|
url?: string;
|
|
7
8
|
};
|
|
8
9
|
type ObsidianPluginRegistryData = OneOrMany<SourceRecord<ObsidianPluginRegistryInfo>> | undefined;
|
|
@@ -30,9 +30,10 @@ const obsidianPluginRegistrySource = defineSource({
|
|
|
30
30
|
data: { url },
|
|
31
31
|
source: url
|
|
32
32
|
};
|
|
33
|
+
const downloads = pluginStatsSchema.parse(await response.json())[pluginId]?.downloads;
|
|
33
34
|
return {
|
|
34
35
|
data: {
|
|
35
|
-
downloadCount:
|
|
36
|
+
downloadCount: downloads === void 0 || downloads === 0 ? void 0 : downloads,
|
|
36
37
|
url
|
|
37
38
|
},
|
|
38
39
|
source: url
|
|
@@ -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/openframeworks-addon-config-mk.d.ts
|
|
5
4
|
declare const openframeworksAddonConfigSchema: z.ZodObject<{
|
|
6
5
|
author: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodString>>>;
|
|
@@ -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/openframeworks-install-xml.d.ts
|
|
5
4
|
declare const openframeworksInstallXmlSchema: z.ZodObject<{
|
|
6
5
|
author: z.ZodOptional<z.ZodPreprocess<z.ZodOptional<z.ZodString>>>;
|
|
@@ -115,7 +115,7 @@ function parseRequirements(install) {
|
|
|
115
115
|
const results = [];
|
|
116
116
|
for (const addon of ensureArray(requires.addon)) {
|
|
117
117
|
const name = getString(addon);
|
|
118
|
-
if (name) results.push(name);
|
|
118
|
+
if (name !== void 0 && name !== "") results.push(name);
|
|
119
119
|
}
|
|
120
120
|
return results;
|
|
121
121
|
}
|
|
@@ -135,7 +135,7 @@ function parseOperatingSystems(install) {
|
|
|
135
135
|
for (const library of ensureArray(link.lib)) {
|
|
136
136
|
if (!is.plainObject(library)) continue;
|
|
137
137
|
const os = getString(library["@_os"]);
|
|
138
|
-
if (os) {
|
|
138
|
+
if (os !== void 0 && os !== "") {
|
|
139
139
|
const mapped = LIB_OS_MAP[os.toLowerCase()] ?? os;
|
|
140
140
|
if (!seen.has(mapped)) {
|
|
141
141
|
seen.add(mapped);
|
|
@@ -152,7 +152,7 @@ const openframeworksInstallXmlSource = defineSource({
|
|
|
152
152
|
key: "openframeworksInstallXml",
|
|
153
153
|
async parse(input, context) {
|
|
154
154
|
const data = parse(await readFile(resolve(context.options.path, input), "utf8"));
|
|
155
|
-
|
|
155
|
+
return data === void 0 ? void 0 : {
|
|
156
156
|
data,
|
|
157
157
|
source: input
|
|
158
158
|
};
|
|
@@ -7,7 +7,7 @@ import { readFile } from "node:fs/promises";
|
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
//#region src/lib/sources/processing-library-properties.ts
|
|
10
|
-
const AUTHOR_SEPARATOR_REGEX = /\band\b
|
|
10
|
+
const AUTHOR_SEPARATOR_REGEX = /\band\b|,|&/v;
|
|
11
11
|
const processingLibraryPropertiesAuthorEntrySchema = z.object({
|
|
12
12
|
name: z.string(),
|
|
13
13
|
url: z.string().optional()
|
|
@@ -32,8 +32,7 @@ const CANONICAL_CATEGORIES = [
|
|
|
32
32
|
"Video & Vision"
|
|
33
33
|
];
|
|
34
34
|
/** Map from letters-only lowercase to canonical category form. */
|
|
35
|
-
const CATEGORY_MAP = new Map(CANONICAL_CATEGORIES.map((cat) => [cat.replaceAll(/[^a-z]/
|
|
36
|
-
CATEGORY_MAP.set("3d", "3D");
|
|
35
|
+
const CATEGORY_MAP = new Map([...CANONICAL_CATEGORIES.map((cat) => [cat.replaceAll(/[^a-z]/giv, "").toLowerCase(), cat]), ["3d", "3D"]]);
|
|
37
36
|
const processingLibraryPropertiesSchema = z.object({
|
|
38
37
|
/** Parsed author entries with optional URLs. */
|
|
39
38
|
authors: z.array(processingLibraryPropertiesAuthorEntrySchema),
|
|
@@ -71,13 +70,13 @@ const processingLibraryPropertiesSchema = z.object({
|
|
|
71
70
|
function parse(content) {
|
|
72
71
|
const raw = parseProperties(content);
|
|
73
72
|
const versionRaw = get(raw, "version") ?? "0";
|
|
74
|
-
const versionParsed =
|
|
73
|
+
const versionParsed = Math.trunc(Number(versionRaw));
|
|
75
74
|
const prettyVersionRaw = get(raw, "prettyVersion");
|
|
76
|
-
const prettyVersion = prettyVersionRaw ? stripInlineComment(prettyVersionRaw) : void 0;
|
|
75
|
+
const prettyVersion = prettyVersionRaw !== void 0 && prettyVersionRaw !== "" ? stripInlineComment(prettyVersionRaw) : void 0;
|
|
77
76
|
const minRevisionRaw = get(raw, "minRevision");
|
|
78
|
-
const minParsed = minRevisionRaw ?
|
|
77
|
+
const minParsed = minRevisionRaw !== void 0 && minRevisionRaw !== "" ? Math.trunc(Number(minRevisionRaw)) : 0;
|
|
79
78
|
const maxRevisionRaw = get(raw, "maxRevision");
|
|
80
|
-
const maxParsed = maxRevisionRaw ?
|
|
79
|
+
const maxParsed = maxRevisionRaw !== void 0 && maxRevisionRaw !== "" ? Math.trunc(Number(maxRevisionRaw)) : 0;
|
|
81
80
|
return processingLibraryPropertiesSchema.parse({
|
|
82
81
|
authors: parseAuthors(get(raw, "authors") ?? get(raw, "authorList") ?? ""),
|
|
83
82
|
categories: parseCategories(get(raw, "categories") ?? get(raw, "category") ?? ""),
|
|
@@ -182,12 +181,12 @@ function parseCategories(value) {
|
|
|
182
181
|
if (trimmed.length === 0) return [];
|
|
183
182
|
const results = [];
|
|
184
183
|
for (const part of trimmed.split(",")) {
|
|
185
|
-
const stripped = part.trim().replaceAll(/^"|"$/
|
|
184
|
+
const stripped = part.trim().replaceAll(/^"|"$/gv, "").trim();
|
|
186
185
|
if (stripped.length === 0) continue;
|
|
187
|
-
const key = stripped.replaceAll(/[^a-z0-9]/
|
|
186
|
+
const key = stripped.replaceAll(/[^a-z0-9]/giv, "").toLowerCase();
|
|
188
187
|
if (key.length === 0) continue;
|
|
189
188
|
const canonical = CATEGORY_MAP.get(key);
|
|
190
|
-
if (canonical && !results.includes(canonical)) results.push(canonical);
|
|
189
|
+
if (canonical !== void 0 && !results.includes(canonical)) results.push(canonical);
|
|
191
190
|
}
|
|
192
191
|
return results;
|
|
193
192
|
}
|
|
@@ -7,7 +7,7 @@ import { readFile } from "node:fs/promises";
|
|
|
7
7
|
import { resolve } from "node:path";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
//#region src/lib/sources/processing-sketch-properties.ts
|
|
10
|
-
const AUTHOR_SEPARATOR_REGEX = /\band\b
|
|
10
|
+
const AUTHOR_SEPARATOR_REGEX = /\band\b|,|&/v;
|
|
11
11
|
const processingSketchPropertiesAuthorEntrySchema = z.object({
|
|
12
12
|
name: z.string(),
|
|
13
13
|
url: z.string().optional()
|
|
@@ -88,20 +88,8 @@ const processingSketchPropertiesSchema = z.object({
|
|
|
88
88
|
*/
|
|
89
89
|
function parse(content) {
|
|
90
90
|
const raw = parseProperties(content);
|
|
91
|
-
const versionRaw = raw.version ?? "0";
|
|
92
|
-
const versionParsed = Number.parseInt(versionRaw, 10);
|
|
93
91
|
const prettyVersionRaw = raw.prettyVersion;
|
|
94
|
-
const prettyVersion = prettyVersionRaw ? stripInlineComment(prettyVersionRaw) : void 0;
|
|
95
|
-
const minRevisionRaw = raw.minRevision;
|
|
96
|
-
const minParsed = minRevisionRaw ? Number.parseInt(minRevisionRaw, 10) : 0;
|
|
97
|
-
const maxRevisionRaw = raw.maxRevision;
|
|
98
|
-
const maxParsed = maxRevisionRaw ? Number.parseInt(maxRevisionRaw, 10) : 0;
|
|
99
|
-
const manifestVersionCodeRaw = raw["manifest.version.code"];
|
|
100
|
-
const manifestVersionCode = manifestVersionCodeRaw ? Number.parseInt(manifestVersionCodeRaw, 10) : void 0;
|
|
101
|
-
const manifestSdkTargetRaw = raw["manifest.sdk.target"];
|
|
102
|
-
const manifestSdkTarget = manifestSdkTargetRaw ? Number.parseInt(manifestSdkTargetRaw, 10) : void 0;
|
|
103
|
-
const manifestSdkMinRaw = raw["manifest.sdk.min"];
|
|
104
|
-
const manifestSdkMin = manifestSdkMinRaw ? Number.parseInt(manifestSdkMinRaw, 10) : void 0;
|
|
92
|
+
const prettyVersion = prettyVersionRaw !== void 0 && prettyVersionRaw !== "" ? stripInlineComment(prettyVersionRaw) : void 0;
|
|
105
93
|
const manifestPermissions = splitCommaSeparated(raw["manifest.permissions"] ?? "");
|
|
106
94
|
return processingSketchPropertiesSchema.parse({
|
|
107
95
|
authors: parseAuthors(raw.authors ?? raw.authorList ?? ""),
|
|
@@ -112,12 +100,12 @@ function parse(content) {
|
|
|
112
100
|
manifestOrientation: nonEmpty(raw["manifest.orientation"]),
|
|
113
101
|
manifestPackage: nonEmpty(raw["manifest.package"]),
|
|
114
102
|
manifestPermissions,
|
|
115
|
-
manifestSdkMin:
|
|
116
|
-
manifestSdkTarget:
|
|
117
|
-
manifestVersionCode:
|
|
103
|
+
manifestSdkMin: parseIntegerOr(raw["manifest.sdk.min"], void 0),
|
|
104
|
+
manifestSdkTarget: parseIntegerOr(raw["manifest.sdk.target"], void 0),
|
|
105
|
+
manifestVersionCode: parseIntegerOr(raw["manifest.version.code"], void 0),
|
|
118
106
|
manifestVersionName: nonEmpty(raw["manifest.version.name"]),
|
|
119
|
-
maxRevision:
|
|
120
|
-
minRevision:
|
|
107
|
+
maxRevision: parseIntegerOr(raw.maxRevision, 0),
|
|
108
|
+
minRevision: parseIntegerOr(raw.minRevision, 0),
|
|
121
109
|
mode: nonEmpty(raw.mode),
|
|
122
110
|
modeId: nonEmpty(raw["mode.id"]),
|
|
123
111
|
name: nonEmpty(raw.name),
|
|
@@ -127,10 +115,15 @@ function parse(content) {
|
|
|
127
115
|
sentence: nonEmpty(raw.sentence),
|
|
128
116
|
templates: nonEmpty(raw.templates),
|
|
129
117
|
url: nonEmpty(unescapeUrl(raw.url ?? "")),
|
|
130
|
-
version:
|
|
118
|
+
version: parseIntegerOr(raw.version, 0),
|
|
131
119
|
zipfilename: nonEmpty(raw.zipfilename)
|
|
132
120
|
});
|
|
133
121
|
}
|
|
122
|
+
function parseIntegerOr(value, fallback) {
|
|
123
|
+
if (value === void 0 || value === "") return fallback;
|
|
124
|
+
const parsed = Math.trunc(Number(value));
|
|
125
|
+
return Number.isNaN(parsed) ? fallback : parsed;
|
|
126
|
+
}
|
|
134
127
|
/** Return a trimmed string, or undefined if empty/whitespace-only. */
|
|
135
128
|
function nonEmpty(value) {
|
|
136
129
|
if (value === void 0) return;
|
|
@@ -126,6 +126,22 @@ function toStringArray(value) {
|
|
|
126
126
|
if (!Array.isArray(value)) return [];
|
|
127
127
|
return value.filter((item) => typeof item === "string");
|
|
128
128
|
}
|
|
129
|
+
/** Parse a single dependency entry, returning undefined when it lacks a name. */
|
|
130
|
+
function parseDependencyEntry(dependency, category) {
|
|
131
|
+
if (!isPlainObject(dependency) || !isNonEmptyString(dependency.name)) return;
|
|
132
|
+
const entry = {
|
|
133
|
+
category,
|
|
134
|
+
name: dependency.name
|
|
135
|
+
};
|
|
136
|
+
const version = toString(dependency.version);
|
|
137
|
+
if (version !== void 0 && version !== "") entry.version = version;
|
|
138
|
+
const versionMin = toString(dependency.versionMin);
|
|
139
|
+
if (versionMin !== void 0 && versionMin !== "") entry.versionMin = versionMin;
|
|
140
|
+
const versionMax = toString(dependency.versionMax);
|
|
141
|
+
if (versionMax !== void 0 && versionMax !== "") entry.versionMax = versionMax;
|
|
142
|
+
if (typeof dependency.optional === "boolean") entry.optional = dependency.optional;
|
|
143
|
+
return entry;
|
|
144
|
+
}
|
|
129
145
|
/** Parse a description block from a publiccode description object. */
|
|
130
146
|
function parseDescription(data) {
|
|
131
147
|
const features = [];
|
|
@@ -134,12 +150,12 @@ function parseDescription(data) {
|
|
|
134
150
|
else if (isPlainObject(feature)) for (const [key, value] of Object.entries(feature)) features.push(typeof value === "string" ? `${key}: ${value}` : key);
|
|
135
151
|
}
|
|
136
152
|
return {
|
|
137
|
-
...isNonEmptyString(data.documentation)
|
|
153
|
+
...isNonEmptyString(data.documentation) && { documentation: data.documentation },
|
|
138
154
|
features,
|
|
139
|
-
...isNonEmptyString(data.genericName)
|
|
140
|
-
...isNonEmptyString(data.localisedName)
|
|
141
|
-
...isNonEmptyString(data.longDescription)
|
|
142
|
-
...isNonEmptyString(data.shortDescription)
|
|
155
|
+
...isNonEmptyString(data.genericName) && { genericName: data.genericName },
|
|
156
|
+
...isNonEmptyString(data.localisedName) && { localisedName: data.localisedName },
|
|
157
|
+
...isNonEmptyString(data.longDescription) && { longDescription: data.longDescription.trim() },
|
|
158
|
+
...isNonEmptyString(data.shortDescription) && { shortDescription: data.shortDescription.trim() }
|
|
143
159
|
};
|
|
144
160
|
}
|
|
145
161
|
/**
|
|
@@ -165,32 +181,30 @@ function parse$1(content) {
|
|
|
165
181
|
const descObject = data.description;
|
|
166
182
|
for (const [lang, langData] of Object.entries(descObject)) if (isPlainObject(langData)) descriptions[lang] = parseDescription(langData);
|
|
167
183
|
const preferredLang = "en" in descriptions ? "en" : Object.keys(descriptions)[0];
|
|
168
|
-
if (preferredLang) description = descriptions[preferredLang];
|
|
184
|
+
if (preferredLang !== void 0 && preferredLang !== "") description = descriptions[preferredLang];
|
|
169
185
|
}
|
|
170
186
|
const contacts = [];
|
|
171
187
|
if (isPlainObject(data.maintenance)) {
|
|
172
188
|
const { maintenance } = data;
|
|
173
|
-
if (Array.isArray(maintenance.contacts)) {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
}
|
|
189
|
+
if (Array.isArray(maintenance.contacts)) for (const contact of maintenance.contacts) {
|
|
190
|
+
if (!isPlainObject(contact) || !isNonEmptyString(contact.name)) continue;
|
|
191
|
+
const entry = { name: contact.name };
|
|
192
|
+
if (isNonEmptyString(contact.email)) entry.email = contact.email;
|
|
193
|
+
if (isNonEmptyString(contact.phone)) entry.phone = contact.phone;
|
|
194
|
+
if (isNonEmptyString(contact.affiliation)) entry.affiliation = contact.affiliation;
|
|
195
|
+
contacts.push(entry);
|
|
181
196
|
}
|
|
182
197
|
}
|
|
183
198
|
const contractors = [];
|
|
184
199
|
if (isPlainObject(data.maintenance)) {
|
|
185
200
|
const { maintenance } = data;
|
|
186
|
-
if (Array.isArray(maintenance.contractors)) {
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
201
|
+
if (Array.isArray(maintenance.contractors)) for (const contractor of maintenance.contractors) {
|
|
202
|
+
if (!isPlainObject(contractor) || !isNonEmptyString(contractor.name)) continue;
|
|
203
|
+
const entry = { name: contractor.name };
|
|
204
|
+
const until = toString(contractor.until);
|
|
205
|
+
if (until !== void 0 && until !== "") entry.until = until;
|
|
206
|
+
if (isNonEmptyString(contractor.website)) entry.website = contractor.website;
|
|
207
|
+
contractors.push(entry);
|
|
194
208
|
}
|
|
195
209
|
}
|
|
196
210
|
const dependencies = [];
|
|
@@ -201,22 +215,10 @@ function parse$1(content) {
|
|
|
201
215
|
"proprietary",
|
|
202
216
|
"hardware"
|
|
203
217
|
]) {
|
|
204
|
-
const
|
|
205
|
-
if (Array.isArray(
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
category,
|
|
209
|
-
name: dep.name
|
|
210
|
-
};
|
|
211
|
-
const version = toString(dep.version);
|
|
212
|
-
if (version) entry.version = version;
|
|
213
|
-
const versionMin = toString(dep.versionMin);
|
|
214
|
-
if (versionMin) entry.versionMin = versionMin;
|
|
215
|
-
const versionMax = toString(dep.versionMax);
|
|
216
|
-
if (versionMax) entry.versionMax = versionMax;
|
|
217
|
-
if (typeof dep.optional === "boolean") entry.optional = dep.optional;
|
|
218
|
-
dependencies.push(entry);
|
|
219
|
-
}
|
|
218
|
+
const categoryDependencies = dependsOn[category];
|
|
219
|
+
if (Array.isArray(categoryDependencies)) for (const dependency of categoryDependencies) {
|
|
220
|
+
const entry = parseDependencyEntry(dependency, category);
|
|
221
|
+
if (entry !== void 0) dependencies.push(entry);
|
|
220
222
|
}
|
|
221
223
|
}
|
|
222
224
|
}
|
|
@@ -238,35 +240,36 @@ function parse$1(content) {
|
|
|
238
240
|
}
|
|
239
241
|
const version = toString(data.softwareVersion);
|
|
240
242
|
const releaseDate = toString(data.releaseDate);
|
|
243
|
+
const publiccodeYmlVersion = toString(data.publiccodeYmlVersion);
|
|
241
244
|
return publiccodeSchema.parse({
|
|
242
|
-
...isNonEmptyString(data.applicationSuite)
|
|
245
|
+
...isNonEmptyString(data.applicationSuite) && { applicationSuite: data.applicationSuite },
|
|
243
246
|
availableLanguages,
|
|
244
247
|
categories: toStringArray(data.categories),
|
|
245
248
|
contacts,
|
|
246
249
|
contractors,
|
|
247
250
|
dependencies,
|
|
248
|
-
...description
|
|
251
|
+
...description && { description },
|
|
249
252
|
descriptions,
|
|
250
|
-
...isNonEmptyString(data.developmentStatus)
|
|
253
|
+
...isNonEmptyString(data.developmentStatus) && { developmentStatus: data.developmentStatus },
|
|
251
254
|
inputTypes: toStringArray(data.inputTypes),
|
|
252
|
-
...isNonEmptyString(data.isBasedOn)
|
|
253
|
-
...isNonEmptyString(data.landingURL)
|
|
254
|
-
...license
|
|
255
|
-
...localisationReady
|
|
256
|
-
...isNonEmptyString(data.logo)
|
|
257
|
-
...mainCopyrightOwner
|
|
258
|
-
...isPlainObject(data.maintenance) && isNonEmptyString(data.maintenance.type)
|
|
259
|
-
...isNonEmptyString(data.monochromeLogo)
|
|
260
|
-
...isNonEmptyString(data.name)
|
|
255
|
+
...isNonEmptyString(data.isBasedOn) && { isBasedOn: data.isBasedOn },
|
|
256
|
+
...isNonEmptyString(data.landingURL) && { landingUrl: data.landingURL },
|
|
257
|
+
...license !== void 0 && { license },
|
|
258
|
+
...localisationReady !== void 0 && { localisationReady },
|
|
259
|
+
...isNonEmptyString(data.logo) && { logo: data.logo },
|
|
260
|
+
...mainCopyrightOwner !== void 0 && { mainCopyrightOwner },
|
|
261
|
+
...isPlainObject(data.maintenance) && isNonEmptyString(data.maintenance.type) && { maintenanceType: data.maintenance.type },
|
|
262
|
+
...isNonEmptyString(data.monochromeLogo) && { monochromeLogo: data.monochromeLogo },
|
|
263
|
+
...isNonEmptyString(data.name) && { name: data.name },
|
|
261
264
|
outputTypes: toStringArray(data.outputTypes),
|
|
262
265
|
platforms: toStringArray(data.platforms),
|
|
263
|
-
...
|
|
264
|
-
...releaseDate
|
|
265
|
-
...repoOwner
|
|
266
|
-
...isNonEmptyString(data.roadmap)
|
|
267
|
-
...isNonEmptyString(data.softwareType)
|
|
268
|
-
...version
|
|
269
|
-
...isNonEmptyString(data.url)
|
|
266
|
+
...publiccodeYmlVersion !== void 0 && publiccodeYmlVersion !== "" && { publiccodeYmlVersion },
|
|
267
|
+
...releaseDate !== void 0 && releaseDate !== "" && { releaseDate },
|
|
268
|
+
...repoOwner !== void 0 && { repoOwner },
|
|
269
|
+
...isNonEmptyString(data.roadmap) && { roadmap: data.roadmap },
|
|
270
|
+
...isNonEmptyString(data.softwareType) && { softwareType: data.softwareType },
|
|
271
|
+
...version !== void 0 && version !== "" && { softwareVersion: version },
|
|
272
|
+
...isNonEmptyString(data.url) && { url: data.url },
|
|
270
273
|
usedBy: toStringArray(data.usedBy)
|
|
271
274
|
});
|
|
272
275
|
}
|
|
@@ -277,7 +280,7 @@ const publiccodeYamlSource = defineSource({
|
|
|
277
280
|
key: "publiccodeYaml",
|
|
278
281
|
async parse(input, context) {
|
|
279
282
|
const data = parse$1(await readFile(resolve(context.options.path, input), "utf8"));
|
|
280
|
-
|
|
283
|
+
return data === void 0 ? void 0 : {
|
|
281
284
|
data,
|
|
282
285
|
source: input
|
|
283
286
|
};
|
|
@@ -80,19 +80,20 @@ function parse(source) {
|
|
|
80
80
|
};
|
|
81
81
|
for (const [header, field] of Object.entries(HEADER_MAP)) {
|
|
82
82
|
const value = headers[header];
|
|
83
|
-
if (value && value !== "UNKNOWN") Object.assign(data, { [field]: value });
|
|
83
|
+
if (value !== void 0 && value !== "" && value !== "UNKNOWN") Object.assign(data, { [field]: value });
|
|
84
84
|
}
|
|
85
|
-
if (headers.Summary && headers.Summary !== "UNKNOWN") data.description = headers.Summary;
|
|
86
|
-
if (headers.Keywords && headers.Keywords !== "UNKNOWN") data.keywords = splitCommaSeparated(headers.Keywords);
|
|
85
|
+
if (headers.Summary !== void 0 && headers.Summary !== "" && headers.Summary !== "UNKNOWN") data.description = headers.Summary;
|
|
86
|
+
if (headers.Keywords !== void 0 && headers.Keywords !== "" && headers.Keywords !== "UNKNOWN") data.keywords = splitCommaSeparated(headers.Keywords);
|
|
87
87
|
data.classifiers = splitMultiValues(headers.Classifier);
|
|
88
88
|
data.platforms = splitMultiValues(headers.Platform);
|
|
89
89
|
data.requires_dist = splitMultiValues(headers["Requires-Dist"]);
|
|
90
|
-
|
|
90
|
+
const projectUrl = headers["Project-URL"];
|
|
91
|
+
if (projectUrl !== void 0 && projectUrl !== "") for (const line of splitMultiValues(projectUrl)) {
|
|
91
92
|
const commaIndex = line.indexOf(", ");
|
|
92
93
|
if (commaIndex > 0) {
|
|
93
94
|
const label = line.slice(0, commaIndex).trim();
|
|
94
95
|
const url = line.slice(commaIndex + 2).trim();
|
|
95
|
-
if (url) data.project_urls[label] = url;
|
|
96
|
+
if (url !== "") data.project_urls[label] = url;
|
|
96
97
|
}
|
|
97
98
|
}
|
|
98
99
|
data.long_description = extractRfc822Body(source);
|