diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..3c032078 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +18 diff --git a/lib/environment/browser.js b/lib/environment/browser.js new file mode 100644 index 00000000..acc7209c --- /dev/null +++ b/lib/environment/browser.js @@ -0,0 +1,5 @@ +/* eslint-env browser */ +"use strict"; + +exports.environment = "browser"; +exports.getCwd = () => location.origin + location.pathname; diff --git a/lib/environment/index.js b/lib/environment/index.js new file mode 100644 index 00000000..dc863685 --- /dev/null +++ b/lib/environment/index.js @@ -0,0 +1,23 @@ +"use strict"; + +exports.env = { + platform: "unknown", + environment: "unknown", + getEnvironment () { + return this.environment; + }, + setEnvironment (newEnvironment) { + this.environment = newEnvironment; + }, + getCwd () { + return "/"; + }, + isBrowser () { + return this.environment === "browser"; + }, + TextDecoder: globalThis.TextDecoder || class { + constructor () { + throw new Error("TextDecoder not available"); + } + } +}; diff --git a/lib/environment/node.js b/lib/environment/node.js new file mode 100644 index 00000000..ff395dfc --- /dev/null +++ b/lib/environment/node.js @@ -0,0 +1,10 @@ +"use strict"; + +const { cwd: processCwd, platform } = require("process"); + +exports.environment = "node"; +exports.platform = platform; + +exports.getCwd = () => processCwd(); + +exports.TextDecoder = globalThis.TextDecoder || require("util").TextDecoder; diff --git a/lib/index.browser.js b/lib/index.browser.js new file mode 100644 index 00000000..b5c550eb --- /dev/null +++ b/lib/index.browser.js @@ -0,0 +1,8 @@ +"use strict"; + +const browser = require("./environment/browser.js"); +const { env } = require("./environment/index.js"); + +Object.assign(env, browser); + +module.exports = require("./index.js"); diff --git a/lib/index.d.ts b/lib/index.d.ts index eda46b83..274752a4 100644 --- a/lib/index.d.ts +++ b/lib/index.d.ts @@ -501,4 +501,12 @@ declare namespace $RefParser { public readonly name = "InvalidPointerError"; public readonly code ="EINVALIDPOINTER"; } + + export const env: { + readonly platform: string; + readonly environment: string; + getCwd(): string; + setEnvironment(newEnv: string): void; + getEnvironment(): string; + }; } diff --git a/lib/index.js b/lib/index.js index 9db08771..aea52ee1 100644 --- a/lib/index.js +++ b/lib/index.js @@ -13,6 +13,7 @@ const maybe = require("call-me-maybe"); const { ono } = require("@jsdevtools/ono"); module.exports = $RefParser; +module.exports.env = require("./environment/index.js").env; module.exports.default = $RefParser; module.exports.JSONParserError = JSONParserError; module.exports.JSONParserErrorGroup = JSONParserErrorGroup; diff --git a/lib/index.node.js b/lib/index.node.js new file mode 100644 index 00000000..e26ebddb --- /dev/null +++ b/lib/index.node.js @@ -0,0 +1,8 @@ +"use strict"; + +const node = require("./environment/node.js"); +const { env } = require("./environment/index.js"); + +Object.assign(env, node); + +module.exports = require("./index.js"); diff --git a/lib/parsers/json.js b/lib/parsers/json.js index b45647ac..bb3df0b4 100644 --- a/lib/parsers/json.js +++ b/lib/parsers/json.js @@ -1,9 +1,7 @@ "use strict"; -const { ParserError } = require("../util/errors"); -const TextDecoder = require("../util/text-decoder"); - -const decoder = new TextDecoder(); +const { ParserError } = require("../util/errors.js"); +const { env } = require("../environment/index.js"); module.exports = { /** @@ -42,6 +40,7 @@ module.exports = { async parse (file) { // eslint-disable-line require-await let data = file.data; if (ArrayBuffer.isView(data)) { + let decoder = new env.TextDecoder(); data = decoder.decode(data); } diff --git a/lib/parsers/text.js b/lib/parsers/text.js index f28fea51..1918cb34 100644 --- a/lib/parsers/text.js +++ b/lib/parsers/text.js @@ -1,7 +1,7 @@ "use strict"; -const { ParserError } = require("../util/errors"); -const TextDecoder = require("../util/text-decoder"); +const { ParserError } = require("../util/errors.js"); +const { env } = require("../environment/index.js"); let TEXT_REGEXP = /\.(txt|htm|html|md|xml|js|min|map|css|scss|less|svg)$/i; @@ -58,7 +58,7 @@ module.exports = { return file.data; } else if (ArrayBuffer.isView(file.data)) { - let decoder = new TextDecoder(this.encoding); + let decoder = new env.TextDecoder(this.encoding); return decoder.decode(file.data); } else { diff --git a/lib/parsers/yaml.js b/lib/parsers/yaml.js index b2c78fce..f00915c1 100644 --- a/lib/parsers/yaml.js +++ b/lib/parsers/yaml.js @@ -1,10 +1,8 @@ "use strict"; -const { ParserError } = require("../util/errors"); -const TextDecoder = require("../util/text-decoder"); const yaml = require("@stoplight/yaml"); - -const decoder = new TextDecoder(); +const { ParserError } = require("../util/errors.js"); +const { env } = require("../environment/index.js"); module.exports = { /** @@ -43,6 +41,7 @@ module.exports = { async parse (file) { // eslint-disable-line require-await let data = file.data; if (ArrayBuffer.isView(data)) { + let decoder = new env.TextDecoder(); data = decoder.decode(data); } diff --git a/lib/resolvers/http.js b/lib/resolvers/http.js index 31a91d08..f2b34311 100644 --- a/lib/resolvers/http.js +++ b/lib/resolvers/http.js @@ -3,6 +3,7 @@ const { ono } = require("@jsdevtools/ono"); const url = require("../util/url"); const { ResolverError } = require("../util/errors"); +const { env } = require("../environment/index.js"); module.exports = { /** @@ -73,7 +74,7 @@ module.exports = { read (file) { let u = url.parse(file.url); - if (process.browser && !u.protocol) { + if (env.isBrowser() && !u.protocol) { // Use the protocol of the current page u.protocol = url.parse(location.href).protocol; } @@ -115,7 +116,7 @@ async function download (u, httpOptions, redirects) { credentials: httpOptions.withCredentials ? "include" : "omit", signal: controller.signal, // browser fetch API does not support redirects https://fetch.spec.whatwg.org/#atomic-http-redirect-handling - redirect: process.browser + redirect: env.isBrowser() ? "follow" : httpOptions.redirects === 0 ? "error" diff --git a/lib/util/text-decoder.js b/lib/util/text-decoder.js deleted file mode 100644 index e3dd01ed..00000000 --- a/lib/util/text-decoder.js +++ /dev/null @@ -1,5 +0,0 @@ -"use strict"; - -const { TextDecoder: NodeTextDecoder } = require("fastestsmallesttextencoderdecoder"); - -module.exports = typeof TextDecoder === "undefined" ? NodeTextDecoder : TextDecoder; diff --git a/lib/util/url.js b/lib/util/url.js index d77763bd..5e0871d2 100644 --- a/lib/util/url.js +++ b/lib/util/url.js @@ -1,7 +1,8 @@ "use strict"; -let isWindows = /^win/.test(process.platform), - forwardSlashPattern = /\//g, +const { env } = require("../environment/index.js"); + +let forwardSlashPattern = /\//g, protocolPattern = /^(\w{2,}):\/\//i, url = module.exports, slash = /\//g, @@ -36,11 +37,11 @@ exports.resolve = require("url").resolve; * @returns {string} */ exports.cwd = function cwd () { - if (process.browser) { - return location.href; + if (env.isBrowser()) { + return env.getCwd(); } - let path = process.cwd(); + let path = env.getCwd(); let lastChar = path.slice(-1); if (lastChar === "/" || lastChar === "\\") { @@ -121,7 +122,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 env.isBrowser(); } else { // It's some other protocol, such as "ftp://", "mongodb://", etc. @@ -137,7 +138,7 @@ exports.isHttp = function isHttp (path) { * @returns {boolean} */ exports.isFileSystemPath = function isFileSystemPath (path) { - if (process.browser) { + if (env.isBrowser()) { // We're running in a browser, so assume that all paths are URLs. // This way, even relative paths will be treated as URLs rather than as filesystem paths return false; @@ -166,7 +167,7 @@ exports.isFileSystemPath = function isFileSystemPath (path) { exports.fromFileSystemPath = function fromFileSystemPath (path) { // Step 1: On Windows, replace backslashes with forward slashes, // rather than encoding them as "%5C" - if (isWindows) { + if (isWindows()) { path = path.replace(/\\/g, "/"); } @@ -222,12 +223,12 @@ exports.toFileSystemPath = function toFileSystemPath (path, keepFileProtocol) { // On Windows, it will start with something like "C:/". // On Posix, it will start with "/" isFileUrl = false; - path = isWindows ? path : "/" + path; + path = isWindows() ? path : "/" + path; } } // Step 4: Normalize Windows paths (unless it's a "file://" URL) - if (isWindows && !isFileUrl) { + if (isWindows() && !isFileUrl) { // Replace forward slashes with backslashes path = path.replace(forwardSlashPattern, "\\"); @@ -280,3 +281,7 @@ exports.safePathToPointer = function safePointerToPath (path) { }) .join("/")}`; }; + +function isWindows () { + return env.platform.startsWith("win"); +} diff --git a/package-lock.json b/package-lock.json index b88a9dd7..0552331f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,7 +13,6 @@ "@stoplight/path": "^1.3.2", "@stoplight/yaml": "^4.0.2", "call-me-maybe": "^1.0.1", - "fastestsmallesttextencoderdecoder": "^1.0.22", "url": "^0.11.3" }, "devDependencies": { @@ -6442,11 +6441,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "node_modules/fastestsmallesttextencoderdecoder": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", - "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==" - }, "node_modules/fastq": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.1.tgz", @@ -21366,11 +21360,6 @@ "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", "dev": true }, - "fastestsmallesttextencoderdecoder": { - "version": "1.0.22", - "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", - "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==" - }, "fastq": { "version": "1.10.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.10.1.tgz", diff --git a/package.json b/package.json index 786209d1..ffc12736 100644 --- a/package.json +++ b/package.json @@ -28,11 +28,24 @@ "url": "https://github.com/stoplightio/json-schema-ref-parser.git" }, "license": "MIT", - "main": "lib/index.js", + "main": "lib/index.node.js", "typings": "lib/index.d.ts", "browser": { + "./lib/index.node.js": "./lib/index.browser.js", + "./lib/environment/node.js": "./lib/environment/browser.js", "fs": false }, + "exports": { + ".": { + "types": "./lib/index.d.ts", + "browser": "./lib/index.browser.js", + "node": "./lib/index.node.js" + }, + "./lib/util/url": "./lib/util/url.js", + "./lib/parsers/json": "./lib/parsers/json.js", + "./lib/parsers/yaml": "./lib/parsers/yaml.js", + "./lib/bundle/stoplight/defaults": "./lib/bundle/stoplight/defaults.js" + }, "files": [ "lib" ], @@ -81,7 +94,6 @@ "@stoplight/path": "^1.3.2", "@stoplight/yaml": "^4.0.2", "call-me-maybe": "^1.0.1", - "fastestsmallesttextencoderdecoder": "^1.0.22", "url": "^0.11.3" } } diff --git a/test/fixtures/polyfill.js b/test/fixtures/polyfill.js deleted file mode 100644 index 7add5abd..00000000 --- a/test/fixtures/polyfill.js +++ /dev/null @@ -1,10 +0,0 @@ -"use strict"; - -const { host } = require("@jsdevtools/host-environment"); - -// Load the Babel Polyfills for old browsers. -// NOTE: It's important that we ONLY do this when needed, -// to ensure that our code works _without_ polyfills everywhere else -if (host.browser.IE) { - require("@babel/polyfill"); -} diff --git a/test/specs/callbacks.spec.js b/test/specs/callbacks.spec.js index ecd43ebb..04bb8785 100644 --- a/test/specs/callbacks.spec.js +++ b/test/specs/callbacks.spec.js @@ -1,7 +1,7 @@ "use strict"; const { expect } = require("chai"); -const $RefParser = require("../../lib"); +const $RefParser = require("../.."); const helper = require("../utils/helper"); const path = require("../utils/path"); const { ParserError } = require("../../lib/util/errors"); diff --git a/test/specs/circular-external-direct/circular-external-direct.spec.js b/test/specs/circular-external-direct/circular-external-direct.spec.js index 408ec73f..c9fc55bd 100644 --- a/test/specs/circular-external-direct/circular-external-direct.spec.js +++ b/test/specs/circular-external-direct/circular-external-direct.spec.js @@ -4,7 +4,7 @@ const chai = require("chai"); const chaiSubset = require("chai-subset"); chai.use(chaiSubset); const { expect } = chai; -const $RefParser = require("../../../lib"); +const $RefParser = require("../../.."); const path = require("../../utils/path"); const parsedSchema = require("./parsed"); const dereferencedSchema = require("./dereferenced"); diff --git a/test/specs/empty/empty.spec.js b/test/specs/empty/empty.spec.js index f3815726..e5564821 100644 --- a/test/specs/empty/empty.spec.js +++ b/test/specs/empty/empty.spec.js @@ -1,7 +1,7 @@ "use strict"; const { expect } = require("chai"); -const $RefParser = require("../../../lib"); +const $RefParser = require("../../.."); const helper = require("../../utils/helper"); const path = require("../../utils/path"); diff --git a/test/specs/exports.spec.js b/test/specs/exports.spec.js index 1723f14e..e2063469 100644 --- a/test/specs/exports.spec.js +++ b/test/specs/exports.spec.js @@ -75,6 +75,7 @@ describe("json-schema-ref-parser package exports", () => { it("should not export anything else", async () => { expect(commonJSExport).to.have.same.keys( "default", + "env", "parse", "resolve", "dereference", diff --git a/test/specs/http.spec.js b/test/specs/http.spec.js index ba241af5..5ccb58e7 100644 --- a/test/specs/http.spec.js +++ b/test/specs/http.spec.js @@ -4,7 +4,7 @@ const { host } = require("@jsdevtools/host-environment"); const { expect, use } = require("chai"); const chai = require("chai"); const spies = require("chai-spies"); -const $RefParser = require("../../lib"); +const $RefParser = require("../.."); use(spies); diff --git a/test/specs/invalid-pointers/invalid-pointers.js b/test/specs/invalid-pointers/invalid-pointers.js index bc62d936..4ccdfa7d 100644 --- a/test/specs/invalid-pointers/invalid-pointers.js +++ b/test/specs/invalid-pointers/invalid-pointers.js @@ -4,7 +4,7 @@ const chai = require("chai"); const chaiSubset = require("chai-subset"); chai.use(chaiSubset); const { expect } = chai; -const $RefParser = require("../../../lib"); +const $RefParser = require("../../.."); const helper = require("../../utils/helper"); const path = require("../../utils/path"); const { JSONParserErrorGroup, InvalidPointerError } = require("../../../lib/util/errors"); diff --git a/test/specs/invalid/invalid.spec.js b/test/specs/invalid/invalid.spec.js index 56bb8057..33f97398 100644 --- a/test/specs/invalid/invalid.spec.js +++ b/test/specs/invalid/invalid.spec.js @@ -5,7 +5,7 @@ const chai = require("chai"); const chaiSubset = require("chai-subset"); chai.use(chaiSubset); const { expect } = chai; -const $RefParser = require("../../../lib"); +const $RefParser = require("../../.."); const helper = require("../../utils/helper"); const path = require("../../utils/path"); const { JSONParserErrorGroup, ParserError, ResolverError } = require("../../../lib/util/errors"); diff --git a/test/specs/missing-pointers/missing-pointers.spec.js b/test/specs/missing-pointers/missing-pointers.spec.js index 92b0d829..dbcbc9c6 100644 --- a/test/specs/missing-pointers/missing-pointers.spec.js +++ b/test/specs/missing-pointers/missing-pointers.spec.js @@ -4,7 +4,7 @@ const chai = require("chai"); const chaiSubset = require("chai-subset"); chai.use(chaiSubset); const { expect } = chai; -const $RefParser = require("../../../lib"); +const $RefParser = require("../../.."); const { JSONParserErrorGroup, MissingPointerError } = require("../../../lib/util/errors"); const helper = require("../../utils/helper"); diff --git a/test/specs/parsers/parsers.spec.js b/test/specs/parsers/parsers.spec.js index 5c790377..9b8cef86 100644 --- a/test/specs/parsers/parsers.spec.js +++ b/test/specs/parsers/parsers.spec.js @@ -10,7 +10,6 @@ const path = require("../../utils/path"); const parsedSchema = require("./parsed"); const dereferencedSchema = require("./dereferenced"); const { JSONParserErrorGroup, ParserError, UnmatchedParserError } = require("../../../lib/util/errors"); -const TextDecoder = require("../../../lib/util/text-decoder"); describe("References to non-JSON files", () => { it("should parse successfully", async () => { diff --git a/test/specs/refs.spec.js b/test/specs/refs.spec.js index b4dad876..139120d0 100644 --- a/test/specs/refs.spec.js +++ b/test/specs/refs.spec.js @@ -2,7 +2,7 @@ const { host } = require("@jsdevtools/host-environment"); const { expect } = require("chai"); -const $RefParser = require("../../lib"); +const $RefParser = require("../.."); const helper = require("../utils/helper"); const path = require("../utils/path"); const parsedSchema = require("./external/parsed");