diff --git a/demo/index.tsx b/demo/index.tsx index 62c5323b..ea025f81 100644 --- a/demo/index.tsx +++ b/demo/index.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { render } from 'react-dom'; import styled from 'styled-components'; -import { resolve as urlResolve } from 'url'; import { RedocStandalone } from '../src'; import ComboBox from './ComboBox'; import FileInput from './components/FileInput'; @@ -87,7 +86,7 @@ class DemoApp extends React.Component< let proxiedUrl = specUrl; if (specUrl !== DEFAULT_SPEC) { proxiedUrl = cors - ? '\\\\cors.redoc.ly/' + urlResolve(window.location.href, specUrl) + ? '\\\\cors.redoc.ly/' + new URL(specUrl, window.location.href).href : specUrl; } return ( diff --git a/package-lock.json b/package-lock.json index 317f417e..c65e12b4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "2.0.0-rc.67", "license": "MIT", "dependencies": { - "@redocly/openapi-core": "^1.0.0-beta.88", + "@redocly/openapi-core": "^1.0.0-beta.95", "classnames": "^2.3.1", "decko": "^1.2.0", "dompurify": "^2.2.8", @@ -17,7 +17,7 @@ "json-pointer": "^0.6.2", "lunr": "^2.3.9", "mark.js": "^8.11.1", - "marked": "^4.0.10", + "marked": "^4.0.15", "mobx-react": "^7.2.0", "openapi-sampler": "^1.2.1", "path-browserify": "^1.0.1", @@ -44,7 +44,7 @@ "@types/json-pointer": "^1.0.30", "@types/lunr": "^2.3.3", "@types/mark.js": "^8.11.5", - "@types/marked": "^4.0.1", + "@types/marked": "^4.0.3", "@types/node": "^15.6.1", "@types/prismjs": "^1.16.5", "@types/prop-types": "^15.7.3", @@ -2590,9 +2590,9 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/@redocly/openapi-core": { - "version": "1.0.0-beta.88", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.88.tgz", - "integrity": "sha512-E9vkLvumIkzII0ydDFGr6uYbZgI9rHMxBveefzM51OUvobvifryXb6VcnQ1T0P8VoHRiYwpgiWlmZeDsNAdZdg==", + "version": "1.0.0-beta.95", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.95.tgz", + "integrity": "sha512-7Nnc4Obp/1lbrjNjD33oOnZCuoJa8awhBCEyyayPWGQFp1SkhjpZJnfnKkFuYbQzMjTIAvEeSp9DOQK/E0fgEA==", "dependencies": { "@redocly/ajv": "^8.6.4", "@types/node": "^14.11.8", @@ -3014,9 +3014,9 @@ } }, "node_modules/@types/marked": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.1.tgz", - "integrity": "sha512-ZigEmCWdNUU7IjZEuQ/iaimYdDHWHfTe3kg8ORfKjyGYd9RWumPoOJRQXB0bO+XLkNwzCthW3wUIQtANaEZ1ag==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.3.tgz", + "integrity": "sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg==", "dev": true }, "node_modules/@types/mime": { @@ -13154,9 +13154,9 @@ "integrity": "sha1-GA8fnr74sOY45BZq1S24eb6y/8U=" }, "node_modules/marked": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.10.tgz", - "integrity": "sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw==", + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.15.tgz", + "integrity": "sha512-esX5lPdTfG4p8LDkv+obbRCyOKzB+820ZZyMOXJZygZBHrH9b3xXR64X4kT3sPe9Nx8qQXbmcz6kFSMt4Nfk6Q==", "bin": { "marked": "bin/marked.js" }, @@ -20971,9 +20971,9 @@ } }, "@redocly/openapi-core": { - "version": "1.0.0-beta.88", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.88.tgz", - "integrity": "sha512-E9vkLvumIkzII0ydDFGr6uYbZgI9rHMxBveefzM51OUvobvifryXb6VcnQ1T0P8VoHRiYwpgiWlmZeDsNAdZdg==", + "version": "1.0.0-beta.95", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.0.0-beta.95.tgz", + "integrity": "sha512-7Nnc4Obp/1lbrjNjD33oOnZCuoJa8awhBCEyyayPWGQFp1SkhjpZJnfnKkFuYbQzMjTIAvEeSp9DOQK/E0fgEA==", "requires": { "@redocly/ajv": "^8.6.4", "@types/node": "^14.11.8", @@ -21369,9 +21369,9 @@ } }, "@types/marked": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.1.tgz", - "integrity": "sha512-ZigEmCWdNUU7IjZEuQ/iaimYdDHWHfTe3kg8ORfKjyGYd9RWumPoOJRQXB0bO+XLkNwzCthW3wUIQtANaEZ1ag==", + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@types/marked/-/marked-4.0.3.tgz", + "integrity": "sha512-HnMWQkLJEf/PnxZIfbm0yGJRRZYYMhb++O9M36UCTA9z53uPvVoSlAwJr3XOpDEryb7Hwl1qAx/MV6YIW1RXxg==", "dev": true }, "@types/mime": { @@ -29069,9 +29069,9 @@ "integrity": "sha1-GA8fnr74sOY45BZq1S24eb6y/8U=" }, "marked": { - "version": "4.0.10", - "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.10.tgz", - "integrity": "sha512-+QvuFj0nGgO970fySghXGmuw+Fd0gD2x3+MqCWLIPf5oxdv1Ka6b2q+z9RP01P/IaKPMEramy+7cNy/Lw8c3hw==" + "version": "4.0.15", + "resolved": "https://registry.npmjs.org/marked/-/marked-4.0.15.tgz", + "integrity": "sha512-esX5lPdTfG4p8LDkv+obbRCyOKzB+820ZZyMOXJZygZBHrH9b3xXR64X4kT3sPe9Nx8qQXbmcz6kFSMt4Nfk6Q==" }, "media-typer": { "version": "0.3.0", diff --git a/package.json b/package.json index d4c4a0a5..1c7383af 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "@types/json-pointer": "^1.0.30", "@types/lunr": "^2.3.3", "@types/mark.js": "^8.11.5", - "@types/marked": "^4.0.1", + "@types/marked": "^4.0.3", "@types/node": "^15.6.1", "@types/prismjs": "^1.16.5", "@types/prop-types": "^15.7.3", @@ -138,7 +138,7 @@ "styled-components": "^4.1.1 || ^5.1.1" }, "dependencies": { - "@redocly/openapi-core": "^1.0.0-beta.88", + "@redocly/openapi-core": "^1.0.0-beta.95", "classnames": "^2.3.1", "decko": "^1.2.0", "dompurify": "^2.2.8", @@ -146,7 +146,7 @@ "json-pointer": "^0.6.2", "lunr": "^2.3.9", "mark.js": "^8.11.1", - "marked": "^4.0.10", + "marked": "^4.0.15", "mobx-react": "^7.2.0", "openapi-sampler": "^1.2.1", "path-browserify": "^1.0.1", diff --git a/src/services/OpenAPIParser.ts b/src/services/OpenAPIParser.ts index bdc86bbe..15ee6c0d 100644 --- a/src/services/OpenAPIParser.ts +++ b/src/services/OpenAPIParser.ts @@ -1,5 +1,3 @@ -import { resolve as urlResolve } from 'url'; - import { OpenAPIRef, OpenAPISchema, OpenAPISpec, Referenced } from '../types'; import { appendToMdHeading, IS_BROWSER } from '../utils/'; @@ -62,7 +60,7 @@ export class OpenAPIParser { const href = IS_BROWSER ? window.location.href : ''; if (typeof specUrl === 'string') { - this.specUrl = urlResolve(href, specUrl); + this.specUrl = new URL(specUrl, href).href; } } diff --git a/src/services/models/Example.ts b/src/services/models/Example.ts index 66bb9201..016e5caa 100644 --- a/src/services/models/Example.ts +++ b/src/services/models/Example.ts @@ -1,5 +1,3 @@ -import { resolve as urlResolve } from 'url'; - import { OpenAPIEncoding, OpenAPIExample, Referenced } from '../../types'; import { isFormUrlEncoded, isJsonLike, urlFormEncodePayload } from '../../utils/openapi'; import { OpenAPIParser } from '../OpenAPIParser'; @@ -23,7 +21,7 @@ export class ExampleModel { this.summary = example.summary; this.description = example.description; if (example.externalValue) { - this.externalValueUrl = urlResolve(parser.specUrl || '', example.externalValue); + this.externalValueUrl = new URL(example.externalValue, parser.specUrl || '').href; } parser.exitRef(infoOrRef); diff --git a/src/utils/helpers.ts b/src/utils/helpers.ts index 2b7ea8e8..1bfba561 100644 --- a/src/utils/helpers.ts +++ b/src/utils/helpers.ts @@ -1,5 +1,4 @@ import slugify from 'slugify'; -import { format, parse } from 'url'; /** * Maps over array passing `isLast` bool to iterator as the second argument @@ -146,18 +145,23 @@ export function isAbsoluteUrl(url: string) { export function resolveUrl(url: string, to: string) { let res; if (to.startsWith('//')) { - const { protocol: specProtocol } = parse(url); - res = `${specProtocol || 'https:'}${to}`; + try { + res = `${new URL(url).protocol || 'https:'}${to}`; + } catch { + res = `https:${to}`; + } } else if (isAbsoluteUrl(to)) { res = to; } else if (!to.startsWith('/')) { res = stripTrailingSlash(url) + '/' + to; } else { - const urlObj = parse(url); - res = format({ - ...urlObj, - pathname: to, - }); + try { + const urlObj = new URL(url); + urlObj.pathname = to; + res = urlObj.href; + } catch { + res = to; + } } return stripTrailingSlash(res); } diff --git a/src/utils/loadAndBundleSpec.ts b/src/utils/loadAndBundleSpec.ts index 8ffb21c2..cc9ff6e3 100644 --- a/src/utils/loadAndBundleSpec.ts +++ b/src/utils/loadAndBundleSpec.ts @@ -1,4 +1,6 @@ import type { Source, Document } from '@redocly/openapi-core'; +// eslint-disable-next-line import/no-internal-modules +import type { ResolvedConfig } from '@redocly/openapi-core/lib/config'; // eslint-disable-next-line import/no-internal-modules import { bundle } from '@redocly/openapi-core/lib/bundle'; @@ -11,7 +13,7 @@ import { OpenAPISpec } from '../types'; import { IS_BROWSER } from './dom'; export async function loadAndBundleSpec(specUrlOrObject: object | string): Promise { - const config = new Config({}); + const config = new Config({} as ResolvedConfig); const bundleOpts = { config, base: IS_BROWSER ? window.location.href : process.cwd(), diff --git a/webpack.config.ts b/webpack.config.ts index 34966cad..38d4747f 100644 --- a/webpack.config.ts +++ b/webpack.config.ts @@ -8,6 +8,7 @@ const nodeExternals = require('webpack-node-externals')({ // bundle in modules that need transpiling + non-js (e.g. css) allowlist: [ 'swagger2openapi', + 'marked', /reftools/, 'oas-resolver', 'oas-kit-common', @@ -65,11 +66,12 @@ export default (env: { standalone?: boolean; browser?: boolean } = {}) => ({ 'node-fetch': 'null', 'node-fetch-h2': 'null', yaml: 'null', + url: 'null', 'safe-json-stringify': 'null', } : (context, request, callback) => { // ignore node-fetch dep of swagger2openapi as it is not used - if (/esprima|node-fetch|node-fetch-h2|\/yaml|safe-json-stringify$/i.test(request)) { + if (/esprima|node-fetch|node-fetch-h2|\/yaml|safe-json-stringify|url$/i.test(request)) { return callback(null, 'var undefined'); } return nodeExternals(context, request, callback);