Skip to content

Commit

Permalink
feat(generics): introduce generics for the input schema and the options
Browse files Browse the repository at this point in the history
  • Loading branch information
jonluca committed Mar 6, 2024
1 parent bdb426b commit 565068b
Show file tree
Hide file tree
Showing 23 changed files with 393 additions and 292 deletions.
42 changes: 23 additions & 19 deletions lib/bundle.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import $Ref from "./ref.js";
import Pointer from "./pointer.js";
import * as url from "./util/url.js";
import type $RefParserOptions from "./options.js";
import type $Refs from "./refs.js";

export default bundle;
import type $RefParser from "./index";
import type { ParserOptions } from "./index";
import type { JSONSchema } from "./index";

/**
* Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
Expand All @@ -14,12 +14,15 @@ export default bundle;
* @param parser
* @param options
*/
function bundle(parser: any, options: any) {
function bundle<S extends JSONSchema = JSONSchema, O extends ParserOptions = ParserOptions>(
parser: $RefParser<S, O>,
options: O,
) {
// console.log('Bundling $ref pointers in %s', parser.$refs._root$Ref.path);

// Build an inventory of all $ref pointers in the JSON Schema
const inventory: any = [];
crawl(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);
crawl<S, O>(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);

// Remap all $ref pointers
remap(inventory);
Expand All @@ -32,19 +35,20 @@ function bundle(parser: any, options: any) {
* @param key - The property key of `parent` to be crawled
* @param path - The full path of the property being crawled, possibly with a JSON Pointer in the hash
* @param pathFromRoot - The path of the property being crawled, from the schema root
* @param indirections
* @param inventory - An array of already-inventoried $ref pointers
* @param $refs
* @param options
*/
function crawl(
function crawl<S, O>(
parent: any,
key: any,
path: any,
pathFromRoot: any,
indirections: any,
inventory: any,
$refs: any,
options: any,
key: string | null,
path: string,
pathFromRoot: string,
indirections: number,
inventory: unknown[],
$refs: $Refs<S>,
options: O,
) {
const obj = key === null ? parent : parent[key];

Expand Down Expand Up @@ -98,15 +102,15 @@ function crawl(
* @param $refs
* @param options
*/
function inventory$Ref(
function inventory$Ref<S, O>(
$refParent: any,
$refKey: any,
path: string,
pathFromRoot: any,
indirections: any,
inventory: any,
$refs: $Refs,
options: $RefParserOptions,
$refs: $Refs<S>,
options: O,
) {
const $ref = $refKey === null ? $refParent : $refParent[$refKey];
const $refPath = url.resolve(path, $ref.$ref);
Expand Down Expand Up @@ -248,9 +252,8 @@ function remap(inventory: any) {
* TODO
*/
function findInInventory(inventory: any, $refParent: any, $refKey: any) {
for (let i = 0; i < inventory.length; i++) {
const existingEntry = inventory[i];
if (existingEntry.parent === $refParent && existingEntry.key === $refKey) {
for (const existingEntry of inventory) {
if (existingEntry && existingEntry.parent === $refParent && existingEntry.key === $refKey) {
return existingEntry;
}
}
Expand All @@ -260,3 +263,4 @@ function removeFromInventory(inventory: any, entry: any) {
const index = inventory.indexOf(entry);
inventory.splice(index, 1);
}
export default bundle;
38 changes: 21 additions & 17 deletions lib/dereference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ import Pointer from "./pointer.js";
import { ono } from "@jsdevtools/ono";
import * as url from "./util/url.js";
import type $Refs from "./refs.js";
import type $RefParserOptions from "./options.js";
import type { DereferenceOptions, ParserOptions } from "./options.js";
import type { JSONSchema } from "./types";
import type $RefParser from "./index";

export default dereference;

Expand All @@ -14,11 +16,14 @@ export default dereference;
* @param parser
* @param options
*/
function dereference(parser: any, options: any) {
function dereference<S extends JSONSchema = JSONSchema, O extends ParserOptions = ParserOptions>(
parser: $RefParser<S, O>,
options: O,
) {
// console.log('Dereferencing $ref pointers in %s', parser.$refs._root$Ref.path);
const dereferenced = crawl(
const dereferenced = crawl<S, O>(
parser.schema,
parser.$refs._root$Ref.path,
parser.$refs._root$Ref.path!,
"#",
new Set(),
new Set(),
Expand All @@ -43,25 +48,26 @@ function dereference(parser: any, options: any) {
* @param options
* @returns
*/
function crawl(
function crawl<S extends JSONSchema = JSONSchema, O extends ParserOptions = ParserOptions>(
obj: any,
path: string,
pathFromRoot: string,
parents: Set<any>,
processedObjects: Set<any>,
dereferencedCache: any,
$refs: $Refs,
options: $RefParserOptions,
$refs: $Refs<S>,
options: O,
) {
let dereferenced;
const result = {
value: obj,
circular: false,
};

const isExcludedPath = options.dereference.excludedPathMatcher || (() => false);
const derefOptions = (options.dereference || {}) as DereferenceOptions;
const isExcludedPath = derefOptions.excludedPathMatcher || (() => false);

if (options.dereference.circular === "ignore" || !processedObjects.has(obj)) {
if (derefOptions?.circular === "ignore" || !processedObjects.has(obj)) {
if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj) && !isExcludedPath(pathFromRoot)) {
parents.add(obj);
processedObjects.add(obj);
Expand Down Expand Up @@ -106,9 +112,7 @@ function crawl(
// Avoid pointless mutations; breaks frozen objects to no profit
if (obj[key] !== dereferenced.value) {
obj[key] = dereferenced.value;
if (options.dereference.onDereference) {
options.dereference.onDereference(value.$ref, obj[key], obj, key);
}
derefOptions?.onDereference?.(value.$ref, obj[key], obj, key);
}
} else {
if (!parents.has(value)) {
Expand Down Expand Up @@ -157,18 +161,18 @@ function crawl(
* @param options
* @returns
*/
function dereference$Ref(
function dereference$Ref<S extends JSONSchema = JSONSchema, O extends ParserOptions = ParserOptions>(
$ref: any,
path: string,
pathFromRoot: string,
parents: Set<any>,
processedObjects: any,
dereferencedCache: any,
$refs: $Refs,
options: $RefParserOptions,
$refs: $Refs<S>,
options: O,
) {
const isExternalRef = $Ref.isExternal$Ref($ref);
const shouldResolveOnCwd = isExternalRef && options?.dereference.externalReferenceResolution === "root";
const shouldResolveOnCwd = isExternalRef && options?.dereference?.externalReferenceResolution === "root";
const $refPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref);

const cache = dereferencedCache.get($refPath);
Expand Down Expand Up @@ -225,7 +229,7 @@ function dereference$Ref(
dereferencedValue = dereferenced.value;
}

if (circular && !directCircular && options.dereference.circular === "ignore") {
if (circular && !directCircular && options.dereference?.circular === "ignore") {
// The user has chosen to "ignore" circular references, so don't change the value
dereferencedValue = $ref;
}
Expand Down

0 comments on commit 565068b

Please sign in to comment.