summaryrefslogtreecommitdiffstats
path: root/node_modules/webpack/lib/WebpackOptionsValidationError.js
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/webpack/lib/WebpackOptionsValidationError.js')
-rw-r--r--node_modules/webpack/lib/WebpackOptionsValidationError.js390
1 files changed, 390 insertions, 0 deletions
diff --git a/node_modules/webpack/lib/WebpackOptionsValidationError.js b/node_modules/webpack/lib/WebpackOptionsValidationError.js
new file mode 100644
index 0000000..5f5da57
--- /dev/null
+++ b/node_modules/webpack/lib/WebpackOptionsValidationError.js
@@ -0,0 +1,390 @@
+/*
+ MIT License http://www.opensource.org/licenses/mit-license.php
+ Author Gajus Kuizinas @gajus
+*/
+"use strict";
+
+const WebpackError = require("./WebpackError");
+const webpackOptionsSchema = require("../schemas/WebpackOptions.json");
+
+const 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);
+ }
+ let schemaPart = webpackOptionsSchema;
+ for (let i = 1; i < path.length; i++) {
+ const inner = schemaPart[path[i]];
+ if (inner) schemaPart = inner;
+ }
+ return schemaPart;
+};
+
+const getSchemaPartText = (schemaPart, additionalPath) => {
+ if (additionalPath) {
+ for (let i = 0; i < additionalPath.length; i++) {
+ const inner = schemaPart[additionalPath[i]];
+ if (inner) schemaPart = inner;
+ }
+ }
+ while (schemaPart.$ref) {
+ schemaPart = getSchemaPart(schemaPart.$ref);
+ }
+ let schemaText = WebpackOptionsValidationError.formatSchema(schemaPart);
+ if (schemaPart.description) {
+ schemaText += `\n-> ${schemaPart.description}`;
+ }
+ return schemaText;
+};
+
+const getSchemaPartDescription = schemaPart => {
+ while (schemaPart.$ref) {
+ schemaPart = getSchemaPart(schemaPart.$ref);
+ }
+ if (schemaPart.description) {
+ return `\n-> ${schemaPart.description}`;
+ }
+ return "";
+};
+
+const SPECIFICITY = {
+ type: 1,
+ oneOf: 1,
+ anyOf: 1,
+ allOf: 1,
+ additionalProperties: 2,
+ enum: 1,
+ instanceof: 1,
+ required: 2,
+ minimum: 2,
+ uniqueItems: 2,
+ minLength: 2,
+ minItems: 2,
+ minProperties: 2,
+ absolutePath: 2
+};
+
+const filterMax = (array, fn) => {
+ const max = array.reduce((max, item) => Math.max(max, fn(item)), 0);
+ return array.filter(item => fn(item) === max);
+};
+
+const filterChildren = children => {
+ children = filterMax(children, err =>
+ err.dataPath ? err.dataPath.length : 0
+ );
+ children = filterMax(children, err => SPECIFICITY[err.keyword] || 2);
+ return children;
+};
+
+const indent = (str, prefix, firstLine) => {
+ if (firstLine) {
+ return prefix + str.replace(/\n(?!$)/g, "\n" + prefix);
+ } else {
+ return str.replace(/\n(?!$)/g, `\n${prefix}`);
+ }
+};
+
+class WebpackOptionsValidationError extends WebpackError {
+ constructor(validationErrors) {
+ super(
+ "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.name = "WebpackOptionsValidationError";
+ this.validationErrors = validationErrors;
+
+ Error.captureStackTrace(this, this.constructor);
+ }
+
+ static formatSchema(schema, prevSchemas) {
+ prevSchemas = prevSchemas || [];
+
+ const formatInnerSchema = (innerSchema, addSelf) => {
+ if (!addSelf) {
+ return WebpackOptionsValidationError.formatSchema(
+ innerSchema,
+ prevSchemas
+ );
+ }
+ if (prevSchemas.includes(innerSchema)) {
+ return "(recursive)";
+ }
+ return WebpackOptionsValidationError.formatSchema(
+ innerSchema,
+ prevSchemas.concat(schema)
+ );
+ };
+
+ if (schema.type === "string") {
+ if (schema.minLength === 1) {
+ return "non-empty string";
+ }
+ if (schema.minLength > 1) {
+ return `string (min length ${schema.minLength})`;
+ }
+ return "string";
+ }
+ if (schema.type === "boolean") {
+ return "boolean";
+ }
+ if (schema.type === "number") {
+ return "number";
+ }
+ if (schema.type === "object") {
+ if (schema.properties) {
+ const required = schema.required || [];
+ return `object { ${Object.keys(schema.properties)
+ .map(property => {
+ if (!required.includes(property)) return property + "?";
+ return property;
+ })
+ .concat(schema.additionalProperties ? ["…"] : [])
+ .join(", ")} }`;
+ }
+ if (schema.additionalProperties) {
+ return `object { <key>: ${formatInnerSchema(
+ schema.additionalProperties
+ )} }`;
+ }
+ return "object";
+ }
+ if (schema.type === "array") {
+ return `[${formatInnerSchema(schema.items)}]`;
+ }
+
+ switch (schema.instanceof) {
+ case "Function":
+ return "function";
+ case "RegExp":
+ return "RegExp";
+ }
+
+ if (schema.enum) {
+ return schema.enum.map(item => JSON.stringify(item)).join(" | ");
+ }
+
+ 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(" | ");
+ }
+ return JSON.stringify(schema, null, 2);
+ }
+
+ static formatValidationError(err) {
+ const dataPath = `configuration${err.dataPath}`;
+ if (err.keyword === "additionalProperties") {
+ const baseMessage = `${dataPath} has an unknown property '${
+ err.params.additionalProperty
+ }'. These properties are valid:\n${getSchemaPartText(err.parentSchema)}`;
+ if (!err.dataPath) {
+ switch (err.params.additionalProperty) {
+ case "debug":
+ return (
+ `${baseMessage}\n` +
+ "The 'debug' property was removed in webpack 2.0.0.\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" +
+ "plugins: [\n" +
+ " new webpack.LoaderOptionsPlugin({\n" +
+ " debug: true\n" +
+ " })\n" +
+ "]"
+ );
+ }
+ return (
+ `${baseMessage}\n` +
+ "For typos: please correct them.\n" +
+ "For loader options: webpack >= v2.0.0 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" +
+ " plugins: [\n" +
+ " new webpack.LoaderOptionsPlugin({\n" +
+ " // test: /\\.xxx$/, // may apply this only for some modules\n" +
+ " options: {\n" +
+ ` ${err.params.additionalProperty}: …\n` +
+ " }\n" +
+ " })\n" +
+ " ]"
+ );
+ }
+ return baseMessage;
+ } else if (err.keyword === "oneOf" || err.keyword === "anyOf") {
+ if (err.children && err.children.length > 0) {
+ if (err.schema.length === 1) {
+ const lastChild = err.children[err.children.length - 1];
+ const remainingChildren = err.children.slice(
+ 0,
+ err.children.length - 1
+ );
+ return WebpackOptionsValidationError.formatValidationError(
+ Object.assign({}, lastChild, {
+ children: remainingChildren,
+ parentSchema: Object.assign(
+ {},
+ err.parentSchema,
+ lastChild.parentSchema
+ )
+ })
+ );
+ }
+ const children = filterChildren(err.children);
+ if (children.length === 1) {
+ return WebpackOptionsValidationError.formatValidationError(
+ children[0]
+ );
+ }
+ return (
+ `${dataPath} should be one of these:\n${getSchemaPartText(
+ err.parentSchema
+ )}\n` +
+ `Details:\n${children
+ .map(
+ err =>
+ " * " +
+ indent(
+ WebpackOptionsValidationError.formatValidationError(err),
+ " ",
+ false
+ )
+ )
+ .join("\n")}`
+ );
+ }
+ return `${dataPath} should be one of these:\n${getSchemaPartText(
+ err.parentSchema
+ )}`;
+ } else if (err.keyword === "enum") {
+ if (
+ err.parentSchema &&
+ err.parentSchema.enum &&
+ err.parentSchema.enum.length === 1
+ ) {
+ return `${dataPath} should be ${getSchemaPartText(err.parentSchema)}`;
+ }
+ return `${dataPath} should be one of these:\n${getSchemaPartText(
+ err.parentSchema
+ )}`;
+ } else if (err.keyword === "allOf") {
+ return `${dataPath} should be:\n${getSchemaPartText(err.parentSchema)}`;
+ } else if (err.keyword === "type") {
+ switch (err.params.type) {
+ case "object":
+ return `${dataPath} should be an object.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ case "string":
+ return `${dataPath} should be a string.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ case "boolean":
+ return `${dataPath} should be a boolean.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ case "number":
+ return `${dataPath} should be a number.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ case "array":
+ return `${dataPath} should be an array:\n${getSchemaPartText(
+ err.parentSchema
+ )}`;
+ }
+ return `${dataPath} should be ${err.params.type}:\n${getSchemaPartText(
+ err.parentSchema
+ )}`;
+ } else if (err.keyword === "instanceof") {
+ return `${dataPath} should be an instance of ${getSchemaPartText(
+ err.parentSchema
+ )}`;
+ } else if (err.keyword === "required") {
+ const missingProperty = err.params.missingProperty.replace(/^\./, "");
+ return `${dataPath} misses the property '${missingProperty}'.\n${getSchemaPartText(
+ err.parentSchema,
+ ["properties", missingProperty]
+ )}`;
+ } else if (err.keyword === "minimum") {
+ return `${dataPath} ${err.message}.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ } else if (err.keyword === "uniqueItems") {
+ return `${dataPath} should not contain the item '${
+ err.data[err.params.i]
+ }' twice.${getSchemaPartDescription(err.parentSchema)}`;
+ } else if (
+ err.keyword === "minLength" ||
+ err.keyword === "minItems" ||
+ err.keyword === "minProperties"
+ ) {
+ if (err.params.limit === 1) {
+ switch (err.keyword) {
+ case "minLength":
+ return `${dataPath} should be an non-empty string.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ case "minItems":
+ return `${dataPath} should be an non-empty array.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ case "minProperties":
+ return `${dataPath} should be an non-empty object.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ }
+ return `${dataPath} should be not empty.${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ } else {
+ return `${dataPath} ${err.message}${getSchemaPartDescription(
+ err.parentSchema
+ )}`;
+ }
+ } else if (err.keyword === "not") {
+ return `${dataPath} should not be ${getSchemaPartText(
+ err.schema
+ )}\n${getSchemaPartText(err.parentSchema)}`;
+ } else if (err.keyword === "absolutePath") {
+ const baseMessage = `${dataPath}: ${
+ err.message
+ }${getSchemaPartDescription(err.parentSchema)}`;
+ 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;
+ } else {
+ return `${dataPath} ${err.message} (${JSON.stringify(
+ err,
+ null,
+ 2
+ )}).\n${getSchemaPartText(err.parentSchema)}`;
+ }
+ }
+}
+
+module.exports = WebpackOptionsValidationError;