From c78fc1a270c8e79167f4a618b4ec7b83a65826fd Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Tue, 10 Mar 2026 14:33:54 +0100 Subject: [PATCH 1/4] feat(dts-generator): add getMessagesByPath declarations and tests to TypedJSONModel --- .../typed-json-model/webapp/model/model.ts | 5 +++ .../webapp/model/test/cases/edgeCases.ts | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/test-packages/typed-json-model/webapp/model/model.ts b/test-packages/typed-json-model/webapp/model/model.ts index a3b70ad..d951928 100644 --- a/test-packages/typed-json-model/webapp/model/model.ts +++ b/test-packages/typed-json-model/webapp/model/model.ts @@ -6,6 +6,7 @@ import { PropertyByRelativeBindingPath, RelativeBindingPath, } from "./typing"; +import Message from "sap/ui/core/message/Message"; export class TypedJSONContext> extends Context { constructor(oModel: TypedJSONModel, sPath: Root) { @@ -43,6 +44,10 @@ export class TypedJSONModel extends JSONModel { return super.getData() as Data; } + getMessagesByPath>(sPath: Path, bPrefixMatch?: boolean): Message[] { + return super.getMessagesByPath(sPath, bPrefixMatch); + } + getProperty>(sPath: Path): PropertyByAbsoluteBindingPath; getProperty, Root extends AbsoluteBindingPath>( sPath: Path, diff --git a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts index 43fe5e6..6f4f4b3 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts @@ -2,6 +2,7 @@ * @file Various edge cases to test the TypedJSONModel */ +import Message from "sap/ui/core/message/Message"; import { TypedJSONModel } from "../../model"; /*********************************************************************************************************************** @@ -65,3 +66,34 @@ const model4 = new TypedJSONModel(edgeCase); /** @expect ok */ model4.setProperty("/anIntersection", { a: 1, b: "b" }); /** @expect ts2345 */ model4.setProperty("/anIntersection", { a: 1 }); /** @expect ts2322 */ model4.setProperty("/anIntersection", { a: 1, b: 2 }); + +/*********************************************************************************************************************** + * Check model.getMessagesByPath + **********************************************************************************************************************/ + +const data = { + aString: "string", + anObject: { a: "foo" }, + anArray: [], + anArrayOfObjects: [{ aNumber: 1 }], +}; + +const model5 = new TypedJSONModel(data); + +/** @expect ok */ model5.getMessagesByPath("/aString"); +/** @expect ok */ model5.getMessagesByPath("/aString", true); + +/** @expect ok */ const messages: Message[] = model5.getMessagesByPath("/anObject"); +/** @expect ok */ model5.getMessagesByPath("/anObject", true); + +/** @expect ok */ model5.getMessagesByPath("/anObject/a"); +/** @expect ok */ model5.getMessagesByPath("/anObject/a", true); + +/** @expect ok */ model5.getMessagesByPath("/anArrayOfObjects/0/aNumber"); +/** @expect ok */ model5.getMessagesByPath("/anArrayOfObjects/0/aNumber", true); + +/** @expect ts2345 */ model5.getMessagesByPath("anObject"); +/** @expect ts2345 */ model5.getMessagesByPath("anObject", true); + +/** @expect ts2345 */ model5.getMessagesByPath("/anArray/0/doesNotExist"); +/** @expect ts2345 */ model5.getMessagesByPath("/anArray/0/doesNotExist", true); From a4faa4d5204d29bab13182039d76e57257da031f Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Tue, 10 Mar 2026 14:37:55 +0100 Subject: [PATCH 2/4] chore(dts-generator): adds getMessagesByPath declaration --- packages/dts-generator/src/resources/typed-json-model.d.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/dts-generator/src/resources/typed-json-model.d.ts b/packages/dts-generator/src/resources/typed-json-model.d.ts index 5d33d33..0475449 100644 --- a/packages/dts-generator/src/resources/typed-json-model.d.ts +++ b/packages/dts-generator/src/resources/typed-json-model.d.ts @@ -2,6 +2,7 @@ declare module "sap/ui/model/json/TypedJSONModel" { import JSONModel from "sap/ui/model/json/JSONModel"; import TypedJSONContext from "sap/ui/model/json/TypedJSONContext"; import Context from "sap/ui/model/Context"; + import Message from "sap/ui/core/message/Message"; /** * TypedJSONModel is a subclass of JSONModel that provides type-safe access to the model data. It is only available when using UI5 with TypeScript. @@ -19,6 +20,10 @@ declare module "sap/ui/model/json/TypedJSONModel" { bReload?: boolean, ): TypedJSONContext; getData(): Data; + getMessagesByPath>( + sPath: Path, + bPrefixMatch?: boolean, + ): Message[]; getProperty>( sPath: Path, ): PropertyByAbsoluteBindingPath; From 969ba945fe8f4d8885094897a90033afabb15df0 Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Thu, 9 Apr 2026 14:22:32 +0200 Subject: [PATCH 3/4] chore(dts-generator): apply changes of other pull requests to reduce merge conflicts --- test-packages/typed-json-model/package.json | 2 +- test-packages/typed-json-model/tsconfig.json | 3 +- .../webapp/model/test/cases/edgeCases.ts | 31 --------- .../webapp/model/test/cases/general.ts | 38 +++++++++++ yarn.lock | 63 +++++-------------- 5 files changed, 55 insertions(+), 82 deletions(-) create mode 100644 test-packages/typed-json-model/webapp/model/test/cases/general.ts diff --git a/test-packages/typed-json-model/package.json b/test-packages/typed-json-model/package.json index 290cf06..dfc18d1 100644 --- a/test-packages/typed-json-model/package.json +++ b/test-packages/typed-json-model/package.json @@ -16,7 +16,7 @@ "ci": "npm run lint && npm run ui5lint && npm run ts-typecheck && npm run test" }, "devDependencies": { - "@types/openui5": "1.136.0", + "@openui5/types": "^1.146.0", "@ui5/cli": "^4.0.30", "@ui5/linter": "^1.20.2", "eslint": "^9.37.0", diff --git a/test-packages/typed-json-model/tsconfig.json b/test-packages/typed-json-model/tsconfig.json index eca45e6..182cca5 100644 --- a/test-packages/typed-json-model/tsconfig.json +++ b/test-packages/typed-json-model/tsconfig.json @@ -11,7 +11,8 @@ "baseUrl": "./", "paths": {}, "composite": true, - "outDir": "./dist" + "outDir": "./dist", + "types": ["@openui5/types"] }, "include": ["./webapp/**/*"], "exclude": ["./**/*.mjs", "./webapp/**/test/**"] diff --git a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts index 6f4f4b3..7541c69 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts @@ -66,34 +66,3 @@ const model4 = new TypedJSONModel(edgeCase); /** @expect ok */ model4.setProperty("/anIntersection", { a: 1, b: "b" }); /** @expect ts2345 */ model4.setProperty("/anIntersection", { a: 1 }); /** @expect ts2322 */ model4.setProperty("/anIntersection", { a: 1, b: 2 }); - -/*********************************************************************************************************************** - * Check model.getMessagesByPath - **********************************************************************************************************************/ - -const data = { - aString: "string", - anObject: { a: "foo" }, - anArray: [], - anArrayOfObjects: [{ aNumber: 1 }], -}; - -const model5 = new TypedJSONModel(data); - -/** @expect ok */ model5.getMessagesByPath("/aString"); -/** @expect ok */ model5.getMessagesByPath("/aString", true); - -/** @expect ok */ const messages: Message[] = model5.getMessagesByPath("/anObject"); -/** @expect ok */ model5.getMessagesByPath("/anObject", true); - -/** @expect ok */ model5.getMessagesByPath("/anObject/a"); -/** @expect ok */ model5.getMessagesByPath("/anObject/a", true); - -/** @expect ok */ model5.getMessagesByPath("/anArrayOfObjects/0/aNumber"); -/** @expect ok */ model5.getMessagesByPath("/anArrayOfObjects/0/aNumber", true); - -/** @expect ts2345 */ model5.getMessagesByPath("anObject"); -/** @expect ts2345 */ model5.getMessagesByPath("anObject", true); - -/** @expect ts2345 */ model5.getMessagesByPath("/anArray/0/doesNotExist"); -/** @expect ts2345 */ model5.getMessagesByPath("/anArray/0/doesNotExist", true); diff --git a/test-packages/typed-json-model/webapp/model/test/cases/general.ts b/test-packages/typed-json-model/webapp/model/test/cases/general.ts new file mode 100644 index 0000000..826863a --- /dev/null +++ b/test-packages/typed-json-model/webapp/model/test/cases/general.ts @@ -0,0 +1,38 @@ +/** + * @file Various general test cases to test the TypedJSONModel for APIs which always return the same type, + * regardless of the provided path (e.g. getObject, getPath, etc.) + */ + +import { TypedJSONModel } from "../../model"; +import Message from "sap/ui/core/message/Message"; + +/*********************************************************************************************************************** + * getMessagesByPath - Only absolute paths are supported + **********************************************************************************************************************/ + +const data = { + aString: "string", + anObject: { a: "foo" }, + anArray: [], + anArrayOfObjects: [{ aNumber: 1 }], +}; + +const model2 = new TypedJSONModel(data); + +/** @expect ok */ model2.getMessagesByPath("/aString"); +/** @expect ok */ model2.getMessagesByPath("/aString", true); + +/** @expect ok */ const messages: Message[] = model2.getMessagesByPath("/anObject"); +/** @expect ok */ model2.getMessagesByPath("/anObject", true); + +/** @expect ok */ model2.getMessagesByPath("/anObject/a"); +/** @expect ok */ model2.getMessagesByPath("/anObject/a", true); + +/** @expect ok */ model2.getMessagesByPath("/anArrayOfObjects/0/aNumber"); +/** @expect ok */ model2.getMessagesByPath("/anArrayOfObjects/0/aNumber", true); + +/** @expect ts2345 */ model2.getMessagesByPath("anObject"); +/** @expect ts2345 */ model2.getMessagesByPath("anObject", true); + +/** @expect ts2345 */ model2.getMessagesByPath("/anArray/0/doesNotExist"); +/** @expect ts2345 */ model2.getMessagesByPath("/anArray/0/doesNotExist", true); diff --git a/yarn.lock b/yarn.lock index 6d38843..dc503b8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2361,6 +2361,14 @@ dependencies: "@octokit/openapi-types" "^24.2.0" +"@openui5/types@^1.146.0": + version "1.146.0" + resolved "https://registry.yarnpkg.com/@openui5/types/-/types-1.146.0.tgz#f3f035bc0f4e25f23acfeba888b927347fb3b336" + integrity sha512-6jzQ54BIpOQEL8+46u2WsaR9gFcjyEaKphUlAS82Pt60OOW8p2xpmTknFRRZDgBmP4IbZZob9nLb82MNGMRTSw== + dependencies: + "@types/jquery" "3.5.13" + "@types/qunit" "2.5.4" + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -2811,14 +2819,6 @@ "@types/jquery" "~3.5.13" "@types/qunit" "^2.5.4" -"@types/openui5@1.136.0": - version "1.136.0" - resolved "https://registry.yarnpkg.com/@types/openui5/-/openui5-1.136.0.tgz#9cada8f12d5d03d03f4975553cb763da2e7fa104" - integrity sha512-gdjK8/bYKsdZUiinARbYW+B6sbAVo0B4KLbHMs/noBzx2wfUoHOb9DiS+lpBpjtfD28NyiluReCp2R4kp7fceA== - dependencies: - "@types/jquery" "~3.5.13" - "@types/qunit" "^2.5.4" - "@types/qunit@2.5.4": version "2.5.4" resolved "https://registry.yarnpkg.com/@types/qunit/-/qunit-2.5.4.tgz#0518940acc6013259a8619a1ec34ce0e4ff8d1c4" @@ -3008,7 +3008,7 @@ yargs "^17.7.2" "@ui5/dts-generator@link:packages/dts-generator": - version "3.9.1" + version "3.10.1" dependencies: "@definitelytyped/dtslint" latest "@definitelytyped/eslint-plugin" latest @@ -10948,7 +10948,7 @@ string-length@^4.0.2: char-regex "^1.0.2" strip-ansi "^6.0.0" -"string-width-cjs@npm:string-width@^4.2.0": +"string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -10966,15 +10966,6 @@ string-width@^1.0.1: is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - string-width@^5.0.1, string-width@^5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-5.1.2.tgz#14f8daec6d81e7221d2a357e668cab73bdbca794" @@ -11062,7 +11053,7 @@ string_decoder@~1.1.1: dependencies: safe-buffer "~5.1.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1": +"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -11076,13 +11067,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - strip-ansi@^7.0.1, strip-ansi@^7.1.0: version "7.1.2" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-7.1.2.tgz#132875abde678c7ea8d691533f2e7e22bb744dba" @@ -11561,7 +11545,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.2.2.tgz#5ebb5e5a5b75f085f22bc3f8460fba308310fa78" integrity sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w== -"typescript-5.3@npm:typescript@~5.3.0-0": +"typescript-5.3@npm:typescript@~5.3.0-0", typescript@5.3.3: version "5.3.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== @@ -11591,7 +11575,7 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.3.tgz#92f8a3e5e3cf497356f4178c34cd65a7f5e8440e" integrity sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ== -"typescript-5.9@npm:typescript@~5.9.0-0": +"typescript-5.9@npm:typescript@~5.9.0-0", typescript@5.9.3, "typescript@>=3 < 6", typescript@^5.9.3: version "5.9.3" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== @@ -11611,21 +11595,11 @@ typescript-eslint@^8.46.1: "@typescript-eslint/typescript-estree" "8.46.1" "@typescript-eslint/utils" "8.46.1" -typescript@5.3.3: - version "5.3.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.3.tgz#b3ce6ba258e72e6305ba66f5c9b452aaee3ffe37" - integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== - typescript@5.8.2: version "5.8.2" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4" integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ== -typescript@5.9.3, "typescript@>=3 < 6", typescript@^5.9.3: - version "5.9.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.9.3.tgz#5b4f59e15310ab17a216f5d6cf53ee476ede670f" - integrity sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw== - uc.micro@^2.0.0, uc.micro@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-2.1.0.tgz#f8d3f7d0ec4c3dea35a7e3c8efa4cb8b45c9e7ee" @@ -12075,7 +12049,7 @@ workerpool@^9.2.0, workerpool@^9.3.4: resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-9.3.4.tgz#f6c92395b2141afd78e2a889e80cb338fe9fca41" integrity sha512-TmPRQYYSAnnDiEB0P/Ytip7bFGvqnSU6I2BcuSw7Hx+JSg/DsUi5ebYfc8GYaSdpuvOcEs6dXxPurOYpe9QFwg== -"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0": +"wrap-ansi-cjs@npm:wrap-ansi@^7.0.0", wrap-ansi@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== @@ -12093,15 +12067,6 @@ wrap-ansi@^6.2.0: string-width "^4.1.0" strip-ansi "^6.0.0" -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - wrap-ansi@^8.1.0: version "8.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-8.1.0.tgz#56dc22368ee570face1b49819975d9b9a5ead214" From c2b4f753a97b059f8971b6e0e6639d6edeaa7e7c Mon Sep 17 00:00:00 2001 From: viktorsperling Date: Thu, 9 Apr 2026 14:24:09 +0200 Subject: [PATCH 4/4] chore(dts-generator): remove unnecessary imports --- .../typed-json-model/webapp/model/test/cases/edgeCases.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts index 7541c69..43fe5e6 100644 --- a/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts +++ b/test-packages/typed-json-model/webapp/model/test/cases/edgeCases.ts @@ -2,7 +2,6 @@ * @file Various edge cases to test the TypedJSONModel */ -import Message from "sap/ui/core/message/Message"; import { TypedJSONModel } from "../../model"; /***********************************************************************************************************************