metascope 0.1.0 → 0.2.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 (111) hide show
  1. package/dist/.DS_Store +0 -0
  2. package/dist/bin/cli.js +14 -14
  3. package/dist/lib/{chunk-DrSxFLj_.js → _virtual/_rolldown/runtime.js} +1 -1
  4. package/dist/lib/file-matching.js +152 -0
  5. package/dist/lib/index.d.ts +11 -1496
  6. package/dist/lib/index.js +6 -6215
  7. package/dist/lib/log.d.ts +11 -0
  8. package/dist/lib/log.js +20 -0
  9. package/dist/lib/metadata-types.d.ts +151 -0
  10. package/dist/lib/metadata-types.js +30 -0
  11. package/dist/lib/metadata.d.ts +16 -0
  12. package/dist/lib/metadata.js +235 -0
  13. package/dist/lib/package.js +5 -0
  14. package/dist/lib/parsers/configparser-parser.js +43 -0
  15. package/dist/lib/parsers/gemspec-parser.js +256 -0
  16. package/dist/lib/parsers/go-mod-parser.js +153 -0
  17. package/dist/lib/parsers/makefile-config-parser.js +102 -0
  18. package/dist/lib/parsers/properties-parser.js +31 -0
  19. package/dist/lib/parsers/rfc822-header-parser.js +48 -0
  20. package/dist/lib/parsers/setup-py-parser.js +173 -0
  21. package/dist/lib/source.d.ts +17 -0
  22. package/dist/lib/source.js +34 -0
  23. package/dist/lib/sources/arduino-library-properties.d.ts +45 -0
  24. package/dist/lib/sources/arduino-library-properties.js +208 -0
  25. package/dist/lib/sources/cinder-cinderblock-xml.d.ts +21 -0
  26. package/dist/lib/sources/cinder-cinderblock-xml.js +134 -0
  27. package/dist/lib/sources/code-stats.d.ts +14 -0
  28. package/dist/lib/sources/code-stats.js +40 -0
  29. package/dist/lib/sources/codemeta-json.d.ts +117 -0
  30. package/dist/lib/sources/codemeta-json.js +226 -0
  31. package/dist/lib/sources/dependency-updates.d.ts +22 -0
  32. package/dist/lib/sources/dependency-updates.js +132 -0
  33. package/dist/lib/sources/file-stats.d.ts +12 -0
  34. package/dist/lib/sources/file-stats.js +48 -0
  35. package/dist/lib/sources/git-config.d.ts +8 -0
  36. package/dist/lib/sources/git-config.js +21 -0
  37. package/dist/lib/sources/git-stats.d.ts +35 -0
  38. package/dist/lib/sources/git-stats.js +130 -0
  39. package/dist/lib/sources/github.d.ts +94 -0
  40. package/dist/lib/sources/github.js +399 -0
  41. package/dist/lib/sources/go-go-mod.d.ts +19 -0
  42. package/dist/lib/sources/go-go-mod.js +38 -0
  43. package/dist/lib/sources/go-goreleaser-yaml.d.ts +19 -0
  44. package/dist/lib/sources/go-goreleaser-yaml.js +152 -0
  45. package/dist/lib/sources/java-pom-xml.d.ts +52 -0
  46. package/dist/lib/sources/java-pom-xml.js +248 -0
  47. package/dist/lib/sources/license-file.d.ts +10 -0
  48. package/dist/lib/sources/license-file.js +26 -0
  49. package/dist/lib/sources/metadata-file.d.ts +14 -0
  50. package/dist/lib/sources/metadata-file.js +109 -0
  51. package/dist/lib/sources/metascope.d.ts +14 -0
  52. package/dist/lib/sources/metascope.js +35 -0
  53. package/dist/lib/sources/node-npm-registry.d.ts +19 -0
  54. package/dist/lib/sources/node-npm-registry.js +74 -0
  55. package/dist/lib/sources/node-package-json.d.ts +7 -0
  56. package/dist/lib/sources/node-package-json.js +27 -0
  57. package/dist/lib/sources/obsidian-plugin-manifest-json.d.ts +17 -0
  58. package/dist/lib/sources/obsidian-plugin-manifest-json.js +34 -0
  59. package/dist/lib/sources/obsidian-plugin-registry.d.ts +10 -0
  60. package/dist/lib/sources/obsidian-plugin-registry.js +44 -0
  61. package/dist/lib/sources/openframeworks-addon-config-mk.d.ts +17 -0
  62. package/dist/lib/sources/openframeworks-addon-config-mk.js +39 -0
  63. package/dist/lib/sources/openframeworks-install-xml.d.ts +20 -0
  64. package/dist/lib/sources/openframeworks-install-xml.js +153 -0
  65. package/dist/lib/sources/processing-library-properties.d.ts +44 -0
  66. package/dist/lib/sources/processing-library-properties.js +219 -0
  67. package/dist/lib/sources/processing-sketch-properties.d.ts +38 -0
  68. package/dist/lib/sources/processing-sketch-properties.js +185 -0
  69. package/dist/lib/sources/publiccode-yaml.d.ts +73 -0
  70. package/dist/lib/sources/publiccode-yaml.js +256 -0
  71. package/dist/lib/sources/python-pkg-info.d.ts +31 -0
  72. package/dist/lib/sources/python-pkg-info.js +115 -0
  73. package/dist/lib/sources/python-pypi-registry.d.ts +19 -0
  74. package/dist/lib/sources/python-pypi-registry.js +101 -0
  75. package/dist/lib/sources/python-pyproject-toml.d.ts +7 -0
  76. package/dist/lib/sources/python-pyproject-toml.js +30 -0
  77. package/dist/lib/sources/python-setup-cfg.d.ts +28 -0
  78. package/dist/lib/sources/python-setup-cfg.js +106 -0
  79. package/dist/lib/sources/python-setup-py.d.ts +28 -0
  80. package/dist/lib/sources/python-setup-py.js +48 -0
  81. package/dist/lib/sources/readme-file.d.ts +11 -0
  82. package/dist/lib/sources/readme-file.js +55 -0
  83. package/dist/lib/sources/ruby-gemspec.d.ts +44 -0
  84. package/dist/lib/sources/ruby-gemspec.js +62 -0
  85. package/dist/lib/sources/rust-cargo-toml.d.ts +40 -0
  86. package/dist/lib/sources/rust-cargo-toml.js +159 -0
  87. package/dist/lib/sources/xcode-info-plist.d.ts +22 -0
  88. package/dist/lib/sources/xcode-info-plist.js +199 -0
  89. package/dist/lib/sources/xcode-project-pbxproj.d.ts +21 -0
  90. package/dist/lib/sources/xcode-project-pbxproj.js +222 -0
  91. package/dist/lib/templates/codemeta.d.ts +47 -0
  92. package/dist/lib/templates/codemeta.js +494 -0
  93. package/dist/lib/templates/frontmatter.d.ts +87 -0
  94. package/dist/lib/templates/frontmatter.js +111 -0
  95. package/dist/lib/templates/index.d.ts +181 -0
  96. package/dist/lib/templates/index.js +22 -0
  97. package/dist/lib/templates/metadata.d.ts +17 -0
  98. package/dist/lib/templates/metadata.js +35 -0
  99. package/dist/lib/templates/project.d.ts +39 -0
  100. package/dist/lib/templates/project.js +51 -0
  101. package/dist/lib/utilities/codemeta-helpers.d.ts +39 -0
  102. package/dist/lib/utilities/codemeta-helpers.js +83 -0
  103. package/dist/lib/utilities/fetch.js +43 -0
  104. package/dist/lib/utilities/formatting.js +28 -0
  105. package/dist/lib/utilities/license-identification.js +141 -0
  106. package/dist/lib/utilities/schema-primitives.js +47 -0
  107. package/dist/lib/utilities/template-helpers.d.ts +135 -0
  108. package/dist/lib/utilities/template-helpers.js +310 -0
  109. package/dist/lib/utilities/tree-sitter-wasm.js +30 -0
  110. package/package.json +6 -6
  111. package/readme.md +62 -15
@@ -0,0 +1,19 @@
1
+ import { OneOrMany, SourceRecord } from "../source.js";
2
+
3
+ //#region src/lib/sources/node-npm-registry.d.ts
4
+ type NodeNpmRegistryInfo = {
5
+ /** Deprecation message, if the package is deprecated. */deprecated?: string; /** Downloads in the last month. */
6
+ downloadsMonthly?: number; /** All-time total downloads. */
7
+ downloadsTotal?: number; /** Downloads in the last week. */
8
+ downloadsWeekly?: number; /** Downloads in the last year. */
9
+ downloadsYearly?: number; /** Number of files in the published package. */
10
+ fileCount?: number; /** Whether the package exposes TypeScript types. */
11
+ hasTypes?: boolean; /** ISO 8601 date the package was last published. */
12
+ publishDateLatest?: string; /** Unpacked size of the published package in bytes. */
13
+ unpackedSizeBytes?: number; /** The npmjs.com URL for the package. */
14
+ url?: string; /** Latest published version string. */
15
+ versionLatest?: string;
16
+ };
17
+ type NodeNpmRegistryData = OneOrMany<SourceRecord<NodeNpmRegistryInfo>> | undefined;
18
+ //#endregion
19
+ export { NodeNpmRegistryData };
@@ -0,0 +1,74 @@
1
+ import { log } from "../log.js";
2
+ import { defineSource } from "../source.js";
3
+ import { ensureArray } from "../utilities/template-helpers.js";
4
+ import { fetchWithRetry } from "../utilities/fetch.js";
5
+ import { nodePackageJsonSource } from "./node-package-json.js";
6
+ import is from "@sindresorhus/is";
7
+ import { z } from "zod";
8
+ import packageJson from "package-json";
9
+ //#region src/lib/sources/node-npm-registry.ts
10
+ const nodeNpmRegistrySource = defineSource({
11
+ async discover(context) {
12
+ if (context.options.offline) {
13
+ log.warn("Skipping Node NPM registry data source since we're in offline mode");
14
+ return [];
15
+ }
16
+ let packages = ensureArray(context.metadata?.nodePackageJson);
17
+ if (packages.length === 0 && !context.completedSources?.has("nodePackageJson")) {
18
+ log.warn(`Missing nodePackageJson in source context metadata for ${context.options.path}, extracting it now...`);
19
+ packages = ensureArray(await nodePackageJsonSource.extract(context));
20
+ }
21
+ return packages.filter((packageJson) => {
22
+ if (packageJson.data.private === true || packageJson.data.publishConfig?.access === "restricted") {
23
+ log.debug(`Skipping NPM registry lookup for "${packageJson.data.name}" in "${context.options.path}" because it is a private package`);
24
+ return false;
25
+ }
26
+ return true;
27
+ }).map((packageJson) => packageJson.data.name);
28
+ },
29
+ key: "nodeNpmRegistry",
30
+ async parse(input) {
31
+ log.debug("Extracting npm metadata...");
32
+ const name = input;
33
+ const [metadata, downloadsWeekly, downloadsMonthly, downloadsYearly, downloadsTotal] = await Promise.all([
34
+ packageJson(name, { fullMetadata: true }).catch(() => void 0),
35
+ fetchDownloads(name, "last-week"),
36
+ fetchDownloads(name, "last-month"),
37
+ fetchDownloads(name, "last-year"),
38
+ fetchDownloads(name, "2005-01-01:3000-01-01")
39
+ ]);
40
+ if (!metadata) return;
41
+ const hasTypes = Boolean(metadata.types ?? metadata.typings ?? (is.plainObject(metadata) ? metadata.exports : void 0));
42
+ const distribution = is.plainObject(metadata.dist) ? metadata.dist : void 0;
43
+ const time = is.plainObject(metadata.time) ? metadata.time : void 0;
44
+ return {
45
+ data: {
46
+ deprecated: typeof metadata.deprecated === "string" ? metadata.deprecated : void 0,
47
+ downloadsMonthly,
48
+ downloadsTotal: downloadsTotal || void 0,
49
+ downloadsWeekly,
50
+ downloadsYearly,
51
+ fileCount: typeof distribution?.fileCount === "number" ? distribution.fileCount : void 0,
52
+ hasTypes,
53
+ publishDateLatest: typeof time?.modified === "string" ? time.modified : void 0,
54
+ unpackedSizeBytes: typeof distribution?.unpackedSize === "number" ? distribution.unpackedSize : void 0,
55
+ url: `https://www.npmjs.com/package/${encodeURIComponent(name)}`,
56
+ versionLatest: metadata.version
57
+ },
58
+ source: `https://www.npmjs.com/package/${encodeURIComponent(name)}`
59
+ };
60
+ },
61
+ phase: 2
62
+ });
63
+ const npmDownloadsSchema = z.object({ downloads: z.number() });
64
+ async function fetchDownloads(packageName, period) {
65
+ try {
66
+ const response = await fetchWithRetry(`https://api.npmjs.org/downloads/point/${period}/${encodeURIComponent(packageName)}`);
67
+ if (!response.ok) return void 0;
68
+ return npmDownloadsSchema.parse(await response.json()).downloads;
69
+ } catch {
70
+ return;
71
+ }
72
+ }
73
+ //#endregion
74
+ export { nodeNpmRegistrySource };
@@ -0,0 +1,7 @@
1
+ import { OneOrMany, SourceRecord } from "../source.js";
2
+ import { NormalizedPackageJson } from "read-pkg";
3
+
4
+ //#region src/lib/sources/node-package-json.d.ts
5
+ type NodePackageJsonData = OneOrMany<SourceRecord<NormalizedPackageJson>> | undefined;
6
+ //#endregion
7
+ export { NodePackageJsonData };
@@ -0,0 +1,27 @@
1
+ import { getMatches } from "../file-matching.js";
2
+ import { defineSource } from "../source.js";
3
+ import { readFile } from "node:fs/promises";
4
+ import { resolve } from "node:path";
5
+ import { parsePackage } from "read-pkg";
6
+ //#region src/lib/sources/node-package-json.ts
7
+ /**
8
+ * Parse package.json content and return structured metadata.
9
+ */
10
+ function parse(content) {
11
+ return parsePackage(content);
12
+ }
13
+ const nodePackageJsonSource = defineSource({
14
+ async discover(context) {
15
+ return getMatches(context.options, ["package.json"]);
16
+ },
17
+ key: "nodePackageJson",
18
+ async parse(input, context) {
19
+ return {
20
+ data: parse(await readFile(resolve(context.options.path, input), "utf8")),
21
+ source: input
22
+ };
23
+ },
24
+ phase: 1
25
+ });
26
+ //#endregion
27
+ export { nodePackageJsonSource };
@@ -0,0 +1,17 @@
1
+ import { OneOrMany, SourceRecord } from "../source.js";
2
+
3
+ //#region src/lib/sources/obsidian-plugin-manifest-json.d.ts
4
+ type ObsidianManifest = {
5
+ /** Plugin author name. */author?: string; /** URL for the plugin author. */
6
+ authorUrl?: string; /** Plugin description. */
7
+ description?: string; /** URL for funding or sponsorship. */
8
+ fundingUrl?: string; /** Unique plugin identifier. */
9
+ id: string; /** Whether the plugin is desktop-only. */
10
+ isDesktopOnly?: boolean; /** Minimum Obsidian app version required. */
11
+ minAppVersion?: string; /** Display name of the plugin. */
12
+ name?: string; /** Plugin version string. */
13
+ version?: string;
14
+ };
15
+ type ObsidianPluginManifestJsonData = OneOrMany<SourceRecord<ObsidianManifest>> | undefined;
16
+ //#endregion
17
+ export { ObsidianPluginManifestJsonData };
@@ -0,0 +1,34 @@
1
+ import { getMatches } from "../file-matching.js";
2
+ import { defineSource } from "../source.js";
3
+ import { readFile } from "node:fs/promises";
4
+ import { resolve } from "node:path";
5
+ import { z } from "zod";
6
+ //#region src/lib/sources/obsidian-plugin-manifest-json.ts
7
+ const manifestSchema = z.object({
8
+ author: z.string().optional(),
9
+ authorUrl: z.string().optional(),
10
+ description: z.string().optional(),
11
+ fundingUrl: z.string().optional(),
12
+ id: z.string(),
13
+ isDesktopOnly: z.boolean().optional(),
14
+ minAppVersion: z.string().optional(),
15
+ name: z.string().optional(),
16
+ version: z.string().optional()
17
+ });
18
+ const obsidianPluginManifestJsonSource = defineSource({
19
+ async discover(context) {
20
+ return getMatches(context.options, ["manifest.json"]);
21
+ },
22
+ key: "obsidianPluginManifestJson",
23
+ async parse(input, context) {
24
+ const content = await readFile(resolve(context.options.path, input), "utf8");
25
+ const parsed = manifestSchema.safeParse(JSON.parse(content));
26
+ if (parsed.success) return {
27
+ data: parsed.data,
28
+ source: input
29
+ };
30
+ },
31
+ phase: 1
32
+ });
33
+ //#endregion
34
+ export { obsidianPluginManifestJsonSource };
@@ -0,0 +1,10 @@
1
+ import { OneOrMany, SourceRecord } from "../source.js";
2
+
3
+ //#region src/lib/sources/obsidian-plugin-registry.d.ts
4
+ type ObsidianPluginRegistryInfo = {
5
+ /** Total community download count. */downloadCount?: number; /** Obsidian plugin directory URL. */
6
+ url?: string;
7
+ };
8
+ type ObsidianPluginRegistryData = OneOrMany<SourceRecord<ObsidianPluginRegistryInfo>> | undefined;
9
+ //#endregion
10
+ export { ObsidianPluginRegistryData };
@@ -0,0 +1,44 @@
1
+ import { log } from "../log.js";
2
+ import { defineSource } from "../source.js";
3
+ import { ensureArray } from "../utilities/template-helpers.js";
4
+ import { fetchWithRetry } from "../utilities/fetch.js";
5
+ import { obsidianPluginManifestJsonSource } from "./obsidian-plugin-manifest-json.js";
6
+ import { z } from "zod";
7
+ //#region src/lib/sources/obsidian-plugin-registry.ts
8
+ const communityPluginsUrl = "https://raw.githubusercontent.com/obsidianmd/obsidian-releases/master/community-plugin-stats.json";
9
+ const pluginStatsSchema = z.record(z.string(), z.record(z.string(), z.number()));
10
+ const obsidianPluginRegistrySource = defineSource({
11
+ async discover(context) {
12
+ if (context.options.offline) {
13
+ log.warn("Skipping Obsidian plugin registry data source since we're in offline mode");
14
+ return [];
15
+ }
16
+ let pluginIds = ensureArray(context.metadata?.obsidianPluginManifestJson).map((value) => value.data.id);
17
+ if (pluginIds.length === 0 && !context.completedSources?.has("obsidianPluginManifestJson")) {
18
+ log.warn(`Missing obsidianPluginManifestJson in source context metadata for ${context.options.path}, extracting it now...`);
19
+ pluginIds = ensureArray(await obsidianPluginManifestJsonSource.extract(context)).map((value) => value.data.id);
20
+ }
21
+ return pluginIds;
22
+ },
23
+ key: "obsidianPluginRegistry",
24
+ async parse(input) {
25
+ log.debug("Extracting Obsidian plugin registry metadata...");
26
+ const pluginId = input;
27
+ const url = `https://obsidian.md/plugins?id=${encodeURIComponent(pluginId)}`;
28
+ const response = await fetchWithRetry(communityPluginsUrl);
29
+ if (!response.ok) return {
30
+ data: { url },
31
+ source: url
32
+ };
33
+ return {
34
+ data: {
35
+ downloadCount: pluginStatsSchema.parse(await response.json())[pluginId]?.downloads || void 0,
36
+ url
37
+ },
38
+ source: url
39
+ };
40
+ },
41
+ phase: 2
42
+ });
43
+ //#endregion
44
+ export { obsidianPluginRegistrySource };
@@ -0,0 +1,17 @@
1
+ import { OneOrMany, SourceRecord } from "../source.js";
2
+ import { z } from "zod";
3
+
4
+ //#region src/lib/sources/openframeworks-addon-config-mk.d.ts
5
+ declare const openframeworksAddonConfigSchema: z.ZodObject<{
6
+ author: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
7
+ dependencies: z.ZodPipe<z.ZodTransform<string[], unknown>, z.ZodArray<z.ZodString>>;
8
+ description: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
9
+ name: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
10
+ platformSections: z.ZodPipe<z.ZodTransform<string[], unknown>, z.ZodArray<z.ZodString>>;
11
+ tags: z.ZodPipe<z.ZodTransform<string[], unknown>, z.ZodArray<z.ZodString>>;
12
+ url: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
13
+ }, z.core.$strip>;
14
+ type OpenframeworksAddonConfig = z.infer<typeof openframeworksAddonConfigSchema>;
15
+ type OpenframeworksAddonConfigMkData = OneOrMany<SourceRecord<OpenframeworksAddonConfig>> | undefined;
16
+ //#endregion
17
+ export { OpenframeworksAddonConfigMkData };
@@ -0,0 +1,39 @@
1
+ import { getMatches } from "../file-matching.js";
2
+ import { defineSource } from "../source.js";
3
+ import { nonEmptyString, optionalUrl, stringArray } from "../utilities/schema-primitives.js";
4
+ import { parseMakefileConfig } from "../parsers/makefile-config-parser.js";
5
+ import { readFile } from "node:fs/promises";
6
+ import { resolve } from "node:path";
7
+ import { z } from "zod";
8
+ //#region src/lib/sources/openframeworks-addon-config-mk.ts
9
+ const openframeworksAddonConfigSchema = z.object({
10
+ author: nonEmptyString,
11
+ dependencies: stringArray,
12
+ description: nonEmptyString,
13
+ name: nonEmptyString,
14
+ platformSections: stringArray,
15
+ tags: stringArray,
16
+ url: optionalUrl
17
+ });
18
+ /**
19
+ * Parse an `addon_config.mk` file and return validated metadata.
20
+ */
21
+ function parse(content) {
22
+ const raw = parseMakefileConfig(content);
23
+ return openframeworksAddonConfigSchema.parse(raw);
24
+ }
25
+ const openframeworksAddonConfigMkSource = defineSource({
26
+ async discover(context) {
27
+ return getMatches(context.options, ["addon_config.mk"]);
28
+ },
29
+ key: "openframeworksAddonConfigMk",
30
+ async parse(input, context) {
31
+ return {
32
+ data: parse(await readFile(resolve(context.options.path, input), "utf8")),
33
+ source: input
34
+ };
35
+ },
36
+ phase: 1
37
+ });
38
+ //#endregion
39
+ export { openframeworksAddonConfigMkSource };
@@ -0,0 +1,20 @@
1
+ import { OneOrMany, SourceRecord } from "../source.js";
2
+ import { z } from "zod";
3
+
4
+ //#region src/lib/sources/openframeworks-install-xml.d.ts
5
+ declare const openframeworksInstallXmlSchema: z.ZodObject<{
6
+ author: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
7
+ codeUrl: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
8
+ description: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
9
+ downloadUrl: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
10
+ name: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
11
+ operatingSystems: z.ZodPipe<z.ZodTransform<string[], unknown>, z.ZodArray<z.ZodString>>;
12
+ requirements: z.ZodPipe<z.ZodTransform<string[], unknown>, z.ZodArray<z.ZodString>>;
13
+ siteUrl: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
14
+ url: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
15
+ version: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
16
+ }, z.core.$strip>;
17
+ type OpenframeworksInstallXml = z.infer<typeof openframeworksInstallXmlSchema>;
18
+ type OpenframeworksInstallXmlData = OneOrMany<SourceRecord<OpenframeworksInstallXml>> | undefined;
19
+ //#endregion
20
+ export { OpenframeworksInstallXmlData };
@@ -0,0 +1,153 @@
1
+ import { getMatches } from "../file-matching.js";
2
+ import { defineSource } from "../source.js";
3
+ import { nonEmptyString, optionalUrl, stringArray } from "../utilities/schema-primitives.js";
4
+ import { ensureArray } from "../utilities/template-helpers.js";
5
+ import { readFile } from "node:fs/promises";
6
+ import { resolve } from "node:path";
7
+ import is from "@sindresorhus/is";
8
+ import { z } from "zod";
9
+ import { XMLParser } from "fast-xml-parser";
10
+ //#region src/lib/sources/openframeworks-install-xml.ts
11
+ /**
12
+ * Source and parser for legacy openFrameworks addon `install.xml` files.
13
+ *
14
+ * This is a legacy format predating `addon_config.mk`. The root element is
15
+ * `<install>`, with flat metadata elements (`<name>`, `<version>`, `<author>`,
16
+ * etc.) followed by build configuration in an `<add>` block.
17
+ *
18
+ * Since `install.xml` is a generic filename, the parser validates that the
19
+ * content is actually an openFrameworks addon by checking for the `<install>`
20
+ * root element and the presence of "addons" in the file content.
21
+ *
22
+ * Uses `fast-xml-parser` with attribute parsing enabled to read `<lib os="...">`
23
+ * attributes for operating system inference.
24
+ */
25
+ const openframeworksInstallXmlSchema = z.object({
26
+ author: nonEmptyString,
27
+ codeUrl: optionalUrl,
28
+ description: nonEmptyString,
29
+ downloadUrl: optionalUrl,
30
+ name: nonEmptyString,
31
+ operatingSystems: stringArray,
32
+ requirements: stringArray,
33
+ siteUrl: optionalUrl,
34
+ url: optionalUrl,
35
+ version: nonEmptyString
36
+ });
37
+ /**
38
+ * Map `<lib os="...">` attribute values to human-readable OS names.
39
+ */
40
+ const LIB_OS_MAP = {
41
+ linux: "Linux",
42
+ mac: "macOS",
43
+ win32: "Windows"
44
+ };
45
+ /**
46
+ * Parse a legacy openFrameworks `install.xml` content string into a structured object.
47
+ * Returns undefined if the XML is malformed, missing the `<install>` root element,
48
+ * or does not appear to be an openFrameworks addon.
49
+ */
50
+ function parse(content) {
51
+ if (!content.toLowerCase().includes("addons")) return;
52
+ const fixedContent = content.replaceAll("<[CDATA[", "<![CDATA[");
53
+ const parser = new XMLParser({
54
+ attributeNamePrefix: "@_",
55
+ ignoreAttributes: false,
56
+ parseTagValue: false
57
+ });
58
+ let data;
59
+ try {
60
+ const parsed = parser.parse(fixedContent);
61
+ if (!is.plainObject(parsed)) return void 0;
62
+ data = parsed;
63
+ } catch {
64
+ return;
65
+ }
66
+ if (!is.plainObject(data.install)) return void 0;
67
+ const { install } = data;
68
+ return openframeworksInstallXmlSchema.parse({
69
+ author: getString(install.author),
70
+ codeUrl: getString(install.code_url),
71
+ description: getString(install.description),
72
+ downloadUrl: getString(install.download_url),
73
+ name: getString(install.name),
74
+ operatingSystems: parseOperatingSystems(install),
75
+ requirements: parseRequirements(install),
76
+ siteUrl: getString(install.site_url),
77
+ url: getString(install.url),
78
+ version: getString(install.version)
79
+ });
80
+ }
81
+ /**
82
+ * Get a trimmed non-empty string from a parsed XML value.
83
+ * Returns undefined for empty strings, non-strings, or whitespace-only values.
84
+ */
85
+ function getString(value) {
86
+ if (typeof value !== "string") return void 0;
87
+ const trimmed = value.trim();
88
+ return trimmed.length > 0 ? trimmed : void 0;
89
+ }
90
+ /**
91
+ * Extract software requirements from `<requires>`.
92
+ * Handles three variants:
93
+ * 1. Empty — skip
94
+ * 2. Free text — emit as-is
95
+ * 3. Structured `<addon>` children — emit each separately
96
+ */
97
+ function parseRequirements(install) {
98
+ const { requires } = install;
99
+ if (requires === void 0 || requires === null) return [];
100
+ if (typeof requires === "string") {
101
+ const trimmed = requires.trim();
102
+ return trimmed.length > 0 ? [trimmed] : [];
103
+ }
104
+ if (is.plainObject(requires)) {
105
+ const results = [];
106
+ for (const addon of ensureArray(requires.addon)) {
107
+ const name = getString(addon);
108
+ if (name) results.push(name);
109
+ }
110
+ return results;
111
+ }
112
+ return [];
113
+ }
114
+ /**
115
+ * Extract operating system information from `<lib os="...">` attributes
116
+ * found within `<add><link>` sections.
117
+ */
118
+ function parseOperatingSystems(install) {
119
+ if (!is.plainObject(install.add)) return [];
120
+ const { add } = install;
121
+ if (!is.plainObject(add.link)) return [];
122
+ const { link } = add;
123
+ const results = [];
124
+ const seen = /* @__PURE__ */ new Set();
125
+ for (const library of ensureArray(link.lib)) {
126
+ if (!is.plainObject(library)) continue;
127
+ const os = getString(library["@_os"]);
128
+ if (os) {
129
+ const mapped = LIB_OS_MAP[os.toLowerCase()] ?? os;
130
+ if (!seen.has(mapped)) {
131
+ seen.add(mapped);
132
+ results.push(mapped);
133
+ }
134
+ }
135
+ }
136
+ return results;
137
+ }
138
+ const openframeworksInstallXmlSource = defineSource({
139
+ async discover(context) {
140
+ return getMatches(context.options, ["install.xml"]);
141
+ },
142
+ key: "openframeworksInstallXml",
143
+ async parse(input, context) {
144
+ const data = parse(await readFile(resolve(context.options.path, input), "utf8"));
145
+ if (data !== void 0) return {
146
+ data,
147
+ source: input
148
+ };
149
+ },
150
+ phase: 1
151
+ });
152
+ //#endregion
153
+ export { openframeworksInstallXmlSource };
@@ -0,0 +1,44 @@
1
+ import { OneOrMany, SourceRecord } from "../source.js";
2
+ import { z } from "zod";
3
+
4
+ //#region src/lib/sources/processing-library-properties.d.ts
5
+ declare const processingLibraryPropertiesSchema: z.ZodObject<{
6
+ authors: z.ZodArray<z.ZodObject<{
7
+ name: z.ZodString;
8
+ url: z.ZodOptional<z.ZodString>;
9
+ }, z.core.$strip>>;
10
+ categories: z.ZodArray<z.ZodEnum<{
11
+ GUI: "GUI";
12
+ "3D": "3D";
13
+ Animation: "Animation";
14
+ Compilations: "Compilations";
15
+ Data: "Data";
16
+ Fabrication: "Fabrication";
17
+ Geometry: "Geometry";
18
+ Hardware: "Hardware";
19
+ "I/O": "I/O";
20
+ Language: "Language";
21
+ Math: "Math";
22
+ Simulation: "Simulation";
23
+ Sound: "Sound";
24
+ Utilities: "Utilities";
25
+ Typography: "Typography";
26
+ "Video & Vision": "Video & Vision";
27
+ }>>;
28
+ download: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
29
+ id: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
30
+ maxRevision: z.ZodNumber;
31
+ minRevision: z.ZodNumber;
32
+ name: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
33
+ paragraph: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
34
+ prettyVersion: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
35
+ raw: z.ZodRecord<z.ZodString, z.ZodString>;
36
+ sentence: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
37
+ type: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
38
+ url: z.ZodPipe<z.ZodTransform<string | undefined, unknown>, z.ZodOptional<z.ZodString>>;
39
+ version: z.ZodNumber;
40
+ }, z.core.$strip>;
41
+ type ProcessingLibraryProperties = z.infer<typeof processingLibraryPropertiesSchema>;
42
+ type ProcessingLibraryPropertiesData = OneOrMany<SourceRecord<ProcessingLibraryProperties>> | undefined;
43
+ //#endregion
44
+ export { ProcessingLibraryPropertiesData };