Merge pull request #8067 from webpack/merge/json-schema

Partial cherry-pick of #7232
This commit is contained in:
Tobias Koppers 2018-09-21 14:57:36 +02:00 committed by GitHub
commit 8414d7a629
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
20 changed files with 1811 additions and 1310 deletions

View File

@ -115,8 +115,8 @@
"lint": "yarn code-lint && yarn schema-lint && yarn type-lint && yarn special-lint",
"code-lint": "eslint --cache \"{setup,lib,bin,hot,buildin,benchmark,tooling,schemas}/**/*.js\" \"test/*.js\" \"test/{configCases,watchCases,statsCases,hotCases}/**/webpack.config.js\" \"examples/**/webpack.config.js\"",
"type-lint": "tsc --pretty",
"special-lint": "node tooling/inherit-types && node tooling/format-file-header",
"special-lint-fix": "node tooling/inherit-types --write --override && node tooling/format-file-header --write",
"special-lint": "node tooling/inherit-types && node tooling/format-schemas && node tooling/format-file-header",
"special-lint-fix": "node tooling/inherit-types --write --override && node tooling/format-schemas --write && node tooling/format-file-header --write",
"fix": "yarn code-lint --fix && yarn special-lint-fix",
"pretty": "prettier --loglevel warn --write \"*.{ts,js,json}\" \"{setup,lib,bin,hot,buildin,benchmark,tooling,schemas}/**/*.{js,json}\" \"test/*.js\" \"test/{configCases,watchCases,statsCases,hotCases}/**/webpack.config.js\" \"examples/**/webpack.config.js\"",
"schema-lint": "node --max-old-space-size=4096 node_modules/jest-cli/bin/jest --testMatch \"<rootDir>/test/*.lint.js\" --no-verbose",

File diff suppressed because it is too large Load Diff

View File

@ -1,65 +1,68 @@
{
"definitions": {
"rule": {
"BannerFunction": {
"description": "The banner as function, it will be wrapped in a comment",
"instanceof": "Function",
"tsType": "(data: { hash: string, chunk: import('../../lib/Chunk'), filename: string, basename: string, query: string}) => string"
},
"Rule": {
"oneOf": [
{
"instanceof": "RegExp"
"instanceof": "RegExp",
"tsType": "RegExp"
},
{
"minLength": 1,
"type": "string"
"type": "string",
"minLength": 1
}
]
},
"rules": {
"Rules": {
"oneOf": [
{
"type": "array",
"items": {
"description": "A rule condition",
"anyOf": [
{
"$ref": "#/definitions/rule"
"$ref": "#/definitions/Rule"
}
]
},
"type": "array"
}
},
{
"$ref": "#/definitions/rule"
"$ref": "#/definitions/Rule"
}
]
}
},
"title": "BannerPluginArgument",
"oneOf": [
{
"title": "BannerPluginOptions",
"type": "object",
"additionalProperties": false,
"required": ["banner"],
"properties": {
"banner": {
"description": "Specifies the banner",
"anyOf": [
{
"instanceof": "Function"
"$ref": "#/definitions/BannerFunction"
},
{
"type": "string"
}
]
},
"raw": {
"description": "If true, banner will not be wrapped in a comment",
"type": "boolean"
},
"entryOnly": {
"description": "If true, the banner will only be added to the entry chunks",
"type": "boolean"
},
"test": {
"description": "Include all modules that pass test assertion",
"exclude": {
"description": "Exclude all modules matching any of these conditions",
"anyOf": [
{
"$ref": "#/definitions/rules"
"$ref": "#/definitions/Rules"
}
]
},
@ -67,28 +70,32 @@
"description": "Include all modules matching any of these conditions",
"anyOf": [
{
"$ref": "#/definitions/rules"
"$ref": "#/definitions/Rules"
}
]
},
"exclude": {
"description": "Exclude all modules matching any of these conditions",
"raw": {
"description": "If true, banner will not be wrapped in a comment",
"type": "boolean"
},
"test": {
"description": "Include all modules that pass test assertion",
"anyOf": [
{
"$ref": "#/definitions/rules"
"$ref": "#/definitions/Rules"
}
]
}
}
},
"required": ["banner"]
},
{
"description": "The banner as function, it will be wrapped in a comment",
"instanceof": "Function"
"$ref": "#/definitions/BannerFunction"
},
{
"description": "The banner as string, it will be wrapped in a comment",
"minLength": 1,
"type": "string"
"type": "string",
"minLength": 1
}
]
}

View File

@ -1,30 +1,32 @@
{
"title": "DllPluginOptions",
"type": "object",
"additionalProperties": false,
"required": ["path"],
"properties": {
"context": {
"description": "Context of requests in the manifest file (defaults to the webpack context)",
"minLength": 1,
"type": "string"
},
"name": {
"description": "Name of the exposed dll function (external name, use value of 'output.library')",
"minLength": 1,
"type": "string"
},
"type": {
"description": "Type of the dll bundle (external type, use value of 'output.libraryTarget')",
"minLength": 1,
"type": "string"
},
"path": {
"description": "Absolute path to the manifest json file (output)",
"minLength": 1,
"type": "string"
"type": "string",
"minLength": 1
},
"entryOnly": {
"description": "If true, only entry points will be exposed",
"type": "boolean"
},
"name": {
"description": "Name of the exposed dll function (external name, use value of 'output.library')",
"type": "string",
"minLength": 1
},
"path": {
"description": "Absolute path to the manifest json file (output)",
"type": "string",
"minLength": 1
},
"type": {
"description": "Type of the dll bundle (external type, use value of 'output.libraryTarget')",
"type": "string",
"minLength": 1
}
}
},
"required": ["path"]
}

View File

@ -1,70 +1,83 @@
{
"additionalProperties": false,
"anyOf": [
{
"required": ["manifest"]
},
{
"required": ["content"]
}
],
"properties": {
"context": {
"description": "(absolute path) context of requests in the manifest (or content property)",
"type": "string",
"absolutePath": true
},
"manifest": {
"description": "An object containing content and name or a string to the absolute path of the JSON manifest to be loaded upon compilation",
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"content": {
"description": "The mappings from request to module id",
"minLength": 1,
"type": "object"
},
"name": {
"description": "The name where the dll is exposed (external name)",
"minLength": 1,
"type": "string"
},
"type": {
"description": "The type how the dll is exposed (external type)",
"minLength": 1,
"type": "string"
}
"definitions": {
"DllReferencePluginOptionsContent": {
"description": "The mappings from request to module info",
"type": "object",
"additionalProperties": {
"description": "Module info",
"type": "object",
"additionalProperties": false,
"properties": {
"buildMeta": {
"description": "Meta information about the module",
"type": "object"
},
"exports": {
"description": "Information about the provided exports of the module",
"anyOf": [
{
"description": "Exports unknown/dynamic",
"enum": [true]
},
{
"description": "List of provided exports of the module",
"type": "array",
"items": {
"description": "Name of the export",
"type": "string",
"minLength": 1
}
}
]
},
"id": {
"description": "Module ID",
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"minLength": 1
}
]
}
},
{
"required": ["id"]
},
"minProperties": 1
},
"DllReferencePluginOptionsManifest": {
"description": "An object containing content, name and type",
"type": "object",
"additionalProperties": false,
"properties": {
"content": {
"description": "The mappings from request to module info",
"anyOf": [
{
"$ref": "#/definitions/DllReferencePluginOptionsContent"
}
]
},
"name": {
"description": "The name where the dll is exposed (external name)",
"type": "string",
"absolutePath": true
"minLength": 1
},
"type": {
"description": "The type how the dll is exposed (external type)",
"anyOf": [
{
"$ref": "#/definitions/DllReferencePluginOptionsSourceType"
}
]
}
]
},
"required": ["content"]
},
"content": {
"description": "The mappings from request to module id (defaults to manifest.content)",
"minLength": 1,
"type": "object"
},
"name": {
"description": "The name where the dll is exposed (external name, defaults to manifest.name)",
"minLength": 1,
"type": "string"
},
"type": {
"description": "The way how the export of the dll bundle is used",
"enum": ["require", "object"]
},
"scope": {
"description": "Prefix which is used for accessing the content of the dll",
"minLength": 1,
"type": "string"
},
"sourceType": {
"description": "How the dll is exposed (libraryTarget, defaults to manifest.type)",
"DllReferencePluginOptionsSourceType": {
"description": "The type how the dll is exposed (external type)",
"enum": [
"var",
"assign",
@ -79,14 +92,113 @@
"umd2",
"jsonp"
]
},
"extensions": {
"description": "Extensions used to resolve modules in the dll bundle (only used when using 'scope')",
"type": "array",
"items": {
"description": "An extension",
"type": "string"
}
}
}
},
"title": "DllReferencePluginOptions",
"anyOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"context": {
"description": "(absolute path) context of requests in the manifest (or content property)",
"type": "string",
"absolutePath": true
},
"extensions": {
"description": "Extensions used to resolve modules in the dll bundle (only used when using 'scope')",
"type": "array",
"items": {
"description": "An extension",
"type": "string"
}
},
"manifest": {
"description": "An object containing content and name or a string to the absolute path of the JSON manifest to be loaded upon compilation",
"oneOf": [
{
"$ref": "#/definitions/DllReferencePluginOptionsManifest"
},
{
"type": "string",
"absolutePath": true
}
]
},
"name": {
"description": "The name where the dll is exposed (external name, defaults to manifest.name)",
"type": "string",
"minLength": 1
},
"scope": {
"description": "Prefix which is used for accessing the content of the dll",
"type": "string",
"minLength": 1
},
"sourceType": {
"description": "How the dll is exposed (libraryTarget, defaults to manifest.type)",
"anyOf": [
{
"$ref": "#/definitions/DllReferencePluginOptionsSourceType"
}
]
},
"type": {
"description": "The way how the export of the dll bundle is used",
"enum": ["require", "object"]
}
},
"required": ["manifest"]
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"content": {
"description": "The mappings from request to module info",
"anyOf": [
{
"$ref": "#/definitions/DllReferencePluginOptionsContent"
}
]
},
"context": {
"description": "(absolute path) context of requests in the manifest (or content property)",
"type": "string",
"absolutePath": true
},
"extensions": {
"description": "Extensions used to resolve modules in the dll bundle (only used when using 'scope')",
"type": "array",
"items": {
"description": "An extension",
"type": "string"
}
},
"name": {
"description": "The name where the dll is exposed (external name)",
"type": "string",
"minLength": 1
},
"scope": {
"description": "Prefix which is used for accessing the content of the dll",
"type": "string",
"minLength": 1
},
"sourceType": {
"description": "How the dll is exposed (libraryTarget)",
"anyOf": [
{
"$ref": "#/definitions/DllReferencePluginOptionsSourceType"
}
]
},
"type": {
"description": "The way how the export of the dll bundle is used",
"enum": ["require", "object"]
}
},
"required": ["content", "name"]
}
]
}

View File

@ -1,11 +1,12 @@
{
"title": "HashedModuleIdsPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"hashFunction": {
"description": "The hashing algorithm to use, defaults to 'md5'. All functions from Node.JS' crypto.createHash are supported.",
"context": {
"description": "The context directory for creating names.",
"type": "string",
"minLength": 1
"absolutePath": true
},
"hashDigest": {
"description": "The encoding to use when generating the hash, defaults to 'base64'. All encodings from Node.JS' hash.digest are supported.",
@ -15,6 +16,11 @@
"description": "The prefix length of the hash digest to use, defaults to 4.",
"type": "number",
"minimum": 1
},
"hashFunction": {
"description": "The hashing algorithm to use, defaults to 'md5'. All functions from Node.JS' crypto.createHash are supported.",
"type": "string",
"minLength": 1
}
}
}

View File

@ -1,29 +1,35 @@
{
"type": "object",
"title": "IgnorePluginOptions",
"oneOf": [
{
"type": "object",
"additionalProperties": false,
"properties": {
"resourceRegExp": {
"description": "A RegExp to test the request against",
"instanceof": "RegExp"
},
"contextRegExp": {
"description": "A RegExp to test the context (directory) against",
"instanceof": "RegExp"
"instanceof": "RegExp",
"tsType": "RegExp"
},
"resourceRegExp": {
"description": "A RegExp to test the request against",
"instanceof": "RegExp",
"tsType": "RegExp"
}
}
},
{
"type": "object",
"additionalProperties": false,
"properties": {
"checkResource": {
"description": "A filter function for resource",
"instanceof": "Function"
},
"checkContext": {
"description": "A filter function for context",
"instanceof": "Function"
"instanceof": "Function",
"tsType": "((context: string) => boolean)"
},
"checkResource": {
"description": "A filter function for resource",
"instanceof": "Function",
"tsType": "((resource: string) => boolean)"
}
}
}

View File

@ -1,4 +1,5 @@
{
"title": "LoaderOptionsPluginOptions",
"type": "object",
"additionalProperties": true,
"properties": {

View File

@ -1,21 +1,21 @@
{
"type": "object",
"additionalProperties": false,
"definitions": {
"rule": {
"oneOf": [
{
"instanceof": "RegExp"
"instanceof": "RegExp",
"tsType": "RegExp"
},
{
"minLength": 1,
"type": "string"
"type": "string",
"minLength": 1
}
]
},
"rules": {
"oneOf": [
{
"type": "array",
"items": {
"description": "A rule condition",
"anyOf": [
@ -23,8 +23,7 @@
"$ref": "#/definitions/rule"
}
]
},
"type": "array"
}
},
{
"$ref": "#/definitions/rule"
@ -32,22 +31,26 @@
]
}
},
"title": "SourceMapDevToolPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"test": {
"description": "Include source maps for modules based on their extension (defaults to .js and .css)",
"anyOf": [
"append": {
"description": "Appends the given value to the original asset. Usually the #sourceMappingURL comment. [url] is replaced with a URL to the source map file. false disables the appending",
"oneOf": [
{
"$ref": "#/definitions/rules"
"description": "Append no SourceMap comment to the bundle, but still generate SourceMaps",
"enum": [false, null]
},
{
"type": "string",
"minLength": 1
}
]
},
"include": {
"description": "Include source maps for module paths that match the given value",
"anyOf": [
{
"$ref": "#/definitions/rules"
}
]
"columns": {
"description": "Indicates whether column mappings should be used (defaults to true)",
"type": "boolean"
},
"exclude": {
"description": "Exclude modules that match the given value from source map generation",
@ -57,6 +60,24 @@
}
]
},
"fallbackModuleFilenameTemplate": {
"description": "Generator string or function to create identifiers of modules for the 'sources' array in the SourceMap used only if 'moduleFilenameTemplate' would result in a conflict",
"oneOf": [
{
"description": "Custom function generating the identifer",
"instanceof": "Function",
"tsType": "Function"
},
{
"type": "string",
"minLength": 1
}
]
},
"fileContext": {
"description": "Path prefix to which the [file] placeholder is relative to",
"type": "string"
},
"filename": {
"description": "Defines the output filename of the SourceMap (will be inlined if no value is provided)",
"oneOf": [
@ -66,78 +87,19 @@
},
{
"type": "string",
"minLength": 1,
"absolutePath": false
"absolutePath": false,
"minLength": 1
}
]
},
"append": {
"description": "Appends the given value to the original asset. Usually the #sourceMappingURL comment. [url] is replaced with a URL to the source map file. false disables the appending",
"oneOf": [
"include": {
"description": "Include source maps for module paths that match the given value",
"anyOf": [
{
"description": "Append no SourceMap comment to the bundle, but still generate SourceMaps",
"enum": [false, null]
},
{
"minLength": 1,
"type": "string"
"$ref": "#/definitions/rules"
}
]
},
"moduleFilenameTemplate": {
"description": "Generator string or function to create identifiers of modules for the 'sources' array in the SourceMap",
"oneOf": [
{
"description": "Custom function generating the identifer",
"instanceof": "Function"
},
{
"minLength": 1,
"type": "string"
}
]
},
"fallbackModuleFilenameTemplate": {
"description": "Generator string or function to create identifiers of modules for the 'sources' array in the SourceMap used only if 'moduleFilenameTemplate' would result in a conflict",
"oneOf": [
{
"description": "Custom function generating the identifer",
"instanceof": "Function"
},
{
"minLength": 1,
"type": "string"
}
]
},
"namespace": {
"description": "Namespace prefix to allow multiple webpack roots in the devtools",
"type": "string"
},
"module": {
"description": "Indicates whether SourceMaps from loaders should be used (defaults to true)",
"type": "boolean"
},
"columns": {
"description": "Indicates whether column mappings should be used (defaults to true)",
"type": "boolean"
},
"noSources": {
"description": "Omit the 'sourceContents' array from the SourceMap",
"type": "boolean"
},
"sourceRoot": {
"description": "Provide a custom value for the 'sourceRoot' property in the SourceMap",
"type": "string"
},
"publicPath": {
"description": "Provide a custom public path for the SourceMapping comment",
"type": "string"
},
"fileContext": {
"description": "Path prefix to which the [file] placeholder is relative to",
"type": "string"
},
"lineToLine": {
"description": "(deprecated) try to map original files line to line to generated files",
"anyOf": [
@ -149,8 +111,8 @@
"type": "object",
"additionalProperties": false,
"properties": {
"test": {
"description": "Include source maps for modules based on their extension (defaults to .js and .css)",
"exclude": {
"description": "Exclude modules that match the given value from source map generation",
"anyOf": [
{
"$ref": "#/definitions/rules"
@ -165,8 +127,8 @@
}
]
},
"exclude": {
"description": "Exclude modules that match the given value from source map generation",
"test": {
"description": "Include source maps for modules based on their extension (defaults to .js and .css)",
"anyOf": [
{
"$ref": "#/definitions/rules"
@ -176,6 +138,48 @@
}
}
]
},
"module": {
"description": "Indicates whether SourceMaps from loaders should be used (defaults to true)",
"type": "boolean"
},
"moduleFilenameTemplate": {
"description": "Generator string or function to create identifiers of modules for the 'sources' array in the SourceMap",
"oneOf": [
{
"description": "Custom function generating the identifer",
"instanceof": "Function",
"tsType": "Function"
},
{
"type": "string",
"minLength": 1
}
]
},
"namespace": {
"description": "Namespace prefix to allow multiple webpack roots in the devtools",
"type": "string"
},
"noSources": {
"description": "Omit the 'sourceContents' array from the SourceMap",
"type": "boolean"
},
"publicPath": {
"description": "Provide a custom public path for the SourceMapping comment",
"type": "string"
},
"sourceRoot": {
"description": "Provide a custom value for the 'sourceRoot' property in the SourceMap",
"type": "string"
},
"test": {
"description": "Include source maps for modules based on their extension (defaults to .js and .css)",
"anyOf": [
{
"$ref": "#/definitions/rules"
}
]
}
}
}

View File

@ -1,4 +1,5 @@
{
"title": "WatchIgnorePluginOptions",
"description": "A list of RegExps or absolute paths to directories or files that should be ignored",
"type": "array",
"items": {
@ -8,7 +9,8 @@
"type": "string"
},
{
"instanceof": "RegExp"
"instanceof": "RegExp",
"tsType": "RegExp"
}
]
},

View File

@ -1,4 +1,5 @@
{
"title": "ProfilingPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {

View File

@ -1,6 +1,7 @@
{
"additionalProperties": false,
"title": "OccurrenceOrderChunkIdsPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"prioritiseInitial": {
"description": "Prioritise initial size over total size",

View File

@ -1,6 +1,7 @@
{
"additionalProperties": false,
"title": "OccurrenceOrderModuleIdsPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"prioritiseInitial": {
"description": "Prioritise initial size over total size",

View File

@ -1,15 +1,8 @@
{
"title": "AggressiveSplittingPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {
"minSize": {
"description": "Byte, split point. Default: 30720",
"type": "number"
},
"maxSize": {
"description": "Byte, maxsize of per file. Default: 51200",
"type": "number"
},
"chunkOverhead": {
"description": "Default: 0",
"type": "number"
@ -17,6 +10,14 @@
"entryChunkMultiplicator": {
"description": "Default: 1",
"type": "number"
},
"maxSize": {
"description": "Byte, maxsize of per file. Default: 51200",
"type": "number"
},
"minSize": {
"description": "Byte, split point. Default: 30720",
"type": "number"
}
}
}

View File

@ -1,4 +1,5 @@
{
"title": "LimitChunkCountPluginOptions",
"type": "object",
"additionalProperties": false,
"properties": {

View File

@ -1,11 +1,12 @@
{
"additionalProperties": false,
"title": "MinChunkSizePluginOptions",
"type": "object",
"required": ["minChunkSize"],
"additionalProperties": false,
"properties": {
"minChunkSize": {
"description": "Minimum number of characters",
"type": "number"
}
}
},
"required": ["minChunkSize"]
}

View File

@ -32,14 +32,14 @@ describe("Schemas", () => {
const allowedProperties = [
"definitions",
"$ref",
"id",
"$id",
"title",
"items",
"properties",
"additionalProperties",
"type",
"oneOf",
"anyOf",
"allOf",
"absolutePath",
"description",
"enum",
@ -49,7 +49,8 @@ describe("Schemas", () => {
"uniqueItems",
"minItems",
"minProperties",
"instanceof"
"instanceof",
"tsType"
];
const validateProperty = property => {
@ -74,7 +75,7 @@ describe("Schemas", () => {
}
});
if (Object.keys(item).indexOf("$ref") >= 0) {
if ("$ref" in item) {
it("should not have other properties next to $ref", () => {
const otherProperties = Object.keys(item).filter(
p => p !== "$ref"
@ -89,6 +90,34 @@ describe("Schemas", () => {
});
}
if ("instanceof" in item) {
it("should have tsType specified when using instanceof", () => {
if (!("tsType" in item)) {
throw new Error("When using instanceof, tsType is required");
}
});
}
if ("absolutePath" in item) {
it("should have type: 'string' specified when using absolutePath", () => {
if (item.type !== "string") {
throw new Error(
"When using absolutePath, type must be 'string'"
);
}
});
}
if ("properties" in item || "additionalProperties" in item) {
it("should have type: 'object' specified when using properties or additionalProperties", () => {
if (item.type !== "object") {
throw new Error(
"When using properties or additionalProperties, type must be 'object'"
);
}
});
}
arrayProperties.forEach(prop => {
if (prop in item) {
describe(prop, () => {

View File

@ -22,17 +22,17 @@ describe("Validation", () => {
},
message: [
" - configuration.entry should be one of these:",
" object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" function | object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
" -> The entry point(s) of the compilation.",
" Details:",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things.",
" * configuration.entry should be an object.",
" -> Multiple entry bundles are created. The key is the chunk name. The value can be a string or an array.",
" * configuration.entry should not be empty.",
" -> An entry point without name. The string is resolved to a module which is loaded upon startup.",
" * configuration.entry should be an array:",
" [non-empty string]",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things."
" [non-empty string]"
]
},
{
@ -44,18 +44,18 @@ describe("Validation", () => {
},
message: [
" - configuration.entry should be one of these:",
" object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" function | object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
" -> The entry point(s) of the compilation.",
" Details:",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things.",
" * configuration.entry['bundle'] should be a string.",
" -> The string is resolved to a module which is loaded upon startup.",
" * configuration.entry['bundle'] should not be empty.",
" * configuration.entry should be a string.",
" -> An entry point without name. The string is resolved to a module which is loaded upon startup.",
" * configuration.entry should be an array:",
" [non-empty string]",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things."
" [non-empty string]"
]
},
{
@ -89,16 +89,16 @@ describe("Validation", () => {
},
message: [
" - configuration.entry should be one of these:",
" object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" function | object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
" -> The entry point(s) of the compilation.",
" Details:",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things.",
" * configuration.entry should be an object.",
" -> Multiple entry bundles are created. The key is the chunk name. The value can be a string or an array.",
" * configuration.entry should be a string.",
" -> An entry point without name. The string is resolved to a module which is loaded upon startup.",
" * configuration.entry should not contain the item 'abc' twice.",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things."
" * configuration.entry should not contain the item 'abc' twice."
]
},
{
@ -111,17 +111,17 @@ describe("Validation", () => {
},
message: [
" - configuration.entry should be one of these:",
" object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" function | object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
" -> The entry point(s) of the compilation.",
" Details:",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things.",
" * configuration.entry should be an object.",
" -> Multiple entry bundles are created. The key is the chunk name. The value can be a string or an array.",
" * configuration.entry should be a string.",
" -> An entry point without name. The string is resolved to a module which is loaded upon startup.",
" * configuration.entry[0] should be a string.",
" -> A non-empty string",
" * configuration.entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things.",
" - configuration.output.filename should be one of these:",
" string | function",
" -> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The `output.path` option determines the location on disk the files are written to, filename is used solely for naming the individual files.",
@ -145,17 +145,17 @@ describe("Validation", () => {
],
message: [
" - configuration[0].entry should be one of these:",
" object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string] | function",
" function | object { <key>: non-empty string | [non-empty string] } | non-empty string | [non-empty string]",
" -> The entry point(s) of the compilation.",
" Details:",
" * configuration[0].entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things.",
" * configuration[0].entry should be an object.",
" -> Multiple entry bundles are created. The key is the chunk name. The value can be a string or an array.",
" * configuration[0].entry should be a string.",
" -> An entry point without name. The string is resolved to a module which is loaded upon startup.",
" * configuration[0].entry[0] should be a string.",
" -> A non-empty string",
" * configuration[0].entry should be an instance of function",
" -> A Function returning an entry object, an entry string, an entry array or a promise to these things.",
" - configuration[1].output.filename should be one of these:",
" string | function",
" -> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The `output.path` option determines the location on disk the files are written to, filename is used solely for naming the individual files.",
@ -185,7 +185,7 @@ describe("Validation", () => {
},
message: [
" - configuration.module.rules[0].oneOf[0] has an unknown property 'passer'. These properties are valid:",
" object { enforce?, exclude?, include?, issuer?, loader?, loaders?, oneOf?, options?, parser?, resolve?, sideEffects?, query?, type?, resource?, resourceQuery?, compiler?, rules?, test?, use? }",
" object { compiler?, enforce?, exclude?, include?, issuer?, loader?, loaders?, oneOf?, options?, parser?, query?, resolve?, resource?, resourceQuery?, rules?, sideEffects?, test?, type?, use? }",
" -> A rule"
]
},
@ -197,9 +197,9 @@ describe("Validation", () => {
},
message: [
" - configuration has an unknown property 'postcss'. These properties are valid:",
" object { mode?, amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, externals?, " +
"loader?, module?, name?, node?, output?, optimization?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, " +
"recordsOutputPath?, recordsPath?, resolve?, resolveLoader?, serve?, stats?, target?, watch?, watchOptions? }",
" object { amd?, bail?, cache?, context?, dependencies?, devServer?, devtool?, entry?, externals?, loader?, mode?, module?, " +
"name?, node?, optimization?, output?, parallelism?, performance?, plugins?, profile?, recordsInputPath?, recordsOutputPath?, " +
"recordsPath?, resolve?, resolveLoader?, serve?, stats?, target?, watch?, watchOptions? }",
" For typos: please correct them.",
" For loader options: webpack >= v2.0.0 no longer allows custom properties in configuration.",
" Loaders should be updated to allow passing options via loader options in module.rules.",
@ -252,9 +252,13 @@ describe("Validation", () => {
}
},
message: [
' - configuration.output.filename: A relative path is expected. However, the provided value "/bar" is an absolute path!',
" - configuration.output.filename should be one of these:",
" string | function",
" -> Specifies the name of each output file on disk. You must **not** specify an absolute path here! The `output.path` option determines the location on disk the files are written to, filename is used solely for naming the individual files.",
" Please use output.path to specify absolute path and output.filename for the file name."
" Details:",
' * configuration.output.filename: A relative path is expected. However, the provided value "/bar" is an absolute path!',
" Please use output.path to specify absolute path and output.filename for the file name.",
" * configuration.output.filename should be an instance of function"
]
},
{
@ -368,9 +372,6 @@ describe("Validation", () => {
" * configuration.plugins[0] misses the property 'apply'.",
" function",
" -> The run point of the plugin, required method.",
" * configuration.plugins[0] misses the property 'apply'.",
" function",
" -> The run point of the plugin, required method.",
" * configuration.plugins[0] should be an instance of function",
" -> Function acting as plugin"
]

146
tooling/format-schemas.js Normal file
View File

@ -0,0 +1,146 @@
const fs = require("fs");
const path = require("path");
const prettier = require("prettier");
const schemasDir = path.resolve(__dirname, "../schemas");
// When --write is set, files will be written in place
// Elsewise it only prints outdated files
const doWrite = process.argv.includes("--write");
const sortObjectAlphabetically = obj => {
const keys = Object.keys(obj).sort();
const newObj = {};
for (const key of keys) {
newObj[key] = obj[key];
}
return newObj;
};
const sortObjectWithList = (obj, props) => {
const keys = Object.keys(obj)
.filter(p => !props.includes(p))
.sort();
const newObj = {};
for (const key of props) {
if (key in obj) {
newObj[key] = obj[key];
}
}
for (const key of keys) {
newObj[key] = obj[key];
}
return newObj;
};
const PROPERTIES = [
"$ref",
"definitions",
"$id",
"id",
"title",
"description",
"type",
"items",
"minItems",
"uniqueItems",
"additionalProperties",
"properties",
"required",
"minProperties",
"oneOf",
"anyOf",
"allOf",
"enum",
"absolutePath",
"minLength",
"minimum",
"instanceof",
"tsType"
];
const NESTED_WITH_NAME = ["definitions", "properties"];
const NESTED_DIRECT = ["items", "additionalProperties"];
const NESTED_ARRAY = ["oneOf", "anyOf", "allOf"];
const processJson = json => {
json = sortObjectWithList(json, PROPERTIES);
for (const name of NESTED_WITH_NAME) {
if (name in json && json[name] && typeof json[name] === "object") {
json[name] = sortObjectAlphabetically(json[name]);
for (const key in json[name]) {
json[name][key] = processJson(json[name][key]);
}
}
}
for (const name of NESTED_DIRECT) {
if (name in json && json[name] && typeof json[name] === "object") {
json[name] = processJson(json[name]);
}
}
for (const name of NESTED_ARRAY) {
if (name in json && Array.isArray(json[name])) {
for (let i = 0; i < json[name].length; i++) {
json[name][i] = processJson(json[name][i]);
}
}
}
return json;
};
const formatSchema = schemaPath => {
const json = require(schemaPath);
const processedJson = processJson(json);
const rawString = JSON.stringify(processedJson, null, 2);
prettier.resolveConfig(schemaPath).then(config => {
config.filepath = schemaPath;
config.parser = "json";
const prettyString = prettier.format(rawString, config);
let normalizedContent = "";
try {
const content = fs.readFileSync(schemaPath, "utf-8");
normalizedContent = content.replace(/\r\n?/g, "\n");
} catch (e) {
// ignore
}
if (normalizedContent.trim() !== prettyString.trim()) {
const basename = path.relative(schemasDir, schemaPath);
if (doWrite) {
fs.writeFileSync(schemaPath, prettyString, "utf-8");
console.error(`schemas/${basename.replace(/\\/g, "/")} updated`);
} else {
console.error(
`schemas/${basename.replace(/\\/g, "/")} need to be updated`
);
process.exitCode = 1;
}
}
});
};
// include the top level folder "./schemas" by default
const dirs = new Set([schemasDir]);
// search for all nestedDirs inside of this folder
for (let dirWithSchemas of dirs) {
for (let item of fs.readdirSync(dirWithSchemas)) {
const absPath = path.resolve(dirWithSchemas, item);
if (fs.statSync(absPath).isDirectory()) {
dirs.add(absPath);
} else if (item.endsWith(".json")) {
formatSchema(absPath);
}
}
}

View File

@ -154,8 +154,8 @@ for (const sourceFile of program.getSourceFiles()) {
}
}
console.log();
process.exitCode = 1;
}
process.exitCode = 1;
}
}
}