From e1f71541be464a402f91e9fcaa734d6a6612da76 Mon Sep 17 00:00:00 2001 From: Amio Date: Sat, 12 Aug 2023 09:18:48 +0800 Subject: [PATCH] feat: use html parsing for github stars badge --- libs/create-badgen-handler-next.ts | 10 ++- libs/query-html.ts | 8 +++ package-lock.json | 111 +++++++++++++++++++++++++++++ package.json | 1 + pages/api/github.ts | 19 +++-- 5 files changed, 142 insertions(+), 7 deletions(-) create mode 100644 libs/query-html.ts diff --git a/libs/create-badgen-handler-next.ts b/libs/create-badgen-handler-next.ts index 9b18c4d0..f2387bac 100644 --- a/libs/create-badgen-handler-next.ts +++ b/libs/create-badgen-handler-next.ts @@ -116,9 +116,13 @@ function simpleDecode (str: string): string { } export class BadgenError { - public status: string // error badge param: status (required) - public color: string // error badge param: color - public code: number // status code for response + /** The "status" param for error badge (required) */ + public status: string + /** The "color" param for error badge, red by default */ + public color: string + /** The status code for error badge response, 500 by default */ + public code: number + /** The error message */ public message: string constructor ({ status, color = 'grey', code = 500, message = '' }) { diff --git a/libs/query-html.ts b/libs/query-html.ts new file mode 100644 index 00000000..82650671 --- /dev/null +++ b/libs/query-html.ts @@ -0,0 +1,8 @@ +import got from 'got' +import { parse } from 'node-html-parser' + +export default async function queryHTML(url: string, cssSelector: string) { + const htmlString = await got(url).text() + const root = parse(htmlString) + return root.querySelector(cssSelector) +} diff --git a/package-lock.json b/package-lock.json index 0ebae150..f58dbe35 100644 --- a/package-lock.json +++ b/package-lock.json @@ -24,6 +24,7 @@ "measurement-protocol": "^0.1.1", "millify": "^6.1.0", "my-way": "^2.0.0", + "node-html-parser": "^6.1.5", "original-url": "^1.2.3", "semver": "^7.3.5", "serve-handler": "^6.1.3", @@ -1648,6 +1649,11 @@ "node": ">=0.6" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, "node_modules/bplist-parser": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/bplist-parser/-/bplist-parser-0.2.0.tgz", @@ -1899,6 +1905,83 @@ "node": ">= 8" } }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-select/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/css-select/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/css-select/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, "node_modules/csstype": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz", @@ -3377,6 +3460,14 @@ "resolved": "https://registry.npmjs.org/haxe-rpc-client/-/haxe-rpc-client-1.0.0.tgz", "integrity": "sha512-AffqK18IUrPB1NL9GK6N1NvOFoeTTJxwXSscO/DydzeOyJ2qbZC17mZNTLlWHEEmfnbRAEjvHT48OiXGO1GAAA==" }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "bin": { + "he": "bin/he" + } + }, "node_modules/hexoid": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/hexoid/-/hexoid-1.0.0.tgz", @@ -4277,6 +4368,15 @@ } } }, + "node_modules/node-html-parser": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/node-html-parser/-/node-html-parser-6.1.5.tgz", + "integrity": "sha512-fAaM511feX++/Chnhe475a0NHD8M7AxDInsqQpz6x63GRF7xYNdS8Vo5dKsIVPgsOvG7eioRRTZQnWBrhDHBSg==", + "dependencies": { + "css-select": "^5.1.0", + "he": "1.2.0" + } + }, "node_modules/normalize-url": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-8.0.0.tgz", @@ -4313,6 +4413,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", diff --git a/package.json b/package.json index 5f358ca9..4b75c684 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "measurement-protocol": "^0.1.1", "millify": "^6.1.0", "my-way": "^2.0.0", + "node-html-parser": "^6.1.5", "original-url": "^1.2.3", "semver": "^7.3.5", "serve-handler": "^6.1.3", diff --git a/pages/api/github.ts b/pages/api/github.ts index 11ef456e..340a8604 100644 --- a/pages/api/github.ts +++ b/pages/api/github.ts @@ -4,6 +4,7 @@ import got from 'libs/got' import { restGithub, queryGithub } from 'libs/github' import { createBadgenHandler, PathArgs, BadgenError } from 'libs/create-badgen-handler-next' import { coverageColor, millify, version } from 'libs/utils' +import queryHTML from 'libs/query-html' type DependentsType = 'REPOSITORY' | 'PACKAGE' @@ -297,7 +298,7 @@ const makeRepoQuery = (topic, owner, repo, restArgs) => { case 'last-commit': queryBody = ` ${ - restArgs.ref ? + restArgs.ref ? `branch: ref(qualifiedName: "${restArgs.ref}")` : 'defaultBranchRef' } { @@ -364,10 +365,20 @@ async function repoStats ({topic, owner, repo, ...restArgs}: PathArgs) { color: 'blue' } case 'stars': - const { stargazers_count } = await meta({ owner, repo }) + // const { stargazers_count } = await meta({ owner, repo }) + const starsElem = await queryHTML(`https://github.com/${owner}/${repo}`, '#repo-stars-counter-star') + const stargazers_count = starsElem?.innerText + + if (stargazers_count === undefined) { + throw new BadgenError({ + status: 'not found', + message: `Could not find stargazers_count for ${owner}/${repo}` + }) + } + return { subject: topic, - status: millify(stargazers_count), + status: stargazers_count, color: 'blue' } case 'license': @@ -451,7 +462,7 @@ async function repoStats ({topic, owner, repo, ...restArgs}: PathArgs) { return { subject: topic, status: millify( - result.branch ? + result.branch ? result.branch.target.history.totalCount : result.defaultBranchRef.target.history.totalCount ),