@sap/cds-compiler 4.0.2 → 4.2.2

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.
Files changed (101) hide show
  1. package/CHANGELOG.md +200 -5
  2. package/bin/cdsc.js +18 -15
  3. package/doc/CHANGELOG_BETA.md +16 -0
  4. package/doc/CHANGELOG_DEPRECATED.md +15 -0
  5. package/lib/api/main.js +33 -13
  6. package/lib/api/options.js +2 -2
  7. package/lib/api/validate.js +25 -25
  8. package/lib/base/location.js +6 -7
  9. package/lib/base/message-registry.js +123 -42
  10. package/lib/base/messages.js +18 -10
  11. package/lib/base/model.js +43 -10
  12. package/lib/checks/defaultValues.js +6 -6
  13. package/lib/checks/elements.js +11 -10
  14. package/lib/checks/foreignKeys.js +0 -5
  15. package/lib/checks/manyNavigations.js +33 -0
  16. package/lib/checks/onConditions.js +22 -14
  17. package/lib/checks/queryNoDbArtifacts.js +132 -73
  18. package/lib/checks/selectItems.js +4 -55
  19. package/lib/checks/sql-snippets.js +15 -4
  20. package/lib/checks/types.js +3 -3
  21. package/lib/checks/utils.js +4 -3
  22. package/lib/checks/validator.js +3 -1
  23. package/lib/compiler/.eslintrc.json +2 -1
  24. package/lib/compiler/assert-consistency.js +71 -40
  25. package/lib/compiler/base.js +7 -2
  26. package/lib/compiler/builtins.js +40 -41
  27. package/lib/compiler/checks.js +415 -367
  28. package/lib/compiler/classes.js +62 -0
  29. package/lib/compiler/cycle-detector.js +9 -9
  30. package/lib/compiler/define.js +124 -90
  31. package/lib/compiler/extend.js +115 -88
  32. package/lib/compiler/finalize-parse-cdl.js +26 -25
  33. package/lib/compiler/generate.js +57 -49
  34. package/lib/compiler/index.js +56 -56
  35. package/lib/compiler/kick-start.js +10 -7
  36. package/lib/compiler/moduleLayers.js +1 -1
  37. package/lib/compiler/populate.js +180 -144
  38. package/lib/compiler/propagator.js +10 -9
  39. package/lib/compiler/resolve.js +321 -246
  40. package/lib/compiler/shared.js +812 -433
  41. package/lib/compiler/tweak-assocs.js +114 -50
  42. package/lib/compiler/utils.js +241 -46
  43. package/lib/edm/.eslintrc.json +40 -1
  44. package/lib/edm/annotations/genericTranslation.js +721 -707
  45. package/lib/edm/annotations/preprocessAnnotations.js +88 -77
  46. package/lib/edm/csn2edm.js +389 -378
  47. package/lib/edm/edm.js +679 -770
  48. package/lib/edm/edmAnnoPreprocessor.js +132 -146
  49. package/lib/edm/edmInboundChecks.js +29 -27
  50. package/lib/edm/edmPreprocessor.js +689 -648
  51. package/lib/edm/edmUtils.js +279 -300
  52. package/lib/gen/Dictionary.json +34 -10
  53. package/lib/gen/language.checksum +1 -1
  54. package/lib/gen/language.interp +1 -1
  55. package/lib/gen/languageParser.js +2857 -2856
  56. package/lib/json/from-csn.js +77 -51
  57. package/lib/json/to-csn.js +15 -15
  58. package/lib/language/antlrParser.js +2 -1
  59. package/lib/language/genericAntlrParser.js +52 -43
  60. package/lib/language/language.g4 +61 -64
  61. package/lib/language/multiLineStringParser.js +2 -0
  62. package/lib/main.d.ts +65 -0
  63. package/lib/model/csnRefs.js +37 -19
  64. package/lib/model/csnUtils.js +51 -18
  65. package/lib/model/revealInternalProperties.js +30 -22
  66. package/lib/modelCompare/compare.js +149 -41
  67. package/lib/modelCompare/utils/filter.js +55 -25
  68. package/lib/optionProcessor.js +21 -9
  69. package/lib/render/manageConstraints.js +20 -17
  70. package/lib/render/toCdl.js +63 -23
  71. package/lib/render/toHdbcds.js +2 -2
  72. package/lib/render/toRename.js +4 -9
  73. package/lib/render/toSql.js +82 -35
  74. package/lib/render/utils/common.js +11 -9
  75. package/lib/render/utils/unique.js +52 -0
  76. package/lib/transform/db/applyTransformations.js +62 -21
  77. package/lib/transform/db/assertUnique.js +7 -8
  78. package/lib/transform/db/associations.js +2 -2
  79. package/lib/transform/db/cdsPersistence.js +9 -9
  80. package/lib/transform/db/constraints.js +47 -17
  81. package/lib/transform/db/expansion.js +138 -68
  82. package/lib/transform/db/flattening.js +98 -30
  83. package/lib/transform/db/rewriteCalculatedElements.js +20 -14
  84. package/lib/transform/db/temporal.js +1 -1
  85. package/lib/transform/db/transformExists.js +8 -7
  86. package/lib/transform/db/views.js +73 -33
  87. package/lib/transform/draft/db.js +11 -9
  88. package/lib/transform/draft/odata.js +1 -1
  89. package/lib/transform/{forOdataNew.js → forOdata.js} +10 -7
  90. package/lib/transform/forRelationalDB.js +148 -136
  91. package/lib/transform/localized.js +92 -54
  92. package/lib/transform/odata/toFinalBaseType.js +3 -3
  93. package/lib/transform/{transformUtilsNew.js → transformUtils.js} +13 -111
  94. package/lib/transform/translateAssocsToJoins.js +14 -28
  95. package/lib/utils/file.js +7 -7
  96. package/lib/utils/moduleResolve.js +210 -121
  97. package/lib/utils/objectUtils.js +1 -1
  98. package/package.json +5 -5
  99. package/share/messages/check-proper-type-of.md +1 -1
  100. package/share/messages/{check-proper-type.md → def-missing-type.md} +3 -5
  101. package/share/messages/message-explanations.json +1 -1
@@ -6,12 +6,15 @@
6
6
  // Please do not add functions “for completeness”, this is not an API file for
7
7
  // others but only by the core compiler.
8
8
 
9
- // TODO: probably split this file into utils/….js
9
+ // TODO: split this file into utils/….js, add some functions from lib/base/model.js
10
10
 
11
11
  'use strict';
12
12
 
13
13
  const { dictAdd, pushToDict, dictFirst } = require('../base/dictionaries');
14
14
  const { kindProperties } = require('./base');
15
+ const { XsnName, XsnArtifact, CsnLocation } = require('./classes');
16
+
17
+ const $inferred = Symbol.for( 'cds.$inferred' );
15
18
 
16
19
  // for links, i.e., properties starting with an underscore '_':
17
20
 
@@ -106,17 +109,23 @@ function linkToOrigin( origin, name, parent, prop, location, silentDep ) {
106
109
  return elem;
107
110
  }
108
111
 
109
- function proxyCopyMembers( art, dictProp, originDict, location, kind ) {
112
+ function proxyCopyMembers( art, dictProp, originDict, location, kind, tmpDeprecated ) {
110
113
  art[dictProp] = Object.create( null );
114
+ // TODO: set $inferred ? for dict?
111
115
  for (const name in originDict) {
112
116
  const origin = originDict[name];
113
- const member = linkToOrigin( origin, name, art, dictProp,
114
- location || origin.location, true );
115
- member.$inferred = 'expanded';
116
- if (kind)
117
- member.kind = kind;
118
- if (kind && origin.masked) // TODO: remove!
119
- member.masked = Object.assign( { $inferred: 'nav' }, origin.masked );
117
+ if (origin !== undefined) {
118
+ const member = linkToOrigin( origin, name, art, dictProp,
119
+ location || origin.location, true );
120
+ member.$inferred = 'expanded';
121
+ // TODO throughout the compiler: do not set art.‹prop›.$inferred if art.$inferred
122
+ if (kind)
123
+ member.kind = kind;
124
+ else if (origin.key && !tmpDeprecated) // TODO(v5/v6): remove tmpDeprecated
125
+ member.key = Object.assign( { $inferred: 'expanded' }, origin.key );
126
+ if (kind && origin.masked) // TODO: remove!
127
+ member.masked = Object.assign( { $inferred: 'nav' }, origin.masked );
128
+ }
120
129
  }
121
130
  }
122
131
 
@@ -132,8 +141,8 @@ function setMemberParent( elem, name, parent, prop ) {
132
141
  if (prop) { // extension or structure include
133
142
  // TODO: consider nested ARRAY OF and RETURNS, COMPOSITION OF type
134
143
  const p = parent.items || parent.targetAspect || parent;
135
- if (!(prop in p))
136
- p[prop] = Object.create(null);
144
+ if (p[prop] === undefined)
145
+ p[prop] = Object.create( null );
137
146
  dictAdd( p[prop], name, elem );
138
147
  }
139
148
  if (parent._outer && parent._outer.items) // TODO: remove for items, too
@@ -155,7 +164,7 @@ function setMemberParent( elem, name, parent, prop ) {
155
164
 
156
165
  else
157
166
  delete elem.name[kind];
158
- });
167
+ } );
159
168
  // try { throw new CompilerAssertion('Foo') } catch (e) { elem.name.stack = e; };
160
169
  }
161
170
 
@@ -166,10 +175,12 @@ function setMemberParent( elem, name, parent, prop ) {
166
175
  * @param {XSN.Artifact} art
167
176
  * @param {XSN.Location} location
168
177
  */
169
- function dependsOn( user, art, location ) {
178
+ function dependsOn( user, art, location, semanticLoc = undefined ) {
179
+ while (user._outer && !user.kind)
180
+ user = user._outer;
170
181
  if (!user._deps)
171
182
  setLink( user, '_deps', [] );
172
- user._deps.push( { art, location } );
183
+ user._deps.push( { art, location, semanticLoc } );
173
184
  }
174
185
 
175
186
  /**
@@ -180,6 +191,8 @@ function dependsOn( user, art, location ) {
180
191
  * @param {XSN.Artifact} art
181
192
  */
182
193
  function dependsOnSilent( user, art ) {
194
+ while (user._outer && !user.kind)
195
+ user = user._outer;
183
196
  if (!user._deps)
184
197
  setLink( user, '_deps', [] );
185
198
  user._deps.push( { art } );
@@ -197,7 +210,7 @@ function storeExtension( elem, name, prop, parent, block ) {
197
210
  // return;
198
211
  // }
199
212
  if (!parent[kind][prop])
200
- parent[kind][prop] = Object.create(null);
213
+ parent[kind][prop] = Object.create( null );
201
214
  pushToDict( parent[kind][prop], name, elem );
202
215
  }
203
216
 
@@ -223,7 +236,7 @@ function withAssociation( ref, test = testFunctionPlaceholder, alsoTestLast = fa
223
236
  * @param {XSN.Path} path
224
237
  */
225
238
  function pathName( path ) {
226
- return (path && !path.broken) ? path.map( id => id.id ).join('.') : '';
239
+ return (path && !path.broken) ? path.map( id => id.id ).join( '.' ) : '';
227
240
  }
228
241
 
229
242
  /**
@@ -235,7 +248,7 @@ function pathName( path ) {
235
248
  * @returns {XSN.Path}
236
249
  */
237
250
  function splitIntoPath( location, name ) {
238
- return name.split('.').map( id => ({ id, location }) );
251
+ return name.split( '.' ).map( id => ({ id, location }) );
239
252
  }
240
253
 
241
254
  /**
@@ -249,11 +262,13 @@ function augmentPath( location, ...args ) {
249
262
  function copyExpr( expr, location, skipUnderscored, rewritePath ) {
250
263
  if (!expr || typeof expr !== 'object')
251
264
  return expr;
252
- else if (Array.isArray(expr))
265
+ else if (Array.isArray( expr ))
253
266
  return expr.map( e => copyExpr( e, location, skipUnderscored, rewritePath ) );
254
267
 
255
268
  const proto = Object.getPrototypeOf( expr );
256
- if (proto && proto !== Object.prototype) // do not copy object from special classes
269
+ if (proto && proto !== Object.prototype && proto !== XsnName.prototype &&
270
+ // do not copy object from special classes outside the compiler domain&&
271
+ proto !== XsnArtifact.prototype && proto !== CsnLocation.prototype)
257
272
  return expr;
258
273
  const r = Object.create( proto );
259
274
  for (const prop of Object.getOwnPropertyNames( expr )) {
@@ -284,7 +299,7 @@ function testExpr( expr, pathTest, queryTest, user ) {
284
299
  if (!expr || typeof expr === 'string') { // parse error or keywords in {xpr:...}
285
300
  return false;
286
301
  }
287
- else if (Array.isArray(expr)) {
302
+ else if (Array.isArray( expr )) {
288
303
  return expr.some( e => testExpr( e, pathTest, queryTest, user ) );
289
304
  }
290
305
  else if (expr.path) {
@@ -295,11 +310,11 @@ function testExpr( expr, pathTest, queryTest, user ) {
295
310
  }
296
311
  else if (expr.op && expr.args) {
297
312
  // unnamed args => array
298
- if (Array.isArray(expr.args))
313
+ if (Array.isArray( expr.args ))
299
314
  return expr.args.some( e => testExpr( e, pathTest, queryTest, user ) );
300
315
  // named args => dictionary
301
- for (const namedArg of Object.keys(expr.args)) {
302
- if (testExpr(expr.args[namedArg], pathTest, queryTest, user))
316
+ for (const namedArg of Object.keys( expr.args )) {
317
+ if (testExpr( expr.args[namedArg], pathTest, queryTest, user ))
303
318
  return true;
304
319
  }
305
320
  }
@@ -314,6 +329,129 @@ function targetMaxNotOne( assoc, item ) {
314
329
  return cardinality && cardinality.targetMax && cardinality.targetMax.val !== 1;
315
330
  }
316
331
 
332
+ /**
333
+ * Call function `callback(art)` for each user-defined main artifact and member
334
+ * `art` of the model reachable from the dictionary `model[prop]`. User-defined
335
+ * artifacts are those with no or a falsy `art.$inferred` value, i.e. this
336
+ * function is useful for checks.
337
+ *
338
+ * The callback function is not called on the following artifacts:
339
+ * - `enum` symbol definitions (use forEachUserDict() yourself if needed)
340
+ * - the anonymous aspect in the `target`/`targetAspect` property (but the
341
+ * callback function is called on its elements).
342
+ * - table aliases
343
+ *
344
+ * The callback function is also called on duplicates. For example, if there are
345
+ * two entities named `E`, the callback function is called on both.
346
+ * It is also called on columns with `inline`.
347
+ *
348
+ * See also function forEachDefinition(), currently in lib/base/model.js.
349
+ */
350
+ function forEachUserArtifact( model, prop, callback ) { // not enums
351
+ forEachUserDict( model, prop, function main( art ) {
352
+ callback( art );
353
+ forEachUserDict( art, 'params', function param( par ) {
354
+ callback( par );
355
+ forEachUserElementAndFKey( par, callback );
356
+ } );
357
+ if (art.$queries) {
358
+ for (const query of art.$queries) {
359
+ callback( query );
360
+ forEachUserDict( query, 'mixin', callback );
361
+ forEachUserElementAndFKey( query, callback );
362
+ if (query.$inlines) // e.g. not with `entity V as projection on V;`
363
+ query.$inlines.forEach( callback );
364
+ }
365
+ }
366
+ else if (art.returns) {
367
+ callback( art.returns );
368
+ forEachUserElementAndFKey( art.returns, callback );
369
+ }
370
+ else {
371
+ forEachUserElementAndFKey( art, callback );
372
+ }
373
+ forEachUserArtifact( art, 'actions', callback );
374
+ } );
375
+ }
376
+
377
+ /**
378
+ * Call function `callback(art)` for each user-defined element and foreign key
379
+ * reachable from artifact `art`. Do not (again) call the callback function on
380
+ * `art` itself, even if it is an element.
381
+ *
382
+ * Consider that we have (nested) `array of`/`many` types, but do not call the
383
+ * callback function on the array item itself (only on elements inside).
384
+ */
385
+ function forEachUserElementAndFKey( art, callback ) {
386
+ while (art.items)
387
+ art = art.items;
388
+ if (art.target) {
389
+ forEachUserDict( art, 'foreignKeys', callback );
390
+ return;
391
+ }
392
+ if (art.targetAspect)
393
+ art = art.targetAspect;
394
+ forEachUserDict( art, 'elements', function element( elem ) {
395
+ callback( elem );
396
+ forEachUserElementAndFKey( elem, callback );
397
+ } );
398
+ }
399
+
400
+ function forEachUserDict( art, prop, callback ) {
401
+ const dict = art[prop];
402
+ if (!dict || dict[$inferred])
403
+ return;
404
+ for (const name in dict) {
405
+ const obj = dict[name];
406
+ if (obj.$inferred)
407
+ continue;
408
+ callback( obj, name, prop );
409
+ if (Array.isArray( obj.$duplicates )) // redefinitions
410
+ obj.$duplicates.forEach( o => callback( o, name, prop ) );
411
+ }
412
+ }
413
+
414
+ /**
415
+ * Call `callback( expr, exprCtx, query )` on all direct expressions `expr` of
416
+ * `query`, where `exprCtx` is the expression context used as key for the
417
+ * `referenceSemantics` in shared.js.
418
+ *
419
+ * Indirect expressions are not called, these are:
420
+ * - the `from` reference (expression of the table alias)
421
+ * - the ON-condition of mixins (expression of the mixin)
422
+ * - the expressions in columns (expression of the column/element)
423
+ */
424
+ function forEachQueryExpr( query, callback ) { // see resolveQuery()
425
+ forEachJoinOn( query, query.from, callback );
426
+ // TODO: run over $inlines ?
427
+ if (query.where)
428
+ callback( query.where, 'where', query );
429
+ if (query.groupBy)
430
+ forEachExprArray( query, query.groupBy, 'groupBy', 'groupBy', callback );
431
+ if (query.having)
432
+ callback( query.having, 'having', query );
433
+ if (query.$orderBy)
434
+ forEachExprArray( query, query.$orderBy, 'orderBy-set-ref', 'orderBy-set-expr', callback );
435
+ if (query.orderBy)
436
+ forEachExprArray( query, query.orderBy, 'orderBy-ref', 'orderBy-expr', callback );
437
+ }
438
+
439
+ function forEachJoinOn( query, from, callback ) {
440
+ if (!from?.join)
441
+ return; // TODO: run over from.path here?
442
+ for (const tab of from.args)
443
+ forEachJoinOn( query, tab, callback );
444
+ if (from.on)
445
+ callback( from.on, 'join-on', query );
446
+ }
447
+
448
+ function forEachExprArray( query, array, refContext, exprContext, callback ) {
449
+ for (const expr of array ) {
450
+ if (expr)
451
+ callback( expr, (expr.path ? refContext : exprContext), query );
452
+ }
453
+ }
454
+
317
455
  // Query tree post-order traversal - called for everything which contributes to the query
318
456
  // i.e. is necessary to calculate the elements of the query
319
457
  // except "real ones": operands of UNION etc, JOIN with ON, and sub queries in FROM
@@ -442,28 +580,6 @@ function isDirectComposition( art ) {
442
580
  return type && type[0] && type[0].id === 'cds.Composition';
443
581
  }
444
582
 
445
- function traverseExpr( expr, exprCtx, user, callback ) {
446
- if (!expr || typeof expr === 'string') // parse error or keywords in {xpr:...}
447
- return;
448
-
449
- if (expr.path) {
450
- callback( expr, exprCtx, user );
451
- // TODO: move arguments and filter traversal to here
452
- return;
453
- }
454
- else if (expr.type || expr.query) {
455
- callback( expr, exprCtx, user );
456
- }
457
-
458
- if (expr.args) {
459
- const args = Array.isArray(expr.args) ? expr.args : Object.values( expr.args );
460
- // TODO: re-think $expected
461
- args.forEach( e => traverseExpr( e, exprCtx, user, callback ) );
462
- }
463
- if (expr.suffix) // fn( … ) OVER …
464
- expr.suffix.forEach( e => traverseExpr( e, exprCtx, user, callback ) );
465
- }
466
-
467
583
  function userQuery( user ) {
468
584
  // TODO: we need _query links set by the definer
469
585
  while (user._main) {
@@ -474,6 +590,63 @@ function userQuery( user ) {
474
590
  return null;
475
591
  }
476
592
 
593
+ function pathStartsWithSelf( ref ) {
594
+ const head = ref && !ref.scope && ref.path?.[0];
595
+ if (head?._navigation?.kind === '$self')
596
+ return true;
597
+ if (head?._artifact?.kind === 'builtin') // CDS variable
598
+ return false;
599
+ return undefined;
600
+ }
601
+
602
+ function columnRefStartsWithSelf( col ) {
603
+ for (; col; col = col._pathHead) {
604
+ const ref = col.value;
605
+ const head = ref && !ref.scope && ref.path?.[0];
606
+ if (head?._navigation?.kind === '$self')
607
+ return true;
608
+ if (head?._artifact?.kind === 'builtin') // CDS variable
609
+ return false;
610
+ }
611
+ return false;
612
+ }
613
+
614
+ // Remark: this function is based on an early check that no target element is
615
+ // covered more than once by a foreign key: then…
616
+ // we only need to check that all foreign key references are primary keys and
617
+ // that the number of foreign and primary keys are the same.
618
+ function isAssocToPrimaryKeys( assoc ) {
619
+ let fkeys = 0;
620
+ const { foreignKeys } = assoc;
621
+ if (!foreignKeys)
622
+ return undefined;
623
+ for (const name in foreignKeys) {
624
+ const fk = foreignKeys[name];
625
+ const elem = fk.targetElement._artifact;
626
+ if (!elem || fk.$duplicates)
627
+ return undefined;
628
+ if (!elem.key?.val)
629
+ return false;
630
+ ++fkeys;
631
+ }
632
+
633
+ const elements = assoc.target._artifact?.elements;
634
+ if (!elements)
635
+ return undefined;
636
+ for (const name in elements) {
637
+ if (elements[name].key?.val)
638
+ --fkeys;
639
+ }
640
+ return fkeys === 0;
641
+ }
642
+
643
+ // only if _effectiveType has been computed:
644
+ function getUnderlyingBuiltinType( art ) {
645
+ while (art?._effectiveType && !art.builtin)
646
+ art = art._origin || art.type?._artifact;
647
+ return art;
648
+ }
649
+
477
650
  function definedViaCdl( art ) {
478
651
  // return !!art._block?.artifacts;
479
652
  // TODO: the above code would work when _block links are correctly set on
@@ -483,6 +656,21 @@ function definedViaCdl( art ) {
483
656
  return $frontend !== 'json' && $frontend !== '$internal';
484
657
  }
485
658
 
659
+ // For error messages: ----------------------------------------------------------
660
+
661
+ // (To be) used for the location in error messages
662
+ function artifactRefLocation( ref ) {
663
+ return (ref._artifact?._main)
664
+ ? ref.path[ref.path.length - 1].location
665
+ : ref.location;
666
+ }
667
+
668
+ function compositionTextVariant( art, composition, association = 'std' ) {
669
+ return (getUnderlyingBuiltinType( art )?.name.absolute === 'cds.Composition')
670
+ ? composition
671
+ : association;
672
+ }
673
+
486
674
  module.exports = {
487
675
  pushLink,
488
676
  annotationVal,
@@ -505,13 +693,20 @@ module.exports = {
505
693
  copyExpr,
506
694
  testExpr,
507
695
  targetMaxNotOne,
696
+ forEachUserArtifact,
697
+ forEachQueryExpr,
508
698
  traverseQueryPost,
509
699
  traverseQueryExtra,
510
700
  viewFromPrimary,
511
701
  setExpandStatus,
512
702
  setExpandStatusAnnotate,
513
703
  isDirectComposition,
514
- traverseExpr,
515
704
  userQuery,
705
+ pathStartsWithSelf,
706
+ columnRefStartsWithSelf,
707
+ isAssocToPrimaryKeys,
708
+ getUnderlyingBuiltinType,
516
709
  definedViaCdl,
710
+ artifactRefLocation,
711
+ compositionTextVariant,
517
712
  };
@@ -1,5 +1,44 @@
1
1
  {
2
+ "root": true,
3
+ //"plugins": ["sonarjs", "jsdoc"],
4
+ //"extends": ["plugin:jsdoc/recommended", "../../../.eslintrc-ydkjsi.json", "plugin:sonarjs/recommended"],
5
+ "plugins": ["sonarjs"],
6
+ "extends": ["../../.eslintrc-ydkjsi.json", "plugin:sonarjs/recommended"],
2
7
  "rules": {
3
- "no-shadow": "off"
8
+ "prefer-const": "error",
9
+ "quotes": ["error", "single", "avoid-escape"],
10
+ "prefer-template": "error",
11
+ "no-trailing-spaces": "error",
12
+ "template-curly-spacing":["error", "never"],
13
+ "complexity": ["warn", 50],
14
+ "max-len": "off",
15
+ // there seem to be false positives
16
+ "jsdoc/require-returns-check": "off",
17
+ // Don't enforce stupid descriptions
18
+ "jsdoc/require-param-description": "off",
19
+ "jsdoc/require-returns-description": "off",
20
+ // Sometimes if-else's are more specific
21
+ "sonarjs/prefer-single-boolean-return": "off",
22
+ // Very whiny and nitpicky
23
+ "sonarjs/cognitive-complexity": "off",
24
+ "sonarjs/no-duplicate-string": "off",
25
+ // Does not recognize TS types
26
+ "jsdoc/no-undefined-types": "off",
27
+ "jsdoc/tag-lines": "off",
28
+ "no-nested-ternary": "off",
29
+ "sonarjs/no-nested-template-literals": "off"
30
+ },
31
+ "parserOptions": {
32
+ "ecmaVersion": 2022,
33
+ "sourceType": "script"
34
+ },
35
+ "env": {
36
+ "es2022": true,
37
+ "node": true
38
+ },
39
+ "settings": {
40
+ "jsdoc": {
41
+ "mode": "typescript"
42
+ }
4
43
  }
5
44
  }