@stats-forge/github-stats-forge-core 0.0.2 → 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.
- package/README.md +0 -10
- package/build/api/api-result.d.ts +6 -7
- package/build/api/api-result.d.ts.map +1 -1
- package/build/api/api-result.js +4 -5
- package/build/api/contributed-to.d.ts +23 -0
- package/build/api/contributed-to.d.ts.map +1 -0
- package/build/api/contributed-to.js +43 -0
- package/build/api/gist.d.ts +8 -22
- package/build/api/gist.d.ts.map +1 -1
- package/build/api/gist.js +14 -36
- package/build/api/handler.d.ts +16 -0
- package/build/api/handler.d.ts.map +1 -0
- package/build/api/handler.js +29 -0
- package/build/api/index.d.ts +13 -12
- package/build/api/index.d.ts.map +1 -1
- package/build/api/index.js +1 -0
- package/build/api/params.d.ts +21 -12
- package/build/api/params.d.ts.map +1 -1
- package/build/api/params.js +41 -19
- package/build/api/pin.d.ts +11 -31
- package/build/api/pin.d.ts.map +1 -1
- package/build/api/pin.js +35 -63
- package/build/api/stats.d.ts +15 -16
- package/build/api/stats.d.ts.map +1 -1
- package/build/api/stats.js +60 -99
- package/build/api/top-langs.d.ts +13 -18
- package/build/api/top-langs.d.ts.map +1 -1
- package/build/api/top-langs.js +35 -72
- package/build/api/wakatime.d.ts +11 -17
- package/build/api/wakatime.d.ts.map +1 -1
- package/build/api/wakatime.js +27 -64
- package/build/calculateRank.d.ts +0 -9
- package/build/calculateRank.d.ts.map +1 -1
- package/build/calculateRank.js +12 -17
- package/build/cards/contributed-to.d.ts +19 -0
- package/build/cards/contributed-to.d.ts.map +1 -0
- package/build/cards/contributed-to.js +242 -0
- package/build/cards/gist.d.ts +3 -4
- package/build/cards/gist.d.ts.map +1 -1
- package/build/cards/gist.js +38 -43
- package/build/cards/options.d.ts +1 -1
- package/build/cards/repo.d.ts +14 -5
- package/build/cards/repo.d.ts.map +1 -1
- package/build/cards/repo.js +93 -103
- package/build/cards/stats.d.ts +18 -11
- package/build/cards/stats.d.ts.map +1 -1
- package/build/cards/stats.js +191 -222
- package/build/cards/top-languages.d.ts +18 -33
- package/build/cards/top-languages.d.ts.map +1 -1
- package/build/cards/top-languages.js +196 -387
- package/build/cards/wakatime.d.ts +17 -8
- package/build/cards/wakatime.d.ts.map +1 -1
- package/build/cards/wakatime.js +133 -187
- package/build/common/Card.d.ts +20 -59
- package/build/common/Card.d.ts.map +1 -1
- package/build/common/Card.js +131 -198
- package/build/common/I18n.d.ts +1 -7
- package/build/common/I18n.d.ts.map +1 -1
- package/build/common/I18n.js +7 -8
- package/build/common/brand.d.ts +76 -0
- package/build/common/brand.d.ts.map +1 -0
- package/build/common/brand.js +73 -0
- package/build/common/color.d.ts +4 -17
- package/build/common/color.d.ts.map +1 -1
- package/build/common/color.js +67 -49
- package/build/common/config.d.ts +4 -14
- package/build/common/config.d.ts.map +1 -1
- package/build/common/config.js +3 -16
- package/build/common/constants.d.ts +6 -2
- package/build/common/constants.d.ts.map +1 -1
- package/build/common/constants.js +5 -1
- package/build/common/date.d.ts +50 -5
- package/build/common/date.d.ts.map +1 -1
- package/build/common/date.js +104 -4
- package/build/common/emojiMap.d.ts +8 -0
- package/build/common/emojiMap.d.ts.map +1 -0
- package/build/common/emojiMap.js +10 -0
- package/build/common/emojiMap.json +1915 -0
- package/build/common/error.d.ts +1 -10
- package/build/common/error.d.ts.map +1 -1
- package/build/common/error.js +1 -10
- package/build/common/fmt.d.ts +3 -15
- package/build/common/fmt.d.ts.map +1 -1
- package/build/common/fmt.js +7 -35
- package/build/common/http.d.ts +2 -7
- package/build/common/http.d.ts.map +1 -1
- package/build/common/http.js +8 -17
- package/build/common/icons.d.ts +20 -20
- package/build/common/icons.d.ts.map +1 -1
- package/build/common/icons.js +108 -67
- package/build/common/languageColors.d.ts +0 -1
- package/build/common/languageColors.d.ts.map +1 -1
- package/build/common/languageColors.js +1 -4
- package/build/common/languageColors.json +18 -2
- package/build/common/ops.d.ts +11 -17
- package/build/common/ops.d.ts.map +1 -1
- package/build/common/ops.js +22 -39
- package/build/common/render.d.ts +34 -82
- package/build/common/render.d.ts.map +1 -1
- package/build/common/render.js +225 -259
- package/build/common/retryer.d.ts +2 -7
- package/build/common/retryer.d.ts.map +1 -1
- package/build/common/retryer.js +4 -11
- package/build/fetchers/contributed-to.d.ts +62 -0
- package/build/fetchers/contributed-to.d.ts.map +1 -0
- package/build/fetchers/contributed-to.js +184 -0
- package/build/fetchers/gist.d.ts +2 -5
- package/build/fetchers/gist.d.ts.map +1 -1
- package/build/fetchers/gist.js +1 -5
- package/build/fetchers/graphql-error.d.ts +13 -0
- package/build/fetchers/graphql-error.d.ts.map +1 -0
- package/build/fetchers/graphql-error.js +29 -0
- package/build/fetchers/index.d.ts +13 -12
- package/build/fetchers/index.d.ts.map +1 -1
- package/build/fetchers/index.js +1 -0
- package/build/fetchers/repo.d.ts +2 -11
- package/build/fetchers/repo.d.ts.map +1 -1
- package/build/fetchers/repo.js +20 -33
- package/build/fetchers/stats.d.ts +16 -40
- package/build/fetchers/stats.d.ts.map +1 -1
- package/build/fetchers/stats.js +89 -271
- package/build/fetchers/top-languages.d.ts +2 -9
- package/build/fetchers/top-languages.d.ts.map +1 -1
- package/build/fetchers/top-languages.js +16 -47
- package/build/fetchers/types.d.ts +25 -1
- package/build/fetchers/types.d.ts.map +1 -1
- package/build/fetchers/wakatime.d.ts +2 -6
- package/build/fetchers/wakatime.d.ts.map +1 -1
- package/build/fetchers/wakatime.js +1 -5
- package/build/graphql/contributionsCollection.d.ts +9 -0
- package/build/graphql/contributionsCollection.d.ts.map +1 -0
- package/build/graphql/contributionsCollection.js +12 -0
- package/build/graphql/contributionsDocument.d.ts +6 -6
- package/build/graphql/contributionsDocument.d.ts.map +1 -1
- package/build/graphql/contributionsDocument.js +8 -16
- package/build/graphql/generated/contributed-to.d.ts +22 -0
- package/build/graphql/generated/contributed-to.d.ts.map +1 -0
- package/build/graphql/generated/contributed-to.js +11 -0
- package/build/graphql/generated/gist.d.ts +1 -1
- package/build/graphql/generated/repo.d.ts +1 -1
- package/build/graphql/generated/stats.d.ts +16 -4
- package/build/graphql/generated/stats.d.ts.map +1 -1
- package/build/graphql/generated/stats.js +2 -2
- package/build/graphql/generated/top-languages.d.ts +2 -2
- package/build/graphql/graphqlDocument.d.ts +1 -2
- package/build/graphql/graphqlDocument.d.ts.map +1 -1
- package/build/graphql/graphqlDocument.js +0 -1
- package/build/graphql/reposContributedToDocument.d.ts +4 -5
- package/build/graphql/reposContributedToDocument.d.ts.map +1 -1
- package/build/graphql/reposContributedToDocument.js +11 -7
- package/build/markup/css.d.ts +35 -0
- package/build/markup/css.d.ts.map +1 -0
- package/build/markup/css.js +64 -0
- package/build/markup/element.d.ts +41 -0
- package/build/markup/element.d.ts.map +1 -0
- package/build/markup/element.js +127 -0
- package/build/markup/html.d.ts +13 -0
- package/build/markup/html.d.ts.map +1 -0
- package/build/markup/html.js +27 -0
- package/build/markup/index.d.ts +9 -0
- package/build/markup/index.d.ts.map +1 -0
- package/build/markup/index.js +6 -0
- package/build/markup/serialize.d.ts +16 -0
- package/build/markup/serialize.d.ts.map +1 -0
- package/build/markup/serialize.js +17 -0
- package/build/themes/index.d.ts +332 -333
- package/build/themes/index.d.ts.map +1 -1
- package/build/themes/index.js +1 -1
- package/build/translations.d.ts +66 -7
- package/build/translations.d.ts.map +1 -1
- package/build/translations.js +686 -629
- package/package.json +17 -26
- package/src/api/api-result.ts +10 -9
- package/src/api/contributed-to.ts +84 -0
- package/src/api/gist.ts +22 -46
- package/src/api/handler.ts +42 -0
- package/src/api/index.ts +13 -12
- package/src/api/params.ts +74 -29
- package/src/api/pin.ts +38 -65
- package/src/api/stats.ts +81 -118
- package/src/api/top-langs.ts +38 -80
- package/src/api/wakatime.ts +35 -73
- package/src/calculateRank.ts +12 -23
- package/src/cards/contributed-to.ts +373 -0
- package/src/cards/gist.ts +55 -49
- package/src/cards/options.ts +1 -1
- package/src/cards/repo.ts +134 -120
- package/src/cards/stats.ts +262 -252
- package/src/cards/top-languages.ts +315 -422
- package/src/cards/wakatime.ts +207 -225
- package/src/common/Card.ts +207 -214
- package/src/common/I18n.ts +7 -8
- package/src/common/brand.ts +109 -0
- package/src/common/color.ts +80 -57
- package/src/common/config.ts +5 -18
- package/src/common/constants.ts +8 -2
- package/src/common/date.ts +135 -5
- package/src/common/emojiMap.json +1915 -0
- package/src/common/emojiMap.ts +13 -0
- package/src/common/error.ts +2 -11
- package/src/common/fmt.ts +7 -44
- package/src/common/http.ts +9 -15
- package/src/common/icons.ts +122 -42
- package/src/common/languageColors.json +18 -2
- package/src/common/languageColors.ts +1 -4
- package/src/common/ops.ts +31 -48
- package/src/common/render.ts +334 -284
- package/src/common/retryer.ts +8 -15
- package/src/fetchers/contributed-to.ts +271 -0
- package/src/fetchers/gist.ts +8 -12
- package/src/fetchers/graphql-error.ts +36 -0
- package/src/fetchers/index.ts +15 -12
- package/src/fetchers/repo.ts +27 -40
- package/src/fetchers/stats.ts +157 -366
- package/src/fetchers/top-languages.ts +27 -55
- package/src/fetchers/types.ts +27 -1
- package/src/fetchers/wakatime.ts +5 -9
- package/src/graphql/contributionsCollection.ts +18 -0
- package/src/graphql/contributionsDocument.ts +14 -19
- package/src/graphql/generated/contributed-to.ts +25 -0
- package/src/graphql/generated/gist.ts +1 -1
- package/src/graphql/generated/repo.ts +1 -1
- package/src/graphql/generated/stats.ts +21 -8
- package/src/graphql/generated/top-languages.ts +2 -2
- package/src/graphql/graphqlDocument.ts +1 -2
- package/src/graphql/queries/contributed-to.graphql +8 -0
- package/src/graphql/queries/stats.graphql +14 -2
- package/src/graphql/reposContributedToDocument.ts +16 -15
- package/src/markup/css.ts +118 -0
- package/src/markup/element.ts +246 -0
- package/src/markup/html.ts +34 -0
- package/src/markup/index.ts +9 -0
- package/src/markup/serialize.ts +27 -0
- package/src/themes/index.ts +1 -1
- package/src/translations.ts +699 -629
- package/build/cards/index.d.ts +0 -11
- package/build/cards/index.d.ts.map +0 -1
- package/build/cards/index.js +0 -7
- package/build/common/html.d.ts +0 -8
- package/build/common/html.d.ts.map +0 -1
- package/build/common/html.js +0 -14
- package/build/index.d.ts +0 -15
- package/build/index.d.ts.map +0 -1
- package/build/index.js +0 -10
- package/src/_emoji-name-map.d.ts +0 -10
- package/src/_github-username-regex.d.ts +0 -4
- package/src/cards/index.ts +0 -21
- package/src/common/html.ts +0 -17
- package/src/index.ts +0 -18
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stats-forge/github-stats-forge-core",
|
|
3
|
-
"version": "0.0
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Dynamically generate stats for your GitHub readme",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"card-generator",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
],
|
|
44
44
|
"repository": {
|
|
45
45
|
"type": "git",
|
|
46
|
-
"url": "https://github.com/stats-forge/github-stats-forge.git",
|
|
46
|
+
"url": "git+https://github.com/stats-forge/github-stats-forge.git",
|
|
47
47
|
"directory": "packages/core"
|
|
48
48
|
},
|
|
49
49
|
"files": [
|
|
@@ -52,20 +52,11 @@
|
|
|
52
52
|
"README.md"
|
|
53
53
|
],
|
|
54
54
|
"type": "module",
|
|
55
|
-
"main": "./build/index.js",
|
|
56
55
|
"exports": {
|
|
57
|
-
".": {
|
|
58
|
-
"@stats/source": "./src/index.ts",
|
|
59
|
-
"default": "./build/index.js"
|
|
60
|
-
},
|
|
61
56
|
"./api": {
|
|
62
57
|
"@stats/source": "./src/api/index.ts",
|
|
63
58
|
"default": "./build/api/index.js"
|
|
64
59
|
},
|
|
65
|
-
"./cards": {
|
|
66
|
-
"@stats/source": "./src/cards/index.ts",
|
|
67
|
-
"default": "./build/cards/index.js"
|
|
68
|
-
},
|
|
69
60
|
"./fetchers": {
|
|
70
61
|
"@stats/source": "./src/fetchers/index.ts",
|
|
71
62
|
"default": "./build/fetchers/index.js"
|
|
@@ -79,36 +70,36 @@
|
|
|
79
70
|
"access": "public"
|
|
80
71
|
},
|
|
81
72
|
"dependencies": {
|
|
82
|
-
"
|
|
83
|
-
"github-username-regex": "^1.0.0",
|
|
84
|
-
"zod": "^4.4.3"
|
|
73
|
+
"zod": "^4.5.4"
|
|
85
74
|
},
|
|
86
75
|
"devDependencies": {
|
|
87
76
|
"@graphql-codegen/core": "6.2.0",
|
|
88
77
|
"@graphql-codegen/typescript": "6.1.0",
|
|
89
|
-
"@graphql-codegen/typescript-operations": "6.1.
|
|
78
|
+
"@graphql-codegen/typescript-operations": "6.1.6",
|
|
90
79
|
"@octokit/graphql-schema": "15.26.1",
|
|
91
80
|
"@testing-library/dom": "10.4.1",
|
|
92
|
-
"@testing-library/jest-dom": "
|
|
81
|
+
"@testing-library/jest-dom": "7.0.1",
|
|
82
|
+
"@types/node": "24.13.3",
|
|
93
83
|
"@uppercod/css-to-object": "1.1.1",
|
|
94
|
-
"graphql": "16.
|
|
95
|
-
"js-yaml": "5.
|
|
96
|
-
"jsdom": "
|
|
97
|
-
"vitest": "4.1.
|
|
84
|
+
"graphql": "16.14.2",
|
|
85
|
+
"js-yaml": "5.4.1",
|
|
86
|
+
"jsdom": "30.0.1",
|
|
87
|
+
"vitest": "4.1.11"
|
|
98
88
|
},
|
|
99
89
|
"engines": {
|
|
100
|
-
"node": ">=
|
|
90
|
+
"node": "^24 || >=26"
|
|
101
91
|
},
|
|
102
92
|
"scripts": {
|
|
103
93
|
"build": "tsc -p tsconfig.build.json",
|
|
94
|
+
"lint:publish": "attw --pack . --profile node16 --ignore-rules cjs-resolves-to-esm && publint --strict",
|
|
104
95
|
"test": "vitest",
|
|
105
96
|
"test:update:snapshot": "vitest -u",
|
|
106
97
|
"test:e2e": "vitest --config vitest.config.e2e.ts",
|
|
107
98
|
"bench": "vitest bench --run --config vitest.config.bench.ts",
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
"generate-
|
|
99
|
+
"typecheck": "tsc -p tsconfig.typecheck.json && tsc -p tsconfig.scripts.json",
|
|
100
|
+
"generate-graphql-types": "node scripts/generate-graphql-types.ts",
|
|
101
|
+
"check-graphql-types": "node scripts/generate-graphql-types.ts --check",
|
|
102
|
+
"generate-language-colors": "node scripts/generate-language-colors.ts",
|
|
103
|
+
"generate-emoji-map": "node scripts/generate-emoji-map.ts"
|
|
113
104
|
}
|
|
114
105
|
}
|
package/src/api/api-result.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ColorParams } from '../common/color.
|
|
2
|
-
import type { ErrorCode } from '../common/error.
|
|
3
|
-
import { CardError } from '../common/error.
|
|
4
|
-
import { renderError } from '../common/render.
|
|
1
|
+
import type { ColorParams } from '../common/color.ts';
|
|
2
|
+
import type { ErrorCode } from '../common/error.ts';
|
|
3
|
+
import { CardError } from '../common/error.ts';
|
|
4
|
+
import { renderError } from '../common/render.ts';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Why a card could not be rendered, in a form a host can act on.
|
|
@@ -37,14 +37,15 @@ export type ApiResult =
|
|
|
37
37
|
|
|
38
38
|
/**
|
|
39
39
|
* Turns anything a handler threw into the one shape it answers with.
|
|
40
|
+
* Anything that is not a `CardError` is treated as upstream's.
|
|
40
41
|
*
|
|
41
|
-
* @param err The failure.
|
|
42
|
-
* Anything that is not a `CardError` is treated as upstream's.
|
|
43
|
-
* @param renderOptions Colors the error card is drawn with;
|
|
44
|
-
* omitted when it was a color that was rejected.
|
|
45
42
|
* @returns The rendered error.
|
|
46
43
|
*/
|
|
47
|
-
export const errorResult = (
|
|
44
|
+
export const errorResult = (
|
|
45
|
+
err: unknown,
|
|
46
|
+
/** omitted when it was a color that was rejected, which cannot draw its own error card */
|
|
47
|
+
renderOptions?: ColorParams,
|
|
48
|
+
): ApiResult => {
|
|
48
49
|
const error = CardError.from(err);
|
|
49
50
|
|
|
50
51
|
return {
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import * as z from 'zod/mini';
|
|
2
|
+
|
|
3
|
+
import { renderContributedToCard } from '../cards/contributed-to.ts';
|
|
4
|
+
import { fetchContributedTo } from '../fetchers/contributed-to.ts';
|
|
5
|
+
|
|
6
|
+
import { cardHandler } from './handler.ts';
|
|
7
|
+
import {
|
|
8
|
+
booleanParam,
|
|
9
|
+
fromParam,
|
|
10
|
+
localeParam,
|
|
11
|
+
looseIntParam,
|
|
12
|
+
numberParam,
|
|
13
|
+
ORDERED_RANGE,
|
|
14
|
+
rawParam,
|
|
15
|
+
safeListParam,
|
|
16
|
+
toParam,
|
|
17
|
+
usernameParam,
|
|
18
|
+
} from './params.ts';
|
|
19
|
+
|
|
20
|
+
/** What the contributed-to endpoint accepts, on top of the shared color params. */
|
|
21
|
+
const contributedToQuery = z
|
|
22
|
+
.object({
|
|
23
|
+
username: usernameParam,
|
|
24
|
+
locale: localeParam,
|
|
25
|
+
repos_count: looseIntParam,
|
|
26
|
+
include_own_repos: booleanParam,
|
|
27
|
+
exclude_repo: safeListParam,
|
|
28
|
+
from: fromParam,
|
|
29
|
+
to: toParam,
|
|
30
|
+
hide_years: booleanParam,
|
|
31
|
+
hide_title: booleanParam,
|
|
32
|
+
hide_border: booleanParam,
|
|
33
|
+
card_width: looseIntParam,
|
|
34
|
+
custom_title: rawParam,
|
|
35
|
+
border_radius: numberParam,
|
|
36
|
+
disable_animations: booleanParam,
|
|
37
|
+
})
|
|
38
|
+
.check(ORDERED_RANGE);
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Render the contributed-to card for a set of query params.
|
|
42
|
+
*
|
|
43
|
+
* @returns The rendered card, or a rendered error.
|
|
44
|
+
*/
|
|
45
|
+
export const contributedTo = cardHandler(
|
|
46
|
+
contributedToQuery,
|
|
47
|
+
async (
|
|
48
|
+
{
|
|
49
|
+
username,
|
|
50
|
+
locale,
|
|
51
|
+
repos_count,
|
|
52
|
+
include_own_repos,
|
|
53
|
+
exclude_repo,
|
|
54
|
+
from,
|
|
55
|
+
to,
|
|
56
|
+
hide_years,
|
|
57
|
+
hide_title,
|
|
58
|
+
hide_border,
|
|
59
|
+
card_width,
|
|
60
|
+
custom_title,
|
|
61
|
+
border_radius,
|
|
62
|
+
disable_animations,
|
|
63
|
+
},
|
|
64
|
+
colors,
|
|
65
|
+
config,
|
|
66
|
+
) => {
|
|
67
|
+
const data = await fetchContributedTo(
|
|
68
|
+
{ username, include_own_repos, repos_count, exclude_repo, from, to },
|
|
69
|
+
config,
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
return renderContributedToCard(data, {
|
|
73
|
+
...colors,
|
|
74
|
+
locale,
|
|
75
|
+
hide_years,
|
|
76
|
+
hide_title,
|
|
77
|
+
hide_border,
|
|
78
|
+
card_width,
|
|
79
|
+
custom_title,
|
|
80
|
+
border_radius,
|
|
81
|
+
disable_animations,
|
|
82
|
+
});
|
|
83
|
+
},
|
|
84
|
+
);
|
package/src/api/gist.ts
CHANGED
|
@@ -1,66 +1,42 @@
|
|
|
1
1
|
import * as z from 'zod/mini';
|
|
2
2
|
|
|
3
|
-
import { renderGistCard } from '../cards/gist.
|
|
4
|
-
import
|
|
5
|
-
import { fetchGist } from '../fetchers/gist.js';
|
|
3
|
+
import { renderGistCard } from '../cards/gist.ts';
|
|
4
|
+
import { fetchGist } from '../fetchers/gist.ts';
|
|
6
5
|
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import type { ApiQuery } from './params.js';
|
|
10
|
-
import { booleanParam, numberParam, parseColorParams, parseParams, safeParam } from './params.js';
|
|
6
|
+
import { cardHandler } from './handler.ts';
|
|
7
|
+
import { booleanParam, localeParam, numberParam, safeParam } from './params.ts';
|
|
11
8
|
|
|
12
9
|
/** What the gist endpoint accepts, on top of the shared color params. */
|
|
13
10
|
const gistQuery = z.object({
|
|
14
11
|
id: safeParam,
|
|
12
|
+
locale: localeParam,
|
|
15
13
|
border_radius: numberParam,
|
|
16
14
|
show_owner: booleanParam,
|
|
17
15
|
browser_rendering: booleanParam,
|
|
18
16
|
hide_border: booleanParam,
|
|
19
17
|
});
|
|
20
18
|
|
|
21
|
-
/** The query this endpoint accepts, checked against the schema above. */
|
|
22
|
-
type GistApiQuery = ApiQuery<typeof gistQuery>;
|
|
23
|
-
|
|
24
19
|
/**
|
|
25
20
|
* Render the gist card for a set of query params.
|
|
26
21
|
*
|
|
27
|
-
* @param query Raw query params, plus any of the shared color params.
|
|
28
|
-
* @param query.id GitHub gist ID.
|
|
29
|
-
* @param query.border_radius Card border radius.
|
|
30
|
-
* @param query.show_owner Whether to show the gist owner.
|
|
31
|
-
* @param query.browser_rendering Whether the browser wraps the description text.
|
|
32
|
-
* @param query.hide_border Whether to hide the card border.
|
|
33
|
-
* @param config Deployment config supplying the PAT pool.
|
|
34
22
|
* @returns The rendered card, or a rendered error.
|
|
35
23
|
*/
|
|
36
|
-
export const gist =
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
try {
|
|
46
|
-
const { id, border_radius, show_owner, browser_rendering, hide_border } = parseParams(
|
|
47
|
-
gistQuery,
|
|
48
|
-
query,
|
|
49
|
-
);
|
|
50
|
-
|
|
24
|
+
export const gist = cardHandler(
|
|
25
|
+
gistQuery,
|
|
26
|
+
async (
|
|
27
|
+
{ id, locale, border_radius, show_owner, browser_rendering, hide_border },
|
|
28
|
+
colors,
|
|
29
|
+
config,
|
|
30
|
+
) => {
|
|
51
31
|
const gistData = await fetchGist({ id }, config);
|
|
52
32
|
|
|
53
|
-
return {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
} catch (err) {
|
|
64
|
-
return errorResult(err, colors);
|
|
65
|
-
}
|
|
66
|
-
};
|
|
33
|
+
return renderGistCard(gistData, {
|
|
34
|
+
...colors,
|
|
35
|
+
locale,
|
|
36
|
+
border_radius,
|
|
37
|
+
show_owner,
|
|
38
|
+
browser_rendering,
|
|
39
|
+
hide_border,
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
);
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type * as z from 'zod/mini';
|
|
2
|
+
|
|
3
|
+
import type { ColorParams } from '../common/color.ts';
|
|
4
|
+
import type { CardConfig } from '../common/config.ts';
|
|
5
|
+
|
|
6
|
+
import type { ApiResult } from './api-result.ts';
|
|
7
|
+
import { errorResult } from './api-result.ts';
|
|
8
|
+
import type { ApiQuery } from './params.ts';
|
|
9
|
+
import { parseColorParams, parseParams } from './params.ts';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* An endpoint: the schema it accepts, and what it draws from the parsed params.
|
|
13
|
+
*
|
|
14
|
+
* Colors parse first and on their own, because a rejected color cannot be used to draw its own error card.
|
|
15
|
+
* Parsing throws, fetching throws, and one `catch` turns whatever was thrown into the answer.
|
|
16
|
+
*
|
|
17
|
+
* @returns The handler, taking the query the schema describes.
|
|
18
|
+
*/
|
|
19
|
+
const cardHandler =
|
|
20
|
+
<TSchema extends z.ZodMiniType>(
|
|
21
|
+
schema: TSchema,
|
|
22
|
+
render: (params: z.output<TSchema>, colors: ColorParams, config: CardConfig) => Promise<string>,
|
|
23
|
+
) =>
|
|
24
|
+
async (query: ApiQuery<TSchema>, config: CardConfig): Promise<ApiResult> => {
|
|
25
|
+
let colors: ColorParams;
|
|
26
|
+
try {
|
|
27
|
+
colors = parseColorParams(query);
|
|
28
|
+
} catch (error) {
|
|
29
|
+
return errorResult(error);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
try {
|
|
33
|
+
return {
|
|
34
|
+
status: 'success',
|
|
35
|
+
content: await render(parseParams(schema, query), colors, config),
|
|
36
|
+
};
|
|
37
|
+
} catch (error) {
|
|
38
|
+
return errorResult(error, colors);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export { cardHandler };
|
package/src/api/index.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export {
|
|
5
|
-
export {
|
|
1
|
+
export { contributedTo } from './contributed-to.ts';
|
|
2
|
+
export { gist } from './gist.ts';
|
|
3
|
+
export { pin } from './pin.ts';
|
|
4
|
+
export { stats } from './stats.ts';
|
|
5
|
+
export { topLangs } from './top-langs.ts';
|
|
6
|
+
export { wakatime } from './wakatime.ts';
|
|
6
7
|
|
|
7
|
-
export type { ApiError, ApiResult } from './api-result.
|
|
8
|
+
export type { ApiError, ApiResult } from './api-result.ts';
|
|
8
9
|
|
|
9
10
|
// every handler but `wakatime` needs the PAT pool, and that one still needs the transport.
|
|
10
|
-
export { CardConfig } from '../common/config.
|
|
11
|
-
export type { CardConfigInit, PersonalAccessToken } from '../common/config.
|
|
12
|
-
export type { FetchLike } from '../common/http.
|
|
13
|
-
export type { ErrorCode } from '../common/error.
|
|
11
|
+
export { CardConfig } from '../common/config.ts';
|
|
12
|
+
export type { CardConfigInit, PersonalAccessToken } from '../common/config.ts';
|
|
13
|
+
export type { FetchLike } from '../common/http.ts';
|
|
14
|
+
export type { ErrorCode } from '../common/error.ts';
|
|
14
15
|
|
|
15
|
-
export { themes } from '../themes/index.
|
|
16
|
-
export type { ThemeName } from '../themes/index.
|
|
16
|
+
export { themes } from '../themes/index.ts';
|
|
17
|
+
export type { ThemeName } from '../themes/index.ts';
|
package/src/api/params.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import * as z from 'zod/mini';
|
|
2
2
|
|
|
3
|
-
import type { ColorParams } from '../common/color.
|
|
4
|
-
import { COLOR_PARAM_KEYS, THEME_PARAM_KEYS, isValidColorInput } from '../common/color.
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
3
|
+
import type { ColorParams } from '../common/color.ts';
|
|
4
|
+
import { COLOR_PARAM_KEYS, THEME_PARAM_KEYS, isValidColorInput } from '../common/color.ts';
|
|
5
|
+
import { GITHUB_USERNAME_PATTERN } from '../common/constants.ts';
|
|
6
|
+
import { getWidestRange, parseRangeDate } from '../common/date.ts';
|
|
7
|
+
import { CardError } from '../common/error.ts';
|
|
8
|
+
import { parseArray, parseBoolean } from '../common/ops.ts';
|
|
9
|
+
import { isLocaleAvailable } from '../translations.ts';
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* @file The api layer is the trust boundary:
|
|
@@ -19,11 +21,20 @@ import { isLocaleAvailable } from '../translations.js';
|
|
|
19
21
|
/** Every param arrives as a string, or not at all. */
|
|
20
22
|
const rawParam = z.optional(z.string());
|
|
21
23
|
|
|
22
|
-
/** Characters a
|
|
24
|
+
/** Characters a repository, owner or gist id may contain. */
|
|
23
25
|
const SAFE_PATTERN = /^[-\w/.,]+$/;
|
|
24
26
|
|
|
25
27
|
/** What a check rejected a param for. */
|
|
26
|
-
type Rejection =
|
|
28
|
+
type Rejection =
|
|
29
|
+
| 'number'
|
|
30
|
+
| 'date'
|
|
31
|
+
| 'out_of_range'
|
|
32
|
+
| 'inverted_range'
|
|
33
|
+
| 'unsafe'
|
|
34
|
+
| 'username'
|
|
35
|
+
| 'locale'
|
|
36
|
+
| 'enum'
|
|
37
|
+
| 'color';
|
|
27
38
|
|
|
28
39
|
/**
|
|
29
40
|
* Every rejection the api can put on an error card, in one place.
|
|
@@ -31,8 +42,11 @@ type Rejection = 'number' | 'year' | 'unsafe' | 'locale' | 'enum' | 'color';
|
|
|
31
42
|
*/
|
|
32
43
|
const REJECTION_MESSAGES: Record<Rejection, (param: string) => string> = {
|
|
33
44
|
number: (param) => `Invalid number input for parameter "${param}"`,
|
|
34
|
-
|
|
45
|
+
date: (param) => `Invalid date input for parameter "${param}"`,
|
|
46
|
+
out_of_range: (param) => `Out of range date for parameter "${param}"`,
|
|
47
|
+
inverted_range: () => 'Range "from" is after "to"',
|
|
35
48
|
unsafe: (param) => `Parameter "${param}" contains unsafe characters`,
|
|
49
|
+
username: (param) => `Invalid username input for parameter "${param}"`,
|
|
36
50
|
locale: () => 'Locale not found',
|
|
37
51
|
enum: (param) => `Incorrect ${param} input`,
|
|
38
52
|
color: (param) => `Invalid color input for parameter "${param}"`,
|
|
@@ -42,11 +56,9 @@ const REJECTION_MESSAGES: Record<Rejection, (param: string) => string> = {
|
|
|
42
56
|
* A check that words its own rejection:
|
|
43
57
|
* the message is built from the kind and the param's path rather than passed in.
|
|
44
58
|
*
|
|
45
|
-
* @param kind What the check rejects the param for.
|
|
46
|
-
* @param passes Whether a value is acceptable.
|
|
47
59
|
* @returns The check, ready for `.check()`.
|
|
48
60
|
*/
|
|
49
|
-
const rejects = (kind: Rejection, passes: (value: string) => boolean) =>
|
|
61
|
+
const rejects = (kind: Rejection, passes: (value: string) => boolean): z.core.$ZodCheck<unknown> =>
|
|
50
62
|
z.refine((value: unknown) => typeof value !== 'string' || passes(value), {
|
|
51
63
|
error: (issue) => REJECTION_MESSAGES[kind](String(issue.path?.[0] ?? '')),
|
|
52
64
|
});
|
|
@@ -72,8 +84,8 @@ const listParam = z.pipe(rawParam, z.transform(parseArray));
|
|
|
72
84
|
* Yields the parsed number, or `undefined` when the param is absent.
|
|
73
85
|
*/
|
|
74
86
|
const numberParam: z.ZodMiniType<number | undefined, string | undefined> = z.pipe(
|
|
75
|
-
rawParam.check(rejects('number', (value) => Number.isFinite(parseFloat(value)))),
|
|
76
|
-
z.transform((value) => (value === undefined ? undefined : parseFloat(value))),
|
|
87
|
+
rawParam.check(rejects('number', (value) => Number.isFinite(Number.parseFloat(value)))),
|
|
88
|
+
z.transform((value) => (value === undefined ? undefined : Number.parseFloat(value))),
|
|
77
89
|
);
|
|
78
90
|
|
|
79
91
|
/**
|
|
@@ -82,17 +94,42 @@ const numberParam: z.ZodMiniType<number | undefined, string | undefined> = z.pip
|
|
|
82
94
|
*/
|
|
83
95
|
const looseIntParam = z.pipe(
|
|
84
96
|
rawParam,
|
|
85
|
-
z.transform((value) => (value === undefined ? undefined : parseInt(value, 10))),
|
|
97
|
+
z.transform((value) => (value === undefined ? undefined : Number.parseInt(value, 10))),
|
|
86
98
|
);
|
|
87
99
|
|
|
88
100
|
/**
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
101
|
+
* One end of the range a card counts within, written as `2024`, `2024-03` or `2024-03-15`.
|
|
102
|
+
*
|
|
103
|
+
* @returns Schema yielding the instant, or `undefined` when the param is absent.
|
|
92
104
|
*/
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
z.
|
|
105
|
+
const rangeParam = (end: 'from' | 'to'): z.ZodMiniType<Date | undefined, string | undefined> => {
|
|
106
|
+
const parse = (value: string): Date | undefined => parseRangeDate(value, end);
|
|
107
|
+
return z.pipe(
|
|
108
|
+
rawParam.check(rejects('date', (value) => parse(value) !== undefined)).check(
|
|
109
|
+
rejects('out_of_range', (value) => {
|
|
110
|
+
const date = parse(value);
|
|
111
|
+
const widest = getWidestRange();
|
|
112
|
+
// a bad shape is already reported by the check above
|
|
113
|
+
return date === undefined || (date >= widest.from && date <= widest.to);
|
|
114
|
+
}),
|
|
115
|
+
),
|
|
116
|
+
z.transform((value) => (value === undefined ? undefined : parse(value))),
|
|
117
|
+
);
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
/** The start of a card's range; see {@link rangeParam}. */
|
|
121
|
+
const fromParam = rangeParam('from');
|
|
122
|
+
|
|
123
|
+
/** The end of a card's range; see {@link rangeParam}. */
|
|
124
|
+
const toParam = rangeParam('to');
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The pair-level rule the two ends cannot see on their own.
|
|
128
|
+
* Every endpoint taking a range applies it, so an order no card could draw is rejected once.
|
|
129
|
+
*/
|
|
130
|
+
const ORDERED_RANGE = z.refine<{ from?: Date | undefined; to?: Date | undefined }>(
|
|
131
|
+
({ from, to }) => from === undefined || to === undefined || from <= to,
|
|
132
|
+
{ error: REJECTION_MESSAGES.inverted_range('from'), path: ['from'] },
|
|
96
133
|
);
|
|
97
134
|
|
|
98
135
|
/**
|
|
@@ -103,6 +140,14 @@ const safeParam: z.ZodMiniType<string | undefined, string | undefined> = rawPara
|
|
|
103
140
|
rejects('unsafe', (value) => !value || SAFE_PATTERN.test(value)),
|
|
104
141
|
);
|
|
105
142
|
|
|
143
|
+
/**
|
|
144
|
+
* A GitHub login, stricter than `safeParam`: no leading, trailing or doubled hyphen.
|
|
145
|
+
* Rejected here so a malformed one is a permanent error rather than the NOT_FOUND GitHub answers.
|
|
146
|
+
*/
|
|
147
|
+
const usernameParam: z.ZodMiniType<string | undefined, string | undefined> = rawParam.check(
|
|
148
|
+
rejects('username', (value) => !value || GITHUB_USERNAME_PATTERN.test(value)),
|
|
149
|
+
);
|
|
150
|
+
|
|
106
151
|
/**
|
|
107
152
|
* A comma-separated list of ids, checked before it is split.
|
|
108
153
|
* The safe pattern allows the commas, so one check covers the whole list.
|
|
@@ -126,7 +171,6 @@ const localeParam = z.pipe(
|
|
|
126
171
|
/**
|
|
127
172
|
* A param the card only renders as one of a fixed set of values.
|
|
128
173
|
*
|
|
129
|
-
* @param values The accepted values, as the card that renders them declares them.
|
|
130
174
|
* @returns Schema yielding one of `values`, or `undefined` when absent.
|
|
131
175
|
*/
|
|
132
176
|
const enumParam = <const T extends ReadonlyArray<string>>(
|
|
@@ -163,11 +207,10 @@ type ApiQuery<TSchema extends z.ZodMiniType> = Partial<z.input<TSchema>> & Color
|
|
|
163
207
|
* Every rejection is the query's fault, so they share one code
|
|
164
208
|
* and differ only in the message the check already worded.
|
|
165
209
|
*
|
|
166
|
-
* @param error What the schema rejected.
|
|
167
210
|
* @returns The failure, ready to render.
|
|
168
211
|
*/
|
|
169
212
|
const toCardError = (error: z.core.$ZodError): CardError => {
|
|
170
|
-
const issue = error.issues
|
|
213
|
+
const [issue] = error.issues;
|
|
171
214
|
return CardError.invalidParam(String(issue?.path[0] ?? ''), issue?.message ?? 'Invalid input');
|
|
172
215
|
};
|
|
173
216
|
|
|
@@ -177,10 +220,9 @@ const toCardError = (error: z.core.$ZodError): CardError => {
|
|
|
177
220
|
* Only the first rejection is reported:
|
|
178
221
|
* the error card has room for one line.
|
|
179
222
|
*
|
|
180
|
-
* @param schema The endpoint's schema.
|
|
181
|
-
* @param query Raw query params.
|
|
182
|
-
* @returns The parsed params.
|
|
183
223
|
* @throws {CardError} When the schema rejects a param.
|
|
224
|
+
*
|
|
225
|
+
* @returns The parsed params.
|
|
184
226
|
*/
|
|
185
227
|
const parseParams = <TSchema extends z.ZodMiniType>(
|
|
186
228
|
schema: TSchema,
|
|
@@ -197,9 +239,9 @@ const parseParams = <TSchema extends z.ZodMiniType>(
|
|
|
197
239
|
* The color params, validated.
|
|
198
240
|
* Split from the endpoint's own schema because a rejected color cannot then be used to render its own error card.
|
|
199
241
|
*
|
|
200
|
-
* @param query Raw query params.
|
|
201
|
-
* @returns The color params.
|
|
202
242
|
* @throws {CardError} When a param does not hold a color or a gradient.
|
|
243
|
+
*
|
|
244
|
+
* @returns The color params.
|
|
203
245
|
*/
|
|
204
246
|
const parseColorParams = (query: unknown): ColorParams => parseParams(colorParamsSchema, query);
|
|
205
247
|
|
|
@@ -208,7 +250,9 @@ export type { ApiQuery };
|
|
|
208
250
|
export {
|
|
209
251
|
booleanParam,
|
|
210
252
|
enumParam,
|
|
253
|
+
fromParam,
|
|
211
254
|
listParam,
|
|
255
|
+
ORDERED_RANGE,
|
|
212
256
|
localeParam,
|
|
213
257
|
looseIntParam,
|
|
214
258
|
numberParam,
|
|
@@ -217,5 +261,6 @@ export {
|
|
|
217
261
|
rawParam,
|
|
218
262
|
safeListParam,
|
|
219
263
|
safeParam,
|
|
220
|
-
|
|
264
|
+
toParam,
|
|
265
|
+
usernameParam,
|
|
221
266
|
};
|