| 
									
										
										
										
											2016-09-09 18:52:34 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Gajus Kuizinas @gajus | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | var webpackOptionsSchema = require("../schemas/webpackOptionsSchema.json"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-09 18:52:34 +08:00
										 |  |  | function WebpackOptionsValidationError(validationErrors) { | 
					
						
							|  |  |  | 	Error.call(this); | 
					
						
							|  |  |  | 	Error.captureStackTrace(this, WebpackOptionsValidationError); | 
					
						
							|  |  |  | 	this.name = "WebpackOptionsValidationError"; | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 	this.message = "Invalid configuration object. " + | 
					
						
							|  |  |  | 		"Webpack has been initialised using a configuration object that does not match the API schema.\n" + | 
					
						
							|  |  |  | 		validationErrors.map(function(err) { | 
					
						
							|  |  |  | 			return " - " + indent(WebpackOptionsValidationError.formatValidationError(err), "   ", false); | 
					
						
							|  |  |  | 		}).join("\n"); | 
					
						
							| 
									
										
										
										
											2016-09-09 18:52:34 +08:00
										 |  |  | 	this.validationErrors = validationErrors; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | module.exports = WebpackOptionsValidationError; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebpackOptionsValidationError.prototype = Object.create(Error.prototype); | 
					
						
							|  |  |  | WebpackOptionsValidationError.prototype.constructor = WebpackOptionsValidationError; | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | WebpackOptionsValidationError.formatValidationError = function formatValidationError(err) { | 
					
						
							|  |  |  | 	var dataPath = "configuration" + err.dataPath; | 
					
						
							|  |  |  | 	switch(err.keyword) { | 
					
						
							|  |  |  | 		case "additionalProperties": | 
					
						
							| 
									
										
										
										
											2016-09-21 02:18:52 +08:00
										 |  |  | 			var baseMessage = dataPath + " has an unknown property '" + err.params.additionalProperty + "'. These properties are valid:\n" + | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 				getSchemaPartText(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": | 
					
						
							|  |  |  | 						return baseMessage + "\n" + | 
					
						
							|  |  |  | 							"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" + | 
					
						
							|  |  |  | 					"        " + err.params.additionalProperty + ": ...\n" + | 
					
						
							|  |  |  | 					"      }\n" + | 
					
						
							|  |  |  | 					"    })\n" + | 
					
						
							| 
									
										
										
										
											2016-09-28 18:54:46 +08:00
										 |  |  | 					"  ]"; | 
					
						
							| 
									
										
										
										
											2016-09-21 02:18:52 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			return baseMessage; | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 		case "oneOf": | 
					
						
							|  |  |  | 		case "anyOf": | 
					
						
							| 
									
										
										
										
											2016-12-14 18:34:31 +08:00
										 |  |  | 			if(err.children && err.children.length > 0) { | 
					
						
							|  |  |  | 				return dataPath + " should be one of these:\n" + | 
					
						
							|  |  |  | 					getSchemaPartText(err.parentSchema) + "\nDetails:\n" + err.children.map(function(err) { | 
					
						
							| 
									
										
										
										
											2016-12-14 19:03:24 +08:00
										 |  |  | 						return " * " + indent(WebpackOptionsValidationError.formatValidationError(err), "   ", false); | 
					
						
							|  |  |  | 					}).join("\n") | 
					
						
							| 
									
										
										
										
											2016-12-14 18:34:31 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			return dataPath + " should be one of these:\n" + | 
					
						
							|  |  |  | 				getSchemaPartText(err.parentSchema); | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 		case "enum": | 
					
						
							| 
									
										
										
										
											2016-12-14 18:34:31 +08:00
										 |  |  | 			if(err.parentSchema && err.parentSchema.enum && err.parentSchema.enum.length === 1) { | 
					
						
							|  |  |  | 				return dataPath + " should be " + getSchemaPartText(err.parentSchema); | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 			return dataPath + " should be one of these:\n" + | 
					
						
							|  |  |  | 				getSchemaPartText(err.parentSchema); | 
					
						
							|  |  |  | 		case "allOf": | 
					
						
							|  |  |  | 			return dataPath + " should be:\n" + | 
					
						
							|  |  |  | 				getSchemaPartText(err.parentSchema); | 
					
						
							|  |  |  | 		case "type": | 
					
						
							|  |  |  | 			switch(err.params.type) { | 
					
						
							|  |  |  | 				case "object": | 
					
						
							|  |  |  | 					return dataPath + " should be an object."; | 
					
						
							|  |  |  | 				case "string": | 
					
						
							|  |  |  | 					return dataPath + " should be a string."; | 
					
						
							|  |  |  | 				case "boolean": | 
					
						
							|  |  |  | 					return dataPath + " should be a boolean."; | 
					
						
							|  |  |  | 				case "number": | 
					
						
							|  |  |  | 					return dataPath + " should be a number."; | 
					
						
							| 
									
										
										
										
											2016-12-14 18:34:31 +08:00
										 |  |  | 				case "array": | 
					
						
							|  |  |  | 					return dataPath + " should be an array:\n" + | 
					
						
							|  |  |  | 						getSchemaPartText(err.parentSchema); | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			return dataPath + " should be " + err.params.type + ":\n" + | 
					
						
							|  |  |  | 				getSchemaPartText(err.parentSchema); | 
					
						
							| 
									
										
										
										
											2016-11-04 06:52:59 +08:00
										 |  |  | 		case "instanceof": | 
					
						
							|  |  |  | 			return dataPath + " should be an instance of " + getSchemaPartText(err.parentSchema) + "."; | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 		case "required": | 
					
						
							|  |  |  | 			var missingProperty = err.params.missingProperty.replace(/^\./, ""); | 
					
						
							|  |  |  | 			return dataPath + " misses the property '" + missingProperty + "'.\n" + | 
					
						
							|  |  |  | 				getSchemaPartText(err.parentSchema, ["properties", missingProperty]); | 
					
						
							|  |  |  | 		case "minLength": | 
					
						
							|  |  |  | 			if(err.params.limit === 1) | 
					
						
							|  |  |  | 				return dataPath + " should not be empty."; | 
					
						
							|  |  |  | 			else | 
					
						
							|  |  |  | 				return dataPath + " " + err.message; | 
					
						
							| 
									
										
										
										
											2016-11-21 08:00:25 +08:00
										 |  |  | 		default: // eslint-disable-line no-fallthrough
 | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 			return dataPath + " " + err.message + " (" + JSON.stringify(err, 0, 2) + ").\n" + | 
					
						
							|  |  |  | 				getSchemaPartText(err.parentSchema); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getSchemaPart(path, parents, additionalPath) { | 
					
						
							|  |  |  | 	parents = parents || 0; | 
					
						
							|  |  |  | 	path = path.split("/"); | 
					
						
							|  |  |  | 	path = path.slice(0, path.length - parents); | 
					
						
							|  |  |  | 	if(additionalPath) { | 
					
						
							|  |  |  | 		additionalPath = additionalPath.split("/"); | 
					
						
							|  |  |  | 		path = path.concat(additionalPath); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var schemaPart = webpackOptionsSchema; | 
					
						
							|  |  |  | 	for(var i = 1; i < path.length; i++) { | 
					
						
							|  |  |  | 		var inner = schemaPart[path[i]]; | 
					
						
							|  |  |  | 		if(inner) | 
					
						
							|  |  |  | 			schemaPart = inner; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return schemaPart; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function getSchemaPartText(schemaPart, additionalPath) { | 
					
						
							|  |  |  | 	if(additionalPath) { | 
					
						
							|  |  |  | 		for(var i = 0; i < additionalPath.length; i++) { | 
					
						
							|  |  |  | 			var inner = schemaPart[additionalPath[i]]; | 
					
						
							|  |  |  | 			if(inner) | 
					
						
							|  |  |  | 				schemaPart = inner; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	while(schemaPart.$ref) schemaPart = getSchemaPart(schemaPart.$ref); | 
					
						
							|  |  |  | 	var schemaText = WebpackOptionsValidationError.formatSchema(schemaPart); | 
					
						
							|  |  |  | 	if(schemaPart.description) | 
					
						
							|  |  |  | 		schemaText += "\n" + schemaPart.description; | 
					
						
							|  |  |  | 	return schemaText; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function formatSchema(schema, prevSchemas) { | 
					
						
							|  |  |  | 	prevSchemas = prevSchemas || []; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	function formatInnerSchema(innerSchema, addSelf) { | 
					
						
							|  |  |  | 		if(!addSelf) return formatSchema(innerSchema, prevSchemas); | 
					
						
							|  |  |  | 		if(prevSchemas.indexOf(innerSchema) >= 0) return "(recursive)"; | 
					
						
							|  |  |  | 		return formatSchema(innerSchema, prevSchemas.concat(schema)); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch(schema.type) { | 
					
						
							|  |  |  | 		case "string": | 
					
						
							| 
									
										
										
										
											2016-12-14 18:34:31 +08:00
										 |  |  | 			if(schema.minLength === 1) | 
					
						
							|  |  |  | 				return "non-empty string"; | 
					
						
							|  |  |  | 			else if(schema.minLength > 1) | 
					
						
							|  |  |  | 				return "string (min length " + schema.minLength + ")"; | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 			return "string"; | 
					
						
							|  |  |  | 		case "boolean": | 
					
						
							|  |  |  | 			return "boolean"; | 
					
						
							| 
									
										
										
										
											2016-09-23 05:35:33 +08:00
										 |  |  | 		case "number": | 
					
						
							|  |  |  | 			return "number"; | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 		case "object": | 
					
						
							|  |  |  | 			if(schema.properties) { | 
					
						
							|  |  |  | 				var required = schema.required || []; | 
					
						
							|  |  |  | 				return "object { " + Object.keys(schema.properties).map(function(property) { | 
					
						
							|  |  |  | 					if(required.indexOf(property) < 0) return property + "?"; | 
					
						
							|  |  |  | 					return property; | 
					
						
							| 
									
										
										
										
											2016-09-21 01:54:14 +08:00
										 |  |  | 				}).concat(schema.additionalProperties ? ["..."] : []).join(", ") + " }"; | 
					
						
							| 
									
										
										
										
											2016-09-19 06:54:35 +08:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			if(schema.additionalProperties) { | 
					
						
							|  |  |  | 				return "object { <key>: " + formatInnerSchema(schema.additionalProperties) + " }"; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return "object"; | 
					
						
							|  |  |  | 		case "array": | 
					
						
							|  |  |  | 			return "[" + formatInnerSchema(schema.items) + "]"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch(schema.instanceof) { | 
					
						
							|  |  |  | 		case "Function": | 
					
						
							|  |  |  | 			return "function"; | 
					
						
							|  |  |  | 		case "RegExp": | 
					
						
							|  |  |  | 			return "RegExp"; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if(schema.$ref) return formatInnerSchema(getSchemaPart(schema.$ref), true); | 
					
						
							|  |  |  | 	if(schema.allOf) return schema.allOf.map(formatInnerSchema).join(" & "); | 
					
						
							|  |  |  | 	if(schema.oneOf) return schema.oneOf.map(formatInnerSchema).join(" | "); | 
					
						
							|  |  |  | 	if(schema.anyOf) return schema.anyOf.map(formatInnerSchema).join(" | "); | 
					
						
							|  |  |  | 	if(schema.enum) return schema.enum.map(function(item) { | 
					
						
							|  |  |  | 		return JSON.stringify(item); | 
					
						
							|  |  |  | 	}).join(" | "); | 
					
						
							|  |  |  | 	return JSON.stringify(schema, 0, 2); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function indent(str, prefix, firstLine) { | 
					
						
							|  |  |  | 	if(firstLine) { | 
					
						
							|  |  |  | 		return prefix + str.replace(/\n(?!$)/g, "\n" + prefix); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return str.replace(/\n(?!$)/g, "\n" + prefix); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | WebpackOptionsValidationError.formatSchema = formatSchema; |