diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 341b6ee7..8141a73d 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -965,6 +965,11 @@ "mimic-response": "^1.0.0" } }, + "code-error-fragment": { + "version": "0.0.230", + "resolved": "https://registry.npmjs.org/code-error-fragment/-/code-error-fragment-0.0.230.tgz", + "integrity": "sha512-cadkfKp6932H8UkhzE/gcUqhRMNf8jHzkAN7+5Myabswaghu4xABTgPHDCjW+dBAJxj/SpkTYokpzDqY4pCzQw==" + }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -1553,6 +1558,11 @@ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==" }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==" + }, "growl": { "version": "1.10.5", "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", @@ -2110,6 +2120,15 @@ "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" }, + "json-to-ast": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/json-to-ast/-/json-to-ast-2.1.0.tgz", + "integrity": "sha512-W9Lq347r8tA1DfMvAGn9QNcgYm4Wm7Yc+k8e6vezpMnRT+NHbtlxgNBXRVjXe9YM6eTn6+p/MKOlV/aABJcSnQ==", + "requires": { + "code-error-fragment": "0.0.230", + "grapheme-splitter": "^1.0.4" + } + }, "json5": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz", diff --git a/package.json b/package.json index 6837be69..1241aa15 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "globals": "^12.4.0", "graceful-fs": "^4.2.3", "ignore": "^5.1.4", + "json-to-ast": "^2.1.0", "json5": "^2.1.3", "minimatch": "^3.0.4", "recast": "^0.18.10", diff --git a/src/cli.ts b/src/cli.ts index 9c3a6353..f8aa53e7 100644 --- a/src/cli.ts +++ b/src/cli.ts @@ -59,6 +59,7 @@ export async function start(): Promise { choices: [ "all", "replace-globals", + "add-i18n", "fix-jquery-plugin-imports", "apply-amd-syntax", "add-renderer-dependencies", diff --git a/src/tasks/addI18n.ts b/src/tasks/addI18n.ts new file mode 100644 index 00000000..ac98ea0b --- /dev/null +++ b/src/tasks/addI18n.ts @@ -0,0 +1,382 @@ +/* + * Will introduce the each control's renderer as dependency for the control + * + * # Find Module (with define call) + * # For each found module + * ## Check if there is a renderer (moduleName+"Renderer.js") available + * ## If so + * ### Add renderer dependency + */ + +import {Syntax} from "esprima"; +import * as FileUtils from "../util/FileUtils"; +import * as ESTree from "estree"; +import * as path from "path"; + +import * as Mod from "../Migration"; +import * as ASTUtils from "../util/ASTUtils"; +import {ASTVisitor} from "../util/ASTVisitor"; +import {SapUiDefineCall} from "../util/SapUiDefineCall"; +import {ModifyJSONContent} from "../util/content/ModifyJSONContent"; +import {hasHigherVersion} from "../util/ConfigUtils"; + + +interface AddI18nResult { + defineCall: SapUiDefineCall; + supportedLocalesModels?: string[]; + fallbackLocaleModels?: string; + supportedLocalesApp?: string[]; + fallbackLocaleApp?: string; + bundleUrlApp?: string; + manifestPath: string; + manifestContent: object; + manifestContentString: string; + manifestVersion: string; + createUI5ModelsSettings: boolean; +} + +async function getFiles(sI18nFolder, fileName) { + let supportedLocales: string[] = []; + const bI18nFolderExists = await FileUtils.exists(sI18nFolder); + if (bI18nFolderExists) { + const listI18n = await FileUtils.fsReadDir(sI18nFolder); + supportedLocales = supportedLocales.concat( + listI18n + .map(si18n => { + if (si18n.startsWith(fileName)) { + if (si18n.includes("_")) { + return si18n.substring( + fileName.length + "_".length, + si18n.lastIndexOf(".properties") + ); + } + return si18n.substring( + fileName.length, + si18n.lastIndexOf(".properties") + ); + } + return undefined; + }) + .filter(locale => locale !== undefined) + ); + } + const fallbackLocale: string = supportedLocales.includes("en") + ? "en" + : supportedLocales[0]; + return { + supportedLocalesModels: supportedLocales, + fallbackLocaleModels: fallbackLocale, + }; +} + +async function analyse( + args: Mod.AnalyseArguments +): Promise { + const moduleName = args.file.getFileName(); + let astDefineCall: ESTree.CallExpression; + + const defineCalls = ASTUtils.findCalls( + args.file.getAST(), + SapUiDefineCall.isValidRootPath, + args.visitor as ASTVisitor + ); + if (defineCalls.length > 1) { + args.reporter.report( + Mod.ReportLevel.WARNING, + "can't handle files with multiple modules" + ); + return undefined; + } else if (defineCalls.length === 1) { + astDefineCall = defineCalls[0].value; + } else { + args.reporter.report( + Mod.ReportLevel.WARNING, + "could not find sap.ui.define call" + ); + return undefined; + } + + const defineCall = new SapUiDefineCall( + astDefineCall, + moduleName, + args.reporter + ); + + if (!defineCall.factory) { + args.reporter.report( + Mod.ReportLevel.WARNING, + "Invalid sap.ui.define call without factory" + ); + return undefined; + } + + const sImportName = defineCall.getParamNameByImport( + "sap/ui/core/UIComponent" + ); + + const validComponentName = moduleName.endsWith("/Component"); + + const isCandidate = object => { + return object.name === sImportName || validComponentName; + }; + + const isReturnStatement = (stmt: ESTree.ReturnStatement): boolean => { + if (stmt.argument.type === Syntax.CallExpression) { + if (stmt.argument.callee.type === Syntax.MemberExpression) { + if ( + stmt.argument.callee.object.type === Syntax.Identifier && + stmt.argument.callee.property.type === Syntax.Identifier + ) { + if ( + isCandidate(stmt.argument.callee.object) && + stmt.argument.callee.property.name === "extend" + ) { + return true; + } + } + } + } + return false; + }; + + const bAddI18n = true; + let nameSpace = ""; + defineCall.factory.body.body.forEach(stmt => { + if (stmt.type === Syntax.VariableDeclaration) { + stmt.declarations.forEach(decl => { + if ( + decl.id.type === Syntax.Identifier && + decl.init && + decl.init.type === Syntax.CallExpression && + decl.init.callee.type === Syntax.MemberExpression && + decl.init.callee.property.type === Syntax.Identifier && + decl.init.callee.object.type === Syntax.Identifier && + decl.init.callee.property.name === "extend" && + isCandidate(decl.init.callee.object) + ) { + if (decl.init.arguments[0].type === Syntax.Literal) { + nameSpace = decl.init.arguments[0].value.toString(); + nameSpace = nameSpace.substring( + 0, + nameSpace.lastIndexOf(".Component") + ); + } + } + }); + } else if ( + stmt.type === Syntax.ReturnStatement && + stmt.argument.type === Syntax.CallExpression + ) { + if ( + isReturnStatement(stmt) && + stmt.argument.arguments[0].type === Syntax.Literal + ) { + nameSpace = stmt.argument.arguments[0].value.toString(); + nameSpace = nameSpace.substring( + 0, + nameSpace.lastIndexOf(".Component") + ); + } + } + }); + + const aFilePath2 = args.file.getFileName().split("/"); + aFilePath2.pop(); + const sFilePath = aFilePath2.join("/"); + + const manifestPath = path.join(sFilePath, "manifest.json"); + // check if manifest.json exists + const bManifestExists = await FileUtils.exists(manifestPath); + let sI18nModelsFolder; + let sI18nAppFolder; + let manifestContent; + let manifestContentString; + let i18nAppValue; + let createUI5ModelsSettings = false; + if (bManifestExists) { + manifestContentString = await FileUtils.fsReadFile( + manifestPath, + "UTF-8" + ); + manifestContent = JSON.parse(manifestContentString); + + i18nAppValue = getObject(manifestContent, ["sap.app", "i18n"]); + if (i18nAppValue && typeof i18nAppValue === "string") { + sI18nAppFolder = i18nAppValue; + } + + // models section + const i18nModelsConfig = getObject(manifestContent, [ + "sap.ui5", + "models", + "i18n", + ]); + if ( + i18nModelsConfig && + i18nModelsConfig.type === "sap.ui.model.resource.ResourceModel" + ) { + if (i18nModelsConfig.settings) { + const bundleName = i18nModelsConfig.settings.bundleName; // "sap.f.cardsVisualTests.i18n.i18n" + if ( + bundleName.startsWith(nameSpace) && + !i18nModelsConfig.settings.supportedLocales && + !i18nModelsConfig.settings.fallbackLocale + ) { + sI18nModelsFolder = bundleName.substring(nameSpace.length); + } + } else if (i18nModelsConfig.uri) { + createUI5ModelsSettings = true; + sI18nModelsFolder = i18nModelsConfig.uri; + } + } + } else { + return undefined; + } + + if (!sI18nModelsFolder && !sI18nAppFolder) { + return undefined; + } + + const oResultObject: AddI18nResult = { + defineCall, + manifestPath, + manifestContent, + manifestContentString, + manifestVersion: manifestContent._version, + createUI5ModelsSettings, + }; + + if (sI18nModelsFolder) { + let fileName; + if (sI18nModelsFolder.endsWith(".properties")) { + sI18nModelsFolder = sI18nModelsFolder.substring( + 0, + sI18nModelsFolder.lastIndexOf(".properties") + ); + const split = sI18nModelsFolder.split("/"); + fileName = split.pop(); + sI18nModelsFolder = path.join(sFilePath, split.join("/")); + } else { + // sI18nFolder = i18n.i18n + const split = sI18nModelsFolder.split("."); + fileName = split.pop(); + sI18nModelsFolder = path.join(sFilePath, split.join("/")); + } + + const {supportedLocalesModels, fallbackLocaleModels} = await getFiles( + sI18nModelsFolder, + fileName + ); + oResultObject.supportedLocalesModels = supportedLocalesModels; + oResultObject.fallbackLocaleModels = fallbackLocaleModels; + } + + if (sI18nAppFolder) { + // sI18nFolder = i18n/i18n.properties + sI18nAppFolder = sI18nAppFolder.substring( + 0, + sI18nAppFolder.lastIndexOf(".properties") + ); + const split = sI18nAppFolder.split("/"); + const fileName = split.pop(); + + sI18nAppFolder = path.join(sFilePath, split.join("/")); + + const {supportedLocalesModels, fallbackLocaleModels} = await getFiles( + sI18nAppFolder, + fileName + ); + oResultObject.supportedLocalesApp = supportedLocalesModels; + oResultObject.fallbackLocaleApp = fallbackLocaleModels; + oResultObject.bundleUrlApp = i18nAppValue; + } + + if ( + bAddI18n && + manifestContent && + ((oResultObject.supportedLocalesModels && + oResultObject.supportedLocalesModels.length > 0) || + (oResultObject.supportedLocalesApp && + oResultObject.supportedLocalesApp.length > 0)) + ) { + args.reporter.collect("addI18n", 1); + args.reporter.storeFinding("Add i18n", defineCall.node.callee.loc); + return oResultObject; + } else { + return undefined; + } +} + +function getObject(oObject, aNames) { + aNames.forEach(sName => { + if (oObject && oObject[sName] !== undefined) { + oObject = oObject[sName]; + } else { + oObject = undefined; + } + }); + return oObject; +} + +async function migrate(args: Mod.MigrateArguments): Promise { + const result = args.analyseResult as AddI18nResult; + + const manifestContentString = result.manifestContentString; + + const manifestContent = ModifyJSONContent.create(manifestContentString); + if ( + result.supportedLocalesModels && + result.supportedLocalesModels.length > 0 + ) { + if (result.createUI5ModelsSettings) { + const aPath = ["sap.ui5", "models", "i18n"]; + manifestContent.add(aPath, { + settings: {}, + }); + manifestContent.replace(["sap.ui5", "models", "i18n", "settings"], { + supportedLocales: result.supportedLocalesModels, + fallbackLocale: result.fallbackLocaleModels, + }); + } else { + manifestContent.add(["sap.ui5", "models", "i18n", "settings"], { + supportedLocales: result.supportedLocalesModels, + fallbackLocale: result.fallbackLocaleModels, + }); + } + } + if (result.supportedLocalesApp && result.supportedLocalesApp.length > 0) { + manifestContent.replace(["sap.app", "i18n"], { + bundleUrl: result.bundleUrlApp, + supportedLocales: result.supportedLocalesApp, + fallbackLocale: result.fallbackLocaleApp, + }); + } + if (result.manifestVersion) { + if (!hasHigherVersion(result.manifestVersion, "1.21.0")) { + manifestContent.replace(["_version"], "1.21.0"); + } + } + + await FileUtils.fsWriteFile( + result.manifestPath, + manifestContent.getContent(), + "UTF-8" + ); + + return false; +} + +/* + * Exports + */ +const migration: Mod.Task = { + description: "Add i18n", + keywords: ["all", "add-i18n"], + priority: 5, + defaultConfig() { + return Promise.resolve({}); + }, + analyse, + migrate, +}; +export = migration; diff --git a/src/util/content/ModifyJSONContent.ts b/src/util/content/ModifyJSONContent.ts new file mode 100644 index 00000000..5e1c9882 --- /dev/null +++ b/src/util/content/ModifyJSONContent.ts @@ -0,0 +1,258 @@ +// input string +// object to modify + +// find node in string and position +// https://github.com/vtrushin/json-to-ast + +const parse = require("json-to-ast"); + +import {AnalyzeCharacter, CodeStyleAnalyzer} from "../CodeStyleAnalyzer"; +import * as StringWhitespaceUtils from "../whitespace/StringWhitespaceUtils"; + +interface Location { + start: Position; + end: Position; +} + +interface Position { + line: number; + column: number; + offset: number; +} + +export class ModifyJSONContent { + private content: string; + private modifiedContent: string; + private settings: {loc: boolean}; + private oContent; + private contentLines: string[]; + private eol: string; + private indent: string; + + constructor(content) { + this.content = content; + this.init(content); + } + + private init(content) { + this.eol = this.calculateEOL(content); + this.indent = this.calculateIndent(content); + this.contentLines = content.split(this.eol); + this.modifiedContent = content; + this.settings = { + // Appends location information. Default is + loc: true, + }; + this.oContent = this.parse(content); + } + + private calculateEOL(content) { + return new CodeStyleAnalyzer(content).getMostCommon( + AnalyzeCharacter.NEWLINE + ) === "N" + ? "\n" + : "\r\n"; + } + + private calculateIndent(content) { + const indent = new CodeStyleAnalyzer(content).getMostCommon( + AnalyzeCharacter.INDENT + ); + if (indent === true) { + return "\t"; + } + if (typeof indent === "number") { + return " ".repeat(indent); + } + return "\t"; // default + } + + private parse(content) { + return parse(content, this.settings); + } + + /** + * + * @param {string[]} aPath list of strings + * @returns {Object} position + */ + find(aPath: string[]) { + let resultElement = this.oContent; + let found = true; + aPath.forEach(path => { + if (found) { + const tempResult = this.findChild(resultElement, path); + if (tempResult === undefined) { + found = false; + } + resultElement = tempResult; + } + }); + if (found) { + return resultElement; + } + return undefined; + } + + private getInsertPosition(element): Position { + if (element.children) { + return element.children[element.children.length - 1].loc.end; + } + return element.loc.start; + } + + private findChild(currentObject, elementName: string) { + let resultChild; + currentObject.children.forEach(child => { + if (child.key.value === elementName) { + resultChild = child.value; + } + }); + return resultChild; + } + + /** + * Replaces a given element at path x + * @param {string[]} aPath + * @param {Object} oContent + */ + replace(aPath: string[], oContent) { + const contentLinesBackup = this.contentLines.slice(); + const oElement = this.find(aPath); + + const startLine = (oElement.loc as Location).start.line - 1; + const endLine = (oElement.loc as Location).end.line - 1; + + const lastElement = aPath.slice().pop(); + + const nextLine = this.contentLines[startLine + 1]; + const currentLine = this.contentLines[startLine]; + let commaRequired = true; + if (nextLine.trim().startsWith("}")) { + commaRequired = false; + } + const targetIndent = this.getIndent(currentLine); + if (startLine === endLine) { + this.contentLines.splice(startLine, 1); + } else { + for (let i = startLine; i < endLine; i++) { + this.contentLines.splice(i, 1); + } + } + + let lineToStart = targetIndent + '"' + lastElement + '": '; + + if (typeof oContent === "object") { + lineToStart += "{"; + + this.contentLines.splice(startLine, 0, lineToStart); + + const insertLine = startLine + 1; + // new content + const newString = this.extractContent(oContent); + + const aNewLines = newString.split("\n").filter(Boolean); + + // insert + let lastPos = insertLine; + aNewLines.forEach(newLine => { + this.contentLines.splice(lastPos++, 0, targetIndent + newLine); + }); + + const lineToEnd = targetIndent + "}" + (commaRequired ? "," : ""); + + this.contentLines.splice(lastPos, 0, lineToEnd); + } else { + const newString = this.extractContent(oContent); + + lineToStart += newString; + lineToStart += commaRequired ? "," : ""; + this.contentLines.splice(startLine, 0, lineToStart); + } + + // update content + try { + // verify content + JSON.stringify(this.getContent()); + this.update(); + } catch (e) { + this.contentLines = contentLinesBackup; + throw e; + } + } + + private extractContent(oContent) { + let newString = JSON.stringify(oContent, null, this.indent); + if (newString.startsWith("{") && newString.endsWith("}")) { + newString = newString.substring(1, newString.length - 1); + } + return newString; + } + + add(aPath, oContent) { + const contentLinesBackup = this.contentLines.slice(); + const oElement = this.find(aPath); + const insertPosition = this.getInsertPosition(oElement) as Position; + const previousLine = this.contentLines[insertPosition.line - 1]; + const targetIndent = this.getIndent(previousLine); + + // new content + const newString = this.extractContent(oContent); + + const aNewLines = newString.split("\n").filter(Boolean); + const newCodeIndent = this.getIndent(aNewLines[0]); + + // insert + let lastPos = insertPosition.line; + aNewLines.forEach(newLine => { + this.contentLines.splice( + lastPos++, + 0, + targetIndent + newLine.substring(newCodeIndent.length) + ); + }); + + // restore comma + if (oElement.children && oElement.children.length > 0) { + this.contentLines[insertPosition.line - 1] = + this.contentLines[insertPosition.line - 1] + ","; + } + // update content + try { + // verify content + JSON.stringify(this.getContent()); + this.update(); + } catch (e) { + this.contentLines = contentLinesBackup; + throw e; + } + } + + private update() { + this.init(this.getContent()); + } + + getContent() { + return this.contentLines.join(this.eol); + } + + static create(content) { + return new ModifyJSONContent(content); + } + + private getIndent(previousLine: string) { + const aChars = previousLine.split(""); + let result = ""; + let valid = true; + aChars.forEach(char => { + if (valid) { + if (StringWhitespaceUtils.isWhitespace(char)) { + result += char; + } else { + valid = false; + } + } + }); + return result; + } +} diff --git a/test/addI18n/project/Component.js b/test/addI18n/project/Component.js new file mode 100644 index 00000000..447d814d --- /dev/null +++ b/test/addI18n/project/Component.js @@ -0,0 +1,16 @@ +sap.ui.define([ + "sap/ui/core/UIComponent" +], function (UIComponent) { + "use strict"; + + return UIComponent.extend("supi.theTests.Component", { + metadata : { + manifest: "json" + }, + init: function () { + // call the init function of the parent + UIComponent.prototype.init.apply(this, arguments); + } + }); + +}); diff --git a/test/addI18n/project/i18n/i18n.properties b/test/addI18n/project/i18n/i18n.properties new file mode 100644 index 00000000..cf429b98 --- /dev/null +++ b/test/addI18n/project/i18n/i18n.properties @@ -0,0 +1,8 @@ +# App Descriptor +appTitle=Card Playground +appDescription=A playground for cards with different layout / content scenarios + +# Not found +NotFound=Not Found +NotFound.text=Sorry, but the requested resource is not available. +NotFound.description=Please check the URL and try again. \ No newline at end of file diff --git a/test/addI18n/project/manifest.expected.json b/test/addI18n/project/manifest.expected.json new file mode 100644 index 00000000..eccfc501 --- /dev/null +++ b/test/addI18n/project/manifest.expected.json @@ -0,0 +1,65 @@ +{ + "_version": "1.21.0", + "sap.app": { + "id": "supi.theTests", + "type": "application", + "i18n": { + "bundleUrl": "i18n/i18n.properties", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui": { + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "dependencies": { + "minUI5Version": "1.30.0", + "libs": { + "sap.ui.core": {}, + "sap.m": {}, + "sap.ui.integration": { + "lazy": true + }, + "sap.f": {}, + "sap.ui.layout": { + "lazy": true + }, + "sap.ui.codeeditor": { + "lazy": true + } + } + }, + "rootView": { + "viewName": "supi.theTests.view.App", + "type": "XML", + "async": true, + "id": "app" + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "supi.theTests.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + }, + "preload": true + } + } + } +} \ No newline at end of file diff --git a/test/addI18n/project/manifest.json b/test/addI18n/project/manifest.json new file mode 100644 index 00000000..2a91a80c --- /dev/null +++ b/test/addI18n/project/manifest.json @@ -0,0 +1,55 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "supi.theTests", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui": { + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "dependencies": { + "minUI5Version": "1.30.0", + "libs": { + "sap.ui.core": {}, + "sap.m": {}, + "sap.ui.integration": { + "lazy": true + }, + "sap.f": {}, + "sap.ui.layout": { + "lazy": true + }, + "sap.ui.codeeditor": { + "lazy": true + } + } + }, + "rootView": { + "viewName": "supi.theTests.view.App", + "type": "XML", + "async": true, + "id": "app" + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "supi.theTests.i18n.i18n" + }, + "preload": true + } + } + } +} \ No newline at end of file diff --git a/test/addI18n/project2/Component.js b/test/addI18n/project2/Component.js new file mode 100644 index 00000000..be7ae1fe --- /dev/null +++ b/test/addI18n/project2/Component.js @@ -0,0 +1,17 @@ +sap.ui.define([ + "sap/ui/core/UIComponent" +], function (UIComponent) { + "use strict"; + + return UIComponent.extend("supi.sample.basicSinglePanel.Component", { + + metadata: { + manifest: "json" + }, + + init: function () { + // call the init function of the parent + UIComponent.prototype.init.apply(this, arguments); + } + }); +}); \ No newline at end of file diff --git a/test/addI18n/project2/i18n/i18n.properties b/test/addI18n/project2/i18n/i18n.properties new file mode 100644 index 00000000..8f78d38c --- /dev/null +++ b/test/addI18n/project2/i18n/i18n.properties @@ -0,0 +1,12 @@ +# App Descriptor +appTitle=App title +appDescription=This is a description coming from the i18n as specified in manifest.json + +# Page Descriptor +pageTitle=Single Panel + +# Form Descriptor +panelTitle=A Panel +treeHeaderButton=Tree Button +viewportHeaderButton=Viewport Button + diff --git a/test/addI18n/project2/i18n/i18n_en.properties b/test/addI18n/project2/i18n/i18n_en.properties new file mode 100644 index 00000000..8f78d38c --- /dev/null +++ b/test/addI18n/project2/i18n/i18n_en.properties @@ -0,0 +1,12 @@ +# App Descriptor +appTitle=App title +appDescription=This is a description coming from the i18n as specified in manifest.json + +# Page Descriptor +pageTitle=Single Panel + +# Form Descriptor +panelTitle=A Panel +treeHeaderButton=Tree Button +viewportHeaderButton=Viewport Button + diff --git a/test/addI18n/project2/manifest.expected.json b/test/addI18n/project2/manifest.expected.json new file mode 100644 index 00000000..436a67be --- /dev/null +++ b/test/addI18n/project2/manifest.expected.json @@ -0,0 +1,59 @@ +{ + "_version": "1.21.0", + "sap.app": { + "_version": "1.1.0", + "id": "supi.sample.basicSinglePanel", + "type": "application", + "i18n": { + "bundleUrl": "i18n/i18n.properties", + "supportedLocales": [ + "", + "en" + ], + "fallbackLocale": "en" + }, + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui": { + "_version": "1.1.0", + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": false, + "phone": false + }, + "supportedThemes": [ + "sap_bluecrystal" + ] + }, + "sap.ui5": { + "_version": "1.1.0", + "rootView": { + "viewName": "supi.sample.basicSinglePanel.view.App", + + "type": "XML", + "async": true, + "id": "app" + }, + "dependencies": { + "minUI5Version": "1.60", + "libs": { + "sap.m": {}, + "sap.ui.vk":{} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "basicSinglePanel.i18n.i18n" + } + } + } + } + +} diff --git a/test/addI18n/project2/manifest.json b/test/addI18n/project2/manifest.json new file mode 100644 index 00000000..e3ec09cb --- /dev/null +++ b/test/addI18n/project2/manifest.json @@ -0,0 +1,52 @@ +{ + "_version": "1.1.0", + "sap.app": { + "_version": "1.1.0", + "id": "supi.sample.basicSinglePanel", + "type": "application", + "i18n": "i18n/i18n.properties", + "title": "{{appTitle}}", + "description": "{{appDescription}}", + "applicationVersion": { + "version": "1.0.0" + } + }, + "sap.ui": { + "_version": "1.1.0", + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": false, + "phone": false + }, + "supportedThemes": [ + "sap_bluecrystal" + ] + }, + "sap.ui5": { + "_version": "1.1.0", + "rootView": { + "viewName": "supi.sample.basicSinglePanel.view.App", + + "type": "XML", + "async": true, + "id": "app" + }, + "dependencies": { + "minUI5Version": "1.60", + "libs": { + "sap.m": {}, + "sap.ui.vk":{} + } + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "basicSinglePanel.i18n.i18n" + } + } + } + } + +} diff --git a/test/addI18n/project3/comp/Component.js b/test/addI18n/project3/comp/Component.js new file mode 100644 index 00000000..487b6eb2 --- /dev/null +++ b/test/addI18n/project3/comp/Component.js @@ -0,0 +1,26 @@ + +sap.ui.define('supi.testhelper.comp.Component', [ + 'supi/base/Component', + 'sap/m/App' +], function(BaseComponent, App) { + + BaseComponent.extend("supi.testhelper.comp.Component", { + metadata: { + "manifest" : "json" + }, + /** + * Initialize the application + * @returns {sap.ui.core.Control} the content + */ + init: function() { + BaseComponent.prototype.init.apply(this, arguments); + }, + /** + * Creates the application layout and returns the outer layout of APF + * @returns + */ + createContent: function() { + BaseComponent.prototype.init.apply(this, arguments); + } + }); +}); \ No newline at end of file diff --git a/test/addI18n/project3/comp/manifest.expected.json b/test/addI18n/project3/comp/manifest.expected.json new file mode 100644 index 00000000..bf65492b --- /dev/null +++ b/test/addI18n/project3/comp/manifest.expected.json @@ -0,0 +1,80 @@ +{ + "_version": "1.21.0", + "sap.app": { + "_version": "1.0.0", + "id": "supi.testhelper.comp", + "type": "component", + "i18n": { + "bundleUrl": "../i18n/applicationUi.properties", + "supportedLocales": [ + "", + "en", + "en_US" + ], + "fallbackLocale": "en" + }, + "title": "{{TestComponent}}", + "description": "Used for Testing", + "tags": { + "keywords": [] + }, + "applicationVersion": { + "version": "1" + }, + "offline": false + }, + "sap.ui5": { + "_version": "1.0.0", + + "resources": { + "js": [], + "css": [] + }, + "dependencies": { + "minUI5Version": "${sap.ui5.dist.version}", + "libs": { + "sap.ui.core": { + "minVersion": "1.30.0" + }, + "sap.suite.ui.commons": { + "minVersion": "1.30.0" + }, + "sap.m": { + "minVersion": "1.30.0" + }, + "sap.ui.layout": { + "minVersion": "1.30.0" + }, + "sap.ushell": { + "minVersion": "1.30.0" + }, + "sap.viz": { + "minVersion": "1.30.0" + } + } + }, + "extends": { + "component": "supi.base.Component", + "minVersion": "1.0.0", + "extensions": {} + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "../i18n/applicationUi.properties", + "settings": { + "supportedLocales": [ + "", + "en", + "en_US" + ], + "fallbackLocale": "en" + } + } + }, + "config": { + "fullWidth": true + } + } +} + diff --git a/test/addI18n/project3/comp/manifest.json b/test/addI18n/project3/comp/manifest.json new file mode 100644 index 00000000..fc0fcf82 --- /dev/null +++ b/test/addI18n/project3/comp/manifest.json @@ -0,0 +1,64 @@ +{ + "_version": "1.0.0", + "sap.app": { + "_version": "1.0.0", + "id": "supi.testhelper.comp", + "type": "component", + "i18n": "../i18n/applicationUi.properties", + "title": "{{TestComponent}}", + "description": "Used for Testing", + "tags": { + "keywords": [] + }, + "applicationVersion": { + "version": "1" + }, + "offline": false + }, + "sap.ui5": { + "_version": "1.0.0", + + "resources": { + "js": [], + "css": [] + }, + "dependencies": { + "minUI5Version": "${sap.ui5.dist.version}", + "libs": { + "sap.ui.core": { + "minVersion": "1.30.0" + }, + "sap.suite.ui.commons": { + "minVersion": "1.30.0" + }, + "sap.m": { + "minVersion": "1.30.0" + }, + "sap.ui.layout": { + "minVersion": "1.30.0" + }, + "sap.ushell": { + "minVersion": "1.30.0" + }, + "sap.viz": { + "minVersion": "1.30.0" + } + } + }, + "extends": { + "component": "supi.base.Component", + "minVersion": "1.0.0", + "extensions": {} + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "../i18n/applicationUi.properties" + } + }, + "config": { + "fullWidth": true + } + } +} + diff --git a/test/addI18n/project3/i18n/apfUi.properties b/test/addI18n/project3/i18n/apfUi.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/apfUi.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/apfUi_en.properties b/test/addI18n/project3/i18n/apfUi_en.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/apfUi_en.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/apfUi_en_US.properties b/test/addI18n/project3/i18n/apfUi_en_US.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/apfUi_en_US.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/applicationMessages.properties b/test/addI18n/project3/i18n/applicationMessages.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/applicationMessages.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/applicationMessages_en.properties b/test/addI18n/project3/i18n/applicationMessages_en.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/applicationMessages_en.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/applicationMessages_en_US.properties b/test/addI18n/project3/i18n/applicationMessages_en_US.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/applicationMessages_en_US.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/applicationUi.properties b/test/addI18n/project3/i18n/applicationUi.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/applicationUi.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/applicationUi_en.properties b/test/addI18n/project3/i18n/applicationUi_en.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/applicationUi_en.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/applicationUi_en_US.properties b/test/addI18n/project3/i18n/applicationUi_en_US.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/applicationUi_en_US.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/demokitTest.properties b/test/addI18n/project3/i18n/demokitTest.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/demokitTest.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/modelerUi.properties b/test/addI18n/project3/i18n/modelerUi.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/modelerUi.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/test_texts.properties b/test/addI18n/project3/i18n/test_texts.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/test_texts.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/test_texts_en.properties b/test/addI18n/project3/i18n/test_texts_en.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/test_texts_en.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project3/i18n/test_texts_en_US.properties b/test/addI18n/project3/i18n/test_texts_en_US.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project3/i18n/test_texts_en_US.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project4/Component.js b/test/addI18n/project4/Component.js new file mode 100644 index 00000000..35499b92 --- /dev/null +++ b/test/addI18n/project4/Component.js @@ -0,0 +1,9 @@ +sap.ui.define(["sap/supi/core/AppComponent"], function(AppComponent) { + "use strict"; + + return AppComponent.extend("supi.Component", { + metadata: { + "manifest": "json" + } + }); +}); diff --git a/test/addI18n/project4/i18n/i18n.properties b/test/addI18n/project4/i18n/i18n.properties new file mode 100644 index 00000000..e20c0585 --- /dev/null +++ b/test/addI18n/project4/i18n/i18n.properties @@ -0,0 +1 @@ +A=B \ No newline at end of file diff --git a/test/addI18n/project4/manifest.expected.json b/test/addI18n/project4/manifest.expected.json new file mode 100644 index 00000000..cabe4806 --- /dev/null +++ b/test/addI18n/project4/manifest.expected.json @@ -0,0 +1,99 @@ +{ + "_version": "1.21.0", + "sap.app": { + "id": "supi", + "type": "application", + "i18n": { + "bundleUrl": "i18n/i18n.properties", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + }, + "applicationVersion": { + "version": "${project.version}" + }, + "title": "{{title}}", + "description": "{{description}}", + "tags": { + "keywords": [] + }, + "ach": "ME", + "dataSources": { + "mainService": { + "uri": "/odata/v4/myservice/", + "type": "OData", + "settings": { + "annotations": ["localAnnotations"], + "odataVersion": "4.0", + "localUri": "localService/metadata.xml" + } + }, + "localAnnotations": { + "uri": "annotations/annotations.xml", + "type": "ODataAnnotation", + "settings": { + "localUri": "annotations/annotations.xml" + } + } + }, + "offline": false, + "resources": "resources.json", + "crossNavigation": { + "inbounds": {}, + "outbounds": {} + } + }, + "sap.ui": { + "technology": "UI5", + "icons": { + "icon": "", + "favIcon": "", + "phone": "", + "phone@2": "", + "tablet": "", + "tablet@2": "" + }, + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "resources": { + "js": [], + "css": [] + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties", + "settings": { + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + } + }, + "": { + "dataSource": "mainService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + } + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/test/addI18n/project4/manifest.json b/test/addI18n/project4/manifest.json new file mode 100644 index 00000000..75edaa0f --- /dev/null +++ b/test/addI18n/project4/manifest.json @@ -0,0 +1,87 @@ +{ + "_version": "1.1.0", + "sap.app": { + "id": "supi", + "type": "application", + "i18n": "i18n/i18n.properties", + "applicationVersion": { + "version": "${project.version}" + }, + "title": "{{title}}", + "description": "{{description}}", + "tags": { + "keywords": [] + }, + "ach": "ME", + "dataSources": { + "mainService": { + "uri": "/odata/v4/myservice/", + "type": "OData", + "settings": { + "annotations": ["localAnnotations"], + "odataVersion": "4.0", + "localUri": "localService/metadata.xml" + } + }, + "localAnnotations": { + "uri": "annotations/annotations.xml", + "type": "ODataAnnotation", + "settings": { + "localUri": "annotations/annotations.xml" + } + } + }, + "offline": false, + "resources": "resources.json", + "crossNavigation": { + "inbounds": {}, + "outbounds": {} + } + }, + "sap.ui": { + "technology": "UI5", + "icons": { + "icon": "", + "favIcon": "", + "phone": "", + "phone@2": "", + "tablet": "", + "tablet@2": "" + }, + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "resources": { + "js": [], + "css": [] + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "i18n/i18n.properties" + }, + "": { + "dataSource": "mainService", + "settings": { + "synchronizationMode": "None", + "operationMode": "Server", + "autoExpandSelect": true, + "earlyRequests": true, + "groupProperties": { + "default": { + "submit": "Auto" + } + } + } + } + } + }, + "sap.fiori": { + "registrationIds": [], + "archeType": "transactional" + } +} diff --git a/test/addI18n/project5/Component.js b/test/addI18n/project5/Component.js new file mode 100644 index 00000000..e8f791c1 --- /dev/null +++ b/test/addI18n/project5/Component.js @@ -0,0 +1,10 @@ +sap.ui.define([ + "sap/ui/core/Component" +], function (Component) { + "use strict"; + return Component.extend("mydemo.Component", { + metadata: { + manifest: "json" + } + }); +}); diff --git a/test/addI18n/project5/manifest.expected.json b/test/addI18n/project5/manifest.expected.json new file mode 100644 index 00000000..27ab531a --- /dev/null +++ b/test/addI18n/project5/manifest.expected.json @@ -0,0 +1,50 @@ +{ + "_version": "1.21.0", + "sap.app": { + "_version": "1.1.0", + "i18n": { + "bundleUrl": "messagebundle.properties", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + }, + "id": "mydemo.MyApp", + "type": "component", + "embeddedBy": "", + "title": "{{title}}", + "description": "{{description}}", + "applicationVersion": { + "version": "1.1.0" + }, + "ach": "ME" + }, + "sap.ui": { + "_version": "1.1.0", + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "componentName": "mydemo.MyApp", + "dependencies": { + "minUI5Version":"1.28", + "libs": { + "sap.m": { + "minVersion": "1.28" + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.flp": { + "type": "plugin" + } +} + diff --git a/test/addI18n/project5/manifest.json b/test/addI18n/project5/manifest.json new file mode 100644 index 00000000..bc34a5d4 --- /dev/null +++ b/test/addI18n/project5/manifest.json @@ -0,0 +1,44 @@ +{ + "_version": "1.4.0", + "sap.app": { + "_version": "1.1.0", + "i18n": "messagebundle.properties", + "id": "mydemo.MyApp", + "type": "component", + "embeddedBy": "", + "title": "{{title}}", + "description": "{{description}}", + "applicationVersion": { + "version": "1.1.0" + }, + "ach": "ME" + }, + "sap.ui": { + "_version": "1.1.0", + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + "sap.ui5": { + "componentName": "mydemo.MyApp", + "dependencies": { + "minUI5Version":"1.28", + "libs": { + "sap.m": { + "minVersion": "1.28" + } + } + }, + "contentDensities": { + "compact": true, + "cozy": true + } + }, + "sap.flp": { + "type": "plugin" + } +} + diff --git a/test/addI18n/project5/messagebundle.properties b/test/addI18n/project5/messagebundle.properties new file mode 100644 index 00000000..f2e020ef --- /dev/null +++ b/test/addI18n/project5/messagebundle.properties @@ -0,0 +1 @@ +A=O \ No newline at end of file diff --git a/test/addI18n/project6/.theming b/test/addI18n/project6/.theming new file mode 100644 index 00000000..0e0dcd23 --- /dev/null +++ b/test/addI18n/project6/.theming @@ -0,0 +1,3 @@ +{ + +} \ No newline at end of file diff --git a/test/addI18n/project6/app/Component.js b/test/addI18n/project6/app/Component.js new file mode 100644 index 00000000..e80dfba9 --- /dev/null +++ b/test/addI18n/project6/app/Component.js @@ -0,0 +1,6 @@ +sap.ui.define(["sap/ui/core/UIComponent"], + function (UIComponent) { + "use strict"; + return UIComponent.extend("myapp.Component", {}); + } +); \ No newline at end of file diff --git a/test/addI18n/project6/app/manifest.expected.json b/test/addI18n/project6/app/manifest.expected.json new file mode 100644 index 00000000..95c7d7c6 --- /dev/null +++ b/test/addI18n/project6/app/manifest.expected.json @@ -0,0 +1,75 @@ +{ + "_version": "1.21.0", + + "sap.app": { + "_version": "1.1.0", + "id": "myapp.app", + "type": "application", + "i18n": { + "bundleUrl": "../messagebundle.properties", + "supportedLocales": [ + "", + "ar", + "sh" + ], + "fallbackLocale": "" + }, + "applicationVersion": { + "version": "${project.version}" + }, + "title": "{{TITLE}}", + "description": "{{DESCRIPTION}}", + "tags": { + "keywords": ["{{TITLE}}"] + }, + "ach": "ME", + "offline": false, + "resources": "resources.json" + }, + + "sap.ui": { + "_version": "1.1.0", + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + + "sap.ui5": { + "_version": "1.1.0", + "dependencies": { + "minUI5Version": "1.30.1", + "libs": { + "sap.ui.core": { + "minVersion": "1.30.1" + }, + "sap.ui.comp": { + "minVersion": "1.30.1" + } + } + }, + + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "../messagebundle.properties", + "settings": { + "supportedLocales": [ + "", + "ar", + "sh" + ], + "fallbackLocale": "" + } + } + }, + + "contentDensities": { + "compact": true, + "cozy": true + } + } +} + diff --git a/test/addI18n/project6/app/manifest.json b/test/addI18n/project6/app/manifest.json new file mode 100644 index 00000000..63cf5bfa --- /dev/null +++ b/test/addI18n/project6/app/manifest.json @@ -0,0 +1,59 @@ +{ + "_version": "1.1.0", + + "sap.app": { + "_version": "1.1.0", + "id": "myapp.app", + "type": "application", + "i18n": "../messagebundle.properties", + "applicationVersion": { + "version": "${project.version}" + }, + "title": "{{TITLE}}", + "description": "{{DESCRIPTION}}", + "tags": { + "keywords": ["{{TITLE}}"] + }, + "ach": "ME", + "offline": false, + "resources": "resources.json" + }, + + "sap.ui": { + "_version": "1.1.0", + "technology": "UI5", + "deviceTypes": { + "desktop": true, + "tablet": true, + "phone": true + } + }, + + "sap.ui5": { + "_version": "1.1.0", + "dependencies": { + "minUI5Version": "1.30.1", + "libs": { + "sap.ui.core": { + "minVersion": "1.30.1" + }, + "sap.ui.comp": { + "minVersion": "1.30.1" + } + } + }, + + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "uri": "../messagebundle.properties" + } + }, + + "contentDensities": { + "compact": true, + "cozy": true + } + } +} + diff --git a/test/addI18n/project6/library.js b/test/addI18n/project6/library.js new file mode 100644 index 00000000..7043185d --- /dev/null +++ b/test/addI18n/project6/library.js @@ -0,0 +1,5 @@ +sap.ui.define([],function() { + 'use strict'; + return {}; + +}); \ No newline at end of file diff --git a/test/addI18n/project6/messagebundle.properties b/test/addI18n/project6/messagebundle.properties new file mode 100644 index 00000000..e20c0585 --- /dev/null +++ b/test/addI18n/project6/messagebundle.properties @@ -0,0 +1 @@ +A=B \ No newline at end of file diff --git a/test/addI18n/project6/messagebundle_ar.properties b/test/addI18n/project6/messagebundle_ar.properties new file mode 100644 index 00000000..51e76b23 --- /dev/null +++ b/test/addI18n/project6/messagebundle_ar.properties @@ -0,0 +1 @@ +A=C \ No newline at end of file diff --git a/test/addI18n/project6/messagebundle_sh.properties b/test/addI18n/project6/messagebundle_sh.properties new file mode 100644 index 00000000..162c0fe8 --- /dev/null +++ b/test/addI18n/project6/messagebundle_sh.properties @@ -0,0 +1 @@ +A=D \ No newline at end of file diff --git a/test/addI18nTest.ts b/test/addI18nTest.ts new file mode 100644 index 00000000..2e8914d6 --- /dev/null +++ b/test/addI18nTest.ts @@ -0,0 +1,220 @@ +import { + CustomFileFinder, + CustomFileInfo, + CustomReporter, +} from "./util/testUtils"; + +const assert = require("assert"); +const fs = require("graceful-fs"); +const recast = require("recast"); +const rootDir = "./test/addI18n/"; +const sinon = require("sinon"); + +import * as FileUtils from "../src/util/FileUtils"; + +import {analyse, migrate} from "../src/tasks/addI18n"; +import {FileInfo} from "ui5-migration"; + +const fileFinder = new CustomFileFinder(); + +interface Content { + /** + * + * @param {string} path file path, e.g. test/MyFile.js + */ + getContent(): string; +} + +function analyseMigrateAndTest( + module: CustomFileInfo, + expectedModification: boolean, + expectedContent: string, + config: {}, + content: Content, + done?: Function, + expectedReports: string[] = [] +) { + const reporter = new CustomReporter([], "debug"); + const pAnalysisAndMigration = analyse({ + file: module, + fileFinder, + reporter, + config, + }) + .then(function(analyseResult) { + if (migrate && analyseResult) { + return migrate({ + file: module, + fileFinder, + reporter, + analyseResult, + config, + }); + } else { + return false; + } + }) + .then(function(didModify) { + assert.strictEqual( + didModify, + expectedModification, + "Modification has invalid value" + ); + const actualContent = content.getContent(); + assert.equal(actualContent, expectedContent); + + assert.deepStrictEqual(reporter.getReports(), expectedReports); + }); + if (!done) { + return pAnalysisAndMigration; + } + return pAnalysisAndMigration + .then(function() { + done(); + }) + .catch(function(e) { + done(e); + }); +} + +describe("addI18n", function() { + let oStub; + beforeEach(function() { + oStub = sinon.stub(FileUtils, "fsWriteFile").resolves(); + }); + + afterEach(function() { + if (oStub) { + oStub.restore(); + } + }); + it("project", function(done) { + const expectedContent = fs.readFileSync( + rootDir + "project/manifest.expected.json", + "utf8" + ); + const module = new CustomFileInfo(rootDir + "project/Component.js"); + analyseMigrateAndTest( + module, + false, + expectedContent, + {}, + { + getContent(): string { + return oStub.getCalls()[0].args[1]; + }, + }, + done, + [] + ); + }); + + it("project2", function(done) { + const expectedContent = fs.readFileSync( + rootDir + "project2/manifest.expected.json", + "utf8" + ); + const module = new CustomFileInfo(rootDir + "project2/Component.js"); + analyseMigrateAndTest( + module, + false, + expectedContent, + {}, + { + getContent(): string { + return oStub.getCalls()[0].args[1]; + }, + }, + done, + [] + ); + }); + + it("project3", function(done) { + const expectedContent = fs.readFileSync( + rootDir + "project3/comp/manifest.expected.json", + "utf8" + ); + const module = new CustomFileInfo( + rootDir + "project3/comp/Component.js" + ); + analyseMigrateAndTest( + module, + false, + expectedContent, + {}, + { + getContent(): string { + return oStub.getCalls()[0].args[1]; + }, + }, + done, + [] + ); + }); + + it("project4", function(done) { + const expectedContent = fs.readFileSync( + rootDir + "project4/manifest.expected.json", + "utf8" + ); + const module = new CustomFileInfo(rootDir + "project4/Component.js"); + analyseMigrateAndTest( + module, + false, + expectedContent, + {}, + { + getContent(): string { + return oStub.getCalls()[0].args[1]; + }, + }, + done, + [] + ); + }); + + it("project5", function(done) { + const expectedContent = fs.readFileSync( + rootDir + "project5/manifest.expected.json", + "utf8" + ); + const module = new CustomFileInfo(rootDir + "project5/Component.js"); + analyseMigrateAndTest( + module, + false, + expectedContent, + {}, + { + getContent(): string { + return oStub.getCalls()[0].args[1]; + }, + }, + done, + [] + ); + }); + + it("project6", function(done) { + const expectedContent = fs.readFileSync( + rootDir + "project6/app/manifest.expected.json", + "utf8" + ); + const module = new CustomFileInfo( + rootDir + "project6/app/Component.js" + ); + analyseMigrateAndTest( + module, + false, + expectedContent, + {}, + { + getContent(): string { + return oStub.getCalls()[0].args[1]; + }, + }, + done, + [] + ); + }); +}); diff --git a/test/util/content/ModifyJSONContentTest.ts b/test/util/content/ModifyJSONContentTest.ts new file mode 100644 index 00000000..88ebc06c --- /dev/null +++ b/test/util/content/ModifyJSONContentTest.ts @@ -0,0 +1,148 @@ +import {ModifyJSONContent} from "../../../src/util/content/ModifyJSONContent"; + +const assert = require("assert"); + +describe("ModifyJSONContent", function() { + it("Should replace i18n sections", function() { + const strContent = `{ + "sap.app": { +\t"id": "supi.theTests", +\t"type": "application", +\t"i18n": "i18n/i18n.properties", +\t"title": "{{appTitle}}" + }, + "sap.ui5": { +\t"models": { +\t "i18n": { +\t\t"type": "sap.ui.model.resource.ResourceModel", +\t\t"settings": { +\t\t "bundleName": "supi.theTests.i18n.i18n" +\t\t}, +\t\t"preload": true +\t } +\t} + } +} +`; + + const strContentExpected = `{ + "sap.app": { +\t"id": "supi.theTests", +\t"type": "application", +\t"i18n": { +\t\t"bundleUrl": "i18n/i18n.properties", +\t\t"supportedLocales": [ +\t\t\t"de", +\t\t\t"en" +\t\t], +\t\t"fallbackLocale": "de" +\t}, +\t"title": "{{appTitle}}" + }, + "sap.ui5": { +\t"models": { +\t "i18n": { +\t\t"type": "sap.ui.model.resource.ResourceModel", +\t\t"settings": { +\t\t "bundleName": "supi.theTests.i18n.i18n", +\t\t "supportedLocales": [ +\t\t \t"de", +\t\t \t"en" +\t\t ], +\t\t "fallbackLocale": "de" +\t\t}, +\t\t"preload": true +\t } +\t} + } +} +`; + + const oModifyJSONContent = ModifyJSONContent.create(strContent); + //const oConfig = oModifyJSONContent.find(["sap.ui5"]["models"]["i18n"]); + + oModifyJSONContent.replace(["sap.app", "i18n"], { + bundleUrl: "i18n/i18n.properties", + supportedLocales: ["de", "en"], + fallbackLocale: "de", + }); + + const aPath = ["sap.ui5", "models", "i18n", "settings"]; + oModifyJSONContent.add(aPath, { + supportedLocales: ["de", "en"], + fallbackLocale: "de", + }); + + assert.deepEqual(oModifyJSONContent.getContent(), strContentExpected); + }); + + it("Should add settings sections", function() { + const strContent = `{ + "sap.app": { +\t"id": "supi.theTests", +\t"type": "application", +\t"i18n": "i18n/i18n.properties", +\t"title": "{{appTitle}}" + }, + "sap.ui5": { +\t"models": { +\t "i18n": { +\t\t"type": "sap.ui.model.resource.ResourceModel", +\t\t"preload": true +\t } +\t} + } +} +`; + + const strContentExpected = `{ + "sap.app": { +\t"id": "supi.theTests", +\t"type": "application", +\t"i18n": "i18n/i18n.properties", +\t"title": "{{appTitle}}" + }, + "sap.ui5": { +\t"models": { +\t "i18n": { +\t\t"type": "sap.ui.model.resource.ResourceModel", +\t\t"preload": true, +\t\t"settings": {} +\t } +\t} + } +} +`; + + const oModifyJSONContent = ModifyJSONContent.create(strContent); + + const aPath = ["sap.ui5", "models", "i18n"]; + oModifyJSONContent.add(aPath, { + settings: {}, + }); + + assert.deepEqual(oModifyJSONContent.getContent(), strContentExpected); + }); + + it("Should replace string", function() { + const strContent = `{ + "_version": "1.14.0", + "start_url": "index.html", + "myprop": "myvalue" +} +`; + + const strContentExpected = `{ + "_version": "1.21.0", + "start_url": "index.html", + "myprop": "myvalue" +} +`; + + const oModifyJSONContent = ModifyJSONContent.create(strContent); + + oModifyJSONContent.replace(["_version"], "1.21.0"); + + assert.deepEqual(oModifyJSONContent.getContent(), strContentExpected); + }); +});