🚀 refactor github contribution
This commit is contained in:
@@ -1,4 +1,75 @@
|
|||||||
import { JSDOM } from "jsdom";
|
import fetch from "node-fetch";
|
||||||
|
import * as parser from "fast-xml-parser";
|
||||||
|
|
||||||
|
// const traverse = (
|
||||||
|
// o: any,
|
||||||
|
// callback: (elements: { name: string; "#text": string; attrs: any }[]) => void,
|
||||||
|
// path: { name: string; "#text": string; attrs: any }[] = []
|
||||||
|
// ) => {
|
||||||
|
// if (o && typeof o === "object")
|
||||||
|
// Object.entries(o)
|
||||||
|
// .filter(([o]) => o !== "attr" && o !== "#text")
|
||||||
|
// .forEach(([name, v]) => {
|
||||||
|
// const el = { name, attrs: v.attrs, "#text": v["#text"] };
|
||||||
|
// const p = [el, ...path];
|
||||||
|
// callback(p);
|
||||||
|
|
||||||
|
// traverse(v, callback, p);
|
||||||
|
// });
|
||||||
|
// };
|
||||||
|
|
||||||
|
const findNode = (o: any, condition: (x: any) => boolean): any => {
|
||||||
|
if (o && typeof o === "object") {
|
||||||
|
if (condition(o)) return o;
|
||||||
|
|
||||||
|
for (const c of Object.values(o)) {
|
||||||
|
const res = findNode(c, condition);
|
||||||
|
if (res) return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const parseUserPage = (content: string) => {
|
||||||
|
const o = parser.parse(content, {
|
||||||
|
attrNodeName: "attr",
|
||||||
|
attributeNamePrefix: "",
|
||||||
|
ignoreAttributes: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
//
|
||||||
|
// parse colorScheme
|
||||||
|
const legend = findNode(
|
||||||
|
o,
|
||||||
|
(x) => x.attr && x.attr.class && x.attr.class.trim() === "legend"
|
||||||
|
);
|
||||||
|
const colorScheme = legend.li.map(
|
||||||
|
(x: any) => x.attr.style.match(/background\-color: +(#\w+)/)![1]!
|
||||||
|
);
|
||||||
|
|
||||||
|
//
|
||||||
|
// parse cells
|
||||||
|
const svg = findNode(
|
||||||
|
o,
|
||||||
|
(x) =>
|
||||||
|
x.attr && x.attr.class && x.attr.class.trim() === "js-calendar-graph-svg"
|
||||||
|
);
|
||||||
|
|
||||||
|
const cells = svg.g.g
|
||||||
|
.map((g: any, x: number) =>
|
||||||
|
g.rect.map(({ attr }: any, y: number) => {
|
||||||
|
const color = attr.fill;
|
||||||
|
const count = +attr["data-count"];
|
||||||
|
const date = attr["data-date"];
|
||||||
|
|
||||||
|
const k = colorScheme.indexOf(color);
|
||||||
|
|
||||||
|
return { x, y, color, count, date, k };
|
||||||
|
})
|
||||||
|
)
|
||||||
|
.flat();
|
||||||
|
|
||||||
|
return { cells, colorScheme };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* get the contribution grid from a github user page
|
* get the contribution grid from a github user page
|
||||||
@@ -6,31 +77,10 @@ import { JSDOM } from "jsdom";
|
|||||||
* @param userName
|
* @param userName
|
||||||
*/
|
*/
|
||||||
export const getGithubUserContribution = async (userName: string) => {
|
export const getGithubUserContribution = async (userName: string) => {
|
||||||
const dom = await JSDOM.fromURL(`https://github.com/${userName}`);
|
const res = await fetch(`https://github.com/${userName}`);
|
||||||
|
const resText = await res.text();
|
||||||
|
|
||||||
const colorScheme = Array.from(
|
return parseUserPage(resText);
|
||||||
dom.window.document.querySelectorAll(".legend > li")
|
|
||||||
).map(
|
|
||||||
(element) =>
|
|
||||||
element.getAttribute("style")!.match(/background\-color: +(#\w+)/)![1]!
|
|
||||||
);
|
|
||||||
|
|
||||||
const cells = Array.from(
|
|
||||||
dom.window.document.querySelectorAll(".js-calendar-graph-svg > g > g")
|
|
||||||
)
|
|
||||||
.map((column, x) =>
|
|
||||||
Array.from(column.querySelectorAll("rect")).map((element, y) => {
|
|
||||||
const count = +element.getAttribute("data-count")!;
|
|
||||||
const date = element.getAttribute("data-date")!;
|
|
||||||
const color = element.getAttribute("fill")!;
|
|
||||||
const k = colorScheme.indexOf(color);
|
|
||||||
|
|
||||||
return { x, y, count, date, color, k };
|
|
||||||
})
|
|
||||||
)
|
|
||||||
.flat();
|
|
||||||
|
|
||||||
return { colorScheme, cells };
|
|
||||||
};
|
};
|
||||||
|
|
||||||
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;
|
type ThenArg<T> = T extends PromiseLike<infer U> ? U : T;
|
||||||
|
|||||||
@@ -2,9 +2,11 @@
|
|||||||
"name": "@snk/github-user-contribution",
|
"name": "@snk/github-user-contribution",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jsdom": "16.4.0"
|
"node-fetch": "2.6.1",
|
||||||
|
"fast-xml-parser": "3.17.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/node-fetch": "2.5.7",
|
||||||
"@types/jsdom": "16.2.4"
|
"@types/jsdom": "16.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
yarn.lock
31
yarn.lock
@@ -629,6 +629,14 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
|
||||||
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
|
||||||
|
|
||||||
|
"@types/node-fetch@2.5.7":
|
||||||
|
version "2.5.7"
|
||||||
|
resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.5.7.tgz#20a2afffa882ab04d44ca786449a276f9f6bbf3c"
|
||||||
|
integrity sha512-o2WVNf5UhWRkxlf6eq+jMZDu7kjgpgJfl4xVNlvryc95O/6F2ld8ztKX+qu+Rjyet93WAWm5LjeX9H5FGkODvw==
|
||||||
|
dependencies:
|
||||||
|
"@types/node" "*"
|
||||||
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node@*":
|
"@types/node@*":
|
||||||
version "14.0.23"
|
version "14.0.23"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.23.tgz#676fa0883450ed9da0bb24156213636290892806"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.23.tgz#676fa0883450ed9da0bb24156213636290892806"
|
||||||
@@ -1737,7 +1745,7 @@ color-name@~1.1.4:
|
|||||||
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
|
||||||
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
|
||||||
|
|
||||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6:
|
||||||
version "1.0.8"
|
version "1.0.8"
|
||||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||||
@@ -2678,6 +2686,11 @@ fast-levenshtein@~2.0.6:
|
|||||||
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
|
||||||
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
|
||||||
|
|
||||||
|
fast-xml-parser@3.17.4:
|
||||||
|
version "3.17.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/fast-xml-parser/-/fast-xml-parser-3.17.4.tgz#d668495fb3e4bbcf7970f3c24ac0019d82e76477"
|
||||||
|
integrity sha512-qudnQuyYBgnvzf5Lj/yxMcf4L9NcVWihXJg7CiU1L+oUCq8MUnFEfH2/nXR/W5uq+yvUN1h7z6s7vs2v1WkL1A==
|
||||||
|
|
||||||
faye-websocket@^0.10.0:
|
faye-websocket@^0.10.0:
|
||||||
version "0.10.0"
|
version "0.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
|
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
|
||||||
@@ -2796,6 +2809,15 @@ forever-agent@~0.6.1:
|
|||||||
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
|
||||||
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
|
||||||
|
|
||||||
|
form-data@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-3.0.0.tgz#31b7e39c85f1355b7139ee0c647cf0de7f83c682"
|
||||||
|
integrity sha512-CKMFDglpbMi6PyN+brwB9Q/GOw0eAnsrEZDgcsH5Krhz5Od/haKHAX0NmQfha2zPPz0JpWzA7GJHGSnvCRLWsg==
|
||||||
|
dependencies:
|
||||||
|
asynckit "^0.4.0"
|
||||||
|
combined-stream "^1.0.8"
|
||||||
|
mime-types "^2.1.12"
|
||||||
|
|
||||||
form-data@~2.3.2:
|
form-data@~2.3.2:
|
||||||
version "2.3.3"
|
version "2.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||||
@@ -4118,7 +4140,7 @@ jsbn@~0.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
|
||||||
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
|
||||||
|
|
||||||
jsdom@16.4.0, jsdom@^16.4.0:
|
jsdom@^16.4.0:
|
||||||
version "16.4.0"
|
version "16.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
|
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.4.0.tgz#36005bde2d136f73eee1a830c6d45e55408edddb"
|
||||||
integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
|
integrity sha512-lYMm3wYdgPhrl7pDcRmvzPhhrGVBeVhPIqeHjzeiHN3DFmD1RBpbExbi8vU7BJdH8VAZYovR8DMt0PNNDM7k8w==
|
||||||
@@ -4652,6 +4674,11 @@ no-case@^3.0.3:
|
|||||||
lower-case "^2.0.1"
|
lower-case "^2.0.1"
|
||||||
tslib "^1.10.0"
|
tslib "^1.10.0"
|
||||||
|
|
||||||
|
node-fetch@2.6.1:
|
||||||
|
version "2.6.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052"
|
||||||
|
integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==
|
||||||
|
|
||||||
node-forge@^0.10.0:
|
node-forge@^0.10.0:
|
||||||
version "0.10.0"
|
version "0.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
|
resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.10.0.tgz#32dea2afb3e9926f02ee5ce8794902691a676bf3"
|
||||||
|
|||||||
Reference in New Issue
Block a user