Comparing version 3.10.0 to 3.13.0
@@ -38,4 +38,4 @@ import { Query, expr } from "./specs/CQN" | ||
(csn: csn) : { | ||
for: ( output: 'json' | 'yaml' | 'yml' | 'sql' | 'cdl' | 'edm' | 'edmx', options? ) => csn | ||
to: ( output: 'json' | 'yaml' | 'yml' | 'sql' | 'cdl' | 'edm' | 'edmx', options? ) => string | ||
for: ( output: 'json' | 'yaml' | 'yml' | 'sql' | 'cdl' | 'edm' | 'edmx', options?:object ) => csn | ||
to: ( output: 'json' | 'yaml' | 'yml' | 'sql' | 'cdl' | 'edm' | 'edmx', options?:object ) => string | ||
} | ||
@@ -42,0 +42,0 @@ } |
@@ -23,3 +23,3 @@ import { SELECT, INSERT, UPDATE, DELETE, Query } from './ql' | ||
*/ | ||
transaction (context) : Transaction | ||
transaction (context : object) : Transaction | ||
} | ||
@@ -49,3 +49,3 @@ | ||
run (query : Query) : Promise<ResultSet> | ||
foreach (query : Query, callback) : this | ||
foreach (query : Query, callback: (row:object) => void) : this | ||
} | ||
@@ -52,0 +52,0 @@ |
module.exports = Object.assign(activate, { | ||
options: ['--username', '--tenant', '--to'], | ||
options: ['--username', '--passcode', '--subdomain', '--to', ], | ||
flags: ['--undeploy'], | ||
shortcuts: ['-u', '-t'], | ||
shortcuts: ['-u', '-p', '-s'], | ||
help: ` | ||
@@ -15,10 +15,10 @@ # SYNOPSIS | ||
*-p* | *--passcode* <passcode> | ||
The passcode for authentication | ||
*-u* | *--username* <name> | ||
The username for authentication. | ||
Deprecated. Use passcode parameter instead. | ||
*-t* | *--tenant* <tenant> | ||
Override the tenant to extend (Otherwise taken from JWT token). | ||
*--to* <url> | ||
@@ -39,22 +39,8 @@ The url to activate. | ||
const client = require('@sap/cds-sidecar-client') | ||
const { askQuestion, askBooleanQuestion } = client.question | ||
const askQuestion = client.question.askQuestion | ||
if (!folder) { | ||
folder = await askQuestion('Project root folder: ') | ||
if (options.username && !options.passcode) { | ||
options.password = await askQuestion('Password: ', undefined, true) | ||
} | ||
if (!options.to) { | ||
options.to = await askQuestion('Application URL: ') | ||
} | ||
if (!options.username) { | ||
options.username = await askQuestion('Username: ') | ||
} | ||
if (options.undeploy === undefined) { | ||
options.undeploy = await askBooleanQuestion('Undeploy previously deployed extension [yN]') | ||
} | ||
options.password = await askQuestion('Password: ', undefined, true) | ||
const collectSources = require('../lib/models/cdsv').collectSources | ||
@@ -61,0 +47,0 @@ const cds = require('../lib/cds') |
@@ -61,4 +61,4 @@ const _cds = require('../../lib/cds') | ||
const fs = require('fs-extra') | ||
const BuildTaskEngine = require('./buildTaskEngine') | ||
const BuildTaskFactory = require('./buildTaskFactory') | ||
const BuildTaskEngine = require('../../lib/build/buildTaskEngine') | ||
const BuildTaskFactory = require('../../lib/build/buildTaskFactory') | ||
@@ -65,0 +65,0 @@ if (!project) { |
@@ -43,2 +43,5 @@ #!/usr/bin/env node | ||
// 'cds cds' --> 'cds compile cds' | ||
if (/^cds$/i.test(cmd)) { args.unshift(cmd); cmd = './compile' } | ||
try { | ||
@@ -51,3 +54,8 @@ // one of our built-in cli commands? | ||
} | ||
const cmdPath = cmd | ||
cmd = require (cmd) | ||
if (typeof cmd !== 'function') { | ||
// we have resolved something unknown, as with 'cds ..' | ||
throw new Error('Unsupported command: ' + cmdPath) | ||
} | ||
@@ -75,3 +83,3 @@ // parse arguments and options for specific command | ||
require('../lib/cds').on ('compilationMessage', (m) => messages.push (m)) | ||
process.on('beforeExit', () => logMessages (messages)) | ||
process.once('beforeExit', () => logMessages (messages)) | ||
} | ||
@@ -78,0 +86,0 @@ |
module.exports = Object.assign(deploy, { | ||
options: ['--to'], flags: ['--no-save'], | ||
options: ['--to'], flags: ['--no-save', '--auto-undeploy'], | ||
shortcuts: ['-2'], | ||
@@ -7,3 +7,3 @@ help: ` | ||
*cds deploy* [ <model> ] [ --to <database> ] | ||
*cds deploy* [ <model> ] [ <options> ] | ||
@@ -14,2 +14,10 @@ Deploys the given model to a database. If no model is given it looks up | ||
Supported databases: sqlite | ||
# OPTIONS | ||
*-2* | *--to* <database> | ||
*--no-save* | ||
`}) | ||
@@ -19,38 +27,51 @@ | ||
function deploy ([model], { to:url, 'no-save':no_save = cds.env.deploy.no_save }) { | ||
async function deploy ([_model], { to:_to, 'no-save':no_save = cds.env.deploy.no_save, 'auto-undeploy': autoUndeploy = false}) { // NOSONAR | ||
const db = cds.connect(url) | ||
if (!model) model = db.options && db.options.model | ||
|| cds.env.requires.db && cds.env.requires.db.model | ||
|| ['db','srv'] | ||
if (!_to && !cds.env.requires.db) throw new Error(` | ||
db.then(()=> db.load(model) .then (csn=> db.deploy (csn)) | ||
.then (() => require ('./etc/init-from-csv') (model)) | ||
.then (() => cds.disconnect())) | ||
.then (url && !no_save && (() => registerDatasource(db,model))) | ||
.catch (e => { | ||
if (!model && e.code === 'MODEL_NOT_FOUND') { | ||
throw new Error('Please specify a data model or configure one in package.json#cds.requires.db.model') | ||
} else throw e | ||
}) | ||
There's no database configured in 'cds.require.db'. | ||
Please do so or specify one, e.g.: | ||
cds deploy --to sqlite:db/my.db | ||
`) | ||
let url = _to | ||
const [,_kind,_database] = /(\w+)?(?::(.*))?/.exec(url||'') | ||
const conf = cds.env.requires.db || {} | ||
const kind = _kind || conf.kind | ||
const model = _model || conf.model || ['db','srv'] | ||
const database = _database || conf.credentials && conf.credentials.database | ||
if (!url && kind && database) url = kind + ':' + database // reconstruct URL out of config | ||
try { | ||
if (kind === 'hana') { | ||
const deployHana = require('../lib/deploy/hana'); | ||
await deployHana(model, null, null, null, { autoUndeploy }); | ||
} else { | ||
const db = await cds.deploy(model) .to (url || kind) | ||
db.disconnect() // REVISIT: we should NOT require to explicitly disconnect | ||
if (_to && !no_save) await registerDatasource (kind,model,database) | ||
console.log (`/> successfully deployed database to ./${database || (kind+'.db')}`) | ||
} | ||
} catch (e) { | ||
if (!model && e.code === 'MODEL_NOT_FOUND') { | ||
throw new Error('Please specify a data model or configure one in package.json#cds.requires.db.model') | ||
} else throw e | ||
} | ||
} | ||
function registerDatasource ({options}, model) { try { | ||
function registerDatasource (kind,model,database) { try { | ||
const package_json = require('path') .resolve ('package.json') | ||
const pj = require (package_json) | ||
if (pj.cds && pj.requires && pj.requires.db) return | ||
const conf = (pj.cds || (pj.cds={})) .requires || (pj.cds.requires = {}) | ||
cds.env.requires.db = conf.db = { | ||
kind: options.kind, | ||
model: model, | ||
credentials: options.credentials, | ||
} | ||
const conf = require (package_json) | ||
const requires = ['cds','requires'] .reduce ((p,n)=>p[n] || (p[n]={}), conf) | ||
cds.env.requires.db = requires.db = { kind, model } | ||
if (database) requires.db.credentials = {database} | ||
const write = require('util').promisify (require('fs').writeFile) | ||
write (package_json, JSON.stringify(pj,null,' ')).then (()=> | ||
console.log (' - updated package.json') | ||
return write (package_json, JSON.stringify(conf,null,' ')).then (()=> | ||
console.log (' > updated package.json') | ||
) | ||
} catch(e){/* ignore */}} | ||
/* eslint no-console: off */ | ||
/* eslint no-console: off */ |
module.exports = Object.assign(extend, { | ||
options: ['--username', '--tenant'], | ||
shortcuts: ['-u', '-t'], | ||
options: ['--username', '--directory', '--subdomain', '--passcode'], | ||
shortcuts: ['-u', '-d', '-s', '-p'], | ||
help: ` | ||
# SYNOPSIS | ||
*cds extend* [ <model> ] | ||
*cds extend* [ <url> ] | ||
@@ -14,10 +14,18 @@ Create an extension project from url [url] | ||
*-u* | *--username* <name> | ||
*-d* | *--directory* <directory> | ||
The target directory. | ||
The username for authentication. | ||
*-s* | *--subdomain* <subdomain> | ||
The subdomain to extend. | ||
*-t* | *--tenant* <tenant> | ||
*-p* | *--passcode* <passcode> | ||
Override the tenant to extend (Otherwise taken from JWT token). | ||
The passcode for authentication | ||
*-u* | *--username* <name> | ||
Deprecated. Use passcode parameter instead. | ||
`}) | ||
@@ -27,2 +35,3 @@ | ||
async function extend ([url], options = {}) { | ||
try { | ||
@@ -32,13 +41,10 @@ const client = require('@sap/cds-sidecar-client') | ||
if (!url) { | ||
url = await askQuestion('Extension Url: ') | ||
url = await askQuestion('Extension Url: '); | ||
} | ||
if (!options.username) { | ||
options.username = await askQuestion('Username: ') | ||
if (options.username && !options.passcode) { | ||
options.password = await askQuestion('Password: ', undefined, true) | ||
} | ||
options.password = await askQuestion('Password: ', undefined, true) | ||
client.extend(url, options) | ||
@@ -45,0 +51,0 @@ } catch (e) { |
@@ -10,3 +10,3 @@ module.exports = Object.assign (help, {help:` | ||
*c* | *compile* ...individual models (= the default) | ||
*d* | *deploy* ...data models to a database | ||
*d* | *deploy* ...data models to a database (sqlite) | ||
*s* | *serve* ...service models to REST clients | ||
@@ -13,0 +13,0 @@ *b* | *build* ...whole modules or projects |
@@ -53,2 +53,3 @@ module.exports = Object.assign (repl, { options: [], help: ` | ||
.replace(/{ (xpr|ref|val): /g, '{$1:') | ||
.replace(/\[Object: null prototype\] /g, '') | ||
} | ||
@@ -55,0 +56,0 @@ |
@@ -34,4 +34,4 @@ module.exports = Object.assign ( serve, { | ||
}) | ||
cds.on ('serve', ({name,path,impl})=>{ | ||
console.log (`[cds] - serving ${name} at ${path}${impl ? ' - impl: ' + _local(impl._source) : ''}`) | ||
cds.on ('serve', ({name,path,_impl})=>{ | ||
console.log (`[cds] - serving ${name} at ${path}${_impl ? ' - impl: ' + _local(_impl._source || '<unknown source>') : ''}`) | ||
}) | ||
@@ -43,2 +43,2 @@ cds.on ('served', ({_sources})=>{ | ||
const _local = (filename) => relative('', filename) | ||
/* eslint no-console:off */ | ||
/* eslint no-console:off */ |
@@ -9,2 +9,56 @@ # Change Log | ||
## Version 3.13.0 - 2019-06-26 | ||
### Added | ||
- `cds serve` now provides a preview of the services in a list page of SAP Fiori Elements | ||
### Changed | ||
- `cds serve` now yields an error if there are no services defined in the model | ||
### Also see | ||
- Changes of `@sap/cds-compiler` 1.15.0 | ||
- Changes of `@sap/cds-ql` 1.14.0 | ||
- Changes of `@sap/cds-services` 1.14.0 | ||
- Changes of `@sap/generator-cds` 2.4.11 | ||
## Version 3.12.0 - 2019-06-17 | ||
### Added | ||
- On request, `cds build/all` now generates OData EDMX files for node.js services | ||
- Performance optimizations for `cds build/all` | ||
### Fixed | ||
- `cds deploy` no longer fails if `data` dir is not present | ||
- `cds build/all` no longer prints a message if `mta.yaml` does not exist | ||
### Also see | ||
- Changes of `@sap/cds-compiler` 1.14.1 | ||
- Changes of `@sap/cds-ql` 1.13.0 | ||
- Changes of `@sap/cds-services` 1.13.0 | ||
## Version 3.11.1 - 2019-06-03 | ||
### Fixed | ||
- `cds deploy` honors saved datasource configuration again | ||
- localization works again for sqlite datasources defined in `package.json` | ||
## Version 3.11.0 - 2019-06-03 | ||
### Added | ||
- `cds deploy` now also finds `.csv` files in imported reuse packages | ||
- Better error messages for various `cds` CLI calls | ||
### Changed | ||
- `cds build/all` for Node.js projects generates proper CSN in `gen/csn.json`. | ||
A warning is emitted if `cds serve` is run with the previous format. Rebuild the project if you see this warning. | ||
### Also see | ||
- Changes of `@sap/cds-compiler` 1.14.0 | ||
- Changes of `@sap/cds-ql` 1.12.0 | ||
- Changes of `@sap/cds-services` 1.12.0 | ||
- Changes of `@sap/generator-cds` 2.4.10 | ||
## Version 3.10.0 - 2019-05-21 | ||
@@ -11,0 +65,0 @@ |
@@ -1,2 +0,2 @@ | ||
const DEBUG = process.env.DEBUG_COMPILE && console.warn // eslint-disable-line | ||
const DEBUG = /\b(y|all|alpha|_localized)\b/.test (process.env.DEBUG) && console.warn // eslint-disable-line | ||
const cds = require('../cds') | ||
@@ -32,3 +32,3 @@ const _4sqlite = ['de','fr'] | ||
for (let each of _4sqlite) | ||
srv.model.definitions [`localized.${each}.${d.name}`] = d | ||
srv.model.definitions [`localized.${each}.${d.name}`] = Object.assign({name: `localized.${each}.${d.name}`}, d) | ||
} | ||
@@ -49,3 +49,2 @@ | ||
_add_placebos4 (srv,each) // only required until the cds compiler gives us the correct views for exposed entities | ||
srv.before ('READ', each, _read_from_localized_entity) | ||
} | ||
@@ -56,16 +55,2 @@ } | ||
// Redirect incoming read requests to localized. views unless in Fiori draft | ||
function _read_from_localized_entity (req) { | ||
if (!req._is_in_fiori_draft) { // TODO: how to correctly detect draft mode | ||
const {SELECT} = req.query, entity = req.target.name | ||
SELECT.from.ref[0] = `localized.${entity}` | ||
if (_4sqlite) { // experimental variant for sqlite | ||
const locale = req.user.locale | ||
if (_4sqlite.includes(locale)) SELECT.from.ref[0] = `localized.${locale}.${entity}` | ||
} | ||
} | ||
} | ||
/////////////////////////////////////////////////////////// | ||
@@ -72,0 +57,0 @@ // cds.connect part |
@@ -1,19 +0,20 @@ | ||
const OUTPUT_MODE_DEFAULT = 'default' | ||
exports.OUTPUT_MODE_DEFAULT = OUTPUT_MODE_DEFAULT | ||
const OUTPUT_MODE_PREVIEW = 'preview' | ||
exports.OUTPUT_MODE_PREVIEW = OUTPUT_MODE_PREVIEW | ||
const OUTPUT_MODE_RESULT = 'result' | ||
exports.OUTPUT_MODE_RESULT = OUTPUT_MODE_RESULT | ||
exports.BUILD_OPTION_OUTPUT_MODE = "outputMode" | ||
// use "/" for cds config entries and not path.sep which is platform specific | ||
const CDS_CONFIG_PATH_SEP = '/' | ||
exports.CDS_CONFIG_PATH_SEP = CDS_CONFIG_PATH_SEP | ||
exports.OUTPUT_MODE_DEFAULT = "default" | ||
exports.OUTPUT_MODE_PREVIEW = "preview" | ||
exports.OUTPUT_MODE_RESULT_ONLY = "resultOnly" | ||
const BUILD_TASK_JAVA = "java-cf" | ||
exports.BUILD_TASK_JAVA = BUILD_TASK_JAVA | ||
const BUILD_TASK_NODE = "node-cf" | ||
exports.BUILD_TASK_NODE = BUILD_TASK_NODE | ||
const BUILD_TASK_HANA = "hana" | ||
exports.BUILD_TASK_HANA = BUILD_TASK_HANA | ||
const BUILD_TASK_FIORI = "fiori" | ||
exports.BUILD_TASK_FIORI = BUILD_TASK_FIORI | ||
exports.BUILD_TASK_JAVA = "java-cf" | ||
exports.BUILD_TASK_NODE = "node-cf" | ||
exports.BUILD_TASK_HANA = "hana" | ||
exports.BUILD_TASK_FIORI = "fiori" | ||
exports.BUILD_TASK_MTX = "mtx" | ||
exports.ODATA_VERSION = "odata.version" | ||
exports.ODATA_VERSION_V2 = "v2" | ||
exports.ODATA_VERSION_V4 = "v4" | ||
exports.BUILD_MODE_INPLACE = "inplace" | ||
exports.BUILD_NODEJS_EDMX_GENERAION = "build.nodejs.edmxgeneration" | ||
exports.CDS_CONFIG_PATH_SEP = "/" |
@@ -1,3 +0,3 @@ | ||
const BuildTaskEngine = require('../../bin/build/buildTaskEngine'); | ||
const BuildTaskFactory = require('../../bin/build/buildTaskFactory'); | ||
const BuildTaskEngine = require('./buildTaskEngine'); | ||
const BuildTaskFactory = require('./buildTaskFactory'); | ||
@@ -4,0 +4,0 @@ module.exports = { |
@@ -15,2 +15,3 @@ const core = require ('@sap/cds-reflect'), $=require; require = (id)=> lazy=> $(id) // eslint-disable-line | ||
connect: require ('./runtime/connect'), | ||
deploy: require ('./runtime/deploy'), | ||
service: require ('./runtime/service'), | ||
@@ -21,2 +22,4 @@ serve: require ('./runtime/serve'), | ||
deployHana: require ('./deploy/hana'), | ||
// Multitenancy and Extensibility | ||
@@ -23,0 +26,0 @@ mtx: require('./mtx'), |
@@ -50,9 +50,2 @@ const cds = require('../cds'), cdsv = _emitting ( cds._compiler ) | ||
// keep _locations as hidden properties | ||
const defs = csn.definitions; for (let each in defs) { | ||
const d = defs[each], loc = xsn.definitions[each].location | ||
Object.defineProperty (d, '_location', {value:loc}) | ||
if (!d['@source'] && d.kind === 'service') d['@source'] = loc.filename //> enumerable | ||
} | ||
// cache _csn to _xsn only in normalized models, i.e. not the flattened OData csn | ||
@@ -59,0 +52,0 @@ if (!_csn) Object.defineProperty (xsn, '_csn', {value:csn, configurable:1, writable:1 }) |
@@ -6,5 +6,5 @@ const cdsv = require('./cdsv') | ||
// alpha fixes for gaps | ||
const {unfold:_unfold_compositions} = require ('../alpha/_unfold_compositions') | ||
const {unfold:_unfold_localized} = require ('../alpha/_localized') | ||
// const {unfold:_unfold_temporal} = require ('../alpha/_temporal') | ||
const DEBUG = process.env.DEBUG_COMPILE && console.warn | ||
const _skip_unused = require ('../alpha/_skip_unused') | ||
@@ -37,9 +37,9 @@ const compile = (csn) => ({ | ||
json: x => JSON.stringify(x,null,2), | ||
edmx: (csn,o) => _2edm (csn,o, {off: 'metadata', only: 'annotations'}[o && o.annos]), | ||
edm: (csn,o) => _2edm (csn,o, 'metadata_json'), | ||
edmx: (csn,o) => _2edm (_unfold_compositions(csn),o, {off: 'metadata', only: 'annotations'}[o && o.annos]), | ||
edm: (csn,o) => _2edm (_unfold_compositions(csn),o, 'metadata_json'), | ||
annos: (csn,o) => _2edm (csn,o, 'annotations'), | ||
swgr: (csn,o) => _2many (cdsv.toSwagger(csn,o).services, '.swgr.json'), | ||
cdl: (csn,o) => _2many (cdsv.toCdl(csn,o),'.cds'), | ||
sql: (csn,o) => _2sql (_unfold_localized (_sql (cdsv.toSql (_skipUnused(csn),o)), csn, o), o), | ||
hana: (csn,o) => _2many (cdsv.toHana(_skipUnused(csn),o).hdbcds, '.hdbcds'), | ||
sql: (csn,o) => _2sql (_unfold_localized (_sql (cdsv.toSql (_skip_unused(csn),o)), csn, o), o), | ||
hana: (csn,o) => _2many (cdsv.toHana(_skip_unused(csn),o).hdbcds, '.hdbcds'), | ||
xsuaa: (csn,o) => require('./xsuaa').xsuaaConfig (csn,o) | ||
@@ -49,49 +49,2 @@ } | ||
/** Skip unused entities marked with @cds.persistence.skip:'if-unused' */ | ||
function _skipUnused (csn) { // NOSONAR | ||
const m = cds.linked (csn) | ||
const services = RegExp (Object.keys (m.services).map(n => '^'+n+'\\.').join('|')) | ||
const localized_ = /^localized\./ | ||
// for each entity e1 marked with @cds.persistence.skip:'if-unused'... | ||
m.foreach (e => !e.abstract && e['@cds.persistence.skip']=='if-unused', e1 => { // NOSONAR | ||
if (localized_.test(e1.name)) return | ||
if (services.test(e1.name)) return | ||
// fetch other entities e2 that contain references to e1 ... | ||
for (let e2 of m.each(cds.entity)) { | ||
if (e2 === e1) continue | ||
if (localized_.test(e2.name)) continue // ignore ref from derived entities | ||
// is e2 a view on e1? | ||
const q = e2.query; if (q && q.target === e1) { // found reference | ||
return DEBUG && DEBUG (`NOT skipping ${e1.name} due to view ${e2.name}`) | ||
} | ||
const x = e2.includes; if (x && x.includes (e1.name)) { // found reference | ||
return DEBUG && DEBUG (`NOT skipping ${e1.name} due to ${e2.name}`) | ||
} | ||
// does e2 contain Associations to e1? | ||
for (let e in e2.elements) { | ||
let a = e2.elements[e] | ||
if (a._target === e1) { // found reference | ||
return DEBUG && DEBUG (`NOT skipping ${e1.name} due to ${e2.name}[${a.name}]`) | ||
} | ||
} | ||
} | ||
// skip e1 if no fererences have been found | ||
skip (e1.name) | ||
}) | ||
function skip (entry) { | ||
if (csn.definitions [entry]) { | ||
DEBUG && DEBUG (`Skipping ${entry}`) | ||
delete csn.definitions [entry] | ||
if (csn._xsn) delete csn._xsn.definitions [entry] | ||
if (!/_texts$/.test(entry)) skip (entry+'_texts') | ||
if (!localized_.test(entry)) skip ('localized.'+entry) | ||
} | ||
} | ||
return csn | ||
} | ||
/** Return output of 2hana as an iterable */ | ||
@@ -98,0 +51,0 @@ function* _2many (result, suffix='.hdbcds') { |
@@ -45,2 +45,10 @@ module.exports = Object.assign (load, {only:get}) | ||
if (!collectedSources || !collectedSources.sources) { | ||
return | ||
} | ||
// deprecated collectedSources åformat - log warning | ||
// TODO - delete later on which requires a cds rebuild to adopt the new csn format | ||
console.warn(`[WARNING] - Model [${file}] has deprecated format - cds rebuild required`) | ||
const parsed = cdsv.parse (collectedSources, options) | ||
@@ -51,4 +59,4 @@ let srv = collectedSources.srv | ||
for (let each in parsed.definitions) { | ||
let d = parsed.definitions[each], src = d['@source'] | ||
if (src) d['@source'] = src.replace(srv,'') | ||
let d = parsed.definitions[each] | ||
if (d.kind === 'service' && d.$location) d.$location = { file: d.$location.file.replace(srv,'') } | ||
} | ||
@@ -68,1 +76,3 @@ } | ||
const _local = (path) => ('' + path).replace(_cwd, '') | ||
/* eslint no-console: off */ |
@@ -10,2 +10,5 @@ /** Both, a namespace and a shortcut for cds.parse.cdl */ | ||
/** @returns {object} the parsed query as a CQN object */ | ||
csv: (...args) => (parse.csv = require('../utils/csv').parse) (...args), | ||
/** @returns {object} the parsed expression as a CQN expr object */ | ||
@@ -12,0 +15,0 @@ expr: (...args) => (parse.expr = require('./cdsv').parseExpr) (...args), |
@@ -12,3 +12,3 @@ const cds = require('../cds') | ||
function xsuaaConfig (model, options) { | ||
function xsuaaConfig(model, options) { | ||
const base = getBaseModel(options) | ||
@@ -20,24 +20,8 @@ const generated = generateConfig(model) | ||
function generateConfig(model) { | ||
const roleTemplates = {} | ||
const scopes = {} | ||
const attributes = {} | ||
const updateRoleTemplate = (scope, attributes=[]) => { | ||
if (roleTemplates[scope]) { | ||
attributes.forEach(a => { | ||
if (!roleTemplates[scope]['attribute-references'].includes(a)) { | ||
roleTemplates[scope]['attribute-references'].push(a) | ||
} | ||
}) | ||
} else { | ||
roleTemplates[scope] = { | ||
name: scope, | ||
description: 'generated', | ||
'scope-references': ['$XSAPPNAME.' + scope], | ||
'attribute-references': attributes | ||
} | ||
} | ||
} | ||
const findUserAttrInExpression = (expr, attributes=[]) => { | ||
const findUserAttrInExpression = (expr, attributes = []) => { | ||
if (Array.isArray(expr)) { // descend arrays | ||
@@ -48,5 +32,5 @@ expr.forEach(e => findUserAttrInExpression(e, attributes)) | ||
const userIdx = expr.ref.indexOf('$user') | ||
if (userIdx >= 0 && userIdx < expr.ref.length-1) { | ||
if (userIdx >= 0 && userIdx < expr.ref.length - 1) { | ||
const attr = expr.ref[userIdx + 1] | ||
if (!hardcoded.Attributes.includes(attr)) attributes.push(attr) | ||
if (!hardcoded.Attributes.includes(attr)) attributes.push(attr) | ||
} | ||
@@ -58,3 +42,3 @@ } | ||
const parseAttributes = (condition) => { // e.g. 'foo = $user.bar or baz = $user.boo' | ||
if (!condition) return [] | ||
if (!condition) return [] | ||
@@ -75,3 +59,2 @@ try { | ||
scopes[scope] = scope | ||
updateRoleTemplate(scope) | ||
} | ||
@@ -86,3 +69,2 @@ | ||
scopes[scope] = scope | ||
updateRoleTemplate(scope, lattributes) | ||
} | ||
@@ -93,2 +75,19 @@ lattributes.forEach(attr => attributes[attr] = true) | ||
}) | ||
var roleTemplates = Object.keys(scopes).map((s) => { | ||
return { | ||
name: s, | ||
description: 'generated', | ||
'scope-references': ['$XSAPPNAME.' + s], | ||
'attribute-references': [] | ||
} | ||
}); | ||
if (Object.keys(attributes).length !== 0) { | ||
roleTemplates.push({ | ||
name: 'userattributes', | ||
description: 'generated', | ||
'default-role-name': 'Attributes of a User', | ||
'scope-references': [], | ||
'attribute-references': Object.keys(attributes) | ||
}) | ||
} | ||
@@ -106,6 +105,7 @@ return { | ||
description: a, | ||
valueType: 's' | ||
valueType: 's', | ||
valueRequired: false | ||
} | ||
}), | ||
'role-templates': Object.values(roleTemplates) | ||
'role-templates': roleTemplates | ||
} | ||
@@ -120,8 +120,8 @@ } | ||
const mergeByName = (type) => { | ||
if (!generated[type]) return | ||
if (!generated[type]) return | ||
if (!result[type]) result[type] = [] | ||
if (!result[type]) result[type] = [] | ||
result[type] = result[type].concat(generated[type].filter((g) => { | ||
if (!base[type].find) throw new Error(`Array expected for '${type}', but was: ${JSON.stringify(base)}`) | ||
return !(base[type].find((b) => b.name === g.name )) | ||
if (!base[type].find) throw new Error(`Array expected for '${type}', but was: ${JSON.stringify(base)}`) | ||
return !(base[type].find((b) => b.name === g.name)) | ||
})) | ||
@@ -136,3 +136,3 @@ } | ||
function getBaseModel(options={}) { | ||
function getBaseModel(options = {}) { | ||
if (typeof options.base === 'string') { | ||
@@ -155,3 +155,3 @@ try { | ||
try { | ||
name = require (path.resolve ('package.json')).name | ||
name = require(path.resolve('package.json')).name | ||
} catch (err) { // no package.json | ||
@@ -158,0 +158,0 @@ name = path.basename(process.cwd()) |
@@ -75,3 +75,6 @@ const cds = require('../cds') | ||
const conf = configured [datasource] | ||
if (!conf) _error (`didn't find a configuration for 'cds.requires.${datasource}'`) | ||
if (!conf) { | ||
if (datasource === 'sqlite') return [ undefined, {kind:'sqlite'}, primary ] | ||
_error (`didn't find a configuration for 'cds.requires.${datasource}'`) | ||
} | ||
if (!conf.kind && !conf.driver) _error (`configuration for 'cds.requires.${datasource}' lacks mandatory property 'kind'`) | ||
@@ -110,3 +113,3 @@ } | ||
}) | ||
for (let p of [ 'transaction', 'run', 'stream', 'foreach', 'read', 'insert', 'update', 'delete', 'acquire', 'release', 'disconnect', 'deploy' ]) { | ||
for (let p of [ 'transaction', 'run', 'stream', 'foreach', 'read', 'insert', 'update', 'delete', 'acquire', 'release', 'disconnect' ]) { | ||
Object.defineProperty (cds, p, {configurable: true, value: (...a) => ds[p](...a)}) | ||
@@ -121,6 +124,6 @@ } | ||
const _disconnect = client.disconnect | ||
client.disconnect = ()=>{ | ||
if (client === cds.session) cds.session = undefined | ||
client.disconnect = param => { | ||
if (!param && client === cds.session) cds.session = undefined | ||
delete cached [datasource] | ||
return _disconnect.call (client) | ||
return _disconnect.call (client, param) | ||
} | ||
@@ -127,0 +130,0 @@ } |
const cds = require ('../cds'), lib = require ('@sap/cds-ql'); lib.inject (cds) | ||
const knownKinds = {sqlite:1} | ||
const ql = module.exports = $$(lib.statements, { | ||
connect: lib.connect.connect //> goes to ./connect.js | ||
connect: (datasource, options, primary)=>{ | ||
if (!options) options = cds.env.requires[datasource] | ||
if (options && options.kind in knownKinds && !options.credentials) options.credentials = {database: options.kind+'.db'} | ||
return lib.connect.connect (datasource, options, primary) //> goes to ./connect.js | ||
} | ||
}) | ||
@@ -26,7 +31,7 @@ if (cds.env.features.localized) { | ||
ENABLE ( | ||
_ANY_isQuery, | ||
_SELECT_from_valueOf, _SELECT_distinct, // _SELECT_from_with_key, | ||
_INSERT_into_valueOf, _INSERT_entry_into, | ||
_UPDATE_entity_valueOf, _UPDATE_set_fluent, _UPDATE_with, //_UPDATE_with_key, | ||
_DELETE_from_valueOf, | ||
_ANY_isQuery, | ||
_SELECT_from_valueOf, _SELECT_distinct, // _SELECT_from_with_key, | ||
_INSERT_into_valueOf, _INSERT_entry_into, | ||
_UPDATE_entity_valueOf, _UPDATE_set_fluent, _UPDATE_with, //_UPDATE_with_key, | ||
_DELETE_from_valueOf, | ||
) | ||
@@ -181,3 +186,2 @@ DISABLED ( | ||
// Add support for UPDATE('Foo') + '... plain sql tail...' | ||
@@ -184,0 +188,0 @@ function _UPDATE_entity_valueOf(){ |
@@ -1,12 +0,2 @@ | ||
/*USAGE:*/()=>{ | ||
const app = require('express')() | ||
cds.serve('all').in(app) //> no subsequent .at() or .with() possible | ||
cds.serve('CatalogService').from('all').in(app).at('/mount-point').with(function(){ | ||
const { Books } = this.entities | ||
this.on('READ', Books, (req) => req.reply([])) | ||
}) | ||
} | ||
module.exports = cds_serve | ||
const cds = require('../cds') | ||
const service = require ('./service') | ||
@@ -30,28 +20,19 @@ const isIdentifier = (x) => typeof x === 'string' && /^[A-Za-z_$][\w$]*$/.test (x) | ||
*/ | ||
function cds_serve (service_or_model, givenOptions={}) { // NOSONAR | ||
const options = Object.assign({}, givenOptions) | ||
function cds_serve (service_or_model, _options) { // NOSONAR | ||
if (!isIdentifier(service_or_model)) { | ||
return cds_serve('all',options).from(service_or_model) | ||
return cds_serve('all',_options).from(service_or_model) | ||
} | ||
const cds = this.serve === cds_serve ? this : global.cds | ||
const ready = Promise.resolve().then (_loadModel) .then (_constructProviders) | ||
const providers=[] //> filled in _constructProviders | ||
const ready = Promise.resolve().then (_loadModel) .then (_constructProviders) | ||
const fluent = _fluent (options) | ||
return fluent | ||
/** | ||
* Fluent API used to fill in options subsequently | ||
*/ | ||
function _fluent (o=options) { | ||
return { | ||
from (model) { o.service = service_or_model; o.model = model; return this }, | ||
to (protocol) { if (protocol) { o.to = protocol } return this }, | ||
at (path) { if (path) { o.at = path } return this }, | ||
with (impl) { if (impl) { o.with = impl } return this }, | ||
in (app) { ready.then (()=>_addProviders2(app)); return this }, | ||
then (r,e) { return ready.then (()=> r(_returnProviders()), e) }, | ||
catch (e) { return ready.catch(e) }, | ||
} | ||
const o = Object.assign({}, _options); return { // fluent API to fill in options subsequently | ||
from (model) { o.service = service_or_model; o.model = model; return this }, | ||
to (protocol) { if (protocol) { o.to = protocol } return this }, | ||
at (path) { if (path) { o.at = path } return this }, | ||
with (impl) { if (impl) { o.with = impl } return this }, | ||
in (app) { ready.then (()=>_addProviders2(app)); return this }, | ||
then (r,e) { return ready.then (()=> r(_returnProviders()), e) }, | ||
catch (e) { return ready.catch(e) }, | ||
} | ||
@@ -63,10 +44,23 @@ | ||
function _loadModel(){ | ||
let model = options.model | ||
if (typeof model === 'object' && !Array.isArray(model)) return model //> already a csn | ||
//> cds.serve(...).from('app') | ||
let model = o.model | ||
//> cds.serve(...).from(csn) | ||
if (typeof model === 'object' && !Array.isArray(model)) return model | ||
//> cds.serve(...) | ||
if (!model) { | ||
if (options.service) model = service_or_model //> compat to cds.serve('all',{service}) | ||
else { options.service = service_or_model; model = 'all' } | ||
//> cds.serve(..., {service}) ==> cds.serve(service) .from (...) | ||
//> Note: this is for compatibility only; it's not documented anymore | ||
if (o.service) model = service_or_model | ||
//> cds.serve('all') ==> cds.serve('all').from('all') | ||
//> cds.serve(service) ==> cds.serve(service).from('all') | ||
else { model = 'all'; o.service = service_or_model } | ||
} | ||
if (model === 'all' || model[0] === 'all') { | ||
model = [ cds.env.folders.app, cds.env.folders.srv, 'services', '.' ].find (m => cds.resolve(m)) | ||
const {app,srv} = cds.env.folders | ||
model = [ app, srv, 'services', '.' ].find (m => cds.resolve(m)) | ||
if (!model) throw new Error (`[cds] - \n | ||
@@ -77,6 +71,8 @@ No service models found in current working directory. | ||
} | ||
const key = Array.isArray(model) ? model.join(';') : model | ||
const cached = cache[key] | ||
if (cached) return cached | ||
else return cache[key] = cds.load (model) | ||
return cache[key] = cds.load (model) | ||
} | ||
@@ -89,3 +85,3 @@ | ||
const o=options, external = cds.env.requires | ||
const external = cds.env.requires | ||
const chosen = o.service && o.service !== 'all' ? def => def.name.endsWith (o.service) : ()=>true | ||
@@ -97,10 +93,11 @@ o.passport = o.passport || (cds.env.auth && cds.env.auth.passport) | ||
const name = def.name | ||
if (def['@cds.ignore'] || !chosen(def) || external[name]) return | ||
if (def['@cds.serve.ignore'] || !chosen(def) || external[name]) return | ||
if ((o.at || o.with) && ++n > 1) throw new Error('You cannot specify `path` or `impl` for multiple services') | ||
const serviceOptions = {...o, at: service.path4 (def, o.at) } | ||
const provider = service.for (csn, {service: name, __proto__: serviceOptions}) | ||
provider.path = serviceOptions.at | ||
provider.impl = service.impl4 (def, o.with) | ||
const options = {...o, at: service.path4 (def, o.at) } | ||
const provider = _asEventEmitter ( //> pull down | ||
service.for (csn, {service: name, __proto__: options}) | ||
) | ||
provider.path = options.at | ||
providers.push (provider) | ||
// cds.services [name] = provider | ||
cds.services [name] = provider | ||
//> only possible when ServiceProvider == ServiceClient | ||
@@ -112,5 +109,7 @@ Object.defineProperty (cds.services, name, { configurable:1, | ||
}) | ||
if (providers.length === 0) throw new Error (`No service models found in ${csn._sources}`) | ||
// invoke all service impl functions --> in a pass 2 to allow them connect to local services | ||
_addImpls() | ||
return providers | ||
@@ -126,7 +125,7 @@ } | ||
service.performanceMeasurement(app) | ||
service.passport(each, app, each._auditLogger, options) | ||
service.passport(each, app, each._auditLogger, o) | ||
// add use method to services for backward compatibility | ||
each.use = app.use | ||
app.use (each.path+'/webapp/*', (_,res)=> res.status(400).send()) // REVISIT: this is to avoid ugly warnings by Fiori requests --> should go into Fiori protocol adapter | ||
app.use (each.path, ProtocolAdapter.for (each, options.to)) | ||
app.use (each.path, ProtocolAdapter.for (each, o.to)) | ||
cds.emit ('serve', each) | ||
@@ -142,16 +141,4 @@ } | ||
for (let each of providers) { | ||
let impl = each.impl | ||
if (typeof impl === 'object') impl = each.impl = impl [each.name] | ||
if (typeof impl !== 'function') continue; | ||
if (/^class\s/.test(Function.prototype.toString.call(impl))) { | ||
const clazz = impl; impl = each.impl = (srv)=>{ // NOSONAR | ||
const inst = new clazz (srv) | ||
for (let e of Reflect.ownKeys (clazz.prototype)) { | ||
if (e in {constructor:1, prototype:1}) continue | ||
srv.on (e, (...args) => inst[e](...args)) | ||
} | ||
} | ||
} | ||
each.with (impl) | ||
// each.impl (each) | ||
let impl = each._impl = service.impl4 (each.definition, o.with) | ||
each.impl (impl) | ||
} | ||
@@ -164,18 +151,44 @@ } | ||
function _returnProviders() { | ||
let all={}, fn='none' | ||
let all={}, srv='none' | ||
for (let each of providers) { | ||
const handler = ProtocolAdapter.for (each, options.to) | ||
fn = all[each.name] = (...args) => handler(...args) | ||
// returned objects are handlers + instances to support code like this: | ||
// const { CatalogService } = cds.serve(...) | ||
// app.use ('/cats', CatalogService) | ||
Object.setPrototypeOf (fn, each) | ||
Object.defineProperty (fn, 'name', {value:each.name}) | ||
srv = all[each.name] = _asHandlerFunction (each) | ||
} | ||
if (providers.length === 1 && fn.name === options.service) { // NOSONAR | ||
if (!(fn.name in fn)) Object.assign (fn,all) // NOSONAR | ||
return fn | ||
if (providers.length === 1 && srv.name === o.service) { // NOSONAR | ||
if (!(srv.name in srv)) Object.assign (srv,all) // NOSONAR | ||
return srv | ||
} | ||
else return all | ||
} | ||
/** | ||
* Decorates services as handler functions to delegate requests to the default protocol adapter. | ||
* This supports usages like this: | ||
* @example | ||
* const { CatalogService } = cds.serve(...) | ||
* app.use ('/cats', CatalogService) | ||
*/ | ||
function _asHandlerFunction (srv) { | ||
const adapter = ProtocolAdapter.for (srv, o.to) | ||
const fn = (...args) => adapter(...args) | ||
Object.setPrototypeOf (fn, srv) | ||
Object.defineProperty (fn, 'name', {value:srv.name}) | ||
return fn | ||
} | ||
/** | ||
* Adds an .emit() function to services, which dispatches events to registered '.on' handlers. | ||
* This supports usages like this: | ||
* @example | ||
* const { CatalogService } = cds.serve(...) | ||
* CatalogService.on ('some-event', msg => console.log(msg)) | ||
* CatalogService.emit ('some-event', {some:'data'}) | ||
*/ | ||
function _asEventEmitter (srv) { | ||
srv.emit = (event, data) => { | ||
const subscription = srv._handlers.on._handlers.find (h => h.event === srv.name+'.'+event) | ||
if (subscription) return subscription.handler ({event, data}) | ||
} | ||
return srv | ||
} | ||
} |
@@ -20,3 +20,3 @@ const cds = require ('../cds') | ||
if (cds.env.features.localized && cds.options && cds.options.kind === 'sqlite') { | ||
if (cds.env.features.localized && ((cds.options && cds.options.kind === 'sqlite') || (cds.env.requires && cds.env.requires.db && cds.env.requires.db.kind === 'sqlite'))) { | ||
const _for = exports.for | ||
@@ -39,19 +39,21 @@ const {serve} = require('../alpha/_localized') | ||
*/ | ||
exports.impl4 = function (def, _impl = def['@impl']) { | ||
const _source = def['@source'] || def._location && def._location.filename | ||
exports.impl4 = function (def, _impl = def['@impl']) { // NOSONAR | ||
const _source = def.$location && def.$location.file || /*legacy:*/ def['@source'] | ||
const dir = _source && isdir(dirname(_source)) ? dirname(_source) : process.cwd() | ||
if (typeof _impl === 'function') return found (_impl) | ||
if (_impl) return load (_impl, true) | ||
if (typeof _impl === 'function') return _found (_impl) | ||
if (_impl) return _load (_impl, true) | ||
if (_source) { | ||
const impl = parse(_source).name + '.js' | ||
return load(impl) || load('js/'+impl) || load('handlers/'+impl) | ||
return _load(impl) || _load('js/'+impl) || _load('handlers/'+impl) | ||
} | ||
function found (impl, _source = impl.name || '<inline>') { | ||
function _found (impl, _source = impl.name || '<inline>') { | ||
return Object.defineProperty (impl, '_source', {value:_source}) | ||
} | ||
function load (file, fail=false) { | ||
function _load (file, fail=false) { | ||
const resolved = resolve(dir,file) | ||
if (fs.isfile (resolved)) return found (require (resolved), file) | ||
if (fs.isfile (resolved)) return _found (require (resolved), file) | ||
else if (fail) throw new Error(`No such handler for ${def.name}: ${resolved}`) | ||
@@ -58,0 +60,0 @@ } |
@@ -34,3 +34,3 @@ module.exports = { | ||
provisioning: true, | ||
metadata: false | ||
metadata: true | ||
}, | ||
@@ -37,0 +37,0 @@ domain: '__default__' |
const path = require ('path'), { dirname, join } = path | ||
const fs = require ('fs') | ||
const fs = require('fs') | ||
const rw = fs.constants.R_OK | fs.constants.W_OK | ||
module.exports = {__proto__:fs, | ||
const utils = module.exports = Object.assign ({ | ||
path, mkdirp, rimraf, rimrafSync, isdir, isfile, find, copy, | ||
get write(){ | ||
}, fs) | ||
Object.defineProperty (utils, 'write', { | ||
get: ()=>{ | ||
const write = require('./write') | ||
Object.defineProperty (this,'write',{value:write}) | ||
Object.defineProperty (utils,'write',{value:write}) | ||
return write | ||
} | ||
} | ||
}) | ||
if (!fs.copyFile) fs.copyFile = (src, dst, callback) => { | ||
@@ -16,0 +18,0 @@ const wr = fs.createWriteStream(dst) .on ('error',_cleanup) .on ('finish',_done) |
{ | ||
"name": "@sap/cds", | ||
"version": "3.10.0", | ||
"version": "3.13.0", | ||
"lockfileVersion": 1, | ||
@@ -8,3 +8,3 @@ "requires": true, | ||
"@babel/runtime": { | ||
"version": "7.4.4", | ||
"version": "7.4.5", | ||
"requires": { | ||
@@ -15,3 +15,3 @@ "regenerator-runtime": "^0.13.2" | ||
"@sap/cds-compiler": { | ||
"version": "1.13.4", | ||
"version": "1.15.0", | ||
"requires": { | ||
@@ -24,14 +24,14 @@ "antlr4": "4.7.1", | ||
"@sap/cds-hana": { | ||
"version": "1.11.1", | ||
"version": "1.13.0", | ||
"requires": { | ||
"@sap/cds-sql": "1.11.1" | ||
"@sap/cds-sql": "1.13.0" | ||
} | ||
}, | ||
"@sap/cds-ql": { | ||
"version": "1.11.1", | ||
"version": "1.14.0", | ||
"requires": { | ||
"@sap/cds-hana": "1.11.1", | ||
"@sap/cds-sql": "1.11.1", | ||
"@sap/cds-sqlite": "1.11.1", | ||
"generic-pool": "3.4.2", | ||
"@sap/cds-hana": "1.13.0", | ||
"@sap/cds-sql": "1.13.0", | ||
"@sap/cds-sqlite": "1.13.0", | ||
"generic-pool": "3.7.1", | ||
"uuid": "3.3.2" | ||
@@ -44,19 +44,19 @@ } | ||
"@sap/cds-services": { | ||
"version": "1.11.1", | ||
"version": "1.14.0", | ||
"requires": { | ||
"@sap/cds-ql": "1.11.1", | ||
"@sap/odata-server": "1.3.3" | ||
"@sap/cds-ql": "1.14.0", | ||
"@sap/odata-server": "1.3.4" | ||
} | ||
}, | ||
"@sap/cds-sql": { | ||
"version": "1.11.1" | ||
"version": "1.13.0" | ||
}, | ||
"@sap/cds-sqlite": { | ||
"version": "1.11.1", | ||
"version": "1.13.0", | ||
"requires": { | ||
"@sap/cds-sql": "1.11.1" | ||
"@sap/cds-sql": "1.13.0" | ||
} | ||
}, | ||
"@sap/generator-cds": { | ||
"version": "2.4.8", | ||
"version": "2.4.11", | ||
"requires": { | ||
@@ -66,12 +66,7 @@ "fs-extra": "7.0.1", | ||
"xml2js": "0.4.19", | ||
"yaml": "1.2.0" | ||
}, | ||
"dependencies": { | ||
"yaml": { | ||
"version": "1.2.0" | ||
} | ||
"yaml": "1.5.1" | ||
} | ||
}, | ||
"@sap/odata-commons": { | ||
"version": "2.1.0", | ||
"version": "2.1.1", | ||
"requires": { | ||
@@ -82,5 +77,5 @@ "big.js": "=5.2.2" | ||
"@sap/odata-server": { | ||
"version": "1.3.3", | ||
"version": "1.3.4", | ||
"requires": { | ||
"@sap/odata-commons": "^2.1.0", | ||
"@sap/odata-commons": "^2.1.1", | ||
"xmlbuilder": "=10.1.0" | ||
@@ -104,3 +99,3 @@ } | ||
"generic-pool": { | ||
"version": "3.4.2" | ||
"version": "3.7.1" | ||
}, | ||
@@ -107,0 +102,0 @@ "graceful-fs": { |
@@ -1,1 +0,1 @@ | ||
{"bin":{"cds":"bin/cds.js"},"bundleDependencies":false,"dependencies":{"@sap/cds-compiler":"1.13.4","@sap/cds-ql":"1.11.1","@sap/cds-reflect":"2.5.0","@sap/cds-services":"1.11.1","@sap/generator-cds":"2.4.8","fs-extra":"7.0.1","yaml":"1.5.1"},"deprecated":false,"description":"Entry Point and API Facade for CDS","engines":{"node":">=8.9"},"eslintConfig":{"extends":"eslint:recommended","env":{"es6":true,"node":true},"parserOptions":{"ecmaVersion":2018},"rules":{"no-unused-vars":["warn",{"argsIgnorePattern":"lazy"}]}},"eslintIgnore":["tests/","gen/","reports/"],"main":"lib/cds.js","name":"@sap/cds","scripts":{"start":"node server.js"},"typings":"apis/cds.d.ts","version":"3.10.0","license":"SEE LICENSE IN developer-license-3.1.txt"} | ||
{"bin":{"cds":"bin/cds.js"},"bundleDependencies":false,"dependencies":{"@sap/cds-compiler":"1.15.0","@sap/cds-ql":"1.14.0","@sap/cds-reflect":"2.5.0","@sap/cds-services":"1.14.0","@sap/generator-cds":"2.4.11","fs-extra":"7.0.1","yaml":"1.5.1"},"deprecated":false,"description":"Entry Point and API Facade for CDS","engines":{"node":">=8.9"},"eslintConfig":{"extends":"eslint:recommended","env":{"es6":true,"node":true},"parserOptions":{"ecmaVersion":2018},"rules":{"no-unused-vars":["warn",{"argsIgnorePattern":"lazy"}]}},"eslintIgnore":["tests/","gen/","reports/","node_modules/"],"main":"lib/cds.js","name":"@sap/cds","scripts":{"start":"node server.js"},"typings":"apis/cds.d.ts","version":"3.13.0","license":"SEE LICENSE IN developer-license-3.1.txt"} |
const express = require('express') | ||
const cds = require('./lib/cds') | ||
const fioriPreview = require ('./lib/utils/fiori-preview') | ||
@@ -12,2 +13,3 @@ /** that's our pretty standard express server.js setup... */ | ||
app.get ('/', (_,res) => res.send (index.html)) //> if none in ./app | ||
app.get ('/\\$fiori-preview', fioriPreview.middleware) | ||
app.use (logger) | ||
@@ -39,4 +41,5 @@ | ||
<style> | ||
body { margin: 44px; font-family: sans-serif } | ||
h1 { font-weight:200 } | ||
body { margin: 44px; font-family: Avenir Next, sans-serif } | ||
h1 { } | ||
.small { font-size: 10px } | ||
</style> | ||
@@ -48,17 +51,29 @@ </head> | ||
${ _has_fiori_html ? `<h3><a href="/fiori.html">/fiori.html</a></h3>` : '' } | ||
${ cds.service.providers.map (service => { | ||
const {path,entities} = service | ||
const exposed=[]; for (let e in entities) exposed.push (e) | ||
return ` | ||
${ cds.service.providers.map (service => ` | ||
<h3> | ||
<a href="${path}">${path}</a> / | ||
<a href="${path}/$metadata">$metadata</a> | ||
<a href="${service.path}">${service.path}</a> / | ||
<a href="${service.path}/$metadata">$metadata</a> | ||
</h3> | ||
<ul>${exposed.map (e => ` | ||
<li><a href="${path}/${e}">${e}</a></li>`).join('')} | ||
</ul>` | ||
}) .join('')} | ||
<ul>${_exposedEntities4(service).map (e =>` | ||
<li> | ||
<a href="${service.path}/${e}">${e}</a> | ||
<a class="small" href="/$fiori-preview?${fioriPreview.buildQueryParams(service.name, e)}" | ||
title="Fiori elements list page"> …in Fiori</a> | ||
</li>`).join('')} | ||
</ul> | ||
`) .join('')} | ||
</body> | ||
</html> | ||
` | ||
function _exposedEntities4 (service) { | ||
const exposed=[], {entities} = service | ||
for (let e in entities) { | ||
if (entities[e]['@cds.autoexposed'] && !entities[e]['@cds.autoexpose']) continue | ||
if (e.endsWith('_texts')) continue | ||
if (e.endsWith('DraftAdministrativeData')) continue | ||
exposed.push(e) | ||
} | ||
return exposed | ||
} | ||
}} | ||
@@ -65,0 +80,0 @@ |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
488835
87
6638
72
5
+ Added@sap/cds-compiler@1.15.0(transitive)
+ Added@sap/cds-hana@1.13.0(transitive)
+ Added@sap/cds-ql@1.14.0(transitive)
+ Added@sap/cds-services@1.14.0(transitive)
+ Added@sap/cds-sql@1.13.0(transitive)
+ Added@sap/cds-sqlite@1.13.0(transitive)
+ Added@sap/generator-cds@2.4.11(transitive)
+ Added@sap/odata-server@1.3.4(transitive)
+ Addedgeneric-pool@3.7.1(transitive)
- Removed@sap/cds-compiler@1.13.4(transitive)
- Removed@sap/cds-hana@1.11.1(transitive)
- Removed@sap/cds-ql@1.11.1(transitive)
- Removed@sap/cds-services@1.11.1(transitive)
- Removed@sap/cds-sql@1.11.1(transitive)
- Removed@sap/cds-sqlite@1.11.1(transitive)
- Removed@sap/generator-cds@2.4.8(transitive)
- Removed@sap/odata-server@1.3.3(transitive)
- Removedgeneric-pool@3.4.2(transitive)
- Removedyaml@1.2.0(transitive)
Updated@sap/cds-compiler@1.15.0
Updated@sap/cds-ql@1.14.0
Updated@sap/cds-services@1.14.0
Updated@sap/generator-cds@2.4.11