Skip to content

Commit 4489504

Browse files
author
release bot
committed
📦 2.3.0
1 parent 027f895 commit 4489504

File tree

4 files changed

+117
-24
lines changed

4 files changed

+117
-24
lines changed

‎action.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ author: "platane"
44

55
runs:
66
using: docker
7-
image: docker://platane/snk@sha256:bd0f7538482216785abbee29da431738f5ea9aff9fc3a4b8df37708a808f0968
7+
image: docker://platane/snk@sha256:2115ffeb538e355aa155630e6e32b6d77ea2345fa8584645c41ace7f5ad667fc
88

99
inputs:
1010
github_user_name:

‎package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "snk",
33
"description": "Generates a snake game from a github user contributions grid",
4-
"version": "2.2.1",
4+
"version": "2.3.0",
55
"private": true,
66
"repository": "github:platane/snk",
77
"devDependencies": {

‎svg-only/dist/197.index.js

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1425,6 +1425,20 @@ const isDomainOrSubdomain = function isDomainOrSubdomain(destination, original)
14251425
return orig === dest || orig[orig.length - dest.length - 1] === '.' && orig.endsWith(dest);
14261426
};
14271427

1428+
/**
1429+
* isSameProtocol reports whether the two provided URLs use the same protocol.
1430+
*
1431+
* Both domains must already be in canonical form.
1432+
* @param {string|URL} original
1433+
* @param {string|URL} destination
1434+
*/
1435+
const isSameProtocol = function isSameProtocol(destination, original) {
1436+
const orig = new URL$1(original).protocol;
1437+
const dest = new URL$1(destination).protocol;
1438+
1439+
return orig === dest;
1440+
};
1441+
14281442
/**
14291443
* Fetch function
14301444
*
@@ -1456,7 +1470,7 @@ function fetch(url, opts) {
14561470
let error = new AbortError('The user aborted a request.');
14571471
reject(error);
14581472
if (request.body && request.body instanceof Stream.Readable) {
1459-
request.body.destroy(error);
1473+
destroyStream(request.body, error);
14601474
}
14611475
if (!response || !response.body) return;
14621476
response.body.emit('error', error);
@@ -1497,9 +1511,43 @@ function fetch(url, opts) {
14971511

14981512
req.on('error', function (err) {
14991513
reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err));
1514+
1515+
if (response && response.body) {
1516+
destroyStream(response.body, err);
1517+
}
1518+
15001519
finalize();
15011520
});
15021521

1522+
fixResponseChunkedTransferBadEnding(req, function (err) {
1523+
if (signal && signal.aborted) {
1524+
return;
1525+
}
1526+
1527+
if (response && response.body) {
1528+
destroyStream(response.body, err);
1529+
}
1530+
});
1531+
1532+
/* c8 ignore next 18 */
1533+
if (parseInt(process.version.substring(1)) < 14) {
1534+
// Before Node.js 14, pipeline() does not fully support async iterators and does not always
1535+
// properly handle when the socket close/end events are out of order.
1536+
req.on('socket', function (s) {
1537+
s.addListener('close', function (hadError) {
1538+
// if a data listener is still present we didn't end cleanly
1539+
const hasDataListener = s.listenerCount('data') > 0;
1540+
1541+
// if end happened before close but the socket didn't emit an error, do it now
1542+
if (response && hasDataListener && !hadError && !(signal && signal.aborted)) {
1543+
const err = new Error('Premature close');
1544+
err.code = 'ERR_STREAM_PREMATURE_CLOSE';
1545+
response.body.emit('error', err);
1546+
}
1547+
});
1548+
});
1549+
}
1550+
15031551
req.on('response', function (res) {
15041552
clearTimeout(reqTimeout);
15051553

@@ -1571,7 +1619,7 @@ function fetch(url, opts) {
15711619
size: request.size
15721620
};
15731621

1574-
if (!isDomainOrSubdomain(request.url, locationURL)) {
1622+
if (!isDomainOrSubdomain(request.url, locationURL) || !isSameProtocol(request.url, locationURL)) {
15751623
for (const name of ['authorization', 'www-authenticate', 'cookie', 'cookie2']) {
15761624
requestOpts.headers.delete(name);
15771625
}
@@ -1664,6 +1712,13 @@ function fetch(url, opts) {
16641712
response = new Response(body, response_options);
16651713
resolve(response);
16661714
});
1715+
raw.on('end', function () {
1716+
// some old IIS servers return zero-length OK deflate responses, so 'data' is never emitted.
1717+
if (!response) {
1718+
response = new Response(body, response_options);
1719+
resolve(response);
1720+
}
1721+
});
16671722
return;
16681723
}
16691724

@@ -1683,6 +1738,44 @@ function fetch(url, opts) {
16831738
writeToStream(req, request);
16841739
});
16851740
}
1741+
function fixResponseChunkedTransferBadEnding(request, errorCallback) {
1742+
let socket;
1743+
1744+
request.on('socket', function (s) {
1745+
socket = s;
1746+
});
1747+
1748+
request.on('response', function (response) {
1749+
const headers = response.headers;
1750+
1751+
if (headers['transfer-encoding'] === 'chunked' && !headers['content-length']) {
1752+
response.once('close', function (hadError) {
1753+
// tests for socket presence, as in some situations the
1754+
// the 'socket' event is not triggered for the request
1755+
// (happens in deno), avoids `TypeError`
1756+
// if a data listener is still present we didn't end cleanly
1757+
const hasDataListener = socket && socket.listenerCount('data') > 0;
1758+
1759+
if (hasDataListener && !hadError) {
1760+
const err = new Error('Premature close');
1761+
err.code = 'ERR_STREAM_PREMATURE_CLOSE';
1762+
errorCallback(err);
1763+
}
1764+
});
1765+
}
1766+
});
1767+
}
1768+
1769+
function destroyStream(stream, err) {
1770+
if (stream.destroy) {
1771+
stream.destroy(err);
1772+
} else {
1773+
// node < 8
1774+
stream.emit('error', err);
1775+
stream.end();
1776+
}
1777+
}
1778+
16861779
/**
16871780
* Redirect code matching
16881781
*

‎svg-only/dist/317.index.js

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -78,27 +78,27 @@ const getGithubUserContribution = async (userName, options = {}) => {
7878
return parseUserPage(resText);
7979
};
8080
const parseUserPage = (content) => {
81-
// take roughly the svg block
81+
// take roughly the table block
8282
const block = content
83-
.split(`class="js-calendar-graph-svg"`)[1]
84-
.split("</svg>")[0];
85-
let x = 0;
86-
let lastYAttribute = 0;
87-
const rects = Array.from(block.matchAll(/<rect[^>]*>[^<]*<\/rect>/g)).map(([m]) => {
88-
const date = m.match(/data-date="([^"]+)"/)[1];
89-
const level = +m.match(/data-level="([^"]+)"/)[1];
90-
const yAttribute = +m.match(/y="([^"]+)"/)[1];
91-
const literalCount = m.match(/(No|\d+) contributions? on/)[1];
92-
const count = literalCount === "No" ? 0 : +literalCount;
93-
if (lastYAttribute > yAttribute)
94-
x++;
95-
lastYAttribute = yAttribute;
96-
return { date, count, level, x, yAttribute };
97-
});
98-
const yAttributes = Array.from(new Set(rects.map((c) => c.yAttribute)).keys()).sort();
99-
const cells = rects.map(({ yAttribute, ...c }) => ({
100-
y: yAttributes.indexOf(yAttribute),
101-
...c,
83+
.split(`aria-describedby="contribution-graph-description"`)[1]
84+
.split("<tbody>")[1]
85+
.split("</tbody>")[0];
86+
const cells = block.split("</tr>").flatMap((inside, y) => inside.split("</td>").flatMap((m) => {
87+
const date = m.match(/data-date="([^"]+)"/)?.[1];
88+
const literalLevel = m.match(/data-level="([^"]+)"/)?.[1];
89+
const literalX = m.match(/data-ix="([^"]+)"/)?.[1];
90+
const literalCount = m.match(/(No|\d+) contributions? on/)?.[1];
91+
if (date && literalLevel && literalX && literalCount)
92+
return [
93+
{
94+
x: +literalX,
95+
y,
96+
date,
97+
count: +literalCount,
98+
level: +literalLevel,
99+
},
100+
];
101+
return [];
102102
}));
103103
return cells;
104104
};

0 commit comments

Comments
 (0)