From 472d3edc79de8270e909ce0326db36ad8ba00909 Mon Sep 17 00:00:00 2001 From: Tobias Sorn Date: Fri, 24 Apr 2020 15:13:05 +0200 Subject: [PATCH 1/4] [INTERNAL] AddI18n functionality Adds supportedLocales and fallbackLocale property to manifest.json. --- npm-shrinkwrap.json | 19 ++ package.json | 1 + src/cli.ts | 1 + src/tasks/addI18n.ts | 333 ++++++++++++++++++++ src/util/content/ModifyJSONContent.ts | 231 ++++++++++++++ test/addI18n/project/Component.js | 29 ++ test/addI18n/project/i18n/i18n.properties | 8 + test/addI18n/project/manifest.expected.json | 275 ++++++++++++++++ test/addI18n/project/manifest.json | 265 ++++++++++++++++ test/addI18nTest.ts | 113 +++++++ test/util/content/ModifyJSONContentTest.ts | 78 +++++ 11 files changed, 1353 insertions(+) create mode 100644 src/tasks/addI18n.ts create mode 100644 src/util/content/ModifyJSONContent.ts create mode 100644 test/addI18n/project/Component.js create mode 100644 test/addI18n/project/i18n/i18n.properties create mode 100644 test/addI18n/project/manifest.expected.json create mode 100644 test/addI18n/project/manifest.json create mode 100644 test/addI18nTest.ts create mode 100644 test/util/content/ModifyJSONContentTest.ts 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..f8a29dd9 --- /dev/null +++ b/src/tasks/addI18n.ts @@ -0,0 +1,333 @@ +/* + * 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 * as DiffOptimizer from "../util/whitespace/DiffOptimizer"; +import {ModifyJSONContent} from "../util/content/ModifyJSONContent"; +import {DiffStringOptimizeStrategy} from "../util/whitespace/DiffStringOptimizeStrategy"; + +//#endregion + +interface AddI18nResult { + defineCall: SapUiDefineCall; + supportedLocalesModels?: string[]; + fallbackLocaleModels?: string; + supportedLocalesApp?: string[]; + fallbackLocaleApp?: string; + bundleUrlApp?: string; + manifestPath: string; + manifestContent: object; + manifestContentString: string; +} + +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.includes("_")) { + return si18n.substring( + fileName.length + "_".length, + si18n.lastIndexOf(".properties") + ); + } + return si18n.substring( + fileName.length, + si18n.lastIndexOf(".properties") + ); + }) + ); + } + const fallbackLocale: string = 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 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 ( + stmt.argument.callee.object.name === sImportName && + 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" && + decl.init.callee.object.name === sImportName + ) { + 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; + 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" && + 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 { + return undefined; + } + + if (!sI18nModelsFolder && !sI18nAppFolder) { + return undefined; + } + + const oResultObject: AddI18nResult = { + defineCall, + manifestPath, + manifestContent, + manifestContentString, + }; + + if (sI18nModelsFolder) { + // sI18nFolder = i18n.i18n + const split = sI18nModelsFolder.split("."); + const 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.length > 0 || + 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 + ) { + 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, + }); + } + 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..700591d9 --- /dev/null +++ b/src/util/content/ModifyJSONContent.ts @@ -0,0 +1,231 @@ +// 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; + + constructor(content) { + this.content = content; + this.init(content); + } + + private init(content) { + this.eol = this.calculateEOL(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 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; + } + + replace(aPath, 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); + } + } + this.contentLines.splice( + startLine, + 0, + targetIndent + '"' + lastElement + '": {' + ); + + 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); + }); + + this.contentLines.splice( + lastPos, + 0, + targetIndent + "}" + (commaRequired ? "," : "") + ); + + // 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, 2); + 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..ed2e01b6 --- /dev/null +++ b/test/addI18n/project/Component.js @@ -0,0 +1,29 @@ +sap.ui.define([ + "sap/ui/core/UIComponent", + "sap/ui/model/json/JSONModel", + "./services/SampleServices" +], function (UIComponent, JSONModel, SampleServices) { + "use strict"; + + return UIComponent.extend("sap.f.cardsVisualTests.Component", { + metadata : { + manifest: "json" + }, + init: function () { + // call the init function of the parent + UIComponent.prototype.init.apply(this, arguments); + + // create the views based on the url/hash + this.getRouter().initialize(); + + var oModel = new JSONModel(); + oModel.loadData("./cardsVisualTests/model/examples.json"); + this.setModel(oModel); + + var oCardManifests = new JSONModel(); + oCardManifests.loadData("./cardsVisualTests/model/cardManifests.json"); + this.setModel(oCardManifests, "manifests"); + } + }); + +}); 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..8692319d --- /dev/null +++ b/test/addI18n/project/manifest.expected.json @@ -0,0 +1,275 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "sap.f.cardsVisualTests", + "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": { + "services": { + "UserRecent": { + "factoryName": "cardsVisualTests.service.UserRecentFactory" + }, + "Navigation": { + "factoryName": "cardsVisualTests.service.SampleNavigationFactory" + } + }, + "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": "sap.f.cardsVisualTests.view.App", + "type": "XML", + "async": true, + "id": "app" + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "sap.f.cardsVisualTests.i18n.i18n", + "supportedLocales": [ + "" + ], + "fallbackLocale": "" + }, + "preload": true + } + }, + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "sap.f.cardsVisualTests.view", + "controlId": "app", + "controlAggregation": "pages", + "transition": "slide", + "bypassed": { + "target": "notFound" + }, + "async": true + }, + "routes": [ + { + "pattern": "", + "name": "appMain", + "target": "main" + }, + { + "pattern": "grid", + "name": "grid", + "target": "grid" + }, + { + "pattern": "zflow", + "name": "zflow", + "target": "zflow" + }, + { + "pattern": "flexibleHeight", + "name": "flexibleHeight", + "target": "flexibleHeight" + }, + { + "pattern": "splitter", + "name": "splitter", + "target": "splitter" + }, + { + "pattern": "nolayout", + "name": "nolayout", + "target": "nolayout" + }, + { + "pattern": "listContent", + "name": "listContent", + "target": "listContent" + }, + { + "pattern": "tableContent", + "name": "tableContent", + "target": "tableContent" + }, + { + "pattern": "objectContent", + "name": "objectContent", + "target": "objectContent" + }, + { + "pattern": "adaptiveContent", + "name": "adaptiveContent", + "target": "adaptiveContent" + }, + { + "pattern": "flp", + "name": "flp", + "target": "flp" + }, { + "pattern": "numericHeader", + "name": "numericHeader", + "target": "numericHeader" + }, + { + "pattern": "analyticalContent", + "name": "analyticalContent", + "target": "analyticalContent" + }, + { + "pattern": "manifest", + "name": "manifest", + "target": "manifest" + }, + { + "pattern": "customContent", + "name": "customContent", + "target": "customContent" + }, + { + "pattern": "gridContainer", + "name": "gridContainer", + "target": "gridContainer" + }, + { + "pattern": "services", + "name": "services", + "target": "services" + }, + { + "pattern": "minHeight", + "name": "minHeight", + "target": "minHeight" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main", + "viewLevel": 1 + }, + "grid": { + "viewId": "grid", + "viewName": "Grid", + "viewLevel": 1 + }, + "zflow": { + "viewId": "zflow", + "viewName": "Zflow", + "viewLevel": 1 + }, + "flexibleHeight": { + "viewId": "flexibleHeight", + "viewName": "FlexibleHeight", + "viewLevel": 1 + }, + "splitter": { + "viewId": "splitter", + "viewName": "Splitter", + "viewLevel": 1 + }, + "nolayout": { + "viewId": "nolayout", + "viewName": "NoLayout", + "viewLevel": 1 + }, + "notFound": { + "viewId": "notFound", + "viewName": "NotFound", + "transition": "show" + }, + "listContent": { + "viewId": "listContent", + "viewName": "ListContent", + "viewLevel": 1 + }, + "tableContent": { + "viewId": "tableContent", + "viewName": "TableContent", + "viewLevel": 1 + }, + "objectContent": { + "viewId": "objectContent", + "viewName": "ObjectContent", + "viewLevel": 1 + }, + "adaptiveContent": { + "viewId": "adaptiveContent", + "viewName": "AdaptiveContent", + "viewLevel": 1 + }, + "analyticalContent": { + "viewId": "analyticalContent", + "viewName": "AnalyticalContent", + "viewLevel": 1 + }, + "flp": { + "viewId": "flp", + "viewName": "Flp", + "viewLevel": 1 + }, + "numericHeader": { + "viewId": "numericHeader", + "viewName": "NumericHeader", + "viewLevel": 1 + }, + "manifest": { + "viewId": "manifest", + "viewName": "Manifest", + "viewLevel": 1 + }, + "customContent": { + "viewId": "custom", + "viewName": "Custom", + "viewLevel": 1 + }, + "gridContainer": { + "viewId": "GridContainer", + "viewName": "GridContainer", + "viewLevel": 1 + }, + "services": { + "viewId": "services", + "viewName": "Services", + "viewLevel": 1 + }, + "minHeight": { + "viewId": "minHeight", + "viewName": "MinHeight", + "viewLevel": 1 + } + } + } + } +} \ 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..e2809bca --- /dev/null +++ b/test/addI18n/project/manifest.json @@ -0,0 +1,265 @@ +{ + "_version": "1.8.0", + "sap.app": { + "id": "sap.f.cardsVisualTests", + "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": { + "services": { + "UserRecent": { + "factoryName": "cardsVisualTests.service.UserRecentFactory" + }, + "Navigation": { + "factoryName": "cardsVisualTests.service.SampleNavigationFactory" + } + }, + "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": "sap.f.cardsVisualTests.view.App", + "type": "XML", + "async": true, + "id": "app" + }, + "models": { + "i18n": { + "type": "sap.ui.model.resource.ResourceModel", + "settings": { + "bundleName": "sap.f.cardsVisualTests.i18n.i18n" + }, + "preload": true + } + }, + "routing": { + "config": { + "routerClass": "sap.m.routing.Router", + "viewType": "XML", + "viewPath": "sap.f.cardsVisualTests.view", + "controlId": "app", + "controlAggregation": "pages", + "transition": "slide", + "bypassed": { + "target": "notFound" + }, + "async": true + }, + "routes": [ + { + "pattern": "", + "name": "appMain", + "target": "main" + }, + { + "pattern": "grid", + "name": "grid", + "target": "grid" + }, + { + "pattern": "zflow", + "name": "zflow", + "target": "zflow" + }, + { + "pattern": "flexibleHeight", + "name": "flexibleHeight", + "target": "flexibleHeight" + }, + { + "pattern": "splitter", + "name": "splitter", + "target": "splitter" + }, + { + "pattern": "nolayout", + "name": "nolayout", + "target": "nolayout" + }, + { + "pattern": "listContent", + "name": "listContent", + "target": "listContent" + }, + { + "pattern": "tableContent", + "name": "tableContent", + "target": "tableContent" + }, + { + "pattern": "objectContent", + "name": "objectContent", + "target": "objectContent" + }, + { + "pattern": "adaptiveContent", + "name": "adaptiveContent", + "target": "adaptiveContent" + }, + { + "pattern": "flp", + "name": "flp", + "target": "flp" + }, { + "pattern": "numericHeader", + "name": "numericHeader", + "target": "numericHeader" + }, + { + "pattern": "analyticalContent", + "name": "analyticalContent", + "target": "analyticalContent" + }, + { + "pattern": "manifest", + "name": "manifest", + "target": "manifest" + }, + { + "pattern": "customContent", + "name": "customContent", + "target": "customContent" + }, + { + "pattern": "gridContainer", + "name": "gridContainer", + "target": "gridContainer" + }, + { + "pattern": "services", + "name": "services", + "target": "services" + }, + { + "pattern": "minHeight", + "name": "minHeight", + "target": "minHeight" + } + ], + "targets": { + "main": { + "viewId": "main", + "viewName": "Main", + "viewLevel": 1 + }, + "grid": { + "viewId": "grid", + "viewName": "Grid", + "viewLevel": 1 + }, + "zflow": { + "viewId": "zflow", + "viewName": "Zflow", + "viewLevel": 1 + }, + "flexibleHeight": { + "viewId": "flexibleHeight", + "viewName": "FlexibleHeight", + "viewLevel": 1 + }, + "splitter": { + "viewId": "splitter", + "viewName": "Splitter", + "viewLevel": 1 + }, + "nolayout": { + "viewId": "nolayout", + "viewName": "NoLayout", + "viewLevel": 1 + }, + "notFound": { + "viewId": "notFound", + "viewName": "NotFound", + "transition": "show" + }, + "listContent": { + "viewId": "listContent", + "viewName": "ListContent", + "viewLevel": 1 + }, + "tableContent": { + "viewId": "tableContent", + "viewName": "TableContent", + "viewLevel": 1 + }, + "objectContent": { + "viewId": "objectContent", + "viewName": "ObjectContent", + "viewLevel": 1 + }, + "adaptiveContent": { + "viewId": "adaptiveContent", + "viewName": "AdaptiveContent", + "viewLevel": 1 + }, + "analyticalContent": { + "viewId": "analyticalContent", + "viewName": "AnalyticalContent", + "viewLevel": 1 + }, + "flp": { + "viewId": "flp", + "viewName": "Flp", + "viewLevel": 1 + }, + "numericHeader": { + "viewId": "numericHeader", + "viewName": "NumericHeader", + "viewLevel": 1 + }, + "manifest": { + "viewId": "manifest", + "viewName": "Manifest", + "viewLevel": 1 + }, + "customContent": { + "viewId": "custom", + "viewName": "Custom", + "viewLevel": 1 + }, + "gridContainer": { + "viewId": "GridContainer", + "viewName": "GridContainer", + "viewLevel": 1 + }, + "services": { + "viewId": "services", + "viewName": "Services", + "viewLevel": 1 + }, + "minHeight": { + "viewId": "minHeight", + "viewName": "MinHeight", + "viewLevel": 1 + } + } + } + } +} \ No newline at end of file diff --git a/test/addI18nTest.ts b/test/addI18nTest.ts new file mode 100644 index 00000000..9dfc4374 --- /dev/null +++ b/test/addI18nTest.ts @@ -0,0 +1,113 @@ +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() { + describe("#start()", function() { + let oStub; + beforeEach(function() { + oStub = sinon.stub(FileUtils, "fsWriteFile").resolves(); + }); + + afterEach(function() { + if (oStub) { + oStub.restore(); + } + }); + it("should addMissingDependencies", 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, + [] + ); + }); + }); +}); diff --git a/test/util/content/ModifyJSONContentTest.ts b/test/util/content/ModifyJSONContentTest.ts new file mode 100644 index 00000000..4396f5ec --- /dev/null +++ b/test/util/content/ModifyJSONContentTest.ts @@ -0,0 +1,78 @@ +import {ModifyJSONContent} from "../../../src/util/content/ModifyJSONContent"; + +const assert = require("assert"); + +describe("ModifyJSONContent", function() { + it("Should succeed if valid version range was given", function() { + const strContent = `{ + "sap.app": { +\t"id": "sap.f.cardsVisualTests", +\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": "sap.f.cardsVisualTests.i18n.i18n" +\t\t}, +\t\t"preload": true +\t } +\t} + } +} +`; + + const strContentExpected = `{ + "sap.app": { +\t"id": "sap.f.cardsVisualTests", +\t"type": "application", +\t"i18n": { +\t "bundleUrl": "i18n/i18n.properties", +\t "supportedLocales": [ +\t "de", +\t "en" +\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": "sap.f.cardsVisualTests.i18n.i18n", +\t\t "supportedLocales": [ +\t\t "de", +\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); + }); +}); From 1cb4dd670b28e98f39217c32f8c822b0816949f1 Mon Sep 17 00:00:00 2001 From: Tobias Sorn Date: Mon, 27 Apr 2020 10:05:47 +0200 Subject: [PATCH 2/4] Make "en" the default fallbackLocale if available --- src/tasks/addI18n.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tasks/addI18n.ts b/src/tasks/addI18n.ts index f8a29dd9..fc6817ac 100644 --- a/src/tasks/addI18n.ts +++ b/src/tasks/addI18n.ts @@ -17,9 +17,7 @@ import * as Mod from "../Migration"; import * as ASTUtils from "../util/ASTUtils"; import {ASTVisitor} from "../util/ASTVisitor"; import {SapUiDefineCall} from "../util/SapUiDefineCall"; -import * as DiffOptimizer from "../util/whitespace/DiffOptimizer"; import {ModifyJSONContent} from "../util/content/ModifyJSONContent"; -import {DiffStringOptimizeStrategy} from "../util/whitespace/DiffStringOptimizeStrategy"; //#endregion @@ -55,7 +53,9 @@ async function getFiles(sI18nFolder, fileName) { }) ); } - const fallbackLocale: string = supportedLocales[0]; + const fallbackLocale: string = supportedLocales.includes("en") + ? "en" + : supportedLocales[0]; return { supportedLocalesModels: supportedLocales, fallbackLocaleModels: fallbackLocale, From e5e0a006271b6a18f46d6348f312bc741f9c224a Mon Sep 17 00:00:00 2001 From: Tobias Sorn Date: Tue, 28 Apr 2020 09:19:37 +0200 Subject: [PATCH 3/4] improve logic keep indent --- src/tasks/addI18n.ts | 10 ++++++++-- src/util/content/ModifyJSONContent.ts | 17 ++++++++++++++++- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/src/tasks/addI18n.ts b/src/tasks/addI18n.ts index fc6817ac..2f1e02a8 100644 --- a/src/tasks/addI18n.ts +++ b/src/tasks/addI18n.ts @@ -107,6 +107,12 @@ async function analyse( "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) { @@ -115,7 +121,7 @@ async function analyse( stmt.argument.callee.property.type === Syntax.Identifier ) { if ( - stmt.argument.callee.object.name === sImportName && + isCandidate(stmt.argument.callee.object) && stmt.argument.callee.property.name === "extend" ) { return true; @@ -139,7 +145,7 @@ async function analyse( decl.init.callee.property.type === Syntax.Identifier && decl.init.callee.object.type === Syntax.Identifier && decl.init.callee.property.name === "extend" && - decl.init.callee.object.name === sImportName + isCandidate(decl.init.callee.object) ) { if (decl.init.arguments[0].type === Syntax.Literal) { nameSpace = decl.init.arguments[0].value.toString(); diff --git a/src/util/content/ModifyJSONContent.ts b/src/util/content/ModifyJSONContent.ts index 700591d9..cc3210da 100644 --- a/src/util/content/ModifyJSONContent.ts +++ b/src/util/content/ModifyJSONContent.ts @@ -27,6 +27,7 @@ export class ModifyJSONContent { private oContent; private contentLines: string[]; private eol: string; + private indent: string; constructor(content) { this.content = content; @@ -35,6 +36,7 @@ export class ModifyJSONContent { private init(content) { this.eol = this.calculateEOL(content); + this.indent = this.calculateIndent(content); this.contentLines = content.split(this.eol); this.modifiedContent = content; this.settings = { @@ -52,6 +54,19 @@ export class ModifyJSONContent { : "\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); } @@ -155,7 +170,7 @@ export class ModifyJSONContent { } private extractContent(oContent) { - let newString = JSON.stringify(oContent, null, 2); + let newString = JSON.stringify(oContent, null, this.indent); if (newString.startsWith("{") && newString.endsWith("}")) { newString = newString.substring(1, newString.length - 1); } From 496e4b56bc8aef35cd772f8f4710998e2247ffd3 Mon Sep 17 00:00:00 2001 From: Tobias Sorn Date: Fri, 8 May 2020 09:11:35 +0200 Subject: [PATCH 4/4] Support edge cases for manifest adjustments --- src/tasks/addI18n.ts | 109 ++++++--- src/util/content/ModifyJSONContent.ts | 52 +++-- test/addI18n/project/Component.js | 19 +- test/addI18n/project/manifest.expected.json | 218 +----------------- test/addI18n/project/manifest.json | 216 +---------------- test/addI18n/project2/Component.js | 17 ++ test/addI18n/project2/i18n/i18n.properties | 12 + test/addI18n/project2/i18n/i18n_en.properties | 12 + test/addI18n/project2/manifest.expected.json | 59 +++++ test/addI18n/project2/manifest.json | 52 +++++ test/addI18n/project3/comp/Component.js | 26 +++ .../project3/comp/manifest.expected.json | 80 +++++++ test/addI18n/project3/comp/manifest.json | 64 +++++ test/addI18n/project3/i18n/apfUi.properties | 1 + .../addI18n/project3/i18n/apfUi_en.properties | 1 + .../project3/i18n/apfUi_en_US.properties | 1 + .../i18n/applicationMessages.properties | 1 + .../i18n/applicationMessages_en.properties | 1 + .../i18n/applicationMessages_en_US.properties | 1 + .../project3/i18n/applicationUi.properties | 1 + .../project3/i18n/applicationUi_en.properties | 1 + .../i18n/applicationUi_en_US.properties | 1 + .../project3/i18n/demokitTest.properties | 1 + .../project3/i18n/modelerUi.properties | 1 + .../project3/i18n/test_texts.properties | 1 + .../project3/i18n/test_texts_en.properties | 1 + .../project3/i18n/test_texts_en_US.properties | 1 + test/addI18n/project4/Component.js | 9 + test/addI18n/project4/i18n/i18n.properties | 1 + test/addI18n/project4/manifest.expected.json | 99 ++++++++ test/addI18n/project4/manifest.json | 87 +++++++ test/addI18n/project5/Component.js | 10 + test/addI18n/project5/manifest.expected.json | 50 ++++ test/addI18n/project5/manifest.json | 44 ++++ .../addI18n/project5/messagebundle.properties | 1 + test/addI18n/project6/.theming | 3 + test/addI18n/project6/app/Component.js | 6 + .../project6/app/manifest.expected.json | 75 ++++++ test/addI18n/project6/app/manifest.json | 59 +++++ test/addI18n/project6/library.js | 5 + .../addI18n/project6/messagebundle.properties | 1 + .../project6/messagebundle_ar.properties | 1 + .../project6/messagebundle_sh.properties | 1 + test/addI18nTest.ts | 165 ++++++++++--- test/util/content/ModifyJSONContentTest.ts | 96 ++++++-- 45 files changed, 1125 insertions(+), 538 deletions(-) create mode 100644 test/addI18n/project2/Component.js create mode 100644 test/addI18n/project2/i18n/i18n.properties create mode 100644 test/addI18n/project2/i18n/i18n_en.properties create mode 100644 test/addI18n/project2/manifest.expected.json create mode 100644 test/addI18n/project2/manifest.json create mode 100644 test/addI18n/project3/comp/Component.js create mode 100644 test/addI18n/project3/comp/manifest.expected.json create mode 100644 test/addI18n/project3/comp/manifest.json create mode 100644 test/addI18n/project3/i18n/apfUi.properties create mode 100644 test/addI18n/project3/i18n/apfUi_en.properties create mode 100644 test/addI18n/project3/i18n/apfUi_en_US.properties create mode 100644 test/addI18n/project3/i18n/applicationMessages.properties create mode 100644 test/addI18n/project3/i18n/applicationMessages_en.properties create mode 100644 test/addI18n/project3/i18n/applicationMessages_en_US.properties create mode 100644 test/addI18n/project3/i18n/applicationUi.properties create mode 100644 test/addI18n/project3/i18n/applicationUi_en.properties create mode 100644 test/addI18n/project3/i18n/applicationUi_en_US.properties create mode 100644 test/addI18n/project3/i18n/demokitTest.properties create mode 100644 test/addI18n/project3/i18n/modelerUi.properties create mode 100644 test/addI18n/project3/i18n/test_texts.properties create mode 100644 test/addI18n/project3/i18n/test_texts_en.properties create mode 100644 test/addI18n/project3/i18n/test_texts_en_US.properties create mode 100644 test/addI18n/project4/Component.js create mode 100644 test/addI18n/project4/i18n/i18n.properties create mode 100644 test/addI18n/project4/manifest.expected.json create mode 100644 test/addI18n/project4/manifest.json create mode 100644 test/addI18n/project5/Component.js create mode 100644 test/addI18n/project5/manifest.expected.json create mode 100644 test/addI18n/project5/manifest.json create mode 100644 test/addI18n/project5/messagebundle.properties create mode 100644 test/addI18n/project6/.theming create mode 100644 test/addI18n/project6/app/Component.js create mode 100644 test/addI18n/project6/app/manifest.expected.json create mode 100644 test/addI18n/project6/app/manifest.json create mode 100644 test/addI18n/project6/library.js create mode 100644 test/addI18n/project6/messagebundle.properties create mode 100644 test/addI18n/project6/messagebundle_ar.properties create mode 100644 test/addI18n/project6/messagebundle_sh.properties diff --git a/src/tasks/addI18n.ts b/src/tasks/addI18n.ts index 2f1e02a8..ac98ea0b 100644 --- a/src/tasks/addI18n.ts +++ b/src/tasks/addI18n.ts @@ -18,8 +18,8 @@ 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"; -//#endregion interface AddI18nResult { defineCall: SapUiDefineCall; @@ -31,6 +31,8 @@ interface AddI18nResult { manifestPath: string; manifestContent: object; manifestContentString: string; + manifestVersion: string; + createUI5ModelsSettings: boolean; } async function getFiles(sI18nFolder, fileName) { @@ -39,18 +41,23 @@ async function getFiles(sI18nFolder, fileName) { if (bI18nFolderExists) { const listI18n = await FileUtils.fsReadDir(sI18nFolder); supportedLocales = supportedLocales.concat( - listI18n.map(si18n => { - if (si18n.includes("_")) { - return si18n.substring( - fileName.length + "_".length, - si18n.lastIndexOf(".properties") - ); - } - return si18n.substring( - fileName.length, - si18n.lastIndexOf(".properties") - ); - }) + 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") @@ -185,6 +192,7 @@ async function analyse( let manifestContent; let manifestContentString; let i18nAppValue; + let createUI5ModelsSettings = false; if (bManifestExists) { manifestContentString = await FileUtils.fsReadFile( manifestPath, @@ -205,16 +213,20 @@ async function analyse( ]); if ( i18nModelsConfig && - i18nModelsConfig.type === "sap.ui.model.resource.ResourceModel" && - i18nModelsConfig.settings + i18nModelsConfig.type === "sap.ui.model.resource.ResourceModel" ) { - 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); + 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 { @@ -230,14 +242,26 @@ async function analyse( manifestPath, manifestContent, manifestContentString, + manifestVersion: manifestContent._version, + createUI5ModelsSettings, }; if (sI18nModelsFolder) { - // sI18nFolder = i18n.i18n - const split = sI18nModelsFolder.split("."); - const fileName = split.pop(); - - sI18nModelsFolder = path.join(sFilePath, split.join("/")); + 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, @@ -270,8 +294,10 @@ async function analyse( if ( bAddI18n && manifestContent && - (oResultObject.supportedLocalesModels.length > 0 || - oResultObject.supportedLocalesApp.length > 0) + ((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); @@ -302,10 +328,21 @@ async function migrate(args: Mod.MigrateArguments): Promise { result.supportedLocalesModels && result.supportedLocalesModels.length > 0 ) { - manifestContent.add(["sap.ui5", "models", "i18n", "settings"], { - supportedLocales: result.supportedLocalesModels, - fallbackLocale: result.fallbackLocaleModels, - }); + 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"], { @@ -314,6 +351,12 @@ async function migrate(args: Mod.MigrateArguments): Promise { 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(), diff --git a/src/util/content/ModifyJSONContent.ts b/src/util/content/ModifyJSONContent.ts index cc3210da..5e1c9882 100644 --- a/src/util/content/ModifyJSONContent.ts +++ b/src/util/content/ModifyJSONContent.ts @@ -111,7 +111,12 @@ export class ModifyJSONContent { return resultChild; } - replace(aPath, oContent) { + /** + * 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); @@ -134,29 +139,36 @@ export class ModifyJSONContent { this.contentLines.splice(i, 1); } } - this.contentLines.splice( - startLine, - 0, - targetIndent + '"' + lastElement + '": {' - ); - const insertLine = startLine + 1; - // new content - const newString = this.extractContent(oContent); + let lineToStart = targetIndent + '"' + lastElement + '": '; - const aNewLines = newString.split("\n").filter(Boolean); + if (typeof oContent === "object") { + lineToStart += "{"; - // insert - let lastPos = insertLine; - aNewLines.forEach(newLine => { - this.contentLines.splice(lastPos++, 0, targetIndent + newLine); - }); + this.contentLines.splice(startLine, 0, lineToStart); - this.contentLines.splice( - lastPos, - 0, - targetIndent + "}" + (commaRequired ? "," : "") - ); + 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 { diff --git a/test/addI18n/project/Component.js b/test/addI18n/project/Component.js index ed2e01b6..447d814d 100644 --- a/test/addI18n/project/Component.js +++ b/test/addI18n/project/Component.js @@ -1,28 +1,15 @@ sap.ui.define([ - "sap/ui/core/UIComponent", - "sap/ui/model/json/JSONModel", - "./services/SampleServices" -], function (UIComponent, JSONModel, SampleServices) { + "sap/ui/core/UIComponent" +], function (UIComponent) { "use strict"; - return UIComponent.extend("sap.f.cardsVisualTests.Component", { + return UIComponent.extend("supi.theTests.Component", { metadata : { manifest: "json" }, init: function () { // call the init function of the parent UIComponent.prototype.init.apply(this, arguments); - - // create the views based on the url/hash - this.getRouter().initialize(); - - var oModel = new JSONModel(); - oModel.loadData("./cardsVisualTests/model/examples.json"); - this.setModel(oModel); - - var oCardManifests = new JSONModel(); - oCardManifests.loadData("./cardsVisualTests/model/cardManifests.json"); - this.setModel(oCardManifests, "manifests"); } }); diff --git a/test/addI18n/project/manifest.expected.json b/test/addI18n/project/manifest.expected.json index 8692319d..eccfc501 100644 --- a/test/addI18n/project/manifest.expected.json +++ b/test/addI18n/project/manifest.expected.json @@ -1,7 +1,7 @@ { - "_version": "1.8.0", + "_version": "1.21.0", "sap.app": { - "id": "sap.f.cardsVisualTests", + "id": "supi.theTests", "type": "application", "i18n": { "bundleUrl": "i18n/i18n.properties", @@ -25,14 +25,6 @@ } }, "sap.ui5": { - "services": { - "UserRecent": { - "factoryName": "cardsVisualTests.service.UserRecentFactory" - }, - "Navigation": { - "factoryName": "cardsVisualTests.service.SampleNavigationFactory" - } - }, "dependencies": { "minUI5Version": "1.30.0", "libs": { @@ -51,7 +43,7 @@ } }, "rootView": { - "viewName": "sap.f.cardsVisualTests.view.App", + "viewName": "supi.theTests.view.App", "type": "XML", "async": true, "id": "app" @@ -60,7 +52,7 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "sap.f.cardsVisualTests.i18n.i18n", + "bundleName": "supi.theTests.i18n.i18n", "supportedLocales": [ "" ], @@ -68,208 +60,6 @@ }, "preload": true } - }, - "routing": { - "config": { - "routerClass": "sap.m.routing.Router", - "viewType": "XML", - "viewPath": "sap.f.cardsVisualTests.view", - "controlId": "app", - "controlAggregation": "pages", - "transition": "slide", - "bypassed": { - "target": "notFound" - }, - "async": true - }, - "routes": [ - { - "pattern": "", - "name": "appMain", - "target": "main" - }, - { - "pattern": "grid", - "name": "grid", - "target": "grid" - }, - { - "pattern": "zflow", - "name": "zflow", - "target": "zflow" - }, - { - "pattern": "flexibleHeight", - "name": "flexibleHeight", - "target": "flexibleHeight" - }, - { - "pattern": "splitter", - "name": "splitter", - "target": "splitter" - }, - { - "pattern": "nolayout", - "name": "nolayout", - "target": "nolayout" - }, - { - "pattern": "listContent", - "name": "listContent", - "target": "listContent" - }, - { - "pattern": "tableContent", - "name": "tableContent", - "target": "tableContent" - }, - { - "pattern": "objectContent", - "name": "objectContent", - "target": "objectContent" - }, - { - "pattern": "adaptiveContent", - "name": "adaptiveContent", - "target": "adaptiveContent" - }, - { - "pattern": "flp", - "name": "flp", - "target": "flp" - }, { - "pattern": "numericHeader", - "name": "numericHeader", - "target": "numericHeader" - }, - { - "pattern": "analyticalContent", - "name": "analyticalContent", - "target": "analyticalContent" - }, - { - "pattern": "manifest", - "name": "manifest", - "target": "manifest" - }, - { - "pattern": "customContent", - "name": "customContent", - "target": "customContent" - }, - { - "pattern": "gridContainer", - "name": "gridContainer", - "target": "gridContainer" - }, - { - "pattern": "services", - "name": "services", - "target": "services" - }, - { - "pattern": "minHeight", - "name": "minHeight", - "target": "minHeight" - } - ], - "targets": { - "main": { - "viewId": "main", - "viewName": "Main", - "viewLevel": 1 - }, - "grid": { - "viewId": "grid", - "viewName": "Grid", - "viewLevel": 1 - }, - "zflow": { - "viewId": "zflow", - "viewName": "Zflow", - "viewLevel": 1 - }, - "flexibleHeight": { - "viewId": "flexibleHeight", - "viewName": "FlexibleHeight", - "viewLevel": 1 - }, - "splitter": { - "viewId": "splitter", - "viewName": "Splitter", - "viewLevel": 1 - }, - "nolayout": { - "viewId": "nolayout", - "viewName": "NoLayout", - "viewLevel": 1 - }, - "notFound": { - "viewId": "notFound", - "viewName": "NotFound", - "transition": "show" - }, - "listContent": { - "viewId": "listContent", - "viewName": "ListContent", - "viewLevel": 1 - }, - "tableContent": { - "viewId": "tableContent", - "viewName": "TableContent", - "viewLevel": 1 - }, - "objectContent": { - "viewId": "objectContent", - "viewName": "ObjectContent", - "viewLevel": 1 - }, - "adaptiveContent": { - "viewId": "adaptiveContent", - "viewName": "AdaptiveContent", - "viewLevel": 1 - }, - "analyticalContent": { - "viewId": "analyticalContent", - "viewName": "AnalyticalContent", - "viewLevel": 1 - }, - "flp": { - "viewId": "flp", - "viewName": "Flp", - "viewLevel": 1 - }, - "numericHeader": { - "viewId": "numericHeader", - "viewName": "NumericHeader", - "viewLevel": 1 - }, - "manifest": { - "viewId": "manifest", - "viewName": "Manifest", - "viewLevel": 1 - }, - "customContent": { - "viewId": "custom", - "viewName": "Custom", - "viewLevel": 1 - }, - "gridContainer": { - "viewId": "GridContainer", - "viewName": "GridContainer", - "viewLevel": 1 - }, - "services": { - "viewId": "services", - "viewName": "Services", - "viewLevel": 1 - }, - "minHeight": { - "viewId": "minHeight", - "viewName": "MinHeight", - "viewLevel": 1 - } - } } } } \ No newline at end of file diff --git a/test/addI18n/project/manifest.json b/test/addI18n/project/manifest.json index e2809bca..2a91a80c 100644 --- a/test/addI18n/project/manifest.json +++ b/test/addI18n/project/manifest.json @@ -1,7 +1,7 @@ { "_version": "1.8.0", "sap.app": { - "id": "sap.f.cardsVisualTests", + "id": "supi.theTests", "type": "application", "i18n": "i18n/i18n.properties", "title": "{{appTitle}}", @@ -19,14 +19,6 @@ } }, "sap.ui5": { - "services": { - "UserRecent": { - "factoryName": "cardsVisualTests.service.UserRecentFactory" - }, - "Navigation": { - "factoryName": "cardsVisualTests.service.SampleNavigationFactory" - } - }, "dependencies": { "minUI5Version": "1.30.0", "libs": { @@ -45,7 +37,7 @@ } }, "rootView": { - "viewName": "sap.f.cardsVisualTests.view.App", + "viewName": "supi.theTests.view.App", "type": "XML", "async": true, "id": "app" @@ -54,212 +46,10 @@ "i18n": { "type": "sap.ui.model.resource.ResourceModel", "settings": { - "bundleName": "sap.f.cardsVisualTests.i18n.i18n" + "bundleName": "supi.theTests.i18n.i18n" }, "preload": true } - }, - "routing": { - "config": { - "routerClass": "sap.m.routing.Router", - "viewType": "XML", - "viewPath": "sap.f.cardsVisualTests.view", - "controlId": "app", - "controlAggregation": "pages", - "transition": "slide", - "bypassed": { - "target": "notFound" - }, - "async": true - }, - "routes": [ - { - "pattern": "", - "name": "appMain", - "target": "main" - }, - { - "pattern": "grid", - "name": "grid", - "target": "grid" - }, - { - "pattern": "zflow", - "name": "zflow", - "target": "zflow" - }, - { - "pattern": "flexibleHeight", - "name": "flexibleHeight", - "target": "flexibleHeight" - }, - { - "pattern": "splitter", - "name": "splitter", - "target": "splitter" - }, - { - "pattern": "nolayout", - "name": "nolayout", - "target": "nolayout" - }, - { - "pattern": "listContent", - "name": "listContent", - "target": "listContent" - }, - { - "pattern": "tableContent", - "name": "tableContent", - "target": "tableContent" - }, - { - "pattern": "objectContent", - "name": "objectContent", - "target": "objectContent" - }, - { - "pattern": "adaptiveContent", - "name": "adaptiveContent", - "target": "adaptiveContent" - }, - { - "pattern": "flp", - "name": "flp", - "target": "flp" - }, { - "pattern": "numericHeader", - "name": "numericHeader", - "target": "numericHeader" - }, - { - "pattern": "analyticalContent", - "name": "analyticalContent", - "target": "analyticalContent" - }, - { - "pattern": "manifest", - "name": "manifest", - "target": "manifest" - }, - { - "pattern": "customContent", - "name": "customContent", - "target": "customContent" - }, - { - "pattern": "gridContainer", - "name": "gridContainer", - "target": "gridContainer" - }, - { - "pattern": "services", - "name": "services", - "target": "services" - }, - { - "pattern": "minHeight", - "name": "minHeight", - "target": "minHeight" - } - ], - "targets": { - "main": { - "viewId": "main", - "viewName": "Main", - "viewLevel": 1 - }, - "grid": { - "viewId": "grid", - "viewName": "Grid", - "viewLevel": 1 - }, - "zflow": { - "viewId": "zflow", - "viewName": "Zflow", - "viewLevel": 1 - }, - "flexibleHeight": { - "viewId": "flexibleHeight", - "viewName": "FlexibleHeight", - "viewLevel": 1 - }, - "splitter": { - "viewId": "splitter", - "viewName": "Splitter", - "viewLevel": 1 - }, - "nolayout": { - "viewId": "nolayout", - "viewName": "NoLayout", - "viewLevel": 1 - }, - "notFound": { - "viewId": "notFound", - "viewName": "NotFound", - "transition": "show" - }, - "listContent": { - "viewId": "listContent", - "viewName": "ListContent", - "viewLevel": 1 - }, - "tableContent": { - "viewId": "tableContent", - "viewName": "TableContent", - "viewLevel": 1 - }, - "objectContent": { - "viewId": "objectContent", - "viewName": "ObjectContent", - "viewLevel": 1 - }, - "adaptiveContent": { - "viewId": "adaptiveContent", - "viewName": "AdaptiveContent", - "viewLevel": 1 - }, - "analyticalContent": { - "viewId": "analyticalContent", - "viewName": "AnalyticalContent", - "viewLevel": 1 - }, - "flp": { - "viewId": "flp", - "viewName": "Flp", - "viewLevel": 1 - }, - "numericHeader": { - "viewId": "numericHeader", - "viewName": "NumericHeader", - "viewLevel": 1 - }, - "manifest": { - "viewId": "manifest", - "viewName": "Manifest", - "viewLevel": 1 - }, - "customContent": { - "viewId": "custom", - "viewName": "Custom", - "viewLevel": 1 - }, - "gridContainer": { - "viewId": "GridContainer", - "viewName": "GridContainer", - "viewLevel": 1 - }, - "services": { - "viewId": "services", - "viewName": "Services", - "viewLevel": 1 - }, - "minHeight": { - "viewId": "minHeight", - "viewName": "MinHeight", - "viewLevel": 1 - } - } } } } \ 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 index 9dfc4374..2e8914d6 100644 --- a/test/addI18nTest.ts +++ b/test/addI18nTest.ts @@ -78,36 +78,143 @@ function analyseMigrateAndTest( } describe("addI18n", function() { - describe("#start()", function() { - let oStub; - beforeEach(function() { - oStub = sinon.stub(FileUtils, "fsWriteFile").resolves(); - }); + let oStub; + beforeEach(function() { + oStub = sinon.stub(FileUtils, "fsWriteFile").resolves(); + }); - afterEach(function() { - if (oStub) { - oStub.restore(); - } - }); - it("should addMissingDependencies", 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]; - }, + 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, - [] - ); - }); + }, + 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 index 4396f5ec..88ebc06c 100644 --- a/test/util/content/ModifyJSONContentTest.ts +++ b/test/util/content/ModifyJSONContentTest.ts @@ -3,10 +3,10 @@ import {ModifyJSONContent} from "../../../src/util/content/ModifyJSONContent"; const assert = require("assert"); describe("ModifyJSONContent", function() { - it("Should succeed if valid version range was given", function() { + it("Should replace i18n sections", function() { const strContent = `{ "sap.app": { -\t"id": "sap.f.cardsVisualTests", +\t"id": "supi.theTests", \t"type": "application", \t"i18n": "i18n/i18n.properties", \t"title": "{{appTitle}}" @@ -16,7 +16,7 @@ describe("ModifyJSONContent", function() { \t "i18n": { \t\t"type": "sap.ui.model.resource.ResourceModel", \t\t"settings": { -\t\t "bundleName": "sap.f.cardsVisualTests.i18n.i18n" +\t\t "bundleName": "supi.theTests.i18n.i18n" \t\t}, \t\t"preload": true \t } @@ -27,15 +27,15 @@ describe("ModifyJSONContent", function() { const strContentExpected = `{ "sap.app": { -\t"id": "sap.f.cardsVisualTests", +\t"id": "supi.theTests", \t"type": "application", \t"i18n": { -\t "bundleUrl": "i18n/i18n.properties", -\t "supportedLocales": [ -\t "de", -\t "en" -\t ], -\t "fallbackLocale": "de" +\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}}" }, @@ -44,10 +44,10 @@ describe("ModifyJSONContent", function() { \t "i18n": { \t\t"type": "sap.ui.model.resource.ResourceModel", \t\t"settings": { -\t\t "bundleName": "sap.f.cardsVisualTests.i18n.i18n", +\t\t "bundleName": "supi.theTests.i18n.i18n", \t\t "supportedLocales": [ -\t\t "de", -\t\t "en" +\t\t \t"de", +\t\t \t"en" \t\t ], \t\t "fallbackLocale": "de" \t\t}, @@ -75,4 +75,74 @@ describe("ModifyJSONContent", function() { 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); + }); });