2016-09-09 18:52:34 +08:00
/ *
MIT License http : //www.opensource.org/licenses/mit-license.php
Author Gajus Kuizinas @ gajus
* /
2017-01-05 00:33:49 +08:00
"use strict" ;
2016-09-19 06:54:35 +08:00
2017-03-25 05:17:47 +08:00
const WebpackError = require ( "./WebpackError" ) ;
2017-01-05 00:33:49 +08:00
const webpackOptionsSchema = require ( "../schemas/webpackOptionsSchema.json" ) ;
2017-10-28 05:22:21 +08:00
const indent = require ( "./util/indent" ) ;
const getSchemaPartText = require ( "./util/getSchemaPartText" ) ;
2017-01-05 00:33:49 +08:00
2017-10-28 05:22:21 +08:00
const getOptionsSchemaPartText = ( schema , additionalPath ) =>
getSchemaPartText ( webpackOptionsSchema , schema , additionalPath ) ;
2017-01-05 00:33:49 +08:00
2017-03-25 05:17:47 +08:00
class WebpackOptionsValidationError extends WebpackError {
2017-01-05 00:33:49 +08:00
constructor ( validationErrors ) {
super ( ) ;
this . name = "WebpackOptionsValidationError" ;
this . message = "Invalid configuration object. " +
"Webpack has been initialised using a configuration object that does not match the API schema.\n" +
validationErrors . map ( err => " - " + indent ( WebpackOptionsValidationError . formatValidationError ( err ) , " " , false ) ) . join ( "\n" ) ;
this . validationErrors = validationErrors ;
2017-02-11 06:35:11 +08:00
2017-02-17 00:16:47 +08:00
Error . captureStackTrace ( this , this . constructor ) ;
2017-01-05 00:33:49 +08:00
}
static formatValidationError ( err ) {
const dataPath = ` configuration ${ err . dataPath } ` ;
if ( err . keyword === "additionalProperties" ) {
2017-10-28 05:22:21 +08:00
const baseMessage = ` ${ dataPath } has an unknown property ' ${ err . params . additionalProperty } '. These properties are valid: \n ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2016-09-21 02:18:52 +08:00
if ( ! err . dataPath ) {
2016-09-21 15:24:00 +08:00
switch ( err . params . additionalProperty ) {
case "debug" :
2017-01-05 00:33:49 +08:00
return ` ${ baseMessage } \n ` +
2016-09-21 15:24:00 +08:00
"The 'debug' property was removed in webpack 2.\n" +
"Loaders should be updated to allow passing this option via loader options in module.rules.\n" +
"Until loaders are updated one can use the LoaderOptionsPlugin to switch loaders into debug mode:\n" +
2016-09-28 18:54:46 +08:00
"plugins: [\n" +
2016-09-21 15:24:00 +08:00
" new webpack.LoaderOptionsPlugin({\n" +
" debug: true\n" +
" })\n" +
2016-09-28 18:54:46 +08:00
"]" ;
2016-09-21 15:24:00 +08:00
}
2016-09-21 02:18:52 +08:00
return baseMessage + "\n" +
"For typos: please correct them.\n" +
"For loader options: webpack 2 no longer allows custom properties in configuration.\n" +
" Loaders should be updated to allow passing options via loader options in module.rules.\n" +
" Until loaders are updated one can use the LoaderOptionsPlugin to pass these options to the loader:\n" +
2016-09-28 18:54:46 +08:00
" plugins: [\n" +
2016-09-21 02:18:52 +08:00
" new webpack.LoaderOptionsPlugin({\n" +
2016-09-21 17:26:46 +08:00
" // test: /\\.xxx$/, // may apply this only for some modules\n" +
2016-09-21 02:18:52 +08:00
" options: {\n" +
2017-01-05 00:33:49 +08:00
` ${ err . params . additionalProperty } : ... \n ` +
2016-09-21 02:18:52 +08:00
" }\n" +
" })\n" +
2016-09-28 18:54:46 +08:00
" ]" ;
2016-09-21 02:18:52 +08:00
}
return baseMessage ;
2017-01-05 00:33:49 +08:00
} else if ( err . keyword === "oneOf" || err . keyword === "anyOf" ) {
2016-12-14 18:34:31 +08:00
if ( err . children && err . children . length > 0 ) {
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be one of these: \n ${ getOptionsSchemaPartText ( err . parentSchema ) } \n ` +
2017-01-11 17:51:58 +08:00
` Details: \n ${ err . children . map ( err => " * " + indent ( WebpackOptionsValidationError . formatValidationError ( err ) , " " , false ) ) . join ( "\n" ) } ` ;
2016-12-14 18:34:31 +08:00
}
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be one of these: \n ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2017-01-05 00:33:49 +08:00
} else if ( err . keyword === "enum" ) {
2016-12-14 18:34:31 +08:00
if ( err . parentSchema && err . parentSchema . enum && err . parentSchema . enum . length === 1 ) {
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2016-12-14 18:34:31 +08:00
}
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be one of these: \n ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2017-01-05 00:33:49 +08:00
} else if ( err . keyword === "allOf" ) {
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be: \n ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2017-01-05 00:33:49 +08:00
} else if ( err . keyword === "type" ) {
2016-09-19 06:54:35 +08:00
switch ( err . params . type ) {
case "object" :
2017-01-05 00:33:49 +08:00
return ` ${ dataPath } should be an object. ` ;
2016-09-19 06:54:35 +08:00
case "string" :
2017-01-05 00:33:49 +08:00
return ` ${ dataPath } should be a string. ` ;
2016-09-19 06:54:35 +08:00
case "boolean" :
2017-01-05 00:33:49 +08:00
return ` ${ dataPath } should be a boolean. ` ;
2016-09-19 06:54:35 +08:00
case "number" :
2017-01-05 00:33:49 +08:00
return ` ${ dataPath } should be a number. ` ;
2016-12-14 18:34:31 +08:00
case "array" :
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be an array: \n ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2016-09-19 06:54:35 +08:00
}
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be ${ err . params . type } : \n ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2017-01-05 00:33:49 +08:00
} else if ( err . keyword === "instanceof" ) {
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } should be an instance of ${ getOptionsSchemaPartText ( err . parentSchema ) } . ` ;
2017-01-05 00:33:49 +08:00
} else if ( err . keyword === "required" ) {
const missingProperty = err . params . missingProperty . replace ( /^\./ , "" ) ;
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } misses the property ' ${ missingProperty } '. \n ${ getOptionsSchemaPartText ( err . parentSchema , [ "properties" , missingProperty ] ) } ` ;
2017-01-05 00:33:49 +08:00
} else if ( err . keyword === "minLength" || err . keyword === "minItems" ) {
2016-09-19 06:54:35 +08:00
if ( err . params . limit === 1 )
2017-01-05 00:33:49 +08:00
return ` ${ dataPath } should not be empty. ` ;
2016-09-19 06:54:35 +08:00
else
2017-01-05 00:33:49 +08:00
return ` ${ dataPath } ${ err . message } ` ;
2017-02-08 19:54:55 +08:00
} else if ( err . keyword === "absolutePath" ) {
2017-03-25 05:21:30 +08:00
const baseMessage = ` ${ dataPath } : ${ err . message } ` ;
if ( dataPath === "configuration.output.filename" ) {
return ` ${ baseMessage } \n ` +
"Please use output.path to specify absolute path and output.filename for the file name." ;
}
return baseMessage ;
2017-01-05 00:33:49 +08:00
} else {
// eslint-disable-line no-fallthrough
2017-10-28 05:22:21 +08:00
return ` ${ dataPath } ${ err . message } ( ${ JSON . stringify ( err , 0 , 2 ) } ). \n ${ getOptionsSchemaPartText ( err . parentSchema ) } ` ;
2016-09-19 06:54:35 +08:00
}
}
}
2017-01-05 00:33:49 +08:00
module . exports = WebpackOptionsValidationError ;