@apidevtools/json-schema-ref-parser 9.1.0 → 9.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,5 +1,7 @@
1
- JSON Schema $Ref Parser
2
- ============================
1
+ # JSON Schema $Ref Parser
2
+
3
+ _**This package needs [a new maintainer](https://github.com/APIDevTools/json-schema-ref-parser/issues/285) or at least some contributors, or a decent number of sponsors so I can hire contractors to do the work. For more information [please read this article](https://phil.tech/2022/bundling-openapi-with-javascript/). I'll mark the repo as read-only and unmaintained on January 15th 2023 along with a bunch of other @apidevtools packages like swagger-parser, so I can focus on scaling up my [reforestation charity](https://protect.earth/) instead of burning myself out trying to maintain a whole load of OSS projects I don't use in my vanishingly small spare time.** - [Phil Sturgeon](https://github.com/philsturgeon)_
4
+
3
5
  #### Parse, Resolve, and Dereference JSON Schema $ref pointers
4
6
 
5
7
  [![Build Status](https://github.com/APIDevTools/json-schema-ref-parser/workflows/CI-CD/badge.svg?branch=master)](https://github.com/APIDevTools/json-schema-ref-parser/actions)
@@ -111,6 +113,13 @@ When using a transpiler such as [Babel](https://babeljs.io/) or [TypeScript](htt
111
113
  import $RefParser from "@apidevtools/json-schema-ref-parser";
112
114
  ```
113
115
 
116
+ If you are using Node.js < 18, you'll need a polyfill for `fetch`, like [node-fetch](https://github.com/node-fetch/node-fetch):
117
+ ```javascript
118
+ import fetch from "node-fetch";
119
+
120
+ globalThis.fetch = fetch;
121
+ ```
122
+
114
123
 
115
124
 
116
125
  Browser support
package/lib/bundle.js CHANGED
@@ -135,7 +135,7 @@ function inventory$Ref ($refParent, $refKey, path, pathFromRoot, indirections, i
135
135
  });
136
136
 
137
137
  // Recursively crawl the resolved value
138
- if (!existingEntry) {
138
+ if (!existingEntry || external) {
139
139
  crawl(pointer.value, null, pointer.path, pathFromRoot, indirections + 1, inventory, $refs, options);
140
140
  }
141
141
  }
@@ -71,6 +71,9 @@ function crawl (obj, path, pathFromRoot, parents, processedObjects, dereferenced
71
71
  // Avoid pointless mutations; breaks frozen objects to no profit
72
72
  if (obj[key] !== dereferenced.value) {
73
73
  obj[key] = dereferenced.value;
74
+ if (options.dereference.onDereference) {
75
+ options.dereference.onDereference(value.$ref, obj[key]);
76
+ }
74
77
  }
75
78
  }
76
79
  else {
package/lib/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { JSONSchema4, JSONSchema4Type, JSONSchema6, JSONSchema6Type, JSONSchema7, JSONSchema7Type } from "json-schema";
1
+ import { JSONSchema4, JSONSchema4Object, JSONSchema4Type, JSONSchema6, JSONSchema6Object, JSONSchema6Type, JSONSchema7, JSONSchema7Object, JSONSchema7Type } from "json-schema";
2
2
 
3
3
  export = $RefParser;
4
4
 
@@ -174,6 +174,7 @@ declare class $RefParser {
174
174
  declare namespace $RefParser {
175
175
 
176
176
  export type JSONSchema = JSONSchema4 | JSONSchema6 | JSONSchema7;
177
+ export type JSONSchemaObject = JSONSchema4Object | JSONSchema6Object | JSONSchema7Object;
177
178
  export type SchemaCallback = (err: Error | null, schema?: JSONSchema) => any;
178
179
  export type $RefsCallback = (err: Error | null, $refs?: $Refs) => any;
179
180
 
@@ -238,6 +239,14 @@ declare namespace $RefParser {
238
239
  * subpaths contain literal $ref keys that should not be dereferenced.
239
240
  */
240
241
  excludedPathMatcher?(path: string): boolean;
242
+
243
+ /**
244
+ * Callback invoked during dereferencing.
245
+ *
246
+ * @argument {string} path The path being dereferenced (ie. the `$ref` string).
247
+ * @argument {JSONSchemaObject} object The JSON-Schema that the `$ref` resolved to.
248
+ */
249
+ onDereference(path: string, value: JSONSchemaObject): void;
241
250
  };
242
251
  }
243
252
 
package/lib/refs.js CHANGED
@@ -4,6 +4,9 @@ const { ono } = require("@jsdevtools/ono");
4
4
  const $Ref = require("./ref");
5
5
  const url = require("./util/url");
6
6
 
7
+ const isWindows = /^win/.test(globalThis.process ? globalThis.process.platform : undefined);
8
+ const getPathFromOs = filePath => isWindows ? filePath.replace(/\\/g, "/") : filePath;
9
+
7
10
  module.exports = $Refs;
8
11
 
9
12
  /**
@@ -44,7 +47,7 @@ function $Refs () {
44
47
  $Refs.prototype.paths = function (types) { // eslint-disable-line no-unused-vars
45
48
  let paths = getPaths(this._$refs, arguments);
46
49
  return paths.map((path) => {
47
- return path.decoded;
50
+ return getPathFromOs(path.decoded);
48
51
  });
49
52
  };
50
53
 
@@ -58,7 +61,7 @@ $Refs.prototype.values = function (types) { // eslint-disable-line no-unused-v
58
61
  let $refs = this._$refs;
59
62
  let paths = getPaths($refs, arguments);
60
63
  return paths.reduce((obj, path) => {
61
- obj[path.decoded] = $refs[path.encoded].value;
64
+ obj[getPathFromOs(path.decoded)] = $refs[path.encoded].value;
62
65
  return obj;
63
66
  }, {});
64
67
  };
@@ -1,7 +1,5 @@
1
1
  "use strict";
2
2
 
3
- const http = require("http");
4
- const https = require("https");
5
3
  const { ono } = require("@jsdevtools/ono");
6
4
  const url = require("../util/url");
7
5
  const { ResolverError } = require("../util/errors");
@@ -75,7 +73,7 @@ module.exports = {
75
73
  read (file) {
76
74
  let u = url.parse(file.url);
77
75
 
78
- if (process.browser && !u.protocol) {
76
+ if (typeof window !== "undefined" && !u.protocol) {
79
77
  // Use the protocol of the current page
80
78
  u.protocol = url.parse(location.href).protocol;
81
79
  }
@@ -95,38 +93,36 @@ module.exports = {
95
93
  * The promise resolves with the raw downloaded data, or rejects if there is an HTTP error.
96
94
  */
97
95
  function download (u, httpOptions, redirects) {
98
- return new Promise(((resolve, reject) => {
99
- u = url.parse(u);
100
- redirects = redirects || [];
101
- redirects.push(u.href);
102
-
103
- get(u, httpOptions)
104
- .then((res) => {
105
- if (res.statusCode >= 400) {
106
- throw ono({ status: res.statusCode }, `HTTP ERROR ${res.statusCode}`);
96
+ u = url.parse(u);
97
+ redirects = redirects || [];
98
+ redirects.push(u.href);
99
+
100
+ return get(u, httpOptions)
101
+ .then((res) => {
102
+ if (res.status >= 400) {
103
+ throw ono({ status: res.statusCode }, `HTTP ERROR ${res.status}`);
104
+ }
105
+ else if (res.status >= 300) {
106
+ if (redirects.length > httpOptions.redirects) {
107
+ throw new ResolverError(ono({ status: res.status },
108
+ `Error downloading ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`));
107
109
  }
108
- else if (res.statusCode >= 300) {
109
- if (redirects.length > httpOptions.redirects) {
110
- reject(new ResolverError(ono({ status: res.statusCode },
111
- `Error downloading ${redirects[0]}. \nToo many redirects: \n ${redirects.join(" \n ")}`)));
112
- }
113
- else if (!res.headers.location) {
114
- throw ono({ status: res.statusCode }, `HTTP ${res.statusCode} redirect with no location header`);
115
- }
116
- else {
117
- // console.log('HTTP %d redirect %s -> %s', res.statusCode, u.href, res.headers.location);
118
- let redirectTo = url.resolve(u, res.headers.location);
119
- download(redirectTo, httpOptions, redirects).then(resolve, reject);
120
- }
110
+ else if (!res.headers.location) {
111
+ throw ono({ status: res.status }, `HTTP ${res.status} redirect with no location header`);
121
112
  }
122
113
  else {
123
- resolve(res.body || Buffer.alloc(0));
114
+ // console.log('HTTP %d redirect %s -> %s', res.status, u.href, res.headers.location);
115
+ let redirectTo = url.resolve(u, res.headers.location);
116
+ return download(redirectTo, httpOptions, redirects);
124
117
  }
125
- })
126
- .catch((err) => {
127
- reject(new ResolverError(ono(err, `Error downloading ${u.href}`), u.href));
128
- });
129
- }));
118
+ }
119
+ else {
120
+ return res.body ? res.arrayBuffer().then(buf => Buffer.from(buf)) : Buffer.alloc(0);
121
+ }
122
+ })
123
+ .catch((err) => {
124
+ throw new ResolverError(ono(err, `Error downloading ${u.href}`), u.href);
125
+ });
130
126
  }
131
127
 
132
128
  /**
@@ -139,42 +135,23 @@ function download (u, httpOptions, redirects) {
139
135
  * The promise resolves with the HTTP Response object.
140
136
  */
141
137
  function get (u, httpOptions) {
142
- return new Promise(((resolve, reject) => {
143
- // console.log('GET', u.href);
144
-
145
- let protocol = u.protocol === "https:" ? https : http;
146
- let req = protocol.get({
147
- hostname: u.hostname,
148
- port: u.port,
149
- path: u.path,
150
- auth: u.auth,
151
- protocol: u.protocol,
152
- headers: httpOptions.headers || {},
153
- withCredentials: httpOptions.withCredentials
154
- });
138
+ let controller;
139
+ let timeoutId;
140
+ if (httpOptions.timeout) {
141
+ controller = new AbortController();
142
+ timeoutId = setTimeout(() => controller.abort(), httpOptions.timeout);
143
+ }
155
144
 
156
- if (typeof req.setTimeout === "function") {
157
- req.setTimeout(httpOptions.timeout);
145
+ return fetch(u, {
146
+ method: "GET",
147
+ headers: httpOptions.headers || {},
148
+ credentials: httpOptions.withCredentials ? "include" : "same-origin",
149
+ signal: controller ? controller.signal : null,
150
+ }).then(response => {
151
+ if (timeoutId) {
152
+ clearTimeout(timeoutId);
158
153
  }
159
154
 
160
- req.on("timeout", () => {
161
- req.abort();
162
- });
163
-
164
- req.on("error", reject);
165
-
166
- req.once("response", (res) => {
167
- res.body = Buffer.alloc(0);
168
-
169
- res.on("data", (data) => {
170
- res.body = Buffer.concat([res.body, Buffer.from(data)]);
171
- });
172
-
173
- res.on("error", reject);
174
-
175
- res.on("end", () => {
176
- resolve(res);
177
- });
178
- });
179
- }));
155
+ return response;
156
+ });
180
157
  }
package/lib/util/url.js CHANGED
@@ -1,6 +1,9 @@
1
1
  "use strict";
2
2
 
3
- let isWindows = /^win/.test(process.platform),
3
+ const nodePath = require("path");
4
+ const projectDir = nodePath.resolve(__dirname, "..", "..");
5
+
6
+ let isWindows = /^win/.test(globalThis.process ? globalThis.process.platform : undefined),
4
7
  forwardSlashPattern = /\//g,
5
8
  protocolPattern = /^(\w{2,}):\/\//i,
6
9
  url = module.exports,
@@ -22,8 +25,22 @@ let urlDecodePatterns = [
22
25
  /\%40/g, "@"
23
26
  ];
24
27
 
25
- exports.parse = require("url").parse;
26
- exports.resolve = require("url").resolve;
28
+ exports.parse = (u) => new URL(u);
29
+
30
+ /**
31
+ * Returns resolved target URL relative to a base URL in a manner similar to that of a Web browser resolving an anchor tag HREF.
32
+ *
33
+ * @return {string}
34
+ */
35
+ exports.resolve = function resolve (from, to) {
36
+ let resolvedUrl = new URL(to, new URL(from, "resolve://"));
37
+ if (resolvedUrl.protocol === "resolve:") {
38
+ // `from` is a relative URL.
39
+ let { pathname, search, hash } = resolvedUrl;
40
+ return pathname + search + hash;
41
+ }
42
+ return resolvedUrl.toString();
43
+ };
27
44
 
28
45
  /**
29
46
  * Returns the current working directory (in Node) or the current page URL (in browsers).
@@ -31,7 +48,7 @@ exports.resolve = require("url").resolve;
31
48
  * @returns {string}
32
49
  */
33
50
  exports.cwd = function cwd () {
34
- if (process.browser) {
51
+ if (typeof window !== "undefined") {
35
52
  return location.href;
36
53
  }
37
54
 
@@ -130,7 +147,7 @@ exports.isHttp = function isHttp (path) {
130
147
  }
131
148
  else if (protocol === undefined) {
132
149
  // There is no protocol. If we're running in a browser, then assume it's HTTP.
133
- return process.browser;
150
+ return typeof window !== "undefined";
134
151
  }
135
152
  else {
136
153
  // It's some other protocol, such as "ftp://", "mongodb://", etc.
@@ -176,7 +193,14 @@ exports.fromFileSystemPath = function fromFileSystemPath (path) {
176
193
  // Step 1: On Windows, replace backslashes with forward slashes,
177
194
  // rather than encoding them as "%5C"
178
195
  if (isWindows) {
179
- path = path.replace(/\\/g, "/");
196
+ const hasProjectDir = path.toUpperCase().includes(projectDir.replace(/\\/g, "\\").toUpperCase());
197
+ const hasProjectUri = path.toUpperCase().includes(projectDir.replace(/\\/g, "/").toUpperCase());
198
+ if (hasProjectDir || hasProjectUri) {
199
+ path = path.replace(/\\/g, "/");
200
+ }
201
+ else {
202
+ path = `${projectDir}/${path}`.replace(/\\/g, "/");
203
+ }
180
204
  }
181
205
 
182
206
  // Step 2: `encodeURI` will take care of MOST characters
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@apidevtools/json-schema-ref-parser",
3
- "version": "9.1.0",
3
+ "version": "9.1.1",
4
4
  "description": "Parse, Resolve, and Dereference JSON Schema $ref pointers",
5
5
  "keywords": [
6
6
  "json",
@@ -21,6 +21,10 @@
21
21
  "name": "Boris Cherny",
22
22
  "email": "boris@performancejs.com"
23
23
  },
24
+ {
25
+ "name": "Phil Sturgeon",
26
+ "email": "phil@apisyouwonthate.com"
27
+ },
24
28
  {
25
29
  "name": "Jakub Rożek",
26
30
  "email": "jakub@stoplight.io"
@@ -32,11 +36,15 @@
32
36
  "url": "https://github.com/APIDevTools/json-schema-ref-parser.git"
33
37
  },
34
38
  "license": "MIT",
39
+ "funding": "https://github.com/sponsors/philsturgeon",
35
40
  "main": "lib/index.js",
36
41
  "typings": "lib/index.d.ts",
37
42
  "browser": {
38
43
  "fs": false
39
44
  },
45
+ "engines": {
46
+ "node": ">= 17"
47
+ },
40
48
  "files": [
41
49
  "lib"
42
50
  ],
@@ -46,7 +54,7 @@
46
54
  "lint": "eslint lib test/fixtures test/specs",
47
55
  "test": "npm run test:node && npm run test:typescript && npm run test:browser && npm run lint",
48
56
  "test:node": "mocha",
49
- "test:browser": "karma start --single-run",
57
+ "test:browser": "cross-env NODE_OPTIONS=--openssl-legacy-provider karma start --single-run",
50
58
  "test:typescript": "tsc --noEmit --strict --lib esnext,dom test/specs/typescript-definition.spec.ts",
51
59
  "coverage": "npm run coverage:node && npm run coverage:browser",
52
60
  "coverage:node": "nyc node_modules/mocha/bin/mocha",
@@ -54,18 +62,22 @@
54
62
  "upgrade": "npm-check -u && npm audit fix"
55
63
  },
56
64
  "devDependencies": {
57
- "@amanda-mitchell/semantic-release-npm-multiple": "^2.5.0",
58
65
  "@babel/polyfill": "^7.12.1",
66
+ "@chiragrupani/karma-chromium-edge-launcher": "^2.2.2",
59
67
  "@jsdevtools/eslint-config": "^1.0.7",
60
68
  "@jsdevtools/host-environment": "^2.1.2",
61
69
  "@jsdevtools/karma-config": "^3.1.7",
62
70
  "@types/node": "^14.14.21",
63
- "chai-subset": "^1.6.0",
64
71
  "chai": "^4.2.0",
72
+ "chai-subset": "^1.6.0",
73
+ "chokidar": "^3.5.3",
74
+ "cross-env": "^7.0.3",
65
75
  "eslint": "^7.18.0",
66
- "karma-cli": "^2.0.0",
76
+ "isomorphic-fetch": "^3.0.0",
67
77
  "karma": "^5.0.2",
78
+ "karma-cli": "^2.0.0",
68
79
  "mocha": "^8.2.1",
80
+ "node-abort-controller": "^3.0.1",
69
81
  "npm-check": "^5.9.0",
70
82
  "nyc": "^15.0.1",
71
83
  "semantic-release-plugin-update-version-in-files": "^1.1.0",
@@ -80,8 +92,7 @@
80
92
  },
81
93
  "release": {
82
94
  "branches": [
83
- "main",
84
- "v9"
95
+ "main"
85
96
  ],
86
97
  "plugins": [
87
98
  "@semantic-release/commit-analyzer",
@@ -95,19 +106,7 @@
95
106
  "placeholder": "X.X.X"
96
107
  }
97
108
  ],
98
- [
99
- "@amanda-mitchell/semantic-release-npm-multiple",
100
- {
101
- "registries": {
102
- "scoped": {
103
- "pkgRoot": "."
104
- },
105
- "unscoped": {
106
- "pkgRoot": "dist"
107
- }
108
- }
109
- }
110
- ],
109
+ "@semantic-release/npm",
111
110
  "@semantic-release/github"
112
111
  ]
113
112
  }