📦 2.3.0
This commit is contained in:
@@ -4,7 +4,7 @@ author: "platane"
|
|||||||
|
|
||||||
runs:
|
runs:
|
||||||
using: docker
|
using: docker
|
||||||
image: docker://platane/snk@sha256:bd0f7538482216785abbee29da431738f5ea9aff9fc3a4b8df37708a808f0968
|
image: docker://platane/snk@sha256:2115ffeb538e355aa155630e6e32b6d77ea2345fa8584645c41ace7f5ad667fc
|
||||||
|
|
||||||
inputs:
|
inputs:
|
||||||
github_user_name:
|
github_user_name:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "snk",
|
"name": "snk",
|
||||||
"description": "Generates a snake game from a github user contributions grid",
|
"description": "Generates a snake game from a github user contributions grid",
|
||||||
"version": "2.2.1",
|
"version": "2.3.0",
|
||||||
"private": true,
|
"private": true,
|
||||||
"repository": "github:platane/snk",
|
"repository": "github:platane/snk",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
97
svg-only/dist/197.index.js
vendored
97
svg-only/dist/197.index.js
vendored
@@ -1425,6 +1425,20 @@ const isDomainOrSubdomain = function isDomainOrSubdomain(destination, original)
|
|||||||
return orig === dest || orig[orig.length - dest.length - 1] === '.' && orig.endsWith(dest);
|
return orig === dest || orig[orig.length - dest.length - 1] === '.' && orig.endsWith(dest);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* isSameProtocol reports whether the two provided URLs use the same protocol.
|
||||||
|
*
|
||||||
|
* Both domains must already be in canonical form.
|
||||||
|
* @param {string|URL} original
|
||||||
|
* @param {string|URL} destination
|
||||||
|
*/
|
||||||
|
const isSameProtocol = function isSameProtocol(destination, original) {
|
||||||
|
const orig = new URL$1(original).protocol;
|
||||||
|
const dest = new URL$1(destination).protocol;
|
||||||
|
|
||||||
|
return orig === dest;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch function
|
* Fetch function
|
||||||
*
|
*
|
||||||
@@ -1456,7 +1470,7 @@ function fetch(url, opts) {
|
|||||||
let error = new AbortError('The user aborted a request.');
|
let error = new AbortError('The user aborted a request.');
|
||||||
reject(error);
|
reject(error);
|
||||||
if (request.body && request.body instanceof Stream.Readable) {
|
if (request.body && request.body instanceof Stream.Readable) {
|
||||||
request.body.destroy(error);
|
destroyStream(request.body, error);
|
||||||
}
|
}
|
||||||
if (!response || !response.body) return;
|
if (!response || !response.body) return;
|
||||||
response.body.emit('error', error);
|
response.body.emit('error', error);
|
||||||
@@ -1497,9 +1511,43 @@ function fetch(url, opts) {
|
|||||||
|
|
||||||
req.on('error', function (err) {
|
req.on('error', function (err) {
|
||||||
reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err));
|
reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err));
|
||||||
|
|
||||||
|
if (response && response.body) {
|
||||||
|
destroyStream(response.body, err);
|
||||||
|
}
|
||||||
|
|
||||||
finalize();
|
finalize();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
fixResponseChunkedTransferBadEnding(req, function (err) {
|
||||||
|
if (signal && signal.aborted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (response && response.body) {
|
||||||
|
destroyStream(response.body, err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/* c8 ignore next 18 */
|
||||||
|
if (parseInt(process.version.substring(1)) < 14) {
|
||||||
|
// Before Node.js 14, pipeline() does not fully support async iterators and does not always
|
||||||
|
// properly handle when the socket close/end events are out of order.
|
||||||
|
req.on('socket', function (s) {
|
||||||
|
s.addListener('close', function (hadError) {
|
||||||
|
// if a data listener is still present we didn't end cleanly
|
||||||
|
const hasDataListener = s.listenerCount('data') > 0;
|
||||||
|
|
||||||
|
// if end happened before close but the socket didn't emit an error, do it now
|
||||||
|
if (response && hasDataListener && !hadError && !(signal && signal.aborted)) {
|
||||||
|
const err = new Error('Premature close');
|
||||||
|
err.code = 'ERR_STREAM_PREMATURE_CLOSE';
|
||||||
|
response.body.emit('error', err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
req.on('response', function (res) {
|
req.on('response', function (res) {
|
||||||
clearTimeout(reqTimeout);
|
clearTimeout(reqTimeout);
|
||||||
|
|
||||||
@@ -1571,7 +1619,7 @@ function fetch(url, opts) {
|
|||||||
size: request.size
|
size: request.size
|
||||||
};
|
};
|
||||||
|
|
||||||
if (!isDomainOrSubdomain(request.url, locationURL)) {
|
if (!isDomainOrSubdomain(request.url, locationURL) || !isSameProtocol(request.url, locationURL)) {
|
||||||
for (const name of ['authorization', 'www-authenticate', 'cookie', 'cookie2']) {
|
for (const name of ['authorization', 'www-authenticate', 'cookie', 'cookie2']) {
|
||||||
requestOpts.headers.delete(name);
|
requestOpts.headers.delete(name);
|
||||||
}
|
}
|
||||||
@@ -1664,6 +1712,13 @@ function fetch(url, opts) {
|
|||||||
response = new Response(body, response_options);
|
response = new Response(body, response_options);
|
||||||
resolve(response);
|
resolve(response);
|
||||||
});
|
});
|
||||||
|
raw.on('end', function () {
|
||||||
|
// some old IIS servers return zero-length OK deflate responses, so 'data' is never emitted.
|
||||||
|
if (!response) {
|
||||||
|
response = new Response(body, response_options);
|
||||||
|
resolve(response);
|
||||||
|
}
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1683,6 +1738,44 @@ function fetch(url, opts) {
|
|||||||
writeToStream(req, request);
|
writeToStream(req, request);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
function fixResponseChunkedTransferBadEnding(request, errorCallback) {
|
||||||
|
let socket;
|
||||||
|
|
||||||
|
request.on('socket', function (s) {
|
||||||
|
socket = s;
|
||||||
|
});
|
||||||
|
|
||||||
|
request.on('response', function (response) {
|
||||||
|
const headers = response.headers;
|
||||||
|
|
||||||
|
if (headers['transfer-encoding'] === 'chunked' && !headers['content-length']) {
|
||||||
|
response.once('close', function (hadError) {
|
||||||
|
// tests for socket presence, as in some situations the
|
||||||
|
// the 'socket' event is not triggered for the request
|
||||||
|
// (happens in deno), avoids `TypeError`
|
||||||
|
// if a data listener is still present we didn't end cleanly
|
||||||
|
const hasDataListener = socket && socket.listenerCount('data') > 0;
|
||||||
|
|
||||||
|
if (hasDataListener && !hadError) {
|
||||||
|
const err = new Error('Premature close');
|
||||||
|
err.code = 'ERR_STREAM_PREMATURE_CLOSE';
|
||||||
|
errorCallback(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function destroyStream(stream, err) {
|
||||||
|
if (stream.destroy) {
|
||||||
|
stream.destroy(err);
|
||||||
|
} else {
|
||||||
|
// node < 8
|
||||||
|
stream.emit('error', err);
|
||||||
|
stream.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redirect code matching
|
* Redirect code matching
|
||||||
*
|
*
|
||||||
|
|||||||
40
svg-only/dist/317.index.js
vendored
40
svg-only/dist/317.index.js
vendored
@@ -78,27 +78,27 @@ const getGithubUserContribution = async (userName, options = {}) => {
|
|||||||
return parseUserPage(resText);
|
return parseUserPage(resText);
|
||||||
};
|
};
|
||||||
const parseUserPage = (content) => {
|
const parseUserPage = (content) => {
|
||||||
// take roughly the svg block
|
// take roughly the table block
|
||||||
const block = content
|
const block = content
|
||||||
.split(`class="js-calendar-graph-svg"`)[1]
|
.split(`aria-describedby="contribution-graph-description"`)[1]
|
||||||
.split("</svg>")[0];
|
.split("<tbody>")[1]
|
||||||
let x = 0;
|
.split("</tbody>")[0];
|
||||||
let lastYAttribute = 0;
|
const cells = block.split("</tr>").flatMap((inside, y) => inside.split("</td>").flatMap((m) => {
|
||||||
const rects = Array.from(block.matchAll(/<rect[^>]*>[^<]*<\/rect>/g)).map(([m]) => {
|
const date = m.match(/data-date="([^"]+)"/)?.[1];
|
||||||
const date = m.match(/data-date="([^"]+)"/)[1];
|
const literalLevel = m.match(/data-level="([^"]+)"/)?.[1];
|
||||||
const level = +m.match(/data-level="([^"]+)"/)[1];
|
const literalX = m.match(/data-ix="([^"]+)"/)?.[1];
|
||||||
const yAttribute = +m.match(/y="([^"]+)"/)[1];
|
const literalCount = m.match(/(No|\d+) contributions? on/)?.[1];
|
||||||
const literalCount = m.match(/(No|\d+) contributions? on/)[1];
|
if (date && literalLevel && literalX && literalCount)
|
||||||
const count = literalCount === "No" ? 0 : +literalCount;
|
return [
|
||||||
if (lastYAttribute > yAttribute)
|
{
|
||||||
x++;
|
x: +literalX,
|
||||||
lastYAttribute = yAttribute;
|
y,
|
||||||
return { date, count, level, x, yAttribute };
|
date,
|
||||||
});
|
count: +literalCount,
|
||||||
const yAttributes = Array.from(new Set(rects.map((c) => c.yAttribute)).keys()).sort();
|
level: +literalLevel,
|
||||||
const cells = rects.map(({ yAttribute, ...c }) => ({
|
},
|
||||||
y: yAttributes.indexOf(yAttribute),
|
];
|
||||||
...c,
|
return [];
|
||||||
}));
|
}));
|
||||||
return cells;
|
return cells;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user