From 7a8806da56a852e28df66d45a2238faa5b3bcf84 Mon Sep 17 00:00:00 2001 From: JonLuca DeCaro Date: Wed, 6 Mar 2024 15:55:08 -0800 Subject: [PATCH] fix(types): make default type extend base object instead of JSONSchema to support non-spec compliant type overloads --- lib/bundle.ts | 6 ++-- lib/dereference.ts | 6 ++-- lib/index.ts | 64 ++++++++++++++++++++--------------------- lib/normalize-args.ts | 4 +-- lib/options.ts | 8 +++--- lib/parse.ts | 6 ++-- lib/pointer.ts | 6 ++-- lib/ref.ts | 6 ++-- lib/refs.ts | 6 ++-- lib/resolve-external.ts | 8 +++--- lib/resolvers/http.ts | 4 +-- lib/types/index.ts | 8 +++--- lib/util/errors.ts | 4 +-- lib/util/plugins.ts | 8 +++--- test/specs/refs.spec.ts | 2 -- test/utils/helper.ts | 2 -- 16 files changed, 72 insertions(+), 76 deletions(-) diff --git a/lib/bundle.ts b/lib/bundle.ts index d5aff2b7..3f8d4fde 100644 --- a/lib/bundle.ts +++ b/lib/bundle.ts @@ -14,7 +14,7 @@ import type { JSONSchema } from "./index"; * @param parser * @param options */ -function bundle = ParserOptions>( +function bundle = ParserOptions>( parser: $RefParser, options: O, ) { @@ -40,7 +40,7 @@ function bundle = * @param $refs * @param options */ -function crawl = ParserOptions>( +function crawl = ParserOptions>( parent: any, key: string | null, path: string, @@ -102,7 +102,7 @@ function crawl = P * @param $refs * @param options */ -function inventory$Ref = ParserOptions>( +function inventory$Ref = ParserOptions>( $refParent: any, $refKey: any, path: string, diff --git a/lib/dereference.ts b/lib/dereference.ts index c767bad2..928613b4 100644 --- a/lib/dereference.ts +++ b/lib/dereference.ts @@ -16,7 +16,7 @@ export default dereference; * @param parser * @param options */ -function dereference = ParserOptions>( +function dereference = ParserOptions>( parser: $RefParser, options: O, ) { @@ -48,7 +48,7 @@ function dereference = ParserOptions>( +function crawl = ParserOptions>( obj: any, path: string, pathFromRoot: string, @@ -161,7 +161,7 @@ function crawl = P * @param options * @returns */ -function dereference$Ref = ParserOptions>( +function dereference$Ref = ParserOptions>( $ref: any, path: string, pathFromRoot: string, diff --git a/lib/index.ts b/lib/index.ts index 103ea726..4542506c 100644 --- a/lib/index.ts +++ b/lib/index.ts @@ -37,7 +37,7 @@ export type RefParserSchema = string | JSONSchema; * * @class */ -export class $RefParser = ParserOptions> { +export class $RefParser = ParserOptions> { /** * The parsed (and possibly dereferenced) JSON schema object * @@ -94,10 +94,10 @@ export class $RefParser = ParserOptions>( + public static parse = ParserOptions>( schema: S | string, ): Promise; - public static parse = ParserOptions>( + public static parse = ParserOptions>( schema: S | string, callback: SchemaCallback, ): Promise; - public static parse = ParserOptions>( + public static parse = ParserOptions>( schema: S | string, options: O, ): Promise; - public static parse = ParserOptions>( + public static parse = ParserOptions>( schema: S | string, options: O, callback: SchemaCallback, ): Promise; - public static parse = ParserOptions>( + public static parse = ParserOptions>( baseUrl: string, schema: S | string, options: O, ): Promise; - public static parse = ParserOptions>( + public static parse = ParserOptions>( baseUrl: string, schema: S | string, options: O, callback: SchemaCallback, ): Promise; - public static parse = ParserOptions>(): + public static parse = ParserOptions>(): | Promise | Promise { const parser = new $RefParser(); @@ -218,34 +218,34 @@ export class $RefParser = ParserOptions>( + public static resolve = ParserOptions>( schema: S | string, ): Promise<$Refs>; - public static resolve = ParserOptions>( + public static resolve = ParserOptions>( schema: S | string, callback: $RefsCallback, ): Promise; - public static resolve = ParserOptions>( + public static resolve = ParserOptions>( schema: S | string, options: O, ): Promise<$Refs>; - public static resolve = ParserOptions>( + public static resolve = ParserOptions>( schema: S | string, options: O, callback: $RefsCallback, ): Promise; - public static resolve = ParserOptions>( + public static resolve = ParserOptions>( baseUrl: string, schema: S | string, options: O, ): Promise<$Refs>; - public static resolve = ParserOptions>( + public static resolve = ParserOptions>( baseUrl: string, schema: S | string, options: O, callback: $RefsCallback, ): Promise; - static resolve = ParserOptions>(): + static resolve = ParserOptions>(): | Promise | Promise { const instance = new $RefParser(); @@ -263,34 +263,34 @@ export class $RefParser = ParserOptions>( + public static bundle = ParserOptions>( schema: S | string, ): Promise; - public static bundle = ParserOptions>( + public static bundle = ParserOptions>( schema: S | string, callback: SchemaCallback, ): Promise; - public static bundle = ParserOptions>( + public static bundle = ParserOptions>( schema: S | string, options: O, ): Promise; - public static bundle = ParserOptions>( + public static bundle = ParserOptions>( schema: S | string, options: O, callback: SchemaCallback, ): Promise; - public static bundle = ParserOptions>( + public static bundle = ParserOptions>( baseUrl: string, schema: S | string, options: O, ): Promise; - public static bundle = ParserOptions>( + public static bundle = ParserOptions>( baseUrl: string, schema: S | string, options: O, callback: SchemaCallback, ): Promise; - static bundle = ParserOptions>(): + static bundle = ParserOptions>(): | Promise | Promise { const instance = new $RefParser(); @@ -337,34 +337,34 @@ export class $RefParser = ParserOptions>( + public static dereference = ParserOptions>( schema: S | string, ): Promise; - public static dereference = ParserOptions>( + public static dereference = ParserOptions>( schema: S | string, callback: SchemaCallback, ): Promise; - public static dereference = ParserOptions>( + public static dereference = ParserOptions>( schema: S | string, options: O, ): Promise; - public static dereference = ParserOptions>( + public static dereference = ParserOptions>( schema: S | string, options: O, callback: SchemaCallback, ): Promise; - public static dereference = ParserOptions>( + public static dereference = ParserOptions>( baseUrl: string, schema: S | string, options: O, ): Promise; - public static dereference = ParserOptions>( + public static dereference = ParserOptions>( baseUrl: string, schema: S | string, options: O, callback: SchemaCallback, ): Promise; - static dereference = ParserOptions>(): + static dereference = ParserOptions>(): | Promise | Promise { const instance = new $RefParser(); @@ -404,7 +404,7 @@ export class $RefParser = ParserOptions>( +function finalize = ParserOptions>( parser: $RefParser, ) { const errors = JSONParserErrorGroup.getParserErrors(parser); diff --git a/lib/normalize-args.ts b/lib/normalize-args.ts index 6bdc43ea..c39f757b 100644 --- a/lib/normalize-args.ts +++ b/lib/normalize-args.ts @@ -4,7 +4,7 @@ import type { JSONSchema, SchemaCallback } from "./types"; // I really dislike this function and the way it's written. It's not clear what it's doing, and it's way too flexible // In the future, I'd like to deprecate the api and accept only named parameters in index.ts -export interface NormalizedArguments = ParserOptions> { +export interface NormalizedArguments = ParserOptions> { path: string; schema: S; options: O & Options; @@ -13,7 +13,7 @@ export interface NormalizedArguments = ParserOptions>( +export function normalizeArgs = ParserOptions>( _args: Partial, ): NormalizedArguments { let path; diff --git a/lib/options.ts b/lib/options.ts index 6a5b2c3a..f9638dc6 100644 --- a/lib/options.ts +++ b/lib/options.ts @@ -53,7 +53,7 @@ export interface DereferenceOptions { * @param [options] - Overridden options * @class */ -export interface $RefParserOptions { +export interface $RefParserOptions { /** * The `parse` options determine how different types of files will be parsed. * @@ -174,7 +174,7 @@ export const getJsonSchemaRefParserDefaultOptions = () => { return defaults; }; -export const getNewOptions = = ParserOptions>( +export const getNewOptions = = ParserOptions>( options: O | undefined, ): O & $RefParserOptions => { const newOptions = getJsonSchemaRefParserDefaultOptions(); @@ -184,8 +184,8 @@ export const getNewOptions = ; }; -export type Options = $RefParserOptions; -export type ParserOptions = DeepPartial<$RefParserOptions>; +export type Options = $RefParserOptions; +export type ParserOptions = DeepPartial<$RefParserOptions>; /** * Merges the properties of the source object into the target object. * diff --git a/lib/parse.ts b/lib/parse.ts index 6c9e1c01..66e048f8 100644 --- a/lib/parse.ts +++ b/lib/parse.ts @@ -15,7 +15,7 @@ import type { FileInfo, JSONSchema } from "./types/index.js"; /** * Reads and parses the specified file path or URL. */ -async function parse = ParserOptions>( +async function parse = ParserOptions>( path: string, $refs: $Refs, options: O, @@ -70,7 +70,7 @@ async function parse = ParserOptions>( +async function readFile = ParserOptions>( file: FileInfo, options: O, $refs: $Refs, @@ -116,7 +116,7 @@ async function readFile = ParserOptions>( +async function parseFile = ParserOptions>( file: FileInfo, options: O, $refs: $Refs, diff --git a/lib/pointer.ts b/lib/pointer.ts index acbc8cbd..df63415a 100644 --- a/lib/pointer.ts +++ b/lib/pointer.ts @@ -26,7 +26,7 @@ const safeDecodeURIComponent = (encodedURIComponent: string): string => { * @param [friendlyPath] - The original user-specified path (used for error messages) * @class */ -class Pointer = ParserOptions> { +class Pointer = ParserOptions> { /** * The {@link $Ref} object that contains this {@link Pointer} object. */ @@ -86,7 +86,7 @@ class Pointer = Pa * the {@link Pointer#$ref} and {@link Pointer#path} will reflect the resolution path * of the resolved value. */ - resolve(obj: any, options?: O, pathFromRoot?: string) { + resolve(obj: S, options?: O, pathFromRoot?: string) { const tokens = Pointer.parse(this.path, this.originalPath); // Crawl the object, one token at a time @@ -144,7 +144,7 @@ class Pointer = Pa * @returns * Returns the modified object, or an entirely new object if the entire object is overwritten. */ - set(obj: any, value: any, options?: O) { + set(obj: S, value: any, options?: O) { const tokens = Pointer.parse(this.path); let token; diff --git a/lib/ref.ts b/lib/ref.ts index ce549ddf..4d8240f7 100644 --- a/lib/ref.ts +++ b/lib/ref.ts @@ -13,7 +13,7 @@ export type $RefError = JSONParserError | ResolverError | ParserError | MissingP * * @class */ -class $Ref = ParserOptions> { +class $Ref = ParserOptions> { /** * The file path or URL of the referenced file. * This path is relative to the path of the main JSON schema file. @@ -185,7 +185,7 @@ class $Ref = Parse * @param options * @returns */ - static isAllowed$Ref(value: unknown, options?: ParserOptions) { + static isAllowed$Ref(value: unknown, options?: ParserOptions) { if (this.is$Ref(value)) { if (value.$ref.substring(0, 2) === "#/" || value.$ref === "#") { // It's a JSON Pointer reference, which is always allowed @@ -266,7 +266,7 @@ class $Ref = Parse * @param resolvedValue - The resolved value, which can be any type * @returns - Returns the dereferenced value */ - static dereference = ParserOptions>( + static dereference = ParserOptions>( $ref: $Ref, resolvedValue: S, ): S { diff --git a/lib/refs.ts b/lib/refs.ts index 67553f43..ea2a07c5 100644 --- a/lib/refs.ts +++ b/lib/refs.ts @@ -6,7 +6,7 @@ import type { ParserOptions } from "./options.js"; import convertPathToPosix from "./util/convert-path-to-posix"; import type { JSONSchema } from "./types"; -interface $RefsMap = ParserOptions> { +interface $RefsMap = ParserOptions> { [url: string]: $Ref; } /** @@ -16,7 +16,7 @@ interface $RefsMap * * See https://apitools.dev/json-schema-ref-parser/docs/refs.html */ -export default class $Refs = ParserOptions> { +export default class $Refs = ParserOptions> { /** * This property is true if the schema contains any circular references. You may want to check this property before serializing the dereferenced schema as JSON, since JSON.stringify() does not support circular references by default. * @@ -215,7 +215,7 @@ export default class $Refs = ParserOptions>( +function getPaths = ParserOptions>( $refs: $RefsMap, types: string[], ) { diff --git a/lib/resolve-external.ts b/lib/resolve-external.ts index ef7fb6a7..207d00cc 100644 --- a/lib/resolve-external.ts +++ b/lib/resolve-external.ts @@ -18,7 +18,7 @@ import type $RefParser from "./index.js"; * The promise resolves once all JSON references in the schema have been resolved, * including nested references that are contained in externally-referenced files. */ -function resolveExternal = ParserOptions>( +function resolveExternal = ParserOptions>( parser: $RefParser, options: O, ) { @@ -52,7 +52,7 @@ function resolveExternal = ParserOptions>( +function crawl = ParserOptions>( obj: string | Buffer | S | undefined | null, path: string, $refs: $Refs, @@ -92,14 +92,14 @@ function crawl = P * The promise resolves once all JSON references in the object have been resolved, * including nested references that are contained in externally-referenced files. */ -async function resolve$Ref = ParserOptions>( +async function resolve$Ref = ParserOptions>( $ref: S, path: string, $refs: $Refs, options: O, ) { const shouldResolveOnCwd = options.dereference?.externalReferenceResolution === "root"; - const resolvedPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, $ref.$ref!); + const resolvedPath = url.resolve(shouldResolveOnCwd ? url.cwd() : path, ($ref as JSONSchema).$ref!); const withoutHash = url.stripHash(resolvedPath); // $ref.$ref = url.relative($refs._root$Ref.path, resolvedPath); diff --git a/lib/resolvers/http.ts b/lib/resolvers/http.ts index faf8f569..36c9880d 100644 --- a/lib/resolvers/http.ts +++ b/lib/resolvers/http.ts @@ -66,7 +66,7 @@ export default { * @returns * The promise resolves with the raw downloaded data, or rejects if there is an HTTP error. */ -async function download( +async function download( u: URL | string, httpOptions: HTTPResolverOptions, _redirects?: string[], @@ -109,7 +109,7 @@ async function download( * Sends an HTTP GET request. * The promise resolves with the HTTP Response object. */ -async function get(u: RequestInfo | URL, httpOptions: HTTPResolverOptions) { +async function get(u: RequestInfo | URL, httpOptions: HTTPResolverOptions) { let controller: any; let timeoutId: any; if (httpOptions.timeout) { diff --git a/lib/types/index.ts b/lib/types/index.ts index 1e3a33df..e335f019 100644 --- a/lib/types/index.ts +++ b/lib/types/index.ts @@ -11,8 +11,8 @@ import type { ParserOptions } from "../options"; export type JSONSchema = JSONSchema4 | JSONSchema6 | JSONSchema7; export type JSONSchemaObject = JSONSchema4Object | JSONSchema6Object | JSONSchema7Object; -export type SchemaCallback = (err: Error | null, schema?: S | object | null) => any; -export type $RefsCallback = ParserOptions> = ( +export type SchemaCallback = (err: Error | null, schema?: S | object | null) => any; +export type $RefsCallback = ParserOptions> = ( err: Error | null, $refs?: $Refs, ) => any; @@ -21,7 +21,7 @@ export type $RefsCallback extends Partial> { +export interface HTTPResolverOptions extends Partial> { /** * You can specify any HTTP headers that should be sent when downloading files. For example, some servers may require you to set the `Accept` or `Referrer` header. */ @@ -48,7 +48,7 @@ export interface HTTPResolverOptions extends * * See https://apitools.dev/json-schema-ref-parser/docs/plugins/resolvers.html */ -export interface ResolverOptions { +export interface ResolverOptions { name?: string; /** * All resolvers have an order property, even the built-in resolvers. If you don't specify an order property, then your resolver will run last. Specifying `order: 1`, like we did in this example, will make your resolver run first. Or you can squeeze your resolver in-between some of the built-in resolvers. For example, `order: 101` would make it run after the file resolver, but before the HTTP resolver. You can see the order of all the built-in resolvers by looking at their source code. diff --git a/lib/util/errors.ts b/lib/util/errors.ts index 5d53b3a7..35d77307 100644 --- a/lib/util/errors.ts +++ b/lib/util/errors.ts @@ -38,7 +38,7 @@ export class JSONParserError extends Error { } export class JSONParserErrorGroup< - S extends JSONSchema = JSONSchema, + S extends object = JSONSchema, O extends ParserOptions = ParserOptions, > extends Error { files: $RefParser; @@ -55,7 +55,7 @@ export class JSONParserErrorGroup< Ono.extend(this); } - static getParserErrors = ParserOptions>( + static getParserErrors = ParserOptions>( parser: $RefParser, ) { const errors = []; diff --git a/lib/util/plugins.ts b/lib/util/plugins.ts index 6dfb1c60..f0d439a9 100644 --- a/lib/util/plugins.ts +++ b/lib/util/plugins.ts @@ -10,7 +10,7 @@ import type { Plugin } from "../types/index.js"; * * @returns */ -export function all = ParserOptions>( +export function all = ParserOptions>( plugins: O["resolve"], ): Plugin[] { return (Object.keys(plugins || {}) as (keyof ResolverOptions)[]) @@ -45,7 +45,7 @@ export function sort(plugins: Plugin[]) { }); } -export interface PluginResult = ParserOptions> { +export interface PluginResult = ParserOptions> { plugin: Plugin; result?: string | Buffer | S; error?: any; @@ -59,7 +59,7 @@ export interface PluginResult = ParserOptions>( +export async function run = ParserOptions>( plugins: Plugin[], method: keyof Plugin | keyof ResolverOptions, file: FileInfo, @@ -129,7 +129,7 @@ export async function run = ParserOptions>( +function getResult = ParserOptions>( obj: Plugin, prop: keyof Plugin | keyof ResolverOptions, file: FileInfo, diff --git a/test/specs/refs.spec.ts b/test/specs/refs.spec.ts index 802f698e..7817a5b9 100644 --- a/test/specs/refs.spec.ts +++ b/test/specs/refs.spec.ts @@ -48,7 +48,6 @@ describe("$Refs object", () => { it("should return only URLs", async () => { const $refs = await $RefParser.resolve(path.abs("test/specs/external/external.yaml")); - // @ts-expect-error TS(2345): Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message const paths = $refs.paths(["http"]); if (isBrowser) { @@ -141,7 +140,6 @@ describe("$Refs object", () => { it("should return only URLs and values", async () => { const $refs = await $RefParser.resolve(path.abs("test/specs/external/external.yaml")); - // @ts-expect-error TS(2345): Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message let values = $refs.values(["http"]); if (isBrowser) { const expected = {}; diff --git a/test/utils/helper.ts b/test/utils/helper.ts index 8abb9717..d6c123e4 100644 --- a/test/utils/helper.ts +++ b/test/utils/helper.ts @@ -40,11 +40,9 @@ const helper = { try { expect((actualFiles = $refs.paths())).to.have.same.members(expectedFiles); if (typeof window === "undefined") { - // @ts-expect-error TS(2345): Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message expect((actualFiles = $refs.paths(["file"]))).to.have.same.members(expectedFiles); expect($refs.paths("http")).to.be.an("array").with.lengthOf(0); } else { - // @ts-expect-error TS(2345): Argument of type 'string[]' is not assignable to p... Remove this comment to see the full error message expect((actualFiles = $refs.paths(["http"]))).to.have.same.members(expectedFiles); expect($refs.paths("file")).to.be.an("array").with.lengthOf(0); }