22
33const optionsSchema = require ( "./optionsSchema.json" ) ;
44
5- function OptionsValidationError ( validationErrors ) {
6- Error . call ( this ) ;
7- Error . captureStackTrace ( this , OptionsValidationError ) ;
8- this . name = "WebpackDevServerOptionsValidationError" ;
9- this . message = `${ "Invalid configuration object. " +
10- "webpack-dev-server has been initialised using a configuration object that does not match the API schema.\n" } ${
11- validationErrors . map ( function ( err ) {
12- return ` - ${ indent ( OptionsValidationError . formatValidationError ( err ) , " " , false ) } ` ;
13- } ) . join ( "\n" ) } `;
14- this . validationErrors = validationErrors ;
15- }
16- module . exports = OptionsValidationError ;
17-
18- OptionsValidationError . prototype = Object . create ( Error . prototype ) ;
19- OptionsValidationError . prototype . constructor = OptionsValidationError ;
20-
21- OptionsValidationError . formatValidationError = function formatValidationError ( err ) {
22- const dataPath = `configuration${ err . dataPath } ` ;
23- switch ( err . keyword ) {
24- case "additionalProperties" :
25- return `${ dataPath } has an unknown property '${ err . params . additionalProperty } '. These properties are valid:\n${
26- getSchemaPartText ( err . parentSchema ) } `;
27- case "oneOf" :
28- case "anyOf" :
29- case "enum" :
30- return `${ dataPath } should be one of these:\n${
31- getSchemaPartText ( err . parentSchema ) } `;
32- case "allOf" :
33- return `${ dataPath } should be:\n${
34- getSchemaPartText ( err . parentSchema ) } `;
35- case "type" :
36- switch ( err . params . type ) {
37- case "object" :
38- return `${ dataPath } should be an object.` ;
39- case "array" :
40- return `${ dataPath } should be an array.` ;
41- case "string" :
42- return `${ dataPath } should be a string.` ;
43- case "boolean" :
44- return `${ dataPath } should be a boolean.` ;
45- case "number" :
46- return `${ dataPath } should be a number.` ;
47- }
48- return `${ dataPath } should be ${ err . params . type } :\n${
49- getSchemaPartText ( err . parentSchema ) } `;
50- case "instanceof" :
51- return `${ dataPath } should be an instance of ${ getSchemaPartText ( err . parentSchema ) } .` ;
52- case "required" : // eslint-disable-line no-case-declarations
53- const missingProperty = err . params . missingProperty . replace ( / ^ \. / , "" ) ;
54- return `${ dataPath } misses the property '${ missingProperty } '.\n${
55- getSchemaPartText ( err . parentSchema , [ "properties" , missingProperty ] ) } `;
56- case "minLength" :
57- if ( err . params . limit === 1 )
58- return `${ dataPath } should not be empty.` ;
59- else
60- return `${ dataPath } ${ err . message } ` ;
61- default :
62- return `${ dataPath } ${ err . message } (${ JSON . stringify ( err , 0 , 2 ) } ).\n${
63- getSchemaPartText ( err . parentSchema ) } `;
64- }
65- }
66-
67- function getSchemaPart ( path , parents , additionalPath ) {
5+ const getSchemaPart = ( path , parents , additionalPath ) => {
686 parents = parents || 0 ;
697 path = path . split ( "/" ) ;
708 path = path . slice ( 0 , path . length - parents ) ;
@@ -79,9 +17,9 @@ function getSchemaPart(path, parents, additionalPath) {
7917 schemaPart = inner ;
8018 }
8119 return schemaPart ;
82- }
20+ } ;
8321
84- function getSchemaPartText ( schemaPart , additionalPath ) {
22+ const getSchemaPartText = ( schemaPart , additionalPath ) => {
8523 if ( additionalPath ) {
8624 for ( let i = 0 ; i < additionalPath . length ; i ++ ) {
8725 const inner = schemaPart [ additionalPath [ i ] ] ;
@@ -94,60 +32,128 @@ function getSchemaPartText(schemaPart, additionalPath) {
9432 if ( schemaPart . description )
9533 schemaText += `\n${ schemaPart . description } ` ;
9634 return schemaText ;
97- }
35+ } ;
9836
99- function formatSchema ( schema , prevSchemas ) {
100- prevSchemas = prevSchemas || [ ] ;
37+ const indent = ( str , prefix , firstLine ) => {
38+ if ( firstLine ) {
39+ return prefix + str . replace ( / \n (? ! $ ) / g, "\n" + prefix ) ;
40+ } else {
41+ return str . replace ( / \n (? ! $ ) / g, `\n${ prefix } ` ) ;
42+ }
43+ } ;
44+
45+ class OptionsValidationError extends Error {
46+
47+ constructor ( validationErrors ) {
48+ super ( ) ;
49+
50+ if ( Error . hasOwnProperty ( "captureStackTrace" ) ) {
51+ Error . captureStackTrace ( this , this . constructor ) ;
52+ }
53+ this . name = "WebpackDevServerOptionsValidationError" ;
10154
102- function formatInnerSchema ( innerSchema , addSelf ) {
103- if ( ! addSelf ) return formatSchema ( innerSchema , prevSchemas ) ;
104- if ( prevSchemas . indexOf ( innerSchema ) >= 0 ) return "(recursive)" ;
105- return formatSchema ( innerSchema , prevSchemas . concat ( schema ) ) ;
55+ this . message = "Invalid configuration object. " +
56+ "webpack-dev-server has been initialised using a configuration object that does not match the API schema.\n" +
57+ validationErrors . map ( err => " - " + indent ( OptionsValidationError . formatValidationError ( err ) , " " , false ) ) . join ( "\n" ) ;
58+ this . validationErrors = validationErrors ;
10659 }
107- switch ( schema . type ) {
108- case "string" :
60+
61+ static formatSchema ( schema , prevSchemas ) {
62+ prevSchemas = prevSchemas || [ ] ;
63+
64+ const formatInnerSchema = ( innerSchema , addSelf ) => {
65+ if ( ! addSelf ) return OptionsValidationError . formatSchema ( innerSchema , prevSchemas ) ;
66+ if ( prevSchemas . indexOf ( innerSchema ) >= 0 ) return "(recursive)" ;
67+ return OptionsValidationError . formatSchema ( innerSchema , prevSchemas . concat ( schema ) ) ;
68+ } ;
69+
70+ if ( schema . type === "string" ) {
71+ if ( schema . minLength === 1 )
72+ return "non-empty string" ;
73+ else if ( schema . minLength > 1 )
74+ return `string (min length ${ schema . minLength } )` ;
10975 return "string" ;
110- case "boolean" :
76+ } else if ( schema . type === "boolean" ) {
11177 return "boolean" ;
112- case "number" :
78+ } else if ( schema . type === "number" ) {
11379 return "number" ;
114- case "object" :
80+ } else if ( schema . type === "object" ) {
11581 if ( schema . properties ) {
11682 const required = schema . required || [ ] ;
117- return `object { ${ Object . keys ( schema . properties ) . map ( function ( property ) {
118- if ( required . indexOf ( property ) < 0 ) return ` ${ property } ?` ;
83+ return `object { ${ Object . keys ( schema . properties ) . map ( property => {
84+ if ( required . indexOf ( property ) < 0 ) return property + "?" ;
11985 return property ;
12086 } ) . concat ( schema . additionalProperties ? [ "..." ] : [ ] ) . join ( ", " ) } }`;
12187 }
12288 if ( schema . additionalProperties ) {
12389 return `object { <key>: ${ formatInnerSchema ( schema . additionalProperties ) } }` ;
12490 }
12591 return "object" ;
126- case "array" :
92+ } else if ( schema . type === "array" ) {
12793 return `[${ formatInnerSchema ( schema . items ) } ]` ;
94+ }
95+
96+ switch ( schema . instanceof ) {
97+ case "Function" :
98+ return "function" ;
99+ case "RegExp" :
100+ return "RegExp" ;
101+ }
102+ if ( schema . $ref ) return formatInnerSchema ( getSchemaPart ( schema . $ref ) , true ) ;
103+ if ( schema . allOf ) return schema . allOf . map ( formatInnerSchema ) . join ( " & " ) ;
104+ if ( schema . oneOf ) return schema . oneOf . map ( formatInnerSchema ) . join ( " | " ) ;
105+ if ( schema . anyOf ) return schema . anyOf . map ( formatInnerSchema ) . join ( " | " ) ;
106+ if ( schema . enum ) return schema . enum . map ( item => JSON . stringify ( item ) ) . join ( " | " ) ;
107+ return JSON . stringify ( schema , 0 , 2 ) ;
128108 }
129- switch ( schema . instanceof ) {
130- case "Function" :
131- return "function" ;
132- case "RegExp" :
133- return "RegExp" ;
134- }
135- if ( schema . $ref ) return formatInnerSchema ( getSchemaPart ( schema . $ref ) , true ) ;
136- if ( schema . allOf ) return schema . allOf . map ( formatInnerSchema ) . join ( " & " ) ;
137- if ( schema . oneOf ) return schema . oneOf . map ( formatInnerSchema ) . join ( " | " ) ;
138- if ( schema . anyOf ) return schema . anyOf . map ( formatInnerSchema ) . join ( " | " ) ;
139- if ( schema . enum ) return schema . enum . map ( function ( item ) {
140- return JSON . stringify ( item ) ;
141- } ) . join ( " | " ) ;
142- return JSON . stringify ( schema , 0 , 2 ) ;
143- }
144109
145- function indent ( str , prefix , firstLine ) {
146- if ( firstLine ) {
147- return prefix + str . replace ( / \n (? ! $ ) / g, `\n${ prefix } ` ) ;
148- } else {
149- return str . replace ( / \n (? ! $ ) / g, `\n${ prefix } ` ) ;
110+ static formatValidationError ( err ) {
111+ const dataPath = `configuration${ err . dataPath } ` ;
112+ if ( err . keyword === "additionalProperties" ) {
113+ return `${ dataPath } has an unknown property '${ err . params . additionalProperty } '. These properties are valid:\n${ getSchemaPartText ( err . parentSchema ) } ` ;
114+ } else if ( err . keyword === "oneOf" || err . keyword === "anyOf" ) {
115+ if ( err . children && err . children . length > 0 ) {
116+ return `${ dataPath } should be one of these:\n${ getSchemaPartText ( err . parentSchema ) } \n` +
117+ `Details:\n${ err . children . map ( err => " * " + indent ( OptionsValidationError . formatValidationError ( err ) , " " , false ) ) . join ( "\n" ) } ` ;
118+ }
119+ return `${ dataPath } should be one of these:\n${ getSchemaPartText ( err . parentSchema ) } ` ;
120+
121+ } else if ( err . keyword === "enum" ) {
122+ if ( err . parentSchema && err . parentSchema . enum && err . parentSchema . enum . length === 1 ) {
123+ return `${ dataPath } should be ${ getSchemaPartText ( err . parentSchema ) } ` ;
124+ }
125+ return `${ dataPath } should be one of these:\n${ getSchemaPartText ( err . parentSchema ) } ` ;
126+ } else if ( err . keyword === "allOf" ) {
127+ return `${ dataPath } should be:\n${ getSchemaPartText ( err . parentSchema ) } ` ;
128+ } else if ( err . keyword === "type" ) {
129+ switch ( err . params . type ) {
130+ case "object" :
131+ return `${ dataPath } should be an object.` ;
132+ case "string" :
133+ return `${ dataPath } should be a string.` ;
134+ case "boolean" :
135+ return `${ dataPath } should be a boolean.` ;
136+ case "number" :
137+ return `${ dataPath } should be a number.` ;
138+ case "array" :
139+ return `${ dataPath } should be an array:\n${ getSchemaPartText ( err . parentSchema ) } ` ;
140+ }
141+ return `${ dataPath } should be ${ err . params . type } :\n${ getSchemaPartText ( err . parentSchema ) } ` ;
142+ } else if ( err . keyword === "instanceof" ) {
143+ return `${ dataPath } should be an instance of ${ getSchemaPartText ( err . parentSchema ) } .` ;
144+ } else if ( err . keyword === "required" ) {
145+ const missingProperty = err . params . missingProperty . replace ( / ^ \. / , "" ) ;
146+ return `${ dataPath } misses the property '${ missingProperty } '.\n${ getSchemaPartText ( err . parentSchema , [ "properties" , missingProperty ] ) } ` ;
147+ } else if ( err . keyword === "minLength" || err . keyword === "minItems" ) {
148+ if ( err . params . limit === 1 )
149+ return `${ dataPath } should not be empty.` ;
150+ else
151+ return `${ dataPath } ${ err . message } ` ;
152+ } else {
153+ // eslint-disable-line no-fallthrough
154+ return `${ dataPath } ${ err . message } (${ JSON . stringify ( err , 0 , 2 ) } ).\n${ getSchemaPartText ( err . parentSchema ) } ` ;
155+ }
150156 }
151157}
152158
153- OptionsValidationError . formatSchema = formatSchema ;
159+ module . exports = OptionsValidationError ;
0 commit comments