@taiga-ui/eslint-plugin-experience-next 0.510.0 → 0.511.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
@@ -1210,6 +1210,7 @@ var recommended = defineConfig([
1210
1210
  '@taiga-ui/experience-next/no-redundant-type-annotation': 'error',
1211
1211
  '@taiga-ui/experience-next/no-repeated-signal-in-conditional': 'error',
1212
1212
  '@taiga-ui/experience-next/no-side-effects-in-computed': 'error',
1213
+ '@taiga-ui/experience-next/no-signal-outside-class': 'error',
1213
1214
  '@taiga-ui/experience-next/no-signal-reads-after-await-in-reactive-context': 'error',
1214
1215
  '@taiga-ui/experience-next/no-untracked-outside-reactive-context': 'error',
1215
1216
  '@taiga-ui/experience-next/no-useless-untracked': 'error',
@@ -46224,7 +46225,7 @@ function buildMultilineStartTag(node, sourceText) {
46224
46225
  closing,
46225
46226
  ].join('\n');
46226
46227
  }
46227
- const rule$S = createRule({
46228
+ const rule$T = createRule({
46228
46229
  name: 'attrs-newline',
46229
46230
  rule: {
46230
46231
  create(context) {
@@ -46404,7 +46405,7 @@ function sameOrder(a, b) {
46404
46405
  return a.length === b.length && a.every((value, index) => value === b[index]);
46405
46406
  }
46406
46407
 
46407
- const rule$R = createRule({
46408
+ const rule$S = createRule({
46408
46409
  create(context, [order]) {
46409
46410
  const decorators = new Set(Object.keys(order));
46410
46411
  return {
@@ -46540,7 +46541,7 @@ function getNodeLabel(node) {
46540
46541
  }
46541
46542
  return node instanceof dist$4.TmplAstBoundText ? 'binding' : 'text';
46542
46543
  }
46543
- const rule$Q = createRule({
46544
+ const rule$R = createRule({
46544
46545
  name: 'element-newline',
46545
46546
  rule: {
46546
46547
  create(context) {
@@ -46679,7 +46680,7 @@ const PRESETS = {
46679
46680
  $VUE: ['$CLASS', '$ID', '$VUE_ATTRIBUTE'],
46680
46681
  $VUE_ATTRIBUTE: /^v-/,
46681
46682
  };
46682
- const rule$P = createRule({
46683
+ const rule$Q = createRule({
46683
46684
  create(context, [options]) {
46684
46685
  const sourceCode = context.sourceCode;
46685
46686
  const settings = {
@@ -47010,7 +47011,7 @@ const config$4 = {
47010
47011
  type: 'suggestion',
47011
47012
  },
47012
47013
  };
47013
- const rule$O = createRule({
47014
+ const rule$P = createRule({
47014
47015
  name: 'html-logical-properties',
47015
47016
  rule: config$4,
47016
47017
  });
@@ -248252,7 +248253,7 @@ function isImportUsedOnlyAsAngularDiFirstArg(node, sourceCode) {
248252
248253
  }
248253
248254
  return hasSafeRuntimeUsage;
248254
248255
  }
248255
- const rule$N = createRule({
248256
+ const rule$O = createRule({
248256
248257
  create(context) {
248257
248258
  const { checker, esTreeNodeToTSNodeMap, sourceCode, tsProgram } = getTypeAwareRuleContext(context);
248258
248259
  const checkCycles = context.options[0]?.checkCycles ?? true;
@@ -248977,7 +248978,7 @@ function getNgDevModeDeclarationFix(program, fixer) {
248977
248978
  ? fixer.insertTextBefore(firstStatement, 'declare const ngDevMode: boolean;\n\n')
248978
248979
  : fixer.insertTextBeforeRange([0, 0], 'declare const ngDevMode: boolean;\n');
248979
248980
  }
248980
- const rule$M = createRule({
248981
+ const rule$N = createRule({
248981
248982
  create(context) {
248982
248983
  const { sourceCode } = context;
248983
248984
  const program = sourceCode.ast;
@@ -249026,7 +249027,7 @@ const rule$M = createRule({
249026
249027
  name: 'injection-token-description',
249027
249028
  });
249028
249029
 
249029
- const rule$L = createRule({
249030
+ const rule$M = createRule({
249030
249031
  create(context) {
249031
249032
  const { sourceCode } = context;
249032
249033
  const namespaceImports = new Map();
@@ -249121,7 +249122,7 @@ const DEFAULT_OPTIONS = {
249121
249122
  importDeclaration: '^@taiga-ui*',
249122
249123
  projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
249123
249124
  };
249124
- const rule$K = createRule({
249125
+ const rule$L = createRule({
249125
249126
  create(context) {
249126
249127
  const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
249127
249128
  const hasNonCodeExtension = (source) => {
@@ -249213,7 +249214,7 @@ const nearestFileUpCache = new Map();
249213
249214
  const markerCache = new Map();
249214
249215
  const indexFileCache = new Map();
249215
249216
  const indexExportsCache = new Map();
249216
- const rule$J = createRule({
249217
+ const rule$K = createRule({
249217
249218
  create(context) {
249218
249219
  const parserServices = dist$3.ESLintUtils.getParserServices(context);
249219
249220
  const program = parserServices.program;
@@ -249407,13 +249408,13 @@ const noDuplicateAttributesRule = angular.templatePlugin.rules?.['no-duplicate-a
249407
249408
  if (!noDuplicateAttributesRule) {
249408
249409
  throw new Error('angular-eslint template rule "no-duplicate-attributes" is not available');
249409
249410
  }
249410
- const rule$I = createRule({
249411
+ const rule$J = createRule({
249411
249412
  name: 'no-duplicate-attrs',
249412
249413
  rule: noDuplicateAttributesRule,
249413
249414
  });
249414
249415
 
249415
249416
  const MESSAGE_ID$c = 'duplicateId';
249416
- const rule$H = createRule({
249417
+ const rule$I = createRule({
249417
249418
  name: 'no-duplicate-id',
249418
249419
  rule: {
249419
249420
  create(context) {
@@ -249474,7 +249475,7 @@ function getTrackingKey(node) {
249474
249475
  ? 'link[rel=canonical]'
249475
249476
  : null;
249476
249477
  }
249477
- const rule$G = createRule({
249478
+ const rule$H = createRule({
249478
249479
  name: 'no-duplicate-in-head',
249479
249480
  rule: {
249480
249481
  create(context) {
@@ -249530,7 +249531,7 @@ const rule$G = createRule({
249530
249531
  });
249531
249532
 
249532
249533
  const COMPONENT_DECORATORS = new Set(['Component']);
249533
- const rule$F = createRule({
249534
+ const rule$G = createRule({
249534
249535
  create(context) {
249535
249536
  const { sourceCode } = context;
249536
249537
  return {
@@ -249823,7 +249824,7 @@ function walkAst(root, visitor) {
249823
249824
  }
249824
249825
  }
249825
249826
 
249826
- const ANGULAR_CORE$1 = '@angular/core';
249827
+ const ANGULAR_CORE$2 = '@angular/core';
249827
249828
  /**
249828
249829
  * Returns the local name bound to a named import from a given source.
249829
249830
  * Handles aliased imports: `import { untracked as ngUntracked } from '@angular/core'`
@@ -249851,7 +249852,7 @@ function getLocalNameForImport(program, source, exportedName) {
249851
249852
  }
249852
249853
  function findAngularCoreImports(program) {
249853
249854
  return program.body.filter((node) => node.type === dist$3.AST_NODE_TYPES.ImportDeclaration &&
249854
- node.source.value === ANGULAR_CORE$1);
249855
+ node.source.value === ANGULAR_CORE$2);
249855
249856
  }
249856
249857
  function findRuntimeAngularCoreImport(program) {
249857
249858
  return (findAngularCoreImports(program).find((node) => node.importKind !== 'type') ?? null);
@@ -249873,7 +249874,7 @@ function findAngularCoreImportSpecifier(program, exportedName) {
249873
249874
  return null;
249874
249875
  }
249875
249876
 
249876
- const ANGULAR_CORE = '@angular/core';
249877
+ const ANGULAR_CORE$1 = '@angular/core';
249877
249878
  const SIGNAL_WRITE_METHODS = new Set(['mutate', 'set', 'update']);
249878
249879
  const AFTER_RENDER_EFFECT_PHASES = new Map([
249879
249880
  ['earlyRead', 'afterRenderEffect().earlyRead'],
@@ -249899,7 +249900,7 @@ function getPropertyName(property) {
249899
249900
  return typeof property.key.value === 'string' ? property.key.value : null;
249900
249901
  }
249901
249902
  function isAngularCoreCall(node, program, exportedName) {
249902
- const localName = getLocalNameForImport(program, ANGULAR_CORE, exportedName);
249903
+ const localName = getLocalNameForImport(program, ANGULAR_CORE$1, exportedName);
249903
249904
  return localName
249904
249905
  ? node.callee.type === dist$3.AST_NODE_TYPES.Identifier &&
249905
249906
  node.callee.name === localName &&
@@ -250178,7 +250179,7 @@ const ANGULAR_SIGNALS_UNTRACKED_GUIDE_URL = 'https://angular.dev/guide/signals#r
250178
250179
  const ANGULAR_SIGNALS_ASYNC_GUIDE_URL = 'https://angular.dev/guide/signals#reactive-context-and-async-operations';
250179
250180
  const createUntrackedRule = createRule;
250180
250181
 
250181
- const rule$E = createUntrackedRule({
250182
+ const rule$F = createUntrackedRule({
250182
250183
  create(context) {
250183
250184
  const { checker, esTreeNodeToTSNodeMap, program } = getTypeAwareRuleContext(context);
250184
250185
  const signalNodeMap = esTreeNodeToTSNodeMap;
@@ -250251,7 +250252,7 @@ const config$3 = {
250251
250252
  type: 'problem',
250252
250253
  },
250253
250254
  };
250254
- const rule$D = createRule({
250255
+ const rule$E = createRule({
250255
250256
  name: 'no-href-with-router-link',
250256
250257
  rule: config$3,
250257
250258
  });
@@ -250312,7 +250313,7 @@ function getScopeRoot(node) {
250312
250313
  return (findAncestor(node, (ancestor) => ancestor.type === dist$3.AST_NODE_TYPES.Program || isFunctionLike(ancestor)) ?? node);
250313
250314
  }
250314
250315
 
250315
- const rule$C = createRule({
250316
+ const rule$D = createRule({
250316
250317
  create(context) {
250317
250318
  const checkImplicitPublic = (node) => {
250318
250319
  const classRef = getEnclosingClass(node);
@@ -250374,7 +250375,7 @@ const rule$C = createRule({
250374
250375
  name: 'no-implicit-public',
250375
250376
  });
250376
250377
 
250377
- const rule$B = createRule({
250378
+ const rule$C = createRule({
250378
250379
  create(context) {
250379
250380
  const { sourceCode } = context;
250380
250381
  return {
@@ -250430,7 +250431,7 @@ function isInfiniteLoopLiteral(node) {
250430
250431
  function isInfiniteLoopTest(test) {
250431
250432
  return test == null || isInfiniteLoopLiteral(test);
250432
250433
  }
250433
- const rule$A = createRule({
250434
+ const rule$B = createRule({
250434
250435
  create(context) {
250435
250436
  return {
250436
250437
  DoWhileStatement(node) {
@@ -250475,7 +250476,7 @@ const rule$A = createRule({
250475
250476
  });
250476
250477
 
250477
250478
  const LEGACY_PEER_DEPS_PATTERN = /^legacy-peer-deps\s*=\s*true$/i;
250478
- const rule$z = createRule({
250479
+ const rule$A = createRule({
250479
250480
  create(context) {
250480
250481
  return {
250481
250482
  Program(node) {
@@ -250935,7 +250936,7 @@ const OBSOLETE_HTML_ATTRS = {
250935
250936
  };
250936
250937
 
250937
250938
  const MESSAGE_ID$9 = 'obsolete';
250938
- const rule$y = createRule({
250939
+ const rule$z = createRule({
250939
250940
  name: 'no-obsolete-attrs',
250940
250941
  rule: {
250941
250942
  create(context) {
@@ -251013,7 +251014,7 @@ const OBSOLETE_HTML_TAGS = new Set([
251013
251014
  ]);
251014
251015
 
251015
251016
  const MESSAGE_ID$8 = 'unexpected';
251016
- const rule$x = createRule({
251017
+ const rule$y = createRule({
251017
251018
  name: 'no-obsolete-tags',
251018
251019
  rule: {
251019
251020
  create(context) {
@@ -251040,7 +251041,7 @@ const rule$x = createRule({
251040
251041
  },
251041
251042
  });
251042
251043
 
251043
- const rule$w = createRule({
251044
+ const rule$x = createRule({
251044
251045
  create(context) {
251045
251046
  const { checker, esTreeNodeToTSNodeMap, sourceCode } = getTypeAwareRuleContext(context);
251046
251047
  return {
@@ -251184,7 +251185,7 @@ const config$2 = {
251184
251185
  type: 'problem',
251185
251186
  },
251186
251187
  };
251187
- const rule$v = createRule({
251188
+ const rule$w = createRule({
251188
251189
  name: 'no-project-as-in-ng-template',
251189
251190
  rule: config$2,
251190
251191
  });
@@ -251221,7 +251222,7 @@ function collectArrayExpressions(node) {
251221
251222
  }
251222
251223
  return result;
251223
251224
  }
251224
- const rule$u = createRule({
251225
+ const rule$v = createRule({
251225
251226
  create(context) {
251226
251227
  const { checker: typeChecker, esTreeNodeToTSNodeMap } = getTypeAwareRuleContext(context);
251227
251228
  const ignoreTupleContextualTyping = context.options[0]?.ignoreTupleContextualTyping ?? true;
@@ -251419,7 +251420,7 @@ function isOptionalMemberReceiver(call) {
251419
251420
  parent.object === current &&
251420
251421
  parent.optional);
251421
251422
  }
251422
- const rule$t = createRule({
251423
+ const rule$u = createRule({
251423
251424
  create(context) {
251424
251425
  const { checker, esTreeNodeToTSNodeMap, sourceCode } = getTypeAwareRuleContext(context);
251425
251426
  const signalNodeMap = esTreeNodeToTSNodeMap;
@@ -251522,15 +251523,22 @@ const rule$t = createRule({
251522
251523
  });
251523
251524
 
251524
251525
  /**
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.
251526
+ * Strips expression wrapper nodes that do not affect the underlying expression:
251527
+ * parentheses, `as` casts, `satisfies`, non-null assertions (`!`), type
251528
+ * assertions (`<T>expr`), and optional-chain wrappers. Iterates until no more
251529
+ * wrappers are found.
251528
251530
  */
251529
251531
  function unwrapExpression(expression) {
251530
251532
  let current = expression;
251531
251533
  let didUnwrap = true;
251532
251534
  while (didUnwrap) {
251533
251535
  didUnwrap = false;
251536
+ const parenthesized = getParenthesizedExpression(current);
251537
+ if (parenthesized) {
251538
+ current = parenthesized;
251539
+ didUnwrap = true;
251540
+ continue;
251541
+ }
251534
251542
  switch (current.type) {
251535
251543
  case dist$3.AST_NODE_TYPES.ChainExpression:
251536
251544
  current = current.expression;
@@ -251544,6 +251552,10 @@ function unwrapExpression(expression) {
251544
251552
  current = current.expression;
251545
251553
  didUnwrap = true;
251546
251554
  break;
251555
+ case dist$3.AST_NODE_TYPES.TSSatisfiesExpression:
251556
+ current = current.expression;
251557
+ didUnwrap = true;
251558
+ break;
251547
251559
  case dist$3.AST_NODE_TYPES.TSTypeAssertion:
251548
251560
  current = current.expression;
251549
251561
  didUnwrap = true;
@@ -251552,6 +251564,19 @@ function unwrapExpression(expression) {
251552
251564
  }
251553
251565
  return current;
251554
251566
  }
251567
+ function isExpressionLike(value) {
251568
+ return (typeof value === 'object' &&
251569
+ value !== null &&
251570
+ 'type' in value &&
251571
+ typeof value.type === 'string');
251572
+ }
251573
+ function getParenthesizedExpression(expression) {
251574
+ const maybeExpression = expression;
251575
+ return maybeExpression.type === 'ParenthesizedExpression' &&
251576
+ isExpressionLike(maybeExpression.expression)
251577
+ ? maybeExpression.expression
251578
+ : null;
251579
+ }
251555
251580
 
251556
251581
  function unwrapMutationTarget(node) {
251557
251582
  let current = node;
@@ -251840,7 +251865,7 @@ function inspectComputedBody(root, context, localScopes, visitedFunctions, repor
251840
251865
  return;
251841
251866
  });
251842
251867
  }
251843
- const rule$s = createRule({
251868
+ const rule$t = createRule({
251844
251869
  create(context) {
251845
251870
  const { checker, esTreeNodeToTSNodeMap, program, sourceCode, tsNodeToESTreeNodeMap, } = getTypeAwareRuleContext(context);
251846
251871
  const signalNodeMap = esTreeNodeToTSNodeMap;
@@ -251883,6 +251908,88 @@ const rule$s = createRule({
251883
251908
  name: 'no-side-effects-in-computed',
251884
251909
  });
251885
251910
 
251911
+ const ANGULAR_CORE = '@angular/core';
251912
+ const SIGNAL_FACTORIES = ['computed', 'effect', 'linkedSignal', 'signal'];
251913
+ function isSignalFactoryCall(node, factoryNames) {
251914
+ if (!node) {
251915
+ return false;
251916
+ }
251917
+ const expression = unwrapExpression(node);
251918
+ return (expression.type === dist$3.AST_NODE_TYPES.CallExpression &&
251919
+ expression.callee.type === dist$3.AST_NODE_TYPES.Identifier &&
251920
+ factoryNames.has(expression.callee.name));
251921
+ }
251922
+ function getModuleScopeVariableDeclaration(statement) {
251923
+ if (statement.type === dist$3.AST_NODE_TYPES.VariableDeclaration) {
251924
+ return statement;
251925
+ }
251926
+ if (statement.type !== dist$3.AST_NODE_TYPES.ExportNamedDeclaration) {
251927
+ return null;
251928
+ }
251929
+ return statement.declaration?.type === dist$3.AST_NODE_TYPES.VariableDeclaration
251930
+ ? statement.declaration
251931
+ : null;
251932
+ }
251933
+ function collectModuleScopeSignalNames(program, factoryNames) {
251934
+ const names = new Set();
251935
+ for (const statement of program.body) {
251936
+ const declaration = getModuleScopeVariableDeclaration(statement);
251937
+ if (!declaration) {
251938
+ continue;
251939
+ }
251940
+ for (const declarator of declaration.declarations) {
251941
+ if (declarator.id.type === dist$3.AST_NODE_TYPES.Identifier &&
251942
+ isSignalFactoryCall(declarator.init, factoryNames)) {
251943
+ names.add(declarator.id.name);
251944
+ }
251945
+ }
251946
+ }
251947
+ return names;
251948
+ }
251949
+ const rule$s = createRule({
251950
+ create(context) {
251951
+ const program = context.sourceCode.ast;
251952
+ const factoryNames = new Set();
251953
+ for (const name of SIGNAL_FACTORIES) {
251954
+ const localName = getLocalNameForImport(program, ANGULAR_CORE, name);
251955
+ if (localName) {
251956
+ factoryNames.add(localName);
251957
+ }
251958
+ }
251959
+ if (factoryNames.size === 0) {
251960
+ return {};
251961
+ }
251962
+ const moduleScopeSignals = collectModuleScopeSignalNames(program, factoryNames);
251963
+ return moduleScopeSignals.size === 0
251964
+ ? {}
251965
+ : {
251966
+ PropertyDefinition(node) {
251967
+ const value = node.value ? unwrapExpression(node.value) : null;
251968
+ if (value?.type !== dist$3.AST_NODE_TYPES.Identifier ||
251969
+ !moduleScopeSignals.has(value.name)) {
251970
+ return;
251971
+ }
251972
+ context.report({
251973
+ data: { name: value.name },
251974
+ messageId: 'noSignalOutsideClass',
251975
+ node: value,
251976
+ });
251977
+ },
251978
+ };
251979
+ },
251980
+ meta: {
251981
+ docs: {
251982
+ description: 'Disallow class properties that reference a module-scope Angular signal; move the signal creation into the class body',
251983
+ },
251984
+ messages: {
251985
+ noSignalOutsideClass: '`{{name}}` is a module-scope signal. Move it into the class body: `{{name}} = signal(...)`.',
251986
+ },
251987
+ schema: [],
251988
+ type: 'problem',
251989
+ },
251990
+ name: 'no-signal-outside-class',
251991
+ });
251992
+
251886
251993
  const rule$r = createUntrackedRule({
251887
251994
  create(context) {
251888
251995
  const { checker, esTreeNodeToTSNodeMap, program, sourceCode } = getTypeAwareRuleContext(context);
@@ -255592,36 +255699,37 @@ const plugin = {
255592
255699
  },
255593
255700
  rules: {
255594
255701
  'array-as-const': rule$5,
255595
- 'attrs-newline': rule$S,
255702
+ 'attrs-newline': rule$T,
255596
255703
  'class-property-naming': rule$4,
255597
- 'decorator-key-sort': rule$R,
255598
- 'element-newline': rule$Q,
255704
+ 'decorator-key-sort': rule$S,
255705
+ 'element-newline': rule$R,
255599
255706
  '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,
255707
+ 'host-attributes-sort': rule$Q,
255708
+ 'html-logical-properties': rule$P,
255709
+ 'import-integrity': rule$O,
255710
+ 'injection-token-description': rule$N,
255711
+ 'no-commonjs-import-patterns': rule$M,
255712
+ 'no-deep-imports': rule$L,
255713
+ 'no-deep-imports-to-indexed-packages': rule$K,
255714
+ 'no-duplicate-attrs': rule$J,
255715
+ 'no-duplicate-id': rule$I,
255716
+ 'no-duplicate-in-head': rule$H,
255717
+ 'no-empty-style-metadata': rule$G,
255718
+ 'no-fully-untracked-effect': rule$F,
255719
+ 'no-href-with-router-link': rule$E,
255720
+ 'no-implicit-public': rule$D,
255721
+ 'no-import-assertions': rule$C,
255722
+ 'no-infinite-loop': rule$B,
255723
+ 'no-legacy-peer-deps': rule$A,
255724
+ 'no-obsolete-attrs': rule$z,
255725
+ 'no-obsolete-tags': rule$y,
255726
+ 'no-playwright-empty-fill': rule$x,
255727
+ 'no-project-as-in-ng-template': rule$w,
255728
+ 'no-redundant-type-annotation': rule$v,
255729
+ 'no-repeated-signal-in-conditional': rule$u,
255623
255730
  'no-restricted-attr-values': rule$2,
255624
- 'no-side-effects-in-computed': rule$s,
255731
+ 'no-side-effects-in-computed': rule$t,
255732
+ 'no-signal-outside-class': rule$s,
255625
255733
  'no-signal-reads-after-await-in-reactive-context': rule$r,
255626
255734
  'no-string-literal-concat': rule$q,
255627
255735
  '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.511.0",
4
4
  "description": "An ESLint plugin to enforce a consistent code styles across taiga-ui projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -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;