@sap/cds-dk 10.0.5 → 10.0.7

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 (58) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/bin/export.js +1 -1
  3. package/bin/version.js +7 -3
  4. package/lib/build/plugins/hana/index.js +19 -2
  5. package/lib/import/asyncapi/parserContext.js +136 -54
  6. package/lib/init/projectReader.js +4 -2
  7. package/lib/init/template/ams/files/package.json.hbs +1 -1
  8. package/lib/init/template/nodejs/index.js +4 -2
  9. package/lib/init/template/test/files/test/test.xs.hbs +3 -2
  10. package/lib/init/template/xsuaa/index.js +11 -7
  11. package/node_modules/@cap-js/openapi/lib/compile/csdl.js +3 -3
  12. package/node_modules/@cap-js/openapi/lib/compile/csdl2openapi.js +111 -103
  13. package/node_modules/@cap-js/openapi/lib/compile/diagram.js +4 -4
  14. package/node_modules/@cap-js/openapi/lib/compile/types.d.ts +3 -1
  15. package/node_modules/@cap-js/openapi/package.json +3 -3
  16. package/node_modules/@sap/cds/CHANGELOG.md +16 -0
  17. package/node_modules/@sap/cds/lib/compile/for/nodejs.js +1 -0
  18. package/node_modules/@sap/cds/lib/env/defaults.js +1 -0
  19. package/node_modules/@sap/cds/lib/plugins.js +4 -2
  20. package/node_modules/@sap/cds/lib/srv/srv-handlers.js +1 -1
  21. package/node_modules/@sap/cds/libx/_runtime/common/Service.js +1 -1
  22. package/node_modules/@sap/cds/libx/_runtime/messaging/common-utils/authorizedRequest.js +3 -2
  23. package/node_modules/@sap/cds/libx/_runtime/remote/Service.js +1 -1
  24. package/node_modules/@sap/cds/package.json +1 -1
  25. package/node_modules/@sap/cds-compiler/CHANGELOG.md +12 -0
  26. package/node_modules/@sap/cds-compiler/lib/compiler/populate.js +1 -0
  27. package/node_modules/@sap/cds-compiler/lib/compiler/resolve.js +1 -1
  28. package/node_modules/@sap/cds-compiler/lib/model/csnUtils.js +13 -8
  29. package/node_modules/@sap/cds-compiler/package.json +1 -1
  30. package/node_modules/@sap/cds-mtxs/CHANGELOG.md +36 -0
  31. package/node_modules/@sap/cds-mtxs/bin/cds-mtx-migrate.js +32 -48
  32. package/node_modules/@sap/cds-mtxs/bin/cds-mtx.js +1 -0
  33. package/node_modules/@sap/cds-mtxs/cds-plugin.js +18 -0
  34. package/node_modules/@sap/cds-mtxs/lib/migration/migration.js +3 -408
  35. package/node_modules/@sap/cds-mtxs/package.json +1 -1
  36. package/node_modules/@sap/cds-mtxs/srv/cf/abstract-provisioning-service.js +5 -6
  37. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/annotations.js +5 -2
  38. package/node_modules/@sap/cds-mtxs/srv/extensibility/linter/index.js +6 -5
  39. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.cds +0 -11
  40. package/node_modules/@sap/cds-mtxs/srv/extensibility-service.js +12 -22
  41. package/node_modules/@sap/cds-mtxs/srv/jobs-service.js +30 -24
  42. package/node_modules/@sap/cds-mtxs/srv/model-provider.js +2 -2
  43. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/ctnr-mgr-base.js +5 -2
  44. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/hdi.js +5 -3
  45. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/srv-mgr.js +3 -2
  46. package/node_modules/@sap/cds-mtxs/srv/plugins/hana/tms.js +17 -0
  47. package/node_modules/@sap/cds-mtxs/srv/plugins/hana.js +14 -13
  48. package/node_modules/media-typer/README.md +15 -14
  49. package/node_modules/media-typer/index.js +0 -8
  50. package/node_modules/media-typer/package.json +16 -12
  51. package/node_modules/sax/lib/sax.js +27 -9
  52. package/node_modules/sax/package.json +1 -1
  53. package/node_modules/ws/package.json +1 -1
  54. package/package.json +4 -4
  55. package/lib/init/template/nodejs/files/.gitignore.hbs +0 -34
  56. package/node_modules/@sap/cds-mtxs/lib/migration/extension-project-builder.js +0 -129
  57. package/node_modules/@sap/cds-mtxs/lib/migration/extension-project.js +0 -89
  58. package/node_modules/@sap/cds-mtxs/lib/migration/mtx-adapter.js +0 -230
@@ -1,129 +0,0 @@
1
- const path = require('path')
2
- const fs = require('fs')
3
- const cds = require('@sap/cds')
4
- const DEBUG = cds.debug('mtx') //Note: cds.debug returns false for @sap/cds@(< 6.2)
5
-
6
- module.exports.build = async function (options) {
7
- const { project } = options
8
- const env = cds.env
9
- const root = cds.root
10
- try {
11
- cds.root = project
12
- cds.env = cds.env.for('cds', project)
13
- options.dest = path.join(project, cds.env.build.target, 'ext')
14
- await new ExtensionBuilder(options).run()
15
- } finally {
16
- cds.root = root
17
- cds.env = env
18
- }
19
- }
20
-
21
- class ExtensionBuilder {
22
- constructor(options) {
23
- this._files = []
24
- this._options = options
25
- }
26
-
27
- async run() {
28
- const { project, dest } = this._options
29
-
30
- // clean any existing content
31
- await fs.promises.rm(dest, { force: true, recursive: true })
32
-
33
- // check existence of appPackage folder only
34
- const appPackageFolder = this._getAppPackageFolder()
35
- if (!fs.existsSync(path.join(project, appPackageFolder))) {
36
- throw new Error(`The SaaS application base model '${appPackageFolder}' is missing.`)
37
- }
38
-
39
- // full compile of the extension using base model - ensuring consistency
40
- const modelFolders = cds.resolve('*', false).filter(p => !p.startsWith('@sap/cds-mtx'))
41
- DEBUG && DEBUG(`Extension model folders: ${modelFolders}`)
42
-
43
- // throws an error if no model is found -> e.code === MODEL_NOT_FOUND
44
- const model = await cds.load(modelFolders)
45
-
46
- // extension CSN using parsed format
47
- const extModel = await cds.load(this._resolveExtensionFiles(model, project), { flavor: 'parsed' })
48
- if (extModel.requires) {
49
- extModel.requires.length = 0
50
- }
51
-
52
- const csn = cds.compile.to.json(extModel)
53
- await this._write(csn, path.join(dest, 'extension.csn'))
54
- await this._collectLanguageBundles(extModel, path.join(dest, 'i18n'))
55
-
56
- const files = Object.keys(await cds.deploy.resources(model))
57
- if (files.length > 0) {
58
- const dataDest = path.join(dest, 'data')
59
- await Promise.all(
60
- files
61
- .filter(file => /\.csv$/.test(file))
62
- .map(csv => this._copy(csv, path.join(dataDest, path.basename(csv))))
63
- )
64
- }
65
- await this._copy(path.join(project, 'package.json'), path.join(dest, 'package.json'))
66
- // add all resources contained in 'gen/ext' folder
67
- await this._writeTarFile(path.join(project, cds.env.build.target, 'extension.tgz'), dest)
68
-
69
- DEBUG && DEBUG('build output:\n' + this._files.map(file => ` ${path.relative(project, file)}`).join('\n'))
70
- }
71
-
72
- _getAppPackageFolder() {
73
- return path.join('node_modules', cds.env.extends || '_base');
74
- }
75
-
76
- _resolveExtensionFiles(model, project) {
77
- const node_modules = path.join(project, 'node_modules')
78
- const paths = model['$sources'].reduce((acc, file) => {
79
- if (file.startsWith(project) && !file.startsWith(node_modules)) {
80
- acc.push(file)
81
- }
82
- return acc
83
- }, [])
84
-
85
- return paths
86
- }
87
-
88
- async _write(data, dest) {
89
- this._files.push(dest)
90
- await fs.promises.mkdir(path.dirname(dest), { recursive: true })
91
- await fs.promises.writeFile(dest, typeof data === "object" && !Buffer.isBuffer(data) ? JSON.stringify(data, null, 2) : data)
92
- }
93
-
94
- async _copy(src, dest) {
95
- this._files.push(dest)
96
- await fs.promises.mkdir(path.dirname(dest), { recursive: true })
97
- await fs.promises.copyFile(src, dest)
98
- }
99
-
100
- async _writeTarFile(tarFile, root, resources) {
101
- const { tar } = cds.utils
102
- await tar.czfd(tarFile, root, resources)
103
- this._files.push(tarFile)
104
- }
105
-
106
- async _collectLanguageBundles(model, dest) {
107
- // collect effective i18n properties...
108
- let bundles = {}
109
- const bundleGenerator = cds.localize.bundles4(model)
110
- if (bundleGenerator && bundleGenerator[Symbol.iterator]) {
111
- for (let [locale, bundle] of bundleGenerator) {
112
- // fallback bundle has the name ""
113
- if (typeof locale === 'string') {
114
- bundles[locale] = bundle
115
- }
116
- }
117
- }
118
- // omit bundles in case the fallback bundle is the only existing entry
119
- const keys = Object.keys(bundles)
120
- if (keys.length === 1 && keys[0] === "" && Object.keys(bundles[keys[0]]).length === 0) {
121
- bundles = {}
122
- }
123
- // copied from ../compile/i18n.js
124
- const { file: base = 'i18n' } = cds.env.i18n
125
- if (Object.keys(bundles).length > 0) {
126
- await this._write(bundles, path.join(dest, base + '.json'))
127
- }
128
- }
129
- }
@@ -1,89 +0,0 @@
1
- const cds = require('@sap/cds')
2
- const path = require('path')
3
- const fs = require('fs').promises
4
- const mtxAdapter = require('./mtx-adapter')
5
- const { build } = require('./extension-project-builder')
6
- module.exports.DEFAULT_TAG = 'migrated'
7
-
8
- module.exports.getExtensionTag = function (filename, tagRegexString, defaultTag = module.exports.DEFAULT_TAG) {
9
- if (!tagRegexString) return defaultTag
10
- const regex = new RegExp(tagRegexString)
11
- const match = filename.match(regex)
12
- return match?.[1] ? match[1] : defaultTag
13
- }
14
-
15
- module.exports.createProjects = async function (mtxExtension, dir, tagRegex, defaultTag = module.exports.DEFAULT_TAG) {
16
-
17
- const validTags = []
18
-
19
- const extensions = _splitExtensionByTag(mtxExtension, tagRegex, defaultTag)
20
-
21
- for (const [tag, extension] of Object.entries(extensions)) {
22
-
23
- const projectFolder = path.join(dir, tag)
24
- try {
25
- await fs.rm(projectFolder, { recursive: true, force: true })
26
- } catch {
27
- // ignore
28
- }
29
- await fs.mkdir(projectFolder, { recursive: true })
30
- // extension is a map of files
31
- await mtxAdapter.writeFilesFromMap(Array.from(extension), projectFolder)
32
- // overwrite package.json
33
- await _writePackageJson(projectFolder, tag, '_base')
34
-
35
- // keep in mind to avoid parallel execution !! - use runner from old mtx?
36
-
37
- try {
38
- await build({ project: projectFolder })
39
- } catch (error) {
40
- if (error.code !== 'MODEL_NOT_FOUND') throw error
41
- // ignore extensions with no model
42
- continue
43
- }
44
- validTags.push(tag)
45
- }
46
-
47
- return validTags
48
- }
49
-
50
- function _splitExtensionByTag(mtxExtension, tagRegex, defaultTag) {
51
-
52
- const result = {}
53
-
54
- // create separate tags
55
- for (const [file, content] of mtxExtension) {
56
- if (!file.startsWith('node_modules')) {
57
- const tag = module.exports.getExtensionTag(file, tagRegex, defaultTag)
58
- if (!result[tag]) result[tag] = new Map()
59
- result[tag].set(file, content)
60
- }
61
- }
62
-
63
- // add node modules to each project to allow build
64
- for (const [file, content] of mtxExtension) {
65
- if (file.startsWith('node_modules')) {
66
- for (const tag in result) {
67
- result[tag].set(file, content)
68
- }
69
- }
70
- }
71
-
72
- return result
73
- }
74
-
75
- async function _writePackageJson(dir, name, main) {
76
- const packageJson = {
77
- "name": name,
78
- "version": "1.0.0",
79
- "description": "Generated extension project",
80
- "cds": {
81
- "extends": main
82
- }
83
- }
84
-
85
- // add compiler settings from main
86
- packageJson.cds.cdsc = cds.env.cdsc
87
-
88
- await fs.writeFile(path.join(dir, 'package.json'), JSON.stringify(packageJson, 2))
89
- }
@@ -1,230 +0,0 @@
1
- const cds = require('@sap/cds')
2
-
3
- const { fs, path } = cds.utils
4
- const tempDir = fs.realpathSync(require('os').tmpdir());
5
- const LOG = cds.log('mtx')
6
-
7
- module.exports.getDbId = async () => {
8
- LOG.info('Retrieving database ID from existing containers...')
9
- const hana = require('@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr').defaultInstance()
10
- const all = await hana.getAll()
11
- const foundDbId = all.length ? all[0].credentials?.database_id : null
12
- LOG.info('Found database ID:', foundDbId || 'none')
13
- return foundDbId
14
- }
15
-
16
- module.exports.getAllTenantIds = async () => {
17
-
18
- const hana = require('@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr').defaultInstance()
19
-
20
- // copied from mtx
21
- const META_TENANT_REGEX = /TENANT-(.*)-META/i
22
- const MT_LIB_TENANT_REGEX = /MT_LIB_TENANT-(.*)/i
23
- const GLOBAL_DATA_META_TENANT = '__META__'
24
- function _tenantFilter(tenantId, index, allTenants) {
25
- const t0 = cds.env.requires.multitenancy?.t0 ?? 't0'
26
- return tenantId
27
- && !META_TENANT_REGEX.test(tenantId)
28
- && !MT_LIB_TENANT_REGEX.test(tenantId)
29
- && tenantId.toLowerCase() !== GLOBAL_DATA_META_TENANT.toLowerCase()
30
- && tenantId !== t0
31
- && allTenants.includes(_prefixTenant(tenantId))
32
- }
33
-
34
- // TODO remove duplicates resulting from multiple bindings
35
- // replaces Tenant.getAllTenantIds()
36
- return (await hana.getAll()).reduce((result, t) => [ ...result, t.labels.tenant_id[0]] , []).filter(_tenantFilter)
37
- }
38
-
39
- function _prefixTenant(tenantId) {
40
- return `TENANT-${tenantId}-META`
41
- }
42
-
43
- module.exports.getMetaTenantName = (tenant) => {
44
- return _prefixTenant(tenant)
45
- }
46
-
47
- module.exports.getMetadata = async (tenant) => {
48
- return getMetadata(tenant)
49
- }
50
-
51
- async function getMetadata(tenant, type = 'onboarding') {
52
-
53
- // replaces Tenant.getMetadata(tenant)
54
- const CONTENT_METADATA_QUERY = 'SELECT CONTENT FROM TENANT_METADATA WHERE ID = ? AND DOMAIN = ? LIMIT 1'
55
- const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
56
-
57
- try {
58
- const result = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(CONTENT_METADATA_QUERY, [type, domain])))
59
- const CONTENT = result?.[0]?.CONTENT || result?.[0]?.content // small tribute to sqlite for testing
60
- if (type === 'onboarding') {
61
- const metadata = CONTENT ? JSON.parse(CONTENT) : {}
62
- // more robust behaviour
63
- if (!metadata.subscribedTenantId) metadata.subscribedTenantId = tenant
64
- return metadata
65
- } else {
66
- return CONTENT ? JSON.parse(CONTENT) : null
67
- }
68
-
69
- } catch (error) {
70
- LOG.error('Failed to query metadata for tenant', tenant, '(domain:', domain, '):', error)
71
- throw error;
72
- }
73
- }
74
-
75
- module.exports.saveMetadata = async (tenant, type, data) => {
76
- const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
77
- const statement = 'UPSERT TENANT_METADATA (ID, CONTENT, DOMAIN) VALUES(?, ?, ?) WHERE ID = ? AND DOMAIN = ?';
78
- await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(statement, [type, JSON.stringify(data), domain, type, domain]))
79
- }
80
-
81
- const COMPILED_FILES = {
82
- CSN_NODE: 'csn_node.json', // deprecated
83
- CSN: 'csn.json',
84
- ODATA_CSN: 'odata_csn.json',
85
- I18N: '_i18n/i18n.json'
86
- }
87
-
88
- const MODEL_TYPE = {
89
- base: 'base',
90
- extension: 'extension',
91
- compiled: 'compiled',
92
- migration: 'migration'
93
- }
94
-
95
- module.exports.getCsn = async (tenant) => {
96
-
97
- const CONTENT_FILE_QUERY = 'SELECT CONTENT FROM TENANT_FILES WHERE TYPE = ? AND FILENAME = ? AND DOMAIN = ? LIMIT 1';
98
-
99
- const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
100
-
101
- try {
102
- const result = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(CONTENT_FILE_QUERY, [MODEL_TYPE.compiled, COMPILED_FILES.CSN_NODE, domain])))
103
- const { CONTENT } = result && result[0] || {}
104
- return CONTENT ? JSON.parse(CONTENT) : null
105
-
106
- } catch (error) {
107
- this.logger.error(`Failed to query collectedSources for tenant '${tenant}' (domain: ${domain}): ${error}`)
108
- throw error;
109
- }
110
-
111
- // const loadedModel = await Tenant.getModel(tenant, 'collectedSources');
112
- // return JSON.parse(loadedModel);
113
- }
114
-
115
- // replaces Content.getExtension(tenant)
116
- module.exports.getExtension = async (tenant) => {
117
-
118
- function _isModelFile(filename) {
119
- const BASE_MODEL_EXTENSION_PROJECT_FILTER = /(.*\.cds$|.*\.csn$|.*\/csn.json$|^csn.json$|.*\/i18n(|_.*)(\.json|\.properties)$)/
120
- return BASE_MODEL_EXTENSION_PROJECT_FILTER.test(filename);
121
- }
122
-
123
- function _convertToExtensionProject(files) {
124
- const BASE_MODEL_NAME = '_base'
125
- const basemodelFiles = new Map();
126
-
127
- for (const [file, content] of files) {
128
- if (_isModelFile(file)) {
129
- const prefixedPath = path.join('node_modules', BASE_MODEL_NAME, file);
130
- basemodelFiles.set(prefixedPath, content);
131
- }
132
- }
133
-
134
- return basemodelFiles;
135
- }
136
-
137
- async function readFiles(modelType) {
138
- const MODEL_FILE_QUERY = 'SELECT FILENAME, CONTENT, TYPE FROM TENANT_FILES WHERE TYPE = ? AND DOMAIN = ?';
139
- const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
140
- try {
141
- const files = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(MODEL_FILE_QUERY, [modelType, domain])));
142
- return files.map(({ FILENAME, CONTENT }) => [FILENAME, CONTENT.toString('utf-8')]);
143
-
144
- } catch (error) {
145
- LOG.error('Failed to query extensions for tenant', tenant, '(domain:', domain, '):', error);
146
- throw error;
147
- }
148
- }
149
-
150
- const extensions = await readFiles(MODEL_TYPE.extension);
151
- if (!extensions?.length) return // return nothing if no extensions exist
152
-
153
- const base = await readFiles(MODEL_TYPE.base);
154
-
155
- return [...extensions, ..._convertToExtensionProject(base)]
156
- }
157
-
158
- module.exports.hasExtensions = async (tenant) => {
159
- if (!(await module.exports.wasOldMtx())) return false
160
- const MODEL_FILE_QUERY = 'SELECT FILENAME FROM TENANT_FILES WHERE TYPE = ? AND DOMAIN = ?';
161
- const domain = cds.env.mtx && cds.env.mtx.domain || '__default__'
162
- try {
163
- const files = (await cds.tx({ tenant: _prefixTenant(tenant) }, tx => tx.run(MODEL_FILE_QUERY, ['extension', domain])));
164
- return files.length
165
- } catch (error) {
166
- LOG.debug('Upgrade check: No @sap/mtx (old mtx) extensions found for tenant', tenant, '(domain:', domain, '):', error);
167
- return false;
168
- }
169
- }
170
-
171
- const wasOldMtx = []
172
-
173
- // use this before automatic tenant list update in upgrade
174
- module.exports.wasOldMtx = async () => {
175
- if (!wasOldMtx.length) {
176
- if (cds.env.requires.db?.credentials?.sm_url) { // old mtx was service-manager based
177
- const hana = require('@sap/cds-mtxs/srv/plugins/hana/hdi-ctnr-mgr').defaultInstance()
178
- try {
179
- wasOldMtx.push(!!(await hana.get('__META__')))
180
- } catch (error) {
181
- if (error.status === 404) wasOldMtx.push(false)
182
- else throw error
183
- }
184
- } else {
185
- wasOldMtx.push(false)
186
- }
187
- }
188
- return wasOldMtx[0]
189
- }
190
-
191
- module.exports.isMigrated = async (tenant) => {
192
- return getMetadata(tenant, 'migrated')
193
- }
194
-
195
- module.exports.getMigrationParameters = async (tenant) => {
196
- return getMetadata(tenant, 'migrationParameters')
197
- }
198
-
199
- module.exports.setMigrated = async (tenant, tagRule, defaultTag, force) => {
200
- const timestamp = new Date();
201
- const timestampIso = timestamp.toISOString();
202
- const data = {
203
- timestamp: timestampIso
204
- }
205
- await module.exports.saveMetadata(tenant, 'migrated', data)
206
- await module.exports.saveMetadata(tenant, 'migrationParameters', { tagRule, defaultTag, force })
207
- }
208
-
209
- function unixPath(filename) {
210
- return filename.replace(/\\/g, '/');
211
- }
212
-
213
- module.exports.writeFilesFromMap = async (files, baseDir) => {
214
- for (const [filename, content] of files) {
215
- const unixFilename = unixPath(filename);
216
- const absoluteFilename = path.resolve(baseDir, unixFilename);
217
-
218
- if (absoluteFilename.includes(baseDir)) {
219
- //this.logger.debug(`Writing file: ${absoluteFilename}`);
220
- await fs.promises.mkdir(path.dirname(absoluteFilename), { recursive: true });
221
- await fs.promises.writeFile(absoluteFilename, content);
222
- } else {
223
- //this.logger.debug(`Do not write file outside of target: ${absoluteFilename}`);
224
- }
225
- }
226
- }
227
-
228
- module.exports.mkdirTemp = async () => {
229
- return fs.promises.mkdtemp(`${tempDir}${path.sep}`);
230
- }