@sap/cds 8.8.3 → 8.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/CHANGELOG.md +40 -4
  2. package/_i18n/i18n_en_US_saptrc.properties +3 -0
  3. package/bin/colors.js +2 -0
  4. package/bin/test.js +103 -75
  5. package/eslint.config.mjs +16 -4
  6. package/lib/compile/for/lean_drafts.js +4 -0
  7. package/lib/compile/parse.js +26 -6
  8. package/lib/env/cds-env.js +3 -1
  9. package/lib/env/cds-requires.js +0 -3
  10. package/lib/env/schemas/cds-rc.js +11 -0
  11. package/lib/log/format/aspects/cls.js +2 -1
  12. package/lib/log/format/json.js +1 -1
  13. package/lib/plugins.js +2 -3
  14. package/lib/ql/SELECT.js +2 -1
  15. package/lib/ql/cds-ql.js +2 -0
  16. package/lib/ql/cds.ql-predicates.js +6 -4
  17. package/lib/ql/resolve.js +46 -0
  18. package/lib/req/validate.js +1 -0
  19. package/lib/srv/bindings.js +64 -43
  20. package/lib/srv/cds-connect.js +1 -1
  21. package/lib/srv/cds-serve.js +2 -2
  22. package/lib/srv/middlewares/auth/ias-auth.js +2 -0
  23. package/lib/srv/protocols/http.js +2 -2
  24. package/lib/srv/protocols/index.js +1 -1
  25. package/lib/srv/protocols/odata-v4.js +0 -1
  26. package/lib/srv/srv-tx.js +1 -1
  27. package/lib/test/cds-test.js +3 -4
  28. package/lib/utils/cds-utils.js +19 -19
  29. package/lib/utils/colors.js +46 -45
  30. package/lib/utils/csv-reader.js +5 -5
  31. package/libx/_runtime/cds-services/adapter/odata-v4/handlers/read.js +1 -2
  32. package/libx/_runtime/cds-services/adapter/odata-v4/odata-to-cqn/index.js +1 -1
  33. package/libx/_runtime/common/Service.js +4 -2
  34. package/libx/_runtime/common/composition/data.js +1 -2
  35. package/libx/_runtime/common/composition/tree.js +6 -4
  36. package/libx/_runtime/common/generic/sorting.js +6 -2
  37. package/libx/_runtime/common/utils/cqn2cqn4sql.js +6 -7
  38. package/libx/_runtime/common/utils/differ.js +1 -1
  39. package/libx/_runtime/common/utils/draft.js +1 -1
  40. package/libx/_runtime/common/utils/foreignKeyPropagations.js +6 -2
  41. package/libx/_runtime/common/utils/keys.js +13 -84
  42. package/libx/_runtime/common/utils/propagateForeignKeys.js +4 -3
  43. package/libx/_runtime/common/utils/resolveView.js +96 -102
  44. package/libx/_runtime/common/utils/rewriteAsterisks.js +1 -1
  45. package/libx/_runtime/common/utils/stream.js +2 -3
  46. package/libx/_runtime/db/utils/columns.js +1 -1
  47. package/libx/_runtime/fiori/lean-draft.js +11 -7
  48. package/libx/_runtime/messaging/kafka.js +3 -4
  49. package/libx/_runtime/remote/Service.js +13 -5
  50. package/libx/_runtime/remote/utils/client.js +1 -0
  51. package/libx/_runtime/ucl/Service.js +135 -126
  52. package/libx/common/utils/path.js +34 -22
  53. package/libx/odata/middleware/create.js +2 -0
  54. package/libx/odata/middleware/operation.js +8 -2
  55. package/libx/odata/middleware/parse.js +1 -1
  56. package/libx/odata/middleware/stream.js +1 -2
  57. package/libx/odata/middleware/update.js +2 -0
  58. package/libx/odata/parse/afterburner.js +17 -9
  59. package/libx/odata/parse/cqn2odata.js +3 -1
  60. package/libx/odata/parse/grammar.peggy +21 -19
  61. package/libx/odata/parse/parser.js +1 -1
  62. package/libx/odata/utils/metadata.js +8 -2
  63. package/libx/odata/utils/odataBind.js +36 -0
  64. package/libx/outbox/index.js +1 -0
  65. package/libx/rest/middleware/operation.js +9 -8
  66. package/libx/rest/middleware/parse.js +1 -0
  67. package/package.json +3 -3
  68. package/lib/i18n/resources.js +0 -150
@@ -1,150 +0,0 @@
1
- const cds = require('..'), { path } = cds.utils
2
- const LOG = cds.log('i18n')
3
-
4
- /**
5
- * Instances of this class are used to fetch and read i18n resources from the file system.
6
- */
7
- class I18nResources {
8
-
9
- constructor (options) {
10
- for (let each in options) super[each] = options[each]
11
- }
12
-
13
-
14
- /**
15
- * The folders to search for i18n files in. By default a shortcut to i18n.folders
16
- * config but can be specified in constructor.
17
- */
18
- get folders() {
19
- return super.folders = cds.env.i18n.folders
20
- }
21
-
22
-
23
- /**
24
- * Returns the files basename to read properties from; default is `'i18n'`.
25
- * @returns {string}
26
- */
27
- get file() {
28
- return super.file ??= cds.env.i18n.file
29
- }
30
-
31
-
32
- /**
33
- * Fetches all i18n files matching {@link file basename} in {@link folders} up to {@link roots}.
34
- * @returns {Record<string,string[]>} a dictionary of files by folders.
35
- */
36
- get files() {
37
-
38
- // prepare the things we need below...
39
- const { existsSync: exists, readdirSync: readdir } = cds.utils.fs
40
- const _folders = I18nResources.folders ??= {}
41
- const _entries = I18nResources.entries ??= {}
42
- const basename = RegExp(`${this.file}[._]`)
43
- const files_by_folders = {} // the result to be returned
44
-
45
- // fetch relatively specified i18n.folders in the neighborhood of sources...
46
- const relative_folders = this.folders.filter (f => f[0] !== '/')
47
- if (relative_folders.length) {
48
- const visited = {}, roots = this.roots, $sources = this.model?.$sources
49
- const $sourcedirs = $sources ? [ ...new Set($sources.map(path.dirname)) ].reverse() : [ cds.home, cds.root ]
50
- $sourcedirs.forEach (function _visit (dir) {
51
- if (dir in visited) return; else visited[dir] = true
52
- LOG.debug ('searching for i18n files in the neighborhood of', dir)
53
- // is there an i18n folder in the currently visited directory?
54
- for (let each of relative_folders) {
55
- const f = path.join(dir,each), _exists = _folders[f] ??= exists(f)
56
- if (_exists && _add_entries4(f)) return // stop at first match from i18n.folders
57
- }
58
- // else recurse up the folder hierarchy till reaching package roots ...
59
- if (roots.includes(dir) || exists(path.join(dir,'package.json'))) return
60
- else _visit (path.dirname(dir))
61
- })
62
- }
63
-
64
- // fetch fully specified i18n.folders, i.e., those starting with /
65
- const specific_folders = this.folders.filter (f => f[0] === '/')
66
- for (let f of specific_folders) {
67
- const _exists = _folders[f] ??= exists(f)
68
- _add_entries4 (_exists ? f : path.join(cds.root,f))
69
- }
70
-
71
- // helper to add matching files from found folder, if any
72
- function _add_entries4 (f) {
73
- const files = (_entries[f] ??= readdir(f)) .filter (f => f.match(basename))
74
- if (files.length) return files_by_folders[f] = files
75
- }
76
-
77
- // finally return the collected files by folders
78
- super.folders = Object.keys (files_by_folders)
79
- return super.files = files_by_folders
80
- }
81
-
82
-
83
- /**
84
- * The root directories up to which to search for {@link files `i18n.files`}.
85
- */
86
- get roots() {
87
- return super.roots = [ cds.env.i18n.root || cds.root ]
88
- }
89
-
90
-
91
- /**
92
- * Returns all locales for which translations are available in this.{@link files}.
93
- * @returns {string[]}
94
- */
95
- get locales() {
96
- const unique_locales = new Set(), {path} = cds.utils
97
- for (let [folder,files] of Object.entries(this.files)) {
98
- for (let file of files) {
99
- const { name, ext } = path.parse (file); switch (ext) {
100
- case '.properties': unique_locales.add(/(?:_(\w+))?$/.exec(name)?.[1]||''); break
101
- case '.json': for (let locale in _load_json(path.join(folder,file))) unique_locales.add(locale); break
102
- case '.csv': return _load_csv (path.join(folder,file))[0].slice(1)
103
- }
104
- }
105
- }
106
- return super.locales = [...unique_locales]
107
- }
108
-
109
-
110
- /**
111
- * Loads content from all files for the given locale.
112
- * @returns {entries[]} An array of entries, one for each file found.
113
- */
114
- content4 (locale, suffix = locale?.replace(/-/g,'_')) {
115
- const content = [], { file, files } = this
116
- for (let folder in files) {
117
- const all = this.content4[folder] ??= _load('json',folder) || _load('csv',folder)
118
- if (all) { if (locale in all) content.push (all[locale]); continue }
119
- const props = _load ('properties', folder, file + (suffix ? '_'+suffix : ''))
120
- if (props) content.push (props)
121
- }
122
- function _load (kind, folder, basename = file) {
123
- const entry = `${basename}.${kind}`; if (!files[folder].includes(entry)) return
124
- const file = path.join (folder, entry)
125
- try { switch (kind) {
126
- case 'properties': return _load_properties (file)
127
- case 'json': return _load_json (file)
128
- case 'csv': return _load_csv (file)
129
- }} finally {
130
- LOG.debug ('read:', file)
131
- }
132
- }
133
- return content
134
- }
135
- }
136
-
137
-
138
- const _load_properties = cds.load.properties
139
- const _load_json = require
140
- const _load_csv = file => {
141
- const csv = cds.load.csv(file); if (!csv) return
142
- const [ header, ...rows ] = csv, all = {}
143
- header.slice(1).forEach ((lang,i) => {
144
- const entries = all[lang] = {}
145
- for (let row of rows) if (row[i]) entries[row[0]] = row[i]
146
- })
147
- return all
148
- }
149
-
150
- module.exports = I18nResources