@@ -62,9 +62,108 @@ function validateDefinition(name, strategy) {
6262 }
6363}
6464
65+ //-----------------------------------------------------------------------------
66+ // Errors
67+ //-----------------------------------------------------------------------------
68+
69+ /**
70+ * Error when an unexpected key is found.
71+ */
72+ class UnexpectedKeyError extends Error {
73+
74+ /**
75+ * Creates a new instance.
76+ * @param {string } key The key that was unexpected.
77+ */
78+ constructor ( key ) {
79+ super ( `Unexpected key "${ key } " found.` ) ;
80+ }
81+ }
82+
83+ /**
84+ * Error when a required key is missing.
85+ */
86+ class MissingKeyError extends Error {
87+
88+ /**
89+ * Creates a new instance.
90+ * @param {string } key The key that was missing.
91+ */
92+ constructor ( key ) {
93+ super ( `Missing required key "${ key } ".` ) ;
94+ }
95+ }
96+
97+ /**
98+ * Error when a key requires other keys that are missing.
99+ */
100+ class MissingDependentKeysError extends Error {
101+
102+ /**
103+ * Creates a new instance.
104+ * @param {string } key The key that was unexpected.
105+ * @param {Array<string> } requiredKeys The keys that are required.
106+ */
107+ constructor ( key , requiredKeys ) {
108+ super ( `Key "${ key } " requires keys "${ requiredKeys . join ( "\", \"" ) } ".` ) ;
109+ }
110+ }
111+
112+ /**
113+ * Wrapper error for errors occuring during a merge or validate operation.
114+ */
115+ class WrapperError extends Error {
116+
117+ /**
118+ * Creates a new instance.
119+ * @param {string } key The object key causing the error.
120+ * @param {Error } source The source error.
121+ */
122+ constructor ( key , source ) {
123+ super ( `Key "${ key } ": ` + source . message ) ;
124+
125+ /**
126+ * The original source error.
127+ * @type {Error }
128+ */
129+ this . source = source ;
130+ }
131+
132+ /**
133+ * The stack from the original error.
134+ * @returns {string }
135+ */
136+ get stack ( ) {
137+ return this . source . stack ;
138+ }
139+
140+ /**
141+ * The line number from the original error.
142+ * @returns {number }
143+ */
144+ get lineNumber ( ) {
145+ return this . source . lineNumber ;
146+ }
147+
148+ /**
149+ * The column number from the original error.
150+ * @returns {number }
151+ */
152+ get columnNumber ( ) {
153+ return this . source . columnNumber ;
154+ }
155+
156+ /**
157+ * The filename from the original error.
158+ * @returns {string }
159+ */
160+ get fileName ( ) {
161+ return this . source . fileName ;
162+ }
163+ }
65164
66165//-----------------------------------------------------------------------------
67- // Class
166+ // Main
68167//-----------------------------------------------------------------------------
69168
70169/**
@@ -159,11 +258,11 @@ class ObjectSchema {
159258
160259 // double check arguments
161260 if ( objects . length < 2 ) {
162- throw new Error ( "merge() requires at least two arguments." ) ;
261+ throw new TypeError ( "merge() requires at least two arguments." ) ;
163262 }
164263
165264 if ( objects . some ( object => ( object == null || typeof object !== "object" ) ) ) {
166- throw new Error ( "All arguments must be objects." ) ;
265+ throw new TypeError ( "All arguments must be objects." ) ;
167266 }
168267
169268 return objects . reduce ( ( result , object ) => {
@@ -179,8 +278,7 @@ class ObjectSchema {
179278 }
180279 }
181280 } catch ( ex ) {
182- ex . message = `Key "${ key } ": ` + ex . message ;
183- throw ex ;
281+ throw new WrapperError ( key , ex ) ;
184282 }
185283 }
186284 return result ;
@@ -200,7 +298,7 @@ class ObjectSchema {
200298
201299 // check to see if the key is defined
202300 if ( ! this . hasKey ( key ) ) {
203- throw new Error ( `Unexpected key " ${ key } " found.` ) ;
301+ throw new UnexpectedKeyError ( key ) ;
204302 }
205303
206304 // validate existing keys
@@ -209,23 +307,22 @@ class ObjectSchema {
209307 // first check to see if any other keys are required
210308 if ( Array . isArray ( strategy . requires ) ) {
211309 if ( ! strategy . requires . every ( otherKey => otherKey in object ) ) {
212- throw new Error ( `Key " ${ key } " requires keys " ${ strategy . requires . join ( "\", \"" ) } ".` ) ;
310+ throw new MissingDependentKeysError ( key , strategy . requires ) ;
213311 }
214312 }
215313
216314 // now apply remaining validation strategy
217315 try {
218316 strategy . validate . call ( strategy , object [ key ] ) ;
219317 } catch ( ex ) {
220- ex . message = `Key "${ key } ": ` + ex . message ;
221- throw ex ;
318+ throw new WrapperError ( key , ex ) ;
222319 }
223320 }
224321
225322 // ensure required keys aren't missing
226323 for ( const [ key ] of this [ requiredKeys ] ) {
227324 if ( ! ( key in object ) ) {
228- throw new Error ( `Missing required key " ${ key } ".` ) ;
325+ throw new MissingKeyError ( key ) ;
229326 }
230327 }
231328
0 commit comments