@sap/cds-mtxs
Version:
SAP Cloud Application Programming Model - Multitenancy library
95 lines (86 loc) • 4.09 kB
JavaScript
const cds = require('@sap/cds')
module.exports = (srv) => {
// mainly normalizing the input
srv.before(['UPDATE', 'UPSERT'], 'Extensions', req => { // must be synchronous to be handled first
const { csn: extension, i18n: bundles, csvs: csvData } = req.data
// Validation of extension
if (!extension) throw new cds.error({ message: 'Property "extension" is missing', code: 400 })
if (Array.isArray(extension)) {
if (!extension.length) throw new cds.error({ message: 'Property "extension" is empty', code: 400 })
} else {
const length = typeof extension === 'string' ? extension.length : Object.keys(extension).length
if (!length) throw new cds.error({ message: 'Property "extension" is malformed', code: 400 })
}
// Merge extension to one extension csn
let extCsn
for (let ext of extension) {
if (typeof ext === 'string') {
if (!ext.length) throw new cds.error({ message: 'Missing extension', code: 400 })
if (_isCSN(ext)) extCsn = _mergeCSN(JSON.parse(ext), extCsn)
else try { extCsn = _mergeCSN(cds.parse.cdl(ext), extCsn) } catch (e) {
if (e.code === 'ERR_CDS_COMPILATION_FAILURE') throw new cds.error({ message: e.message, code: 422 })
else throw e
}
} else {
if (!Object.keys(ext).length) throw new cds.error({ message: 'Missing extension', code: 400 })
extCsn = _mergeCSN(ext, extCsn)
}
}
if (extCsn.requires) delete extCsn.requires
// merge i18n and csvs
let csvs = {}
const i18nJson = _mergeBundles(bundles) // convert to i18n.json
if (csvData) csvs = _convertData(csvData)
// REVISIT - overwrite existing parameters from API?
req.data.csvs = csvs
req.data.i18n = i18nJson
req.data.csn = extCsn
})
const _isCSN = str => str.substring(0, 1) === '{'
const _mergeCSN = function (extension, merged) {
if (!merged) merged = { extensions: [], definitions: {} }
if (extension.definitions) Object.assign(merged.definitions, extension.definitions)
if (extension.extensions) merged.extensions.push(...extension.extensions)
return merged
}
const _mergeBundles = function (bundles) {
if (!Array.isArray(bundles)) return bundles ?? {}
let mergedI18nJson = {}
let fromJson = false
bundles.forEach(file => {
const key = file.name.match(/i18n_*(.*)\.properties/), lang = key?.[1]
if (key) {
if (fromJson) throw new cds.error({ message: `Mixed i18n file types not supported: i18n.json and ${file.name}`, code: 422 })
mergedI18nJson[lang] = _toJson(file.content)
} else if (file.name === 'i18n.json') {
if (Object.entries(mergedI18nJson).length) throw new cds.error({ message: `Mixed i18n file types not supported: i18n.json and .properties`, code: 422 })
try {
mergedI18nJson = JSON.parse(file.content)
fromJson = true
} catch (e) {
throw new cds.error({ message: `Invalid JSON content in i18n.json: ${e.message}`, code: 422 })
}
}
})
return mergedI18nJson
}
const _convertData = function (resources) {
const csvs = {}
if (resources && Array.isArray(resources) && resources.length) {
resources.forEach(file => {
if (file.name.endsWith('.csv')) {
csvs[file.name] = file.content
}
})
}
return csvs
}
const _toJson = function (content) {
const json = {}, splitted = content.split('\n')
splitted.forEach(s => {
const parts = s.split('=').map(s => s.trim()), [key, val] = parts
if (parts.length === 2) json[key] = val
})
return json
}
}