@taiga-ui/eslint-plugin-experience-next 0.510.0 → 0.512.0

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/README.md CHANGED
@@ -103,6 +103,7 @@ from third-party plugins. The exact severities and file globs live in
103
103
  | [no-redundant-type-annotation](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-redundant-type-annotation.md) | Disallow redundant type annotations when the type is already inferred from the initializer | ✅ | 🔧 | |
104
104
  | [no-repeated-signal-in-conditional](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-repeated-signal-in-conditional.md) | Disallow reading the same nullable Angular signal more than once in a conditional expression | ✅ | 🔧 | |
105
105
  | [no-side-effects-in-computed](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-side-effects-in-computed.md) | Disallow side effects and effectful helper calls inside Angular `computed()` callbacks | ✅ | | |
106
+ | [no-signal-outside-class](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-signal-outside-class.md) | Disallow class properties that reference a module-scope Angular signal | ✅ | | |
106
107
  | [no-signal-reads-after-await-in-reactive-context](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-signal-reads-after-await-in-reactive-context.md) | Disallow bare signal reads after `await` inside reactive callbacks | ✅ | | |
107
108
  | [no-string-literal-concat](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-string-literal-concat.md) | Disallow string literal concatenation; merge adjacent literals into one | ✅ | 🔧 | |
108
109
  | [no-untracked-outside-reactive-context](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-untracked-outside-reactive-context.md) | Disallow `untracked()` outside reactive callbacks, except explicit post-`await` snapshots | ✅ | 🔧 | |
package/index.d.ts CHANGED
@@ -125,6 +125,9 @@ declare const plugin: {
125
125
  'no-side-effects-in-computed': import("@typescript-eslint/utils/ts-eslint").RuleModule<"sideEffectInComputed", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
126
126
  name: string;
127
127
  };
128
+ 'no-signal-outside-class': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noSignalOutsideClass", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
129
+ name: string;
130
+ };
128
131
  'no-signal-reads-after-await-in-reactive-context': import("@typescript-eslint/utils/ts-eslint").RuleModule<"readAfterAwait", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
129
132
  name: string;
130
133
  };
package/index.esm.js CHANGED
@@ -373,6 +373,14 @@ const TUI_RECOMMENDED_NAMING_CONVENTION = [
373
373
  format: ['camelCase'],
374
374
  selector: ['classMethod', 'classProperty'],
375
375
  },
376
+ {
377
+ filter: {
378
+ match: true,
379
+ regex: String.raw `^(Infinity|NaN|Number|Math)$`,
380
+ },
381
+ format: null,
382
+ selector: 'classProperty',
383
+ },
376
384
  {
377
385
  format: ['UPPER_CASE', 'camelCase', 'PascalCase'],
378
386
  selector: ['variable'],
@@ -1210,6 +1218,7 @@ var recommended = defineConfig([
1210
1218
  '@taiga-ui/experience-next/no-redundant-type-annotation': 'error',
1211
1219
  '@taiga-ui/experience-next/no-repeated-signal-in-conditional': 'error',
1212
1220
  '@taiga-ui/experience-next/no-side-effects-in-computed': 'error',
1221
+ '@taiga-ui/experience-next/no-signal-outside-class': 'error',
1213
1222
  '@taiga-ui/experience-next/no-signal-reads-after-await-in-reactive-context': 'error',
1214
1223
  '@taiga-ui/experience-next/no-untracked-outside-reactive-context': 'error',
1215
1224
  '@taiga-ui/experience-next/no-useless-untracked': 'error',
@@ -46224,7 +46233,7 @@ function buildMultilineStartTag(node, sourceText) {
46224
46233
  closing,
46225
46234
  ].join('\n');
46226
46235
  }
46227
- const rule$S = createRule({
46236
+ const rule$T = createRule({
46228
46237
  name: 'attrs-newline',
46229
46238
  rule: {
46230
46239
  create(context) {
@@ -46404,7 +46413,7 @@ function sameOrder(a, b) {
46404
46413
  return a.length === b.length && a.every((value, index) => value === b[index]);
46405
46414
  }
46406
46415
 
46407
- const rule$R = createRule({
46416
+ const rule$S = createRule({
46408
46417
  create(context, [order]) {
46409
46418
  const decorators = new Set(Object.keys(order));
46410
46419
  return {
@@ -46540,7 +46549,7 @@ function getNodeLabel(node) {
46540
46549
  }
46541
46550
  return node instanceof dist$4.TmplAstBoundText ? 'binding' : 'text';
46542
46551
  }
46543
- const rule$Q = createRule({
46552
+ const rule$R = createRule({
46544
46553
  name: 'element-newline',
46545
46554
  rule: {
46546
46555
  create(context) {
@@ -46679,7 +46688,7 @@ const PRESETS = {
46679
46688
  $VUE: ['$CLASS', '$ID', '$VUE_ATTRIBUTE'],
46680
46689
  $VUE_ATTRIBUTE: /^v-/,
46681
46690
  };
46682
- const rule$P = createRule({
46691
+ const rule$Q = createRule({
46683
46692
  create(context, [options]) {
46684
46693
  const sourceCode = context.sourceCode;
46685
46694
  const settings = {
@@ -47010,7 +47019,7 @@ const config$4 = {
47010
47019
  type: 'suggestion',
47011
47020
  },
47012
47021
  };
47013
- const rule$O = createRule({
47022
+ const rule$P = createRule({
47014
47023
  name: 'html-logical-properties',
47015
47024
  rule: config$4,
47016
47025
  });
@@ -248252,7 +248261,7 @@ function isImportUsedOnlyAsAngularDiFirstArg(node, sourceCode) {
248252
248261
  }
248253
248262
  return hasSafeRuntimeUsage;
248254
248263
  }
248255
- const rule$N = createRule({
248264
+ const rule$O = createRule({
248256
248265
  create(context) {
248257
248266
  const { checker, esTreeNodeToTSNodeMap, sourceCode, tsProgram } = getTypeAwareRuleContext(context);
248258
248267
  const checkCycles = context.options[0]?.checkCycles ?? true;
@@ -248977,7 +248986,7 @@ function getNgDevModeDeclarationFix(program, fixer) {
248977
248986
  ? fixer.insertTextBefore(firstStatement, 'declare const ngDevMode: boolean;\n\n')
248978
248987
  : fixer.insertTextBeforeRange([0, 0], 'declare const ngDevMode: boolean;\n');
248979
248988
  }
248980
- const rule$M = createRule({
248989
+ const rule$N = createRule({
248981
248990
  create(context) {
248982
248991
  const { sourceCode } = context;
248983
248992
  const program = sourceCode.ast;
@@ -249026,7 +249035,7 @@ const rule$M = createRule({
249026
249035
  name: 'injection-token-description',
249027
249036
  });
249028
249037
 
249029
- const rule$L = createRule({
249038
+ const rule$M = createRule({
249030
249039
  create(context) {
249031
249040
  const { sourceCode } = context;
249032
249041
  const namespaceImports = new Map();
@@ -249121,7 +249130,7 @@ const DEFAULT_OPTIONS = {
249121
249130
  importDeclaration: '^@taiga-ui*',
249122
249131
  projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
249123
249132
  };
249124
- const rule$K = createRule({
249133
+ const rule$L = createRule({
249125
249134
  create(context) {
249126
249135
  const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
249127
249136
  const hasNonCodeExtension = (source) => {
@@ -249213,7 +249222,7 @@ const nearestFileUpCache = new Map();
249213
249222
  const markerCache = new Map();
249214
249223
  const indexFileCache = new Map();
249215
249224
  const indexExportsCache = new Map();
249216
- const rule$J = createRule({
249225
+ const rule$K = createRule({
249217
249226
  create(context) {
249218
249227
  const parserServices = dist$3.ESLintUtils.getParserServices(context);
249219
249228
  const program = parserServices.program;
@@ -249407,13 +249416,13 @@ const noDuplicateAttributesRule = angular.templatePlugin.rules?.['no-duplicate-a
249407
249416
  if (!noDuplicateAttributesRule) {
249408
249417
  throw new Error('angular-eslint template rule "no-duplicate-attributes" is not available');
249409
249418
  }
249410
- const rule$I = createRule({
249419
+ const rule$J = createRule({
249411
249420
  name: 'no-duplicate-attrs',
249412
249421
  rule: noDuplicateAttributesRule,
249413
249422
  });
249414
249423
 
249415
249424
  const MESSAGE_ID$c = 'duplicateId';
249416
- const rule$H = createRule({
249425
+ const rule$I = createRule({
249417
249426
  name: 'no-duplicate-id',
249418
249427
  rule: {
249419
249428
  create(context) {
@@ -249474,7 +249483,7 @@ function getTrackingKey(node) {
249474
249483
  ? 'link[rel=canonical]'
249475
249484
  : null;
249476
249485
  }
249477
- const rule$G = createRule({
249486
+ const rule$H = createRule({
249478
249487
  name: 'no-duplicate-in-head',
249479
249488
  rule: {
249480
249489
  create(context) {
@@ -249530,7 +249539,7 @@ const rule$G = createRule({
249530
249539
  });
249531
249540
 
249532
249541
  const COMPONENT_DECORATORS = new Set(['Component']);
249533
- const rule$F = createRule({
249542
+ const rule$G = createRule({
249534
249543
  create(context) {
249535
249544
  const { sourceCode } = context;
249536
249545
  return {
@@ -249823,7 +249832,7 @@ function walkAst(root, visitor) {
249823
249832
  }
249824
249833
  }
249825
249834
 
249826
- const ANGULAR_CORE$1 = '@angular/core';
249835
+ const ANGULAR_CORE$2 = '@angular/core';
249827
249836
  /**
249828
249837
  * Returns the local name bound to a named import from a given source.
249829
249838
  * Handles aliased imports: `import { untracked as ngUntracked } from '@angular/core'`
@@ -249851,7 +249860,7 @@ function getLocalNameForImport(program, source, exportedName) {
249851
249860
  }
249852
249861
  function findAngularCoreImports(program) {
249853
249862
  return program.body.filter((node) => node.type === dist$3.AST_NODE_TYPES.ImportDeclaration &&
249854
- node.source.value === ANGULAR_CORE$1);
249863
+ node.source.value === ANGULAR_CORE$2);
249855
249864
  }
249856
249865
  function findRuntimeAngularCoreImport(program) {
249857
249866
  return (findAngularCoreImports(program).find((node) => node.importKind !== 'type') ?? null);
@@ -249873,7 +249882,7 @@ function findAngularCoreImportSpecifier(program, exportedName) {
249873
249882
  return null;
249874
249883
  }
249875
249884
 
249876
- const ANGULAR_CORE = '@angular/core';
249885
+ const ANGULAR_CORE$1 = '@angular/core';
249877
249886
  const SIGNAL_WRITE_METHODS = new Set(['mutate', 'set', 'update']);
249878
249887
  const AFTER_RENDER_EFFECT_PHASES = new Map([
249879
249888
  ['earlyRead', 'afterRenderEffect().earlyRead'],
@@ -249899,7 +249908,7 @@ function getPropertyName(property) {
249899
249908
  return typeof property.key.value === 'string' ? property.key.value : null;
249900
249909
  }
249901
249910
  function isAngularCoreCall(node, program, exportedName) {
249902
- const localName = getLocalNameForImport(program, ANGULAR_CORE, exportedName);
249911
+ const localName = getLocalNameForImport(program, ANGULAR_CORE$1, exportedName);
249903
249912
  return localName
249904
249913
  ? node.callee.type === dist$3.AST_NODE_TYPES.Identifier &&
249905
249914
  node.callee.name === localName &&
@@ -250178,7 +250187,7 @@ const ANGULAR_SIGNALS_UNTRACKED_GUIDE_URL = 'https://angular.dev/guide/signals#r
250178
250187
  const ANGULAR_SIGNALS_ASYNC_GUIDE_URL = 'https://angular.dev/guide/signals#reactive-context-and-async-operations';
250179
250188
  const createUntrackedRule = createRule;
250180
250189
 
250181
- const rule$E = createUntrackedRule({
250190
+ const rule$F = createUntrackedRule({
250182
250191
  create(context) {
250183
250192
  const { checker, esTreeNodeToTSNodeMap, program } = getTypeAwareRuleContext(context);
250184
250193
  const signalNodeMap = esTreeNodeToTSNodeMap;
@@ -250251,7 +250260,7 @@ const config$3 = {
250251
250260
  type: 'problem',
250252
250261
  },
250253
250262
  };
250254
- const rule$D = createRule({
250263
+ const rule$E = createRule({
250255
250264
  name: 'no-href-with-router-link',
250256
250265
  rule: config$3,
250257
250266
  });
@@ -250312,7 +250321,7 @@ function getScopeRoot(node) {
250312
250321
  return (findAncestor(node, (ancestor) => ancestor.type === dist$3.AST_NODE_TYPES.Program || isFunctionLike(ancestor)) ?? node);
250313
250322
  }
250314
250323
 
250315
- const rule$C = createRule({
250324
+ const rule$D = createRule({
250316
250325
  create(context) {
250317
250326
  const checkImplicitPublic = (node) => {
250318
250327
  const classRef = getEnclosingClass(node);
@@ -250374,7 +250383,7 @@ const rule$C = createRule({
250374
250383
  name: 'no-implicit-public',
250375
250384
  });
250376
250385
 
250377
- const rule$B = createRule({
250386
+ const rule$C = createRule({
250378
250387
  create(context) {
250379
250388
  const { sourceCode } = context;
250380
250389
  return {
@@ -250430,7 +250439,7 @@ function isInfiniteLoopLiteral(node) {
250430
250439
  function isInfiniteLoopTest(test) {
250431
250440
  return test == null || isInfiniteLoopLiteral(test);
250432
250441
  }
250433
- const rule$A = createRule({
250442
+ const rule$B = createRule({
250434
250443
  create(context) {
250435
250444
  return {
250436
250445
  DoWhileStatement(node) {
@@ -250475,7 +250484,7 @@ const rule$A = createRule({
250475
250484
  });
250476
250485
 
250477
250486
  const LEGACY_PEER_DEPS_PATTERN = /^legacy-peer-deps\s*=\s*true$/i;
250478
- const rule$z = createRule({
250487
+ const rule$A = createRule({
250479
250488
  create(context) {
250480
250489
  return {
250481
250490
  Program(node) {
@@ -250935,7 +250944,7 @@ const OBSOLETE_HTML_ATTRS = {
250935
250944
  };
250936
250945
 
250937
250946
  const MESSAGE_ID$9 = 'obsolete';
250938
- const rule$y = createRule({
250947
+ const rule$z = createRule({
250939
250948
  name: 'no-obsolete-attrs',
250940
250949
  rule: {
250941
250950
  create(context) {
@@ -251013,7 +251022,7 @@ const OBSOLETE_HTML_TAGS = new Set([
251013
251022
  ]);
251014
251023
 
251015
251024
  const MESSAGE_ID$8 = 'unexpected';
251016
- const rule$x = createRule({
251025
+ const rule$y = createRule({
251017
251026
  name: 'no-obsolete-tags',
251018
251027
  rule: {
251019
251028
  create(context) {
@@ -251040,7 +251049,7 @@ const rule$x = createRule({
251040
251049
  },
251041
251050
  });
251042
251051
 
251043
- const rule$w = createRule({
251052
+ const rule$x = createRule({
251044
251053
  create(context) {
251045
251054
  const { checker, esTreeNodeToTSNodeMap, sourceCode } = getTypeAwareRuleContext(context);
251046
251055
  return {
@@ -251184,7 +251193,7 @@ const config$2 = {
251184
251193
  type: 'problem',
251185
251194
  },
251186
251195
  };
251187
- const rule$v = createRule({
251196
+ const rule$w = createRule({
251188
251197
  name: 'no-project-as-in-ng-template',
251189
251198
  rule: config$2,
251190
251199
  });
@@ -251221,7 +251230,7 @@ function collectArrayExpressions(node) {
251221
251230
  }
251222
251231
  return result;
251223
251232
  }
251224
- const rule$u = createRule({
251233
+ const rule$v = createRule({
251225
251234
  create(context) {
251226
251235
  const { checker: typeChecker, esTreeNodeToTSNodeMap } = getTypeAwareRuleContext(context);
251227
251236
  const ignoreTupleContextualTyping = context.options[0]?.ignoreTupleContextualTyping ?? true;
@@ -251419,7 +251428,7 @@ function isOptionalMemberReceiver(call) {
251419
251428
  parent.object === current &&
251420
251429
  parent.optional);
251421
251430
  }
251422
- const rule$t = createRule({
251431
+ const rule$u = createRule({
251423
251432
  create(context) {
251424
251433
  const { checker, esTreeNodeToTSNodeMap, sourceCode } = getTypeAwareRuleContext(context);
251425
251434
  const signalNodeMap = esTreeNodeToTSNodeMap;
@@ -251522,15 +251531,22 @@ const rule$t = createRule({
251522
251531
  });
251523
251532
 
251524
251533
  /**
251525
- * Strips TypeScript-only wrapper nodes that have no runtime meaning:
251526
- * `as` casts, non-null assertions (`!`), type assertions (`<T>expr`), and
251527
- * optional-chain wrappers. Iterates until no more wrappers are found.
251534
+ * Strips expression wrapper nodes that do not affect the underlying expression:
251535
+ * parentheses, `as` casts, `satisfies`, non-null assertions (`!`), type
251536
+ * assertions (`<T>expr`), and optional-chain wrappers. Iterates until no more
251537
+ * wrappers are found.
251528
251538
  */
251529
251539
  function unwrapExpression(expression) {
251530
251540
  let current = expression;
251531
251541
  let didUnwrap = true;
251532
251542
  while (didUnwrap) {
251533
251543
  didUnwrap = false;
251544
+ const parenthesized = getParenthesizedExpression(current);
251545
+ if (parenthesized) {
251546
+ current = parenthesized;
251547
+ didUnwrap = true;
251548
+ continue;
251549
+ }
251534
251550
  switch (current.type) {
251535
251551
  case dist$3.AST_NODE_TYPES.ChainExpression:
251536
251552
  current = current.expression;
@@ -251544,6 +251560,10 @@ function unwrapExpression(expression) {
251544
251560
  current = current.expression;
251545
251561
  didUnwrap = true;
251546
251562
  break;
251563
+ case dist$3.AST_NODE_TYPES.TSSatisfiesExpression:
251564
+ current = current.expression;
251565
+ didUnwrap = true;
251566
+ break;
251547
251567
  case dist$3.AST_NODE_TYPES.TSTypeAssertion:
251548
251568
  current = current.expression;
251549
251569
  didUnwrap = true;
@@ -251552,6 +251572,19 @@ function unwrapExpression(expression) {
251552
251572
  }
251553
251573
  return current;
251554
251574
  }
251575
+ function isExpressionLike(value) {
251576
+ return (typeof value === 'object' &&
251577
+ value !== null &&
251578
+ 'type' in value &&
251579
+ typeof value.type === 'string');
251580
+ }
251581
+ function getParenthesizedExpression(expression) {
251582
+ const maybeExpression = expression;
251583
+ return maybeExpression.type === 'ParenthesizedExpression' &&
251584
+ isExpressionLike(maybeExpression.expression)
251585
+ ? maybeExpression.expression
251586
+ : null;
251587
+ }
251555
251588
 
251556
251589
  function unwrapMutationTarget(node) {
251557
251590
  let current = node;
@@ -251840,7 +251873,7 @@ function inspectComputedBody(root, context, localScopes, visitedFunctions, repor
251840
251873
  return;
251841
251874
  });
251842
251875
  }
251843
- const rule$s = createRule({
251876
+ const rule$t = createRule({
251844
251877
  create(context) {
251845
251878
  const { checker, esTreeNodeToTSNodeMap, program, sourceCode, tsNodeToESTreeNodeMap, } = getTypeAwareRuleContext(context);
251846
251879
  const signalNodeMap = esTreeNodeToTSNodeMap;
@@ -251883,6 +251916,88 @@ const rule$s = createRule({
251883
251916
  name: 'no-side-effects-in-computed',
251884
251917
  });
251885
251918
 
251919
+ const ANGULAR_CORE = '@angular/core';
251920
+ const SIGNAL_FACTORIES = ['computed', 'effect', 'linkedSignal', 'signal'];
251921
+ function isSignalFactoryCall(node, factoryNames) {
251922
+ if (!node) {
251923
+ return false;
251924
+ }
251925
+ const expression = unwrapExpression(node);
251926
+ return (expression.type === dist$3.AST_NODE_TYPES.CallExpression &&
251927
+ expression.callee.type === dist$3.AST_NODE_TYPES.Identifier &&
251928
+ factoryNames.has(expression.callee.name));
251929
+ }
251930
+ function getModuleScopeVariableDeclaration(statement) {
251931
+ if (statement.type === dist$3.AST_NODE_TYPES.VariableDeclaration) {
251932
+ return statement;
251933
+ }
251934
+ if (statement.type !== dist$3.AST_NODE_TYPES.ExportNamedDeclaration) {
251935
+ return null;
251936
+ }
251937
+ return statement.declaration?.type === dist$3.AST_NODE_TYPES.VariableDeclaration
251938
+ ? statement.declaration
251939
+ : null;
251940
+ }
251941
+ function collectModuleScopeSignalNames(program, factoryNames) {
251942
+ const names = new Set();
251943
+ for (const statement of program.body) {
251944
+ const declaration = getModuleScopeVariableDeclaration(statement);
251945
+ if (!declaration) {
251946
+ continue;
251947
+ }
251948
+ for (const declarator of declaration.declarations) {
251949
+ if (declarator.id.type === dist$3.AST_NODE_TYPES.Identifier &&
251950
+ isSignalFactoryCall(declarator.init, factoryNames)) {
251951
+ names.add(declarator.id.name);
251952
+ }
251953
+ }
251954
+ }
251955
+ return names;
251956
+ }
251957
+ const rule$s = createRule({
251958
+ create(context) {
251959
+ const program = context.sourceCode.ast;
251960
+ const factoryNames = new Set();
251961
+ for (const name of SIGNAL_FACTORIES) {
251962
+ const localName = getLocalNameForImport(program, ANGULAR_CORE, name);
251963
+ if (localName) {
251964
+ factoryNames.add(localName);
251965
+ }
251966
+ }
251967
+ if (factoryNames.size === 0) {
251968
+ return {};
251969
+ }
251970
+ const moduleScopeSignals = collectModuleScopeSignalNames(program, factoryNames);
251971
+ return moduleScopeSignals.size === 0
251972
+ ? {}
251973
+ : {
251974
+ PropertyDefinition(node) {
251975
+ const value = node.value ? unwrapExpression(node.value) : null;
251976
+ if (value?.type !== dist$3.AST_NODE_TYPES.Identifier ||
251977
+ !moduleScopeSignals.has(value.name)) {
251978
+ return;
251979
+ }
251980
+ context.report({
251981
+ data: { name: value.name },
251982
+ messageId: 'noSignalOutsideClass',
251983
+ node: value,
251984
+ });
251985
+ },
251986
+ };
251987
+ },
251988
+ meta: {
251989
+ docs: {
251990
+ description: 'Disallow class properties that reference a module-scope Angular signal; move the signal creation into the class body',
251991
+ },
251992
+ messages: {
251993
+ noSignalOutsideClass: '`{{name}}` is a module-scope signal. Move it into the class body: `{{name}} = signal(...)`.',
251994
+ },
251995
+ schema: [],
251996
+ type: 'problem',
251997
+ },
251998
+ name: 'no-signal-outside-class',
251999
+ });
252000
+
251886
252001
  const rule$r = createUntrackedRule({
251887
252002
  create(context) {
251888
252003
  const { checker, esTreeNodeToTSNodeMap, program, sourceCode } = getTypeAwareRuleContext(context);
@@ -255592,36 +255707,37 @@ const plugin = {
255592
255707
  },
255593
255708
  rules: {
255594
255709
  'array-as-const': rule$5,
255595
- 'attrs-newline': rule$S,
255710
+ 'attrs-newline': rule$T,
255596
255711
  'class-property-naming': rule$4,
255597
- 'decorator-key-sort': rule$R,
255598
- 'element-newline': rule$Q,
255712
+ 'decorator-key-sort': rule$S,
255713
+ 'element-newline': rule$R,
255599
255714
  'flat-exports': rule$3,
255600
- 'host-attributes-sort': rule$P,
255601
- 'html-logical-properties': rule$O,
255602
- 'import-integrity': rule$N,
255603
- 'injection-token-description': rule$M,
255604
- 'no-commonjs-import-patterns': rule$L,
255605
- 'no-deep-imports': rule$K,
255606
- 'no-deep-imports-to-indexed-packages': rule$J,
255607
- 'no-duplicate-attrs': rule$I,
255608
- 'no-duplicate-id': rule$H,
255609
- 'no-duplicate-in-head': rule$G,
255610
- 'no-empty-style-metadata': rule$F,
255611
- 'no-fully-untracked-effect': rule$E,
255612
- 'no-href-with-router-link': rule$D,
255613
- 'no-implicit-public': rule$C,
255614
- 'no-import-assertions': rule$B,
255615
- 'no-infinite-loop': rule$A,
255616
- 'no-legacy-peer-deps': rule$z,
255617
- 'no-obsolete-attrs': rule$y,
255618
- 'no-obsolete-tags': rule$x,
255619
- 'no-playwright-empty-fill': rule$w,
255620
- 'no-project-as-in-ng-template': rule$v,
255621
- 'no-redundant-type-annotation': rule$u,
255622
- 'no-repeated-signal-in-conditional': rule$t,
255715
+ 'host-attributes-sort': rule$Q,
255716
+ 'html-logical-properties': rule$P,
255717
+ 'import-integrity': rule$O,
255718
+ 'injection-token-description': rule$N,
255719
+ 'no-commonjs-import-patterns': rule$M,
255720
+ 'no-deep-imports': rule$L,
255721
+ 'no-deep-imports-to-indexed-packages': rule$K,
255722
+ 'no-duplicate-attrs': rule$J,
255723
+ 'no-duplicate-id': rule$I,
255724
+ 'no-duplicate-in-head': rule$H,
255725
+ 'no-empty-style-metadata': rule$G,
255726
+ 'no-fully-untracked-effect': rule$F,
255727
+ 'no-href-with-router-link': rule$E,
255728
+ 'no-implicit-public': rule$D,
255729
+ 'no-import-assertions': rule$C,
255730
+ 'no-infinite-loop': rule$B,
255731
+ 'no-legacy-peer-deps': rule$A,
255732
+ 'no-obsolete-attrs': rule$z,
255733
+ 'no-obsolete-tags': rule$y,
255734
+ 'no-playwright-empty-fill': rule$x,
255735
+ 'no-project-as-in-ng-template': rule$w,
255736
+ 'no-redundant-type-annotation': rule$v,
255737
+ 'no-repeated-signal-in-conditional': rule$u,
255623
255738
  'no-restricted-attr-values': rule$2,
255624
- 'no-side-effects-in-computed': rule$s,
255739
+ 'no-side-effects-in-computed': rule$t,
255740
+ 'no-signal-outside-class': rule$s,
255625
255741
  'no-signal-reads-after-await-in-reactive-context': rule$r,
255626
255742
  'no-string-literal-concat': rule$q,
255627
255743
  'no-untracked-outside-reactive-context': rule$p,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ui/eslint-plugin-experience-next",
3
- "version": "0.510.0",
3
+ "version": "0.512.0",
4
4
  "description": "An ESLint plugin to enforce a consistent code styles across taiga-ui projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -4,6 +4,13 @@ export declare const TUI_RECOMMENDED_NAMING_CONVENTION: readonly [{
4
4
  }, {
5
5
  readonly format: readonly ["camelCase"];
6
6
  readonly selector: readonly ["classMethod", "classProperty"];
7
+ }, {
8
+ readonly filter: {
9
+ readonly match: true;
10
+ readonly regex: string;
11
+ };
12
+ readonly format: null;
13
+ readonly selector: "classProperty";
7
14
  }, {
8
15
  readonly format: readonly ["UPPER_CASE", "camelCase", "PascalCase"];
9
16
  readonly selector: readonly ["variable"];
@@ -28,6 +35,13 @@ export declare const TUI_CUSTOM_TAIGA_NAMING_CONVENTION: readonly [{
28
35
  }, {
29
36
  readonly format: readonly ["camelCase"];
30
37
  readonly selector: readonly ["classMethod", "classProperty"];
38
+ }, {
39
+ readonly filter: {
40
+ readonly match: true;
41
+ readonly regex: string;
42
+ };
43
+ readonly format: null;
44
+ readonly selector: "classProperty";
31
45
  }, {
32
46
  readonly format: readonly ["UPPER_CASE", "camelCase", "PascalCase"];
33
47
  readonly selector: readonly ["variable"];
@@ -0,0 +1,4 @@
1
+ export declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"noSignalOutsideClass", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
2
+ name: string;
3
+ };
4
+ export default rule;
@@ -1,7 +1,8 @@
1
1
  import { type TSESTree } from '@typescript-eslint/utils';
2
2
  /**
3
- * Strips TypeScript-only wrapper nodes that have no runtime meaning:
4
- * `as` casts, non-null assertions (`!`), type assertions (`<T>expr`), and
5
- * optional-chain wrappers. Iterates until no more wrappers are found.
3
+ * Strips expression wrapper nodes that do not affect the underlying expression:
4
+ * parentheses, `as` casts, `satisfies`, non-null assertions (`!`), type
5
+ * assertions (`<T>expr`), and optional-chain wrappers. Iterates until no more
6
+ * wrappers are found.
6
7
  */
7
8
  export declare function unwrapExpression(expression: TSESTree.Expression): TSESTree.Expression;