From dbd4bb6e153ea6b234df39d62e8727a6d6e7d0f0 Mon Sep 17 00:00:00 2001 From: Alan Poulain Date: Fri, 23 Sep 2022 17:48:24 +0200 Subject: [PATCH 1/3] feat: make the lib isomorphic --- lib/resolvers/http.js | 111 +++++++++++++++++------------------------- lib/util/url.js | 8 +-- 2 files changed, 49 insertions(+), 70 deletions(-) diff --git a/lib/resolvers/http.js b/lib/resolvers/http.js index eaadd2de..31c9b2de 100644 --- a/lib/resolvers/http.js +++ b/lib/resolvers/http.js @@ -70,12 +70,12 @@ module.exports = { * @param {object} file - An object containing information about the referenced file * @param {string} file.url - The full URL of the referenced file * @param {string} file.extension - The lowercased file extension (e.g. ".txt", ".html", etc.) - * @returns {Promise} + * @returns {Promise} */ read (file) { let u = url.parse(file.url); - if (process.browser && !u.protocol) { + if (typeof window !== "undefined" && !u.protocol) { // Use the protocol of the current page u.protocol = url.parse(location.href).protocol; } @@ -91,42 +91,40 @@ module.exports = { * @param {object} httpOptions - The `options.resolve.http` object * @param {number} [redirects] - The redirect URLs that have already been followed * - * @returns {Promise} + * @returns {Promise} * The promise resolves with the raw downloaded data, or rejects if there is an HTTP error. */ function download (u, httpOptions, redirects) { - return new Promise(((resolve, reject) => { - u = url.parse(u); - redirects = redirects || []; - redirects.push(u.href); - - get(u, httpOptions) - .then((res) => { - if (res.statusCode >= 400) { - throw ono({ status: res.statusCode }, `HTTP ERROR ${res.statusCode}`); + u = url.parse(u); + redirects = redirects || []; + redirects.push(u.href); + + return get(u, httpOptions) + .then((res) => { + if (res.statusCode >= 400) { + throw ono({ status: res.statusCode }, `HTTP ERROR ${res.statusCode}`); + } + else if (res.statusCode >= 300) { + if (redirects.length > httpOptions.redirects) { + throw new ResolverError(ono({ status: res.statusCode }, + `Error downloading ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`)); } - else if (res.statusCode >= 300) { - if (redirects.length > httpOptions.redirects) { - reject(new ResolverError(ono({ status: res.statusCode }, - `Error downloading ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`))); - } - else if (!res.headers.location) { - throw ono({ status: res.statusCode }, `HTTP ${res.statusCode} redirect with no location header`); - } - else { - // console.log('HTTP %d redirect %s -> %s', res.statusCode, u.href, res.headers.location); - let redirectTo = url.resolve(u, res.headers.location); - download(redirectTo, httpOptions, redirects).then(resolve, reject); - } + else if (!res.headers.location) { + throw ono({ status: res.statusCode }, `HTTP ${res.statusCode} redirect with no location header`); } else { - resolve(res.body || Buffer.alloc(0)); + // console.log('HTTP %d redirect %s -> %s', res.statusCode, u.href, res.headers.location); + let redirectTo = url.resolve(u, res.headers.location); + return download(redirectTo, httpOptions, redirects); } - }) - .catch((err) => { - reject(new ResolverError(ono(err, `Error downloading ${u.href}`), u.href)); - }); - })); + } + else { + return res.text(); + } + }) + .catch((err) => { + throw new ResolverError(ono(err, `Error downloading ${u.href}`), u.href); + }); } /** @@ -139,42 +137,23 @@ function download (u, httpOptions, redirects) { * The promise resolves with the HTTP Response object. */ function get (u, httpOptions) { - return new Promise(((resolve, reject) => { - // console.log('GET', u.href); - - let protocol = u.protocol === "https:" ? https : http; - let req = protocol.get({ - hostname: u.hostname, - port: u.port, - path: u.path, - auth: u.auth, - protocol: u.protocol, - headers: httpOptions.headers || {}, - withCredentials: httpOptions.withCredentials - }); + let controller; + let timeoutId; + if (httpOptions.timeout) { + controller = new AbortController(); + timeoutId = setTimeout(() => controller.abort(), httpOptions.timeout); + } - if (typeof req.setTimeout === "function") { - req.setTimeout(httpOptions.timeout); + return fetch(u, { + method: 'GET', + headers: httpOptions.headers || {}, + credentials: httpOptions.withCredentials ? 'include' : 'same-origin', + signal: controller ? controller.signal : null, + }).then(response => { + if (timeoutId) { + clearTimeout(timeoutId); } - req.on("timeout", () => { - req.abort(); - }); - - req.on("error", reject); - - req.once("response", (res) => { - res.body = Buffer.alloc(0); - - res.on("data", (data) => { - res.body = Buffer.concat([res.body, Buffer.from(data)]); - }); - - res.on("error", reject); - - res.on("end", () => { - resolve(res); - }); - }); - })); + return response; + }); } diff --git a/lib/util/url.js b/lib/util/url.js index 210be5f5..e2ec06ca 100644 --- a/lib/util/url.js +++ b/lib/util/url.js @@ -1,6 +1,6 @@ "use strict"; -let isWindows = /^win/.test(process.platform), +let isWindows = /^win/.test(globalThis.process?.platform), forwardSlashPattern = /\//g, protocolPattern = /^(\w{2,}):\/\//i, url = module.exports, @@ -22,7 +22,7 @@ let urlDecodePatterns = [ /\%40/g, "@" ]; -exports.parse = require("url").parse; +exports.parse = (url) => new URL(url); /** * Returns resolved target URL relative to a base URL in a manner similar to that of a Web browser resolving an anchor tag HREF. @@ -45,7 +45,7 @@ exports.resolve = function resolve (from, to) { * @returns {string} */ exports.cwd = function cwd () { - if (process.browser) { + if (typeof window !== "undefined") { return location.href; } @@ -144,7 +144,7 @@ exports.isHttp = function isHttp (path) { } else if (protocol === undefined) { // There is no protocol. If we're running in a browser, then assume it's HTTP. - return process.browser; + return typeof window !== "undefined"; } else { // It's some other protocol, such as "ftp://", "mongodb://", etc. From b4a9b1b97d6056cb27ec5b23af3d3c816922a8b3 Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Tue, 11 Oct 2022 12:27:21 +0100 Subject: [PATCH 2/3] chore: fix lint issues --- .eslintrc.yml | 2 ++ lib/resolvers/http.js | 6 ++---- lib/util/url.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.eslintrc.yml b/.eslintrc.yml index c11ebb19..8ce416a4 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -7,3 +7,5 @@ extends: "@jsdevtools" env: node: true browser: true +rules: + "@typescript-eslint/no-explicit-any": ["off"] diff --git a/lib/resolvers/http.js b/lib/resolvers/http.js index 31c9b2de..7e5f10d8 100644 --- a/lib/resolvers/http.js +++ b/lib/resolvers/http.js @@ -1,7 +1,5 @@ "use strict"; -const http = require("http"); -const https = require("https"); const { ono } = require("@jsdevtools/ono"); const url = require("../util/url"); const { ResolverError } = require("../util/errors"); @@ -145,9 +143,9 @@ function get (u, httpOptions) { } return fetch(u, { - method: 'GET', + method: "GET", headers: httpOptions.headers || {}, - credentials: httpOptions.withCredentials ? 'include' : 'same-origin', + credentials: httpOptions.withCredentials ? "include" : "same-origin", signal: controller ? controller.signal : null, }).then(response => { if (timeoutId) { diff --git a/lib/util/url.js b/lib/util/url.js index e2ec06ca..a8bfbcd8 100644 --- a/lib/util/url.js +++ b/lib/util/url.js @@ -22,7 +22,7 @@ let urlDecodePatterns = [ /\%40/g, "@" ]; -exports.parse = (url) => new URL(url); +exports.parse = (u) => new URL(u); /** * Returns resolved target URL relative to a base URL in a manner similar to that of a Web browser resolving an anchor tag HREF. From e2a4af6d91c73ff1bfbdeadf2fd3ccd556894a67 Mon Sep 17 00:00:00 2001 From: Phil Sturgeon <67381+philsturgeon@users.noreply.github.com> Date: Tue, 11 Oct 2022 12:38:36 +0100 Subject: [PATCH 3/3] BREAKING: support ended for node v10 --- .github/workflows/CI-CD.yaml | 12 +++++++----- package.json | 3 +++ 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/CI-CD.yaml b/.github/workflows/CI-CD.yaml index 2f712974..4b2b3b2b 100644 --- a/.github/workflows/CI-CD.yaml +++ b/.github/workflows/CI-CD.yaml @@ -8,6 +8,8 @@ name: CI-CD on: push: + branches: + - main pull_request: schedule: - cron: "0 0 1 * *" @@ -25,9 +27,9 @@ jobs: - macos-latest - windows-latest node: - - 10 - - 12 - 14 + - 16 + - 18 steps: - name: Checkout source @@ -36,7 +38,7 @@ jobs: - name: Install Node ${{ matrix.node }} uses: actions/setup-node@v1 with: - node-version: ${{ matrix.node }} + node-version: ${{ matrix.node }4 - name: Install dependencies run: npm ci @@ -74,7 +76,7 @@ jobs: - name: Install Node uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 - name: Install dependencies run: npm ci @@ -123,7 +125,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-node@v1 with: - node-version: 12 + node-version: 14 - name: Install dependencies run: npm ci diff --git a/package.json b/package.json index 4cea85a6..b87ee2b1 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,9 @@ "browser": { "fs": false }, + "engines": { + "node": ">= 14" + }, "files": [ "lib" ],