From d47f869f87a583cdbee821fb0beaf98a68689773 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Mon, 12 Jun 2023 09:30:46 +0200 Subject: [PATCH 1/5] [FEATURE] Add 'component' type and specVersion 3.1 Basically a copy of the 'application' type but with the same path mappings as 'library' (directories: 'src' and 'test') and a namespaced runtime path. JIRA: CPOUI5FOUNDATION-27 --- lib/specifications/Specification.js | 3 + lib/specifications/SpecificationVersion.js | 2 +- lib/specifications/types/Application.js | 8 +- lib/specifications/types/Component.js | 259 +++++ lib/specifications/types/Library.js | 5 +- .../schema/specVersion/kind/extension.json | 2 +- .../kind/extension/project-shim.json | 4 +- .../kind/extension/server-middleware.json | 4 +- .../specVersion/kind/extension/task.json | 4 +- .../schema/specVersion/kind/project.json | 14 +- .../specVersion/kind/project/application.json | 4 +- .../specVersion/kind/project/component.json | 108 ++ .../specVersion/kind/project/library.json | 4 +- .../specVersion/kind/project/module.json | 4 +- .../kind/project/theme-library.json | 4 +- .../schema/specVersion/specVersion.json | 2 +- lib/validation/schema/ui5.json | 6 +- test/fixtures/component.a/middleware.a.js | 1 + .../collection/library.a/package.json | 17 + .../library.a/src/library/a/.library | 17 + .../library/a/themes/base/library.source.less | 6 + .../library.a/test/library/a/Test.html | 0 .../collection/library.a/ui5.yaml | 5 + .../collection/library.b/package.json | 9 + .../library.b/src/library/b/.library | 17 + .../library.b/test/library/b/Test.html | 0 .../collection/library.b/ui5.yaml | 5 + .../collection/library.c/package.json | 9 + .../library.c/src/library/c/.library | 17 + .../library.c/test/LibraryC/Test.html | 0 .../collection/library.c/ui5.yaml | 5 + .../node_modules/library.d/package.json | 9 + .../library.d/src/library/d/.library | 11 + .../library.d/test/library/d/Test.html | 0 .../node_modules/library.d/ui5.yaml | 10 + .../node_modules/collection/package.json | 18 + .../node_modules/collection/ui5.yaml | 12 + .../library.d/main/src/library/d/.library | 11 + .../library.d/main/src/library/d/some.js | 4 + .../library.d/main/test/library/d/Test.html | 0 .../node_modules/library.d/package.json | 9 + .../node_modules/library.d/ui5.yaml | 10 + test/fixtures/component.a/package.json | 13 + test/fixtures/component.a/src/index.html | 9 + test/fixtures/component.a/src/manifest.json | 13 + test/fixtures/component.a/src/test.js | 5 + test/fixtures/component.a/task.a.js | 1 + .../component.a/ui5-test-configPath.yaml | 7 + .../component.a/ui5-test-corrupt.yaml | 1 + test/fixtures/component.a/ui5-test-empty.yaml | 0 test/fixtures/component.a/ui5-test-error.yaml | 7 + test/fixtures/component.a/ui5.yaml | 5 + test/fixtures/component.h/pom.xml | 41 + .../webapp-project.artifactId/manifest.json | 13 + .../webapp-properties.appId/manifest.json | 13 + .../manifest.json | 13 + test/fixtures/component.h/webapp/Component.js | 8 + .../fixtures/component.h/webapp/manifest.json | 13 + .../component.h/webapp/sectionsA/section1.js | 3 + .../component.h/webapp/sectionsA/section2.js | 3 + .../component.h/webapp/sectionsA/section3.js | 3 + .../component.h/webapp/sectionsB/section1.js | 3 + .../component.h/webapp/sectionsB/section2.js | 3 + .../component.h/webapp/sectionsB/section3.js | 3 + test/lib/specifications/types/Component.js | 679 ++++++++++++ .../__helper__/builder-bundleOptions.js | 11 +- .../schema/__helper__/customConfiguration.js | 4 +- .../validation/schema/__helper__/extension.js | 4 +- .../validation/schema/__helper__/framework.js | 12 +- .../validation/schema/__helper__/project.js | 56 +- .../schema/specVersion/kind/extension.js | 2 +- .../schema/specVersion/kind/project.js | 22 + .../specVersion/kind/project/application.js | 12 +- .../specVersion/kind/project/component.js | 967 ++++++++++++++++++ .../specVersion/kind/project/library.js | 12 +- .../schema/specVersion/kind/project/module.js | 4 +- .../specVersion/kind/project/theme-library.js | 4 +- test/lib/validation/schema/ui5.js | 4 +- 78 files changed, 2539 insertions(+), 73 deletions(-) create mode 100644 lib/specifications/types/Component.js create mode 100644 lib/validation/schema/specVersion/kind/project/component.json create mode 100644 test/fixtures/component.a/middleware.a.js create mode 100644 test/fixtures/component.a/node_modules/collection/library.a/package.json create mode 100644 test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library create mode 100644 test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less create mode 100644 test/fixtures/component.a/node_modules/collection/library.a/test/library/a/Test.html create mode 100644 test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml create mode 100644 test/fixtures/component.a/node_modules/collection/library.b/package.json create mode 100644 test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library create mode 100644 test/fixtures/component.a/node_modules/collection/library.b/test/library/b/Test.html create mode 100644 test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml create mode 100644 test/fixtures/component.a/node_modules/collection/library.c/package.json create mode 100644 test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library create mode 100644 test/fixtures/component.a/node_modules/collection/library.c/test/LibraryC/Test.html create mode 100644 test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml create mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json create mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library create mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/test/library/d/Test.html create mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml create mode 100644 test/fixtures/component.a/node_modules/collection/package.json create mode 100644 test/fixtures/component.a/node_modules/collection/ui5.yaml create mode 100644 test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library create mode 100644 test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js create mode 100644 test/fixtures/component.a/node_modules/library.d/main/test/library/d/Test.html create mode 100644 test/fixtures/component.a/node_modules/library.d/package.json create mode 100644 test/fixtures/component.a/node_modules/library.d/ui5.yaml create mode 100644 test/fixtures/component.a/package.json create mode 100644 test/fixtures/component.a/src/index.html create mode 100644 test/fixtures/component.a/src/manifest.json create mode 100644 test/fixtures/component.a/src/test.js create mode 100644 test/fixtures/component.a/task.a.js create mode 100644 test/fixtures/component.a/ui5-test-configPath.yaml create mode 100644 test/fixtures/component.a/ui5-test-corrupt.yaml create mode 100644 test/fixtures/component.a/ui5-test-empty.yaml create mode 100644 test/fixtures/component.a/ui5-test-error.yaml create mode 100644 test/fixtures/component.a/ui5.yaml create mode 100644 test/fixtures/component.h/pom.xml create mode 100644 test/fixtures/component.h/webapp-project.artifactId/manifest.json create mode 100644 test/fixtures/component.h/webapp-properties.appId/manifest.json create mode 100644 test/fixtures/component.h/webapp-properties.componentName/manifest.json create mode 100644 test/fixtures/component.h/webapp/Component.js create mode 100644 test/fixtures/component.h/webapp/manifest.json create mode 100644 test/fixtures/component.h/webapp/sectionsA/section1.js create mode 100644 test/fixtures/component.h/webapp/sectionsA/section2.js create mode 100644 test/fixtures/component.h/webapp/sectionsA/section3.js create mode 100644 test/fixtures/component.h/webapp/sectionsB/section1.js create mode 100644 test/fixtures/component.h/webapp/sectionsB/section2.js create mode 100644 test/fixtures/component.h/webapp/sectionsB/section3.js create mode 100644 test/lib/specifications/types/Component.js create mode 100644 test/lib/validation/schema/specVersion/kind/project/component.js diff --git a/lib/specifications/Specification.js b/lib/specifications/Specification.js index 5c2af4142..3e60eed07 100644 --- a/lib/specifications/Specification.js +++ b/lib/specifications/Specification.js @@ -39,6 +39,9 @@ class Specification { case "application": { return createAndInitializeSpec("types/Application.js", parameters); } + case "component": { + return createAndInitializeSpec("types/Component.js", parameters); + } case "library": { return createAndInitializeSpec("types/Library.js", parameters); } diff --git a/lib/specifications/SpecificationVersion.js b/lib/specifications/SpecificationVersion.js index ae48edee3..d53adb2b0 100644 --- a/lib/specifications/SpecificationVersion.js +++ b/lib/specifications/SpecificationVersion.js @@ -4,7 +4,7 @@ const SPEC_VERSION_PATTERN = /^\d+\.\d+$/; const SUPPORTED_VERSIONS = [ "0.1", "1.0", "1.1", "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", - "3.0" + "3.0", "3.1" ]; /** diff --git a/lib/specifications/types/Application.js b/lib/specifications/types/Application.js index 05303eb92..9506c74b9 100644 --- a/lib/specifications/types/Application.js +++ b/lib/specifications/types/Application.js @@ -66,11 +66,17 @@ class Application extends ComponentProject { return null; // Applications do not have a dedicated test directory } + /** + * Get a resource reader for the sources of the project (excluding any test resources) + * without a virtual base path + * + * @returns {@ui5/fs/ReaderCollection} Reader collection + */ _getRawSourceReader() { return createReader({ fsBasePath: this.getSourcePath(), virBasePath: "/", - name: `Source reader for application project ${this.getName()}`, + name: `Raw source reader for application project ${this.getName()}`, project: this }); } diff --git a/lib/specifications/types/Component.js b/lib/specifications/types/Component.js new file mode 100644 index 000000000..227dc629c --- /dev/null +++ b/lib/specifications/types/Component.js @@ -0,0 +1,259 @@ +import fsPath from "node:path"; +import ComponentProject from "../ComponentProject.js"; +import {createReader} from "@ui5/fs/resourceFactory"; + +/** + * Component + * + * @public + * @class + * @alias @ui5/project/specifications/types/Component + * @extends @ui5/project/specifications/ComponentProject + * @hideconstructor + */ +class Component extends ComponentProject { + constructor(parameters) { + super(parameters); + + this._pManifests = Object.create(null); + + this._srcPath = "src"; + this._testPath = "test"; + this._testPathExists = false; + + this._propertiesFilesSourceEncoding = "UTF-8"; + } + + /* === Attributes === */ + + /** + * Get the cachebuster signature type configuration of the project + * + * @returns {string} time or hash + */ + getCachebusterSignatureType() { + return this._config.builder && this._config.builder.cachebuster && + this._config.builder.cachebuster.signatureType || "time"; + } + + /** + * Get the path of the project's source directory. This might not be POSIX-style on some platforms. + * + * @public + * @returns {string} Absolute path to the source directory of the project + */ + getSourcePath() { + return fsPath.join(this.getRootPath(), this._srcPath); + } + + /* === Resource Access === */ + /** + * Get a resource reader for the sources of the project (excluding any test resources) + * + * @param {string[]} excludes List of glob patterns to exclude + * @returns {@ui5/fs/ReaderCollection} Reader collection + */ + _getSourceReader(excludes) { + return createReader({ + fsBasePath: this.getSourcePath(), + virBasePath: `/resources/${this._namespace}/`, + name: `Source reader for component project ${this.getName()}`, + project: this, + excludes + }); + } + + /** + * Get a resource reader for the test-resources of the project + * + * @param {string[]} excludes List of glob patterns to exclude + * @returns {@ui5/fs/ReaderCollection} Reader collection + */ + _getTestReader(excludes) { + if (!this._testPathExists) { + return null; + } + const testReader = createReader({ + fsBasePath: fsPath.join(this.getRootPath(), this._testPath), + virBasePath: `/test-resources/${this._namespace}/`, + name: `Runtime test-resources reader for component project ${this.getName()}`, + project: this, + excludes + }); + return testReader; + } + + /** + * Get a resource reader for the sources of the project (excluding any test resources) + * without a virtual base path + * + * @returns {@ui5/fs/ReaderCollection} Reader collection + */ + _getRawSourceReader() { + return createReader({ + fsBasePath: this.getSourcePath(), + virBasePath: "/", + name: `Raw source reader for component project ${this.getName()}`, + project: this + }); + } + + /* === Internals === */ + /** + * @private + * @param {object} config Configuration object + */ + async _configureAndValidatePaths(config) { + await super._configureAndValidatePaths(config); + + if (config.resources && config.resources.configuration && config.resources.configuration.paths) { + if (config.resources.configuration.paths.src) { + this._srcPath = config.resources.configuration.paths.src; + } + if (config.resources.configuration.paths.test) { + this._testPath = config.resources.configuration.paths.test; + } + } + if (!(await this._dirExists("/" + this._srcPath))) { + throw new Error( + `Unable to find source directory '${this._srcPath}' in component project ${this.getName()}`); + } + this._testPathExists = await this._dirExists("/" + this._testPath); + + this._log.verbose(`Path mapping for component project ${this.getName()}:`); + this._log.verbose(` Physical root path: ${this.getRootPath()}`); + this._log.verbose(` Mapped to:`); + this._log.verbose(` /resources/ => ${this._srcPath}`); + this._log.verbose( + ` /test-resources/ => ${this._testPath}${this._testPathExists ? "" : " [does not exist]"}`); + } + + /** + * @private + * @param {object} config Configuration object + * @param {object} buildDescription Cache metadata object + */ + async _parseConfiguration(config, buildDescription) { + await super._parseConfiguration(config, buildDescription); + + if (buildDescription) { + this._namespace = buildDescription.namespace; + return; + } + this._namespace = await this._getNamespace(); + } + + /** + * Determine component namespace either based on a project`s + * manifest.json or manifest.appdescr_variant (fallback if present) + * + * @returns {string} Namespace of the project + * @throws {Error} if namespace can not be determined + */ + async _getNamespace() { + try { + return await this._getNamespaceFromManifestJson(); + } catch (manifestJsonError) { + if (manifestJsonError.code !== "ENOENT") { + throw manifestJsonError; + } + // No manifest.json present + // => attempt fallback to manifest.appdescr_variant (typical for App Variants) + try { + return await this._getNamespaceFromManifestAppDescVariant(); + } catch (appDescVarError) { + if (appDescVarError.code === "ENOENT") { + // Fallback not possible: No manifest.appdescr_variant present + // => Throw error indicating missing manifest.json + // (do not mention manifest.appdescr_variant since it is only + // relevant for the rather "uncommon" App Variants) + throw new Error( + `Could not find required manifest.json for project ` + + `${this.getName()}: ${manifestJsonError.message}`); + } + throw appDescVarError; + } + } + } + + /** + * Determine application namespace by checking manifest.json. + * Any maven placeholders are resolved from the projects pom.xml + * + * @returns {string} Namespace of the project + * @throws {Error} if namespace can not be determined + */ + async _getNamespaceFromManifestJson() { + const manifest = await this._getManifest("/manifest.json"); + let appId; + // check for a proper sap.app/id in manifest.json to determine namespace + if (manifest["sap.app"] && manifest["sap.app"].id) { + appId = manifest["sap.app"].id; + } else { + throw new Error( + `No sap.app/id configuration found in manifest.json of project ${this.getName()}`); + } + + if (this._hasMavenPlaceholder(appId)) { + try { + appId = await this._resolveMavenPlaceholder(appId); + } catch (err) { + throw new Error( + `Failed to resolve namespace of project ${this.getName()}: ${err.message}`); + } + } + const namespace = appId.replace(/\./g, "/"); + this._log.verbose( + `Namespace of project ${this.getName()} is ${namespace} (from manifest.json)`); + return namespace; + } + + /** + * Determine application namespace by checking manifest.appdescr_variant. + * + * @returns {string} Namespace of the project + * @throws {Error} if namespace can not be determined + */ + async _getNamespaceFromManifestAppDescVariant() { + const manifest = await this._getManifest("/manifest.appdescr_variant"); + let appId; + // check for the id property in manifest.appdescr_variant to determine namespace + if (manifest && manifest.id) { + appId = manifest.id; + } else { + throw new Error( + `No "id" property found in manifest.appdescr_variant of project ${this.getName()}`); + } + + const namespace = appId.replace(/\./g, "/"); + this._log.verbose( + `Namespace of project ${this.getName()} is ${namespace} (from manifest.appdescr_variant)`); + return namespace; + } + + /** + * Reads and parses a JSON file with the provided name from the projects source directory + * + * @param {string} filePath Name of the JSON file to read. Typically "manifest.json" or "manifest.appdescr_variant" + * @returns {Promise} resolves with an object containing the content requested manifest file + */ + async _getManifest(filePath) { + if (this._pManifests[filePath]) { + return this._pManifests[filePath]; + } + return this._pManifests[filePath] = this._getRawSourceReader().byPath(filePath) + .then(async (resource) => { + if (!resource) { + throw new Error( + `Could not find resource ${filePath} in project ${this.getName()}`); + } + return JSON.parse(await resource.getString()); + }).catch((err) => { + throw new Error( + `Failed to read ${filePath} for project ` + + `${this.getName()}: ${err.message}`); + }); + } +} + +export default Component; diff --git a/lib/specifications/types/Library.js b/lib/specifications/types/Library.js index 064568570..abf7faf28 100644 --- a/lib/specifications/types/Library.js +++ b/lib/specifications/types/Library.js @@ -107,9 +107,10 @@ class Library extends ComponentProject { } /** - * * Get a resource reader for the sources of the project (excluding any test resources) + * without a virtual base path * In the future the path structure can be flat or namespaced depending on the project + * setup * * @returns {@ui5/fs/ReaderCollection} Reader collection */ @@ -117,7 +118,7 @@ class Library extends ComponentProject { return resourceFactory.createReader({ fsBasePath: this.getSourcePath(), virBasePath: "/", - name: `Source reader for library project ${this.getName()}`, + name: `Raw source reader for library project ${this.getName()}`, project: this }); } diff --git a/lib/validation/schema/specVersion/kind/extension.json b/lib/validation/schema/specVersion/kind/extension.json index 27bf6005c..633aaea6b 100644 --- a/lib/validation/schema/specVersion/kind/extension.json +++ b/lib/validation/schema/specVersion/kind/extension.json @@ -5,7 +5,7 @@ "type": "object", "required": ["specVersion", "kind", "type", "metadata"], "properties": { - "specVersion": { "enum": ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] }, + "specVersion": { "enum": ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] }, "kind": { "enum": ["extension"] }, diff --git a/lib/validation/schema/specVersion/kind/extension/project-shim.json b/lib/validation/schema/specVersion/kind/extension/project-shim.json index 415785f1d..cb5a4dbfa 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": ["3.0"] } + "specVersion": { "enum": ["3.0", "3.1"] } } }, "then": { "additionalProperties": false, "properties": { "specVersion": { - "enum": ["3.0"] + "enum": ["3.0", "3.1"] }, "kind": { "enum": ["extension"] diff --git a/lib/validation/schema/specVersion/kind/extension/server-middleware.json b/lib/validation/schema/specVersion/kind/extension/server-middleware.json index a65db5b56..1b46323be 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": ["3.0"] } + "specVersion": { "enum": ["3.0", "3.1"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["3.0"] }, + "specVersion": { "enum": ["3.0", "3.1"] }, "kind": { "enum": ["extension"] }, diff --git a/lib/validation/schema/specVersion/kind/extension/task.json b/lib/validation/schema/specVersion/kind/extension/task.json index f19291e0c..7e02c82eb 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": ["3.0"] } + "specVersion": { "enum": ["3.0", "3.1"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["3.0"] }, + "specVersion": { "enum": ["3.0", "3.1"] }, "kind": { "enum": ["extension"] }, diff --git a/lib/validation/schema/specVersion/kind/project.json b/lib/validation/schema/specVersion/kind/project.json index f42fa8a2b..d1aa74b58 100644 --- a/lib/validation/schema/specVersion/kind/project.json +++ b/lib/validation/schema/specVersion/kind/project.json @@ -5,7 +5,7 @@ "type": "object", "required": ["specVersion", "type"], "properties": { - "specVersion": { "enum": ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] }, + "specVersion": { "enum": ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] }, "kind": { "enum": ["project", null], "$comment": "Using null to allow not defining 'kind' which defaults to project" @@ -13,12 +13,14 @@ "type": { "enum": [ "application", + "component", "library", "theme-library", "module" ] } }, + "if": { "properties": { "type": {"const": null} @@ -61,6 +63,16 @@ }, "then": { "$ref": "project/module.json" + }, + "else": { + "if": { + "properties": { + "type": {"const": "component"} + } + }, + "then": { + "$ref": "project/component.json" + } } } } diff --git a/lib/validation/schema/specVersion/kind/project/application.json b/lib/validation/schema/specVersion/kind/project/application.json index 81073634a..1091be04e 100644 --- a/lib/validation/schema/specVersion/kind/project/application.json +++ b/lib/validation/schema/specVersion/kind/project/application.json @@ -6,13 +6,13 @@ "required": ["specVersion", "type", "metadata"], "if": { "properties": { - "specVersion": { "enum": ["3.0"] } + "specVersion": { "enum": ["3.0", "3.1"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["3.0"] }, + "specVersion": { "enum": ["3.0", "3.1"] }, "kind": { "enum": ["project", null] }, diff --git a/lib/validation/schema/specVersion/kind/project/component.json b/lib/validation/schema/specVersion/kind/project/component.json new file mode 100644 index 000000000..49539317f --- /dev/null +++ b/lib/validation/schema/specVersion/kind/project/component.json @@ -0,0 +1,108 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema", + "$id": "http://ui5.sap/schema/specVersion/kind/project/component.json", + + "type": "object", + "required": ["specVersion", "type", "metadata"], + "if": { + "properties": { + "specVersion": { "enum": ["3.1"] } + } + }, + "then": { + "additionalProperties": false, + "properties": { + "specVersion": { "enum": ["3.1"] }, + "kind": { + "enum": ["project", null] + }, + "type": { + "enum": ["component"] + }, + "metadata": { + "$ref": "../project.json#/definitions/metadata-3.0" + }, + "framework": { + "$ref": "../project.json#/definitions/framework" + }, + "resources": { + "$ref": "#/definitions/resources" + }, + "builder": { + "$ref": "#/definitions/builder-specVersion-3.0" + }, + "server": { + "$ref": "../project.json#/definitions/server" + }, + "customConfiguration": { + "type": "object", + "additionalProperties": true + } + } + }, + "else": { + }, + + "definitions": { + "resources": { + "type": "object", + "additionalProperties": false, + "properties": { + "configuration": { + "type": "object", + "additionalProperties": false, + "properties": { + "propertiesFileSourceEncoding": { + "$ref": "../project.json#/definitions/resources-configuration-propertiesFileSourceEncoding" + }, + "paths": { + "type": "object", + "additionalProperties": false, + "properties": { + "src": { + "type": "string" + }, + "test": { + "type": "string" + } + } + } + } + } + } + }, + "builder-specVersion-3.0": { + "type": "object", + "additionalProperties": false, + "properties": { + "resources": { + "$ref": "../project.json#/definitions/builder-resources" + }, + "cachebuster": { + "type": "object", + "additionalProperties": false, + "properties": { + "signatureType": { + "enum": ["time", "hash"] + } + } + }, + "bundles": { + "$ref": "../project.json#/definitions/builder-bundles-3.0" + }, + "componentPreload": { + "$ref": "../project.json#/definitions/builder-componentPreload-specVersion-2.3" + }, + "customTasks": { + "$ref": "../project.json#/definitions/customTasks" + }, + "minification": { + "$ref": "../project.json#/definitions/builder-minification" + }, + "settings": { + "$ref": "../project.json#/definitions/builder-settings" + } + } + } + } +} diff --git a/lib/validation/schema/specVersion/kind/project/library.json b/lib/validation/schema/specVersion/kind/project/library.json index d36a1f83e..d5114b633 100644 --- a/lib/validation/schema/specVersion/kind/project/library.json +++ b/lib/validation/schema/specVersion/kind/project/library.json @@ -6,13 +6,13 @@ "required": ["specVersion", "type", "metadata"], "if": { "properties": { - "specVersion": { "enum": ["3.0"] } + "specVersion": { "enum": ["3.0", "3.1"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["3.0"] }, + "specVersion": { "enum": ["3.0", "3.1"] }, "kind": { "enum": ["project", null] }, diff --git a/lib/validation/schema/specVersion/kind/project/module.json b/lib/validation/schema/specVersion/kind/project/module.json index 9684f27d1..586a6adf1 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": ["3.0"] } + "specVersion": { "enum": ["3.0", "3.1"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["3.0"] }, + "specVersion": { "enum": ["3.0", "3.1"] }, "kind": { "enum": ["project", null] }, diff --git a/lib/validation/schema/specVersion/kind/project/theme-library.json b/lib/validation/schema/specVersion/kind/project/theme-library.json index 522b7064a..44f3f2aa5 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": ["3.0"] } + "specVersion": { "enum": ["3.0", "3.1"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["3.0"] }, + "specVersion": { "enum": ["3.0", "3.1"] }, "kind": { "enum": ["project", null] }, diff --git a/lib/validation/schema/specVersion/specVersion.json b/lib/validation/schema/specVersion/specVersion.json index 16458d467..6debcbd3e 100644 --- a/lib/validation/schema/specVersion/specVersion.json +++ b/lib/validation/schema/specVersion/specVersion.json @@ -5,7 +5,7 @@ "type": "object", "required": ["specVersion"], "properties": { - "specVersion": { "enum": ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] }, + "specVersion": { "enum": ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] }, "kind": { "enum": ["project", "extension", null], "$comment": "Using null to allow not defining 'kind' which defaults to project" diff --git a/lib/validation/schema/ui5.json b/lib/validation/schema/ui5.json index 59af95301..61795c909 100644 --- a/lib/validation/schema/ui5.json +++ b/lib/validation/schema/ui5.json @@ -10,17 +10,17 @@ "properties": { "specVersion": { "enum": [ - "3.0", + "3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0", "1.1", "1.0", "0.1" ], - "errorMessage": "Unsupported \"specVersion\"\nYour UI5 CLI installation might be outdated.\nSupported specification versions: \"3.0\", \"2.6\", \"2.5\", \"2.4\", \"2.3\", \"2.2\", \"2.1\", \"2.0\", \"1.1\", \"1.0\", \"0.1\"\nFor details, see: https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions" + "errorMessage": "Unsupported \"specVersion\"\nYour UI5 CLI installation might be outdated.\nSupported specification versions: \"3.1\", \"3.0\", \"2.6\", \"2.5\", \"2.4\", \"2.3\", \"2.2\", \"2.1\", \"2.0\", \"1.1\", \"1.0\", \"0.1\"\nFor details, see: https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions" } }, "if": { "properties": { - "specVersion": { "enum": ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] } + "specVersion": { "enum": ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"] } } }, "then": { diff --git a/test/fixtures/component.a/middleware.a.js b/test/fixtures/component.a/middleware.a.js new file mode 100644 index 000000000..ea41b01de --- /dev/null +++ b/test/fixtures/component.a/middleware.a.js @@ -0,0 +1 @@ +module.exports = function () {}; diff --git a/test/fixtures/component.a/node_modules/collection/library.a/package.json b/test/fixtures/component.a/node_modules/collection/library.a/package.json new file mode 100644 index 000000000..2179673d4 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.a/package.json @@ -0,0 +1,17 @@ +{ + "name": "library.a", + "version": "1.0.0", + "description": "Simple SAPUI5 based library", + "dependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "ui5": { + "name": "library.a", + "type": "library", + "settings": { + "src": "src", + "test": "test" + } + } +} diff --git a/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library b/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library new file mode 100644 index 000000000..25c8603f3 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library @@ -0,0 +1,17 @@ + + + + library.a + SAP SE + ${copyright} + ${version} + + Library A + + + + library.d + + + + diff --git a/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less b/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less new file mode 100644 index 000000000..ff0f1d5e3 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less @@ -0,0 +1,6 @@ +@libraryAColor1: lightgoldenrodyellow; + +.library-a-foo { + color: @libraryAColor1; + padding: 1px 2px 3px 4px; +} diff --git a/test/fixtures/component.a/node_modules/collection/library.a/test/library/a/Test.html b/test/fixtures/component.a/node_modules/collection/library.a/test/library/a/Test.html new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml b/test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml new file mode 100644 index 000000000..8d4784313 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.a diff --git a/test/fixtures/component.a/node_modules/collection/library.b/package.json b/test/fixtures/component.a/node_modules/collection/library.b/package.json new file mode 100644 index 000000000..2a0243b16 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.b/package.json @@ -0,0 +1,9 @@ +{ + "name": "library.b", + "version": "1.0.0", + "description": "Simple SAPUI5 based library", + "dependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library b/test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library new file mode 100644 index 000000000..36052aceb --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library @@ -0,0 +1,17 @@ + + + + library.b + SAP SE + ${copyright} + ${version} + + Library B + + + + library.d + + + + diff --git a/test/fixtures/component.a/node_modules/collection/library.b/test/library/b/Test.html b/test/fixtures/component.a/node_modules/collection/library.b/test/library/b/Test.html new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml b/test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml new file mode 100644 index 000000000..b2fe5be59 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.b diff --git a/test/fixtures/component.a/node_modules/collection/library.c/package.json b/test/fixtures/component.a/node_modules/collection/library.c/package.json new file mode 100644 index 000000000..64ac75d6f --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.c/package.json @@ -0,0 +1,9 @@ +{ + "name": "library.c", + "version": "1.0.0", + "description": "Simple SAPUI5 based library", + "dependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library b/test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library new file mode 100644 index 000000000..4180ce2af --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library @@ -0,0 +1,17 @@ + + + + library.c + SAP SE + ${copyright} + ${version} + + Library C + + + + library.d + + + + diff --git a/test/fixtures/component.a/node_modules/collection/library.c/test/LibraryC/Test.html b/test/fixtures/component.a/node_modules/collection/library.c/test/LibraryC/Test.html new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml b/test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml new file mode 100644 index 000000000..7c5e38a7f --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.c diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json new file mode 100644 index 000000000..90c75040a --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json @@ -0,0 +1,9 @@ +{ + "name": "library.d", + "version": "1.0.0", + "description": "Simple SAPUI5 based library", + "dependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library new file mode 100644 index 000000000..21251d1bb --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library @@ -0,0 +1,11 @@ + + + + library.d + SAP SE + ${copyright} + ${version} + + Library D + + diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/test/library/d/Test.html b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/test/library/d/Test.html new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml new file mode 100644 index 000000000..a47c1f64c --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml @@ -0,0 +1,10 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d +resources: + configuration: + paths: + src: main/src + test: main/test diff --git a/test/fixtures/component.a/node_modules/collection/package.json b/test/fixtures/component.a/node_modules/collection/package.json new file mode 100644 index 000000000..81b948438 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/package.json @@ -0,0 +1,18 @@ +{ + "name": "collection", + "version": "1.0.0", + "description": "Simple Collection", + "dependencies": { + "library.d": "file:../library.d" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "collection": { + "modules": { + "library.a": "./library.a", + "library.b": "./library.b", + "library.c": "./library.c" + } + } +} diff --git a/test/fixtures/component.a/node_modules/collection/ui5.yaml b/test/fixtures/component.a/node_modules/collection/ui5.yaml new file mode 100644 index 000000000..e47048de6 --- /dev/null +++ b/test/fixtures/component.a/node_modules/collection/ui5.yaml @@ -0,0 +1,12 @@ +specVersion: "2.1" +metadata: + name: application.a.collection.dependency.shim +kind: extension +type: project-shim +shims: + collections: + collection: + modules: + "library.a": "./library.a" + "library.b": "./library.b" + "library.c": "./library.c" \ No newline at end of file diff --git a/test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library b/test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library new file mode 100644 index 000000000..53c2d14c9 --- /dev/null +++ b/test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library @@ -0,0 +1,11 @@ + + + + library.d + SAP SE + Some fancy copyright + ${version} + + Library D + + diff --git a/test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js b/test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js new file mode 100644 index 000000000..81e734360 --- /dev/null +++ b/test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js @@ -0,0 +1,4 @@ +/*! + * ${copyright} + */ +console.log('HelloWorld'); \ No newline at end of file diff --git a/test/fixtures/component.a/node_modules/library.d/main/test/library/d/Test.html b/test/fixtures/component.a/node_modules/library.d/main/test/library/d/Test.html new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/component.a/node_modules/library.d/package.json b/test/fixtures/component.a/node_modules/library.d/package.json new file mode 100644 index 000000000..90c75040a --- /dev/null +++ b/test/fixtures/component.a/node_modules/library.d/package.json @@ -0,0 +1,9 @@ +{ + "name": "library.d", + "version": "1.0.0", + "description": "Simple SAPUI5 based library", + "dependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/test/fixtures/component.a/node_modules/library.d/ui5.yaml b/test/fixtures/component.a/node_modules/library.d/ui5.yaml new file mode 100644 index 000000000..a47c1f64c --- /dev/null +++ b/test/fixtures/component.a/node_modules/library.d/ui5.yaml @@ -0,0 +1,10 @@ +--- +specVersion: "2.3" +type: library +metadata: + name: library.d +resources: + configuration: + paths: + src: main/src + test: main/test diff --git a/test/fixtures/component.a/package.json b/test/fixtures/component.a/package.json new file mode 100644 index 000000000..cd7457d2b --- /dev/null +++ b/test/fixtures/component.a/package.json @@ -0,0 +1,13 @@ +{ + "name": "component.a", + "version": "1.0.0", + "description": "Simple SAPUI5 based component", + "main": "index.html", + "dependencies": { + "library.d": "file:../library.d", + "collection": "file:../collection" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + } +} diff --git a/test/fixtures/component.a/src/index.html b/test/fixtures/component.a/src/index.html new file mode 100644 index 000000000..77b0207cc --- /dev/null +++ b/test/fixtures/component.a/src/index.html @@ -0,0 +1,9 @@ + + + + Application A + + + + + \ No newline at end of file diff --git a/test/fixtures/component.a/src/manifest.json b/test/fixtures/component.a/src/manifest.json new file mode 100644 index 000000000..781945df9 --- /dev/null +++ b/test/fixtures/component.a/src/manifest.json @@ -0,0 +1,13 @@ +{ + "_version": "1.1.0", + "sap.app": { + "_version": "1.1.0", + "id": "id1", + "type": "application", + "applicationVersion": { + "version": "1.2.2" + }, + "embeds": ["embedded"], + "title": "{{title}}" + } +} \ No newline at end of file diff --git a/test/fixtures/component.a/src/test.js b/test/fixtures/component.a/src/test.js new file mode 100644 index 000000000..a3df410c3 --- /dev/null +++ b/test/fixtures/component.a/src/test.js @@ -0,0 +1,5 @@ +function test(paramA) { + var variableA = paramA; + console.log(variableA); +} +test(); diff --git a/test/fixtures/component.a/task.a.js b/test/fixtures/component.a/task.a.js new file mode 100644 index 000000000..ea41b01de --- /dev/null +++ b/test/fixtures/component.a/task.a.js @@ -0,0 +1 @@ +module.exports = function () {}; diff --git a/test/fixtures/component.a/ui5-test-configPath.yaml b/test/fixtures/component.a/ui5-test-configPath.yaml new file mode 100644 index 000000000..9dfaec758 --- /dev/null +++ b/test/fixtures/component.a/ui5-test-configPath.yaml @@ -0,0 +1,7 @@ +--- +specVersion: "3.1" +type: component +metadata: + name: component.a +customConfiguration: + configPathTest: true \ No newline at end of file diff --git a/test/fixtures/component.a/ui5-test-corrupt.yaml b/test/fixtures/component.a/ui5-test-corrupt.yaml new file mode 100644 index 000000000..ecce9d7e7 --- /dev/null +++ b/test/fixtures/component.a/ui5-test-corrupt.yaml @@ -0,0 +1 @@ +|-\nfoo\nbar diff --git a/test/fixtures/component.a/ui5-test-empty.yaml b/test/fixtures/component.a/ui5-test-empty.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/test/fixtures/component.a/ui5-test-error.yaml b/test/fixtures/component.a/ui5-test-error.yaml new file mode 100644 index 000000000..639b4889a --- /dev/null +++ b/test/fixtures/component.a/ui5-test-error.yaml @@ -0,0 +1,7 @@ +--- +specVersion: "3.1" +type: component +metadata: + name: component.a +xyz: + foo: true \ No newline at end of file diff --git a/test/fixtures/component.a/ui5.yaml b/test/fixtures/component.a/ui5.yaml new file mode 100644 index 000000000..f149b0e87 --- /dev/null +++ b/test/fixtures/component.a/ui5.yaml @@ -0,0 +1,5 @@ +--- +specVersion: "3.1" +type: component +metadata: + name: component.a diff --git a/test/fixtures/component.h/pom.xml b/test/fixtures/component.h/pom.xml new file mode 100644 index 000000000..7ee5daf7a --- /dev/null +++ b/test/fixtures/component.h/pom.xml @@ -0,0 +1,41 @@ + + + + + + + 4.0.0 + + + + + com.sap.test + component.h + 1.0.0 + war + + + + + component.h + Simple SAPUI5 based component + + + + + + + component.h + + + + + diff --git a/test/fixtures/component.h/webapp-project.artifactId/manifest.json b/test/fixtures/component.h/webapp-project.artifactId/manifest.json new file mode 100644 index 000000000..7de6072ce --- /dev/null +++ b/test/fixtures/component.h/webapp-project.artifactId/manifest.json @@ -0,0 +1,13 @@ +{ + "_version": "1.1.0", + "sap.app": { + "_version": "1.1.0", + "id": "${project.artifactId}", + "type": "application", + "applicationVersion": { + "version": "1.2.2" + }, + "embeds": ["embedded"], + "title": "{{title}}" + } +} diff --git a/test/fixtures/component.h/webapp-properties.appId/manifest.json b/test/fixtures/component.h/webapp-properties.appId/manifest.json new file mode 100644 index 000000000..e1515df70 --- /dev/null +++ b/test/fixtures/component.h/webapp-properties.appId/manifest.json @@ -0,0 +1,13 @@ +{ + "_version": "1.1.0", + "sap.app": { + "_version": "1.1.0", + "id": "${appId}", + "type": "application", + "applicationVersion": { + "version": "1.2.2" + }, + "embeds": ["embedded"], + "title": "{{title}}" + } +} diff --git a/test/fixtures/component.h/webapp-properties.componentName/manifest.json b/test/fixtures/component.h/webapp-properties.componentName/manifest.json new file mode 100644 index 000000000..7d63e359c --- /dev/null +++ b/test/fixtures/component.h/webapp-properties.componentName/manifest.json @@ -0,0 +1,13 @@ +{ + "_version": "1.1.0", + "sap.app": { + "_version": "1.1.0", + "id": "${componentName}", + "type": "application", + "applicationVersion": { + "version": "1.2.2" + }, + "embeds": ["embedded"], + "title": "{{title}}" + } +} diff --git a/test/fixtures/component.h/webapp/Component.js b/test/fixtures/component.h/webapp/Component.js new file mode 100644 index 000000000..cb9bd4068 --- /dev/null +++ b/test/fixtures/component.h/webapp/Component.js @@ -0,0 +1,8 @@ +sap.ui.define(["sap/ui/core/UIComponent"], function(UIComponent){ + "use strict"; + return UIComponent.extend('application.h.Component', { + metadata: { + manifest: "json" + } + }); +}); diff --git a/test/fixtures/component.h/webapp/manifest.json b/test/fixtures/component.h/webapp/manifest.json new file mode 100644 index 000000000..32b7e4a84 --- /dev/null +++ b/test/fixtures/component.h/webapp/manifest.json @@ -0,0 +1,13 @@ +{ + "_version": "1.1.0", + "sap.app": { + "_version": "1.1.0", + "id": "application.h", + "type": "application", + "applicationVersion": { + "version": "1.2.2" + }, + "embeds": ["embedded"], + "title": "{{title}}" + } +} diff --git a/test/fixtures/component.h/webapp/sectionsA/section1.js b/test/fixtures/component.h/webapp/sectionsA/section1.js new file mode 100644 index 000000000..ac4a81296 --- /dev/null +++ b/test/fixtures/component.h/webapp/sectionsA/section1.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/m/Button"], function(Button) { + console.log("Section 1 included"); +}); diff --git a/test/fixtures/component.h/webapp/sectionsA/section2.js b/test/fixtures/component.h/webapp/sectionsA/section2.js new file mode 100644 index 000000000..e009c8286 --- /dev/null +++ b/test/fixtures/component.h/webapp/sectionsA/section2.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/m/Button"], function(Button) { + console.log("Section 2 included"); +}); diff --git a/test/fixtures/component.h/webapp/sectionsA/section3.js b/test/fixtures/component.h/webapp/sectionsA/section3.js new file mode 100644 index 000000000..5fd9349d4 --- /dev/null +++ b/test/fixtures/component.h/webapp/sectionsA/section3.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/m/Button"], function(Button) { + console.log("Section 3 included"); +}); diff --git a/test/fixtures/component.h/webapp/sectionsB/section1.js b/test/fixtures/component.h/webapp/sectionsB/section1.js new file mode 100644 index 000000000..ac4a81296 --- /dev/null +++ b/test/fixtures/component.h/webapp/sectionsB/section1.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/m/Button"], function(Button) { + console.log("Section 1 included"); +}); diff --git a/test/fixtures/component.h/webapp/sectionsB/section2.js b/test/fixtures/component.h/webapp/sectionsB/section2.js new file mode 100644 index 000000000..e009c8286 --- /dev/null +++ b/test/fixtures/component.h/webapp/sectionsB/section2.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/m/Button"], function(Button) { + console.log("Section 2 included"); +}); diff --git a/test/fixtures/component.h/webapp/sectionsB/section3.js b/test/fixtures/component.h/webapp/sectionsB/section3.js new file mode 100644 index 000000000..5fd9349d4 --- /dev/null +++ b/test/fixtures/component.h/webapp/sectionsB/section3.js @@ -0,0 +1,3 @@ +sap.ui.define(["sap/m/Button"], function(Button) { + console.log("Section 3 included"); +}); diff --git a/test/lib/specifications/types/Component.js b/test/lib/specifications/types/Component.js new file mode 100644 index 000000000..559d4a9f9 --- /dev/null +++ b/test/lib/specifications/types/Component.js @@ -0,0 +1,679 @@ +import test from "ava"; +import path from "node:path"; +import {fileURLToPath} from "node:url"; +import {createResource} from "@ui5/fs/resourceFactory"; +import sinonGlobal from "sinon"; +import Specification from "../../../../lib/specifications/Specification.js"; +import Component from "../../../../lib/specifications/types/Component.js"; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const componentAPath = path.join(__dirname, "..", "..", "..", "fixtures", "component.a"); +const componentHPath = path.join(__dirname, "..", "..", "..", "fixtures", "component.h"); + +test.beforeEach((t) => { + t.context.sinon = sinonGlobal.createSandbox(); + t.context.projectInput = { + id: "component.a.id", + version: "1.0.0", + modulePath: componentAPath, + configuration: { + specVersion: "3.1", + kind: "project", + type: "component", + metadata: {name: "component.a"} + } + }; + + t.context.componentHInput = { + id: "component.h.id", + version: "1.0.0", + modulePath: componentHPath, + configuration: { + specVersion: "3.1", + kind: "project", + type: "component", + metadata: {name: "component.h"}, + resources: { + configuration: { + paths: { + src: "webapp" + } + } + } + } + }; +}); + +test.afterEach.always((t) => { + t.context.sinon.restore(); +}); + +test("Correct class", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + t.true(project instanceof Component, `Is an instance of the Component class`); +}); + +test("getNamespace", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + t.is(project.getNamespace(), "id1", + "Returned correct namespace"); +}); + +test("getSourcePath", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + t.is(project.getSourcePath(), path.join(componentAPath, "src"), + "Returned correct source path"); +}); + +test("getCachebusterSignatureType: Default", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + t.is(project.getCachebusterSignatureType(), "time", + "Returned correct default cachebuster signature type configuration"); +}); + +test("getCachebusterSignatureType: Configuration", async (t) => { + const {projectInput} = t.context; + projectInput.configuration.builder = { + cachebuster: { + signatureType: "hash" + } + }; + const project = await Specification.create(projectInput); + t.is(project.getCachebusterSignatureType(), "hash", + "Returned correct default cachebuster signature type configuration"); +}); + +test("Access project resources via reader: buildtime style", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + const reader = project.getReader(); + const resource = await reader.byPath("/resources/id1/manifest.json"); + t.truthy(resource, "Found the requested resource"); + t.is(resource.getPath(), "/resources/id1/manifest.json", "Resource has correct path"); +}); + +test("Access project resources via reader: flat style", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + const reader = project.getReader({style: "flat"}); + const resource = await reader.byPath("/manifest.json"); + t.truthy(resource, "Found the requested resource"); + t.is(resource.getPath(), "/manifest.json", "Resource has correct path"); +}); + +test("Access project resources via reader: runtime style", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + const reader = project.getReader({style: "runtime"}); + const resource = await reader.byPath("/resources/id1/manifest.json"); + t.truthy(resource, "Found the requested resource"); + t.is(resource.getPath(), "/resources/id1/manifest.json", "Resource has correct path"); +}); + +test("Access project resources via reader w/ builder excludes", async (t) => { + const {projectInput} = t.context; + const baselineProject = await Specification.create(projectInput); + + projectInput.configuration.builder = { + resources: { + excludes: ["**/manifest.json"] + } + }; + const excludesProject = await Specification.create(projectInput); + + // We now have two projects: One with excludes and one without + // Always compare the results of both to make sure a file is really excluded because of the + // configuration and not because of a typo or because of it's absence in the fixture + + t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for default style"); + + t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for buildtime style"); + t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for buildtime style"); + + t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for dist style"); + t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for dist style"); + + t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for flat style"); + t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for flat style"); + + t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for runtime style"); + t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found excluded resource for runtime style"); +}); + +test("Access project resources via workspace w/ builder excludes", async (t) => { + const {projectInput} = t.context; + const baselineProject = await Specification.create(projectInput); + + projectInput.configuration.builder = { + resources: { + excludes: ["**/manifest.json"] + } + }; + const excludesProject = await Specification.create(projectInput); + + // We now have two projects: One with excludes and one without + // Always compare the results of both to make sure a file is really excluded because of the + // configuration and not because of a typo or because of it's absence in the fixture + + t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for default style"); +}); + +test("Access project resources w/ absolute builder excludes", async (t) => { + const {projectInput} = t.context; + const baselineProject = await Specification.create(projectInput); + + projectInput.configuration.builder = { + resources: { + excludes: ["/resources/id1/manifest.json"] + } + }; + const excludesProject = await Specification.create(projectInput); + + // We now have two projects: One with excludes and one without + // Always compare the results of both to make sure a file is really excluded because of the + // configuration and not because of a typo or because of it's absence in the fixture + + t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for default style"); + + t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for buildtime style"); + t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for buildtime style"); + + t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for dist style"); + t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for dist style"); + + t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for flat style"); + t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for flat style"); + + // Excludes are not applied for "runtime" style + t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for runtime style"); + t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found excluded resource for runtime style"); + + t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 0, + "Did not find excluded resource for default style"); +}); + +test("Access project resources w/ relative builder excludes", async (t) => { + const {projectInput} = t.context; + const baselineProject = await Specification.create(projectInput); + + projectInput.configuration.builder = { + resources: { + excludes: ["manifest.json"] // Has no effect since component excludes must be absolute or use wildcards + } + }; + const excludesProject = await Specification.create(projectInput); + + // We now have two projects: One with excludes and one without + // Always compare the results of both to make sure a file is really excluded because of the + // configuration and not because of a typo or because of it's absence in the fixture + + t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for default style"); + + t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for buildtime style"); + t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for buildtime style"); + + t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for dist style"); + t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for dist style"); + + t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for flat style"); + t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for flat style"); + + // Excludes are not applied for "runtime" style + t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for runtime style"); + t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found excluded resource for runtime style"); + + t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for default style"); +}); + +test("Access project resources w/ incorrect builder excludes", async (t) => { + const {projectInput} = t.context; + const baselineProject = await Specification.create(projectInput); + + projectInput.configuration.builder = { + resources: { + excludes: ["/manifest.json"] + } + }; + const excludesProject = await Specification.create(projectInput); + + // We now have two projects: One with excludes and one without + // Always compare the results of both to make sure a file is really excluded because of the + // configuration and not because of a typo or because of it's absence in the fixture + + t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for default style"); + + t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for buildtime style"); + t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for buildtime style"); + + t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for dist style"); + t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for dist style"); + + t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for flat style"); + t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for flat style"); + + // Excludes are not applied for "runtime" style + t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for runtime style"); + t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, + "Found excluded resource for runtime style"); + + t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, + "Found resource in baseline project for default style"); + t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 1, + "Did not find excluded resource for default style"); +}); + +test("Modify project resources via workspace and access via flat and runtime readers", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + const workspace = project.getWorkspace(); + const workspaceResource = await workspace.byPath("/resources/id1/index.html"); + t.truthy(workspaceResource, "Found resource in workspace"); + + const newContent = (await workspaceResource.getString()).replace("Component A", "Some Name"); + workspaceResource.setString(newContent); + await workspace.write(workspaceResource); + + const flatReader = project.getReader({style: "flat"}); + const flatReaderResource = await flatReader.byPath("/index.html"); + t.truthy(flatReaderResource, "Found the requested resource byPath"); + t.is(flatReaderResource.getPath(), "/index.html", "Resource (byPath) has correct path"); + t.is(await flatReaderResource.getString(), newContent, "Found resource (byPath) has expected (changed) content"); + + const flatGlobResult = await flatReader.byGlob("**/index.html"); + t.is(flatGlobResult.length, 1, "Found the requested resource byGlob"); + t.is(flatGlobResult[0].getPath(), "/index.html", "Resource (byGlob) has correct path"); + t.is(await flatGlobResult[0].getString(), newContent, "Found resource (byGlob) has expected (changed) content"); + + const runtimeReader = project.getReader({style: "runtime"}); + const runtimeReaderResource = await runtimeReader.byPath("/resources/id1/index.html"); + t.truthy(runtimeReaderResource, "Found the requested resource byPath"); + t.is(runtimeReaderResource.getPath(), "/resources/id1/index.html", "Resource (byPath) has correct path"); + t.is(await runtimeReaderResource.getString(), newContent, "Found resource (byPath) has expected (changed) content"); + + const runtimeGlobResult = await runtimeReader.byGlob("**/index.html"); + t.is(runtimeGlobResult.length, 1, "Found the requested resource byGlob"); + t.is(runtimeGlobResult[0].getPath(), "/resources/id1/index.html", "Resource (byGlob) has correct path"); + t.is(await runtimeGlobResult[0].getString(), newContent, "Found resource (byGlob) has expected (changed) content"); +}); + + +test("Read and write resources outside of app namespace", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + const workspace = project.getWorkspace(); + + await workspace.write(createResource({ + path: "/resources/my-custom-bundle.js" + })); + + const buildtimeReader = project.getReader({style: "buildtime"}); + const buildtimeReaderResource = await buildtimeReader.byPath("/resources/my-custom-bundle.js"); + t.truthy(buildtimeReaderResource, "Found the requested resource byPath (buildtime)"); + t.is(buildtimeReaderResource.getPath(), "/resources/my-custom-bundle.js", + "Resource (byPath) has correct path (buildtime)"); + + const buildtimeGlobResult = await buildtimeReader.byGlob("**/my-custom-bundle.js"); + t.is(buildtimeGlobResult.length, 1, "Found the requested resource byGlob (buildtime)"); + t.is(buildtimeGlobResult[0].getPath(), "/resources/my-custom-bundle.js", + "Resource (byGlob) has correct path (buildtime)"); + + const flatReader = project.getReader({style: "flat"}); + const flatReaderResource = await flatReader.byPath("/resources/my-custom-bundle.js"); + t.falsy(flatReaderResource, "Resource outside of app namespace can't be read using flat reader"); + + const flatGlobResult = await flatReader.byGlob("**/my-custom-bundle.js"); + t.is(flatGlobResult.length, 0, "Resource outside of app namespace can't be found using flat reader"); + + const runtimeReader = project.getReader({style: "runtime"}); + const runtimeReaderResource = await runtimeReader.byPath("/resources/my-custom-bundle.js"); + t.truthy(runtimeReaderResource, "Found the requested resource byPath (runtime)"); + t.is(runtimeReaderResource.getPath(), "/resources/my-custom-bundle.js", + "Resource (byPath) has correct path (runtime)"); + + const runtimeGlobResult = await runtimeReader.byGlob("**/my-custom-bundle.js"); + t.is(runtimeGlobResult.length, 1, "Found the requested resource byGlob (runtime)"); + t.is(runtimeGlobResult[0].getPath(), "/resources/my-custom-bundle.js", + "Resource (byGlob) has correct path (runtime)"); +}); + +test("_configureAndValidatePaths: Default paths", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + + t.is(project._srcPath, "src", "Correct default path"); +}); + +test("_configureAndValidatePaths: Custom src directory", async (t) => { + const componentHPath = path.join(__dirname, "..", "..", "..", "fixtures", "component.h"); + const projectInput = { + id: "component.h.id", + version: "1.0.0", + modulePath: componentHPath, + configuration: { + specVersion: "3.1", + kind: "project", + type: "component", + metadata: {name: "component.h"}, + resources: { + configuration: { + paths: { + src: "webapp-properties.componentName" + } + } + } + } + }; + + const project = await Specification.create(projectInput); + + t.is(project._srcPath, "webapp-properties.componentName", "Correct path for src"); +}); + +test("_configureAndValidatePaths: src directory does not exist", async (t) => { + const {projectInput} = t.context; + projectInput.configuration.resources = { + configuration: { + paths: { + src: "does/not/exist" + } + } + }; + const err = await t.throwsAsync(Specification.create(projectInput)); + + t.is(err.message, "Unable to find source directory 'does/not/exist' in component project component.a"); +}); + +test("_getNamespaceFromManifestJson: No 'sap.app' configuration found", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + sinon.stub(project, "_getManifest").resolves({}); + + const error = await t.throwsAsync(project._getNamespaceFromManifestJson()); + t.is(error.message, "No sap.app/id configuration found in manifest.json of project component.a", + "Rejected with correct error message"); +}); + +test("_getNamespaceFromManifestJson: No component id in 'sap.app' configuration found", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + sinon.stub(project, "_getManifest").resolves({"sap.app": {}}); + + const error = await t.throwsAsync(project._getNamespaceFromManifestJson()); + t.is(error.message, "No sap.app/id configuration found in manifest.json of project component.a"); +}); + +test("_getNamespaceFromManifestJson: set namespace to id", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + sinon.stub(project, "_getManifest").resolves({"sap.app": {id: "my.id"}}); + + const namespace = await project._getNamespaceFromManifestJson(); + t.is(namespace, "my/id", "Returned correct namespace"); +}); + +test("_getNamespaceFromManifestAppDescVariant: No 'id' property found", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + sinon.stub(project, "_getManifest").resolves({}); + + const error = await t.throwsAsync(project._getNamespaceFromManifestAppDescVariant()); + t.is(error.message, `No "id" property found in manifest.appdescr_variant of project component.a`, + "Rejected with correct error message"); +}); + +test("_getNamespaceFromManifestAppDescVariant: set namespace to id", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + sinon.stub(project, "_getManifest").resolves({id: "my.id"}); + + const namespace = await project._getNamespaceFromManifestAppDescVariant(); + t.is(namespace, "my/id", "Returned correct namespace"); +}); + +test("_getNamespace: Correct fallback to manifest.appdescr_variant if manifest.json is missing", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + const _getManifestStub = sinon.stub(project, "_getManifest") + .onFirstCall().rejects({code: "ENOENT"}) + .onSecondCall().resolves({id: "my.id"}); + + const namespace = await project._getNamespace(); + t.is(namespace, "my/id", "Returned correct namespace"); + t.is(_getManifestStub.callCount, 2, "_getManifest called exactly twice"); + t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json first"); + t.is(_getManifestStub.getCall(1).args[0], "/manifest.appdescr_variant", + "_getManifest called for manifest.appdescr_variant in fallback"); +}); + +test("_getNamespace: Correct error message if fallback to manifest.appdescr_variant failed", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + const _getManifestStub = sinon.stub(project, "_getManifest") + .onFirstCall().rejects({code: "ENOENT"}) + .onSecondCall().rejects(new Error("EPON: Pony Error")); + + const error = await t.throwsAsync(project._getNamespace()); + t.is(error.message, "EPON: Pony Error", + "Rejected with correct error message"); + t.is(_getManifestStub.callCount, 2, "_getManifest called exactly twice"); + t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json first"); + t.is(_getManifestStub.getCall(1).args[0], "/manifest.appdescr_variant", + "_getManifest called for manifest.appdescr_variant in fallback"); +}); + +test("_getNamespace: Correct error message if fallback to manifest.appdescr_variant is not possible", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + const _getManifestStub = sinon.stub(project, "_getManifest") + .onFirstCall().rejects({message: "No such stable or directory: manifest.json", code: "ENOENT"}) + .onSecondCall().rejects({code: "ENOENT"}); // both files are missing + + const error = await t.throwsAsync(project._getNamespace()); + t.deepEqual(error.message, + "Could not find required manifest.json for project component.a: " + + "No such stable or directory: manifest.json", + "Rejected with correct error message"); + + t.is(_getManifestStub.callCount, 2, "_getManifest called exactly twice"); + t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json first"); + t.is(_getManifestStub.getCall(1).args[0], "/manifest.appdescr_variant", + "_getManifest called for manifest.appdescr_variant in fallback"); +}); + +test("_getNamespace: No fallback if manifest.json is present but failed to parse", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + const _getManifestStub = sinon.stub(project, "_getManifest") + .onFirstCall().rejects(new Error("EPON: Pony Error")); + + const error = await t.throwsAsync(project._getNamespace()); + t.is(error.message, "EPON: Pony Error", + "Rejected with correct error message"); + + t.is(_getManifestStub.callCount, 1, "_getManifest called exactly once"); + t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json only"); +}); + +test("_getManifest: reads correctly", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + + const content = await project._getManifest("/manifest.json"); + t.is(content._version, "1.1.0", "manifest.json content has been read"); +}); + +test("_getManifest: invalid JSON", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + + const byPathStub = sinon.stub().resolves({ + getString: async () => "no json" + }); + + project._getRawSourceReader = () => { + return { + byPath: byPathStub + }; + }; + + const error = await t.throwsAsync(project._getManifest("/some-manifest.json")); + t.regex(error.message, /^Failed to read \/some-manifest\.json for project component\.a: /, + "Rejected with correct error message"); + t.is(byPathStub.callCount, 1, "byPath got called once"); + t.is(byPathStub.getCall(0).args[0], "/some-manifest.json", "byPath got called with the correct argument"); +}); + +test.serial("_getManifest: File does not exist", async (t) => { + const {projectInput} = t.context; + const project = await Specification.create(projectInput); + + const error = await t.throwsAsync(project._getManifest("/does-not-exist.json")); + t.deepEqual(error.message, + "Failed to read /does-not-exist.json for project component.a: " + + "Could not find resource /does-not-exist.json in project component.a", + "Rejected with correct error message"); +}); + +test.serial("_getManifest: result is cached", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + + const byPathStub = sinon.stub().resolves({ + getString: async () => `{"pony": "no unicorn"}` + }); + + project._getRawSourceReader = () => { + return { + byPath: byPathStub + }; + }; + + const content = await project._getManifest("/some-manifest.json"); + t.deepEqual(content, {pony: "no unicorn"}, "Correct result on first call"); + + const content2 = await project._getManifest("/some-other-manifest.json"); + t.deepEqual(content2, {pony: "no unicorn"}, "Correct result on second call"); + + t.is(byPathStub.callCount, 2, "byPath got called exactly twice (and then cached)"); +}); + +test.serial("_getManifest: Caches successes and failures", async (t) => { + const {projectInput, sinon} = t.context; + const project = await Specification.create(projectInput); + + const getStringStub = sinon.stub() + .onFirstCall().rejects(new Error("EPON: Pony Error")) + .onSecondCall().resolves(`{"pony": "no unicorn"}`); + const byPathStub = sinon.stub().resolves({ + getString: getStringStub + }); + + project._getRawSourceReader = () => { + return { + byPath: byPathStub + }; + }; + + const error = await t.throwsAsync(project._getManifest("/some-manifest.json")); + t.deepEqual(error.message, + "Failed to read /some-manifest.json for project component.a: " + + "EPON: Pony Error", + "Rejected with correct error message"); + + const content = await project._getManifest("/some-other.manifest.json"); + t.deepEqual(content, {pony: "no unicorn"}, "Correct result on second call"); + + const error2 = await t.throwsAsync(project._getManifest("/some-manifest.json")); + t.deepEqual(error2.message, + "Failed to read /some-manifest.json for project component.a: " + + "EPON: Pony Error", + "From cache: Rejected with correct error message"); + + const content2 = await project._getManifest("/some-other.manifest.json"); + t.deepEqual(content2, {pony: "no unicorn"}, "From cache: Correct result on first call"); + + t.is(byPathStub.callCount, 2, + "byPath got called exactly twice (and then cached)"); +}); + +test("namespace: detect namespace from pom.xml via ${project.artifactId}", async (t) => { + const {componentHInput} = t.context; + componentHInput.configuration.resources.configuration.paths.src = "webapp-project.artifactId"; + const project = await Specification.create(componentHInput); + + t.is(project.getNamespace(), "component/h", + "namespace was successfully set since getJson provides the correct object structure"); +}); + +test("namespace: detect namespace from pom.xml via ${componentName} from properties", async (t) => { + const {componentHInput} = t.context; + componentHInput.configuration.resources.configuration.paths.src = "webapp-properties.componentName"; + const project = await Specification.create(componentHInput); + + t.is(project.getNamespace(), "component/h", + "namespace was successfully set since getJson provides the correct object structure"); +}); + +test("namespace: detect namespace from pom.xml via ${appId} from properties", async (t) => { + const {componentHInput} = t.context; + componentHInput.configuration.resources.configuration.paths.src = "webapp-properties.appId"; + + const error = await t.throwsAsync(Specification.create(componentHInput)); + t.deepEqual(error.message, "Failed to resolve namespace of project component.h: \"${appId}\"" + + " couldn't be resolved from maven property \"appId\" of pom.xml of project component.h"); +}); diff --git a/test/lib/validation/schema/__helper__/builder-bundleOptions.js b/test/lib/validation/schema/__helper__/builder-bundleOptions.js index 1ba0be8da..7f99b62da 100644 --- a/test/lib/validation/schema/__helper__/builder-bundleOptions.js +++ b/test/lib/validation/schema/__helper__/builder-bundleOptions.js @@ -3,15 +3,20 @@ */ export default { /** - * Executes the tests for different kind of projects, e.g. "application", "library" + * Executes the tests for different kind of projects, e.g. "application", "library", "component" * * @param {Function} test ava test * @param {Function} assertValidation assertion function - * @param {string} type one of "application" and "library" + * @param {string} type one of "application" and "library", "component" */ defineTests: function(test, assertValidation, type) { // Version specific tests - ["3.0"].forEach(function(specVersion) { + let specVersionsToTest = ["3.1", "3.0"]; + if (type === "component") { + // Component type only became available with specVersion 3.1 + specVersionsToTest = ["3.1"]; + } + specVersionsToTest.forEach(function(specVersion) { test(`${type} (specVersion ${specVersion}): builder/bundles/bundleOptions`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/customConfiguration.js b/test/lib/validation/schema/__helper__/customConfiguration.js index 356cce67b..0543aba4b 100644 --- a/test/lib/validation/schema/__helper__/customConfiguration.js +++ b/test/lib/validation/schema/__helper__/customConfiguration.js @@ -13,7 +13,9 @@ export default { */ defineTests: function(test, assertValidation, type, additionalConfiguration) { additionalConfiguration = additionalConfiguration || {}; - + if (type === "component") { + return; + } // version specific tests for customConfiguration test(`${type}: Invalid customConfiguration (specVersion 2.0)`, async (t) => { await assertValidation(t, Object.assign({ diff --git a/test/lib/validation/schema/__helper__/extension.js b/test/lib/validation/schema/__helper__/extension.js index 69eb7d155..90822f931 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); - ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + ["3.1", "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, @@ -86,7 +86,7 @@ export default { }); }); - ["3.0"].forEach((specVersion) => { + ["3.1", "3.0"].forEach((specVersion) => { test(`kind: extension / type: ${type}: Invalid metadata.name (${specVersion})`, async (t) => { await assertValidation(t, Object.assign({ "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/framework.js b/test/lib/validation/schema/__helper__/framework.js index d8d5ffd22..aecb295d2 100644 --- a/test/lib/validation/schema/__helper__/framework.js +++ b/test/lib/validation/schema/__helper__/framework.js @@ -3,14 +3,20 @@ */ export default { /** - * Executes the tests for different types of kind project, e.g. "application", "library" and "theme-library" + * Executes the tests for different types of kind project, + * e.g. "application", "component", library" and "theme-library" * * @param {Function} test ava test * @param {Function} assertValidation assertion function - * @param {string} type one of "application", "library" and "theme-library" + * @param {string} type one of "application", "component", library" and "theme-library" */ defineTests: function(test, assertValidation, type) { - ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + let specVersionsToTest = ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"]; + if (type === "component") { + // Component type only became available with specVersion 3.1 + specVersionsToTest = ["3.1"]; + } + specVersionsToTest.forEach((specVersion) => { test(`${type} (specVersion ${specVersion}): framework configuration: OpenUI5`, async (t) => { const config = { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/project.js b/test/lib/validation/schema/__helper__/project.js index 8d58ada78..4d4b98541 100644 --- a/test/lib/validation/schema/__helper__/project.js +++ b/test/lib/validation/schema/__helper__/project.js @@ -16,7 +16,7 @@ export default { */ defineTests: function(test, assertValidation, type) { // framework tests - if (["application", "library", "theme-library"].includes(type)) { + if (["application", "library", "theme-library", "component"].includes(type)) { framework.defineTests(test, assertValidation, type); } @@ -24,12 +24,17 @@ export default { customConfiguration.defineTests(test, assertValidation, type); // builder.bundleOptions tests - if (["application", "library"].includes(type)) { + if (["application", "library", "component"].includes(type)) { bundleOptions.defineTests(test, assertValidation, type); } // version specific tests - ["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + let specVersionsToTest = ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"]; + if (type === "component") { + // Component type only became available with specVersion 3.1 + specVersionsToTest = ["3.1"]; + } + specVersionsToTest.forEach((specVersion) => { // tests for all kinds and version 2.0 and above test(`${type} (specVersion ${specVersion}): No metadata`, async (t) => { await assertValidation(t, { @@ -260,28 +265,35 @@ 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" + if (type !== "component") { + ["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) => { + let specVersionsToTest2 = ["3.1", "3.0"]; + if (type === "component") { + // Component type only became available with specVersion 3.1 + specVersionsToTest2 = ["3.1"]; + } + specVersionsToTest2.forEach((specVersion) => { test(`${type} (specVersion ${specVersion}): Invalid metadata.name`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/extension.js b/test/lib/validation/schema/specVersion/kind/extension.js index 8fefe5bbe..345036a65 100644 --- a/test/lib/validation/schema/specVersion/kind/extension.js +++ b/test/lib/validation/schema/specVersion/kind/extension.js @@ -38,7 +38,7 @@ test.after.always((t) => { }; t.context.ajvCoverage.verify(thresholds); }); -["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { +["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { test(`Type project-shim (${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project.js b/test/lib/validation/schema/specVersion/kind/project.js index ba9d09ca5..42e088330 100644 --- a/test/lib/validation/schema/specVersion/kind/project.js +++ b/test/lib/validation/schema/specVersion/kind/project.js @@ -123,6 +123,27 @@ test("Type module (no kind)", async (t) => { }); }); +test("Type component", async (t) => { + await assertValidation(t, { + "specVersion": "3.1", + "kind": "project", + "type": "component", + "metadata": { + "name": "my-component" + } + }); +}); + +test("Type component (no kind)", async (t) => { + await assertValidation(t, { + "specVersion": "3.1", + "type": "component", + "metadata": { + "name": "my-component" + } + }); +}); + test("No type", async (t) => { await assertValidation(t, { "specVersion": "2.0", @@ -171,6 +192,7 @@ test("Invalid type", async (t) => { params: { allowedValues: [ "application", + "component", "library", "theme-library", "module", diff --git a/test/lib/validation/schema/specVersion/kind/project/application.js b/test/lib/validation/schema/specVersion/kind/project/application.js index 54cf855f5..b9fbc4168 100644 --- a/test/lib/validation/schema/specVersion/kind/project/application.js +++ b/test/lib/validation/schema/specVersion/kind/project/application.js @@ -45,7 +45,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { test(`Valid configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -435,7 +435,7 @@ test.after.always((t) => { keyword: "enum", message: "should be equal to one of the allowed values", params: { - allowedValues: ["3.0", "2.6", "2.5", "2.4"].includes(specVersion) ? [ + allowedValues: ["3.1", "3.0", "2.6", "2.5", "2.4"].includes(specVersion) ? [ "raw", "preload", "require", @@ -539,7 +539,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5", "2.4", "2.3"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5", "2.4", "2.3"].forEach(function(specVersion) { test(`application (specVersion ${specVersion}): builder/componentPreload/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -636,7 +636,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5", "2.4"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5", "2.4"].forEach(function(specVersion) { // Unsupported cases for older spec-versions already tested via "allowedValues" comparison above test(`application (specVersion ${specVersion}): builder/bundles/bundleDefinition/sections/mode: bundleInfo`, async (t) => { @@ -664,7 +664,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { test(`application (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -845,7 +845,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6"].forEach(function(specVersion) { +["3.1", "3.0", "2.6"].forEach(function(specVersion) { test(`application (specVersion ${specVersion}): builder/minification/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project/component.js b/test/lib/validation/schema/specVersion/kind/project/component.js new file mode 100644 index 000000000..ea51a19ba --- /dev/null +++ b/test/lib/validation/schema/specVersion/kind/project/component.js @@ -0,0 +1,967 @@ +import test from "ava"; +import Ajv from "ajv"; +import ajvErrors from "ajv-errors"; +import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; +import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; +import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; +import project from "../../../__helper__/project.js"; + +async function assertValidation(t, config, expectedErrors = undefined) { + const validation = t.context.validator.validate({config, project: {id: "my-project"}}); + if (expectedErrors) { + const validationError = await t.throwsAsync(validation, { + instanceOf: ValidationError, + name: "ValidationError" + }); + 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 { + await t.notThrowsAsync(validation); + } +} + +test.before((t) => { + t.context.validator = new Validator({Ajv, ajvErrors, schemaName: "ui5"}); + t.context.ajvCoverage = new AjvCoverage(t.context.validator.ajv, { + includes: ["schema/specVersion/kind/project/component.json"] + }); +}); + +test.after.always((t) => { + t.context.ajvCoverage.createReport("html", {dir: "coverage/ajv-project-component"}); + const thresholds = { + statements: 80, + branches: 75, + functions: 100, + lines: 80 + }; + t.context.ajvCoverage.verify(thresholds); +}); + +["3.1"].forEach(function(specVersion) { + test(`Valid configuration (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "project", + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "okay" + }, + "resources": { + "configuration": { + "propertiesFileSourceEncoding": "UTF-8", + "paths": { + "src": "/my/path" + } + } + }, + "builder": { + "resources": { + "excludes": [ + "/resources/some/project/name/test_results/**", + "/test-resources/**", + "!/test-resources/some/project/name/demo-app/**" + ] + }, + "bundles": [ + { + "bundleDefinition": { + "name": "sap-ui-custom.js", + "defaultFileTypes": [ + ".js" + ], + "sections": [ + { + "name": "my-raw-section", + "mode": "raw", + "filters": [ + "ui5loader-autoconfig.js" + ], + "resolve": true, + "resolveConditional": true, + "renderer": true, + "sort": true + }, + { + "mode": "provided", + "filters": [ + "ui5loader-autoconfig.js" + ], + "resolve": false, + "resolveConditional": false, + "renderer": false, + "sort": false, + "declareRawModules": true + } + ] + }, + "bundleOptions": { + "optimize": true, + "decorateBootstrapModule": true, + "addTryCatchRestartWrapper": true, + "usePredefineCalls": true + } + }, + { + "bundleDefinition": { + "name": "app.js", + "defaultFileTypes": [ + ".js" + ], + "sections": [ + { + "name": "some-app-preload", + "mode": "preload", + "filters": [ + "some/app/Component.js" + ], + "resolve": true, + "sort": true, + "declareRawModules": false + }, + { + "mode": "require", + "filters": [ + "ui5loader-autoconfig.js" + ], + "resolve": true + } + ] + }, + "bundleOptions": { + "optimize": true, + "numberOfParts": 3 + } + } + ], + "componentPreload": { + "paths": [ + "some/glob/**/pattern/Component.js", + "some/other/glob/**/pattern/Component.js" + ], + "namespaces": [ + "some/namespace", + "some/other/namespace" + ] + }, + "cachebuster": { + "signatureType": "hash" + }, + "customTasks": [ + { + "name": "custom-task-1", + "beforeTask": "replaceCopyright", + "configuration": { + "some-key": "some value" + } + }, + { + "name": "custom-task-2", + "afterTask": "custom-task-1", + "configuration": { + "color": "blue" + } + }, + { + "name": "custom-task-2", + "beforeTask": "not-valid", + "configuration": false + } + ] + }, + "server": { + "settings": { + "httpPort": 1337, + "httpsPort": 1443 + }, + "customMiddleware": [ + { + "name": "myCustomMiddleware", + "mountPath": "/myapp", + "afterMiddleware": "compression", + "configuration": { + "debug": true + } + }, + { + "name": "myCustomMiddleware-2", + "beforeMiddleware": "myCustomMiddleware", + "configuration": { + "debug": true + } + } + ] + } + }); + }); + + test(`Invalid resources configuration (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test" + }, + "resources": { + "configuration": { + "propertiesFileSourceEncoding": "FOO", + "paths": { + "app": "src", + "src": { + "path": "invalid" + } + }, + "notAllowed": true + }, + "notAllowed": true + } + }, [ + { + dataPath: "/resources", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "notAllowed", + } + }, + { + dataPath: "/resources/configuration", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "notAllowed", + } + }, + { + dataPath: "/resources/configuration/propertiesFileSourceEncoding", + keyword: "enum", + message: "should be equal to one of the allowed values", + params: { + allowedValues: [ + "UTF-8", + "ISO-8859-1" + ], + } + }, + { + dataPath: "/resources/configuration/paths", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "app", + } + }, + { + dataPath: "/resources/configuration/paths/src", + keyword: "type", + message: "should be string", + params: { + type: "string" + } + } + ]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test" + }, + "resources": { + "configuration": { + "paths": "src" + } + } + }, [ + { + dataPath: "/resources/configuration/paths", + keyword: "type", + message: "should be object", + params: { + type: "object" + } + } + ]); + }); + + test(`Invalid builder configuration (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + // jsdoc is not supported for type component + "jsdoc": { + "excludes": [ + "some/project/name/thirdparty/**" + ] + }, + "bundles": [ + { + "bundleDefinition": { + "name": "sap-ui-custom.js", + "defaultFileTypes": [ + ".js" + ], + "sections": [ + { + "name": true, + "mode": "raw", + "filters": [ + "ui5loader-autoconfig.js" + ], + "resolve": true, + "sort": true, + "declareModules": true + } + ] + }, + "bundleOptions": { + "optimize": true + } + }, + { + "bundleDefinition": { + "defaultFileTypes": [ + ".js", true + ], + "sections": [ + { + "filters": [ + "some/app/Component.js" + ], + "resolve": true, + "sort": true, + "declareRawModules": [] + }, + { + "mode": "provide", + "filters": "*", + "resolve": true + } + ] + }, + "bundleOptions": { + "optimize": "true", + "numberOfParts": "3", + "notAllowed": true + } + } + ], + "componentPreload": { + "path": "some/invalid/path", + "paths": "some/invalid/glob/**/pattern/Component.js", + "namespaces": "some/invalid/namespace", + }, + "libraryPreload": {} // Only supported for type library + } + }, [ + { + dataPath: "/builder", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "jsdoc" + } + }, + { + dataPath: "/builder", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "libraryPreload" + } + }, + { + dataPath: "/builder/bundles/0/bundleDefinition/sections/0", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "declareModules", + } + }, + { + dataPath: "/builder/bundles/0/bundleDefinition/sections/0/name", + keyword: "type", + message: "should be string", + params: { + type: "string", + } + }, + { + dataPath: "/builder/bundles/1/bundleDefinition", + keyword: "required", + message: "should have required property 'name'", + params: { + missingProperty: "name", + } + }, + { + dataPath: "/builder/bundles/1/bundleDefinition/defaultFileTypes/1", + keyword: "type", + message: "should be string", + params: { + type: "string", + } + }, + { + dataPath: "/builder/bundles/1/bundleDefinition/sections/0", + keyword: "required", + message: "should have required property 'mode'", + params: { + missingProperty: "mode", + } + }, + { + dataPath: "/builder/bundles/1/bundleDefinition/sections/0/declareRawModules", + keyword: "type", + message: "should be boolean", + params: { + type: "boolean", + } + }, + { + dataPath: "/builder/bundles/1/bundleDefinition/sections/1/mode", + keyword: "enum", + message: "should be equal to one of the allowed values", + params: { + allowedValues: ["3.1"].includes(specVersion) ? [ + "raw", + "preload", + "require", + "provided", + "bundleInfo" + ] : [ + "raw", + "preload", + "require", + "provided" + ] + } + }, + { + dataPath: "/builder/bundles/1/bundleDefinition/sections/1/filters", + keyword: "type", + message: "should be array", + params: { + type: "array", + } + }, + { + dataPath: "/builder/bundles/1/bundleOptions", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "notAllowed", + } + }, + { + dataPath: "/builder/bundles/1/bundleOptions/optimize", + keyword: "type", + message: "should be boolean", + params: { + type: "boolean", + } + }, + { + dataPath: "/builder/bundles/1/bundleOptions/numberOfParts", + keyword: "type", + message: "should be number", + params: { + type: "number", + } + }, + { + dataPath: "/builder/componentPreload", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "path", + } + }, + { + dataPath: "/builder/componentPreload/paths", + keyword: "type", + message: "should be array", + params: { + type: "array", + } + }, + { + dataPath: "/builder/componentPreload/namespaces", + keyword: "type", + message: "should be array", + params: { + type: "array", + } + } + ]); + }); + test(`component (specVersion ${specVersion}): builder/componentPreload/excludes`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "project", + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "componentPreload": { + "excludes": [ + "some/excluded/files/**", + "some/other/excluded/files/**" + ] + } + } + }); + }); + test(`Invalid builder/componentPreload/excludes configuration (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "componentPreload": { + "excludes": "some/excluded/files/**" + } + } + }, [ + { + dataPath: "/builder/componentPreload/excludes", + keyword: "type", + message: "should be array", + params: { + type: "array", + }, + }, + ]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "componentPreload": { + "excludes": [ + true, + 1, + {} + ], + "notAllowed": true + } + } + }, [ + { + dataPath: "/builder/componentPreload", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "notAllowed", + }, + }, + { + dataPath: "/builder/componentPreload/excludes/0", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/componentPreload/excludes/1", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/componentPreload/excludes/2", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + ]); + }); + test(`component (specVersion ${specVersion}): builder/bundles/bundleDefinition/sections/mode: bundleInfo`, + async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "project", + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "bundles": [{ + "bundleDefinition": { + "name": "my-bundle.js", + "sections": [{ + "name": "my-bundle-info", + "mode": "bundleInfo", + "filters": [] + }] + } + }] + } + }); + }); + test(`component (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "project", + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "settings": { + "includeDependency": [ + "sap.a", + "sap.b" + ], + "includeDependencyRegExp": [ + ".ui.[a-z]+", + "^sap.[mf]$" + ], + "includeDependencyTree": [ + "sap.c", + "sap.d" + ] + } + } + }); + }); + test(`Invalid builder/settings/includeDependency* configuration (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "settings": { + "includeDependency": "a", + "includeDependencyRegExp": "b", + "includeDependencyTree": "c" + } + } + }, [ + { + dataPath: "/builder/settings/includeDependency", + keyword: "type", + message: "should be array", + params: { + type: "array", + }, + }, + { + dataPath: "/builder/settings/includeDependencyRegExp", + keyword: "type", + message: "should be array", + params: { + type: "array", + }, + }, + { + dataPath: "/builder/settings/includeDependencyTree", + keyword: "type", + message: "should be array", + params: { + type: "array", + }, + }, + ]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "settings": { + "includeDependency": [ + true, + 1, + {} + ], + "includeDependencyRegExp": [ + true, + 1, + {} + ], + "includeDependencyTree": [ + true, + 1, + {} + ], + "notAllowed": true + } + } + }, [ + { + dataPath: "/builder/settings", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "notAllowed", + }, + }, + { + dataPath: "/builder/settings/includeDependency/0", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependency/1", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependency/2", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependencyRegExp/0", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependencyRegExp/1", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependencyRegExp/2", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependencyTree/0", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependencyTree/1", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/settings/includeDependencyTree/2", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + ]); + }); + test(`component (specVersion ${specVersion}): builder/minification/excludes`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "project", + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "minification": { + "excludes": [ + "some/excluded/files/**", + "some/other/excluded/files/**" + ] + } + } + }); + }); + test(`Invalid builder/minification/excludes configuration (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "minification": { + "excludes": "some/excluded/files/**" + } + } + }, [ + { + dataPath: "/builder/minification/excludes", + keyword: "type", + message: "should be array", + params: { + type: "array", + }, + }, + ]); + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "metadata": { + "name": "com.sap.ui5.test", + "copyright": "yes" + }, + "builder": { + "minification": { + "excludes": [ + true, + 1, + {} + ], + "notAllowed": true + } + } + }, [ + { + dataPath: "/builder/minification", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "notAllowed", + }, + }, + { + dataPath: "/builder/minification/excludes/0", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/minification/excludes/1", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + { + dataPath: "/builder/minification/excludes/2", + keyword: "type", + message: "should be string", + params: { + type: "string", + }, + }, + ]); + }); + test(`Invalid project name (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "type": "component", + "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": "component", + "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": "component", + "metadata": { + "name": "a".repeat(81) + } + }, [{ + 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 80 characters", + params: { + limit: 80, + }, + }] + }, + }]); + }); +}); + +project.defineTests(test, assertValidation, "component"); diff --git a/test/lib/validation/schema/specVersion/kind/project/library.js b/test/lib/validation/schema/specVersion/kind/project/library.js index 59c3a9649..cc3f7740a 100644 --- a/test/lib/validation/schema/specVersion/kind/project/library.js +++ b/test/lib/validation/schema/specVersion/kind/project/library.js @@ -45,7 +45,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { test(`library (specVersion ${specVersion}): Valid configuration`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -401,7 +401,7 @@ test.after.always((t) => { keyword: "enum", message: "should be equal to one of the allowed values", params: { - allowedValues: ["3.0", "2.6", "2.5", "2.4"].includes(specVersion) ? [ + allowedValues: ["3.1", "3.0", "2.6", "2.5", "2.4"].includes(specVersion) ? [ "raw", "preload", "require", @@ -616,7 +616,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5", "2.4", "2.3"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5", "2.4", "2.3"].forEach(function(specVersion) { test(`library (specVersion ${specVersion}): builder/libraryPreload/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -809,7 +809,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5", "2.4"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5", "2.4"].forEach(function(specVersion) { // Unsupported cases for older spec-versions already tested via "allowedValues" comparison above test(`library (specVersion ${specVersion}): builder/bundles/bundleDefinition/sections/mode: bundleInfo`, async (t) => { @@ -837,7 +837,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { test(`library (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -1018,7 +1018,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6"].forEach(function(specVersion) { +["3.1", "3.0", "2.6"].forEach(function(specVersion) { test(`library (specVersion ${specVersion}): builder/minification/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project/module.js b/test/lib/validation/schema/specVersion/kind/project/module.js index 4c3b4715c..d0df38fad 100644 --- a/test/lib/validation/schema/specVersion/kind/project/module.js +++ b/test/lib/validation/schema/specVersion/kind/project/module.js @@ -45,7 +45,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { +["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { test(`Valid configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -144,7 +144,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { test(`Server configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, 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 fb0273e1c..5e6d088f2 100644 --- a/test/lib/validation/schema/specVersion/kind/project/theme-library.js +++ b/test/lib/validation/schema/specVersion/kind/project/theme-library.js @@ -46,7 +46,7 @@ test.after.always((t) => { }); -["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { test(`Valid configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -167,7 +167,7 @@ test.after.always((t) => { }); }); -["3.0", "2.6", "2.5"].forEach(function(specVersion) { +["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { test(`theme-library (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/ui5.js b/test/lib/validation/schema/ui5.js index 433aed2a5..19d83cf2c 100644 --- a/test/lib/validation/schema/ui5.js +++ b/test/lib/validation/schema/ui5.js @@ -102,7 +102,7 @@ test("Invalid specVersion", async (t) => { message: `Unsupported "specVersion" Your UI5 CLI installation might be outdated. -Supported specification versions: "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0", "1.1", "1.0", "0.1" +Supported specification versions: "3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0", "1.1", "1.0", "0.1" For details, see: https://sap.github.io/ui5-tooling/pages/Configuration/#specification-versions`, params: { errors: [ @@ -112,6 +112,7 @@ For details, see: https://sap.github.io/ui5-tooling/pages/Configuration/#specifi message: "should be equal to one of the allowed values", params: { allowedValues: [ + "3.1", "3.0", "2.6", "2.5", @@ -144,6 +145,7 @@ test("Invalid type", async (t) => { params: { allowedValues: [ "application", + "component", "library", "theme-library", "module" From cdde9cdd608166a0277b3c9fc07daf86f9435b50 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Wed, 14 Jun 2023 15:40:23 +0200 Subject: [PATCH 2/5] [INTERNAL] SpecificationVersion: Add test helper function #getVersionsForRange --- lib/specifications/SpecificationVersion.js | 20 ++++++- .../specifications/SpecificationVersion.js | 51 ++++++++++++++++++ .../__helper__/builder-bundleOptions.js | 16 +++--- .../schema/__helper__/customConfiguration.js | 54 ++++++++++--------- .../validation/schema/__helper__/extension.js | 7 +-- .../validation/schema/__helper__/framework.js | 11 ++-- .../validation/schema/__helper__/project.js | 21 +++----- .../schema/specVersion/kind/extension.js | 4 +- .../kind/extension/project-shim.js | 5 +- .../kind/extension/server-middleware.js | 3 +- .../schema/specVersion/kind/extension/task.js | 3 +- .../specVersion/kind/project/application.js | 15 +++--- .../specVersion/kind/project/component.js | 3 +- .../specVersion/kind/project/library.js | 15 +++--- .../schema/specVersion/kind/project/module.js | 9 ++-- .../specVersion/kind/project/theme-library.js | 8 +-- 16 files changed, 159 insertions(+), 86 deletions(-) diff --git a/lib/specifications/SpecificationVersion.js b/lib/specifications/SpecificationVersion.js index d53adb2b0..7bbac1eef 100644 --- a/lib/specifications/SpecificationVersion.js +++ b/lib/specifications/SpecificationVersion.js @@ -63,8 +63,8 @@ class SpecificationVersion { * Test whether the instance's Specification Version falls into the provided range * * @public -@param {string} range [Semver]{@link https://www.npmjs.com/package/semver}-style version range, -for example 2.2 - 2.4 + * @param {string} range [Semver]{@link https://www.npmjs.com/package/semver}-style version range, + * for example 2.2 - 2.4 or =3.0 * @returns {boolean} True if the instance's Specification Version falls into the provided range */ satisfies(range) { @@ -263,6 +263,22 @@ for example 2.2 - 2.4 const comparator = new SpecificationVersion(specVersion); return comparator.neq(testVersion); } + + /** + * Create an array of Specification Versions that match with the provided range. This is mainly used + * for testing purposes. I.e. to execute identical tests for a range of specification versions. + * + * @public + * @param {string} range [Semver]{@link https://www.npmjs.com/package/semver}-style version range, + * for example 2.2 - 2.4 or =3.0 + * @returns {string[]} Array of versions that match the specified range + */ + static getVersionsForRange(range) { + return SUPPORTED_VERSIONS.filter((specVersion) => { + const comparator = new SpecificationVersion(specVersion); + return comparator.satisfies(range); + }); + } } function getUnsupportedSpecVersionMessage(specVersion) { diff --git a/test/lib/specifications/SpecificationVersion.js b/test/lib/specifications/SpecificationVersion.js index b50aa010d..64efc696f 100644 --- a/test/lib/specifications/SpecificationVersion.js +++ b/test/lib/specifications/SpecificationVersion.js @@ -67,6 +67,12 @@ test("(instance) satisfies", (t) => { t.is(new SpecificationVersion("2.2").satisfies("^2.2"), true); t.is(new SpecificationVersion("2.3").satisfies("^2.2"), true); + // range: >=2.2 + t.is(new SpecificationVersion("2.1").satisfies(">=2.2"), false); + t.is(new SpecificationVersion("2.2").satisfies(">=2.2"), true); + t.is(new SpecificationVersion("2.3").satisfies(">=2.2"), true); + t.is(new SpecificationVersion("3.1").satisfies(">=2.2"), true); + // range: > 1.0 t.is(new SpecificationVersion("1.0").satisfies("> 1.0"), false); t.is(new SpecificationVersion("1.1").satisfies("> 1.0"), true); @@ -162,6 +168,12 @@ test("(static) satisfies", (t) => { t.is(SpecificationVersion.satisfies("2.2", "^2.2"), true); t.is(SpecificationVersion.satisfies("2.3", "^2.2"), true); + // range: >=2.2 + t.is(SpecificationVersion.satisfies("2.1", ">=2.2"), false); + t.is(SpecificationVersion.satisfies("2.2", ">=2.2"), true); + t.is(SpecificationVersion.satisfies("2.3", ">=2.2"), true); + t.is(SpecificationVersion.satisfies("3.1", ">=2.2"), true); + // range: > 1.0 t.is(SpecificationVersion.satisfies("1.0", "> 1.0"), false); t.is(SpecificationVersion.satisfies("1.1", "> 1.0"), true); @@ -212,6 +224,45 @@ test("(static) low level comparator", (t) => { t.is(SpecificationVersion.neq("2.2", "2.2"), false); }); +test("(static) getVersionsForRange", (t) => { + // range: 1.x + t.deepEqual(SpecificationVersion.getVersionsForRange("1.x"), [ + "1.0", "1.1" + ]); + + // range: ^2.2 + t.deepEqual(SpecificationVersion.getVersionsForRange("^2.2"), [ + "2.2", "2.3", "2.4", "2.5", "2.6" + ]); + + // range: >=2.2 + t.deepEqual(SpecificationVersion.getVersionsForRange(">=2.2"), [ + "2.2", "2.3", "2.4", "2.5", "2.6", + "3.0", "3.1", + ]); + + // range: > 1.0 + t.deepEqual(SpecificationVersion.getVersionsForRange("> 1.0"), [ + "1.1", + "2.0", "2.1", "2.2", "2.3", "2.4", "2.5", "2.6", + "3.0", "3.1", + ]); + + // range: 2.2 - 2.4 + t.deepEqual(SpecificationVersion.getVersionsForRange("2.2 - 2.4"), [ + "2.2", "2.3", "2.4" + ]); + + // range: 0.1 || 1.0 - 1.1 || ^2.5 + t.deepEqual(SpecificationVersion.getVersionsForRange("0.1 || 1.0 - 1.1 || ^2.5"), [ + "0.1", "1.0", "1.1", + "2.5", "2.6" + ]); + + // Incorrect range returns empty array + t.deepEqual(SpecificationVersion.getVersionsForRange("not a range"), []); +}); + test("getSemverCompatibleVersion", (t) => { t.is(__localFunctions__.getSemverCompatibleVersion("0.1"), "0.1.0"); t.is(__localFunctions__.getSemverCompatibleVersion("1.1"), "1.1.0"); diff --git a/test/lib/validation/schema/__helper__/builder-bundleOptions.js b/test/lib/validation/schema/__helper__/builder-bundleOptions.js index 7f99b62da..27278b974 100644 --- a/test/lib/validation/schema/__helper__/builder-bundleOptions.js +++ b/test/lib/validation/schema/__helper__/builder-bundleOptions.js @@ -1,22 +1,20 @@ +import SpecificationVersion from "../../../../../lib/specifications/SpecificationVersion.js"; + /** * Common test functionality for builder/bundles/bundleOptions section in config */ export default { /** - * Executes the tests for different kind of projects, e.g. "application", "library", "component" + * Executes the tests for different kind of projects, e.g. "application", "component", "library" * * @param {Function} test ava test * @param {Function} assertValidation assertion function - * @param {string} type one of "application" and "library", "component" + * @param {string} type one of "application", "component" and "library" */ defineTests: function(test, assertValidation, type) { - // Version specific tests - let specVersionsToTest = ["3.1", "3.0"]; - if (type === "component") { - // Component type only became available with specVersion 3.1 - specVersionsToTest = ["3.1"]; - } - specVersionsToTest.forEach(function(specVersion) { + // Version specific tests (component type only became available with specVersion 3.1) + const range = type === "component" ? ">=3.1" : ">=3.0"; + SpecificationVersion.getVersionsForRange(range).forEach(function(specVersion) { test(`${type} (specVersion ${specVersion}): builder/bundles/bundleOptions`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/customConfiguration.js b/test/lib/validation/schema/__helper__/customConfiguration.js index 0543aba4b..607560658 100644 --- a/test/lib/validation/schema/__helper__/customConfiguration.js +++ b/test/lib/validation/schema/__helper__/customConfiguration.js @@ -1,43 +1,47 @@ +import SpecificationVersion from "../../../../../lib/specifications/SpecificationVersion.js"; + /** * Common test functionality for customConfiguration section in config */ export default { /** - * Executes the tests for different kind of projects, e.g. "application", "library", "theme-library" and "module" + * Executes the tests for different kind of projects, + * e.g. "application", "component", "library", "theme-library" and "module" * * @param {Function} test ava test * @param {Function} assertValidation assertion function * @param {string} type one of "project-shim", "server-middleware" "task", - * "application", "library", "theme-library" and "module" + * "application", "component", "library", "theme-library" and "module" * @param {object} additionalConfiguration additional configuration content */ defineTests: function(test, assertValidation, type, additionalConfiguration) { additionalConfiguration = additionalConfiguration || {}; - if (type === "component") { - return; - } - // version specific tests for customConfiguration - test(`${type}: Invalid customConfiguration (specVersion 2.0)`, async (t) => { - await assertValidation(t, Object.assign({ - "specVersion": "2.0", - "type": type, - "metadata": { - "name": "my-" + type - }, - "customConfiguration": {} - }, additionalConfiguration), [ - { - dataPath: "", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "customConfiguration", + if (type !== "component") { // Component type only became available with specVersion 3.1 + // version specific tests for customConfiguration + test(`${type}: Invalid customConfiguration (specVersion 2.0)`, async (t) => { + await assertValidation(t, Object.assign({ + "specVersion": "2.0", + "type": type, + "metadata": { + "name": "my-" + type + }, + "customConfiguration": {} + }, additionalConfiguration), [ + { + dataPath: "", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "customConfiguration", + } } - } - ]); - }); + ]); + }); + } - ["2.6", "2.5", "2.4", "2.3", "2.2", "2.1"].forEach((specVersion) => { + // Component type only became available with specVersion 3.1 + const range = type === "component" ? ">=3.1" : ">=2.1"; + SpecificationVersion.getVersionsForRange(range).forEach((specVersion) => { test(`${type}: Valid customConfiguration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, Object.assign( { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/extension.js b/test/lib/validation/schema/__helper__/extension.js index 90822f931..516bc889c 100644 --- a/test/lib/validation/schema/__helper__/extension.js +++ b/test/lib/validation/schema/__helper__/extension.js @@ -1,3 +1,4 @@ +import SpecificationVersion from "../../../../../lib/specifications/SpecificationVersion.js"; import customConfiguration from "./customConfiguration.js"; /** @@ -18,7 +19,7 @@ export default { customConfiguration.defineTests(test, assertValidation, type, additionalConfiguration); - ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + SpecificationVersion.getVersionsForRange(">=2.0").forEach((specVersion) => { test(`kind: extension / type: ${type} basic (${specVersion})`, async (t) => { await assertValidation(t, Object.assign({ "specVersion": specVersion, @@ -67,7 +68,7 @@ export default { }); }); - ["2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + SpecificationVersion.getVersionsForRange("2.0 - 2.6").forEach((specVersion) => { test(`kind: extension / type: ${type}: Invalid metadata.name (${specVersion})`, async (t) => { await assertValidation(t, Object.assign({ "specVersion": specVersion, @@ -86,7 +87,7 @@ export default { }); }); - ["3.1", "3.0"].forEach((specVersion) => { + SpecificationVersion.getVersionsForRange(">=3.0").forEach((specVersion) => { test(`kind: extension / type: ${type}: Invalid metadata.name (${specVersion})`, async (t) => { await assertValidation(t, Object.assign({ "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/framework.js b/test/lib/validation/schema/__helper__/framework.js index aecb295d2..0e614b162 100644 --- a/test/lib/validation/schema/__helper__/framework.js +++ b/test/lib/validation/schema/__helper__/framework.js @@ -1,3 +1,5 @@ +import SpecificationVersion from "../../../../../lib/specifications/SpecificationVersion.js"; + /** * Common test functionality for framework section in config */ @@ -11,12 +13,9 @@ export default { * @param {string} type one of "application", "component", library" and "theme-library" */ defineTests: function(test, assertValidation, type) { - let specVersionsToTest = ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"]; - if (type === "component") { - // Component type only became available with specVersion 3.1 - specVersionsToTest = ["3.1"]; - } - specVersionsToTest.forEach((specVersion) => { + // Component type only became available with specVersion 3.1 + const range = type === "component" ? ">=3.1" : ">=2.0"; + SpecificationVersion.getVersionsForRange(range).forEach((specVersion) => { test(`${type} (specVersion ${specVersion}): framework configuration: OpenUI5`, async (t) => { const config = { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/project.js b/test/lib/validation/schema/__helper__/project.js index 4d4b98541..c76b66cbf 100644 --- a/test/lib/validation/schema/__helper__/project.js +++ b/test/lib/validation/schema/__helper__/project.js @@ -1,3 +1,4 @@ +import SpecificationVersion from "../../../../../lib/specifications/SpecificationVersion.js"; import framework from "./framework.js"; import customConfiguration from "./customConfiguration.js"; import bundleOptions from "./builder-bundleOptions.js"; @@ -12,7 +13,7 @@ export default { * * @param {Function} test ava test * @param {Function} assertValidation assertion function - * @param {string} type one of "application", "library", "theme-library" and "module" + * @param {string} type one of "application", "component", "library", "theme-library" and "module" */ defineTests: function(test, assertValidation, type) { // framework tests @@ -29,12 +30,9 @@ export default { } // version specific tests - let specVersionsToTest = ["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"]; - if (type === "component") { - // Component type only became available with specVersion 3.1 - specVersionsToTest = ["3.1"]; - } - specVersionsToTest.forEach((specVersion) => { + // Component type only became available with specVersion 3.1 + const range = type === "component" ? ">=3.1" : ">=2.0"; + SpecificationVersion.getVersionsForRange(range).forEach((specVersion) => { // tests for all kinds and version 2.0 and above test(`${type} (specVersion ${specVersion}): No metadata`, async (t) => { await assertValidation(t, { @@ -288,12 +286,9 @@ export default { }); } - let specVersionsToTest2 = ["3.1", "3.0"]; - if (type === "component") { - // Component type only became available with specVersion 3.1 - specVersionsToTest2 = ["3.1"]; - } - specVersionsToTest2.forEach((specVersion) => { + // Component type only became available with specVersion 3.1 + const v3Range = type === "component" ? ">=3.1" : ">=3.0"; + SpecificationVersion.getVersionsForRange(v3Range).forEach((specVersion) => { test(`${type} (specVersion ${specVersion}): Invalid metadata.name`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/extension.js b/test/lib/validation/schema/specVersion/kind/extension.js index 345036a65..54fbb1fdc 100644 --- a/test/lib/validation/schema/specVersion/kind/extension.js +++ b/test/lib/validation/schema/specVersion/kind/extension.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../lib/validation/ValidationError.js"; @@ -38,7 +39,8 @@ test.after.always((t) => { }; t.context.ajvCoverage.verify(thresholds); }); -["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { + +SpecificationVersion.getVersionsForRange(">=2.0").forEach((specVersion) => { test(`Type project-shim (${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, 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 daff1b0bb..dfad329fe 100644 --- a/test/lib/validation/schema/specVersion/kind/extension/project-shim.js +++ b/test/lib/validation/schema/specVersion/kind/extension/project-shim.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,7 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { +SpecificationVersion.getVersionsForRange(">=2.0").forEach((specVersion) => { test(`kind: extension / type: project-shim (${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -127,7 +128,7 @@ test.after.always((t) => { }); }); -["3.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`Invalid extension name (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, 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 f887078eb..39b5efe6f 100644 --- a/test/lib/validation/schema/specVersion/kind/extension/server-middleware.js +++ b/test/lib/validation/schema/specVersion/kind/extension/server-middleware.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,7 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`Invalid extension name (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/extension/task.js b/test/lib/validation/schema/specVersion/kind/extension/task.js index a9dfe9452..f2a6a1017 100644 --- a/test/lib/validation/schema/specVersion/kind/extension/task.js +++ b/test/lib/validation/schema/specVersion/kind/extension/task.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,7 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`Invalid extension name (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project/application.js b/test/lib/validation/schema/specVersion/kind/project/application.js index b9fbc4168..ca005d415 100644 --- a/test/lib/validation/schema/specVersion/kind/project/application.js +++ b/test/lib/validation/schema/specVersion/kind/project/application.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,7 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.0").forEach(function(specVersion) { test(`Valid configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -509,7 +510,7 @@ test.after.always((t) => { }); }); -["2.2", "2.1", "2.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange("2.0 - 2.2").forEach(function(specVersion) { test(`Unsupported builder/componentPreload/excludes configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -539,7 +540,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5", "2.4", "2.3"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.3").forEach(function(specVersion) { test(`application (specVersion ${specVersion}): builder/componentPreload/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -636,7 +637,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5", "2.4"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.4").forEach(function(specVersion) { // Unsupported cases for older spec-versions already tested via "allowedValues" comparison above test(`application (specVersion ${specVersion}): builder/bundles/bundleDefinition/sections/mode: bundleInfo`, async (t) => { @@ -664,7 +665,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.5").forEach(function(specVersion) { test(`application (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -845,7 +846,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.6").forEach(function(specVersion) { test(`application (specVersion ${specVersion}): builder/minification/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -942,7 +943,7 @@ test.after.always((t) => { }); }); -["3.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`Invalid project name (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project/component.js b/test/lib/validation/schema/specVersion/kind/project/component.js index ea51a19ba..3e8e604db 100644 --- a/test/lib/validation/schema/specVersion/kind/project/component.js +++ b/test/lib/validation/schema/specVersion/kind/project/component.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,7 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.1"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.1").forEach(function(specVersion) { test(`Valid configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project/library.js b/test/lib/validation/schema/specVersion/kind/project/library.js index cc3f7740a..baf248fa1 100644 --- a/test/lib/validation/schema/specVersion/kind/project/library.js +++ b/test/lib/validation/schema/specVersion/kind/project/library.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,7 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.0").forEach(function(specVersion) { test(`library (specVersion ${specVersion}): Valid configuration`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -564,7 +565,7 @@ test.after.always((t) => { }); }); -["2.2", "2.1", "2.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange("2.0 - 2.2").forEach(function(specVersion) { test(`Unsupported builder/libraryPreload configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -616,7 +617,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5", "2.4", "2.3"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.3").forEach(function(specVersion) { test(`library (specVersion ${specVersion}): builder/libraryPreload/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -809,7 +810,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5", "2.4"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.4").forEach(function(specVersion) { // Unsupported cases for older spec-versions already tested via "allowedValues" comparison above test(`library (specVersion ${specVersion}): builder/bundles/bundleDefinition/sections/mode: bundleInfo`, async (t) => { @@ -837,7 +838,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.5").forEach(function(specVersion) { test(`library (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -1018,7 +1019,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.6").forEach(function(specVersion) { test(`library (specVersion ${specVersion}): builder/minification/excludes`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -1115,7 +1116,7 @@ test.after.always((t) => { }); }); -["3.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`Invalid project name (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project/module.js b/test/lib/validation/schema/specVersion/kind/project/module.js index d0df38fad..f92e8e24c 100644 --- a/test/lib/validation/schema/specVersion/kind/project/module.js +++ b/test/lib/validation/schema/specVersion/kind/project/module.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,7 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); -["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { +SpecificationVersion.getVersionsForRange(">=2.0").forEach((specVersion) => { test(`Valid configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -106,7 +107,7 @@ test.after.always((t) => { }); }); -["2.4", "2.3", "2.2", "2.1", "2.0"].forEach((specVersion) => { +SpecificationVersion.getVersionsForRange("2.0 - 2.4").forEach((specVersion) => { test(`No server configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -144,7 +145,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.5").forEach(function(specVersion) { test(`Server configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -349,7 +350,7 @@ test.after.always((t) => { }); }); -["3.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`Invalid project name (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, 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 5e6d088f2..eff5bdbf0 100644 --- a/test/lib/validation/schema/specVersion/kind/project/theme-library.js +++ b/test/lib/validation/schema/specVersion/kind/project/theme-library.js @@ -1,6 +1,7 @@ import test from "ava"; import Ajv from "ajv"; import ajvErrors from "ajv-errors"; +import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; @@ -45,8 +46,7 @@ test.after.always((t) => { t.context.ajvCoverage.verify(thresholds); }); - -["3.1", "3.0", "2.6", "2.5", "2.4", "2.3", "2.2", "2.1", "2.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.0").forEach(function(specVersion) { test(`Valid configuration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -167,7 +167,7 @@ test.after.always((t) => { }); }); -["3.1", "3.0", "2.6", "2.5"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=2.5").forEach(function(specVersion) { test(`theme-library (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { await assertValidation(t, { "specVersion": specVersion, @@ -348,7 +348,7 @@ test.after.always((t) => { }); }); -["3.0"].forEach(function(specVersion) { +SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`Invalid project name (specVersion ${specVersion})`, async (t) => { await assertValidation(t, { "specVersion": specVersion, From 9e1e665105abb1c0401443a0d55ec4dc3590db6d Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Thu, 10 Aug 2023 11:17:06 +0200 Subject: [PATCH 3/5] [INTERNAL] Remove component type Might not be part of specVersion 3.1 --- lib/specifications/Specification.js | 3 - lib/specifications/types/Component.js | 259 ----- .../schema/specVersion/kind/project.json | 11 - .../specVersion/kind/project/component.json | 108 -- test/fixtures/component.a/middleware.a.js | 1 - .../collection/library.a/package.json | 17 - .../library.a/src/library/a/.library | 17 - .../library/a/themes/base/library.source.less | 6 - .../library.a/test/library/a/Test.html | 0 .../collection/library.a/ui5.yaml | 5 - .../collection/library.b/package.json | 9 - .../library.b/src/library/b/.library | 17 - .../library.b/test/library/b/Test.html | 0 .../collection/library.b/ui5.yaml | 5 - .../collection/library.c/package.json | 9 - .../library.c/src/library/c/.library | 17 - .../library.c/test/LibraryC/Test.html | 0 .../collection/library.c/ui5.yaml | 5 - .../node_modules/library.d/package.json | 9 - .../library.d/src/library/d/.library | 11 - .../library.d/test/library/d/Test.html | 0 .../node_modules/library.d/ui5.yaml | 10 - .../node_modules/collection/package.json | 18 - .../node_modules/collection/ui5.yaml | 12 - .../library.d/main/src/library/d/.library | 11 - .../library.d/main/src/library/d/some.js | 4 - .../library.d/main/test/library/d/Test.html | 0 .../node_modules/library.d/package.json | 9 - .../node_modules/library.d/ui5.yaml | 10 - test/fixtures/component.a/package.json | 13 - test/fixtures/component.a/src/index.html | 9 - test/fixtures/component.a/src/manifest.json | 13 - test/fixtures/component.a/src/test.js | 5 - test/fixtures/component.a/task.a.js | 1 - .../component.a/ui5-test-configPath.yaml | 7 - .../component.a/ui5-test-corrupt.yaml | 1 - test/fixtures/component.a/ui5-test-empty.yaml | 0 test/fixtures/component.a/ui5-test-error.yaml | 7 - test/fixtures/component.a/ui5.yaml | 5 - test/fixtures/component.h/pom.xml | 41 - .../webapp-project.artifactId/manifest.json | 13 - .../webapp-properties.appId/manifest.json | 13 - .../manifest.json | 13 - test/fixtures/component.h/webapp/Component.js | 8 - .../fixtures/component.h/webapp/manifest.json | 13 - .../component.h/webapp/sectionsA/section1.js | 3 - .../component.h/webapp/sectionsA/section2.js | 3 - .../component.h/webapp/sectionsA/section3.js | 3 - .../component.h/webapp/sectionsB/section1.js | 3 - .../component.h/webapp/sectionsB/section2.js | 3 - .../component.h/webapp/sectionsB/section3.js | 3 - test/lib/specifications/types/Component.js | 679 ------------ .../__helper__/builder-bundleOptions.js | 9 +- .../schema/__helper__/customConfiguration.js | 48 +- .../validation/schema/__helper__/framework.js | 8 +- .../validation/schema/__helper__/project.js | 52 +- .../schema/specVersion/kind/project.js | 22 - .../specVersion/kind/project/component.js | 968 ------------------ test/lib/validation/schema/ui5.js | 1 - 59 files changed, 52 insertions(+), 2498 deletions(-) delete mode 100644 lib/specifications/types/Component.js delete mode 100644 lib/validation/schema/specVersion/kind/project/component.json delete mode 100644 test/fixtures/component.a/middleware.a.js delete mode 100644 test/fixtures/component.a/node_modules/collection/library.a/package.json delete mode 100644 test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library delete mode 100644 test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less delete mode 100644 test/fixtures/component.a/node_modules/collection/library.a/test/library/a/Test.html delete mode 100644 test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml delete mode 100644 test/fixtures/component.a/node_modules/collection/library.b/package.json delete mode 100644 test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library delete mode 100644 test/fixtures/component.a/node_modules/collection/library.b/test/library/b/Test.html delete mode 100644 test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml delete mode 100644 test/fixtures/component.a/node_modules/collection/library.c/package.json delete mode 100644 test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library delete mode 100644 test/fixtures/component.a/node_modules/collection/library.c/test/LibraryC/Test.html delete mode 100644 test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml delete mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json delete mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library delete mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/test/library/d/Test.html delete mode 100644 test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml delete mode 100644 test/fixtures/component.a/node_modules/collection/package.json delete mode 100644 test/fixtures/component.a/node_modules/collection/ui5.yaml delete mode 100644 test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library delete mode 100644 test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js delete mode 100644 test/fixtures/component.a/node_modules/library.d/main/test/library/d/Test.html delete mode 100644 test/fixtures/component.a/node_modules/library.d/package.json delete mode 100644 test/fixtures/component.a/node_modules/library.d/ui5.yaml delete mode 100644 test/fixtures/component.a/package.json delete mode 100644 test/fixtures/component.a/src/index.html delete mode 100644 test/fixtures/component.a/src/manifest.json delete mode 100644 test/fixtures/component.a/src/test.js delete mode 100644 test/fixtures/component.a/task.a.js delete mode 100644 test/fixtures/component.a/ui5-test-configPath.yaml delete mode 100644 test/fixtures/component.a/ui5-test-corrupt.yaml delete mode 100644 test/fixtures/component.a/ui5-test-empty.yaml delete mode 100644 test/fixtures/component.a/ui5-test-error.yaml delete mode 100644 test/fixtures/component.a/ui5.yaml delete mode 100644 test/fixtures/component.h/pom.xml delete mode 100644 test/fixtures/component.h/webapp-project.artifactId/manifest.json delete mode 100644 test/fixtures/component.h/webapp-properties.appId/manifest.json delete mode 100644 test/fixtures/component.h/webapp-properties.componentName/manifest.json delete mode 100644 test/fixtures/component.h/webapp/Component.js delete mode 100644 test/fixtures/component.h/webapp/manifest.json delete mode 100644 test/fixtures/component.h/webapp/sectionsA/section1.js delete mode 100644 test/fixtures/component.h/webapp/sectionsA/section2.js delete mode 100644 test/fixtures/component.h/webapp/sectionsA/section3.js delete mode 100644 test/fixtures/component.h/webapp/sectionsB/section1.js delete mode 100644 test/fixtures/component.h/webapp/sectionsB/section2.js delete mode 100644 test/fixtures/component.h/webapp/sectionsB/section3.js delete mode 100644 test/lib/specifications/types/Component.js delete mode 100644 test/lib/validation/schema/specVersion/kind/project/component.js diff --git a/lib/specifications/Specification.js b/lib/specifications/Specification.js index 3e60eed07..5c2af4142 100644 --- a/lib/specifications/Specification.js +++ b/lib/specifications/Specification.js @@ -39,9 +39,6 @@ class Specification { case "application": { return createAndInitializeSpec("types/Application.js", parameters); } - case "component": { - return createAndInitializeSpec("types/Component.js", parameters); - } case "library": { return createAndInitializeSpec("types/Library.js", parameters); } diff --git a/lib/specifications/types/Component.js b/lib/specifications/types/Component.js deleted file mode 100644 index 227dc629c..000000000 --- a/lib/specifications/types/Component.js +++ /dev/null @@ -1,259 +0,0 @@ -import fsPath from "node:path"; -import ComponentProject from "../ComponentProject.js"; -import {createReader} from "@ui5/fs/resourceFactory"; - -/** - * Component - * - * @public - * @class - * @alias @ui5/project/specifications/types/Component - * @extends @ui5/project/specifications/ComponentProject - * @hideconstructor - */ -class Component extends ComponentProject { - constructor(parameters) { - super(parameters); - - this._pManifests = Object.create(null); - - this._srcPath = "src"; - this._testPath = "test"; - this._testPathExists = false; - - this._propertiesFilesSourceEncoding = "UTF-8"; - } - - /* === Attributes === */ - - /** - * Get the cachebuster signature type configuration of the project - * - * @returns {string} time or hash - */ - getCachebusterSignatureType() { - return this._config.builder && this._config.builder.cachebuster && - this._config.builder.cachebuster.signatureType || "time"; - } - - /** - * Get the path of the project's source directory. This might not be POSIX-style on some platforms. - * - * @public - * @returns {string} Absolute path to the source directory of the project - */ - getSourcePath() { - return fsPath.join(this.getRootPath(), this._srcPath); - } - - /* === Resource Access === */ - /** - * Get a resource reader for the sources of the project (excluding any test resources) - * - * @param {string[]} excludes List of glob patterns to exclude - * @returns {@ui5/fs/ReaderCollection} Reader collection - */ - _getSourceReader(excludes) { - return createReader({ - fsBasePath: this.getSourcePath(), - virBasePath: `/resources/${this._namespace}/`, - name: `Source reader for component project ${this.getName()}`, - project: this, - excludes - }); - } - - /** - * Get a resource reader for the test-resources of the project - * - * @param {string[]} excludes List of glob patterns to exclude - * @returns {@ui5/fs/ReaderCollection} Reader collection - */ - _getTestReader(excludes) { - if (!this._testPathExists) { - return null; - } - const testReader = createReader({ - fsBasePath: fsPath.join(this.getRootPath(), this._testPath), - virBasePath: `/test-resources/${this._namespace}/`, - name: `Runtime test-resources reader for component project ${this.getName()}`, - project: this, - excludes - }); - return testReader; - } - - /** - * Get a resource reader for the sources of the project (excluding any test resources) - * without a virtual base path - * - * @returns {@ui5/fs/ReaderCollection} Reader collection - */ - _getRawSourceReader() { - return createReader({ - fsBasePath: this.getSourcePath(), - virBasePath: "/", - name: `Raw source reader for component project ${this.getName()}`, - project: this - }); - } - - /* === Internals === */ - /** - * @private - * @param {object} config Configuration object - */ - async _configureAndValidatePaths(config) { - await super._configureAndValidatePaths(config); - - if (config.resources && config.resources.configuration && config.resources.configuration.paths) { - if (config.resources.configuration.paths.src) { - this._srcPath = config.resources.configuration.paths.src; - } - if (config.resources.configuration.paths.test) { - this._testPath = config.resources.configuration.paths.test; - } - } - if (!(await this._dirExists("/" + this._srcPath))) { - throw new Error( - `Unable to find source directory '${this._srcPath}' in component project ${this.getName()}`); - } - this._testPathExists = await this._dirExists("/" + this._testPath); - - this._log.verbose(`Path mapping for component project ${this.getName()}:`); - this._log.verbose(` Physical root path: ${this.getRootPath()}`); - this._log.verbose(` Mapped to:`); - this._log.verbose(` /resources/ => ${this._srcPath}`); - this._log.verbose( - ` /test-resources/ => ${this._testPath}${this._testPathExists ? "" : " [does not exist]"}`); - } - - /** - * @private - * @param {object} config Configuration object - * @param {object} buildDescription Cache metadata object - */ - async _parseConfiguration(config, buildDescription) { - await super._parseConfiguration(config, buildDescription); - - if (buildDescription) { - this._namespace = buildDescription.namespace; - return; - } - this._namespace = await this._getNamespace(); - } - - /** - * Determine component namespace either based on a project`s - * manifest.json or manifest.appdescr_variant (fallback if present) - * - * @returns {string} Namespace of the project - * @throws {Error} if namespace can not be determined - */ - async _getNamespace() { - try { - return await this._getNamespaceFromManifestJson(); - } catch (manifestJsonError) { - if (manifestJsonError.code !== "ENOENT") { - throw manifestJsonError; - } - // No manifest.json present - // => attempt fallback to manifest.appdescr_variant (typical for App Variants) - try { - return await this._getNamespaceFromManifestAppDescVariant(); - } catch (appDescVarError) { - if (appDescVarError.code === "ENOENT") { - // Fallback not possible: No manifest.appdescr_variant present - // => Throw error indicating missing manifest.json - // (do not mention manifest.appdescr_variant since it is only - // relevant for the rather "uncommon" App Variants) - throw new Error( - `Could not find required manifest.json for project ` + - `${this.getName()}: ${manifestJsonError.message}`); - } - throw appDescVarError; - } - } - } - - /** - * Determine application namespace by checking manifest.json. - * Any maven placeholders are resolved from the projects pom.xml - * - * @returns {string} Namespace of the project - * @throws {Error} if namespace can not be determined - */ - async _getNamespaceFromManifestJson() { - const manifest = await this._getManifest("/manifest.json"); - let appId; - // check for a proper sap.app/id in manifest.json to determine namespace - if (manifest["sap.app"] && manifest["sap.app"].id) { - appId = manifest["sap.app"].id; - } else { - throw new Error( - `No sap.app/id configuration found in manifest.json of project ${this.getName()}`); - } - - if (this._hasMavenPlaceholder(appId)) { - try { - appId = await this._resolveMavenPlaceholder(appId); - } catch (err) { - throw new Error( - `Failed to resolve namespace of project ${this.getName()}: ${err.message}`); - } - } - const namespace = appId.replace(/\./g, "/"); - this._log.verbose( - `Namespace of project ${this.getName()} is ${namespace} (from manifest.json)`); - return namespace; - } - - /** - * Determine application namespace by checking manifest.appdescr_variant. - * - * @returns {string} Namespace of the project - * @throws {Error} if namespace can not be determined - */ - async _getNamespaceFromManifestAppDescVariant() { - const manifest = await this._getManifest("/manifest.appdescr_variant"); - let appId; - // check for the id property in manifest.appdescr_variant to determine namespace - if (manifest && manifest.id) { - appId = manifest.id; - } else { - throw new Error( - `No "id" property found in manifest.appdescr_variant of project ${this.getName()}`); - } - - const namespace = appId.replace(/\./g, "/"); - this._log.verbose( - `Namespace of project ${this.getName()} is ${namespace} (from manifest.appdescr_variant)`); - return namespace; - } - - /** - * Reads and parses a JSON file with the provided name from the projects source directory - * - * @param {string} filePath Name of the JSON file to read. Typically "manifest.json" or "manifest.appdescr_variant" - * @returns {Promise} resolves with an object containing the content requested manifest file - */ - async _getManifest(filePath) { - if (this._pManifests[filePath]) { - return this._pManifests[filePath]; - } - return this._pManifests[filePath] = this._getRawSourceReader().byPath(filePath) - .then(async (resource) => { - if (!resource) { - throw new Error( - `Could not find resource ${filePath} in project ${this.getName()}`); - } - return JSON.parse(await resource.getString()); - }).catch((err) => { - throw new Error( - `Failed to read ${filePath} for project ` + - `${this.getName()}: ${err.message}`); - }); - } -} - -export default Component; diff --git a/lib/validation/schema/specVersion/kind/project.json b/lib/validation/schema/specVersion/kind/project.json index d1aa74b58..65191e05f 100644 --- a/lib/validation/schema/specVersion/kind/project.json +++ b/lib/validation/schema/specVersion/kind/project.json @@ -13,7 +13,6 @@ "type": { "enum": [ "application", - "component", "library", "theme-library", "module" @@ -63,16 +62,6 @@ }, "then": { "$ref": "project/module.json" - }, - "else": { - "if": { - "properties": { - "type": {"const": "component"} - } - }, - "then": { - "$ref": "project/component.json" - } } } } diff --git a/lib/validation/schema/specVersion/kind/project/component.json b/lib/validation/schema/specVersion/kind/project/component.json deleted file mode 100644 index 49539317f..000000000 --- a/lib/validation/schema/specVersion/kind/project/component.json +++ /dev/null @@ -1,108 +0,0 @@ -{ - "$schema": "http://json-schema.org/draft-07/schema", - "$id": "http://ui5.sap/schema/specVersion/kind/project/component.json", - - "type": "object", - "required": ["specVersion", "type", "metadata"], - "if": { - "properties": { - "specVersion": { "enum": ["3.1"] } - } - }, - "then": { - "additionalProperties": false, - "properties": { - "specVersion": { "enum": ["3.1"] }, - "kind": { - "enum": ["project", null] - }, - "type": { - "enum": ["component"] - }, - "metadata": { - "$ref": "../project.json#/definitions/metadata-3.0" - }, - "framework": { - "$ref": "../project.json#/definitions/framework" - }, - "resources": { - "$ref": "#/definitions/resources" - }, - "builder": { - "$ref": "#/definitions/builder-specVersion-3.0" - }, - "server": { - "$ref": "../project.json#/definitions/server" - }, - "customConfiguration": { - "type": "object", - "additionalProperties": true - } - } - }, - "else": { - }, - - "definitions": { - "resources": { - "type": "object", - "additionalProperties": false, - "properties": { - "configuration": { - "type": "object", - "additionalProperties": false, - "properties": { - "propertiesFileSourceEncoding": { - "$ref": "../project.json#/definitions/resources-configuration-propertiesFileSourceEncoding" - }, - "paths": { - "type": "object", - "additionalProperties": false, - "properties": { - "src": { - "type": "string" - }, - "test": { - "type": "string" - } - } - } - } - } - } - }, - "builder-specVersion-3.0": { - "type": "object", - "additionalProperties": false, - "properties": { - "resources": { - "$ref": "../project.json#/definitions/builder-resources" - }, - "cachebuster": { - "type": "object", - "additionalProperties": false, - "properties": { - "signatureType": { - "enum": ["time", "hash"] - } - } - }, - "bundles": { - "$ref": "../project.json#/definitions/builder-bundles-3.0" - }, - "componentPreload": { - "$ref": "../project.json#/definitions/builder-componentPreload-specVersion-2.3" - }, - "customTasks": { - "$ref": "../project.json#/definitions/customTasks" - }, - "minification": { - "$ref": "../project.json#/definitions/builder-minification" - }, - "settings": { - "$ref": "../project.json#/definitions/builder-settings" - } - } - } - } -} diff --git a/test/fixtures/component.a/middleware.a.js b/test/fixtures/component.a/middleware.a.js deleted file mode 100644 index ea41b01de..000000000 --- a/test/fixtures/component.a/middleware.a.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = function () {}; diff --git a/test/fixtures/component.a/node_modules/collection/library.a/package.json b/test/fixtures/component.a/node_modules/collection/library.a/package.json deleted file mode 100644 index 2179673d4..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.a/package.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name": "library.a", - "version": "1.0.0", - "description": "Simple SAPUI5 based library", - "dependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "ui5": { - "name": "library.a", - "type": "library", - "settings": { - "src": "src", - "test": "test" - } - } -} diff --git a/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library b/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library deleted file mode 100644 index 25c8603f3..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/.library +++ /dev/null @@ -1,17 +0,0 @@ - - - - library.a - SAP SE - ${copyright} - ${version} - - Library A - - - - library.d - - - - diff --git a/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less b/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less deleted file mode 100644 index ff0f1d5e3..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.a/src/library/a/themes/base/library.source.less +++ /dev/null @@ -1,6 +0,0 @@ -@libraryAColor1: lightgoldenrodyellow; - -.library-a-foo { - color: @libraryAColor1; - padding: 1px 2px 3px 4px; -} diff --git a/test/fixtures/component.a/node_modules/collection/library.a/test/library/a/Test.html b/test/fixtures/component.a/node_modules/collection/library.a/test/library/a/Test.html deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml b/test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml deleted file mode 100644 index 8d4784313..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.a/ui5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -specVersion: "2.3" -type: library -metadata: - name: library.a diff --git a/test/fixtures/component.a/node_modules/collection/library.b/package.json b/test/fixtures/component.a/node_modules/collection/library.b/package.json deleted file mode 100644 index 2a0243b16..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.b/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "library.b", - "version": "1.0.0", - "description": "Simple SAPUI5 based library", - "dependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - } -} diff --git a/test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library b/test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library deleted file mode 100644 index 36052aceb..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.b/src/library/b/.library +++ /dev/null @@ -1,17 +0,0 @@ - - - - library.b - SAP SE - ${copyright} - ${version} - - Library B - - - - library.d - - - - diff --git a/test/fixtures/component.a/node_modules/collection/library.b/test/library/b/Test.html b/test/fixtures/component.a/node_modules/collection/library.b/test/library/b/Test.html deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml b/test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml deleted file mode 100644 index b2fe5be59..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.b/ui5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -specVersion: "2.3" -type: library -metadata: - name: library.b diff --git a/test/fixtures/component.a/node_modules/collection/library.c/package.json b/test/fixtures/component.a/node_modules/collection/library.c/package.json deleted file mode 100644 index 64ac75d6f..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.c/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "library.c", - "version": "1.0.0", - "description": "Simple SAPUI5 based library", - "dependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - } -} diff --git a/test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library b/test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library deleted file mode 100644 index 4180ce2af..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.c/src/library/c/.library +++ /dev/null @@ -1,17 +0,0 @@ - - - - library.c - SAP SE - ${copyright} - ${version} - - Library C - - - - library.d - - - - diff --git a/test/fixtures/component.a/node_modules/collection/library.c/test/LibraryC/Test.html b/test/fixtures/component.a/node_modules/collection/library.c/test/LibraryC/Test.html deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml b/test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml deleted file mode 100644 index 7c5e38a7f..000000000 --- a/test/fixtures/component.a/node_modules/collection/library.c/ui5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -specVersion: "2.3" -type: library -metadata: - name: library.c diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json deleted file mode 100644 index 90c75040a..000000000 --- a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "library.d", - "version": "1.0.0", - "description": "Simple SAPUI5 based library", - "dependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - } -} diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library deleted file mode 100644 index 21251d1bb..000000000 --- a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/src/library/d/.library +++ /dev/null @@ -1,11 +0,0 @@ - - - - library.d - SAP SE - ${copyright} - ${version} - - Library D - - diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/test/library/d/Test.html b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/test/library/d/Test.html deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml b/test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml deleted file mode 100644 index a47c1f64c..000000000 --- a/test/fixtures/component.a/node_modules/collection/node_modules/library.d/ui5.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -specVersion: "2.3" -type: library -metadata: - name: library.d -resources: - configuration: - paths: - src: main/src - test: main/test diff --git a/test/fixtures/component.a/node_modules/collection/package.json b/test/fixtures/component.a/node_modules/collection/package.json deleted file mode 100644 index 81b948438..000000000 --- a/test/fixtures/component.a/node_modules/collection/package.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "name": "collection", - "version": "1.0.0", - "description": "Simple Collection", - "dependencies": { - "library.d": "file:../library.d" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "collection": { - "modules": { - "library.a": "./library.a", - "library.b": "./library.b", - "library.c": "./library.c" - } - } -} diff --git a/test/fixtures/component.a/node_modules/collection/ui5.yaml b/test/fixtures/component.a/node_modules/collection/ui5.yaml deleted file mode 100644 index e47048de6..000000000 --- a/test/fixtures/component.a/node_modules/collection/ui5.yaml +++ /dev/null @@ -1,12 +0,0 @@ -specVersion: "2.1" -metadata: - name: application.a.collection.dependency.shim -kind: extension -type: project-shim -shims: - collections: - collection: - modules: - "library.a": "./library.a" - "library.b": "./library.b" - "library.c": "./library.c" \ No newline at end of file diff --git a/test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library b/test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library deleted file mode 100644 index 53c2d14c9..000000000 --- a/test/fixtures/component.a/node_modules/library.d/main/src/library/d/.library +++ /dev/null @@ -1,11 +0,0 @@ - - - - library.d - SAP SE - Some fancy copyright - ${version} - - Library D - - diff --git a/test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js b/test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js deleted file mode 100644 index 81e734360..000000000 --- a/test/fixtures/component.a/node_modules/library.d/main/src/library/d/some.js +++ /dev/null @@ -1,4 +0,0 @@ -/*! - * ${copyright} - */ -console.log('HelloWorld'); \ No newline at end of file diff --git a/test/fixtures/component.a/node_modules/library.d/main/test/library/d/Test.html b/test/fixtures/component.a/node_modules/library.d/main/test/library/d/Test.html deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fixtures/component.a/node_modules/library.d/package.json b/test/fixtures/component.a/node_modules/library.d/package.json deleted file mode 100644 index 90c75040a..000000000 --- a/test/fixtures/component.a/node_modules/library.d/package.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "name": "library.d", - "version": "1.0.0", - "description": "Simple SAPUI5 based library", - "dependencies": {}, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - } -} diff --git a/test/fixtures/component.a/node_modules/library.d/ui5.yaml b/test/fixtures/component.a/node_modules/library.d/ui5.yaml deleted file mode 100644 index a47c1f64c..000000000 --- a/test/fixtures/component.a/node_modules/library.d/ui5.yaml +++ /dev/null @@ -1,10 +0,0 @@ ---- -specVersion: "2.3" -type: library -metadata: - name: library.d -resources: - configuration: - paths: - src: main/src - test: main/test diff --git a/test/fixtures/component.a/package.json b/test/fixtures/component.a/package.json deleted file mode 100644 index cd7457d2b..000000000 --- a/test/fixtures/component.a/package.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "name": "component.a", - "version": "1.0.0", - "description": "Simple SAPUI5 based component", - "main": "index.html", - "dependencies": { - "library.d": "file:../library.d", - "collection": "file:../collection" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - } -} diff --git a/test/fixtures/component.a/src/index.html b/test/fixtures/component.a/src/index.html deleted file mode 100644 index 77b0207cc..000000000 --- a/test/fixtures/component.a/src/index.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - Application A - - - - - \ No newline at end of file diff --git a/test/fixtures/component.a/src/manifest.json b/test/fixtures/component.a/src/manifest.json deleted file mode 100644 index 781945df9..000000000 --- a/test/fixtures/component.a/src/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_version": "1.1.0", - "sap.app": { - "_version": "1.1.0", - "id": "id1", - "type": "application", - "applicationVersion": { - "version": "1.2.2" - }, - "embeds": ["embedded"], - "title": "{{title}}" - } -} \ No newline at end of file diff --git a/test/fixtures/component.a/src/test.js b/test/fixtures/component.a/src/test.js deleted file mode 100644 index a3df410c3..000000000 --- a/test/fixtures/component.a/src/test.js +++ /dev/null @@ -1,5 +0,0 @@ -function test(paramA) { - var variableA = paramA; - console.log(variableA); -} -test(); diff --git a/test/fixtures/component.a/task.a.js b/test/fixtures/component.a/task.a.js deleted file mode 100644 index ea41b01de..000000000 --- a/test/fixtures/component.a/task.a.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = function () {}; diff --git a/test/fixtures/component.a/ui5-test-configPath.yaml b/test/fixtures/component.a/ui5-test-configPath.yaml deleted file mode 100644 index 9dfaec758..000000000 --- a/test/fixtures/component.a/ui5-test-configPath.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -specVersion: "3.1" -type: component -metadata: - name: component.a -customConfiguration: - configPathTest: true \ No newline at end of file diff --git a/test/fixtures/component.a/ui5-test-corrupt.yaml b/test/fixtures/component.a/ui5-test-corrupt.yaml deleted file mode 100644 index ecce9d7e7..000000000 --- a/test/fixtures/component.a/ui5-test-corrupt.yaml +++ /dev/null @@ -1 +0,0 @@ -|-\nfoo\nbar diff --git a/test/fixtures/component.a/ui5-test-empty.yaml b/test/fixtures/component.a/ui5-test-empty.yaml deleted file mode 100644 index e69de29bb..000000000 diff --git a/test/fixtures/component.a/ui5-test-error.yaml b/test/fixtures/component.a/ui5-test-error.yaml deleted file mode 100644 index 639b4889a..000000000 --- a/test/fixtures/component.a/ui5-test-error.yaml +++ /dev/null @@ -1,7 +0,0 @@ ---- -specVersion: "3.1" -type: component -metadata: - name: component.a -xyz: - foo: true \ No newline at end of file diff --git a/test/fixtures/component.a/ui5.yaml b/test/fixtures/component.a/ui5.yaml deleted file mode 100644 index f149b0e87..000000000 --- a/test/fixtures/component.a/ui5.yaml +++ /dev/null @@ -1,5 +0,0 @@ ---- -specVersion: "3.1" -type: component -metadata: - name: component.a diff --git a/test/fixtures/component.h/pom.xml b/test/fixtures/component.h/pom.xml deleted file mode 100644 index 7ee5daf7a..000000000 --- a/test/fixtures/component.h/pom.xml +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - - 4.0.0 - - - - - com.sap.test - component.h - 1.0.0 - war - - - - - component.h - Simple SAPUI5 based component - - - - - - - component.h - - - - - diff --git a/test/fixtures/component.h/webapp-project.artifactId/manifest.json b/test/fixtures/component.h/webapp-project.artifactId/manifest.json deleted file mode 100644 index 7de6072ce..000000000 --- a/test/fixtures/component.h/webapp-project.artifactId/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_version": "1.1.0", - "sap.app": { - "_version": "1.1.0", - "id": "${project.artifactId}", - "type": "application", - "applicationVersion": { - "version": "1.2.2" - }, - "embeds": ["embedded"], - "title": "{{title}}" - } -} diff --git a/test/fixtures/component.h/webapp-properties.appId/manifest.json b/test/fixtures/component.h/webapp-properties.appId/manifest.json deleted file mode 100644 index e1515df70..000000000 --- a/test/fixtures/component.h/webapp-properties.appId/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_version": "1.1.0", - "sap.app": { - "_version": "1.1.0", - "id": "${appId}", - "type": "application", - "applicationVersion": { - "version": "1.2.2" - }, - "embeds": ["embedded"], - "title": "{{title}}" - } -} diff --git a/test/fixtures/component.h/webapp-properties.componentName/manifest.json b/test/fixtures/component.h/webapp-properties.componentName/manifest.json deleted file mode 100644 index 7d63e359c..000000000 --- a/test/fixtures/component.h/webapp-properties.componentName/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_version": "1.1.0", - "sap.app": { - "_version": "1.1.0", - "id": "${componentName}", - "type": "application", - "applicationVersion": { - "version": "1.2.2" - }, - "embeds": ["embedded"], - "title": "{{title}}" - } -} diff --git a/test/fixtures/component.h/webapp/Component.js b/test/fixtures/component.h/webapp/Component.js deleted file mode 100644 index cb9bd4068..000000000 --- a/test/fixtures/component.h/webapp/Component.js +++ /dev/null @@ -1,8 +0,0 @@ -sap.ui.define(["sap/ui/core/UIComponent"], function(UIComponent){ - "use strict"; - return UIComponent.extend('application.h.Component', { - metadata: { - manifest: "json" - } - }); -}); diff --git a/test/fixtures/component.h/webapp/manifest.json b/test/fixtures/component.h/webapp/manifest.json deleted file mode 100644 index 32b7e4a84..000000000 --- a/test/fixtures/component.h/webapp/manifest.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "_version": "1.1.0", - "sap.app": { - "_version": "1.1.0", - "id": "application.h", - "type": "application", - "applicationVersion": { - "version": "1.2.2" - }, - "embeds": ["embedded"], - "title": "{{title}}" - } -} diff --git a/test/fixtures/component.h/webapp/sectionsA/section1.js b/test/fixtures/component.h/webapp/sectionsA/section1.js deleted file mode 100644 index ac4a81296..000000000 --- a/test/fixtures/component.h/webapp/sectionsA/section1.js +++ /dev/null @@ -1,3 +0,0 @@ -sap.ui.define(["sap/m/Button"], function(Button) { - console.log("Section 1 included"); -}); diff --git a/test/fixtures/component.h/webapp/sectionsA/section2.js b/test/fixtures/component.h/webapp/sectionsA/section2.js deleted file mode 100644 index e009c8286..000000000 --- a/test/fixtures/component.h/webapp/sectionsA/section2.js +++ /dev/null @@ -1,3 +0,0 @@ -sap.ui.define(["sap/m/Button"], function(Button) { - console.log("Section 2 included"); -}); diff --git a/test/fixtures/component.h/webapp/sectionsA/section3.js b/test/fixtures/component.h/webapp/sectionsA/section3.js deleted file mode 100644 index 5fd9349d4..000000000 --- a/test/fixtures/component.h/webapp/sectionsA/section3.js +++ /dev/null @@ -1,3 +0,0 @@ -sap.ui.define(["sap/m/Button"], function(Button) { - console.log("Section 3 included"); -}); diff --git a/test/fixtures/component.h/webapp/sectionsB/section1.js b/test/fixtures/component.h/webapp/sectionsB/section1.js deleted file mode 100644 index ac4a81296..000000000 --- a/test/fixtures/component.h/webapp/sectionsB/section1.js +++ /dev/null @@ -1,3 +0,0 @@ -sap.ui.define(["sap/m/Button"], function(Button) { - console.log("Section 1 included"); -}); diff --git a/test/fixtures/component.h/webapp/sectionsB/section2.js b/test/fixtures/component.h/webapp/sectionsB/section2.js deleted file mode 100644 index e009c8286..000000000 --- a/test/fixtures/component.h/webapp/sectionsB/section2.js +++ /dev/null @@ -1,3 +0,0 @@ -sap.ui.define(["sap/m/Button"], function(Button) { - console.log("Section 2 included"); -}); diff --git a/test/fixtures/component.h/webapp/sectionsB/section3.js b/test/fixtures/component.h/webapp/sectionsB/section3.js deleted file mode 100644 index 5fd9349d4..000000000 --- a/test/fixtures/component.h/webapp/sectionsB/section3.js +++ /dev/null @@ -1,3 +0,0 @@ -sap.ui.define(["sap/m/Button"], function(Button) { - console.log("Section 3 included"); -}); diff --git a/test/lib/specifications/types/Component.js b/test/lib/specifications/types/Component.js deleted file mode 100644 index 559d4a9f9..000000000 --- a/test/lib/specifications/types/Component.js +++ /dev/null @@ -1,679 +0,0 @@ -import test from "ava"; -import path from "node:path"; -import {fileURLToPath} from "node:url"; -import {createResource} from "@ui5/fs/resourceFactory"; -import sinonGlobal from "sinon"; -import Specification from "../../../../lib/specifications/Specification.js"; -import Component from "../../../../lib/specifications/types/Component.js"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const componentAPath = path.join(__dirname, "..", "..", "..", "fixtures", "component.a"); -const componentHPath = path.join(__dirname, "..", "..", "..", "fixtures", "component.h"); - -test.beforeEach((t) => { - t.context.sinon = sinonGlobal.createSandbox(); - t.context.projectInput = { - id: "component.a.id", - version: "1.0.0", - modulePath: componentAPath, - configuration: { - specVersion: "3.1", - kind: "project", - type: "component", - metadata: {name: "component.a"} - } - }; - - t.context.componentHInput = { - id: "component.h.id", - version: "1.0.0", - modulePath: componentHPath, - configuration: { - specVersion: "3.1", - kind: "project", - type: "component", - metadata: {name: "component.h"}, - resources: { - configuration: { - paths: { - src: "webapp" - } - } - } - } - }; -}); - -test.afterEach.always((t) => { - t.context.sinon.restore(); -}); - -test("Correct class", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - t.true(project instanceof Component, `Is an instance of the Component class`); -}); - -test("getNamespace", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - t.is(project.getNamespace(), "id1", - "Returned correct namespace"); -}); - -test("getSourcePath", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - t.is(project.getSourcePath(), path.join(componentAPath, "src"), - "Returned correct source path"); -}); - -test("getCachebusterSignatureType: Default", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - t.is(project.getCachebusterSignatureType(), "time", - "Returned correct default cachebuster signature type configuration"); -}); - -test("getCachebusterSignatureType: Configuration", async (t) => { - const {projectInput} = t.context; - projectInput.configuration.builder = { - cachebuster: { - signatureType: "hash" - } - }; - const project = await Specification.create(projectInput); - t.is(project.getCachebusterSignatureType(), "hash", - "Returned correct default cachebuster signature type configuration"); -}); - -test("Access project resources via reader: buildtime style", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - const reader = project.getReader(); - const resource = await reader.byPath("/resources/id1/manifest.json"); - t.truthy(resource, "Found the requested resource"); - t.is(resource.getPath(), "/resources/id1/manifest.json", "Resource has correct path"); -}); - -test("Access project resources via reader: flat style", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - const reader = project.getReader({style: "flat"}); - const resource = await reader.byPath("/manifest.json"); - t.truthy(resource, "Found the requested resource"); - t.is(resource.getPath(), "/manifest.json", "Resource has correct path"); -}); - -test("Access project resources via reader: runtime style", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - const reader = project.getReader({style: "runtime"}); - const resource = await reader.byPath("/resources/id1/manifest.json"); - t.truthy(resource, "Found the requested resource"); - t.is(resource.getPath(), "/resources/id1/manifest.json", "Resource has correct path"); -}); - -test("Access project resources via reader w/ builder excludes", async (t) => { - const {projectInput} = t.context; - const baselineProject = await Specification.create(projectInput); - - projectInput.configuration.builder = { - resources: { - excludes: ["**/manifest.json"] - } - }; - const excludesProject = await Specification.create(projectInput); - - // We now have two projects: One with excludes and one without - // Always compare the results of both to make sure a file is really excluded because of the - // configuration and not because of a typo or because of it's absence in the fixture - - t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for default style"); - - t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for buildtime style"); - t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for buildtime style"); - - t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for dist style"); - t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for dist style"); - - t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for flat style"); - t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for flat style"); - - t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for runtime style"); - t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found excluded resource for runtime style"); -}); - -test("Access project resources via workspace w/ builder excludes", async (t) => { - const {projectInput} = t.context; - const baselineProject = await Specification.create(projectInput); - - projectInput.configuration.builder = { - resources: { - excludes: ["**/manifest.json"] - } - }; - const excludesProject = await Specification.create(projectInput); - - // We now have two projects: One with excludes and one without - // Always compare the results of both to make sure a file is really excluded because of the - // configuration and not because of a typo or because of it's absence in the fixture - - t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for default style"); -}); - -test("Access project resources w/ absolute builder excludes", async (t) => { - const {projectInput} = t.context; - const baselineProject = await Specification.create(projectInput); - - projectInput.configuration.builder = { - resources: { - excludes: ["/resources/id1/manifest.json"] - } - }; - const excludesProject = await Specification.create(projectInput); - - // We now have two projects: One with excludes and one without - // Always compare the results of both to make sure a file is really excluded because of the - // configuration and not because of a typo or because of it's absence in the fixture - - t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for default style"); - - t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for buildtime style"); - t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for buildtime style"); - - t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for dist style"); - t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for dist style"); - - t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for flat style"); - t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for flat style"); - - // Excludes are not applied for "runtime" style - t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for runtime style"); - t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found excluded resource for runtime style"); - - t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 0, - "Did not find excluded resource for default style"); -}); - -test("Access project resources w/ relative builder excludes", async (t) => { - const {projectInput} = t.context; - const baselineProject = await Specification.create(projectInput); - - projectInput.configuration.builder = { - resources: { - excludes: ["manifest.json"] // Has no effect since component excludes must be absolute or use wildcards - } - }; - const excludesProject = await Specification.create(projectInput); - - // We now have two projects: One with excludes and one without - // Always compare the results of both to make sure a file is really excluded because of the - // configuration and not because of a typo or because of it's absence in the fixture - - t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for default style"); - - t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for buildtime style"); - t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for buildtime style"); - - t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for dist style"); - t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for dist style"); - - t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for flat style"); - t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for flat style"); - - // Excludes are not applied for "runtime" style - t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for runtime style"); - t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found excluded resource for runtime style"); - - t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for default style"); -}); - -test("Access project resources w/ incorrect builder excludes", async (t) => { - const {projectInput} = t.context; - const baselineProject = await Specification.create(projectInput); - - projectInput.configuration.builder = { - resources: { - excludes: ["/manifest.json"] - } - }; - const excludesProject = await Specification.create(projectInput); - - // We now have two projects: One with excludes and one without - // Always compare the results of both to make sure a file is really excluded because of the - // configuration and not because of a typo or because of it's absence in the fixture - - t.is((await baselineProject.getReader({}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getReader({}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for default style"); - - t.is((await baselineProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for buildtime style"); - t.is((await excludesProject.getReader({style: "buildtime"}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for buildtime style"); - - t.is((await baselineProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for dist style"); - t.is((await excludesProject.getReader({style: "dist"}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for dist style"); - - t.is((await baselineProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for flat style"); - t.is((await excludesProject.getReader({style: "flat"}).byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for flat style"); - - // Excludes are not applied for "runtime" style - t.is((await baselineProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for runtime style"); - t.is((await excludesProject.getReader({style: "runtime"}).byGlob("**/manifest.json")).length, 1, - "Found excluded resource for runtime style"); - - t.is((await baselineProject.getWorkspace().byGlob("**/manifest.json")).length, 1, - "Found resource in baseline project for default style"); - t.is((await excludesProject.getWorkspace().byGlob("**/manifest.json")).length, 1, - "Did not find excluded resource for default style"); -}); - -test("Modify project resources via workspace and access via flat and runtime readers", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - const workspace = project.getWorkspace(); - const workspaceResource = await workspace.byPath("/resources/id1/index.html"); - t.truthy(workspaceResource, "Found resource in workspace"); - - const newContent = (await workspaceResource.getString()).replace("Component A", "Some Name"); - workspaceResource.setString(newContent); - await workspace.write(workspaceResource); - - const flatReader = project.getReader({style: "flat"}); - const flatReaderResource = await flatReader.byPath("/index.html"); - t.truthy(flatReaderResource, "Found the requested resource byPath"); - t.is(flatReaderResource.getPath(), "/index.html", "Resource (byPath) has correct path"); - t.is(await flatReaderResource.getString(), newContent, "Found resource (byPath) has expected (changed) content"); - - const flatGlobResult = await flatReader.byGlob("**/index.html"); - t.is(flatGlobResult.length, 1, "Found the requested resource byGlob"); - t.is(flatGlobResult[0].getPath(), "/index.html", "Resource (byGlob) has correct path"); - t.is(await flatGlobResult[0].getString(), newContent, "Found resource (byGlob) has expected (changed) content"); - - const runtimeReader = project.getReader({style: "runtime"}); - const runtimeReaderResource = await runtimeReader.byPath("/resources/id1/index.html"); - t.truthy(runtimeReaderResource, "Found the requested resource byPath"); - t.is(runtimeReaderResource.getPath(), "/resources/id1/index.html", "Resource (byPath) has correct path"); - t.is(await runtimeReaderResource.getString(), newContent, "Found resource (byPath) has expected (changed) content"); - - const runtimeGlobResult = await runtimeReader.byGlob("**/index.html"); - t.is(runtimeGlobResult.length, 1, "Found the requested resource byGlob"); - t.is(runtimeGlobResult[0].getPath(), "/resources/id1/index.html", "Resource (byGlob) has correct path"); - t.is(await runtimeGlobResult[0].getString(), newContent, "Found resource (byGlob) has expected (changed) content"); -}); - - -test("Read and write resources outside of app namespace", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - const workspace = project.getWorkspace(); - - await workspace.write(createResource({ - path: "/resources/my-custom-bundle.js" - })); - - const buildtimeReader = project.getReader({style: "buildtime"}); - const buildtimeReaderResource = await buildtimeReader.byPath("/resources/my-custom-bundle.js"); - t.truthy(buildtimeReaderResource, "Found the requested resource byPath (buildtime)"); - t.is(buildtimeReaderResource.getPath(), "/resources/my-custom-bundle.js", - "Resource (byPath) has correct path (buildtime)"); - - const buildtimeGlobResult = await buildtimeReader.byGlob("**/my-custom-bundle.js"); - t.is(buildtimeGlobResult.length, 1, "Found the requested resource byGlob (buildtime)"); - t.is(buildtimeGlobResult[0].getPath(), "/resources/my-custom-bundle.js", - "Resource (byGlob) has correct path (buildtime)"); - - const flatReader = project.getReader({style: "flat"}); - const flatReaderResource = await flatReader.byPath("/resources/my-custom-bundle.js"); - t.falsy(flatReaderResource, "Resource outside of app namespace can't be read using flat reader"); - - const flatGlobResult = await flatReader.byGlob("**/my-custom-bundle.js"); - t.is(flatGlobResult.length, 0, "Resource outside of app namespace can't be found using flat reader"); - - const runtimeReader = project.getReader({style: "runtime"}); - const runtimeReaderResource = await runtimeReader.byPath("/resources/my-custom-bundle.js"); - t.truthy(runtimeReaderResource, "Found the requested resource byPath (runtime)"); - t.is(runtimeReaderResource.getPath(), "/resources/my-custom-bundle.js", - "Resource (byPath) has correct path (runtime)"); - - const runtimeGlobResult = await runtimeReader.byGlob("**/my-custom-bundle.js"); - t.is(runtimeGlobResult.length, 1, "Found the requested resource byGlob (runtime)"); - t.is(runtimeGlobResult[0].getPath(), "/resources/my-custom-bundle.js", - "Resource (byGlob) has correct path (runtime)"); -}); - -test("_configureAndValidatePaths: Default paths", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - - t.is(project._srcPath, "src", "Correct default path"); -}); - -test("_configureAndValidatePaths: Custom src directory", async (t) => { - const componentHPath = path.join(__dirname, "..", "..", "..", "fixtures", "component.h"); - const projectInput = { - id: "component.h.id", - version: "1.0.0", - modulePath: componentHPath, - configuration: { - specVersion: "3.1", - kind: "project", - type: "component", - metadata: {name: "component.h"}, - resources: { - configuration: { - paths: { - src: "webapp-properties.componentName" - } - } - } - } - }; - - const project = await Specification.create(projectInput); - - t.is(project._srcPath, "webapp-properties.componentName", "Correct path for src"); -}); - -test("_configureAndValidatePaths: src directory does not exist", async (t) => { - const {projectInput} = t.context; - projectInput.configuration.resources = { - configuration: { - paths: { - src: "does/not/exist" - } - } - }; - const err = await t.throwsAsync(Specification.create(projectInput)); - - t.is(err.message, "Unable to find source directory 'does/not/exist' in component project component.a"); -}); - -test("_getNamespaceFromManifestJson: No 'sap.app' configuration found", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - sinon.stub(project, "_getManifest").resolves({}); - - const error = await t.throwsAsync(project._getNamespaceFromManifestJson()); - t.is(error.message, "No sap.app/id configuration found in manifest.json of project component.a", - "Rejected with correct error message"); -}); - -test("_getNamespaceFromManifestJson: No component id in 'sap.app' configuration found", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - sinon.stub(project, "_getManifest").resolves({"sap.app": {}}); - - const error = await t.throwsAsync(project._getNamespaceFromManifestJson()); - t.is(error.message, "No sap.app/id configuration found in manifest.json of project component.a"); -}); - -test("_getNamespaceFromManifestJson: set namespace to id", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - sinon.stub(project, "_getManifest").resolves({"sap.app": {id: "my.id"}}); - - const namespace = await project._getNamespaceFromManifestJson(); - t.is(namespace, "my/id", "Returned correct namespace"); -}); - -test("_getNamespaceFromManifestAppDescVariant: No 'id' property found", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - sinon.stub(project, "_getManifest").resolves({}); - - const error = await t.throwsAsync(project._getNamespaceFromManifestAppDescVariant()); - t.is(error.message, `No "id" property found in manifest.appdescr_variant of project component.a`, - "Rejected with correct error message"); -}); - -test("_getNamespaceFromManifestAppDescVariant: set namespace to id", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - sinon.stub(project, "_getManifest").resolves({id: "my.id"}); - - const namespace = await project._getNamespaceFromManifestAppDescVariant(); - t.is(namespace, "my/id", "Returned correct namespace"); -}); - -test("_getNamespace: Correct fallback to manifest.appdescr_variant if manifest.json is missing", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - const _getManifestStub = sinon.stub(project, "_getManifest") - .onFirstCall().rejects({code: "ENOENT"}) - .onSecondCall().resolves({id: "my.id"}); - - const namespace = await project._getNamespace(); - t.is(namespace, "my/id", "Returned correct namespace"); - t.is(_getManifestStub.callCount, 2, "_getManifest called exactly twice"); - t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json first"); - t.is(_getManifestStub.getCall(1).args[0], "/manifest.appdescr_variant", - "_getManifest called for manifest.appdescr_variant in fallback"); -}); - -test("_getNamespace: Correct error message if fallback to manifest.appdescr_variant failed", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - const _getManifestStub = sinon.stub(project, "_getManifest") - .onFirstCall().rejects({code: "ENOENT"}) - .onSecondCall().rejects(new Error("EPON: Pony Error")); - - const error = await t.throwsAsync(project._getNamespace()); - t.is(error.message, "EPON: Pony Error", - "Rejected with correct error message"); - t.is(_getManifestStub.callCount, 2, "_getManifest called exactly twice"); - t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json first"); - t.is(_getManifestStub.getCall(1).args[0], "/manifest.appdescr_variant", - "_getManifest called for manifest.appdescr_variant in fallback"); -}); - -test("_getNamespace: Correct error message if fallback to manifest.appdescr_variant is not possible", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - const _getManifestStub = sinon.stub(project, "_getManifest") - .onFirstCall().rejects({message: "No such stable or directory: manifest.json", code: "ENOENT"}) - .onSecondCall().rejects({code: "ENOENT"}); // both files are missing - - const error = await t.throwsAsync(project._getNamespace()); - t.deepEqual(error.message, - "Could not find required manifest.json for project component.a: " + - "No such stable or directory: manifest.json", - "Rejected with correct error message"); - - t.is(_getManifestStub.callCount, 2, "_getManifest called exactly twice"); - t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json first"); - t.is(_getManifestStub.getCall(1).args[0], "/manifest.appdescr_variant", - "_getManifest called for manifest.appdescr_variant in fallback"); -}); - -test("_getNamespace: No fallback if manifest.json is present but failed to parse", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - const _getManifestStub = sinon.stub(project, "_getManifest") - .onFirstCall().rejects(new Error("EPON: Pony Error")); - - const error = await t.throwsAsync(project._getNamespace()); - t.is(error.message, "EPON: Pony Error", - "Rejected with correct error message"); - - t.is(_getManifestStub.callCount, 1, "_getManifest called exactly once"); - t.is(_getManifestStub.getCall(0).args[0], "/manifest.json", "_getManifest called for manifest.json only"); -}); - -test("_getManifest: reads correctly", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - - const content = await project._getManifest("/manifest.json"); - t.is(content._version, "1.1.0", "manifest.json content has been read"); -}); - -test("_getManifest: invalid JSON", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - - const byPathStub = sinon.stub().resolves({ - getString: async () => "no json" - }); - - project._getRawSourceReader = () => { - return { - byPath: byPathStub - }; - }; - - const error = await t.throwsAsync(project._getManifest("/some-manifest.json")); - t.regex(error.message, /^Failed to read \/some-manifest\.json for project component\.a: /, - "Rejected with correct error message"); - t.is(byPathStub.callCount, 1, "byPath got called once"); - t.is(byPathStub.getCall(0).args[0], "/some-manifest.json", "byPath got called with the correct argument"); -}); - -test.serial("_getManifest: File does not exist", async (t) => { - const {projectInput} = t.context; - const project = await Specification.create(projectInput); - - const error = await t.throwsAsync(project._getManifest("/does-not-exist.json")); - t.deepEqual(error.message, - "Failed to read /does-not-exist.json for project component.a: " + - "Could not find resource /does-not-exist.json in project component.a", - "Rejected with correct error message"); -}); - -test.serial("_getManifest: result is cached", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - - const byPathStub = sinon.stub().resolves({ - getString: async () => `{"pony": "no unicorn"}` - }); - - project._getRawSourceReader = () => { - return { - byPath: byPathStub - }; - }; - - const content = await project._getManifest("/some-manifest.json"); - t.deepEqual(content, {pony: "no unicorn"}, "Correct result on first call"); - - const content2 = await project._getManifest("/some-other-manifest.json"); - t.deepEqual(content2, {pony: "no unicorn"}, "Correct result on second call"); - - t.is(byPathStub.callCount, 2, "byPath got called exactly twice (and then cached)"); -}); - -test.serial("_getManifest: Caches successes and failures", async (t) => { - const {projectInput, sinon} = t.context; - const project = await Specification.create(projectInput); - - const getStringStub = sinon.stub() - .onFirstCall().rejects(new Error("EPON: Pony Error")) - .onSecondCall().resolves(`{"pony": "no unicorn"}`); - const byPathStub = sinon.stub().resolves({ - getString: getStringStub - }); - - project._getRawSourceReader = () => { - return { - byPath: byPathStub - }; - }; - - const error = await t.throwsAsync(project._getManifest("/some-manifest.json")); - t.deepEqual(error.message, - "Failed to read /some-manifest.json for project component.a: " + - "EPON: Pony Error", - "Rejected with correct error message"); - - const content = await project._getManifest("/some-other.manifest.json"); - t.deepEqual(content, {pony: "no unicorn"}, "Correct result on second call"); - - const error2 = await t.throwsAsync(project._getManifest("/some-manifest.json")); - t.deepEqual(error2.message, - "Failed to read /some-manifest.json for project component.a: " + - "EPON: Pony Error", - "From cache: Rejected with correct error message"); - - const content2 = await project._getManifest("/some-other.manifest.json"); - t.deepEqual(content2, {pony: "no unicorn"}, "From cache: Correct result on first call"); - - t.is(byPathStub.callCount, 2, - "byPath got called exactly twice (and then cached)"); -}); - -test("namespace: detect namespace from pom.xml via ${project.artifactId}", async (t) => { - const {componentHInput} = t.context; - componentHInput.configuration.resources.configuration.paths.src = "webapp-project.artifactId"; - const project = await Specification.create(componentHInput); - - t.is(project.getNamespace(), "component/h", - "namespace was successfully set since getJson provides the correct object structure"); -}); - -test("namespace: detect namespace from pom.xml via ${componentName} from properties", async (t) => { - const {componentHInput} = t.context; - componentHInput.configuration.resources.configuration.paths.src = "webapp-properties.componentName"; - const project = await Specification.create(componentHInput); - - t.is(project.getNamespace(), "component/h", - "namespace was successfully set since getJson provides the correct object structure"); -}); - -test("namespace: detect namespace from pom.xml via ${appId} from properties", async (t) => { - const {componentHInput} = t.context; - componentHInput.configuration.resources.configuration.paths.src = "webapp-properties.appId"; - - const error = await t.throwsAsync(Specification.create(componentHInput)); - t.deepEqual(error.message, "Failed to resolve namespace of project component.h: \"${appId}\"" + - " couldn't be resolved from maven property \"appId\" of pom.xml of project component.h"); -}); diff --git a/test/lib/validation/schema/__helper__/builder-bundleOptions.js b/test/lib/validation/schema/__helper__/builder-bundleOptions.js index 27278b974..b87e12813 100644 --- a/test/lib/validation/schema/__helper__/builder-bundleOptions.js +++ b/test/lib/validation/schema/__helper__/builder-bundleOptions.js @@ -5,16 +5,15 @@ import SpecificationVersion from "../../../../../lib/specifications/Specificatio */ export default { /** - * Executes the tests for different kind of projects, e.g. "application", "component", "library" + * Executes the tests for different kind of projects, e.g. "application", "library" * * @param {Function} test ava test * @param {Function} assertValidation assertion function - * @param {string} type one of "application", "component" and "library" + * @param {string} type one of "application", "library" */ defineTests: function(test, assertValidation, type) { - // Version specific tests (component type only became available with specVersion 3.1) - const range = type === "component" ? ">=3.1" : ">=3.0"; - SpecificationVersion.getVersionsForRange(range).forEach(function(specVersion) { + // Version specific tests + SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) { test(`${type} (specVersion ${specVersion}): builder/bundles/bundleOptions`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/customConfiguration.js b/test/lib/validation/schema/__helper__/customConfiguration.js index 607560658..34db358c9 100644 --- a/test/lib/validation/schema/__helper__/customConfiguration.js +++ b/test/lib/validation/schema/__helper__/customConfiguration.js @@ -6,42 +6,38 @@ import SpecificationVersion from "../../../../../lib/specifications/Specificatio export default { /** * Executes the tests for different kind of projects, - * e.g. "application", "component", "library", "theme-library" and "module" + * e.g. "application", "library", "theme-library" and "module" * * @param {Function} test ava test * @param {Function} assertValidation assertion function * @param {string} type one of "project-shim", "server-middleware" "task", - * "application", "component", "library", "theme-library" and "module" + * "application", "library", "theme-library" and "module" * @param {object} additionalConfiguration additional configuration content */ defineTests: function(test, assertValidation, type, additionalConfiguration) { additionalConfiguration = additionalConfiguration || {}; - if (type !== "component") { // Component type only became available with specVersion 3.1 - // version specific tests for customConfiguration - test(`${type}: Invalid customConfiguration (specVersion 2.0)`, async (t) => { - await assertValidation(t, Object.assign({ - "specVersion": "2.0", - "type": type, - "metadata": { - "name": "my-" + type - }, - "customConfiguration": {} - }, additionalConfiguration), [ - { - dataPath: "", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "customConfiguration", - } + // version specific tests for customConfiguration + test(`${type}: Invalid customConfiguration (specVersion 2.0)`, async (t) => { + await assertValidation(t, Object.assign({ + "specVersion": "2.0", + "type": type, + "metadata": { + "name": "my-" + type + }, + "customConfiguration": {} + }, additionalConfiguration), [ + { + dataPath: "", + keyword: "additionalProperties", + message: "should NOT have additional properties", + params: { + additionalProperty: "customConfiguration", } - ]); - }); - } + } + ]); + }); - // Component type only became available with specVersion 3.1 - const range = type === "component" ? ">=3.1" : ">=2.1"; - SpecificationVersion.getVersionsForRange(range).forEach((specVersion) => { + SpecificationVersion.getVersionsForRange(">=2.1").forEach((specVersion) => { test(`${type}: Valid customConfiguration (specVersion ${specVersion})`, async (t) => { await assertValidation(t, Object.assign( { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/framework.js b/test/lib/validation/schema/__helper__/framework.js index 0e614b162..841ce8fc7 100644 --- a/test/lib/validation/schema/__helper__/framework.js +++ b/test/lib/validation/schema/__helper__/framework.js @@ -6,16 +6,14 @@ import SpecificationVersion from "../../../../../lib/specifications/Specificatio export default { /** * Executes the tests for different types of kind project, - * e.g. "application", "component", library" and "theme-library" + * e.g. "application", library" and "theme-library" * * @param {Function} test ava test * @param {Function} assertValidation assertion function - * @param {string} type one of "application", "component", library" and "theme-library" + * @param {string} type one of "application", library" and "theme-library" */ defineTests: function(test, assertValidation, type) { - // Component type only became available with specVersion 3.1 - const range = type === "component" ? ">=3.1" : ">=2.0"; - SpecificationVersion.getVersionsForRange(range).forEach((specVersion) => { + SpecificationVersion.getVersionsForRange(">=2.0").forEach((specVersion) => { test(`${type} (specVersion ${specVersion}): framework configuration: OpenUI5`, async (t) => { const config = { "specVersion": specVersion, diff --git a/test/lib/validation/schema/__helper__/project.js b/test/lib/validation/schema/__helper__/project.js index c76b66cbf..baddd13c6 100644 --- a/test/lib/validation/schema/__helper__/project.js +++ b/test/lib/validation/schema/__helper__/project.js @@ -13,11 +13,11 @@ export default { * * @param {Function} test ava test * @param {Function} assertValidation assertion function - * @param {string} type one of "application", "component", "library", "theme-library" and "module" + * @param {string} type one of "application", "library", "theme-library" and "module" */ defineTests: function(test, assertValidation, type) { // framework tests - if (["application", "library", "theme-library", "component"].includes(type)) { + if (["application", "library", "theme-library"].includes(type)) { framework.defineTests(test, assertValidation, type); } @@ -25,14 +25,12 @@ export default { customConfiguration.defineTests(test, assertValidation, type); // builder.bundleOptions tests - if (["application", "library", "component"].includes(type)) { + if (["application", "library"].includes(type)) { bundleOptions.defineTests(test, assertValidation, type); } // version specific tests - // Component type only became available with specVersion 3.1 - const range = type === "component" ? ">=3.1" : ">=2.0"; - SpecificationVersion.getVersionsForRange(range).forEach((specVersion) => { + SpecificationVersion.getVersionsForRange(">=2.0").forEach((specVersion) => { // tests for all kinds and version 2.0 and above test(`${type} (specVersion ${specVersion}): No metadata`, async (t) => { await assertValidation(t, { @@ -263,32 +261,28 @@ export default { }); }); - if (type !== "component") { - ["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" - } + ["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" } - ]); - }); + } + ]); }); - } + }); - // Component type only became available with specVersion 3.1 - const v3Range = type === "component" ? ">=3.1" : ">=3.0"; - SpecificationVersion.getVersionsForRange(v3Range).forEach((specVersion) => { + SpecificationVersion.getVersionsForRange(">=3.0").forEach((specVersion) => { test(`${type} (specVersion ${specVersion}): Invalid metadata.name`, async (t) => { await assertValidation(t, { "specVersion": specVersion, diff --git a/test/lib/validation/schema/specVersion/kind/project.js b/test/lib/validation/schema/specVersion/kind/project.js index 42e088330..ba9d09ca5 100644 --- a/test/lib/validation/schema/specVersion/kind/project.js +++ b/test/lib/validation/schema/specVersion/kind/project.js @@ -123,27 +123,6 @@ test("Type module (no kind)", async (t) => { }); }); -test("Type component", async (t) => { - await assertValidation(t, { - "specVersion": "3.1", - "kind": "project", - "type": "component", - "metadata": { - "name": "my-component" - } - }); -}); - -test("Type component (no kind)", async (t) => { - await assertValidation(t, { - "specVersion": "3.1", - "type": "component", - "metadata": { - "name": "my-component" - } - }); -}); - test("No type", async (t) => { await assertValidation(t, { "specVersion": "2.0", @@ -192,7 +171,6 @@ test("Invalid type", async (t) => { params: { allowedValues: [ "application", - "component", "library", "theme-library", "module", diff --git a/test/lib/validation/schema/specVersion/kind/project/component.js b/test/lib/validation/schema/specVersion/kind/project/component.js deleted file mode 100644 index 3e8e604db..000000000 --- a/test/lib/validation/schema/specVersion/kind/project/component.js +++ /dev/null @@ -1,968 +0,0 @@ -import test from "ava"; -import Ajv from "ajv"; -import ajvErrors from "ajv-errors"; -import SpecificationVersion from "../../../../../../../lib/specifications/SpecificationVersion.js"; -import AjvCoverage from "../../../../../../utils/AjvCoverage.js"; -import {_Validator as Validator} from "../../../../../../../lib/validation/validator.js"; -import ValidationError from "../../../../../../../lib/validation/ValidationError.js"; -import project from "../../../__helper__/project.js"; - -async function assertValidation(t, config, expectedErrors = undefined) { - const validation = t.context.validator.validate({config, project: {id: "my-project"}}); - if (expectedErrors) { - const validationError = await t.throwsAsync(validation, { - instanceOf: ValidationError, - name: "ValidationError" - }); - 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 { - await t.notThrowsAsync(validation); - } -} - -test.before((t) => { - t.context.validator = new Validator({Ajv, ajvErrors, schemaName: "ui5"}); - t.context.ajvCoverage = new AjvCoverage(t.context.validator.ajv, { - includes: ["schema/specVersion/kind/project/component.json"] - }); -}); - -test.after.always((t) => { - t.context.ajvCoverage.createReport("html", {dir: "coverage/ajv-project-component"}); - const thresholds = { - statements: 80, - branches: 75, - functions: 100, - lines: 80 - }; - t.context.ajvCoverage.verify(thresholds); -}); - -SpecificationVersion.getVersionsForRange(">=3.1").forEach(function(specVersion) { - test(`Valid configuration (specVersion ${specVersion})`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "kind": "project", - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "okay" - }, - "resources": { - "configuration": { - "propertiesFileSourceEncoding": "UTF-8", - "paths": { - "src": "/my/path" - } - } - }, - "builder": { - "resources": { - "excludes": [ - "/resources/some/project/name/test_results/**", - "/test-resources/**", - "!/test-resources/some/project/name/demo-app/**" - ] - }, - "bundles": [ - { - "bundleDefinition": { - "name": "sap-ui-custom.js", - "defaultFileTypes": [ - ".js" - ], - "sections": [ - { - "name": "my-raw-section", - "mode": "raw", - "filters": [ - "ui5loader-autoconfig.js" - ], - "resolve": true, - "resolveConditional": true, - "renderer": true, - "sort": true - }, - { - "mode": "provided", - "filters": [ - "ui5loader-autoconfig.js" - ], - "resolve": false, - "resolveConditional": false, - "renderer": false, - "sort": false, - "declareRawModules": true - } - ] - }, - "bundleOptions": { - "optimize": true, - "decorateBootstrapModule": true, - "addTryCatchRestartWrapper": true, - "usePredefineCalls": true - } - }, - { - "bundleDefinition": { - "name": "app.js", - "defaultFileTypes": [ - ".js" - ], - "sections": [ - { - "name": "some-app-preload", - "mode": "preload", - "filters": [ - "some/app/Component.js" - ], - "resolve": true, - "sort": true, - "declareRawModules": false - }, - { - "mode": "require", - "filters": [ - "ui5loader-autoconfig.js" - ], - "resolve": true - } - ] - }, - "bundleOptions": { - "optimize": true, - "numberOfParts": 3 - } - } - ], - "componentPreload": { - "paths": [ - "some/glob/**/pattern/Component.js", - "some/other/glob/**/pattern/Component.js" - ], - "namespaces": [ - "some/namespace", - "some/other/namespace" - ] - }, - "cachebuster": { - "signatureType": "hash" - }, - "customTasks": [ - { - "name": "custom-task-1", - "beforeTask": "replaceCopyright", - "configuration": { - "some-key": "some value" - } - }, - { - "name": "custom-task-2", - "afterTask": "custom-task-1", - "configuration": { - "color": "blue" - } - }, - { - "name": "custom-task-2", - "beforeTask": "not-valid", - "configuration": false - } - ] - }, - "server": { - "settings": { - "httpPort": 1337, - "httpsPort": 1443 - }, - "customMiddleware": [ - { - "name": "myCustomMiddleware", - "mountPath": "/myapp", - "afterMiddleware": "compression", - "configuration": { - "debug": true - } - }, - { - "name": "myCustomMiddleware-2", - "beforeMiddleware": "myCustomMiddleware", - "configuration": { - "debug": true - } - } - ] - } - }); - }); - - test(`Invalid resources configuration (specVersion ${specVersion})`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test" - }, - "resources": { - "configuration": { - "propertiesFileSourceEncoding": "FOO", - "paths": { - "app": "src", - "src": { - "path": "invalid" - } - }, - "notAllowed": true - }, - "notAllowed": true - } - }, [ - { - dataPath: "/resources", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "notAllowed", - } - }, - { - dataPath: "/resources/configuration", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "notAllowed", - } - }, - { - dataPath: "/resources/configuration/propertiesFileSourceEncoding", - keyword: "enum", - message: "should be equal to one of the allowed values", - params: { - allowedValues: [ - "UTF-8", - "ISO-8859-1" - ], - } - }, - { - dataPath: "/resources/configuration/paths", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "app", - } - }, - { - dataPath: "/resources/configuration/paths/src", - keyword: "type", - message: "should be string", - params: { - type: "string" - } - } - ]); - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test" - }, - "resources": { - "configuration": { - "paths": "src" - } - } - }, [ - { - dataPath: "/resources/configuration/paths", - keyword: "type", - message: "should be object", - params: { - type: "object" - } - } - ]); - }); - - test(`Invalid builder configuration (specVersion ${specVersion})`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - // jsdoc is not supported for type component - "jsdoc": { - "excludes": [ - "some/project/name/thirdparty/**" - ] - }, - "bundles": [ - { - "bundleDefinition": { - "name": "sap-ui-custom.js", - "defaultFileTypes": [ - ".js" - ], - "sections": [ - { - "name": true, - "mode": "raw", - "filters": [ - "ui5loader-autoconfig.js" - ], - "resolve": true, - "sort": true, - "declareModules": true - } - ] - }, - "bundleOptions": { - "optimize": true - } - }, - { - "bundleDefinition": { - "defaultFileTypes": [ - ".js", true - ], - "sections": [ - { - "filters": [ - "some/app/Component.js" - ], - "resolve": true, - "sort": true, - "declareRawModules": [] - }, - { - "mode": "provide", - "filters": "*", - "resolve": true - } - ] - }, - "bundleOptions": { - "optimize": "true", - "numberOfParts": "3", - "notAllowed": true - } - } - ], - "componentPreload": { - "path": "some/invalid/path", - "paths": "some/invalid/glob/**/pattern/Component.js", - "namespaces": "some/invalid/namespace", - }, - "libraryPreload": {} // Only supported for type library - } - }, [ - { - dataPath: "/builder", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "jsdoc" - } - }, - { - dataPath: "/builder", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "libraryPreload" - } - }, - { - dataPath: "/builder/bundles/0/bundleDefinition/sections/0", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "declareModules", - } - }, - { - dataPath: "/builder/bundles/0/bundleDefinition/sections/0/name", - keyword: "type", - message: "should be string", - params: { - type: "string", - } - }, - { - dataPath: "/builder/bundles/1/bundleDefinition", - keyword: "required", - message: "should have required property 'name'", - params: { - missingProperty: "name", - } - }, - { - dataPath: "/builder/bundles/1/bundleDefinition/defaultFileTypes/1", - keyword: "type", - message: "should be string", - params: { - type: "string", - } - }, - { - dataPath: "/builder/bundles/1/bundleDefinition/sections/0", - keyword: "required", - message: "should have required property 'mode'", - params: { - missingProperty: "mode", - } - }, - { - dataPath: "/builder/bundles/1/bundleDefinition/sections/0/declareRawModules", - keyword: "type", - message: "should be boolean", - params: { - type: "boolean", - } - }, - { - dataPath: "/builder/bundles/1/bundleDefinition/sections/1/mode", - keyword: "enum", - message: "should be equal to one of the allowed values", - params: { - allowedValues: ["3.1"].includes(specVersion) ? [ - "raw", - "preload", - "require", - "provided", - "bundleInfo" - ] : [ - "raw", - "preload", - "require", - "provided" - ] - } - }, - { - dataPath: "/builder/bundles/1/bundleDefinition/sections/1/filters", - keyword: "type", - message: "should be array", - params: { - type: "array", - } - }, - { - dataPath: "/builder/bundles/1/bundleOptions", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "notAllowed", - } - }, - { - dataPath: "/builder/bundles/1/bundleOptions/optimize", - keyword: "type", - message: "should be boolean", - params: { - type: "boolean", - } - }, - { - dataPath: "/builder/bundles/1/bundleOptions/numberOfParts", - keyword: "type", - message: "should be number", - params: { - type: "number", - } - }, - { - dataPath: "/builder/componentPreload", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "path", - } - }, - { - dataPath: "/builder/componentPreload/paths", - keyword: "type", - message: "should be array", - params: { - type: "array", - } - }, - { - dataPath: "/builder/componentPreload/namespaces", - keyword: "type", - message: "should be array", - params: { - type: "array", - } - } - ]); - }); - test(`component (specVersion ${specVersion}): builder/componentPreload/excludes`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "kind": "project", - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "componentPreload": { - "excludes": [ - "some/excluded/files/**", - "some/other/excluded/files/**" - ] - } - } - }); - }); - test(`Invalid builder/componentPreload/excludes configuration (specVersion ${specVersion})`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "componentPreload": { - "excludes": "some/excluded/files/**" - } - } - }, [ - { - dataPath: "/builder/componentPreload/excludes", - keyword: "type", - message: "should be array", - params: { - type: "array", - }, - }, - ]); - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "componentPreload": { - "excludes": [ - true, - 1, - {} - ], - "notAllowed": true - } - } - }, [ - { - dataPath: "/builder/componentPreload", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "notAllowed", - }, - }, - { - dataPath: "/builder/componentPreload/excludes/0", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/componentPreload/excludes/1", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/componentPreload/excludes/2", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - ]); - }); - test(`component (specVersion ${specVersion}): builder/bundles/bundleDefinition/sections/mode: bundleInfo`, - async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "kind": "project", - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "bundles": [{ - "bundleDefinition": { - "name": "my-bundle.js", - "sections": [{ - "name": "my-bundle-info", - "mode": "bundleInfo", - "filters": [] - }] - } - }] - } - }); - }); - test(`component (specVersion ${specVersion}): builder/settings/includeDependency*`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "kind": "project", - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "settings": { - "includeDependency": [ - "sap.a", - "sap.b" - ], - "includeDependencyRegExp": [ - ".ui.[a-z]+", - "^sap.[mf]$" - ], - "includeDependencyTree": [ - "sap.c", - "sap.d" - ] - } - } - }); - }); - test(`Invalid builder/settings/includeDependency* configuration (specVersion ${specVersion})`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "settings": { - "includeDependency": "a", - "includeDependencyRegExp": "b", - "includeDependencyTree": "c" - } - } - }, [ - { - dataPath: "/builder/settings/includeDependency", - keyword: "type", - message: "should be array", - params: { - type: "array", - }, - }, - { - dataPath: "/builder/settings/includeDependencyRegExp", - keyword: "type", - message: "should be array", - params: { - type: "array", - }, - }, - { - dataPath: "/builder/settings/includeDependencyTree", - keyword: "type", - message: "should be array", - params: { - type: "array", - }, - }, - ]); - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "settings": { - "includeDependency": [ - true, - 1, - {} - ], - "includeDependencyRegExp": [ - true, - 1, - {} - ], - "includeDependencyTree": [ - true, - 1, - {} - ], - "notAllowed": true - } - } - }, [ - { - dataPath: "/builder/settings", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "notAllowed", - }, - }, - { - dataPath: "/builder/settings/includeDependency/0", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependency/1", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependency/2", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependencyRegExp/0", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependencyRegExp/1", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependencyRegExp/2", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependencyTree/0", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependencyTree/1", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/settings/includeDependencyTree/2", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - ]); - }); - test(`component (specVersion ${specVersion}): builder/minification/excludes`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "kind": "project", - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "minification": { - "excludes": [ - "some/excluded/files/**", - "some/other/excluded/files/**" - ] - } - } - }); - }); - test(`Invalid builder/minification/excludes configuration (specVersion ${specVersion})`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "minification": { - "excludes": "some/excluded/files/**" - } - } - }, [ - { - dataPath: "/builder/minification/excludes", - keyword: "type", - message: "should be array", - params: { - type: "array", - }, - }, - ]); - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "metadata": { - "name": "com.sap.ui5.test", - "copyright": "yes" - }, - "builder": { - "minification": { - "excludes": [ - true, - 1, - {} - ], - "notAllowed": true - } - } - }, [ - { - dataPath: "/builder/minification", - keyword: "additionalProperties", - message: "should NOT have additional properties", - params: { - additionalProperty: "notAllowed", - }, - }, - { - dataPath: "/builder/minification/excludes/0", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/minification/excludes/1", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - { - dataPath: "/builder/minification/excludes/2", - keyword: "type", - message: "should be string", - params: { - type: "string", - }, - }, - ]); - }); - test(`Invalid project name (specVersion ${specVersion})`, async (t) => { - await assertValidation(t, { - "specVersion": specVersion, - "type": "component", - "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": "component", - "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": "component", - "metadata": { - "name": "a".repeat(81) - } - }, [{ - 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 80 characters", - params: { - limit: 80, - }, - }] - }, - }]); - }); -}); - -project.defineTests(test, assertValidation, "component"); diff --git a/test/lib/validation/schema/ui5.js b/test/lib/validation/schema/ui5.js index 19d83cf2c..8cc1c77d7 100644 --- a/test/lib/validation/schema/ui5.js +++ b/test/lib/validation/schema/ui5.js @@ -145,7 +145,6 @@ test("Invalid type", async (t) => { params: { allowedValues: [ "application", - "component", "library", "theme-library", "module" From 20b6781114d8fb553be76be9ec272d59aca2d4b0 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Thu, 10 Aug 2023 11:32:29 +0200 Subject: [PATCH 4/5] [FEATURE] Schema: Allow builder.resources.exclude config for modules --- .../specVersion/kind/project/module.json | 91 ++++++++++++++----- .../schema/specVersion/kind/project/module.js | 21 +++++ 2 files changed, 90 insertions(+), 22 deletions(-) diff --git a/lib/validation/schema/specVersion/kind/project/module.json b/lib/validation/schema/specVersion/kind/project/module.json index 586a6adf1..e6fe250b8 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": ["3.0", "3.1"] } + "specVersion": { "enum": ["3.1"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["3.0", "3.1"] }, + "specVersion": { "enum": ["3.1"] }, "kind": { "enum": ["project", null] }, @@ -26,7 +26,7 @@ "$ref": "#/definitions/resources" }, "builder": { - "$ref": "#/definitions/builder-specVersion-2.5" + "$ref": "#/definitions/builder-specVersion-3.1" }, "server": { "$ref": "../project.json#/definitions/server" @@ -40,13 +40,13 @@ "else": { "if": { "properties": { - "specVersion": { "enum": ["2.5", "2.6"] } + "specVersion": { "enum": ["3.0"] } } }, "then": { "additionalProperties": false, "properties": { - "specVersion": { "enum": ["2.5", "2.6"] }, + "specVersion": { "enum": ["3.0"] }, "kind": { "enum": ["project", null] }, @@ -54,7 +54,7 @@ "enum": ["module"] }, "metadata": { - "$ref": "../project.json#/definitions/metadata" + "$ref": "../project.json#/definitions/metadata-3.0" }, "resources": { "$ref": "#/definitions/resources" @@ -74,13 +74,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] }, @@ -93,6 +93,12 @@ "resources": { "$ref": "#/definitions/resources" }, + "builder": { + "$ref": "#/definitions/builder-specVersion-2.5" + }, + "server": { + "$ref": "../project.json#/definitions/server" + }, "customConfiguration": { "type": "object", "additionalProperties": true @@ -100,20 +106,49 @@ } }, "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" + } } } } @@ -149,6 +184,18 @@ "$ref": "../project.json#/definitions/builder-settings" } } + }, + "builder-specVersion-3.1": { + "type": "object", + "additionalProperties": false, + "properties": { + "resources": { + "$ref": "../project.json#/definitions/builder-resources" + }, + "settings": { + "$ref": "../project.json#/definitions/builder-settings" + } + } } } } diff --git a/test/lib/validation/schema/specVersion/kind/project/module.js b/test/lib/validation/schema/specVersion/kind/project/module.js index f92e8e24c..e49b4769c 100644 --- a/test/lib/validation/schema/specVersion/kind/project/module.js +++ b/test/lib/validation/schema/specVersion/kind/project/module.js @@ -418,4 +418,25 @@ SpecificationVersion.getVersionsForRange(">=3.0").forEach(function(specVersion) }); }); +SpecificationVersion.getVersionsForRange(">=3.1").forEach(function(specVersion) { + test(`Builder resource excludes (specVersion ${specVersion})`, async (t) => { + await assertValidation(t, { + "specVersion": specVersion, + "kind": "project", + "type": "module", + "metadata": { + "name": "my-module" + }, + "builder": { + "resources": { + "excludes": [ + "/resources/some/project/name/test_results/**", + "!/test-resources/some/project/name/demo-app/**" + ] + } + } + }); + }); +}); + project.defineTests(test, assertValidation, "module"); From 5711ce7892e27b02d6d46eb5c092782cea851b28 Mon Sep 17 00:00:00 2001 From: Merlin Beutlberger Date: Fri, 18 Aug 2023 09:32:10 +0200 Subject: [PATCH 5/5] [INTERNAL] Apply suggestions from code review Co-authored-by: Florian Vogt --- lib/specifications/SpecificationVersion.js | 2 +- lib/specifications/types/Library.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/specifications/SpecificationVersion.js b/lib/specifications/SpecificationVersion.js index 7bbac1eef..2634fe944 100644 --- a/lib/specifications/SpecificationVersion.js +++ b/lib/specifications/SpecificationVersion.js @@ -265,7 +265,7 @@ class SpecificationVersion { } /** - * Create an array of Specification Versions that match with the provided range. This is mainly used + * Creates an array of Specification Versions that match with the provided range. This is mainly used * for testing purposes. I.e. to execute identical tests for a range of specification versions. * * @public diff --git a/lib/specifications/types/Library.js b/lib/specifications/types/Library.js index abf7faf28..d3d2059a0 100644 --- a/lib/specifications/types/Library.js +++ b/lib/specifications/types/Library.js @@ -108,7 +108,7 @@ class Library extends ComponentProject { /** * Get a resource reader for the sources of the project (excluding any test resources) - * without a virtual base path + * without a virtual base path. * In the future the path structure can be flat or namespaced depending on the project * setup *