fork of hey-api/openapi-ts because I need some additional things
1import { Ono } from '@jsdevtools/ono';
2
3import type { $RefParser } from '..';
4import type $Ref from '../ref';
5import type { JSONSchema } from '../types';
6import { getHash, stripHash, toFileSystemPath } from './url';
7
8export type JSONParserErrorType =
9 | 'EUNKNOWN'
10 | 'EPARSER'
11 | 'EUNMATCHEDPARSER'
12 | 'ETIMEOUT'
13 | 'ERESOLVER'
14 | 'EUNMATCHEDRESOLVER'
15 | 'EMISSINGPOINTER'
16 | 'EINVALIDPOINTER';
17
18export class JSONParserError extends Error {
19 public readonly name: string;
20 public readonly message: string;
21 public source: string | undefined;
22 public path: Array<string | number> | null;
23 public readonly code: JSONParserErrorType;
24 public constructor(message: string, source?: string) {
25 super();
26
27 this.code = 'EUNKNOWN';
28 this.name = 'JSONParserError';
29 this.message = message;
30 this.source = source;
31 this.path = null;
32
33 Ono.extend(this);
34 }
35
36 get footprint() {
37 return `${this.path}+${this.source}+${this.code}+${this.message}`;
38 }
39}
40
41export class JSONParserErrorGroup<S extends object = JSONSchema> extends Error {
42 files: $RefParser;
43
44 constructor(parser: $RefParser) {
45 super();
46
47 this.files = parser;
48 this.name = 'JSONParserErrorGroup';
49 this.message = `${this.errors.length} error${
50 this.errors.length > 1 ? 's' : ''
51 } occurred while reading '${toFileSystemPath(parser.$refs._root$Ref!.path)}'`;
52
53 Ono.extend(this);
54 }
55
56 static getParserErrors<S extends object = JSONSchema>(parser: $RefParser) {
57 const errors = [];
58
59 for (const $ref of Object.values(parser.$refs._$refs) as $Ref<S>[]) {
60 if ($ref.errors) {
61 errors.push(...$ref.errors);
62 }
63 }
64
65 return errors;
66 }
67
68 get errors(): Array<
69 | JSONParserError
70 | InvalidPointerError
71 | ResolverError
72 | ParserError
73 | MissingPointerError
74 | UnmatchedParserError
75 | UnmatchedResolverError
76 > {
77 return JSONParserErrorGroup.getParserErrors<S>(this.files);
78 }
79}
80
81export class ParserError extends JSONParserError {
82 code = 'EPARSER' as JSONParserErrorType;
83 name = 'ParserError';
84 constructor(message: any, source: any) {
85 super(`Error parsing ${source}: ${message}`, source);
86 }
87}
88
89export class UnmatchedParserError extends JSONParserError {
90 code = 'EUNMATCHEDPARSER' as JSONParserErrorType;
91 name = 'UnmatchedParserError';
92
93 constructor(source: string) {
94 super(`Could not find parser for "${source}"`, source);
95 }
96}
97
98export class ResolverError extends JSONParserError {
99 code = 'ERESOLVER' as JSONParserErrorType;
100 name = 'ResolverError';
101 ioErrorCode?: string;
102 constructor(ex: Error | any, source?: string) {
103 super(ex.message || `Error reading file "${source}"`, source);
104 if ('code' in ex) {
105 this.ioErrorCode = String(ex.code);
106 }
107 }
108}
109
110export class UnmatchedResolverError extends JSONParserError {
111 code = 'EUNMATCHEDRESOLVER' as JSONParserErrorType;
112 name = 'UnmatchedResolverError';
113 constructor(source: any) {
114 super(`Could not find resolver for "${source}"`, source);
115 }
116}
117
118export class MissingPointerError extends JSONParserError {
119 code = 'EMISSINGPOINTER' as JSONParserErrorType;
120 name = 'MissingPointerError';
121 constructor(token: string, path: string) {
122 super(
123 `Missing $ref pointer "${getHash(path)}". Token "${token}" does not exist.`,
124 stripHash(path),
125 );
126 }
127}
128
129export class TimeoutError extends JSONParserError {
130 code = 'ETIMEOUT' as JSONParserErrorType;
131 name = 'TimeoutError';
132 constructor(timeout: number) {
133 super(`Dereferencing timeout reached: ${timeout}ms`);
134 }
135}
136
137export class InvalidPointerError extends JSONParserError {
138 code = 'EUNMATCHEDRESOLVER' as JSONParserErrorType;
139 name = 'InvalidPointerError';
140 constructor(pointer: string, path: string) {
141 super(`Invalid $ref pointer "${pointer}". Pointers must begin with "#/"`, stripHash(path));
142 }
143}
144
145export function isHandledError(err: any): err is JSONParserError {
146 return err instanceof JSONParserError || err instanceof JSONParserErrorGroup;
147}
148
149export function normalizeError(err: any) {
150 if (err.path === null) {
151 err.path = [];
152 }
153
154 return err;
155}