Skip to content

Commit

Permalink
minimum repro of bundle error for bug with json schema validator site
Browse files Browse the repository at this point in the history
  • Loading branch information
jonluca committed Apr 22, 2024
1 parent e4ecbc5 commit adc3983
Show file tree
Hide file tree
Showing 7 changed files with 112 additions and 546 deletions.
Binary file modified .yarn/install-state.gz
Binary file not shown.
65 changes: 49 additions & 16 deletions lib/bundle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,20 @@ import type $RefParser from "./index";
import type { ParserOptions } from "./index";
import type { JSONSchema } from "./index";

export interface InventoryEntry {
$ref: any;
parent: any;
key: any;
pathFromRoot: any;
depth: any;
file: any;
hash: any;
value: any;
circular: any;
extended: any;
external: any;
indirections: any;
}
/**
* Bundles all external JSON references into the main JSON schema, thus resulting in a schema that
* only has *internal* references, not any *external* references.
Expand All @@ -21,7 +35,7 @@ function bundle<S extends object = JSONSchema, O extends ParserOptions<S> = Pars
// 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 = [];
const inventory: InventoryEntry[] = [];
crawl<S, O>(parser, "schema", parser.$refs._root$Ref.path + "#", "#", 0, inventory, parser.$refs, options);

// Remap all $ref pointers
Expand All @@ -41,16 +55,16 @@ function bundle<S extends object = JSONSchema, O extends ParserOptions<S> = Pars
* @param options
*/
function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(
parent: any,
parent: object | $RefParser<S, O>,
key: string | null,
path: string,
pathFromRoot: string,
indirections: number,
inventory: unknown[],
inventory: InventoryEntry[],
$refs: $Refs<S, O>,
options: O,
) {
const obj = key === null ? parent : parent[key];
const obj = key === null ? parent : parent[key as keyof typeof parent];

if (obj && typeof obj === "object" && !ArrayBuffer.isView(obj)) {
if ($Ref.isAllowed$Ref(obj)) {
Expand All @@ -71,7 +85,7 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
// This produces the shortest possible bundled references
return a.length - b.length;
}
});
}) as (keyof typeof obj)[];

// eslint-disable-next-line no-shadow
for (const key of keys) {
Expand Down Expand Up @@ -104,11 +118,11 @@ function crawl<S extends object = JSONSchema, O extends ParserOptions<S> = Parse
*/
function inventory$Ref<S extends object = JSONSchema, O extends ParserOptions<S> = ParserOptions<S>>(
$refParent: any,
$refKey: any,
$refKey: string | null,
path: string,
pathFromRoot: any,
indirections: any,
inventory: any,
pathFromRoot: string,
indirections: number,
inventory: InventoryEntry[],
$refs: $Refs<S, O>,
options: O,
) {
Expand All @@ -118,7 +132,8 @@ function inventory$Ref<S extends object = JSONSchema, O extends ParserOptions<S>
if (pointer === null) {
return;
}
const depth = Pointer.parse(pathFromRoot).length;
const parsed = Pointer.parse(pathFromRoot);
const depth = parsed.length;
const file = url.stripHash(pointer.path);
const hash = url.getHash(pointer.path);
const external = file !== $refs._root$Ref.path;
Expand Down Expand Up @@ -178,9 +193,9 @@ function inventory$Ref<S extends object = JSONSchema, O extends ParserOptions<S>
*
* @param inventory
*/
function remap(inventory: any) {
function remap(inventory: InventoryEntry[]) {
// Group & sort all the $ref pointers, so they're in the order that we need to dereference/remap them
inventory.sort((a: any, b: any) => {
inventory.sort((a: InventoryEntry, b: InventoryEntry) => {
if (a.file !== b.file) {
// Group all the $refs that point to the same file
return a.file < b.file ? -1 : +1;
Expand Down Expand Up @@ -243,23 +258,41 @@ function remap(inventory: any) {
entry.$ref.$ref = entry.pathFromRoot;
}
}

// console.log(' new value: %s', (entry.$ref && entry.$ref.$ref) ? entry.$ref.$ref : '[object Object]');
}

// we want to ensure that any $refs that point to another $ref are remapped to point to the final value
// let hadChange = true;
// while (hadChange) {
// hadChange = false;
// for (const entry of inventory) {
// if (entry.$ref && typeof entry.$ref === "object" && "$ref" in entry.$ref) {
// const resolved = inventory.find((e: InventoryEntry) => e.pathFromRoot === entry.$ref.$ref);
// if (resolved) {
// const resolvedPointsToAnotherRef =
// resolved.$ref && typeof resolved.$ref === "object" && "$ref" in resolved.$ref;
// if (resolvedPointsToAnotherRef && entry.$ref.$ref !== resolved.$ref.$ref) {
// // console.log('Re-mapping $ref pointer "%s" at %s', entry.$ref.$ref, entry.pathFromRoot);
// entry.$ref.$ref = resolved.$ref.$ref;
// hadChange = true;
// }
// }
// }
// }
// }
}

/**
* TODO
*/
function findInInventory(inventory: any, $refParent: any, $refKey: any) {
function findInInventory(inventory: InventoryEntry[], $refParent: any, $refKey: any) {
for (const existingEntry of inventory) {
if (existingEntry && existingEntry.parent === $refParent && existingEntry.key === $refKey) {
return existingEntry;
}
}
}

function removeFromInventory(inventory: any, entry: any) {
function removeFromInventory(inventory: InventoryEntry[], entry: any) {
const index = inventory.indexOf(entry);
inventory.splice(index, 1);
}
Expand Down
8 changes: 0 additions & 8 deletions test/specs/bundle/bundle.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,20 +3,12 @@ import { expect } from "vitest";
import $RefParser from "../../../lib/index.js";
import path from "../../utils/path";
import dereferencedSchema from "./bundled";
import Ajv from "ajv";
import addFormats from "ajv-formats";

describe("Bundles", () => {
it("should bundle correctly", async () => {
const parser = new $RefParser();
const schema = path.rel("test/specs/bundle/schemaA.json");
const bundled = await parser.bundle(schema);
const derefed = await parser.dereference(bundled);
const ajv = new Ajv();
addFormats(ajv);

const compiled = ajv.compile(derefed);
const compiledDerefed = ajv.compile(bundled);
expect(bundled).to.deep.equal(dereferencedSchema);
});
});
Loading

0 comments on commit adc3983

Please sign in to comment.