@sap/cds-compiler 4.1.2 → 4.2.4
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.
- package/CHANGELOG.md +107 -1
- package/bin/cdsc.js +6 -3
- package/doc/CHANGELOG_BETA.md +5 -0
- package/doc/CHANGELOG_DEPRECATED.md +15 -0
- package/lib/api/main.js +2 -2
- package/lib/api/options.js +2 -2
- package/lib/api/validate.js +24 -24
- package/lib/base/message-registry.js +41 -6
- package/lib/base/messages.js +7 -0
- package/lib/base/model.js +38 -8
- package/lib/checks/elements.js +11 -10
- package/lib/checks/manyNavigations.js +33 -0
- package/lib/checks/onConditions.js +5 -2
- package/lib/checks/queryNoDbArtifacts.js +2 -3
- package/lib/checks/selectItems.js +4 -55
- package/lib/checks/utils.js +3 -2
- package/lib/checks/validator.js +3 -1
- package/lib/compiler/.eslintrc.json +2 -1
- package/lib/compiler/assert-consistency.js +27 -24
- package/lib/compiler/base.js +6 -2
- package/lib/compiler/builtins.js +34 -34
- package/lib/compiler/checks.js +179 -208
- package/lib/compiler/classes.js +2 -2
- package/lib/compiler/cycle-detector.js +6 -6
- package/lib/compiler/define.js +66 -45
- package/lib/compiler/extend.js +81 -72
- package/lib/compiler/finalize-parse-cdl.js +26 -26
- package/lib/compiler/generate.js +61 -45
- package/lib/compiler/index.js +47 -49
- package/lib/compiler/kick-start.js +8 -7
- package/lib/compiler/moduleLayers.js +1 -1
- package/lib/compiler/populate.js +42 -35
- package/lib/compiler/propagator.js +6 -6
- package/lib/compiler/resolve.js +170 -126
- package/lib/compiler/shared.js +122 -45
- package/lib/compiler/tweak-assocs.js +93 -40
- package/lib/compiler/utils.js +15 -12
- package/lib/edm/.eslintrc.json +40 -1
- package/lib/edm/annotations/genericTranslation.js +721 -707
- package/lib/edm/annotations/preprocessAnnotations.js +88 -77
- package/lib/edm/csn2edm.js +389 -378
- package/lib/edm/edm.js +678 -772
- package/lib/edm/edmAnnoPreprocessor.js +132 -146
- package/lib/edm/edmInboundChecks.js +29 -27
- package/lib/edm/edmPreprocessor.js +686 -646
- package/lib/edm/edmUtils.js +277 -296
- package/lib/gen/language.checksum +1 -1
- package/lib/gen/language.interp +1 -1
- package/lib/gen/languageParser.js +1253 -1276
- package/lib/json/from-csn.js +34 -4
- package/lib/json/to-csn.js +4 -4
- package/lib/language/language.g4 +2 -5
- package/lib/main.d.ts +61 -1
- package/lib/model/csnUtils.js +31 -2
- package/lib/model/revealInternalProperties.js +1 -1
- package/lib/modelCompare/compare.js +37 -2
- package/lib/modelCompare/utils/filter.js +1 -1
- package/lib/optionProcessor.js +15 -3
- package/lib/render/toCdl.js +30 -4
- package/lib/render/toSql.js +5 -9
- package/lib/render/utils/common.js +8 -6
- package/lib/transform/db/applyTransformations.js +1 -1
- package/lib/transform/db/cdsPersistence.js +1 -1
- package/lib/transform/db/constraints.js +47 -17
- package/lib/transform/db/expansion.js +133 -50
- package/lib/transform/db/flattening.js +75 -7
- package/lib/transform/forOdata.js +4 -1
- package/lib/transform/forRelationalDB.js +80 -62
- package/lib/transform/localized.js +91 -54
- package/lib/transform/transformUtils.js +9 -10
- package/lib/utils/file.js +7 -7
- package/lib/utils/moduleResolve.js +210 -121
- package/lib/utils/objectUtils.js +1 -1
- package/package.json +5 -5
package/lib/compiler/populate.js
CHANGED
|
@@ -48,8 +48,8 @@ const {
|
|
|
48
48
|
} = require('./utils');
|
|
49
49
|
const { typeParameters } = require('./builtins');
|
|
50
50
|
|
|
51
|
-
const $inferred = Symbol.for('cds.$inferred');
|
|
52
|
-
const $location = Symbol.for('cds.$location');
|
|
51
|
+
const $inferred = Symbol.for( 'cds.$inferred' );
|
|
52
|
+
const $location = Symbol.for( 'cds.$location' );
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* These properties are copied from specified elements.
|
|
@@ -166,7 +166,7 @@ function populate( model ) {
|
|
|
166
166
|
*
|
|
167
167
|
* Calculating an effective association/composition implies calculating its
|
|
168
168
|
* target entity (including redirections), but not induce calculating the
|
|
169
|
-
* target's elements. Calculating an effective structure (entities, …)
|
|
169
|
+
* target's elements. Calculating an effective structure (entities, …) does
|
|
170
170
|
* not imply calculating the effective types of its elements. Calculating an
|
|
171
171
|
* effective array does not imply calculating its effective line type.
|
|
172
172
|
*/
|
|
@@ -215,7 +215,7 @@ function populate( model ) {
|
|
|
215
215
|
// console.log( 'ET-DO:', effectiveSeqNo, a?.kind, a?.name, a._extensions?.elements?.length )
|
|
216
216
|
extendArtifactAfter( a ); // after setting _effectiveType (for messages)
|
|
217
217
|
if (a.typeProps$)
|
|
218
|
-
setSpecifiedElementTypeProperties(a);
|
|
218
|
+
setSpecifiedElementTypeProperties( a );
|
|
219
219
|
}
|
|
220
220
|
// console.log( 'ET-END:', art?.kind, art?.name )
|
|
221
221
|
return art;
|
|
@@ -393,7 +393,7 @@ function populate( model ) {
|
|
|
393
393
|
proxyCopyMembers( art, 'elements', struct.elements, art.path?.location, '$navElement' );
|
|
394
394
|
return true;
|
|
395
395
|
}
|
|
396
|
-
if (art.elements || art.kind === '$
|
|
396
|
+
if (art.elements || art.kind === '$inline' ||
|
|
397
397
|
// no element expansions for "non-proper" types like
|
|
398
398
|
// entities (as parameter types) etc:
|
|
399
399
|
struct.kind !== 'type' && struct.kind !== 'element' && struct.kind !== 'param' &&
|
|
@@ -407,7 +407,8 @@ function populate( model ) {
|
|
|
407
407
|
const location = ref && ref.location || art.location;
|
|
408
408
|
// console.log( message( null, location, art, {target:struct,art}, 'Info','EXPAND-ELEM')
|
|
409
409
|
// .toString(), Object.keys(struct.elements))
|
|
410
|
-
proxyCopyMembers( art, 'elements', struct.elements, weakLocation( location )
|
|
410
|
+
proxyCopyMembers( art, 'elements', struct.elements, weakLocation( location ),
|
|
411
|
+
null, isDeprecatedEnabled( options, 'noKeyPropagationWithExpansions' ) );
|
|
411
412
|
// Set elements expansion status (the if condition is always true, as no
|
|
412
413
|
// elements expansion will take place on artifact with existing other
|
|
413
414
|
// member property):
|
|
@@ -541,7 +542,7 @@ function populate( model ) {
|
|
|
541
542
|
}
|
|
542
543
|
else if (typePropertiesFromSpecifiedElements[prop]) {
|
|
543
544
|
if (!ielem.typeProps$)
|
|
544
|
-
setLink(ielem, 'typeProps$', Object.create(null));
|
|
545
|
+
setLink( ielem, 'typeProps$', Object.create( null ) );
|
|
545
546
|
// Note: At this point in time, effectiveType() was likely not called on the
|
|
546
547
|
// element, yet. Setting it here, we can't compare it to its value from _origin.
|
|
547
548
|
ielem.typeProps$[prop] = selem[prop];
|
|
@@ -550,14 +551,14 @@ function populate( model ) {
|
|
|
550
551
|
|
|
551
552
|
selem.$replacement = true;
|
|
552
553
|
if (selem.elements)
|
|
553
|
-
setLink(ielem, 'elements$', selem.elements);
|
|
554
|
+
setLink( ielem, 'elements$', selem.elements );
|
|
554
555
|
if (selem.enum)
|
|
555
|
-
setLink(ielem, 'enum$', selem.enum);
|
|
556
|
+
setLink( ielem, 'enum$', selem.enum );
|
|
556
557
|
}
|
|
557
558
|
}
|
|
558
559
|
|
|
559
560
|
if (wasAnnotated)
|
|
560
|
-
setExpandStatusAnnotate(art, 'annotate');
|
|
561
|
+
setExpandStatusAnnotate( art, 'annotate' );
|
|
561
562
|
|
|
562
563
|
// TODO: We don't check enum$, yet! We first need to fix expansion for
|
|
563
564
|
// `cast(elem as EnumType)` (see #9421)
|
|
@@ -577,8 +578,8 @@ function populate( model ) {
|
|
|
577
578
|
for (const prop in art.typeProps$) {
|
|
578
579
|
let o = art;
|
|
579
580
|
if (o._effectiveType !== 0) { // cyclic
|
|
580
|
-
while (!o[prop] && getOrigin(o))
|
|
581
|
-
o = getOrigin(o);
|
|
581
|
+
while (!o[prop] && getOrigin( o ))
|
|
582
|
+
o = getOrigin( o );
|
|
582
583
|
}
|
|
583
584
|
|
|
584
585
|
if (typePropertiesFromSpecifiedElements[prop] === 'if-undefined') {
|
|
@@ -595,7 +596,7 @@ function populate( model ) {
|
|
|
595
596
|
if (query._combined || !query.from || !query.$tableAliases)
|
|
596
597
|
// already done (TODO: re-check!) or $join query or parse error
|
|
597
598
|
return query;
|
|
598
|
-
setLink( query, '_combined', Object.create(null) );
|
|
599
|
+
setLink( query, '_combined', Object.create( null ) );
|
|
599
600
|
query.$inlines = [];
|
|
600
601
|
forEachGeneric( query, '$tableAliases', resolveTabRef );
|
|
601
602
|
initFromColumns( query, query.columns );
|
|
@@ -621,7 +622,7 @@ function populate( model ) {
|
|
|
621
622
|
forEachGeneric( { elements: alias.elements }, 'elements', ( elem, name ) => {
|
|
622
623
|
if (elem.$duplicates !== true)
|
|
623
624
|
dictAddArray( query._combined, name, elem, null ); // not dictAdd()
|
|
624
|
-
});
|
|
625
|
+
} );
|
|
625
626
|
}
|
|
626
627
|
}
|
|
627
628
|
|
|
@@ -666,7 +667,7 @@ function populate( model ) {
|
|
|
666
667
|
function initFromColumns( query, columns, inlineHead = undefined ) {
|
|
667
668
|
const elemsParent = query.items || query;
|
|
668
669
|
if (!inlineHead) {
|
|
669
|
-
elemsParent.elements = Object.create(null);
|
|
670
|
+
elemsParent.elements = Object.create( null );
|
|
670
671
|
if (query._main._leadingQuery === query) // never the case for 'expand'
|
|
671
672
|
query._main.elements = elemsParent.elements;
|
|
672
673
|
}
|
|
@@ -700,7 +701,7 @@ function populate( model ) {
|
|
|
700
701
|
col.kind = 'element';
|
|
701
702
|
dictAdd( elemsParent.elements, id, col, ( name, location ) => {
|
|
702
703
|
error( 'duplicate-definition', [ location, query ], { name, '#': 'element' } );
|
|
703
|
-
});
|
|
704
|
+
} );
|
|
704
705
|
setMemberParent( col, id, query );
|
|
705
706
|
}
|
|
706
707
|
}
|
|
@@ -773,7 +774,7 @@ function populate( model ) {
|
|
|
773
774
|
// col ($replacement set before *)
|
|
774
775
|
// false if two cols have same name
|
|
775
776
|
function wildcardSiblings( columns, query ) {
|
|
776
|
-
const siblings = Object.create(null);
|
|
777
|
+
const siblings = Object.create( null );
|
|
777
778
|
if (!columns)
|
|
778
779
|
return siblings;
|
|
779
780
|
|
|
@@ -798,7 +799,7 @@ function populate( model ) {
|
|
|
798
799
|
const { elements } = query.items || query;
|
|
799
800
|
let location = wildcard.location || query.from && query.from.location || query.location;
|
|
800
801
|
const inferred = query._main.$inferred;
|
|
801
|
-
const excludingDict = (colParent || query).excludingDict || Object.create(null);
|
|
802
|
+
const excludingDict = (colParent || query).excludingDict || Object.create( null );
|
|
802
803
|
|
|
803
804
|
const envParent = wildcard._pathHead; // TODO: rename _pathHead to _columnParent
|
|
804
805
|
// console.log('S1:',location.line,location.col,
|
|
@@ -825,15 +826,15 @@ function populate( model ) {
|
|
|
825
826
|
dictAdd( elements, name, sibling, ( _name, loc ) => {
|
|
826
827
|
// there can be a definition from a previous inline with the same name:
|
|
827
828
|
error( 'duplicate-definition', [ loc, query ], { name, '#': 'element' } );
|
|
828
|
-
});
|
|
829
|
+
} );
|
|
829
830
|
setMemberParent( sibling, name, query );
|
|
830
831
|
}
|
|
831
832
|
// else {
|
|
832
833
|
// sibling.$inferred = 'query';
|
|
833
834
|
// }
|
|
834
835
|
}
|
|
835
|
-
else if (Array.isArray(navElem)) {
|
|
836
|
-
const names = navElem.filter( e => !e.$duplicates)
|
|
836
|
+
else if (Array.isArray( navElem )) {
|
|
837
|
+
const names = navElem.filter( e => !e.$duplicates )
|
|
837
838
|
.map( e => `${ e.name.alias }.${ e.name.element }` );
|
|
838
839
|
if (names.length) {
|
|
839
840
|
error( 'wildcard-ambiguous', [ location, query ], { id: name, names },
|
|
@@ -848,7 +849,7 @@ function populate( model ) {
|
|
|
848
849
|
dictAdd( elements, name, elem, ( _name, loc ) => {
|
|
849
850
|
// there can be a definition from a previous inline with the same name:
|
|
850
851
|
error( 'duplicate-definition', [ loc, query ], { name, '#': 'element' } );
|
|
851
|
-
});
|
|
852
|
+
} );
|
|
852
853
|
elem.$inferred = '*';
|
|
853
854
|
elem.name.$inferred = '*';
|
|
854
855
|
if (envParent)
|
|
@@ -895,7 +896,7 @@ function populate( model ) {
|
|
|
895
896
|
if (!sibling.target || sibling.target.$inferred || // not explicit REDIRECTED TO
|
|
896
897
|
path && path[path.length - 1].id !== sibling.name.id) { // or renamed
|
|
897
898
|
const { id } = sibling.name;
|
|
898
|
-
if (Array.isArray(navElem)) {
|
|
899
|
+
if (Array.isArray( navElem )) {
|
|
899
900
|
// ID published! Used in stakeholder project; if renamed, add to oldMessageIds
|
|
900
901
|
info( 'wildcard-excluding-many', [ sibling.name.location, query ],
|
|
901
902
|
{ id, keyword: 'excluding' },
|
|
@@ -1000,6 +1001,12 @@ function populate( model ) {
|
|
|
1000
1001
|
|
|
1001
1002
|
function redirectImplicitlyDo( elem, assoc, target, service ) {
|
|
1002
1003
|
// console.log('ES:',elem.name.absolute,elem.name.element);
|
|
1004
|
+
if (assoc._main === target && elem._main?.kind === 'entity' &&
|
|
1005
|
+
elem._main?._ancestors?.includes( target )) {
|
|
1006
|
+
// source and target of the model association are the same entity, and
|
|
1007
|
+
// the current main artifact is a suitable auto-redirection target → return it
|
|
1008
|
+
return elem._main;
|
|
1009
|
+
}
|
|
1003
1010
|
const elemScope = scopedRedirections && // null if no scoped redirections
|
|
1004
1011
|
preferredElemScope( target, service, elem, assoc._main || assoc );
|
|
1005
1012
|
const exposed = minimalExposure( target, service, elemScope );
|
|
@@ -1009,7 +1016,7 @@ function populate( model ) {
|
|
|
1009
1016
|
if (isAutoExposed( target ))
|
|
1010
1017
|
target = createAutoExposed( origTarget, service, elemScope );
|
|
1011
1018
|
const desc = origTarget._descendants ||
|
|
1012
|
-
setLink( origTarget, '_descendants', Object.create(null) );
|
|
1019
|
+
setLink( origTarget, '_descendants', Object.create( null ) );
|
|
1013
1020
|
if (!desc[service.name.absolute]) // could be the target itself (no repeated msgs)!
|
|
1014
1021
|
desc[service.name.absolute] = [ target ];
|
|
1015
1022
|
else
|
|
@@ -1031,16 +1038,16 @@ function populate( model ) {
|
|
|
1031
1038
|
std: 'Replace target $(TARGET) by one of $(SORTED_ARTS); can\'t auto-redirect this association if multiple projections exist in this service',
|
|
1032
1039
|
// eslint-disable-next-line max-len
|
|
1033
1040
|
two: 'Replace target $(TARGET) by $(SORTED_ARTS) or $(SECOND); can\'t auto-redirect this association if multiple projections exist in this service',
|
|
1034
|
-
});
|
|
1041
|
+
} );
|
|
1035
1042
|
// continuation semantics: no auto-redirection
|
|
1036
1043
|
}
|
|
1037
1044
|
else {
|
|
1038
1045
|
// referred (and probably inferred) assoc (without a user-provided target at that place)
|
|
1039
1046
|
// HINT: consider bin/cdsv2m.js when changing the following message text
|
|
1040
|
-
// No grouped and sub messages yet (TODO
|
|
1047
|
+
// No grouped and sub messages yet (TODO v5): mention at all target places with all assocs
|
|
1041
1048
|
const withAnno = annotationVal( exposed[0]['@cds.redirection.target'] );
|
|
1042
1049
|
for (const proj of exposed) {
|
|
1043
|
-
// TODO: def-ambiguous-target (just
|
|
1050
|
+
// TODO: def-ambiguous-target (just v5, as the current is infamous and used in options),
|
|
1044
1051
|
message( 'redirected-implicitly-ambiguous',
|
|
1045
1052
|
[ weakLocation( proj.name.location ), proj ],
|
|
1046
1053
|
{
|
|
@@ -1064,7 +1071,7 @@ function populate( model ) {
|
|
|
1064
1071
|
return target;
|
|
1065
1072
|
}
|
|
1066
1073
|
|
|
1067
|
-
// Return projections of `target` in `service`.
|
|
1074
|
+
// Return projections of `target` in `service`. Sorted by
|
|
1068
1075
|
// - first, only consider projections with @cds.redirection.target=true
|
|
1069
1076
|
// - exclude all indirect projections, i.e. those which are projection on others in list
|
|
1070
1077
|
//
|
|
@@ -1081,7 +1088,7 @@ function populate( model ) {
|
|
|
1081
1088
|
return exposed || [];
|
|
1082
1089
|
let min = [];
|
|
1083
1090
|
for (const e of exposed) {
|
|
1084
|
-
if (min.every( m => m._ancestors?.includes( e ))) {
|
|
1091
|
+
if (min.every( m => m._ancestors?.includes( e ) )) {
|
|
1085
1092
|
min = [ e ];
|
|
1086
1093
|
}
|
|
1087
1094
|
else if (min.length !== 1 || !e._ancestors?.includes( min[0] )) {
|
|
@@ -1228,7 +1235,7 @@ function populate( model ) {
|
|
|
1228
1235
|
return `${ service.name.absolute }.${ absolute }`;
|
|
1229
1236
|
const base = definitionScope( target );
|
|
1230
1237
|
if (base === target)
|
|
1231
|
-
return `${ service.name.absolute }.${ absolute.substring( absolute.lastIndexOf('.') + 1 ) }`;
|
|
1238
|
+
return `${ service.name.absolute }.${ absolute.substring( absolute.lastIndexOf( '.' ) + 1 ) }`;
|
|
1232
1239
|
// for scoped (e.g. calculated) entities, use exposed name of base:
|
|
1233
1240
|
const exposed = minimalExposure( base, service, elemScope );
|
|
1234
1241
|
// console.log(exposed.map( a => a.name.absolute ));
|
|
@@ -1300,18 +1307,18 @@ function populate( model ) {
|
|
|
1300
1307
|
};
|
|
1301
1308
|
// forward target parameters to projection
|
|
1302
1309
|
if (target.params) {
|
|
1303
|
-
art.params = Object.create(null);
|
|
1310
|
+
art.params = Object.create( null );
|
|
1304
1311
|
// is art.query.from.path[0].$syntax: ':' required?
|
|
1305
|
-
art.query.from.path[0].args = Object.create(null);
|
|
1306
|
-
forEachGeneric(target, 'params', (p, pn) => {
|
|
1307
|
-
art.params[pn] = linkToOrigin(p, pn, art, 'params', p.location);
|
|
1312
|
+
art.query.from.path[0].args = Object.create( null );
|
|
1313
|
+
forEachGeneric( target, 'params', (p, pn) => {
|
|
1314
|
+
art.params[pn] = linkToOrigin( p, pn, art, 'params', p.location );
|
|
1308
1315
|
art.query.from.path[0].args[pn] = {
|
|
1309
1316
|
name: { id: p.name.id, location: p.location },
|
|
1310
1317
|
location: p.location,
|
|
1311
1318
|
scope: 'param',
|
|
1312
1319
|
path: [ { id: pn, location: p.location } ],
|
|
1313
1320
|
};
|
|
1314
|
-
});
|
|
1321
|
+
} );
|
|
1315
1322
|
}
|
|
1316
1323
|
// TODO: do we need to tag the generated entity with elemScope = 'auto'?
|
|
1317
1324
|
if (autoexposed) {
|
|
@@ -20,7 +20,7 @@ const {
|
|
|
20
20
|
withAssociation,
|
|
21
21
|
viewFromPrimary,
|
|
22
22
|
} = require('./utils');
|
|
23
|
-
const $inferred = Symbol.for('cds.$inferred');
|
|
23
|
+
const $inferred = Symbol.for( 'cds.$inferred' );
|
|
24
24
|
// const { refString } = require( '../base/messages')
|
|
25
25
|
|
|
26
26
|
// Note that propagation here is also used for deep-copying (function `onlyViaParent`)
|
|
@@ -104,7 +104,7 @@ function propagate( model ) {
|
|
|
104
104
|
if (target._calcOrigin?._origin && target.value?._artifact) {
|
|
105
105
|
chain.push({ target, source: target.value._artifact });
|
|
106
106
|
if (checkAndSetStatus( target.value._artifact ))
|
|
107
|
-
news.push(target.value._artifact);
|
|
107
|
+
news.push( target.value._artifact );
|
|
108
108
|
|
|
109
109
|
if (target.value?._artifact.$inferred !== 'include') {
|
|
110
110
|
// If the referred to element is not inferred, it is a new one and not the original.
|
|
@@ -242,11 +242,11 @@ function propagate( model ) {
|
|
|
242
242
|
target.location ||
|
|
243
243
|
target._outer && target._outer.location;
|
|
244
244
|
const dict = source[prop];
|
|
245
|
-
target[prop] = Object.create(null); // also propagate empty elements
|
|
245
|
+
target[prop] = Object.create( null ); // also propagate empty elements
|
|
246
246
|
for (const name in dict) {
|
|
247
247
|
const member = linkToOrigin( dict[name], name, target, prop, location );
|
|
248
248
|
member.$inferred = 'proxy';
|
|
249
|
-
setEffectiveType(member, dict[name]);
|
|
249
|
+
setEffectiveType( member, dict[name] );
|
|
250
250
|
}
|
|
251
251
|
target[prop][$inferred] = 'prop';
|
|
252
252
|
}
|
|
@@ -286,7 +286,7 @@ function propagate( model ) {
|
|
|
286
286
|
if (target.kind === 'param' && source.kind === 'entity')
|
|
287
287
|
return; // Don't propagate from entity types to parameters (+ return type).
|
|
288
288
|
if (target.kind)
|
|
289
|
-
always(prop, target, source); // not in 'items'
|
|
289
|
+
always( prop, target, source ); // not in 'items'
|
|
290
290
|
}
|
|
291
291
|
|
|
292
292
|
function notNull( prop, target, source, viaType ) {
|
|
@@ -379,7 +379,7 @@ function checkAndSetStatus( art ) {
|
|
|
379
379
|
|
|
380
380
|
function setEffectiveType( target, source ) {
|
|
381
381
|
if (source._effectiveType !== undefined)
|
|
382
|
-
setLink( target, '_effectiveType', source._effectiveType);
|
|
382
|
+
setLink( target, '_effectiveType', source._effectiveType );
|
|
383
383
|
}
|
|
384
384
|
|
|
385
385
|
module.exports = {
|