diff --git a/.eslintrc.json b/.eslintrc.json index a7a3f42..75afc02 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -22,6 +22,7 @@ // examples, and because it is not a recommended rule, you should either // disable it, or understand what it enforces. // https://typescript-eslint.io/rules/explicit-function-return-type/ - "@typescript-eslint/explicit-function-return-type": "warn" + "@typescript-eslint/explicit-function-return-type": "warn", + "@typescript-eslint/no-explicit-any": "warn" } } diff --git a/.gitignore b/.gitignore index 08b35db..b33d66e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ coverage # Transpiled files build/ +out/ # VS Code .vscode diff --git a/package-lock.json b/package-lock.json index 5089dbe..e0523d3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,10 @@ "version": "1.0.0", "license": "MIT", "dependencies": { - "js-yaml": "^4.1.0" + "@studiorack/core": "^1.2.6", + "graphql-request": "^6.1.0", + "js-yaml": "^4.1.0", + "semver": "^7.6.0" }, "devDependencies": { "@types/jest": "~29.5", @@ -1104,6 +1107,14 @@ "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", @@ -1163,7 +1174,6 @@ "version": "8.0.2", "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, "dependencies": { "string-width": "^5.1.2", "string-width-cjs": "npm:string-width@^4.2.0", @@ -1180,7 +1190,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, "engines": { "node": ">=12" }, @@ -1192,7 +1201,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, "engines": { "node": ">=12" }, @@ -1203,14 +1211,12 @@ "node_modules/@isaacs/cliui/node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" }, "node_modules/@isaacs/cliui/node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, "dependencies": { "eastasianwidth": "^0.2.0", "emoji-regex": "^9.2.2", @@ -1227,7 +1233,6 @@ "version": "7.1.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, "dependencies": { "ansi-regex": "^6.0.1" }, @@ -1242,7 +1247,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, "dependencies": { "ansi-styles": "^6.1.0", "string-width": "^5.0.1", @@ -1728,7 +1732,6 @@ "version": "0.11.0", "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, "optional": true, "engines": { "node": ">=14" @@ -1758,6 +1761,43 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@studiorack/core": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@studiorack/core/-/core-1.2.6.tgz", + "integrity": "sha512-sqOtkTNDp4CIaJGvNhGL1YG1AjY+dUGuXqCW0o2doiu1EbnqLVW7VTxQEzb6nhSaYm+hWM2BPdYuXn6U017p6A==", + "dependencies": { + "@vscode/sudo-prompt": "^9.3.1", + "adm-zip": "^0.4.16", + "fs-extra": "^10.1.0", + "glob": "^10.3.6", + "node-fetch": "^2.6.1", + "nodejs-fs-utils": "^1.2.5", + "readline-sync": "^1.4.10", + "semver": "^7.3.4", + "slugify": "^1.4.6" + } + }, + "node_modules/@studiorack/core/node_modules/glob": { + "version": "10.3.12", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.12.tgz", + "integrity": "sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.6", + "minimatch": "^9.0.1", + "minipass": "^7.0.4", + "path-scurry": "^1.10.2" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", @@ -2118,6 +2158,11 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, + "node_modules/@vscode/sudo-prompt": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/@vscode/sudo-prompt/-/sudo-prompt-9.3.1.tgz", + "integrity": "sha512-9ORTwwS74VaTn38tNbQhsA5U44zkJfcb0BdTSyyG6frP4e8KMtHuTXYmwefe5dpL8XB1aGSIVTaLjD3BbWb5iA==" + }, "node_modules/acorn": { "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", @@ -2150,6 +2195,14 @@ "node": ">=0.4.0" } }, + "node_modules/adm-zip": { + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz", + "integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg==", + "engines": { + "node": ">=0.3.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -2197,7 +2250,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -2206,7 +2258,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2371,14 +2422,12 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/brace-expansion": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -2572,7 +2621,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2583,8 +2631,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/concat-map": { "version": "0.0.1", @@ -2627,11 +2674,18 @@ "optional": true, "peer": true }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -2743,8 +2797,7 @@ "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" }, "node_modules/electron-to-chromium": { "version": "1.4.736", @@ -2767,8 +2820,7 @@ "node_modules/emoji-regex": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" }, "node_modules/error-ex": { "version": "1.3.2", @@ -3358,7 +3410,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", - "dev": true, "dependencies": { "cross-spawn": "^7.0.0", "signal-exit": "^4.0.1" @@ -3374,7 +3425,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, "engines": { "node": ">=14" }, @@ -3382,6 +3432,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -3554,8 +3617,7 @@ "node_modules/graceful-fs": { "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/graphemer": { "version": "1.4.0", @@ -3563,6 +3625,27 @@ "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", "dev": true }, + "node_modules/graphql": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "peer": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-request": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/graphql-request/-/graphql-request-6.1.0.tgz", + "integrity": "sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==", + "dependencies": { + "@graphql-typed-document-node/core": "^3.2.0", + "cross-fetch": "^3.1.5" + }, + "peerDependencies": { + "graphql": "14 - 16" + } + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3699,7 +3782,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, "engines": { "node": ">=8" } @@ -3758,8 +3840,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", @@ -3831,7 +3912,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" }, @@ -4465,6 +4545,17 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -4618,7 +4709,6 @@ "version": "9.0.4", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz", "integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -4633,11 +4723,15 @@ "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", - "dev": true, "engines": { "node": ">=16 || 14 >=14.17" } }, + "node_modules/module-require": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/module-require/-/module-require-1.4.5.tgz", + "integrity": "sha512-ksEXPs62btutKsbJKph7rLhdu7A6JIIHXTqvr3uhOP1mViI8JeHkNzYHJnVlHVCaRCuHa7XMBnKmxc23YZGl6Q==" + }, "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -4650,6 +4744,25 @@ "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -4662,6 +4775,14 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, + "node_modules/nodejs-fs-utils": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/nodejs-fs-utils/-/nodejs-fs-utils-1.2.6.tgz", + "integrity": "sha512-uDIfV3Qvjrtis2jOhHYzvUTAReqtnBXCVm0efjAYDgrCgZZBDxMQcZE7SsDAui4zzQ7GpqYUFUwoOpOoQD4vpA==", + "dependencies": { + "module-require": "*" + } + }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -4815,7 +4936,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -4830,7 +4950,6 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.2.tgz", "integrity": "sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==", - "dev": true, "dependencies": { "lru-cache": "^10.2.0", "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" @@ -4846,7 +4965,6 @@ "version": "10.2.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", - "dev": true, "engines": { "node": "14 || >=16.14" } @@ -5065,6 +5183,14 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, + "node_modules/readline-sync": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/readline-sync/-/readline-sync-1.4.10.tgz", + "integrity": "sha512-gNva8/6UAe8QYepIQH/jQ2qn91Qj0B9sYjMBBs3QOB8F2CXcKgLxQaJRP76sWVRQt+QU+8fAkCbCvjjMFu7Ycw==", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -5216,7 +5342,6 @@ "version": "7.6.0", "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -5231,7 +5356,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -5242,14 +5366,12 @@ "node_modules/semver/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -5261,7 +5383,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -5287,6 +5408,14 @@ "node": ">=8" } }, + "node_modules/slugify": { + "version": "1.6.6", + "resolved": "https://registry.npmjs.org/slugify/-/slugify-1.6.6.tgz", + "integrity": "sha512-h+z7HKHYXj6wJU+AnS/+IH8Uh9fdcX1Lrhg1/VMdf9PwoBQXFcXiAdsy2tSK0P6gKwJLXp02r90ahUCqHk9rrw==", + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/source-map": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", @@ -5350,7 +5479,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5365,7 +5493,6 @@ "version": "4.2.3", "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -5379,7 +5506,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5392,7 +5518,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -5523,6 +5648,11 @@ "node": ">=8.0" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" + }, "node_modules/ts-api-utils": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", @@ -5694,6 +5824,14 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "dev": true }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.0.13", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", @@ -5764,11 +5902,24 @@ "makeerror": "1.0.12" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -5801,7 +5952,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", diff --git a/package.json b/package.json index d256e13..d07b953 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,10 @@ "node": ">= 20.9 < 21" }, "dependencies": { - "js-yaml": "^4.1.0" + "@studiorack/core": "^1.2.6", + "graphql-request": "^6.1.0", + "js-yaml": "^4.1.0", + "semver": "^7.6.0" }, "devDependencies": { "@types/jest": "~29.5", diff --git a/src/main.ts b/src/main.ts index 22fd600..bd43283 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,33 +1,61 @@ -import fs from 'fs'; -import yaml from 'js-yaml'; -import { PluginInterface, PluginRegistry } from './types/Plugin.js'; +import { dirCreate, fileJsonCreate } from '@studiorack/core'; +import { + PluginEntry, + PluginInterface, + PluginRegistry, +} from './types/Plugin.js'; +import { githubGetPack } from './sources/github.js'; +import { localGetPack } from './sources/local.js'; -function registryLoad(repo: string, version: string, id: string) { - const file: string = fs.readFileSync(`./src/plugins/${repo}/${version}/${id}.yaml`, 'utf8'); - return yaml.load(file) as PluginInterface; -} +const DIST_PATH: string = './out'; +const REGISTRY_OUT: string = 'index.json'; +const REGISTRY_OUT_EFFECTS: string = 'effects.json'; +const REGISTRY_OUT_INSTRUMENTS: string = 'instruments.json'; +const REGISTRY_OUT_SFZ: string = 'sfz.json'; -function registryNew() { +export function registryNew(type: string): PluginRegistry { return { - name: 'StudioRack Registry', - url: 'https://studiorack.github.io/studiorack-registry', + name: `StudioRack Registry - ${type}`, + url: `https://studiorack.github.io/studiorack-registry/${type}.json`, version: '2.0.0', - objects: [], + objects: {}, }; } -function run() { - const registry: PluginRegistry = registryNew(); - const pluginRepo: string = 'surge-synthesizer/releases-xt'; - const pluginVersion: string = '1.3.1'; - const pluginId: string = 'surge'; - const plugin: PluginInterface = registryLoad(pluginRepo, pluginVersion, pluginId); - // registry.objects[`${pluginRepo}/${pluginId}`] = { - // id: pluginId, - // version: pluginVersion, - // versions[pluginVersion]: plugin;, - // } - console.log(plugin); +async function registrySave(path: string, file: PluginRegistry) { + dirCreate(DIST_PATH); + fileJsonCreate(path, file); +} + +async function run() { + const registry: PluginRegistry = registryNew('registry'); + registry.objects = Object.assign(registry.objects, await githubGetPack()); + registry.objects = Object.assign(registry.objects, localGetPack()); + + // Create separate registries for Effects and Instruments + const effects: PluginRegistry = registryNew('effects'); + const index: PluginRegistry = registryNew('index'); + const instruments: PluginRegistry = registryNew('instruments'); + const sfz: PluginRegistry = registryNew('sfz'); + for (const pluginId in registry.objects) { + const pluginEntry: PluginEntry = registry.objects[pluginId]; + const plugin: PluginInterface = pluginEntry.versions[pluginEntry.version]; + // Check if tags include Effect/Fx + if (plugin.tags.includes('Effect') || plugin.tags.includes('Fx')) { + effects.objects[pluginId] = pluginEntry; + } + if (plugin.tags.includes('Instrument')) { + instruments.objects[pluginId] = pluginEntry; + } + if (plugin.tags.includes('sfz')) { + sfz.objects[pluginId] = pluginEntry; + } + index.objects[pluginId] = pluginEntry; + } + registrySave(`${DIST_PATH}/${REGISTRY_OUT}`, index); + registrySave(`${DIST_PATH}/${REGISTRY_OUT_EFFECTS}`, effects); + registrySave(`${DIST_PATH}/${REGISTRY_OUT_INSTRUMENTS}`, instruments); + registrySave(`${DIST_PATH}/${REGISTRY_OUT_SFZ}`, sfz); } run(); diff --git a/src/plugins/sfztools/sfizz/1.2.3.yaml b/src/plugins/sfztools/sfizz/1.2.3.yaml new file mode 100644 index 0000000..1245da9 --- /dev/null +++ b/src/plugins/sfztools/sfizz/1.2.3.yaml @@ -0,0 +1,27 @@ +--- +name: Sfizz +author: SFZTools +homepage: https://github.com/sfztools/sfizz +description: SFZ parser and synth c++ library, providing AU / LV2 / VST3 plugins and JACK standalone client. +date: 2024-01-14T00:00:00.000Z +license: bsd-2-clause +tags: + - Instrument + - Sampler + - Synth +files: + audio: + url: https://studiorack.github.io/studiorack-registry/plugins/sfztools/sfizz/sfizz.flac + size: 47910 + image: + url: https://studiorack.github.io/studiorack-registry/plugins/sfztools/sfizz/sfizz.jpg + size: 33976 + linux: + url: https://github.com/sfztools/sfizz/releases/download/1.2.3/sfizz-1.2.3.tar.gz + size: 19102967 + mac: + url: https://github.com/sfztools/sfizz/releases/download/1.2.3/sfizz-1.2.3-macos.tar.gz + size: 1748833 + win: + url: https://github.com/sfztools/sfizz/releases/download/1.2.3/sfizz-1.2.3-win64.zip + size: 8286178 diff --git a/src/plugins/sfztools/sfizz/sfizz.flac b/src/plugins/sfztools/sfizz/sfizz.flac new file mode 100644 index 0000000..cf72921 Binary files /dev/null and b/src/plugins/sfztools/sfizz/sfizz.flac differ diff --git a/src/plugins/sfztools/sfizz/sfizz.jpg b/src/plugins/sfztools/sfizz/sfizz.jpg new file mode 100644 index 0000000..41fc847 Binary files /dev/null and b/src/plugins/sfztools/sfizz/sfizz.jpg differ diff --git a/src/plugins/surge-synthesizer/releases-xt/1.3.1/surge.yaml b/src/plugins/surge-synthesizer/releases-xt/1.3.1/surge.yaml deleted file mode 100644 index a5ed945..0000000 --- a/src/plugins/surge-synthesizer/releases-xt/1.3.1/surge.yaml +++ /dev/null @@ -1,27 +0,0 @@ ---- -name: Surge XT -author: Surge Synth Team -homepage: https://surge-synthesizer.github.io -description: Hybrid synthesizer featuring many synthesis techniques, a great selection of filters, a flexible modulation engine, a smorgasbord of effects, and modern features like MPE and microtuning. -date: 2024-02-06T00:00:00.000Z -license: gpl-3.0 -tags: - - Instrument - - Synth - - Modulation -files: - audio: - url: https://studiorack.github.io/studiorack-registry/audio/surge.flac - size: 141339 - image: - url: https://studiorack.github.io/studiorack-registry/image/surge.jpg - size: 159518 - linux: - url: surge-xt-linux-1.3.1-pluginsonly.tar.gz - size: 94448096 - mac: - url: surge-xt-macos-1.3.1-pluginsonly.zip - size: 180726292 - win: - url: surge-xt-win64-1.3.1-pluginsonly.zip - size: 48165645 diff --git a/src/plugins/surge-synthesizer/surge/1.3.0.yaml b/src/plugins/surge-synthesizer/surge/1.3.0.yaml new file mode 100644 index 0000000..7166fb7 --- /dev/null +++ b/src/plugins/surge-synthesizer/surge/1.3.0.yaml @@ -0,0 +1,27 @@ +--- +name: Surge XT +author: Surge Synth Team +homepage: https://github.com/surge-synthesizer/surge +description: Hybrid synthesizer featuring many synthesis techniques, a great selection of filters, a flexible modulation engine, a smorgasbord of effects, and modern features like MPE and microtuning. +date: 2023-12-08T00:00:00.000Z +license: gpl-3.0 +tags: + - Instrument + - Synth + - Modulation +files: + audio: + url: https://studiorack.github.io/studiorack-registry/plugins/surge-synthesizer/surge/surge.flac + size: 141339 + image: + url: https://studiorack.github.io/studiorack-registry/plugins/surge-synthesizer/surge/surge.jpg + size: 159518 + linux: + url: https://github.com/surge-synthesizer/releases-xt/releases/download/1.3.0/surge-xt-linux-1.3.0-pluginsonly.tar.gz + size: 94448096 + mac: + url: https://github.com/surge-synthesizer/releases-xt/releases/download/1.3.0/surge-xt-macos-1.3.0-pluginsonly.zip + size: 180726292 + win: + url: https://github.com/surge-synthesizer/releases-xt/releases/download/1.3.0/surge-xt-win64-1.3.0-pluginsonly.zip + size: 48165645 diff --git a/src/plugins/surge-synthesizer/surge/1.3.1.yaml b/src/plugins/surge-synthesizer/surge/1.3.1.yaml new file mode 100644 index 0000000..3ba2bd6 --- /dev/null +++ b/src/plugins/surge-synthesizer/surge/1.3.1.yaml @@ -0,0 +1,27 @@ +--- +name: Surge XT +author: Surge Synth Team +homepage: https://github.com/surge-synthesizer/surge +description: Hybrid synthesizer featuring many synthesis techniques, a great selection of filters, a flexible modulation engine, a smorgasbord of effects, and modern features like MPE and microtuning. +date: 2024-02-06T00:00:00.000Z +license: gpl-3.0 +tags: + - Instrument + - Synth + - Modulation +files: + audio: + url: https://studiorack.github.io/studiorack-registry/plugins/surge-synthesizer/surge/surge.flac + size: 141339 + image: + url: https://studiorack.github.io/studiorack-registry/plugins/surge-synthesizer/surge/surge.jpg + size: 159518 + linux: + url: https://github.com/surge-synthesizer/releases-xt/releases/download/1.3.1/surge-xt-linux-1.3.1-pluginsonly.tar.gz + size: 94448096 + mac: + url: https://github.com/surge-synthesizer/releases-xt/releases/download/1.3.1/surge-xt-macos-1.3.1-pluginsonly.zip + size: 180726292 + win: + url: https://github.com/surge-synthesizer/releases-xt/releases/download/1.3.1/surge-xt-win64-1.3.1-pluginsonly.zip + size: 48165645 diff --git a/src/plugins/surge-synthesizer/surge/surge.flac b/src/plugins/surge-synthesizer/surge/surge.flac new file mode 100644 index 0000000..9c96173 Binary files /dev/null and b/src/plugins/surge-synthesizer/surge/surge.flac differ diff --git a/src/plugins/surge-synthesizer/surge/surge.jpg b/src/plugins/surge-synthesizer/surge/surge.jpg new file mode 100644 index 0000000..fda0bd7 Binary files /dev/null and b/src/plugins/surge-synthesizer/surge/surge.jpg differ diff --git a/src/sources/github.ts b/src/sources/github.ts new file mode 100644 index 0000000..34b0a2f --- /dev/null +++ b/src/sources/github.ts @@ -0,0 +1,130 @@ +import * as semver from 'semver'; +import { PluginLocal, pluginValidateSchema, safeSlug } from '@studiorack/core'; +import fetch from 'node-fetch'; +import { gql, GraphQLClient, RequestDocument } from 'graphql-request'; +import { PluginPack, PluginRelease } from '../types/Plugin.js'; + +// Plugins need to have a topic `studiorack-plugin` to appear in the results +// https://github.com/topics/studiorack-plugin +const GITHUB_API: string = 'https://api.github.com/graphql'; +const GITHUB_TOPIC: string = 'studiorack-plugin'; +const GITHUB_REPO_PAGINATION: number = 100; +const GITHUB_RELEASES_PAGINATION: number = 100; + +interface GitHubRelease { + tagName: string; +} + +interface GitHubRepository { + nameWithOwner: string; + licenseInfo: { + key: string; + }; + releases: { + nodes: GitHubRelease[]; + }; +} + +interface GitHubSearch { + search: { + nodes: GitHubRepository[]; + }; +} + +async function githubGetPack(): Promise { + const pluginPack: PluginPack = {}; + const results: GitHubSearch = await githubSearchRepos(GITHUB_API); + for (const repo of results.search.nodes) { + for (const release of repo.releases.nodes) { + await githubGetRelease(pluginPack, repo, release); + } + } + console.log(pluginPack); + return pluginPack; +} + +async function githubSearchRepos(url: string): Promise { + const headers: any = {}; + if (process.env.GITHUB_TOKEN) + headers.Authorization = `Bearer ${process.env.GITHUB_TOKEN}`; + const graphQLClient = new GraphQLClient(url, { headers }); + const query: RequestDocument = gql` + { + search(query: "topic:${GITHUB_TOPIC} fork:true", type: REPOSITORY, first: ${GITHUB_REPO_PAGINATION}) { + nodes { + ... on Repository { + nameWithOwner + licenseInfo { + key + } + releases(first: ${GITHUB_RELEASES_PAGINATION}) { + nodes { + tagName + } + } + } + } + } + } + `; + return graphQLClient.request(query); +} + +async function githubGetRelease( + pluginPack: PluginPack, + repo: GitHubRepository, + release: GitHubRelease, +) { + const pluginsJsonList = await githubGetPlugins( + `https://github.com/${repo.nameWithOwner}/releases/download/${release.tagName}/plugins.json`, + ); + pluginsJsonList.plugins.forEach((plugin: PluginRelease) => { + // For each plugin sanitize the id and add to registry + const pluginId = safeSlug(`${repo.nameWithOwner}/${safeSlug(plugin.id)}`); + const pluginVersion = semver.coerce(plugin.version)?.version || '0.0.0'; + console.log('github', pluginId, pluginVersion); + if (!pluginPack[pluginId]) { + pluginPack[pluginId] = { + version: pluginVersion, + versions: {}, + }; + } + // TODO update plugins.json to not need these fields + delete plugin.id; + delete plugin.version; + pluginPack[pluginId].versions[pluginVersion] = plugin; + // If plugin version is greater than the current, set as latest version + if (semver.gt(pluginVersion, pluginPack[pluginId].version)) { + pluginPack[pluginId].version = pluginVersion; + } + }); + return pluginPack; +} + +async function githubGetPlugins(url: string) { + const pluginsValid: PluginRelease[] = []; + const pluginsJson = await getJSONSafe(url); + pluginsJson.plugins.forEach((plugin: PluginRelease) => { + const error = pluginValidateSchema(plugin as unknown as PluginLocal); + if (error === false) { + pluginsValid.push(plugin); + } else { + console.log(error, plugin); + } + }); + return { plugins: pluginsValid }; +} + +async function getJSONSafe(url: string): Promise { + console.log('⤓', url); + try { + const response = await fetch(url); + const json = await response.json(); + return json; + } catch (error) { + // console.log(error); + return { plugins: [] }; + } +} + +export { githubGetPack }; diff --git a/src/sources/local.ts b/src/sources/local.ts new file mode 100644 index 0000000..1112977 --- /dev/null +++ b/src/sources/local.ts @@ -0,0 +1,43 @@ +import yaml from 'js-yaml'; +import path from 'path'; +import * as semver from 'semver'; +import { dirRead, fileReadString, safeSlug } from '@studiorack/core'; +import { PluginInterface, PluginPack } from '../types/Plugin.js'; + +const LOCAL_DIR: string = path.join('src', 'plugins'); +const LOCAL_EXT: string = '.yaml'; +const LOCAL_REG: string = path.join(LOCAL_DIR, '**', '*' + LOCAL_EXT); + +export function localGetPack() { + const pack: PluginPack = {}; + const filepaths: string[] = dirRead(LOCAL_REG); + filepaths.forEach((filepath: string) => { + // TODO update studiorack/core to handle these strings + const parts: string[] = filepath + .replace(LOCAL_DIR, '') + .replace(LOCAL_EXT, '') + .substring(1) + .split(path.sep); + const id = safeSlug(`${parts[0]}/${parts[1]}`); + const version = parts[2]; + if (!pack[id]) { + pack[id] = { + version, + versions: {}, + }; + } + // Release is different from version and can vary per version + const plugin: PluginInterface = localGetFile(filepath); + pack[id].versions[version] = plugin; + // If plugin version is greater than the current, set as latest version + if (semver.gt(version, pack[id].version)) { + pack[id].version = version; + } + }); + return pack; +} + +export function localGetFile(path: string) { + const file: string = fileReadString(path); + return yaml.load(file) as PluginInterface; +} diff --git a/src/sources/owlplug.ts b/src/sources/owlplug.ts new file mode 100644 index 0000000..a17b5f8 --- /dev/null +++ b/src/sources/owlplug.ts @@ -0,0 +1,93 @@ +import * as semver from 'semver'; +import { + fileReadJson, + pathGetId, + pathGetVersion, + PluginInterface, + PluginPack, + safeSlug, +} from '@studiorack/core'; + +const REGISTRY_URL = 'https://central.owlplug.com/store'; + +interface OwlPluginInterface { + name: string; + creator: string; + screenshotUrl: string; + description: string; + pageUrl: string; + donateUrl: string; + version: string; + technicalUid: string; + type: string; + stage: string; + tags: string[]; + bundles: OwlPluginFiles[]; +} + +interface OwlPluginFiles { + name: string; + targets: string[]; + format: string; + downloadUrl: string; + fileSize: number; +} + +async function getOwlplugPack(): Promise { + const pluginPack: PluginPack = {}; + const registry = await fileReadJson(REGISTRY_URL); + registry.products.forEach((product: OwlPluginInterface) => { + const plugin: PluginInterface = { + author: product.creator, + date: new Date().toISOString(), + description: product.description, + homepage: product.pageUrl, + id: pathGetId(product.screenshotUrl), + name: product.name, + files: { + audio: { name: '', size: 0 }, + image: { name: product.screenshotUrl, size: 0 }, + linux: { name: '', size: 0 }, + mac: { name: '', size: 0 }, + win: { name: '', size: 0 }, + }, + release: `v${registry.version}`, + repo: 'owlplug/central', + tags: product.tags, + version: pathGetVersion(product.version || '0.0.0'), + }; + product.bundles.forEach((bundle: OwlPluginFiles) => { + if (bundle.targets.includes('linux')) { + plugin.files.linux.name = bundle.downloadUrl; + plugin.files.linux.size = bundle.fileSize; + } + if (bundle.targets.includes('osx')) { + plugin.files.mac.name = bundle.downloadUrl; + plugin.files.mac.size = bundle.fileSize; + } else if (bundle.targets.includes('win64')) { + plugin.files.win.name = bundle.downloadUrl; + plugin.files.win.size = bundle.fileSize; + } + }); + // For each plugin sanitize the id and add to registry + const pluginId = safeSlug(`${plugin.repo}/${plugin.id}`); + const pluginVersion = semver.coerce(plugin.version)?.version || '0.0.0'; + console.log('owlplug', pluginId, pluginVersion); + if (!pluginPack[pluginId]) { + pluginPack[pluginId] = { + id: pluginId, + license: '', + version: pluginVersion, + versions: {}, + }; + } + pluginPack[pluginId].versions[pluginVersion] = plugin; + // If plugin version is greater than the current, set as latest version + if (semver.gt(pluginVersion, pluginPack[pluginId].version)) { + pluginPack[pluginId].version = pluginVersion; + } + }); + return pluginPack; +} + +export { getOwlplugPack }; diff --git a/src/types/Plugin.ts b/src/types/Plugin.ts index bb929cc..099b353 100644 --- a/src/types/Plugin.ts +++ b/src/types/Plugin.ts @@ -2,7 +2,7 @@ export interface PluginRegistry { name: string; url: string; version: string; - objects: PluginPack[]; + objects: PluginPack; } export interface PluginPack { @@ -10,7 +10,6 @@ export interface PluginPack { } export interface PluginEntry { - id: string; version: string; versions: { [version: string]: PluginInterface }; } @@ -35,13 +34,11 @@ export interface PluginInterface { homepage: string; name: string; files: PluginFiles; - license?: PluginLicense; + license: string; tags: string[]; } -interface PluginLicense { - key: string; - name: string; - url: string; - same: boolean; +export interface PluginRelease extends PluginInterface { + id: string; + version: string; }