diff --git a/lib/specifications/Specification.js b/lib/specifications/Specification.js index 60dbd969f..06f27feaa 100644 --- a/lib/specifications/Specification.js +++ b/lib/specifications/Specification.js @@ -120,7 +120,7 @@ class Specification { this._log.verbose(err.message); throw new Error( `${config.kind} ${config.metadata.name} defines unsupported Specification Version ` + - `${originalSpecVersion}. Please manually upgrade to 2.0 or higher. ` + + `${originalSpecVersion}. Please manually upgrade to 3.0 or higher. ` + `For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions - ` + `An attempted migration to a supported specification version failed, ` + `likely due to unrecognized configuration. Check verbose log for details.`); @@ -249,6 +249,9 @@ class Specification { } _migrateLegacyProject(config) { + // Stick to 2.6 since 3.0 adds further restrictions (i.e. for the name) and enables + // functionality for extensions that shouldn't be enabled if the specVersion is not + // explicitly set to 3.x config.specVersion = "2.6"; // propertiesFileSourceEncoding (relevant for applications and libraries) default diff --git a/lib/validation/schema/specVersion/kind/extension.json b/lib/validation/schema/specVersion/kind/extension.json index c5c469100..2c673c508 100644 --- a/lib/validation/schema/specVersion/kind/extension.json +++ b/lib/validation/schema/specVersion/kind/extension.json @@ -70,6 +70,25 @@ "type": "string" } } + }, + "metadata-3.0": { + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 50, + "pattern": "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + "title": "Extension Name", + "description": "Unique identifier for the extension. E.g. ui5-task-fearless-rock", + "errorMessage": "Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name" + }, + "copyright": { + "type": "string" + } + } } } } diff --git a/lib/validation/schema/specVersion/kind/extension/project-shim.json b/lib/validation/schema/specVersion/kind/extension/project-shim.json index 4f3d9226c..415785f1d 100644 --- a/lib/validation/schema/specVersion/kind/extension/project-shim.json +++ b/lib/validation/schema/specVersion/kind/extension/project-shim.json @@ -6,14 +6,14 @@ "required": ["specVersion", "kind", "type", "metadata", "shims"], "if": { "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "3.0"] } + "specVersion": { "enum": ["3.0"] } } }, "then": { "additionalProperties": false, "properties": { "specVersion": { - "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "3.0"] + "enum": ["3.0"] }, "kind": { "enum": ["extension"] @@ -22,7 +22,7 @@ "enum": ["project-shim"] }, "metadata": { - "$ref": "../extension.json#/definitions/metadata" + "$ref": "../extension.json#/definitions/metadata-3.0" }, "shims": { "$ref": "#/definitions/shims" @@ -34,22 +34,53 @@ } }, "else": { - "additionalProperties": false, - "properties": { - "specVersion": { - "enum": ["2.0"] - }, - "kind": { - "enum": ["extension"] - }, - "type": { - "enum": ["project-shim"] - }, - "metadata": { - "$ref": "../extension.json#/definitions/metadata" - }, - "shims": { - "$ref": "#/definitions/shims" + "if": { + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6"] } + } + }, + "then": { + "additionalProperties": false, + "properties": { + "specVersion": { + "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6"] + }, + "kind": { + "enum": ["extension"] + }, + "type": { + "enum": ["project-shim"] + }, + "metadata": { + "$ref": "../extension.json#/definitions/metadata" + }, + "shims": { + "$ref": "#/definitions/shims" + }, + "customConfiguration": { + "type": "object", + "additionalProperties": true + } + } + }, + "else": { + "additionalProperties": false, + "properties": { + "specVersion": { + "enum": ["2.0"] + }, + "kind": { + "enum": ["extension"] + }, + "type": { + "enum": ["project-shim"] + }, + "metadata": { + "$ref": "../extension.json#/definitions/metadata" + }, + "shims": { + "$ref": "#/definitions/shims" + } } } }, diff --git a/lib/validation/schema/specVersion/kind/extension/server-middleware.json b/lib/validation/schema/specVersion/kind/extension/server-middleware.json index 151c0c222..a65db5b56 100644 --- a/lib/validation/schema/specVersion/kind/extension/server-middleware.json +++ b/lib/validation/schema/specVersion/kind/extension/server-middleware.json @@ -7,13 +7,13 @@ "required": ["specVersion", "kind", "type", "metadata", "middleware"], "if": { "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "3.0"] } + "specVersion": { "enum": ["3.0"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "3.0"] }, + "specVersion": { "enum": ["3.0"] }, "kind": { "enum": ["extension"] }, @@ -21,7 +21,7 @@ "enum": ["server-middleware"] }, "metadata": { - "$ref": "../extension.json#/definitions/metadata" + "$ref": "../extension.json#/definitions/metadata-3.0" }, "middleware": { "$ref": "#/definitions/middleware" @@ -33,20 +33,49 @@ } }, "else": { - "additionalProperties": false, - "properties": { - "specVersion": { "enum": ["2.0"] }, - "kind": { - "enum": ["extension"] - }, - "type": { - "enum": ["server-middleware"] - }, - "metadata": { - "$ref": "../extension.json#/definitions/metadata" - }, - "middleware": { - "$ref": "#/definitions/middleware" + "if": { + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6"] } + } + }, + "then": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6"] }, + "kind": { + "enum": ["extension"] + }, + "type": { + "enum": ["server-middleware"] + }, + "metadata": { + "$ref": "../extension.json#/definitions/metadata" + }, + "middleware": { + "$ref": "#/definitions/middleware" + }, + "customConfiguration": { + "type": "object", + "additionalProperties": true + } + } + }, + "else": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.0"] }, + "kind": { + "enum": ["extension"] + }, + "type": { + "enum": ["server-middleware"] + }, + "metadata": { + "$ref": "../extension.json#/definitions/metadata" + }, + "middleware": { + "$ref": "#/definitions/middleware" + } } } }, diff --git a/lib/validation/schema/specVersion/kind/extension/task.json b/lib/validation/schema/specVersion/kind/extension/task.json index ab5413c78..f19291e0c 100644 --- a/lib/validation/schema/specVersion/kind/extension/task.json +++ b/lib/validation/schema/specVersion/kind/extension/task.json @@ -6,13 +6,13 @@ "required": ["specVersion", "kind", "type", "metadata", "task"], "if": { "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "3.0"] } + "specVersion": { "enum": ["3.0"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6", "3.0"] }, + "specVersion": { "enum": ["3.0"] }, "kind": { "enum": ["extension"] }, @@ -20,7 +20,7 @@ "enum": ["task"] }, "metadata": { - "$ref": "../extension.json#/definitions/metadata" + "$ref": "../extension.json#/definitions/metadata-3.0" }, "task": { "$ref": "#/definitions/task" @@ -32,20 +32,49 @@ } }, "else": { - "additionalProperties": false, - "properties": { - "specVersion": { "enum": ["2.0"] }, - "kind": { - "enum": ["extension"] - }, - "type": { - "enum": ["task"] - }, - "metadata": { - "$ref": "../extension.json#/definitions/metadata" - }, - "task": { - "$ref": "#/definitions/task" + "if": { + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6"] } + } + }, + "then": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4", "2.5", "2.6"] }, + "kind": { + "enum": ["extension"] + }, + "type": { + "enum": ["task"] + }, + "metadata": { + "$ref": "../extension.json#/definitions/metadata" + }, + "task": { + "$ref": "#/definitions/task" + }, + "customConfiguration": { + "type": "object", + "additionalProperties": true + } + } + }, + "else": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.0"] }, + "kind": { + "enum": ["extension"] + }, + "type": { + "enum": ["task"] + }, + "metadata": { + "$ref": "../extension.json#/definitions/metadata" + }, + "task": { + "$ref": "#/definitions/task" + } } } }, diff --git a/lib/validation/schema/specVersion/kind/project.json b/lib/validation/schema/specVersion/kind/project.json index 3d6a1a49b..3d8554584 100644 --- a/lib/validation/schema/specVersion/kind/project.json +++ b/lib/validation/schema/specVersion/kind/project.json @@ -93,6 +93,37 @@ } } }, + "metadata-3.0": { + "type": "object", + "required": ["name"], + "additionalProperties": false, + "properties": { + "name": { + "type": "string", + "minLength": 3, + "maxLength": 50, + "pattern": "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + "title": "Project Name", + "description": "Unique identifier for the project. E.g. organization.product.project", + "errorMessage": "Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name" + }, + "copyright": { + "type": "string" + }, + "deprecated": { + "type": "boolean", + "default": false + }, + "sapInternal": { + "type": "boolean", + "default": false + }, + "allowSapInternal": { + "type": "boolean", + "default": false + } + } + }, "resources-configuration-propertiesFileSourceEncoding": { "enum": ["UTF-8", "ISO-8859-1"], "default": "UTF-8", diff --git a/lib/validation/schema/specVersion/kind/project/application.json b/lib/validation/schema/specVersion/kind/project/application.json index fd0b063c2..81073634a 100644 --- a/lib/validation/schema/specVersion/kind/project/application.json +++ b/lib/validation/schema/specVersion/kind/project/application.json @@ -20,7 +20,7 @@ "enum": ["application"] }, "metadata": { - "$ref": "../project.json#/definitions/metadata" + "$ref": "../project.json#/definitions/metadata-3.0" }, "framework": { "$ref": "../project.json#/definitions/framework" diff --git a/lib/validation/schema/specVersion/kind/project/library.json b/lib/validation/schema/specVersion/kind/project/library.json index 86f1efe0a..d36a1f83e 100644 --- a/lib/validation/schema/specVersion/kind/project/library.json +++ b/lib/validation/schema/specVersion/kind/project/library.json @@ -20,7 +20,7 @@ "enum": ["library"] }, "metadata": { - "$ref": "../project.json#/definitions/metadata" + "$ref": "../project.json#/definitions/metadata-3.0" }, "framework": { "$ref": "../project.json#/definitions/framework" diff --git a/lib/validation/schema/specVersion/kind/project/module.json b/lib/validation/schema/specVersion/kind/project/module.json index 8bd717ff5..9684f27d1 100644 --- a/lib/validation/schema/specVersion/kind/project/module.json +++ b/lib/validation/schema/specVersion/kind/project/module.json @@ -6,13 +6,13 @@ "required": ["specVersion", "type", "metadata"], "if": { "properties": { - "specVersion": { "enum": ["2.5", "2.6", "3.0"] } + "specVersion": { "enum": ["3.0"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["2.5", "2.6", "3.0"] }, + "specVersion": { "enum": ["3.0"] }, "kind": { "enum": ["project", null] }, @@ -20,7 +20,7 @@ "enum": ["module"] }, "metadata": { - "$ref": "../project.json#/definitions/metadata" + "$ref": "../project.json#/definitions/metadata-3.0" }, "resources": { "$ref": "#/definitions/resources" @@ -40,13 +40,13 @@ "else": { "if": { "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] } + "specVersion": { "enum": ["2.5", "2.6"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] }, + "specVersion": { "enum": ["2.5", "2.6"] }, "kind": { "enum": ["project", null] }, @@ -59,6 +59,12 @@ "resources": { "$ref": "#/definitions/resources" }, + "builder": { + "$ref": "#/definitions/builder-specVersion-2.5" + }, + "server": { + "$ref": "../project.json#/definitions/server" + }, "customConfiguration": { "type": "object", "additionalProperties": true @@ -66,25 +72,53 @@ } }, "else": { - "additionalProperties": false, - "properties": { - "specVersion": { "enum": ["2.0"] }, - "kind": { - "enum": ["project", null] - }, - "type": { - "enum": ["module"] - }, - "metadata": { - "$ref": "../project.json#/definitions/metadata" - }, - "resources": { - "$ref": "#/definitions/resources" + "if": { + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] } + } + }, + "then": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] }, + "kind": { + "enum": ["project", null] + }, + "type": { + "enum": ["module"] + }, + "metadata": { + "$ref": "../project.json#/definitions/metadata" + }, + "resources": { + "$ref": "#/definitions/resources" + }, + "customConfiguration": { + "type": "object", + "additionalProperties": true + } + } + }, + "else": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.0"] }, + "kind": { + "enum": ["project", null] + }, + "type": { + "enum": ["module"] + }, + "metadata": { + "$ref": "../project.json#/definitions/metadata" + }, + "resources": { + "$ref": "#/definitions/resources" + } } } } }, - "definitions": { "resources": { "type": "object", diff --git a/lib/validation/schema/specVersion/kind/project/theme-library.json b/lib/validation/schema/specVersion/kind/project/theme-library.json index fc292179a..522b7064a 100644 --- a/lib/validation/schema/specVersion/kind/project/theme-library.json +++ b/lib/validation/schema/specVersion/kind/project/theme-library.json @@ -6,13 +6,13 @@ "required": ["specVersion", "type", "metadata"], "if": { "properties": { - "specVersion": { "enum": ["2.5", "2.6", "3.0"] } + "specVersion": { "enum": ["3.0"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["2.5", "2.6", "3.0"] }, + "specVersion": { "enum": ["3.0"] }, "kind": { "enum": ["project", null] }, @@ -20,7 +20,7 @@ "enum": ["theme-library"] }, "metadata": { - "$ref": "../project.json#/definitions/metadata" + "$ref": "../project.json#/definitions/metadata-3.0" }, "framework": { "$ref": "../project.json#/definitions/framework" @@ -43,13 +43,13 @@ "else": { "if": { "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] } + "specVersion": { "enum": ["2.5", "2.6"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] }, + "specVersion": { "enum": ["2.5", "2.6"] }, "kind": { "enum": ["project", null] }, @@ -66,7 +66,7 @@ "$ref": "library.json#/definitions/resources" }, "builder": { - "$ref": "#/definitions/builder" + "$ref": "#/definitions/builder-specVersion-2.5" }, "server": { "$ref": "../project.json#/definitions/server" @@ -78,34 +78,71 @@ } }, "else": { - "additionalProperties": false, - "properties": { - "specVersion": { "enum": ["2.0"] }, - "kind": { - "enum": ["project", null] - }, - "type": { - "enum": ["theme-library"] - }, - "metadata": { - "$ref": "../project.json#/definitions/metadata" - }, - "framework": { - "$ref": "../project.json#/definitions/framework" - }, - "resources": { - "$ref": "library.json#/definitions/resources" - }, - "builder": { - "$ref": "#/definitions/builder" - }, - "server": { - "$ref": "../project.json#/definitions/server" + "if": { + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] } + } + }, + "then": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.1", "2.2", "2.3", "2.4"] }, + "kind": { + "enum": ["project", null] + }, + "type": { + "enum": ["theme-library"] + }, + "metadata": { + "$ref": "../project.json#/definitions/metadata" + }, + "framework": { + "$ref": "../project.json#/definitions/framework" + }, + "resources": { + "$ref": "library.json#/definitions/resources" + }, + "builder": { + "$ref": "#/definitions/builder" + }, + "server": { + "$ref": "../project.json#/definitions/server" + }, + "customConfiguration": { + "type": "object", + "additionalProperties": true + } + } + }, + "else": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["2.0"] }, + "kind": { + "enum": ["project", null] + }, + "type": { + "enum": ["theme-library"] + }, + "metadata": { + "$ref": "../project.json#/definitions/metadata" + }, + "framework": { + "$ref": "../project.json#/definitions/framework" + }, + "resources": { + "$ref": "library.json#/definitions/resources" + }, + "builder": { + "$ref": "#/definitions/builder" + }, + "server": { + "$ref": "../project.json#/definitions/server" + } } } } }, - "definitions": { "builder": { "type": "object", diff --git a/test/lib/specifications/Specification.js b/test/lib/specifications/Specification.js index 6fbafbe74..aee440410 100644 --- a/test/lib/specifications/Specification.js +++ b/test/lib/specifications/Specification.js @@ -149,7 +149,7 @@ test("Migrate legacy project unexpected configuration", async (t) => { const err = await t.throwsAsync(Specification.create(t.context.basicProjectInput)); t.is(err.message, - "project application.a defines unsupported Specification Version 1.0. Please manually upgrade to 2.0 or " + + "project application.a defines unsupported Specification Version 1.0. Please manually upgrade to 3.0 or " + "higher. For details see https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions - " + "An attempted migration to a supported specification version failed, likely due to unrecognized " + "configuration. Check verbose log for details.", diff --git a/test/lib/validation/schema/__helper__/extension.js b/test/lib/validation/schema/__helper__/extension.js index 33143db77..79799ee96 100644 --- a/test/lib/validation/schema/__helper__/extension.js +++ b/test/lib/validation/schema/__helper__/extension.js @@ -18,7 +18,7 @@ export default { customConfiguration.defineTests(test, assertValidation, type, additionalConfiguration); - ["2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { test(`kind: extension / type: ${type} basic (${specVersion})`, async (t) => { await assertValidation(t, Object.assign({ "specVersion": specVersion, @@ -66,5 +66,57 @@ export default { }]); }); }); + + ["2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + test(`kind: extension / type: ${type}: Invalid metadata.name (${specVersion})`, async (t) => { + await assertValidation(t, Object.assign({ + "specVersion": specVersion, + "type": type, + "metadata": { + "name": {} + } + }, additionalConfiguration), [{ + dataPath: "/metadata/name", + keyword: "type", + message: "should be string", + params: { + type: "string" + } + }]); + }); + }); + + ["3.0"].forEach((specVersion) => { + test(`kind: extension / type: ${type}: Invalid metadata.name (${specVersion})`, async (t) => { + await assertValidation(t, Object.assign({ + "specVersion": specVersion, + "type": type, + "metadata": { + "name": {} + } + }, additionalConfiguration), [{ + dataPath: "/metadata/name", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, { + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "type", + message: "should be string", + params: { + type: "string", + } + }] + }, + }]); + }); + }); } }; diff --git a/test/lib/validation/schema/__helper__/project.js b/test/lib/validation/schema/__helper__/project.js index 777aeba51..50737b761 100644 --- a/test/lib/validation/schema/__helper__/project.js +++ b/test/lib/validation/schema/__helper__/project.js @@ -75,25 +75,6 @@ export default { }]); }); - test(`${type} (specVersion ${specVersion}): Invalid metadata.name`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "type": type, - "metadata": { - "name": {} - } - }, [ - { - dataPath: "/metadata/name", - keyword: "type", - message: "should be string", - params: { - type: "string" - } - } - ]); - }); - test(`${type} (specVersion ${specVersion}): Invalid metadata.copyright`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -278,5 +259,54 @@ export default { }]); }); }); + + ["2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + test(`${type} (specVersion ${specVersion}): Invalid metadata.name`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": type, + "metadata": { + "name": {} + } + }, [ + { + dataPath: "/metadata/name", + keyword: "type", + message: "should be string", + params: { + type: "string" + } + } + ]); + }); + }); + + ["3.0"].forEach((specVersion) => { + test(`${type} (specVersion ${specVersion}): Invalid metadata.name`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": type, + "metadata": { + "name": {} + } + }, [ + { + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "type", + message: "should be string", + params: { + type: "string", + } + }] + }, + } + ]); + }); + }); } }; diff --git a/test/lib/validation/schema/specVersion/kind/extension.js b/test/lib/validation/schema/specVersion/kind/extension.js index 565b92245..817e6c31b 100644 --- a/test/lib/validation/schema/specVersion/kind/extension.js +++ b/test/lib/validation/schema/specVersion/kind/extension.js @@ -152,3 +152,43 @@ test.after.always((t) => { }]); }); }); + +test("Legacy: Special characters in name (task)", async (t) => { + await assertValidation(t, { + "specVersion": "2.0", + "kind": "extension", + "type": "task", + "metadata": { + "name": "รค".repeat(51) + }, + "task": { + "path": "task.js" + } + }); +}); + +test("Legacy: Special characters in name (server-middleware)", async (t) => { + await assertValidation(t, { + "specVersion": "2.0", + "kind": "extension", + "type": "server-middleware", + "metadata": { + "name": "@my(middleware)" + }, + "middleware": { + "path": "middleware.js" + } + }); +}); + +test("Legacy: Special characters in name (project-shim)", async (t) => { + await assertValidation(t, { + "specVersion": "2.0", + "kind": "extension", + "type": "project-shim", + "metadata": { + "name": "my/(project)-shim" + }, + "shims": {} + }); +}); diff --git a/test/lib/validation/schema/specVersion/kind/extension/project-shim.js b/test/lib/validation/schema/specVersion/kind/extension/project-shim.js index 3fb2fb286..b2583a12b 100644 --- a/test/lib/validation/schema/specVersion/kind/extension/project-shim.js +++ b/test/lib/validation/schema/specVersion/kind/extension/project-shim.js @@ -15,6 +15,11 @@ async function assertValidation(t, config, expectedErrors = undefined) { }); validationError.errors.forEach((error) => { delete error.schemaPath; + if (error.params && Array.isArray(error.params.errors)) { + error.params.errors.forEach(($) => { + delete $.schemaPath; + }); + } }); t.deepEqual(validationError.errors, expectedErrors); } else { @@ -122,6 +127,79 @@ test.after.always((t) => { }); }); +["3.0"].forEach(function(specVersion) { + test(`Invalid extension name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "project-shim", + "metadata": { + "name": "illegal/name" + }, + "shims": {} + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "pattern", + message: `should match pattern "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$"`, + params: { + pattern: "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + } + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "project-shim", + "metadata": { + "name": "a" + }, + "shims": {} + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "minLength", + message: "should NOT be shorter than 3 characters", + params: { + limit: 3, + } + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "project-shim", + "metadata": { + "name": "a".repeat(51) + }, + "shims": {} + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "maxLength", + message: "should NOT be longer than 50 characters", + params: { + limit: 50, + } + }] + }, + }]); + }); +}); const additionalConfiguration = { "shims": { diff --git a/test/lib/validation/schema/specVersion/kind/extension/server-middleware.js b/test/lib/validation/schema/specVersion/kind/extension/server-middleware.js index 6a97ac218..54dab5cbd 100644 --- a/test/lib/validation/schema/specVersion/kind/extension/server-middleware.js +++ b/test/lib/validation/schema/specVersion/kind/extension/server-middleware.js @@ -15,6 +15,11 @@ async function assertValidation(t, config, expectedErrors = undefined) { }); validationError.errors.forEach((error) => { delete error.schemaPath; + if (error.params && Array.isArray(error.params.errors)) { + error.params.errors.forEach(($) => { + delete $.schemaPath; + }); + } }); t.deepEqual(validationError.errors, expectedErrors); } else { @@ -40,6 +45,86 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); +["3.0"].forEach(function(specVersion) { + test(`Invalid extension name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "server-middleware", + "metadata": { + "name": "illegal-๐Ÿฆœ" + }, + "middleware": { + "path": "/bar" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "pattern", + message: `should match pattern "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$"`, + params: { + pattern: "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + } + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "server-middleware", + "metadata": { + "name": "a" + }, + "middleware": { + "path": "/bar" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "minLength", + message: "should NOT be shorter than 3 characters", + params: { + limit: 3, + } + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "server-middleware", + "metadata": { + "name": "a".repeat(51) + }, + "middleware": { + "path": "/bar" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "maxLength", + message: "should NOT be longer than 50 characters", + params: { + limit: 50, + } + }] + }, + }]); + }); +}); + const additionalConfiguration = { "middleware": { "path": "/foo" diff --git a/test/lib/validation/schema/specVersion/kind/extension/task.js b/test/lib/validation/schema/specVersion/kind/extension/task.js index 7abbf36d0..63f5be3e9 100644 --- a/test/lib/validation/schema/specVersion/kind/extension/task.js +++ b/test/lib/validation/schema/specVersion/kind/extension/task.js @@ -15,6 +15,11 @@ async function assertValidation(t, config, expectedErrors = undefined) { }); validationError.errors.forEach((error) => { delete error.schemaPath; + if (error.params && Array.isArray(error.params.errors)) { + error.params.errors.forEach(($) => { + delete $.schemaPath; + }); + } }); t.deepEqual(validationError.errors, expectedErrors); } else { @@ -40,6 +45,86 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); +["3.0"].forEach(function(specVersion) { + test(`Invalid extension name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "task", + "metadata": { + "name": "illegal-๐Ÿฆœ" + }, + "task": { + "path": "/bar" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "pattern", + message: `should match pattern "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$"`, + params: { + pattern: "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + } + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "task", + "metadata": { + "name": "a" + }, + "task": { + "path": "/bar" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "minLength", + message: "should NOT be shorter than 3 characters", + params: { + limit: 3, + } + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "kind": "extension", + "type": "task", + "metadata": { + "name": "a".repeat(51) + }, + "task": { + "path": "/bar" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid extension name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "maxLength", + message: "should NOT be longer than 50 characters", + params: { + limit: 50, + } + }] + }, + }]); + }); +}); + const additionalConfiguration = { "task": { "path": "/foo" diff --git a/test/lib/validation/schema/specVersion/kind/project.js b/test/lib/validation/schema/specVersion/kind/project.js index 231c0ef29..2c9c2290a 100644 --- a/test/lib/validation/schema/specVersion/kind/project.js +++ b/test/lib/validation/schema/specVersion/kind/project.js @@ -195,3 +195,43 @@ test("No specVersion", async (t) => { } }]); }); + +test("Legacy: Special characters in name (application)", async (t) => { + await assertValidation(t, { + "specVersion": "2.0", + "type": "application", + "metadata": { + "name": "/".repeat(51) + } + }); +}); + +test("Legacy: Special characters in name (library)", async (t) => { + await assertValidation(t, { + "specVersion": "2.0", + "type": "library", + "metadata": { + "name": "my/(library)" + } + }); +}); + +test("Legacy: Special characters in name (theme-library)", async (t) => { + await assertValidation(t, { + "specVersion": "2.0", + "type": "theme-library", + "metadata": { + "name": "my/(theme)-library" + } + }); +}); + +test("Legacy: Special characters in name (module)", async (t) => { + await assertValidation(t, { + "specVersion": "2.0", + "type": "module", + "metadata": { + "name": "my/(module)" + } + }); +}); diff --git a/test/lib/validation/schema/specVersion/kind/project/application.js b/test/lib/validation/schema/specVersion/kind/project/application.js index 81b959e4f..4c0a73d5f 100644 --- a/test/lib/validation/schema/specVersion/kind/project/application.js +++ b/test/lib/validation/schema/specVersion/kind/project/application.js @@ -942,4 +942,72 @@ test.after.always((t) => { }); }); +["3.0"].forEach(function(specVersion) { + test(`Invalid project name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "application", + "metadata": { + "name": "illegal/name" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "pattern", + message: `should match pattern "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$"`, + params: { + pattern: "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + }, + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "application", + "metadata": { + "name": "a" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "minLength", + message: "should NOT be shorter than 3 characters", + params: { + limit: 3, + }, + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "application", + "metadata": { + "name": "a".repeat(51) + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "maxLength", + message: "should NOT be longer than 50 characters", + params: { + limit: 50, + }, + }] + }, + }]); + }); +}); + project.defineTests(test, assertValidation, "application"); diff --git a/test/lib/validation/schema/specVersion/kind/project/library.js b/test/lib/validation/schema/specVersion/kind/project/library.js index 3ba3ecfd6..60e0c6225 100644 --- a/test/lib/validation/schema/specVersion/kind/project/library.js +++ b/test/lib/validation/schema/specVersion/kind/project/library.js @@ -1115,4 +1115,71 @@ test.after.always((t) => { }); }); +["3.0"].forEach(function(specVersion) { + test(`Invalid project name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "library", + "metadata": { + "name": "illegal-๐Ÿฆœ" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "pattern", + message: `should match pattern "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$"`, + params: { + pattern: "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + }, + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "library", + "metadata": { + "name": "a" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "minLength", + message: "should NOT be shorter than 3 characters", + params: { + limit: 3, + }, + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "library", + "metadata": { + "name": "a".repeat(51) + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "maxLength", + message: "should NOT be longer than 50 characters", + params: { + limit: 50, + }, + }] + }, + }]); + }); +}); project.defineTests(test, assertValidation, "library"); diff --git a/test/lib/validation/schema/specVersion/kind/project/module.js b/test/lib/validation/schema/specVersion/kind/project/module.js index a750806b4..06e059cf7 100644 --- a/test/lib/validation/schema/specVersion/kind/project/module.js +++ b/test/lib/validation/schema/specVersion/kind/project/module.js @@ -15,6 +15,11 @@ async function assertValidation(t, config, expectedErrors = undefined) { }); validationError.errors.forEach((error) => { delete error.schemaPath; + if (error.params && Array.isArray(error.params.errors)) { + error.params.errors.forEach(($) => { + delete $.schemaPath; + }); + } }); t.deepEqual(validationError.errors, expectedErrors); } else { @@ -344,4 +349,72 @@ test.after.always((t) => { }); }); +["3.0"].forEach(function(specVersion) { + test(`Invalid project name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "module", + "metadata": { + "name": "illegal-๐Ÿฆœ" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "pattern", + message: `should match pattern "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$"`, + params: { + pattern: "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + } + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "module", + "metadata": { + "name": "a" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "minLength", + message: "should NOT be shorter than 3 characters", + params: { + limit: 3, + }, + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "module", + "metadata": { + "name": "a".repeat(51) + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "maxLength", + message: "should NOT be longer than 50 characters", + params: { + limit: 50, + }, + }] + }, + }]); + }); +}); + project.defineTests(test, assertValidation, "module"); diff --git a/test/lib/validation/schema/specVersion/kind/project/theme-library.js b/test/lib/validation/schema/specVersion/kind/project/theme-library.js index 24abd992c..220f193fa 100644 --- a/test/lib/validation/schema/specVersion/kind/project/theme-library.js +++ b/test/lib/validation/schema/specVersion/kind/project/theme-library.js @@ -348,4 +348,71 @@ test.after.always((t) => { }); }); +["3.0"].forEach(function(specVersion) { + test(`Invalid project name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "theme-library", + "metadata": { + "name": "illegal-๐Ÿฆœ" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "pattern", + message: `should match pattern "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$"`, + params: { + pattern: "^(?:@[0-9a-z-_.]+\\/)?[a-z][0-9a-z-_.]*$", + }, + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "theme-library", + "metadata": { + "name": "a" + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "minLength", + message: "should NOT be shorter than 3 characters", + params: { + limit: 3, + }, + }] + }, + }]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "theme-library", + "metadata": { + "name": "a".repeat(51) + } + }, [{ + dataPath: "/metadata/name", + keyword: "errorMessage", + message: `Not a valid project name. It must consist of lowercase alphanumeric characters, dash, underscore and period only. Additionally, it may contain an npm-style package scope. For details see: https://sap.github.io/ui5-tooling/stable/pages/Configuration/#name`, + params: { + errors: [{ + dataPath: "/metadata/name", + keyword: "maxLength", + message: "should NOT be longer than 50 characters", + params: { + limit: 50, + }, + }] + }, + }]); + }); +}); project.defineTests(test, assertValidation, "theme-library");