@stats-organization/github-readme-stats-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1 -0
  3. package/build/api/gist.d.ts +19 -0
  4. package/build/api/gist.d.ts.map +1 -0
  5. package/build/api/gist.js +77 -0
  6. package/build/api/index.d.ts +37 -0
  7. package/build/api/index.d.ts.map +1 -0
  8. package/build/api/index.js +115 -0
  9. package/build/api/pin.d.ts +27 -0
  10. package/build/api/pin.d.ts.map +1 -0
  11. package/build/api/pin.js +104 -0
  12. package/build/api/top-langs.d.ts +31 -0
  13. package/build/api/top-langs.d.ts.map +1 -0
  14. package/build/api/top-langs.js +121 -0
  15. package/build/api/wakatime.d.ts +28 -0
  16. package/build/api/wakatime.d.ts.map +1 -0
  17. package/build/api/wakatime.js +85 -0
  18. package/build/calculateRank.d.ts +28 -0
  19. package/build/calculateRank.d.ts.map +1 -0
  20. package/build/calculateRank.js +63 -0
  21. package/build/cards/gist.d.ts +21 -0
  22. package/build/cards/gist.d.ts.map +1 -0
  23. package/build/cards/gist.js +124 -0
  24. package/build/cards/repo.d.ts +21 -0
  25. package/build/cards/repo.d.ts.map +1 -0
  26. package/build/cards/repo.js +264 -0
  27. package/build/cards/stats.d.ts +49 -0
  28. package/build/cards/stats.d.ts.map +1 -0
  29. package/build/cards/stats.js +527 -0
  30. package/build/cards/top-languages.d.ts +143 -0
  31. package/build/cards/top-languages.d.ts.map +1 -0
  32. package/build/cards/top-languages.js +795 -0
  33. package/build/cards/wakatime.d.ts +16 -0
  34. package/build/cards/wakatime.d.ts.map +1 -0
  35. package/build/cards/wakatime.js +387 -0
  36. package/build/common/Card.d.ts +109 -0
  37. package/build/common/Card.d.ts.map +1 -0
  38. package/build/common/Card.js +241 -0
  39. package/build/common/I18n.d.ts +26 -0
  40. package/build/common/I18n.d.ts.map +1 -0
  41. package/build/common/I18n.js +34 -0
  42. package/build/common/color.d.ts +53 -0
  43. package/build/common/color.d.ts.map +1 -0
  44. package/build/common/color.js +92 -0
  45. package/build/common/config.d.ts +3 -0
  46. package/build/common/config.d.ts.map +1 -0
  47. package/build/common/config.js +69 -0
  48. package/build/common/constants.d.ts +6 -0
  49. package/build/common/constants.d.ts.map +1 -0
  50. package/build/common/constants.js +7 -0
  51. package/build/common/error.d.ts +53 -0
  52. package/build/common/error.d.ts.map +1 -0
  53. package/build/common/error.js +72 -0
  54. package/build/common/fmt.d.ts +27 -0
  55. package/build/common/fmt.d.ts.map +1 -0
  56. package/build/common/fmt.js +66 -0
  57. package/build/common/html.d.ts +10 -0
  58. package/build/common/html.d.ts.map +1 -0
  59. package/build/common/html.js +18 -0
  60. package/build/common/http.d.ts +9 -0
  61. package/build/common/http.d.ts.map +1 -0
  62. package/build/common/http.js +18 -0
  63. package/build/common/icons.d.ts +26 -0
  64. package/build/common/icons.d.ts.map +1 -0
  65. package/build/common/icons.js +77 -0
  66. package/build/common/languageColors.json +667 -0
  67. package/build/common/log.d.ts +9 -0
  68. package/build/common/log.d.ts.map +1 -0
  69. package/build/common/log.js +8 -0
  70. package/build/common/ops.d.ts +65 -0
  71. package/build/common/ops.d.ts.map +1 -0
  72. package/build/common/ops.js +137 -0
  73. package/build/common/render.d.ts +155 -0
  74. package/build/common/render.d.ts.map +1 -0
  75. package/build/common/render.js +361 -0
  76. package/build/common/retryer.d.ts +22 -0
  77. package/build/common/retryer.d.ts.map +1 -0
  78. package/build/common/retryer.js +86 -0
  79. package/build/fetchers/gist.d.ts +26 -0
  80. package/build/fetchers/gist.d.ts.map +1 -0
  81. package/build/fetchers/gist.js +99 -0
  82. package/build/fetchers/repo.d.ts +16 -0
  83. package/build/fetchers/repo.d.ts.map +1 -0
  84. package/build/fetchers/repo.js +116 -0
  85. package/build/fetchers/stats.d.ts +22 -0
  86. package/build/fetchers/stats.d.ts.map +1 -0
  87. package/build/fetchers/stats.js +339 -0
  88. package/build/fetchers/top-languages.d.ts +20 -0
  89. package/build/fetchers/top-languages.d.ts.map +1 -0
  90. package/build/fetchers/top-languages.js +139 -0
  91. package/build/fetchers/wakatime.d.ts +11 -0
  92. package/build/fetchers/wakatime.d.ts.map +1 -0
  93. package/build/fetchers/wakatime.js +25 -0
  94. package/build/index.d.ts +20 -0
  95. package/build/index.d.ts.map +1 -0
  96. package/build/index.js +19 -0
  97. package/build/themes/index.d.ts +469 -0
  98. package/build/themes/index.d.ts.map +1 -0
  99. package/build/themes/index.js +468 -0
  100. package/build/translations.d.ts +533 -0
  101. package/build/translations.d.ts.map +1 -0
  102. package/build/translations.js +1140 -0
  103. package/package.json +94 -0
  104. package/src/api/gist.js +99 -0
  105. package/src/api/index.js +185 -0
  106. package/src/api/pin.js +146 -0
  107. package/src/api/top-langs.js +168 -0
  108. package/src/api/wakatime.js +113 -0
  109. package/src/calculateRank.js +86 -0
  110. package/src/cards/gist.js +187 -0
  111. package/src/cards/repo.js +365 -0
  112. package/src/cards/stats.js +673 -0
  113. package/src/cards/top-languages.js +1023 -0
  114. package/src/cards/types.d.ts +78 -0
  115. package/src/cards/wakatime.js +471 -0
  116. package/src/common/Card.js +275 -0
  117. package/src/common/I18n.js +42 -0
  118. package/src/common/color.js +145 -0
  119. package/src/common/config.js +78 -0
  120. package/src/common/constants.js +9 -0
  121. package/src/common/error.js +90 -0
  122. package/src/common/fmt.js +80 -0
  123. package/src/common/html.js +22 -0
  124. package/src/common/http.js +21 -0
  125. package/src/common/icons.js +81 -0
  126. package/src/common/languageColors.json +667 -0
  127. package/src/common/log.ts +12 -0
  128. package/src/common/ops.js +172 -0
  129. package/src/common/render.js +442 -0
  130. package/src/common/retryer.js +104 -0
  131. package/src/fetchers/gist.js +114 -0
  132. package/src/fetchers/repo.js +165 -0
  133. package/src/fetchers/stats.js +478 -0
  134. package/src/fetchers/top-languages.js +177 -0
  135. package/src/fetchers/types.d.ts +128 -0
  136. package/src/fetchers/wakatime.js +37 -0
  137. package/src/index.ts +25 -0
  138. package/src/themes/README.md +229 -0
  139. package/src/themes/index.ts +476 -0
  140. package/src/translations.js +1156 -0
@@ -0,0 +1,113 @@
1
+ // @ts-check
2
+
3
+ import { renderWakatimeCard } from "../cards/wakatime.js";
4
+ import {
5
+ MissingParamError,
6
+ retrieveSecondaryMessage,
7
+ } from "../common/error.js";
8
+ import { parseArray, parseBoolean } from "../common/ops.js";
9
+ import { renderError } from "../common/render.js";
10
+ import { fetchWakatimeStats } from "../fetchers/wakatime.js";
11
+ import { isLocaleAvailable } from "../translations.js";
12
+
13
+ // @ts-ignore
14
+ export default async ({
15
+ username,
16
+ title_color,
17
+ icon_color,
18
+ hide_border,
19
+ card_width,
20
+ line_height,
21
+ text_color,
22
+ bg_color,
23
+ theme,
24
+ hide_title,
25
+ hide_progress,
26
+ custom_title,
27
+ locale,
28
+ layout,
29
+ langs_count,
30
+ hide,
31
+ api_domain,
32
+ border_radius,
33
+ border_color,
34
+ display_format,
35
+ disable_animations,
36
+ }) => {
37
+ if (locale && !isLocaleAvailable(locale)) {
38
+ return {
39
+ status: "error - permanent",
40
+ content: renderError({
41
+ message: "Something went wrong",
42
+ secondaryMessage: "Language not found",
43
+ renderOptions: {
44
+ title_color,
45
+ text_color,
46
+ bg_color,
47
+ border_color,
48
+ theme,
49
+ },
50
+ }),
51
+ };
52
+ }
53
+
54
+ try {
55
+ const stats = await fetchWakatimeStats({ username, api_domain });
56
+
57
+ return {
58
+ status: "success",
59
+ content: renderWakatimeCard(stats, {
60
+ custom_title,
61
+ hide_title: parseBoolean(hide_title),
62
+ hide_border: parseBoolean(hide_border),
63
+ card_width: parseInt(card_width, 10),
64
+ hide: parseArray(hide),
65
+ line_height,
66
+ title_color,
67
+ icon_color,
68
+ text_color,
69
+ bg_color,
70
+ theme,
71
+ hide_progress,
72
+ border_radius,
73
+ border_color,
74
+ locale: locale ? locale.toLowerCase() : null,
75
+ layout,
76
+ langs_count,
77
+ display_format,
78
+ disable_animations: parseBoolean(disable_animations),
79
+ }),
80
+ };
81
+ } catch (err) {
82
+ if (err instanceof Error) {
83
+ return {
84
+ status: "error - temporary",
85
+ content: renderError({
86
+ message: err.message,
87
+ secondaryMessage: retrieveSecondaryMessage(err),
88
+ renderOptions: {
89
+ title_color,
90
+ text_color,
91
+ bg_color,
92
+ border_color,
93
+ theme,
94
+ show_repo_link: !(err instanceof MissingParamError),
95
+ },
96
+ }),
97
+ };
98
+ }
99
+ return {
100
+ status: "error - temporary",
101
+ content: renderError({
102
+ message: "An unknown error occurred",
103
+ renderOptions: {
104
+ title_color,
105
+ text_color,
106
+ bg_color,
107
+ border_color,
108
+ theme,
109
+ },
110
+ }),
111
+ };
112
+ }
113
+ };
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Calculates the exponential cdf.
3
+ *
4
+ * @param {number} x The value.
5
+ * @returns {number} The exponential cdf.
6
+ */
7
+ function exponential_cdf(x) {
8
+ return 1 - 2 ** -x;
9
+ }
10
+
11
+ /**
12
+ * Calculates the log normal cdf.
13
+ *
14
+ * @param {number} x The value.
15
+ * @returns {number} The log normal cdf.
16
+ */
17
+ function log_normal_cdf(x) {
18
+ // approximation
19
+ return x / (1 + x);
20
+ }
21
+
22
+ /**
23
+ * Calculates the users rank.
24
+ *
25
+ * @param {object} params Parameters on which the user's rank depends.
26
+ * @param {boolean} params.all_commits Whether `include_all_commits` was used.
27
+ * @param {number} params.commits Number of commits.
28
+ * @param {number} params.prs The number of pull requests.
29
+ * @param {number} params.issues The number of issues.
30
+ * @param {number} params.reviews The number of reviews.
31
+ * @param {number} params.repos Total number of repos.
32
+ * @param {number} params.stars The number of stars.
33
+ * @param {number} params.followers The number of followers.
34
+ * @returns {{ level: string, percentile: number }} The users rank.
35
+ */
36
+ function calculateRank({
37
+ all_commits,
38
+ commits,
39
+ prs,
40
+ issues,
41
+ reviews,
42
+ // eslint-disable-next-line no-unused-vars
43
+ repos, // unused
44
+ stars,
45
+ followers,
46
+ }) {
47
+ const COMMITS_MEDIAN = all_commits ? 1000 : 250,
48
+ COMMITS_WEIGHT = 2;
49
+ const PRS_MEDIAN = 50,
50
+ PRS_WEIGHT = 3;
51
+ const ISSUES_MEDIAN = 25,
52
+ ISSUES_WEIGHT = 1;
53
+ const REVIEWS_MEDIAN = 2,
54
+ REVIEWS_WEIGHT = 1;
55
+ const STARS_MEDIAN = 50,
56
+ STARS_WEIGHT = 4;
57
+ const FOLLOWERS_MEDIAN = 10,
58
+ FOLLOWERS_WEIGHT = 1;
59
+
60
+ const TOTAL_WEIGHT =
61
+ COMMITS_WEIGHT +
62
+ PRS_WEIGHT +
63
+ ISSUES_WEIGHT +
64
+ REVIEWS_WEIGHT +
65
+ STARS_WEIGHT +
66
+ FOLLOWERS_WEIGHT;
67
+
68
+ const THRESHOLDS = [1, 12.5, 25, 37.5, 50, 62.5, 75, 87.5, 100];
69
+ const LEVELS = ["S", "A+", "A", "A-", "B+", "B", "B-", "C+", "C"];
70
+
71
+ const rank =
72
+ 1 -
73
+ (COMMITS_WEIGHT * exponential_cdf(commits / COMMITS_MEDIAN) +
74
+ PRS_WEIGHT * exponential_cdf(prs / PRS_MEDIAN) +
75
+ ISSUES_WEIGHT * exponential_cdf(issues / ISSUES_MEDIAN) +
76
+ REVIEWS_WEIGHT * exponential_cdf(reviews / REVIEWS_MEDIAN) +
77
+ STARS_WEIGHT * log_normal_cdf(stars / STARS_MEDIAN) +
78
+ FOLLOWERS_WEIGHT * log_normal_cdf(followers / FOLLOWERS_MEDIAN)) /
79
+ TOTAL_WEIGHT;
80
+
81
+ const level = LEVELS[THRESHOLDS.findIndex((t) => rank * 100 <= t)];
82
+
83
+ return { level, percentile: rank * 100 };
84
+ }
85
+
86
+ export { calculateRank };
@@ -0,0 +1,187 @@
1
+ // @ts-check
2
+
3
+ import { default as Card } from "../common/Card.js";
4
+ import { getCardColors } from "../common/color.js";
5
+ import { kFormatter, wrapTextMultiline } from "../common/fmt.js";
6
+ import { encodeHTML } from "../common/html.js";
7
+ import { icons } from "../common/icons.js";
8
+ import languageColors from "../common/languageColors.json" with { type: "json" };
9
+ import { parseEmojis } from "../common/ops.js";
10
+ import {
11
+ countWrappedLines,
12
+ createLanguageNode,
13
+ flexLayout,
14
+ iconWithLabel,
15
+ measureText,
16
+ wrappedTextNode,
17
+ wrappedTextStyles,
18
+ } from "../common/render.js";
19
+
20
+ const ICON_SIZE = 16;
21
+ const CARD_DEFAULT_WIDTH = 400;
22
+ const X_OFFSET = 25;
23
+ const HEADER_MAX_LENGTH = 35;
24
+ const DESCRIPTION_BOX_WIDTH = CARD_DEFAULT_WIDTH - 2 * X_OFFSET;
25
+ const DESCRIPTION_FONT_SIZE = 13;
26
+ const DESCRIPTION_LINE_HEIGHT_PX = 16;
27
+ const DESCRIPTION_MAX_LINES = 10;
28
+
29
+ /**
30
+ * @typedef {import('./types').GistCardOptions} GistCardOptions Gist card options.
31
+ * @typedef {import('../fetchers/types').GistData} GistData Gist data.
32
+ */
33
+
34
+ /**
35
+ * Render gist card.
36
+ *
37
+ * @param {GistData} gistData Gist data.
38
+ * @param {Partial<GistCardOptions>} options Gist card options.
39
+ * @returns {string} Gist card.
40
+ */
41
+ const renderGistCard = (gistData, options = {}) => {
42
+ const { name, nameWithOwner, description, language, starsCount, forksCount } =
43
+ gistData;
44
+ const {
45
+ title_color,
46
+ icon_color,
47
+ text_color,
48
+ bg_color,
49
+ theme = "default_repocard",
50
+ border_radius,
51
+ border_color,
52
+ show_owner = false,
53
+ browser_rendering = false,
54
+ hide_border = false,
55
+ } = options;
56
+
57
+ // returns theme based colors with proper overrides and defaults
58
+ const { titleColor, textColor, iconColor, bgColor, borderColor } =
59
+ getCardColors({
60
+ title_color,
61
+ icon_color,
62
+ text_color,
63
+ bg_color,
64
+ border_color,
65
+ theme,
66
+ });
67
+
68
+ const desc = parseEmojis(description || "No description provided");
69
+
70
+ let descriptionLines, descriptionSvg;
71
+ if (browser_rendering) {
72
+ // The browser performs the actual text wrapping inside the foreignObject;
73
+ // we only estimate the line count server-side so the SVG can reserve enough
74
+ // height. The estimate uses measureText for font-aware widths instead of a
75
+ // fixed character count.
76
+ descriptionLines = countWrappedLines(
77
+ desc,
78
+ DESCRIPTION_FONT_SIZE,
79
+ DESCRIPTION_BOX_WIDTH,
80
+ DESCRIPTION_MAX_LINES,
81
+ );
82
+
83
+ descriptionSvg = wrappedTextNode({
84
+ text: desc,
85
+ x: X_OFFSET,
86
+ y: -3,
87
+ width: DESCRIPTION_BOX_WIDTH,
88
+ height: descriptionLines * DESCRIPTION_LINE_HEIGHT_PX + 10, // 10px extra for "descenders" like g, j, q, p, y
89
+ lineCount: descriptionLines,
90
+ className: "description",
91
+ testId: "description-text",
92
+ });
93
+ } else {
94
+ const linesLimit = 10;
95
+ const multiLineDescription = wrapTextMultiline(
96
+ desc,
97
+ DESCRIPTION_BOX_WIDTH,
98
+ DESCRIPTION_FONT_SIZE,
99
+ linesLimit,
100
+ );
101
+ descriptionLines = multiLineDescription.length;
102
+ descriptionSvg = multiLineDescription
103
+ .map(
104
+ (line) =>
105
+ `<tspan dy="1.2em" x="${X_OFFSET}">${encodeHTML(line)}</tspan>`,
106
+ )
107
+ .join("");
108
+ descriptionSvg = `<text class="description" x="${X_OFFSET}" y="-5">
109
+ ${descriptionSvg}
110
+ </text>`;
111
+ }
112
+
113
+ const lineHeight = descriptionLines > 3 ? 12 : 10;
114
+ const height =
115
+ (descriptionLines > 1 ? 120 : 110) + descriptionLines * lineHeight;
116
+
117
+ const totalStars = kFormatter(starsCount);
118
+ const totalForks = kFormatter(forksCount);
119
+ const svgStars = iconWithLabel(
120
+ icons.star,
121
+ totalStars,
122
+ "starsCount",
123
+ ICON_SIZE,
124
+ );
125
+ const svgForks = iconWithLabel(
126
+ icons.fork,
127
+ totalForks,
128
+ "forksCount",
129
+ ICON_SIZE,
130
+ );
131
+
132
+ const languageName = language || "Unspecified";
133
+ // @ts-ignore
134
+ const languageColor = languageColors[languageName] || "#858585";
135
+
136
+ const svgLanguage = createLanguageNode(languageName, languageColor);
137
+
138
+ const starAndForkCount = flexLayout({
139
+ items: [svgLanguage, svgStars, svgForks],
140
+ sizes: [
141
+ measureText(languageName, 12),
142
+ ICON_SIZE + measureText(`${totalStars}`, 12),
143
+ ICON_SIZE + measureText(`${totalForks}`, 12),
144
+ ],
145
+ gap: 25,
146
+ }).join("");
147
+
148
+ const header = show_owner ? nameWithOwner : name;
149
+
150
+ const card = new Card({
151
+ defaultTitle:
152
+ header.length > HEADER_MAX_LENGTH
153
+ ? `${header.slice(0, HEADER_MAX_LENGTH)}...`
154
+ : header,
155
+ titlePrefixIcon: icons.gist,
156
+ width: CARD_DEFAULT_WIDTH,
157
+ height,
158
+ border_radius,
159
+ colors: {
160
+ titleColor,
161
+ textColor,
162
+ iconColor,
163
+ bgColor,
164
+ borderColor,
165
+ },
166
+ });
167
+
168
+ card.setCSS(`
169
+ .description {
170
+ font: 400 ${DESCRIPTION_FONT_SIZE}px 'Segoe UI', Ubuntu, Sans-Serif;fill: ${textColor};
171
+ ${browser_rendering ? wrappedTextStyles(textColor) : ""}
172
+ }
173
+ .gray { font: 400 12px 'Segoe UI', Ubuntu, Sans-Serif; fill: ${textColor} }
174
+ .icon { fill: ${iconColor} }
175
+ `);
176
+ card.setHideBorder(hide_border);
177
+
178
+ return card.render(`
179
+ ${descriptionSvg}
180
+
181
+ <g transform="translate(30, ${height - 75})">
182
+ ${starAndForkCount}
183
+ </g>
184
+ `);
185
+ };
186
+
187
+ export { renderGistCard };