Socket
Socket
Sign inDemoInstall

@sap/cds-compiler

Package Overview
Dependencies
Maintainers
1
Versions
105
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@sap/cds-compiler - npm Package Compare versions

Comparing version 4.0.0 to 4.0.2

15

CHANGELOG.md

@@ -10,2 +10,17 @@ # ChangeLog for cds compiler and backends

## Version 4.0.2 - 2023-06-22
### Fixed
- to.sql.migration: When drop-creating views, also drop-create (transitively) dependent views.
- to.edm(x):
+ Forward `@odata.singleton { nullable }` annotation to parameter entity.
+ Annotations assigned to a parameterized entity are propagated to the parameter entity if the annotation is
applicable to either an `edm.EntitySet` or `edm.Singleton`. This especially covers all `@Capabilities` and their
shortcut forms like `@readonly` and `@insertonly`. The original annotation is not removed from the original entity.
Annotations that should be rendered at the parameter `edm.EntityType` can be qualified with `$parameters`.
Explicitly qualified annotations are removed from the original entity allowing individual assignments.
## Version 4.0.0 - 2023-06-06

@@ -12,0 +27,0 @@

30

lib/api/main.js

@@ -387,2 +387,3 @@ /** @module API */

const markedSkipByUs = {};
const cleanup = [];

@@ -408,2 +409,3 @@ // Delete artifacts that are already present in csn

cleanup.push(() => delete diffArtifact['@cds.persistence.skip']);
markedSkipByUs[artifactName] = true;
}

@@ -413,2 +415,29 @@ });

const sortOrder = sortViews({ sql: {}, csn: afterImage });
const dependentsDict = {};
sortOrder.forEach(({ name, dependents }) => {
dependentsDict[name] = dependents;
});
const stack = Object.keys(drops.creates);
while (stack.length > 0) {
const name = stack.pop();
const artifact = diff.definitions[name];
if (drops.creates[name] === undefined) {
if (artifact['@cds.persistence.skip'] && markedSkipByUs[name]) {
// Remove the skip so we render a CREATE VIEW
diff.definitions[name]['@cds.persistence.skip'] = false;
drops.creates[name] = `DROP VIEW ${ identifierUtils.renderArtifactName(name) };`;
}
}
const dependents = dependentsDict[name];
if (dependents) { // schedule any dependents for processing that don't have a drop-create yet
for (const dependantName in dependents) {
if (!drops.creates[dependantName])
stack.push(dependantName);
}
}
}
// Convert the diff to SQL.

@@ -425,3 +454,2 @@ if (!internalOptions.beta)

// TODO: Handle `ADD CONSTRAINT` etc!
const sortOrder = sortViews({ sql: {}, csn: afterImage });

@@ -428,0 +456,0 @@ const dropSqls = [];

6

lib/model/sortViews.js

@@ -96,3 +96,2 @@ 'use strict';

const { layers, leftover } = sortTopologically(csn, _dependents, _dependencies);
cleanup.forEach(fn => fn());
if (leftover.length > 0)

@@ -103,3 +102,3 @@ throw new ModelError('Unable to build a correct dependency graph! Are there cycles?');

// keep the "artifact name" - needed for to.hdi sorting
layers.forEach(layer => layer.forEach(objName => result.push({ name: objName, sql: sql[objName] })));
layers.forEach(layer => layer.forEach(objName => result.push({ name: objName, sql: sql[objName], dependents: csn.definitions[objName][_dependents] })));
// attach sql artifacts which are not considered during the view sorting algorithm

@@ -112,3 +111,6 @@ // --> this is the case for "ALTER TABLE ADD CONSTRAINT" statements,

});
cleanup.forEach(fn => fn());
return result;
};

@@ -315,6 +315,4 @@ 'use strict';

// Rename shorthand annotations within artifact or element 'node' according to a builtin
// list.
// Rename shorthand annotations within artifact or element 'node' according to a builtin list
function renameShorthandAnnotations(node) {
// FIXME: Verify this list - are they all still required? Do we need any more?
const setMappings = {

@@ -326,8 +324,8 @@ '@label': '@Common.Label',

const renameMappings = {
'@ValueList.entity': '@Common.ValueList.entity',
'@ValueList.type': '@Common.ValueList.type',
'@Capabilities.Deletable': '@Capabilities.DeleteRestrictions.Deletable',
'@Capabilities.Insertable': '@Capabilities.InsertRestrictions.Insertable',
'@Capabilities.Updatable': '@Capabilities.UpdateRestrictions.Updatable',
'@Capabilities.Readable': '@Capabilities.ReadRestrictions.Readable',
'@ValueList.entity': { val: '@Common.ValueList', op: 'entity' },
'@ValueList.type': { val: '@Common.ValueList', op: 'type' },
'@Capabilities.Deletable': { val: '@Capabilities.DeleteRestrictions', op: 'Deletable' },
'@Capabilities.Insertable': { val: '@Capabilities.InsertRestrictions', op: 'Insertable' },
'@Capabilities.Updatable': { val: '@Capabilities.UpdateRestrictions', op: 'Updatable' },
'@Capabilities.Readable': { val: '@Capabilities.ReadRestrictions', op: 'Readable' }
};

@@ -337,2 +335,4 @@

const renameShortCuts = Object.keys(renameMappings);
// Capabilities shortcuts have precedence over @readonly/@insertonly
Object.keys(node).forEach( name => {

@@ -342,9 +342,15 @@ if (!name.startsWith('@'))

// Rename according to map above
const renamePrefix = (name in renameMappings) ? name : renameShortCuts.find(p => name.startsWith(p + '.'));
const renamePrefix = (name in renameMappings)
? name
: renameShortCuts.find(p => name.startsWith(p + '.'));
if(renamePrefix) {
renameAnnotation(node, name, name.replace(renamePrefix, renameMappings[renamePrefix]));
} else {
const mapping = renameMappings[renamePrefix];
renameAnnotation(node, name, name.replace(renamePrefix, `${mapping.val}.${mapping.op}`));
}
else {
// The two mappings have no overlap, so no need to check for second map if first matched.
// Rename according to map above
const setPrefix = (name in setMappings) ? name : setShortCuts.find(p => name.startsWith(p + '.'));
const setPrefix = (name in setMappings)
? name
: setShortCuts.find(p => name.startsWith(p + '.') || name.startsWith(p + '#'));
if(setPrefix) {

@@ -354,34 +360,42 @@ setAnnotation(node, name.replace(setPrefix, setMappings[setPrefix]), node[name]);

}
});
// Special case: '@readonly' becomes a triplet of capability restrictions for entities,
// but '@Core.Immutable' for everything else.
if (!(node['@readonly'] && node['@insertonly'])) {
if (name === '@readonly' && node[name]) {
// Special case: '@readonly' becomes a triplet of capability restrictions for entities,
// but '@Core.Computed' for everything else.
// only if not both readonly/insertonly are true do the mapping
if(!(node['@readonly'] && node['@insertonly'])) {
if(node['@readonly']) {
const setRO = (qualifier) => {
if (node.kind === 'entity' || node.kind === 'aspect') {
setAnnotation(node, '@Capabilities.DeleteRestrictions.Deletable', false);
setAnnotation(node, '@Capabilities.InsertRestrictions.Insertable', false);
setAnnotation(node, '@Capabilities.UpdateRestrictions.Updatable', false);
setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifier ? '#' + qualifier : ''}.Deletable`, false);
setAnnotation(node, `@Capabilities.InsertRestrictions${ qualifier ? '#' + qualifier : ''}.Insertable`, false);
setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifier ? '#' + qualifier : ''}.Updatable`, false);
} else {
setAnnotation(node, '@Core.Computed', true);
}
};
setRO(undefined);
}
// @insertonly is effective on entities/queries only
if (node['@insertonly'] && (node.kind === 'entity' || node.kind === 'aspect')) {
const setIO = (qualifier) => {
setAnnotation(node, `@Capabilities.DeleteRestrictions${ qualifier ? '#' + qualifier : ''}.Deletable`, false);
setAnnotation(node, `@Capabilities.ReadRestrictions${ qualifier ? '#' + qualifier : ''}.Readable`, false);
setAnnotation(node, `@Capabilities.UpdateRestrictions${ qualifier ? '#' + qualifier : ''}.Updatable`, false);
}
// @insertonly is effective on entities/queries only
else if (name === '@insertonly' && node[name]) {
if (node.kind === 'entity' || node.kind === 'aspect') {
setAnnotation(node, '@Capabilities.DeleteRestrictions.Deletable', false);
setAnnotation(node, '@Capabilities.ReadRestrictions.Readable', false);
setAnnotation(node, '@Capabilities.UpdateRestrictions.Updatable', false);
}
}
setIO(undefined);
}
// Only on element level: translate @mandatory
if (name === '@mandatory' && node[name] &&
node.kind === undefined && node['@Common.FieldControl'] === undefined) {
}
// @Validation.Pattern is applicable to "Term" => node.kind === annotation
if (node['@assert.format'] != null)
setAnnotation(node, '@Validation.Pattern', node['@assert.format']);
// Only on element level
if(node.kind == null) {
if (node['@mandatory']&& node['@Common.FieldControl'] === undefined) {
setAnnotation(node, '@Common.FieldControl', { '#': 'Mandatory' });
}
if (name === '@assert.format' && node[name] !== null)
setAnnotation(node, '@Validation.Pattern', node['@assert.format']);
if (name === '@assert.range' && node[name] !== null) {
if (node['@assert.range'] != null) {
if (Array.isArray(node['@assert.range']) && node['@assert.range'].length === 2) {

@@ -392,3 +406,3 @@ setAnnotation(node, '@Validation.Minimum', node['@assert.range'][0]);

}
});
}
}

@@ -395,0 +409,0 @@

{
"name": "@sap/cds-compiler",
"version": "4.0.0",
"version": "4.0.2",
"description": "CDS (Core Data Services) compiler and backends",

@@ -5,0 +5,0 @@ "homepage": "https://cap.cloud.sap/",

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc