Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@sap/cds-compiler

Package Overview
Dependencies
Maintainers
0
Versions
113
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 5.5.2 to 5.6.0

3

bin/cdsse.js

@@ -161,2 +161,5 @@ #!/usr/bin/env node

}
else if (n === 'Boolean') {
console.log( 'true keyword\nfalse keyword' );
}
else if (n !== 'Identifier') {

@@ -163,0 +166,0 @@ console.log( n, 'unknown' );

@@ -209,2 +209,4 @@ // The builtin artifacts of CDS

IsActiveEntity: {},
HasActiveEntity: {},
HasDraftEntity: {},
},

@@ -211,0 +213,0 @@ // Require that elements are accessed, i.e. no $draft, only $draft.<element>.

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

DataIntegration (published)
EntityRelationship (experimental)
Graph (published, experimental)

@@ -79,2 +80,7 @@ Hierarchy (published, experimental)

},
EntityRelationship: {
ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/EntityRelationship.xml' },
inc: { Alias: 'EntityRelationship', Namespace: 'com.sap.vocabularies.EntityRelationship.v1' },
int: { filename: 'EntityRelationship.xml' },
},
Graph: {

@@ -81,0 +87,0 @@ ref: { Uri: 'https://sap.github.io/odata-vocabularies/vocabularies/Graph.xml' },

191

lib/gen/BaseParser.js

@@ -1,2 +0,2 @@

// Base class for generated parser, for redepage v0.1.18
// Base class for generated parser, for redepage v0.1.19

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

$hasErrors = null;
leanConditions = {};
// trace:

@@ -167,2 +168,3 @@ trace = [];

}
this._tracePush( [ 'E', 0 ] );
const match = this._matchesInFollow( type, keyword, 'E' );

@@ -208,5 +210,7 @@ // If the parser reaches this point with match = null, even the top-level rule

const { keyword } = this.tokens[this.tokenIdx];
if (!keyword || this.keywords[keyword] ||
this._matchesInFollow( 'Id', keyword, 'R' ))
if (!keyword || this.keywords[keyword])
return this.g( state, follow );
this._tracePush( [ 'R', 0 ] );
if (this._matchesInFollow( 'Id', keyword, 'R' ))
return this.g( state, follow );
this.nextTokenAsId = true;

@@ -262,2 +266,4 @@ return false; // do not execute action after it

ci( state, ident = 'ident' ) { // consume identifier token
if (this.tokenIdx === this.fixKeywordTokenIdx)
return this.e();
const la = this.tokens[this.tokenIdx];

@@ -392,43 +398,70 @@ if (this.keywords[la.keyword])

// predicate used before rule call if with LL(1) conflict, 'Id' in other case
lP( first2 ) { // only start rule if this predicate returns true
// predicate used before rule call (and called by `ckP` and `gP`) on keyword
// branch if with weak LL(1) conflict, i.e. there is an 'Id' branch or the
// default branch has `Id` in its first-set (TODO: or rule end, and `Id` is in
// follow-union)
lP( first2 ) {
// nothing to check if not a non-reserved keyword:
const { keyword: lk1 } = this.tokens[this.tokenIdx];
if (!lk1 || this.keywords[lk1] !== 0)
if (!lk1 || this.keywords[lk1] !== 0 || this.fixKeywordTokenIdx === this.tokenIdx)
return true;
this._tracePush( [ 'K' ] );
const { type: lt2, keyword: lk2 } = this.tokens[this.tokenIdx + 1];
// Argument first2 is just a performance hint with ckP():
if (lt2 === 'IllegalToken')
return true
// Argument first2 is just a performance hint:
if (lk2 && first2?.[0] === 'Id' && !this.keywords[lk2] ||
first2?.includes( lk2 || lt2 )) {
this._tracePush( [ 'K', true ] );
this._traceSubPush( true );
return true;
}
this._tracePush( [ 'K' ] );
// now check it dynamically:
let cmd = this.table[this.s][lk1];
if (cmd[2] !== 1)
throw Error( `Unexpected command '${ cmd?.[0] }' without prediction at state ${ this.s } for ‘${ lk1 }’` );
if (this._walkPred( this.table[this.s][lk1], lk1, lt2, lk2 ))
return true;
this._tracePush( [ 'I' ] );
const choice = this.table[this.s];
if (!this._walkPred( choice.Id || choice[''], null, lt2, lk2 ))
return true;
this.nextTokenAsId = true;
return false;
}
// if not the keyword match, the command is “goto” or “rule call”
const savedState = this.s;
this.s = (cmd[0] === 'ck') ? cmd[1] : this._pred_keyword( cmd[1], lk1 );
_walkPred( cmd, lk1, lt2, lk2 ) {
const saved = this._saveForWalk();
const { length } = this.stack;
if (typeof cmd[0] !== 'number') // don't skip push to state with rule call
this.s = cmd[1];
if (cmd[0] !== (lk1 ? 'ck' : 'ci')) { // make the std case fast
let match1 = this._pred_next( 'Id', lk1, 'P' ); // TODO: really P for I?
if (!match1) {
if (lk1 || match1 === false) // assert for correct code generation
throw Error( `Cannot match first prediction token in rule at state ${ saved.s }` );
if (match1 == null) {
this._traceSubPush( 0 ); // TODO: make _pred_next push this
match1 = this._matchesInFollow( 'Id', lk1, 'I' );
}
else {
this._traceSubPush( false );
}
Object.assign( this, saved );
this.stack.length = length;
return !!match1;
}
}
this._traceSubPush( '' ); // between the two tokens
++this.tokenIdx; // for user lookahead fns and conditions
const match = this._pred_next( lt2, lk2, 'K' );
let match2 = this._pred_next( lt2, lk2, (lk1 ? 'K' : 'I') );
if (match2 == null) {
this._traceSubPush( 0 ); // TODO: make _pred_next push this
match2 = !!this._matchesInFollow( lt2, lk2, (lk1 ? 'K' : 'I') );
}
else {
this._traceSubPush( match2 );
}
Object.assign( this, saved );
this.stack.length = length;
--this.tokenIdx;
this.s = savedState;
const r = match ?? true;
if (match == null)
this._traceSubPush( 0 );
if (lt2 === 'IllegalToken')
return true
// TODO: instead of this IllegalToken test, implement a “confirm unreserved
// keyword as Id” prediction which tests whether the token after the then-Id
// matches.
this._traceSubPush( r );
if (!r)
this.nextTokenAsId = true;
return r;
return match2;
}

@@ -440,32 +473,12 @@

_pred_keyword( state, keyword ) {
// returns state after matching the first token as keyword, for lP()
while (state) {
this._traceSubPush( state );
let cmd = this.table[state];
if (!Array.isArray( cmd ))
cmd = cmd[keyword] || cmd.Id || cmd[''];
switch (cmd[0]) {
case 'ck': case 'mk':
return cmd[1]; // state after token consumption
case 'g': // TODO: another rule call?
break;
default:
if (typeof cmd[0] !== 'number')
throw Error( `Unexpected command ${ cmd[0] } at state ${ this.s }` );
}
state = cmd[1];
}
// reached end of rule without having consumed a token
throw Error( 'Not supported: option for unreserved keywords in follow set' );
}
_pred_next( type, keyword, mode ) { // mode = K | E | R | M
const useConditions = (mode === 'M'); // TODO: extra method with conditions ?
let hasEnteredRule = false;
_pred_next( type, keyword, mode ) { // mode = P | K | I | E | R | M
const properCall = (mode === 'P');
const lean = (mode !== 'M'); // TODO: extra method with conditions ?
// TODO: if false, use condition in this.leanConditions
let hasMatchedToken = null; // undecided yet → calculate on demand
while (this.s) {
if (useConditions)
this._tracePush( this.s );
if (lean)
this._traceSubPush( this.s );
else
this._traceSubPush( this.s );
this._tracePush( this.s ); // TODO: push new state instead
let cmd = this.table[this.s];

@@ -477,8 +490,10 @@ if (!Array.isArray( cmd )) {

: keyword && cmd[keyword] || cmd[type];
cmd = !(c && useConditions && this._rejectCondition( c, mode )) && c || cmd[''];
cmd = !(c && this._rejectCondition( c, mode, lean )) && c || cmd[''];
}
const state = this.s;
this.s = cmd[1];
switch (cmd[0]) {
case 'c': case 'ck': case 'ckA': // TODO: re-check ckA
return true;
case 'ciA':
case 'ciA': // TODO: fixKeywordTokenIdx ?
return mode !== 'R';

@@ -491,3 +506,4 @@ // in the R prediction for optional `Id<reserved>` at rule end, only

return mode !== 'R';
cmd = this.table[this.s]['']; // is currently always 'g' or 'e'
cmd = this.table[state]['']; // is currently always 'g' or 'e'
this.s = cmd[1];
break;

@@ -508,8 +524,19 @@ case 'm':

if (typeof cmd[0] !== 'number')
throw Error( `Unexpected command ${ cmd[0] } at state ${ this.s }` );
throw Error( `Unexpected command ${ cmd[0] } at state ${ state }` );
// If the parser enters a rule, reaching the rule end (can happen with
// option `minTokensMatched`) means "no match".
hasEnteredRule = true;
hasMatchedToken = false;
// If we want to support conditions before matching the first token in a
// rule, we would have to handle `this.stack` and `this.dynamically_`.
if (properCall) {
// rule_() - TODO: also w/ conditions before matching first token
this.stack.push( {
ruleState: cmd[1],
followState: cmd[0],
tokenIdx: this.tokenIdx,
prec: this.prec_,
} );
this.dynamic_ = Object.create( this.dynamic_ );
this.prec_ = null;
}
}

@@ -519,3 +546,2 @@ // We could optimize with rule call - only 'Id' must be further investigated

// in both cases if no condition is evaluated
this.s = cmd[1];
// TODO <prepare=…, arg=…> for real trial run also before all returns

@@ -535,19 +561,22 @@ // if (cmd[5])

// behind the current rule _after_ having decided that the token is to be
// matched as identifier.
return !hasEnteredRule && null; // let caller decide how to interpret this
// matched as identifier.
return (hasMatchedToken ?? this.tokenIdx > this.stack.at( -1 ).tokenIdx)
&& null; // let caller decide how to interpret this
}
_rejectCondition( cmd, mode ) {
_rejectCondition( cmd, mode, lean ) {
const cond = cmd[3];
if (!cond)
if (!cond || lean && !this.leanConditions[cond])
return false;
if (!this.constructor.tracingParser)
return !this[cond]( mode, cmd[4] );
// TODO: let this[cond]( true ) return recovery badness in error case
const { traceName } = this[cond];
this._tracePush( [ 'C', traceName?.call( this, cmd[4] ) ?? cond ] );
// calling the condition might have side effects (precendence conditions have)
// → call tracing “name” before
// TODO: let this[cond]( true ) return recovery badness in error case
if (!lean) {
const { traceName } = this[cond];
this._tracePush( [ 'C', traceName?.call( this, cmd[4] ) ?? cond ] );
// calling the condition might have side effects (precendence conditions have)
// → call tracing “name” before
}
const fail = !this[cond]( mode, cmd[4] );
this._traceSubPush( !fail );
this._traceSubPush( lean ? { true: 'C✔', false: 'C✖' }[!fail] : !fail );
return fail;

@@ -557,3 +586,3 @@ }

_matchesInFollow( type, keyword, mode ) { // mode = E | R
this._tracePush( [ mode, 0 ] );
// TODO: now also set stack!
const savedState = this.s;

@@ -579,5 +608,7 @@ // TODO: caching

_confirmExpected( token, saved ) { // mode = M
const [ type, keyword ] = (/^[_a-z]/.test( token )) ? [ 'Id', token ] : [ token ];
const fix = /^[_a-z]/.test( token );
const [ type, keyword ] = (fix) ? [ 'Id', token ] : [ token ];
Object.assign( this.la(), { type, keyword } );
this._cloneFromSaved( saved );
this.fixKeywordTokenIdx = fix && this.tokenIdx;
this.trace = [];

@@ -655,2 +686,4 @@ let match;

!Object.hasOwn( expecting, prop ) && prop.charAt(0) !== ' ') {
// TODO: or call this.translateParserToken_ always?
// it should then directly set the dictionary -> setTokenInSet_()
if (lookahead) { // yes, independently from ckA()

@@ -732,2 +765,3 @@ for (const p of this.translateParserToken_( prop, lookahead ))

this._trace( 'collect tokens for message,' );
const { trace } = this;
const saved = this._saveForWalk();

@@ -739,2 +773,3 @@ const expecting = Object.keys( set )

Object.assign( this, saved );
this.trace = trace;
// TODO: also trace M(…) collection, extra line for each token, with condition

@@ -780,2 +815,3 @@ return expecting;

this.conditionStackLength = null;
this.fixKeywordTokenIdx = -1; // was set when collecting expecting-set

@@ -907,2 +943,5 @@ // TODO: re-check for rule calls which are at the optional rule end:

hide_( mode ) {
return mode !== 'M';
}
precLeft_( _test, prec ) { // <prec=…>, <…,assoc=left>, <…,prefix=once>

@@ -909,0 +948,0 @@ const parentPrec = this.stack.at( -1 ).prec;

@@ -43,2 +43,4 @@ 'use strict';

class AstBuildingParser extends BaseParser {
leanConditions = { afterBrace: true };
constructor( lexer, keywords, table, options, messageFunctions ) {

@@ -216,2 +218,12 @@ super( lexer, keywords, table ); // lexer has file

notAfterEntityArgOrFilter( mode ) {
if (mode !== 'M')
return true;
const { type } = this.lb();
if (type !== ')' && type !== ']')
return true;
const { followState } = this.stack.at( -1 );
return !this.table[followState][':'];
}
// <prec=10, postfix=once> + test that the next token is not `null`; TODO: code

@@ -259,2 +271,19 @@ // completion for `… default 3 not ~;` → currently just `null` but hey

/**
* Restrictions according to the expression of a select column.
* Currently only to restrict it to a single `Id` for published associations.
*/
columnExpr( mode, arg ) {
if (mode)
return this.columnExpr$;
// TODO: should we use (text of) syntax-unexpected-assoc somewhere ?
if (arg)
this.columnExpr$ = this.tokenIdx;
else if (this.columnExpr$ !== this.tokenIdx - 1 ||
this.lb().type !== 'Id' ||
[ 'true', 'false', 'null' ].includes( this.lb().keyword ) )
this.columnExpr$ = null;
return null;
}
/**
* Prepare element restrictions and check validility of final anno assignments.

@@ -327,5 +356,17 @@ *

noRepeatedCardinality( mode ) {
if (this.tokens[this.tokenIdx - 2]?.type !== ']')
return true;
if (mode === 'M')
return false;
// currently just warning if same cardinality provided twice
const same = { one: '1', many: '*' }[this.la().keyword];
return this.tokens[this.tokenIdx - 3]?.text === same;
}
/**
* `;` between statements is optional only after a `}` (ex braces of structure
* values for annotations).
* values for annotations and foreign key specifications).
*
* Beware: mentioned in leanConditions, i.e. executed in predictions!
*/

@@ -335,2 +376,13 @@ afterBrace( test ) {

this.afterBrace$ = this.tokenIdx;
// TODO TOOL: the following test belongs to the BaseParser.js:
if (this.conditionTokenIdx === this.tokenIdx && // tested on same
this.conditionStackLength == null && // after error recover
test !== 'M')
return true;
// Strange optional `;` after PROJECTION ON source: the rule exit prediction
// for fromRefWithOptAlias etc now checks C(afterBrace):
if (test === 'E' && this.afterBrace$ > 0 &&
this.tokens[this.afterBrace$ - 1]?.keyword === 'projection' &&
this.tokens[this.afterBrace$].keyword === 'on')
return true;
return this.afterBrace$ === this.tokenIdx;

@@ -846,3 +898,3 @@ }

this.reportDuplicateClause( 'cardinality', targetMax, art.cardinality.targetMax,
card.keyword, true );
card.keyword );
}

@@ -855,5 +907,5 @@ else {

// TODO: as condition
reportExpandInline( column, isInline ) {
// called before matching `{`
const { name } = column;
if (column.value && !column.value.path) {

@@ -874,14 +926,5 @@ // improve error location when using "inline" `.{…}` after ref (arguments and

}
if (isInline && name) {
const alias = this.tokens[this.tokenIdx - 2];
const location = (isInline === true)
? alias.location
: this.combineLocation( isInline, alias );
this.error( 'syntax-unexpected-alias', location, { code: '.{ ‹inline› }' },
'Unexpected alias name before $(CODE)' );
// continuation semantics: ignore AS
}
}
reportDuplicateClause( prop, erroneous, chosen, code, literalValIfNotEq ) {
reportDuplicateClause( prop, erroneous, chosen, code ) {
// probably easier for message linters not to use (?:) for the message id...?

@@ -898,7 +941,3 @@ const args = {

}
else if (prop !== 'notNull') { // already via guard in grammar
if (literalValIfNotEq)
args.code = chosen.val;
this.message( 'syntax-duplicate-clause', erroneous.location, args );
}
// TODO extra msg text 'syntax-duplicate-clause' for noRepeatedCardinality()
}

@@ -1102,16 +1141,12 @@

// TODO: as condition
associationInSelectItem( art ) {
if (art.name)
return;
this.classifyImplicitName( 'ItemAssoc', art.value );
const path = art.value?.path;
// we cannot compare "just one token before `:`" because there might be annos
if (path && path.length === 1 && !art.name && !art.expand && !art.inline) {
const name = path[0];
if (path.length === 1 && !name.args && !name.cardinality && !name.where) {
art.name = name;
delete art.value;
return;
}
if (path?.length) {
art.name = path.at( -1 ); // usually length 1, but make it also work during error recovery
delete art.value;
}
this.error( 'syntax-unexpected-assoc', this.la(), {},
'Unexpected association definition in select item' );
}

@@ -1118,0 +1153,0 @@

@@ -655,2 +655,5 @@ 'use strict';

if (iterateOptions.keepKeysOrigin)
setProp(obj, '$originalKeyRef', { ref: root.ref, as: root.as });
return obj;

@@ -657,0 +660,0 @@ });

@@ -191,3 +191,3 @@ 'use strict';

{ error, info, throwWithAnyError }, csnUtils,
{ skipArtifact: isExternalServiceMember });
{ skipArtifact: isExternalServiceMember, keepKeysOrigin: true });
}

@@ -194,0 +194,0 @@

@@ -5,3 +5,3 @@ 'use strict';

const { setProp } = require('../../base/model');
const { applyTransformations, implicitAs, findAnnotationExpression, copyAnnotations, isDeepEqual } = require('../../model/csnUtils');
const { transformAnnotationExpression, applyTransformations, implicitAs, findAnnotationExpression, copyAnnotations, isDeepEqual } = require('../../model/csnUtils');
const { EdmTypeFacetNames } = require('../../edm/EdmPrimitiveTypeDefinitions');

@@ -64,2 +64,4 @@

}
adaptAnnotationsRefs(generatedForeignKeys, csnUtils);
setProp(element, '$generatedForeignKeys', generatedForeignKeys.map(gfk => gfk[0]));

@@ -74,5 +76,5 @@ orderedElements.push(...generatedForeignKeys);

}, Object.create(null));
}
}
function createForeignKeysForElement(csnUtils, path, element, prefix, csn, options, pathDelimiter, lvl = 0 ) {
function createForeignKeysForElement(csnUtils, path, element, prefix, csn, options, pathDelimiter, lvl = 0, originalkey = {} ) {
const special$self = !csn?.definitions?.$self && '$self';

@@ -115,3 +117,12 @@ const isInspectRefResult = !Array.isArray(path);

const result = csnUtils.inspectRef(continuePath);
fks = fks.concat(createForeignKeysForElement(csnUtils, result, result.art, alias, csn, options, pathDelimiter, lvl + 1));
let gfks = createForeignKeysForElement(csnUtils, result, result.art, alias, csn, options, pathDelimiter, lvl + 1,
lvl === 0 ? { ref: key.ref, as: key.as, $path: key.$path, $originalKeyRef: key.$originalKeyRef } : originalkey);
if (lvl === 0) {
gfks.forEach(gfk => copyAnnotations(key, gfk[1]));
// once applied -> remove the annotations from the keys array, to keep the OData CSN size as small as possible
Object.keys(key).forEach( prop => {
if (prop[0] === '@') delete key[prop]
});
}
fks = fks.concat(gfks);
});

@@ -125,3 +136,3 @@ }

const continuePath = getContinuePath([ 'elements', elemName ]);
fks = fks.concat(createForeignKeysForElement(csnUtils, continuePath, elem, elemName, csn, options, pathDelimiter, lvl + 1));
fks = fks.concat(createForeignKeysForElement(csnUtils, continuePath, elem, elemName, csn, options, pathDelimiter, lvl + 1, originalkey));
}

@@ -138,3 +149,3 @@ });

});
return [ [ prefix, newFk ] ];
return [ [ prefix, newFk, originalkey ] ];
}

@@ -149,5 +160,9 @@

fk[1]['@odata.foreignKey4'] = prefix;
const validAnnoNames = Object.keys(element).filter(pn => pn[0] === '@' && !findAnnotationExpression(element, pn));
copyAnnotations(element, fk[1], true, {}, validAnnoNames);
const allowedOverwriteAnnotationNames = ['@odata.Type', ...EdmTypeFacetNames.map(f => `@odata.${f}`)];
const validAnnoNames = Object.keys(element).filter(pn => pn[0] === '@' && !allowedOverwriteAnnotationNames.includes(pn) && !findAnnotationExpression(element, pn));
copyAnnotations(element, fk[1], false, {}, validAnnoNames);
const overwriteAnnoNames = Object.keys(element).filter(pn => allowedOverwriteAnnotationNames.includes(pn) && !findAnnotationExpression(element, pn));
copyAnnotations(element, fk[1], true, {}, overwriteAnnoNames);
// propagate not null to final foreign key

@@ -185,4 +200,72 @@ for (const prop of [ 'notNull', 'key' ]) {

}
function adaptAnnotationsRefs(generatedForeignKeys, csnUtils) {
let reportedErrorsForAnnoPath = {};
generatedForeignKeys.forEach(gfk => {
Object.entries(gfk[1]).forEach(([key, value]) => {
if (key[0] !== '@') return;
transformAnnotationExpression(gfk[1], key, {
ref: (_parent, _prop, ref, path, _p, _ppn, ctx) => {
if (ref[0] !== '$self') {
const { art } = csnUtils.inspectRef(getOriginatingKeyPath(gfk, path));
if (csnUtils.isManagedAssociation(art)) {
if (!reportedErrorsForAnnoPath[path]) {
error('odata-anno-xpr-ref', path, { elemref: { ref }, anno: key, '#': 'fk_substitution' });
reportedErrorsForAnnoPath[path] = true;
}
} else {
const gfkForRef = findGeneratedForeignKeyForKeyRef(generatedForeignKeys, ref);
if (gfkForRef.length === 1) {
ref[0] = gfkForRef[0][0];
if (ctx?.annoExpr?.['=']) {
ctx.annoExpr['='] = true;
}
} else {
// check if the annotation reference points to a structure that has been expanded,
// if so -> report an error
const foundInOriginalRef = findOriginalRef(generatedForeignKeys.filter(gfk => gfk[2].$originalKeyRef), ref);
// references to expanded structures in flat mode will be found in the $originalKeyRef
// and in strucred mode more than one match will be found in the generated foreign keys
if ((foundInOriginalRef.length || gfkForRef.length > 1) && !reportedErrorsForAnnoPath[path]) {
error('odata-anno-xpr-ref', path, { elemref: { ref }, anno: key, '#': 'fk_substitution' });
reportedErrorsForAnnoPath[path] = true;
}
}
}
}
}
}, value?.$path?.slice(0, value.$path.length - 1));
});
});
// During tuple expansion, the key ref object looses the $path, therefore
// it needs to be extracted from the anno path
function getOriginatingKeyPath(gfk, path) {
return gfk[2].$path || path.slice(0, path.findIndex(ps => ps[0] === '@'));
}
// Loops through the generated foreign keys for this entity
// and filters the ones, which were created for this specific
// key ref. In case there are more than one foreign keys found,
// that means the key ref points to a structured element/managed assoc
function findGeneratedForeignKeyForKeyRef(generatedForeignKeys, ref) {
return generatedForeignKeys.filter(gfk => {
return (ref.join() === (gfk[2].as || implicitAs(gfk[2].ref)));
});
}
// Tuple expansion is performed before the generation of the foreign keys and the original(unexpanded) key ref
// is stored in the property $originalKeyRef. Here we try to evaluate whether the reference in the annotation
// points to a structure that has been expanded.
function findOriginalRef(generatedForeignKeys, ref) {
return generatedForeignKeys.filter(gfk => {
return (ref.join() === (gfk[2].$originalKeyRef.as || implicitAs(gfk[2].$originalKeyRef.ref)));
});
}
}
}
module.exports = createForeignKeyElements;
{
"name": "@sap/cds-compiler",
"version": "5.5.2",
"version": "5.6.0",
"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

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

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

Sorry, the diff of this file is not supported yet

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