From 4586a86ce7e8bfbac3aa89d47b80fc678f822fc2 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 12:38:54 +0100 Subject: [PATCH 01/15] feat: add missing lang histories --- app/Console/Commands/LoadProLang.php | 80 ++++++++++++++++++++++++-- app/Console/Commands/ProLangAssets.php | 11 +++- 2 files changed, 85 insertions(+), 6 deletions(-) diff --git a/app/Console/Commands/LoadProLang.php b/app/Console/Commands/LoadProLang.php index 1a3ae26..bcb1791 100644 --- a/app/Console/Commands/LoadProLang.php +++ b/app/Console/Commands/LoadProLang.php @@ -51,9 +51,9 @@ private function saveProLang(array $item) { 'name' => $yearGroup['name'], ), array( - 'apiId' => $yearGroup['id'], - 'position' => $yearGroup['position'], - 'name' => $yearGroup['name'], + 'apiId' => $yearGroup['id'] ?? null, + 'position' => $yearGroup['position'] ?? null, + 'name' => $yearGroup['name'] ?? null, )); $updatedLang = ProLang::updateOrCreate( @@ -118,12 +118,84 @@ private function getLanguages(int $page) { } /** - * Execute the console command. + * Add some languages like Phel missing in prolang api */ + private function addProLanguage() { + $langToAdd = array( + // Data : https://phel-lang.org/ and preums itselft + array( + 'authors' => array(), + 'company' => null, + 'id' => uniqid().'_Phel', + 'link' => '', + 'name' => 'Phel', + 'predecessors' => array(), + 'yearGroup' => array( + 'name' => '2020s', + ), + 'years' => array(2020), + ), + // Data : https://janet-lang.org/ and preums itselft + array( + 'authors' => array(), + 'company' => null, + 'id' => uniqid().'_Janet', + 'link' => '', + 'name' => 'Janet', + 'predecessors' => array(), + 'yearGroup' => array( + 'name' => '2010s', + ), + 'years' => array(2017), + ), + ); + + foreach ($langToAdd as $item) { + $this->saveProLang($item); + Log::info('action=add_missing_lang, status=succes, lang='.$item['name']); + } + } + + /** + * Add links between languages + * - Some data are missing from prolang api + * - Ex : Php is Hack's predecessors + */ + private function updateLangFamily() { + $langFamilies = array( + // Data: https://github.com/janet-lang/janet + 'Janet' => array('C'), + // Data : https://phel-lang.org/ + 'Phel' => array('PHP', 'Clojure', 'Janet', 'Lisp'), + // https://en.wikipedia.org/wiki/PHP + 'PHP' => array('C', 'C++', 'Perl'), + // Data : https://en.wikipedia.org/wiki/Hack_(programming_language) + 'Hack' => array('PHP', 'OCaml', 'Java', 'Scala', 'Haskell', 'C#'), + ); + + foreach ($langFamilies as $name => $value) { + $lang = ProLang::where('name', $name)->first(); + if ($lang) { + $parents = ProLang::whereIn( + 'name', $value + )->pluck('id'); + + $lang->parents()->sync($parents); + $lang->save(); + + Log::info("action=save_lang, status=success, lang=$name"); + } else { + Log::info("action=save_lang, status=failed, reason=lang $name not found"); + } + } + } + public function handle() { Log::info('action=load_prolang_command, status=started'); $this->getLanguages(1); + $this->addProLanguage(); + $this->updateLangFamily(); Log::info('action=load_prolang_command, status=finished'); } diff --git a/app/Console/Commands/ProLangAssets.php b/app/Console/Commands/ProLangAssets.php index 5cd41c7..d6894e1 100644 --- a/app/Console/Commands/ProLangAssets.php +++ b/app/Console/Commands/ProLangAssets.php @@ -1117,6 +1117,12 @@ function member ), 'Common Lisp' => array(), 'Windows PowerShell' => array(), + 'Phel' => array( + 'mainRepository' => 'https://github.com/phel-lang/phel-lang', + ), + 'Janet' => array( + 'mainRepository' => 'https://github.com/janet-lang/janet', + ), ); DB::transaction(function () use ($langsData) { @@ -1141,9 +1147,10 @@ function member */ public function handle() { Log::info('action=prolang_assets_command, status=started'); - $this->updateAssets(); - Log::info('action=prolang_assets_command, status=finished'); + $this->updateAssets(); $this->updateLinks(); + + Log::info('action=prolang_assets_command, status=finished'); } } From 8d59d69267fbf5d01fb940bc950d3328bff12936 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 12:49:31 +0100 Subject: [PATCH 02/15] fix: close lang drawer --- resources/js/components/prolang/LangCard.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/js/components/prolang/LangCard.vue b/resources/js/components/prolang/LangCard.vue index 41b66c9..b56629b 100644 --- a/resources/js/components/prolang/LangCard.vue +++ b/resources/js/components/prolang/LangCard.vue @@ -1,7 +1,7 @@ diff --git a/resources/js/pages/RepositoryHistory.vue b/resources/js/pages/RepositoryHistory.vue index 9481afd..818f6aa 100644 --- a/resources/js/pages/RepositoryHistory.vue +++ b/resources/js/pages/RepositoryHistory.vue @@ -67,10 +67,10 @@ import RepositoryDetails from "@/components/repository/RepositoryDetails.vue" import RepositoryLanguages from "@/components/repository/RepositoryLanguages.vue" import RepositoryRelease from "@/components/repository/RepositoryRelease.vue" import RepositoryTopics from "@/components/repository/RepositoryTopics.vue" -import type { GithubCommit, GithubCommitActivity, GithubCommitDiff, GithubRelease, GithubSearchResultItem } from "@/types/main" +import type { GithubCommit, GithubCommitActivity, GithubCommitDiff, GithubRelease, GithubRepository } from "@/types/main" const props = defineProps<{ - repository: GithubSearchResultItem + repository: GithubRepository commits: { firstCommit: GithubCommit | null lastCommit: GithubCommit diff --git a/resources/js/types/main.d.ts b/resources/js/types/main.d.ts index 71e7ef0..60558e5 100644 --- a/resources/js/types/main.d.ts +++ b/resources/js/types/main.d.ts @@ -112,7 +112,6 @@ export type ProLangAuthor = { } export type ProLangLanguage = { - // TODO: add predecessors in hisotry id: number apiId: string company: string | null @@ -125,8 +124,9 @@ export type ProLangLanguage = { codeTitle: string rawCode: string | null rawCodeLink: string | null - children: ProLangLanguage[] - parents: ProLangLanguage[] + children: Array> + parents: Array> + paths: string[] } export type YearGroup = { From 247caadf0baba225243becf12c92765b9aa90c19 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 18:57:43 +0100 Subject: [PATCH 08/15] chore: remove useless file --- resources/js/lib/utils.ts | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 resources/js/lib/utils.ts diff --git a/resources/js/lib/utils.ts b/resources/js/lib/utils.ts deleted file mode 100644 index 03aaa4b..0000000 --- a/resources/js/lib/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { type ClassValue, clsx } from "clsx" -import { twMerge } from "tailwind-merge" - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} From c827aa2e88cc32b8799d65472fa8fa4bf3147e23 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 18:59:07 +0100 Subject: [PATCH 09/15] chore: remove useless tailwind --- package-lock.json | 248 +++------------------------------------------- package.json | 1 - 2 files changed, 15 insertions(+), 234 deletions(-) diff --git a/package-lock.json b/package-lock.json index faf7b7f..0e20858 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,6 @@ "@hackernoon/pixel-icon-library": "^1.0.6", "@inertiajs/vue3": "^2.2.19", "@nanostores/vue": "^1.0.1", - "@tailwindcss/vite": "^4.1.11", "@vueuse/core": "^12.8.2", "@yeger/vue-masonry-wall": "^5.1.4", "chart.js": "^4.5.1", @@ -43,19 +42,6 @@ "lightningcss-linux-x64-gnu": "^1.29.1" } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@awesome.me/webawesome": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@awesome.me/webawesome/-/webawesome-3.0.0.tgz", @@ -734,53 +720,12 @@ "vue": "^3.0.0" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.12", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.12.tgz", - "integrity": "sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==", - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz", "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==", "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.29", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.29.tgz", - "integrity": "sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==", - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@kurkle/color": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/@kurkle/color/-/color-0.3.4.tgz", @@ -1527,79 +1472,6 @@ "integrity": "sha512-r4C9C/5kSfMBIr0D9imvpRdCNXtUNgyYThc4YlS6K5Hchv1UyxNQ9mxwj+BTRH2i1Neits260sR3OjKMnplsFA==", "license": "MIT" }, - "node_modules/@tailwindcss/node": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.11.tgz", - "integrity": "sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==", - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "enhanced-resolve": "^5.18.1", - "jiti": "^2.4.2", - "lightningcss": "1.30.1", - "magic-string": "^0.30.17", - "source-map-js": "^1.2.1", - "tailwindcss": "4.1.11" - } - }, - "node_modules/@tailwindcss/oxide": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.11.tgz", - "integrity": "sha512-Q69XzrtAhuyfHo+5/HMgr1lAiPP/G40OMFAnws7xcFEYqcypZmdW8eGXaOUIeOl1dzPJBPENXgbjsOyhg2nkrg==", - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "detect-libc": "^2.0.4", - "tar": "^7.4.3" - }, - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.1.11", - "@tailwindcss/oxide-darwin-arm64": "4.1.11", - "@tailwindcss/oxide-darwin-x64": "4.1.11", - "@tailwindcss/oxide-freebsd-x64": "4.1.11", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.11", - "@tailwindcss/oxide-linux-arm64-gnu": "4.1.11", - "@tailwindcss/oxide-linux-arm64-musl": "4.1.11", - "@tailwindcss/oxide-linux-x64-gnu": "4.1.11", - "@tailwindcss/oxide-linux-x64-musl": "4.1.11", - "@tailwindcss/oxide-wasm32-wasi": "4.1.11", - "@tailwindcss/oxide-win32-arm64-msvc": "4.1.11", - "@tailwindcss/oxide-win32-x64-msvc": "4.1.11" - } - }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.11.tgz", - "integrity": "sha512-ESgStEOEsyg8J5YcMb1xl8WFOXfeBmrhAwGsFxxB2CxY9evy63+AtpbDLAyRkJnxLy2WsD1qF13E97uQyP1lfQ==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@tailwindcss/vite": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.11.tgz", - "integrity": "sha512-RHYhrR3hku0MJFRV+fN2gNbDNEh3dwKvY8XJvTxCSXeMOsCRSr+uKvDWQcbizrHgjML6ZmTE5OwMrl5wKcujCw==", - "license": "MIT", - "dependencies": { - "@tailwindcss/node": "4.1.11", - "@tailwindcss/oxide": "4.1.11", - "tailwindcss": "4.1.11" - }, - "peerDependencies": { - "vite": "^5.2.0 || ^6 || ^7" - } - }, "node_modules/@types/conventional-commits-parser": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/@types/conventional-commits-parser/-/conventional-commits-parser-5.0.2.tgz", @@ -2177,15 +2049,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -2530,6 +2393,8 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", "integrity": "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==", "license": "Apache-2.0", + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -2581,19 +2446,6 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, - "node_modules/enhanced-resolve": { - "version": "5.18.2", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.2.tgz", - "integrity": "sha512-6Jw4sE1maoRJo3q8MsSIn2onJFbLTOjY9hlx4DZXmOKvLRd1Ok2kXmAGXaafL2+ijsJZ1ClYbl/pmqr9+k4iUQ==", - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -2916,12 +2768,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "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==", - "license": "ISC" - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3153,6 +2999,7 @@ "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", + "devOptional": true, "license": "MIT", "bin": { "jiti": "lib/jiti-cli.mjs" @@ -3244,6 +3091,8 @@ "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.30.1.tgz", "integrity": "sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==", "license": "MPL-2.0", + "optional": true, + "peer": true, "dependencies": { "detect-libc": "^2.0.3" }, @@ -3279,6 +3128,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3299,6 +3149,7 @@ "os": [ "darwin" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3319,6 +3170,7 @@ "os": [ "freebsd" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3339,6 +3191,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3359,6 +3212,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3379,6 +3233,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3419,6 +3274,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3439,6 +3295,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3459,6 +3316,7 @@ "os": [ "win32" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3479,6 +3337,7 @@ "os": [ "linux" ], + "peer": true, "engines": { "node": ">= 12.0.0" }, @@ -3821,48 +3680,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/minizlib": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.0.2.tgz", - "integrity": "sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==", - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", "license": "MIT" }, - "node_modules/mkdirp": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-3.0.1.tgz", - "integrity": "sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==", - "license": "MIT", - "bin": { - "mkdirp": "dist/cjs/src/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/muggle-string": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz", @@ -4875,38 +4698,6 @@ "node": ">=16.0.0" } }, - "node_modules/tailwindcss": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.11.tgz", - "integrity": "sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==", - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.2.tgz", - "integrity": "sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/tar": { - "version": "7.4.3", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.4.3.tgz", - "integrity": "sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==", - "license": "ISC", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.0.1", - "mkdirp": "^3.0.1", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/text-extensions": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/text-extensions/-/text-extensions-2.4.0.tgz", @@ -5377,15 +5168,6 @@ "node": ">=10" } }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 0ef0851..bf2edaf 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,6 @@ "@hackernoon/pixel-icon-library": "^1.0.6", "@inertiajs/vue3": "^2.2.19", "@nanostores/vue": "^1.0.1", - "@tailwindcss/vite": "^4.1.11", "@vueuse/core": "^12.8.2", "@yeger/vue-masonry-wall": "^5.1.4", "chart.js": "^4.5.1", From c773e11535172cdc61ef3733edb791201e4129a7 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 19:30:14 +0100 Subject: [PATCH 10/15] feat(path): add all langs family path --- app/Models/ProLang.php | 37 ++++++++++++++ tests/Unit/Models/ProLangTest.php | 84 +++++++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 tests/Unit/Models/ProLangTest.php diff --git a/app/Models/ProLang.php b/app/Models/ProLang.php index c575573..fead52a 100644 --- a/app/Models/ProLang.php +++ b/app/Models/ProLang.php @@ -5,6 +5,7 @@ use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsToMany; +use Illuminate\Support\Facades\DB; /** * @property int $id @@ -21,6 +22,8 @@ class ProLang extends Model { protected $guarded = array('id'); + protected $appends = array('paths'); + protected $casts = array( 'years' => 'array', ); @@ -52,4 +55,38 @@ public function authors(): BelongsToMany { public function authorNames(): array { return $this->authors()->pluck('name')->toArray(); } + + // paths + + public function getPathsAttribute() { + $targetId = DB::table('pro_langs')->where('id', $this->id)->value('id'); + + $paths = DB::select(" + WITH RECURSIVE paths AS ( + SELECT + l.id, + l.name, + l.name::text AS path + FROM pro_langs l + WHERE NOT EXISTS ( + SELECT 1 FROM predecessors p WHERE p.child_id = l.id + ) + + UNION ALL + + SELECT + c.id, + c.name, + paths.path || ' -> ' || c.name + FROM paths + JOIN predecessors p ON p.parent_id = paths.id + JOIN pro_langs c ON c.id = p.child_id + ) + SELECT path + FROM paths + WHERE id = ? + ", array($targetId)); + + return array_map(fn ($r) => $r->path, $paths); + } } diff --git a/tests/Unit/Models/ProLangTest.php b/tests/Unit/Models/ProLangTest.php new file mode 100644 index 0000000..433f39c --- /dev/null +++ b/tests/Unit/Models/ProLangTest.php @@ -0,0 +1,84 @@ + '', + 'name' => '1990', + 'position' => 1, + )); + + $parents = array_map(function (string $name) use ($group) { + $l = ProLang::create(array( + 'name' => $name, + 'apiId' => '', + 'link' => '', + 'company' => null, + 'years' => '["1990"]', + 'yearGroupId' => $group->id, + )); + + return $l; + }, array('LiveScript', 'Perl')); + + $lang = ProLang::create(array( + 'name' => 'JvaScript', + 'apiId' => '', + 'link' => '', + 'company' => null, + 'years' => '["1990"]', + 'yearGroupId' => $group->id, + )); + + $anotherLang = ProLang::create(array( + 'name' => 'Awesome', + 'apiId' => '', + 'link' => '', + 'company' => null, + 'years' => '["1990"]', + 'yearGroupId' => $group->id, + )); + + $lang->parents()->sync($parents); + $anotherLang->children()->sync(array( + $parents[0], + )); + + expect(count($lang->paths))->toBe(2); + expect($lang->paths)->toContain('Perl -> JvaScript'); + expect($lang->paths)->toContain('Awesome -> LiveScript -> JvaScript'); +}); + +it('should be able to detect if it is an orphan lang', function () { + $group = YearGroup::create(array( + 'apiId' => '', + 'name' => '1990', + 'position' => 1, + )); + + $lang = ProLang::create(array( + 'name' => 'JvaScript', + 'apiId' => '', + 'link' => '', + 'company' => null, + 'years' => '["1990"]', + 'yearGroupId' => $group->id, + )); + + $anotherLang = ProLang::create(array( + 'name' => 'Awesome', + 'apiId' => '', + 'link' => '', + 'company' => null, + 'years' => '["1990"]', + 'yearGroupId' => $group->id, + )); + + expect($lang->isOrphan())->toBe(true); + + $lang->parents()->sync($anotherLang); + + expect($lang->isOrphan())->toBe(false); +}); From e31962657db7a7541a0b4150e7a302633fd8785f Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 19:30:56 +0100 Subject: [PATCH 11/15] test: use common function for tests --- tests/Datasets/ProLang.php | 16 +++++++++++++++- tests/Unit/Commands/LoadProLangTest.php | 12 ------------ 2 files changed, 15 insertions(+), 13 deletions(-) diff --git a/tests/Datasets/ProLang.php b/tests/Datasets/ProLang.php index 2164999..37f3eca 100644 --- a/tests/Datasets/ProLang.php +++ b/tests/Datasets/ProLang.php @@ -1,5 +1,8 @@ Http::response( + $prolang, + 200, + ), + )); + + (new LoadProLang())->handle(); +} + +$proLang = getProLangSample('prolang-api.json'); dataset('prolang', array( array($proLang)) diff --git a/tests/Unit/Commands/LoadProLangTest.php b/tests/Unit/Commands/LoadProLangTest.php index 29c7e0e..0d94a17 100644 --- a/tests/Unit/Commands/LoadProLangTest.php +++ b/tests/Unit/Commands/LoadProLangTest.php @@ -1,23 +1,11 @@ Http::response( - $prolang, - 200, - ), - )); - - (new LoadProLang())->handle(); - } - it('should call prolang api', function (array $prolang) { mockProlangApi($prolang); From 9e3bf4aa724bd15898be04cd5d55ecaf547f8989 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 19:36:06 +0100 Subject: [PATCH 12/15] ci: generate wayfinder before vue-tsc --- .github/workflows/lint.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 4e4a5e9..bddbadb 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -37,4 +37,6 @@ jobs: run: npx biome check - name: Lint TS errors - run: npx vue-tsc --noEmit --checkJs --project tsconfig.json + run: | + php artisan wayfinder:generate + npx vue-tsc --noEmit --checkJs --project tsconfig.json From a4081d6d0028526592b60435799561972436daa0 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 19:50:15 +0100 Subject: [PATCH 13/15] ci(draft): use postgres instead of sqlite for test --- .github/workflows/tests.yml | 49 ++++++++++++++++++++++--------------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 038f158..f0d01f3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -13,38 +13,47 @@ on: jobs: ci: runs-on: ubuntu-latest + services: + postgres: + image: postgres:15 + env: + POSTGRES_USER: test + POSTGRES_PASSWORD: secret + POSTGRES_DB: test_db + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 steps: - - name: Checkout - uses: actions/checkout@v4 + - uses: actions/checkout@v4 - - name: Setup PHP - uses: shivammathur/setup-php@v2 + - uses: shivammathur/setup-php@v2 with: php-version: 8.4 tools: composer:v2 coverage: xdebug - - name: Setup Node - uses: actions/setup-node@v4 + - uses: actions/setup-node@v4 with: node-version: '22' cache: 'npm' - - name: Install Node Dependencies - run: npm ci - - - name: Install Dependencies - run: composer install --no-interaction --prefer-dist --optimize-autoloader - - - name: Copy Environment File - run: cp .env.example .env - - - name: Generate Application Key - run: php artisan key:generate - - - name: Build Assets - run: npm run build + - run: npm ci + - run: composer install --no-interaction --prefer-dist --optimize-autoloader + - run: cp .env.example .env + - run: php artisan key:generate + - run: npm run build - name: Tests + env: + DB_CONNECTION: pgsql + DB_HOST: 127.0.0.1 + DB_PORT: 5432 + DB_DATABASE: test_db + DB_USERNAME: test + DB_PASSWORD: secret run: ./vendor/bin/pest From 9316a6f49f516a778b77a1abed5a3c64662569c7 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 21:08:44 +0100 Subject: [PATCH 14/15] test: something for github action --- app/Models/Api/GithubRepositoryApi.php | 45 ++++++++++++++------------ 1 file changed, 25 insertions(+), 20 deletions(-) diff --git a/app/Models/Api/GithubRepositoryApi.php b/app/Models/Api/GithubRepositoryApi.php index 41a2f38..05e1960 100644 --- a/app/Models/Api/GithubRepositoryApi.php +++ b/app/Models/Api/GithubRepositoryApi.php @@ -34,26 +34,31 @@ public static function get() { } private function parseRepository(array $item): GithubRepository { - return new GithubRepository( - id: $item['id'], - stars: $item['stargazers_count'], - name: $item['name'], - fullName: $item['full_name'], - description: $item['description'], - url: $item['html_url'], - createdAt: new DateTime($item['created_at']), - updatedAt: new DateTime($item['updated_at']), - language: $item['language'], - topics: $item['topics'], - watchers: $item['watchers'], - forks: $item['forks'], - owner: new GithubRepositoryOwner( - login: $item['owner']['login'], - id: $item['owner']['id'], - avatarUrl: $item['owner']['avatar_url'], - ), - ownerIsOrganization: $item['owner']['type'] === 'Organization', - ); + try { + return new GithubRepository( + id: $item['id'], + stars: $item['stargazers_count'], + name: $item['name'], + fullName: $item['full_name'], + description: $item['description'], + url: $item['html_url'], + createdAt: new DateTime($item['created_at']), + updatedAt: new DateTime($item['updated_at']), + language: $item['language'], + topics: $item['topics'], + watchers: $item['watchers'], + forks: $item['forks'], + owner: new GithubRepositoryOwner( + login: $item['owner']['login'], + id: $item['owner']['id'], + avatarUrl: $item['owner']['avatar_url'], + ), + ownerIsOrganization: $item['owner']['type'] === 'Organization', + ); + } catch (\Exception $e) { + print_r($e); + var_dump($item); + } } /** From 5a4365aa311cf61389f35094b56739fa0b915556 Mon Sep 17 00:00:00 2001 From: amiceli Date: Sun, 11 Jan 2026 21:17:19 +0100 Subject: [PATCH 15/15] test: mock requests for Frozen command --- app/Models/Api/GithubRepositoryApi.php | 45 +++++++++---------- .../Unit/Commands/FroozeRepositoriesTest.php | 6 +++ 2 files changed, 26 insertions(+), 25 deletions(-) diff --git a/app/Models/Api/GithubRepositoryApi.php b/app/Models/Api/GithubRepositoryApi.php index 05e1960..41a2f38 100644 --- a/app/Models/Api/GithubRepositoryApi.php +++ b/app/Models/Api/GithubRepositoryApi.php @@ -34,31 +34,26 @@ public static function get() { } private function parseRepository(array $item): GithubRepository { - try { - return new GithubRepository( - id: $item['id'], - stars: $item['stargazers_count'], - name: $item['name'], - fullName: $item['full_name'], - description: $item['description'], - url: $item['html_url'], - createdAt: new DateTime($item['created_at']), - updatedAt: new DateTime($item['updated_at']), - language: $item['language'], - topics: $item['topics'], - watchers: $item['watchers'], - forks: $item['forks'], - owner: new GithubRepositoryOwner( - login: $item['owner']['login'], - id: $item['owner']['id'], - avatarUrl: $item['owner']['avatar_url'], - ), - ownerIsOrganization: $item['owner']['type'] === 'Organization', - ); - } catch (\Exception $e) { - print_r($e); - var_dump($item); - } + return new GithubRepository( + id: $item['id'], + stars: $item['stargazers_count'], + name: $item['name'], + fullName: $item['full_name'], + description: $item['description'], + url: $item['html_url'], + createdAt: new DateTime($item['created_at']), + updatedAt: new DateTime($item['updated_at']), + language: $item['language'], + topics: $item['topics'], + watchers: $item['watchers'], + forks: $item['forks'], + owner: new GithubRepositoryOwner( + login: $item['owner']['login'], + id: $item['owner']['id'], + avatarUrl: $item['owner']['avatar_url'], + ), + ownerIsOrganization: $item['owner']['type'] === 'Organization', + ); } /** diff --git a/tests/Unit/Commands/FroozeRepositoriesTest.php b/tests/Unit/Commands/FroozeRepositoriesTest.php index 44db81b..03e1393 100644 --- a/tests/Unit/Commands/FroozeRepositoriesTest.php +++ b/tests/Unit/Commands/FroozeRepositoriesTest.php @@ -15,6 +15,12 @@ 200, ), )); + Http::fake(array( + 'https://api.github.com/repos/*' => Http::response( + $repos[0], + 200, + ), + )); FrozenRepository::insert(array( 'created_at' => Carbon::now(),