From 4489504b7a388f97f8fad92e156d0f69c2c2486f Mon Sep 17 00:00:00 2001 From: release bot Date: Mon, 17 Jul 2023 20:37:27 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=A6=202.3.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- action.yml | 2 +- package.json | 2 +- svg-only/dist/197.index.js | 97 +++++++++++++++++++++++++++++++++++++- svg-only/dist/317.index.js | 40 ++++++++-------- 4 files changed, 117 insertions(+), 24 deletions(-) diff --git a/action.yml b/action.yml index e04cf83d..dc032b7a 100644 --- a/action.yml +++ b/action.yml @@ -4,7 +4,7 @@ author: "platane" runs: using: docker - image: docker://platane/snk@sha256:bd0f7538482216785abbee29da431738f5ea9aff9fc3a4b8df37708a808f0968 + image: docker://platane/snk@sha256:2115ffeb538e355aa155630e6e32b6d77ea2345fa8584645c41ace7f5ad667fc inputs: github_user_name: diff --git a/package.json b/package.json index 02c16fb4..649c9e69 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "snk", "description": "Generates a snake game from a github user contributions grid", - "version": "2.2.1", + "version": "2.3.0", "private": true, "repository": "github:platane/snk", "devDependencies": { diff --git a/svg-only/dist/197.index.js b/svg-only/dist/197.index.js index cfc84c84..a48bbe50 100644 --- a/svg-only/dist/197.index.js +++ b/svg-only/dist/197.index.js @@ -1425,6 +1425,20 @@ const isDomainOrSubdomain = function isDomainOrSubdomain(destination, original) 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 * @@ -1456,7 +1470,7 @@ function fetch(url, opts) { let error = new AbortError('The user aborted a request.'); reject(error); if (request.body && request.body instanceof Stream.Readable) { - request.body.destroy(error); + destroyStream(request.body, error); } if (!response || !response.body) return; response.body.emit('error', error); @@ -1497,9 +1511,43 @@ function fetch(url, opts) { req.on('error', function (err) { reject(new FetchError(`request to ${request.url} failed, reason: ${err.message}`, 'system', err)); + + if (response && response.body) { + destroyStream(response.body, err); + } + 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) { clearTimeout(reqTimeout); @@ -1571,7 +1619,7 @@ function fetch(url, opts) { 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']) { requestOpts.headers.delete(name); } @@ -1664,6 +1712,13 @@ function fetch(url, opts) { response = new Response(body, response_options); 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; } @@ -1683,6 +1738,44 @@ function fetch(url, opts) { 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 * diff --git a/svg-only/dist/317.index.js b/svg-only/dist/317.index.js index 2f94d6db..a095f5e9 100644 --- a/svg-only/dist/317.index.js +++ b/svg-only/dist/317.index.js @@ -78,27 +78,27 @@ const getGithubUserContribution = async (userName, options = {}) => { return parseUserPage(resText); }; const parseUserPage = (content) => { - // take roughly the svg block + // take roughly the table block const block = content - .split(`class="js-calendar-graph-svg"`)[1] - .split("")[0]; - let x = 0; - let lastYAttribute = 0; - const rects = Array.from(block.matchAll(/]*>[^<]*<\/rect>/g)).map(([m]) => { - const date = m.match(/data-date="([^"]+)"/)[1]; - const level = +m.match(/data-level="([^"]+)"/)[1]; - const yAttribute = +m.match(/y="([^"]+)"/)[1]; - const literalCount = m.match(/(No|\d+) contributions? on/)[1]; - const count = literalCount === "No" ? 0 : +literalCount; - if (lastYAttribute > yAttribute) - x++; - lastYAttribute = yAttribute; - return { date, count, level, x, yAttribute }; - }); - const yAttributes = Array.from(new Set(rects.map((c) => c.yAttribute)).keys()).sort(); - const cells = rects.map(({ yAttribute, ...c }) => ({ - y: yAttributes.indexOf(yAttribute), - ...c, + .split(`aria-describedby="contribution-graph-description"`)[1] + .split("")[1] + .split("")[0]; + const cells = block.split("").flatMap((inside, y) => inside.split("").flatMap((m) => { + const date = m.match(/data-date="([^"]+)"/)?.[1]; + const literalLevel = m.match(/data-level="([^"]+)"/)?.[1]; + const literalX = m.match(/data-ix="([^"]+)"/)?.[1]; + const literalCount = m.match(/(No|\d+) contributions? on/)?.[1]; + if (date && literalLevel && literalX && literalCount) + return [ + { + x: +literalX, + y, + date, + count: +literalCount, + level: +literalLevel, + }, + ]; + return []; })); return cells; };