@taiga-ui/eslint-plugin-experience-next 0.526.0 → 0.528.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
@@ -75,6 +75,7 @@ from third-party plugins. The exact severities and file globs live in
75
75
  | [array-as-const](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/array-as-const.md) | Exported array of class references should be marked with `as const` | | 🔧 | |
76
76
  | [at-compat](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/at-compat.md) | Keep built-in `.at()` and indexed access aligned with the TypeScript target | ✅ | 🔧 | |
77
77
  | [attrs-newline](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/attrs-newline.md) | Enforce one attribute per line when a start tag spans multiple lines | ✅ | 🔧 | |
78
+ | [class-accessibility-spacing](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/class-accessibility-spacing.md) | Separate adjacent class members with a blank line when their accessibility group changes | ✅ | 🔧 | |
78
79
  | [class-property-naming](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/class-property-naming.md) | Enforce custom naming for class properties based on their type | | 🔧 | |
79
80
  | [decorator-key-sort](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/decorator-key-sort.md) | Sorts the keys of the object passed to the `@Component/@Injectable/@NgModule/@Pipe` decorator | ✅ | 🔧 | |
80
81
  | [element-newline](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/element-newline.md) | Require line breaks around block-level child nodes in HTML templates | ✅ | 🔧 | |
package/index.d.ts CHANGED
@@ -18,6 +18,9 @@ declare const plugin: {
18
18
  'attrs-newline': import("eslint").Rule.RuleModule & {
19
19
  name: string;
20
20
  };
21
+ 'class-accessibility-spacing': import("@typescript-eslint/utils/ts-eslint").RuleModule<"classAccessibilitySpacing", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
22
+ name: string;
23
+ };
21
24
  'class-property-naming': import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalidName", [import("./rules/taiga-specific/class-property-naming").RuleConfig[]], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
22
25
  name: string;
23
26
  };
package/index.esm.js CHANGED
@@ -465,8 +465,111 @@ const TUI_MEMBER_ORDERING_CONVENTION = [
465
465
  '#private-instance-method',
466
466
  ];
467
467
 
468
+ function isSingleLineNode(node) {
469
+ return node.loc.start.line === node.loc.end.line;
470
+ }
471
+ function isLineBreakCharacter(char) {
472
+ return char === '\n' || char === '\r';
473
+ }
474
+ function hasCommentLikeText(text) {
475
+ return text.includes('//') || text.includes('/*');
476
+ }
477
+ function hasBlankLine(text) {
478
+ let lineBreaks = 0;
479
+ for (let index = 0; index < text.length; index++) {
480
+ const char = text[index];
481
+ if (char === '\n') {
482
+ lineBreaks++;
483
+ }
484
+ else if (char === '\r') {
485
+ lineBreaks++;
486
+ if (text[index + 1] === '\n') {
487
+ index++;
488
+ }
489
+ }
490
+ if (lineBreaks > 1) {
491
+ return true;
492
+ }
493
+ }
494
+ return false;
495
+ }
496
+ function hasBlankLineBetweenNodes(text) {
497
+ const lines = splitLines(text);
498
+ const linesBetweenNodes = lines.slice(1, -1);
499
+ return linesBetweenNodes.some((line) => line.trim() === '');
500
+ }
501
+ function getLineBreak(text) {
502
+ if (text.includes('\r\n')) {
503
+ return '\r\n';
504
+ }
505
+ return text.includes('\r') ? '\r' : '\n';
506
+ }
507
+ function hasLineBreak(text) {
508
+ for (const char of text) {
509
+ if (isLineBreakCharacter(char)) {
510
+ return true;
511
+ }
512
+ }
513
+ return false;
514
+ }
515
+ function getLeadingIndentation(text) {
516
+ let index = 0;
517
+ while (index < text.length && (text[index] === ' ' || text[index] === '\t')) {
518
+ index++;
519
+ }
520
+ return text.slice(0, index);
521
+ }
522
+ function getLineStartOffset(text, offset) {
523
+ let index = offset - 1;
524
+ while (index >= 0) {
525
+ const char = text[index];
526
+ if (isLineBreakCharacter(char)) {
527
+ return index + 1;
528
+ }
529
+ index--;
530
+ }
531
+ return 0;
532
+ }
533
+ function getLineEndOffset(text, lineStartOffset) {
534
+ let index = lineStartOffset;
535
+ while (index < text.length) {
536
+ const char = text[index];
537
+ if (isLineBreakCharacter(char)) {
538
+ return index;
539
+ }
540
+ index++;
541
+ }
542
+ return text.length;
543
+ }
544
+ function getNextLineStartOffset(text, offset) {
545
+ let index = offset;
546
+ while (index < text.length) {
547
+ const char = text[index];
548
+ if (char === '\r') {
549
+ return text[index + 1] === '\n' ? index + 2 : index + 1;
550
+ }
551
+ if (char === '\n') {
552
+ return index + 1;
553
+ }
554
+ index++;
555
+ }
556
+ return offset;
557
+ }
558
+ function splitLines(text) {
559
+ return text.split(/\r\n|\n|\r/);
560
+ }
561
+ function getIndentAtOffset(text, offset) {
562
+ const lineStart = getLineStartOffset(text, offset);
563
+ const indent = text.slice(lineStart, offset);
564
+ return indent.trim() === '' ? indent : '';
565
+ }
566
+ function getSpacingReplacement(sourceCode, betweenText, nextLine, blankLineCount) {
567
+ const indentation = getLeadingIndentation(sourceCode.lines[nextLine - 1] ?? '');
568
+ return `${getLineBreak(betweenText).repeat(blankLineCount + 1)}${indentation}`;
569
+ }
570
+
468
571
  function buildAST(text) {
469
- const lines = text.split('\n');
572
+ const lines = splitLines(text);
470
573
  const lastLine = lines[lines.length - 1] ?? '';
471
574
  return {
472
575
  body: [],
@@ -1149,6 +1252,7 @@ var recommended = defineConfig([
1149
1252
  '@angular-eslint/use-lifecycle-interface': 'error',
1150
1253
  '@angular-eslint/use-pipe-transform-interface': 'error',
1151
1254
  '@taiga-ui/experience-next/at-compat': 'error',
1255
+ '@taiga-ui/experience-next/class-accessibility-spacing': 'error',
1152
1256
  '@taiga-ui/experience-next/decorator-key-sort': [
1153
1257
  'error',
1154
1258
  {
@@ -14876,6 +14980,40 @@ function getParenthesizedExpression(expression) {
14876
14980
  : null;
14877
14981
  }
14878
14982
 
14983
+ function isFieldLikeMember(member) {
14984
+ return (member.type === dist$4.AST_NODE_TYPES.PropertyDefinition ||
14985
+ member.type === dist$4.AST_NODE_TYPES.TSAbstractPropertyDefinition);
14986
+ }
14987
+ function isAccessorMember(member) {
14988
+ return (member.type === dist$4.AST_NODE_TYPES.MethodDefinition &&
14989
+ (member.kind === 'get' || member.kind === 'set'));
14990
+ }
14991
+ function isRelevantSpacingClassMember(member) {
14992
+ return isFieldLikeMember(member) || isAccessorMember(member);
14993
+ }
14994
+ function isAccessibilityClassMember(member) {
14995
+ switch (member.type) {
14996
+ case dist$4.AST_NODE_TYPES.AccessorProperty:
14997
+ case dist$4.AST_NODE_TYPES.MethodDefinition:
14998
+ case dist$4.AST_NODE_TYPES.PropertyDefinition:
14999
+ case dist$4.AST_NODE_TYPES.TSAbstractAccessorProperty:
15000
+ case dist$4.AST_NODE_TYPES.TSAbstractMethodDefinition:
15001
+ case dist$4.AST_NODE_TYPES.TSAbstractPropertyDefinition:
15002
+ case dist$4.AST_NODE_TYPES.TSIndexSignature:
15003
+ return true;
15004
+ default:
15005
+ return false;
15006
+ }
15007
+ }
15008
+ function isEcmascriptPrivateClassMember(member) {
15009
+ return 'key' in member && member.key.type === dist$4.AST_NODE_TYPES.PrivateIdentifier;
15010
+ }
15011
+ function getAccessibilityGroup(member) {
15012
+ return isEcmascriptPrivateClassMember(member)
15013
+ ? 'private'
15014
+ : (member.accessibility ?? 'public');
15015
+ }
15016
+
14879
15017
  const EQUALITY_OPERATORS = new Set(['!=', '!==', '==', '===']);
14880
15018
  function getChainExpressionRoot(node) {
14881
15019
  const parent = getParentNode(node);
@@ -15091,62 +15229,11 @@ function getMemberExpressionPropertyName(node) {
15091
15229
  return node.computed ? getStaticStringValue(node.property) : null;
15092
15230
  }
15093
15231
  function getClassMemberName(member) {
15094
- return member.key.type === dist$4.AST_NODE_TYPES.PrivateIdentifier
15232
+ return isEcmascriptPrivateClassMember(member)
15095
15233
  ? null
15096
15234
  : getStaticPropertyName(member.key);
15097
15235
  }
15098
15236
 
15099
- function isSingleLineNode(node) {
15100
- return node.loc.start.line === node.loc.end.line;
15101
- }
15102
- function hasCommentLikeText(text) {
15103
- return text.includes('//') || text.includes('/*');
15104
- }
15105
- function hasBlankLine(text) {
15106
- let lineBreaks = 0;
15107
- for (let index = 0; index < text.length; index++) {
15108
- const char = text[index];
15109
- if (char === '\n') {
15110
- lineBreaks++;
15111
- }
15112
- else if (char === '\r') {
15113
- lineBreaks++;
15114
- if (text[index + 1] === '\n') {
15115
- index++;
15116
- }
15117
- }
15118
- if (lineBreaks > 1) {
15119
- return true;
15120
- }
15121
- }
15122
- return false;
15123
- }
15124
- function getLineBreak(text) {
15125
- if (text.includes('\r\n')) {
15126
- return '\r\n';
15127
- }
15128
- return text.includes('\r') ? '\r' : '\n';
15129
- }
15130
- function getLeadingIndentation(text) {
15131
- let index = 0;
15132
- while (index < text.length && (text[index] === ' ' || text[index] === '\t')) {
15133
- index++;
15134
- }
15135
- return text.slice(0, index);
15136
- }
15137
- function getLineStartOffset(text, offset) {
15138
- return text.lastIndexOf('\n', offset - 1) + 1;
15139
- }
15140
- function getIndentAtOffset(text, offset) {
15141
- const lineStart = getLineStartOffset(text, offset);
15142
- const indent = text.slice(lineStart, offset);
15143
- return indent.trim() === '' ? indent : '';
15144
- }
15145
- function getSpacingReplacement(sourceCode, betweenText, nextLine, blankLineCount) {
15146
- const indentation = getLeadingIndentation(sourceCode.lines[nextLine - 1] ?? '');
15147
- return `${getLineBreak(betweenText).repeat(blankLineCount + 1)}${indentation}`;
15148
- }
15149
-
15150
15237
  const RULE_DOCS_BASE_URL = 'https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs';
15151
15238
  const ruleCreator = dist$4.ESLintUtils.RuleCreator((name) => `${RULE_DOCS_BASE_URL}/${name}.md`);
15152
15239
  function createRule(options) {
@@ -216065,12 +216152,10 @@ function getPreferredTemporaryNames(node) {
216065
216152
  ];
216066
216153
  }
216067
216154
  function getClassElementName(member) {
216068
- if (!('key' in member)) {
216069
- return null;
216155
+ if (isEcmascriptPrivateClassMember(member)) {
216156
+ return member.key.name;
216070
216157
  }
216071
- return member.key.type === dist$4.AST_NODE_TYPES.PrivateIdentifier
216072
- ? member.key.name
216073
- : getStaticPropertyName(member.key);
216158
+ return 'key' in member ? getStaticPropertyName(member.key) : null;
216074
216159
  }
216075
216160
  function hasClassElementName(classBody, name) {
216076
216161
  return classBody.body.some((member) => getClassElementName(member) === name);
@@ -216220,7 +216305,7 @@ function getLastIndexFix(fixer, sourceCode, node, call) {
216220
216305
  }
216221
216306
  return null;
216222
216307
  }
216223
- const rule$X = createRule({
216308
+ const rule$Y = createRule({
216224
216309
  create(context) {
216225
216310
  const typeAwareContext = getTypeAwareRuleContext(context);
216226
216311
  const compilerOptions = typeAwareContext.tsProgram.getCompilerOptions();
@@ -248017,15 +248102,16 @@ function buildMultilineStartTag(node, sourceText) {
248017
248102
  const closing = sourceText
248018
248103
  .slice(lastAttr ? lastAttr.sourceSpan.end.offset : startTag.end.offset, startTag.end.offset)
248019
248104
  .trimStart();
248105
+ const lineBreak = getLineBreak(sourceText);
248020
248106
  return [
248021
248107
  tagStart.trimEnd(),
248022
248108
  ...attrs.map((attr) => sourceText
248023
248109
  .slice(attr.sourceSpan.start.offset, attr.sourceSpan.end.offset)
248024
248110
  .trim()),
248025
248111
  closing,
248026
- ].join('\n');
248112
+ ].join(lineBreak);
248027
248113
  }
248028
- const rule$W = createRule({
248114
+ const rule$X = createRule({
248029
248115
  name: 'attrs-newline',
248030
248116
  rule: {
248031
248117
  create(context) {
@@ -248111,6 +248197,59 @@ const rule$W = createRule({
248111
248197
  },
248112
248198
  });
248113
248199
 
248200
+ const rule$W = createRule({
248201
+ create(context) {
248202
+ const sourceCode = context.sourceCode;
248203
+ return {
248204
+ ClassBody(node) {
248205
+ for (let index = 0; index < node.body.length - 1; index++) {
248206
+ const current = node.body[index];
248207
+ const next = node.body[index + 1];
248208
+ if (!current ||
248209
+ !next ||
248210
+ !isAccessibilityClassMember(current) ||
248211
+ !isAccessibilityClassMember(next)) {
248212
+ continue;
248213
+ }
248214
+ const accessibilityGroupChanged = getAccessibilityGroup(current) !== getAccessibilityGroup(next);
248215
+ if (!accessibilityGroupChanged) {
248216
+ continue;
248217
+ }
248218
+ const betweenText = sourceCode.text.slice(current.range[1], next.range[0]);
248219
+ const missingBlankLine = !hasBlankLineBetweenNodes(betweenText);
248220
+ if (!missingBlankLine) {
248221
+ continue;
248222
+ }
248223
+ const reportTarget = {
248224
+ messageId: 'classAccessibilitySpacing',
248225
+ node: next,
248226
+ };
248227
+ if (hasCommentLikeText(betweenText)) {
248228
+ context.report(reportTarget);
248229
+ continue;
248230
+ }
248231
+ context.report({
248232
+ ...reportTarget,
248233
+ fix: (fixer) => fixer.replaceTextRange([current.range[1], next.range[0]], getSpacingReplacement(sourceCode, betweenText, next.loc.start.line, 1)),
248234
+ });
248235
+ }
248236
+ },
248237
+ };
248238
+ },
248239
+ meta: {
248240
+ docs: {
248241
+ description: 'Require a blank line between adjacent class members when their accessibility group changes',
248242
+ },
248243
+ fixable: 'code',
248244
+ messages: {
248245
+ classAccessibilitySpacing: 'Class members with different accessibility groups should be separated by a blank line',
248246
+ },
248247
+ schema: [],
248248
+ type: 'layout',
248249
+ },
248250
+ name: 'class-accessibility-spacing',
248251
+ });
248252
+
248114
248253
  function isObject(node) {
248115
248254
  return node?.type === dist$3.AST_NODE_TYPES.ObjectExpression;
248116
248255
  }
@@ -248301,6 +248440,7 @@ const rule$U = createRule({
248301
248440
  name: 'element-newline',
248302
248441
  rule: {
248303
248442
  create(context) {
248443
+ const lineBreak = getLineBreak(context.sourceCode.getText());
248304
248444
  return {
248305
248445
  Element(rawNode) {
248306
248446
  const node = rawNode;
@@ -248321,7 +248461,7 @@ const rule$U = createRule({
248321
248461
  fix: (fixer) => fixer.insertTextBeforeRange([
248322
248462
  firstChild.sourceSpan.start.offset,
248323
248463
  firstChild.sourceSpan.start.offset,
248324
- ], '\n'),
248464
+ ], lineBreak),
248325
248465
  loc: sourceSpanToLoc(firstChild.sourceSpan),
248326
248466
  messageId: MESSAGE_ID$i,
248327
248467
  });
@@ -248339,7 +248479,7 @@ const rule$U = createRule({
248339
248479
  fix: (fixer) => fixer.insertTextAfterRange([
248340
248480
  child.sourceSpan.end.offset,
248341
248481
  child.sourceSpan.end.offset,
248342
- ], '\n'),
248482
+ ], lineBreak),
248343
248483
  loc: sourceSpanToLoc(next.sourceSpan),
248344
248484
  messageId: MESSAGE_ID$i,
248345
248485
  });
@@ -248353,7 +248493,7 @@ const rule$U = createRule({
248353
248493
  fix: (fixer) => fixer.insertTextAfterRange([
248354
248494
  lastChild.sourceSpan.end.offset,
248355
248495
  lastChild.sourceSpan.end.offset,
248356
- ], '\n'),
248496
+ ], lineBreak),
248357
248497
  loc: sourceSpanToLoc(lastChild.sourceSpan),
248358
248498
  messageId: MESSAGE_ID$i,
248359
248499
  });
@@ -248644,19 +248784,21 @@ function getAttachedComments(hostObject, properties, sourceCode, comments) {
248644
248784
  return usedComments.size === comments.length ? attached : null;
248645
248785
  }
248646
248786
  function renderFixWithComments(hostObject, sortedProperties, sourceCode, attachedComments) {
248787
+ const lineBreak = getLineBreak(sourceCode.text);
248647
248788
  const objectIndentation = getLineIndentation(sourceCode.text, hostObject.range[0]);
248648
248789
  const propertyIndentation = getPropertyIndentation(hostObject, sortedProperties, sourceCode.text, attachedComments);
248649
- return `{\n${sortedProperties
248790
+ return `{${lineBreak}${sortedProperties
248650
248791
  .map(({ node }, index) => renderPropertyWithComments(node, attachedComments.get(node), sourceCode, propertyIndentation, index === sortedProperties.length - 1))
248651
- .join('\n')}\n${objectIndentation}}`;
248792
+ .join(lineBreak)}${lineBreak}${objectIndentation}}`;
248652
248793
  }
248653
248794
  function renderPropertyWithComments(property, attachedComments, sourceCode, propertyIndentation, isLast) {
248795
+ const lineBreak = getLineBreak(sourceCode.text);
248654
248796
  const lines = attachedComments?.leading.map((comment) => `${propertyIndentation}${sourceCode.text.slice(...comment.range)}`) ?? [];
248655
248797
  const trailingComment = attachedComments?.trailing
248656
248798
  ? ` ${sourceCode.text.slice(...attachedComments.trailing.range)}`
248657
248799
  : '';
248658
248800
  lines.push(`${propertyIndentation}${sourceCode.getText(property)}${isLast ? '' : ','}${trailingComment}`);
248659
- return lines.join('\n');
248801
+ return lines.join(lineBreak);
248660
248802
  }
248661
248803
  function getPropertyIndentation(hostObject, properties, sourceText, attachedComments) {
248662
248804
  for (const { node } of properties) {
@@ -248670,9 +248812,7 @@ function getPropertyIndentation(hostObject, properties, sourceText, attachedComm
248670
248812
  }
248671
248813
  function getLineIndentation(sourceText, offset) {
248672
248814
  let lineStart = offset;
248673
- while (lineStart > 0 &&
248674
- sourceText[lineStart - 1] !== '\n' &&
248675
- sourceText[lineStart - 1] !== '\r') {
248815
+ while (lineStart > 0 && !isLineBreakCharacter(sourceText[lineStart - 1])) {
248676
248816
  lineStart--;
248677
248817
  }
248678
248818
  let indentationEnd = lineStart;
@@ -249382,11 +249522,15 @@ const rule$R = createRule({
249382
249522
  }
249383
249523
  function buildImportRemovalFix(fixer, node) {
249384
249524
  const [start, end] = node.range;
249385
- const lineStart = sourceCode.text.lastIndexOf('\n', start - 1) + 1;
249525
+ const lineStart = getLineStartOffset(sourceCode.text, start);
249386
249526
  const removeStart = /^\s*$/.test(sourceCode.text.slice(lineStart, start))
249387
249527
  ? lineStart
249388
249528
  : start;
249389
- const removeEnd = sourceCode.text[end] === '\n' ? end + 1 : end;
249529
+ const lineEnd = getLineEndOffset(sourceCode.text, end);
249530
+ const isImportLastStatementOnLine = sourceCode.text.slice(end, lineEnd).trim() === '';
249531
+ const removeEnd = isImportLastStatementOnLine
249532
+ ? getNextLineStartOffset(sourceCode.text, end)
249533
+ : end;
249390
249534
  return [fixer.removeRange([removeStart, removeEnd])];
249391
249535
  }
249392
249536
  function buildDuplicateImportFix(fixer, first, rest) {
@@ -249700,7 +249844,7 @@ const rule$R = createRule({
249700
249844
  const relPath = computeRelativeImportPath(context.filename, sourceFilePath);
249701
249845
  newImports.push(`${importPrefix} {${names.join(', ')}} from ${quote}${relPath}${quote}${semi}`);
249702
249846
  }
249703
- return newImports.join('\n');
249847
+ return newImports.join(getLineBreak(sourceCode.text));
249704
249848
  }
249705
249849
  function checkDefaultImport(node) {
249706
249850
  if ((!checkDefaultImports &&
@@ -250050,17 +250194,18 @@ function getDescriptionNode(node) {
250050
250194
  function prependTokenName(text, name) {
250051
250195
  return `${text.slice(0, 1)}[${name}]: ${text.slice(1)}`;
250052
250196
  }
250053
- function getNgDevModeDeclarationFix(program, fixer) {
250197
+ function getNgDevModeDeclarationFix(program, fixer, sourceCode) {
250054
250198
  const lastImport = [...program.body]
250055
250199
  .reverse()
250056
250200
  .find((statement) => statement.type === dist$3.AST_NODE_TYPES.ImportDeclaration);
250201
+ const lineBreak = getLineBreak(sourceCode.text);
250057
250202
  if (lastImport) {
250058
- return fixer.insertTextAfter(lastImport, '\n\ndeclare const ngDevMode: boolean;');
250203
+ return fixer.insertTextAfter(lastImport, `${lineBreak}${lineBreak}declare const ngDevMode: boolean;`);
250059
250204
  }
250060
250205
  const [firstStatement] = program.body;
250061
250206
  return firstStatement
250062
- ? fixer.insertTextBefore(firstStatement, 'declare const ngDevMode: boolean;\n\n')
250063
- : fixer.insertTextBeforeRange([0, 0], 'declare const ngDevMode: boolean;\n');
250207
+ ? fixer.insertTextBefore(firstStatement, `declare const ngDevMode: boolean;${lineBreak}${lineBreak}`)
250208
+ : fixer.insertTextBeforeRange([0, 0], `declare const ngDevMode: boolean;${lineBreak}`);
250064
250209
  }
250065
250210
  const rule$Q = createRule({
250066
250211
  create(context) {
@@ -250090,7 +250235,7 @@ const rule$Q = createRule({
250090
250235
  shouldAddNgDevModeDeclaration &&
250091
250236
  !hasVariableInScope(sourceCode, description, NG_DEV_MODE)) {
250092
250237
  shouldAddNgDevModeDeclaration = false;
250093
- fixes.unshift(getNgDevModeDeclarationFix(program, fixer));
250238
+ fixes.unshift(getNgDevModeDeclarationFix(program, fixer, sourceCode));
250094
250239
  }
250095
250240
  return fixes;
250096
250241
  },
@@ -250708,11 +250853,10 @@ function getSinglePropertyRange(text, property) {
250708
250853
  : [property.range[0], property.range[1]];
250709
250854
  }
250710
250855
  function getLineStart(text, index) {
250711
- return text.lastIndexOf('\n', index - 1) + 1;
250856
+ return getLineStartOffset(text, index);
250712
250857
  }
250713
250858
  function getNextLineStart(text, index) {
250714
- const lineEnd = text.indexOf('\n', index);
250715
- return lineEnd === -1 ? index : lineEnd + 1;
250859
+ return getNextLineStartOffset(text, index);
250716
250860
  }
250717
250861
  function hasCommentsInRange(sourceCode, [start, end]) {
250718
250862
  return sourceCode
@@ -251170,40 +251314,78 @@ const rule$H = createRule({
251170
251314
  rule: config$3,
251171
251315
  });
251172
251316
 
251317
+ function isClassMemberCandidate(node) {
251318
+ return (node.type === dist$4.AST_NODE_TYPES.MethodDefinition ||
251319
+ node.type === dist$4.AST_NODE_TYPES.PropertyDefinition);
251320
+ }
251321
+ function isConstructorMember(node) {
251322
+ return node.type === dist$4.AST_NODE_TYPES.MethodDefinition && node.kind === 'constructor';
251323
+ }
251324
+ function getParameterPropertyName(node) {
251325
+ const { parameter } = node;
251326
+ return parameter.type === dist$4.AST_NODE_TYPES.Identifier
251327
+ ? parameter.name
251328
+ : parameter.left.name;
251329
+ }
251330
+ function getCandidateName(node) {
251331
+ return node.type === dist$4.AST_NODE_TYPES.TSParameterProperty
251332
+ ? (getParameterPropertyName(node) ?? 'member')
251333
+ : (getStaticPropertyName(node.key) ?? 'member');
251334
+ }
251335
+ function getCandidateKind(node) {
251336
+ return node.type === dist$4.AST_NODE_TYPES.MethodDefinition ? node.kind : 'property';
251337
+ }
251338
+ function getFirstNonWhitespaceOffset(text, offset) {
251339
+ let index = offset;
251340
+ while (index < text.length && text[index]?.trim() === '') {
251341
+ index++;
251342
+ }
251343
+ return index;
251344
+ }
251345
+ function getPublicModifierInsertion(options) {
251346
+ const { node, sourceCode } = options;
251347
+ const lastDecoratorIndex = node.decorators.length - 1;
251348
+ const lastDecorator = node.decorators[lastDecoratorIndex];
251349
+ if (lastDecorator) {
251350
+ const [, end] = lastDecorator.range;
251351
+ const memberStart = getFirstNonWhitespaceOffset(sourceCode.text, end);
251352
+ const hasWhitespaceAfterDecorator = memberStart > end;
251353
+ return {
251354
+ range: [memberStart, memberStart],
251355
+ text: hasWhitespaceAfterDecorator ? 'public ' : ' public ',
251356
+ };
251357
+ }
251358
+ return {
251359
+ range: [node.range[0], node.range[0]],
251360
+ text: 'public ',
251361
+ };
251362
+ }
251173
251363
  const rule$G = createRule({
251174
251364
  create(context) {
251365
+ const sourceCode = context.sourceCode;
251175
251366
  const checkImplicitPublic = (node) => {
251176
251367
  const classRef = getEnclosingClass(node);
251177
- if (!classRef ||
251178
- node.kind === 'constructor' ||
251179
- !!node?.accessibility ||
251180
- node.key?.type === dist$4.AST_NODE_TYPES.PrivateIdentifier) {
251368
+ if (!classRef) {
251181
251369
  return;
251182
251370
  }
251183
- const name = node?.key?.name ||
251184
- node?.parameter?.name ||
251185
- (node?.key?.type === 'Identifier' ? node.key.name : 'member');
251186
- let range = node?.parameter?.range ??
251187
- node?.key?.range ??
251188
- node?.range ?? [0, 0];
251189
- if (node.kind === 'set' || node.kind === 'get') {
251190
- const [start, end] = node.key.range;
251191
- range = [start - node.kind.length - 1, end - node.kind.length - 1];
251192
- }
251193
- else if (node.kind === 'method' && node.key?.object?.name === 'Symbol') {
251194
- const [start, end] = range;
251195
- range = [start - 1, end - 1];
251196
- }
251197
- if (node.type === 'PropertyDefinition' && node.decorators?.length > 0) {
251198
- const [, end] = node.decorators[node.decorators.length - 1].range ?? [];
251199
- range = [end + 1, end + 2];
251371
+ const privateNameCannotBePublic = isClassMemberCandidate(node) && isEcmascriptPrivateClassMember(node);
251372
+ if (isConstructorMember(node) ||
251373
+ Boolean(node.accessibility) ||
251374
+ privateNameCannotBePublic) {
251375
+ return;
251200
251376
  }
251201
251377
  context.report({
251202
251378
  data: {
251203
- kind: node.kind || 'property',
251204
- name,
251379
+ kind: getCandidateKind(node),
251380
+ name: getCandidateName(node),
251381
+ },
251382
+ fix: (fixer) => {
251383
+ const { range, text } = getPublicModifierInsertion({
251384
+ node,
251385
+ sourceCode,
251386
+ });
251387
+ return fixer.insertTextBeforeRange(range, text);
251205
251388
  },
251206
- fix: (fixer) => fixer.insertTextBeforeRange(range, ' public '),
251207
251389
  messageId: 'implicitPublic',
251208
251390
  node,
251209
251391
  });
@@ -251322,7 +251504,7 @@ const rule$D = createRule({
251322
251504
  return {
251323
251505
  Program(node) {
251324
251506
  const text = context.sourceCode.getText(node);
251325
- const lines = text.split('\n');
251507
+ const lines = splitLines(text);
251326
251508
  for (const [index, line] of lines.entries()) {
251327
251509
  const trimmed = line.trim();
251328
251510
  if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith(';')) {
@@ -251664,11 +251846,12 @@ const rule$B = createRule({
251664
251846
  return null;
251665
251847
  }
251666
251848
  const indent = getIndentAtOffset(sourceCode.text, insertOffset);
251849
+ const lineBreak = getLineBreak(sourceCode.text);
251667
251850
  const declarations = result.lets
251668
251851
  .map(({ expression, name }, index) => `${index === 0 ? '' : indent}@let ${name} = ${expression};`)
251669
- .join('\n');
251852
+ .join(lineBreak);
251670
251853
  return [
251671
- fixer.insertTextBeforeRange([insertOffset, insertOffset], `${declarations}\n${indent}`),
251854
+ fixer.insertTextBeforeRange([insertOffset, insertOffset], `${declarations}${lineBreak}${indent}`),
251672
251855
  fixer.replaceTextRange([node.sourceSpan.start, node.sourceSpan.end], result.reference),
251673
251856
  ];
251674
251857
  },
@@ -252664,10 +252847,11 @@ const rule$v = createRule({
252664
252847
  fix(fixer) {
252665
252848
  const varName = getCalleeName(firstCall);
252666
252849
  const parentStatement = findParentStatement(node);
252850
+ const lineBreak = getLineBreak(sourceCode.text);
252667
252851
  if (parentStatement) {
252668
252852
  const indent = getStatementIndent$1(parentStatement, sourceCode.text);
252669
252853
  const fixes = [
252670
- fixer.insertTextBefore(parentStatement, `const ${varName} = ${callText};\n\n${indent}`),
252854
+ fixer.insertTextBefore(parentStatement, `const ${varName} = ${callText};${lineBreak}${lineBreak}${indent}`),
252671
252855
  ];
252672
252856
  for (const call of calls) {
252673
252857
  fixes.push(fixer.replaceText(getTargetNode(call), varName));
@@ -252694,7 +252878,7 @@ const rule$v = createRule({
252694
252878
  lastIndex = end;
252695
252879
  }
252696
252880
  replacedBody += bodyText.slice(lastIndex);
252697
- const newBody = `{\n${innerIndent}const ${varName} = ${callText};\n\n${innerIndent}return ${replacedBody};\n${outerIndent}}`;
252881
+ const newBody = `{${lineBreak}${innerIndent}const ${varName} = ${callText};${lineBreak}${lineBreak}${innerIndent}return ${replacedBody};${lineBreak}${outerIndent}}`;
252698
252882
  const bodyRangeStart = arrowBody.range[0];
252699
252883
  const textBeforeBody = sourceCode.text.slice(0, bodyRangeStart);
252700
252884
  const whitespaceBeforeBody = /\s*$/.exec(textBeforeBody)?.[0] ?? '';
@@ -253146,6 +253330,10 @@ const rule$s = createUntrackedRule({
253146
253330
  name: 'no-signal-reads-after-await-in-reactive-context',
253147
253331
  });
253148
253332
 
253333
+ const CARRIAGE_RETURN = String.fromCharCode(13);
253334
+ const LINE_FEED = String.fromCharCode(10);
253335
+ const ESCAPED_CARRIAGE_RETURN = String.fromCharCode(92, 114);
253336
+ const ESCAPED_LINE_FEED = String.fromCharCode(92, 110);
253149
253337
  function collectParts(node) {
253150
253338
  return node.type === dist$4.AST_NODE_TYPES.BinaryExpression && node.operator === '+'
253151
253339
  ? [...collectParts(node.left), ...collectParts(node.right)]
@@ -253165,8 +253353,8 @@ function buildMergedString(parts) {
253165
253353
  const quote = combined.includes("'") && !combined.includes('"') ? '"' : "'";
253166
253354
  const escaped = combined
253167
253355
  .replaceAll('\\', '\\\\')
253168
- .replaceAll('\r', String.raw `\r`)
253169
- .replaceAll('\n', String.raw `\n`)
253356
+ .replaceAll(CARRIAGE_RETURN, ESCAPED_CARRIAGE_RETURN)
253357
+ .replaceAll(LINE_FEED, ESCAPED_LINE_FEED)
253170
253358
  .replaceAll('\t', String.raw `\t`)
253171
253359
  .replaceAll(new RegExp(quote, 'g'), `\\${quote}`);
253172
253360
  return `${quote}${escaped}${quote}`;
@@ -253300,13 +253488,14 @@ function findUntrackedAlias(program) {
253300
253488
  * Builds fixer actions that add `untracked` to an existing `@angular/core` import,
253301
253489
  * or insert a new import declaration when none exists.
253302
253490
  */
253303
- function buildUntrackedImportFixes(program, fixer) {
253491
+ function buildUntrackedImportFixes(program, fixer, sourceCode) {
253304
253492
  const coreImport = findRuntimeAngularCoreImport(program);
253493
+ const lineBreak = getLineBreak(sourceCode.text);
253305
253494
  if (!coreImport) {
253306
253495
  const firstStatement = program.body[0];
253307
253496
  return firstStatement
253308
253497
  ? [
253309
- fixer.insertTextBefore(firstStatement, "import { untracked } from '@angular/core';\n"),
253498
+ fixer.insertTextBefore(firstStatement, `import { untracked } from '@angular/core';${lineBreak}`),
253310
253499
  ]
253311
253500
  : [];
253312
253501
  }
@@ -253321,7 +253510,7 @@ function buildUntrackedImportFixes(program, fixer) {
253321
253510
  return defaultImport
253322
253511
  ? [fixer.insertTextAfter(defaultImport, ', { untracked }')]
253323
253512
  : [
253324
- fixer.insertTextAfter(coreImport, "\nimport { untracked } from '@angular/core';"),
253513
+ fixer.insertTextAfter(coreImport, `${lineBreak}import { untracked } from '@angular/core';`),
253325
253514
  ];
253326
253515
  }
253327
253516
  /**
@@ -253411,10 +253600,9 @@ function dedent(text, extraSpaces) {
253411
253600
  return text;
253412
253601
  }
253413
253602
  const prefix = ' '.repeat(extraSpaces);
253414
- return text
253415
- .split('\n')
253603
+ return splitLines(text)
253416
253604
  .map((line) => (line.startsWith(prefix) ? line.slice(extraSpaces) : line))
253417
- .join('\n');
253605
+ .join(getLineBreak(text));
253418
253606
  }
253419
253607
 
253420
253608
  function isDirectCallOrNewArgument(node) {
@@ -253617,7 +253805,8 @@ function buildReplacement(untrackedCall, parentStatement, sourceCode) {
253617
253805
  const firstStmtColumn = firstStmt.loc.start.column;
253618
253806
  const extra = firstStmtColumn - parentColumn;
253619
253807
  const indented = stmts.map((s) => dedent(sourceCode.getText(s), extra));
253620
- return indented.join(`\n${''.padStart(parentColumn)}`);
253808
+ const lineBreak = getLineBreak(sourceCode.text);
253809
+ return indented.join(`${lineBreak}${''.padStart(parentColumn)}`);
253621
253810
  }
253622
253811
  // Expression body: arrow `() => expr` — just emit `expr;`
253623
253812
  return `${sourceCode.getText(body)};`;
@@ -253728,14 +253917,7 @@ const rule$p = createUntrackedRule({
253728
253917
  const rule$o = createRule({
253729
253918
  create(context, [{ printWidth }]) {
253730
253919
  const sourceCode = context.sourceCode;
253731
- const getLineEndIndex = (lineStartIndex) => {
253732
- const text = sourceCode.text;
253733
- const newLineIndex = text.indexOf('\n', lineStartIndex);
253734
- const rawEndIndex = newLineIndex === -1 ? text.length : newLineIndex;
253735
- return rawEndIndex > lineStartIndex && text[rawEndIndex - 1] === '\r'
253736
- ? rawEndIndex - 1
253737
- : rawEndIndex;
253738
- };
253920
+ const getLineEndIndex = (lineStartIndex) => getLineEndOffset(sourceCode.text, lineStartIndex);
253739
253921
  const hasAnyCommentsInside = (node) => sourceCode.getCommentsInside(node).length > 0;
253740
253922
  const isTemplateLikeExpression = (expression) => expression.type === dist$3.AST_NODE_TYPES.TemplateLiteral ||
253741
253923
  expression.type === dist$3.AST_NODE_TYPES.TaggedTemplateExpression;
@@ -253847,7 +254029,7 @@ const rule$o = createRule({
253847
254029
  if (inner.type === dist$3.AST_NODE_TYPES.ObjectExpression &&
253848
254030
  canInlineObjectExpression(inner)) {
253849
254031
  const innerText = sourceCode.getText(inner);
253850
- return innerText.includes('\n');
254032
+ return hasLineBreak(innerText);
253851
254033
  }
253852
254034
  }
253853
254035
  if (value.type === dist$3.AST_NODE_TYPES.ArrowFunctionExpression) {
@@ -253859,7 +254041,7 @@ const rule$o = createRule({
253859
254041
  if (inner.type === dist$3.AST_NODE_TYPES.ObjectExpression &&
253860
254042
  canInlineObjectExpression(inner)) {
253861
254043
  const innerText = sourceCode.getText(inner);
253862
- return innerText.includes('\n');
254044
+ return hasLineBreak(innerText);
253863
254045
  }
253864
254046
  }
253865
254047
  }
@@ -253868,7 +254050,7 @@ const rule$o = createRule({
253868
254050
  if (bodyExpr.type === dist$3.AST_NODE_TYPES.ObjectExpression &&
253869
254051
  canInlineObjectExpression(bodyExpr)) {
253870
254052
  const innerText = sourceCode.getText(bodyExpr);
253871
- return innerText.includes('\n');
254053
+ return hasLineBreak(innerText);
253872
254054
  }
253873
254055
  }
253874
254056
  }
@@ -253932,7 +254114,7 @@ const rule$o = createRule({
253932
254114
  ObjectExpression(node) {
253933
254115
  const originalText = sourceCode.getText(node);
253934
254116
  if (!canInlineObjectExpression(node) ||
253935
- !originalText.includes('\n') ||
254117
+ !hasLineBreak(originalText) ||
253936
254118
  hasPendingInnerInlineCandidate(node) ||
253937
254119
  hasArrowReturningMultiPropObject(node)) {
253938
254120
  return;
@@ -254306,35 +254488,37 @@ function renderConditionalReturn(ifStatement, consequentExpression, alternateExp
254306
254488
  return inlineReturn;
254307
254489
  }
254308
254490
  const branchIndent = `${indent} `;
254309
- return `return ${test}\n${branchIndent}? ${consequent}\n${branchIndent}: ${alternate};`;
254491
+ const lineBreak = getLineBreak(sourceCode.text);
254492
+ return `return ${test}${lineBreak}${branchIndent}? ${consequent}${lineBreak}${branchIndent}: ${alternate};`;
254310
254493
  }
254311
254494
  function renderBooleanTestReturn(ifStatement, sourceCode, strategy) {
254312
254495
  const test = sourceCode.getText(ifStatement.test);
254496
+ const lineBreak = getLineBreak(sourceCode.text);
254313
254497
  if (strategy === 'negate') {
254314
- if (!test.includes('\n')) {
254498
+ if (!hasLineBreak(test)) {
254315
254499
  const renderedTest = needsParenthesesInBooleanCoercion(ifStatement.test)
254316
254500
  ? `(${test})`
254317
254501
  : test;
254318
254502
  return `return !${renderedTest};`;
254319
254503
  }
254320
254504
  const indent = getStatementIndent(ifStatement, sourceCode);
254321
- return `return !(\n${indent} ${test}\n${indent});`;
254505
+ return `return !(${lineBreak}${indent} ${test}${lineBreak}${indent});`;
254322
254506
  }
254323
254507
  if (strategy === 'coerce') {
254324
- if (!test.includes('\n')) {
254508
+ if (!hasLineBreak(test)) {
254325
254509
  const renderedTest = needsParenthesesInBooleanCoercion(ifStatement.test)
254326
254510
  ? `(${test})`
254327
254511
  : test;
254328
254512
  return `return !!${renderedTest};`;
254329
254513
  }
254330
254514
  const indent = getStatementIndent(ifStatement, sourceCode);
254331
- return `return !!(\n${indent} ${test}\n${indent});`;
254515
+ return `return !!(${lineBreak}${indent} ${test}${lineBreak}${indent});`;
254332
254516
  }
254333
- if (!test.includes('\n')) {
254517
+ if (!hasLineBreak(test)) {
254334
254518
  return `return ${test};`;
254335
254519
  }
254336
254520
  const indent = getStatementIndent(ifStatement, sourceCode);
254337
- return `return (\n${indent} ${test}\n${indent});`;
254521
+ return `return (${lineBreak}${indent} ${test}${lineBreak}${indent});`;
254338
254522
  }
254339
254523
  const rule$m = createRule({
254340
254524
  create(context) {
@@ -254912,7 +255096,7 @@ const rule$i = createUntrackedRule({
254912
255096
  ? (fixer) => [fixer.replaceText(read, wrapped)]
254913
255097
  : (fixer) => [
254914
255098
  fixer.replaceText(read, wrapped),
254915
- ...buildUntrackedImportFixes(program, fixer),
255099
+ ...buildUntrackedImportFixes(program, fixer, sourceCode),
254916
255100
  ];
254917
255101
  }
254918
255102
  return {
@@ -255051,8 +255235,7 @@ const rule$g = createRule({
255051
255235
  let openQuoteOffset = valueSpan.start.offset - 1;
255052
255236
  while (openQuoteOffset >= 0 &&
255053
255237
  (sourceText[openQuoteOffset] === ' ' ||
255054
- sourceText[openQuoteOffset] === '\n' ||
255055
- sourceText[openQuoteOffset] === '\r' ||
255238
+ isLineBreakCharacter(sourceText[openQuoteOffset]) ||
255056
255239
  sourceText[openQuoteOffset] === '\t')) {
255057
255240
  openQuoteOffset--;
255058
255241
  }
@@ -255063,8 +255246,7 @@ const rule$g = createRule({
255063
255246
  if (isQuotedAttribute) {
255064
255247
  while (closeQuoteOffset < sourceText.length &&
255065
255248
  (sourceText[closeQuoteOffset] === ' ' ||
255066
- sourceText[closeQuoteOffset] === '\n' ||
255067
- sourceText[closeQuoteOffset] === '\r' ||
255249
+ isLineBreakCharacter(sourceText[closeQuoteOffset]) ||
255068
255250
  sourceText[closeQuoteOffset] === '\t')) {
255069
255251
  closeQuoteOffset++;
255070
255252
  }
@@ -255121,6 +255303,7 @@ const rule$f = createRule({
255121
255303
  rule: {
255122
255304
  create(context) {
255123
255305
  const sourceText = context.sourceCode.getText();
255306
+ const lineBreak = getLineBreak(sourceText);
255124
255307
  let reported = false;
255125
255308
  return {
255126
255309
  Element(rawNode) {
@@ -255132,7 +255315,7 @@ const rule$f = createRule({
255132
255315
  }
255133
255316
  reported = true;
255134
255317
  context.report({
255135
- fix: (fixer) => fixer.insertTextBeforeRange([0, 0], '<!DOCTYPE html>\n'),
255318
+ fix: (fixer) => fixer.insertTextBeforeRange([0, 0], `<!DOCTYPE html>${lineBreak}`),
255136
255319
  loc: sourceSpanToLoc(node.startSourceSpan),
255137
255320
  messageId: MESSAGE_ID$6,
255138
255321
  });
@@ -255526,18 +255709,6 @@ const rule$a = createRule({
255526
255709
  name: 'short-tui-imports',
255527
255710
  });
255528
255711
 
255529
- function isFieldLikeMember(member) {
255530
- return (member.type === dist$4.AST_NODE_TYPES.PropertyDefinition ||
255531
- member.type === dist$4.AST_NODE_TYPES.TSAbstractPropertyDefinition);
255532
- }
255533
- function isAccessorMember(member) {
255534
- return (member.type === dist$4.AST_NODE_TYPES.MethodDefinition &&
255535
- (member.kind === 'get' || member.kind === 'set'));
255536
- }
255537
- function isRelevantSpacingClassMember(member) {
255538
- return isFieldLikeMember(member) || isAccessorMember(member);
255539
- }
255540
-
255541
255712
  const rule$9 = createRule({
255542
255713
  create(context) {
255543
255714
  const sourceCode = context.sourceCode;
@@ -256766,7 +256937,7 @@ function buildRewrittenImports({ baseImportPath, node, state, symbolToEntryPoint
256766
256937
  if (remainingImportStatement) {
256767
256938
  importStatements.push(remainingImportStatement);
256768
256939
  }
256769
- return importStatements.join('\n');
256940
+ return importStatements.join(getLineBreak(state.sourceCode.text));
256770
256941
  }
256771
256942
  function buildNamedImportStatement({ importKind, importPath, specifiers, state, }) {
256772
256943
  const importKeyword = importKind === 'type' ? 'import type' : 'import';
@@ -256904,8 +257075,9 @@ const plugin = {
256904
257075
  },
256905
257076
  rules: {
256906
257077
  'array-as-const': rule$5,
256907
- 'at-compat': rule$X,
256908
- 'attrs-newline': rule$W,
257078
+ 'at-compat': rule$Y,
257079
+ 'attrs-newline': rule$X,
257080
+ 'class-accessibility-spacing': rule$W,
256909
257081
  'class-property-naming': rule$4,
256910
257082
  'decorator-key-sort': rule$V,
256911
257083
  'element-newline': rule$U,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ui/eslint-plugin-experience-next",
3
- "version": "0.526.0",
3
+ "version": "0.528.0",
4
4
  "description": "An ESLint plugin to enforce a consistent code styles across taiga-ui projects",
5
5
  "homepage": "https://github.com/taiga-family/toolkit#readme",
6
6
  "bugs": {
@@ -54,10 +54,10 @@
54
54
  "eslint-plugin-unicorn": "64.0.0",
55
55
  "eslint-plugin-unused-imports": "4.4.1",
56
56
  "globals": "17.6.0",
57
- "typescript-eslint": "8.59.1"
57
+ "typescript-eslint": "8.59.2"
58
58
  },
59
59
  "devDependencies": {
60
- "@typescript-eslint/rule-tester": "8.59.1"
60
+ "@typescript-eslint/rule-tester": "8.59.2"
61
61
  },
62
62
  "peerDependencies": {
63
63
  "eslint": "^9.39.4"
@@ -0,0 +1,4 @@
1
+ export declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"classAccessibilitySpacing", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
2
+ name: string;
3
+ };
4
+ export default rule;
@@ -1,4 +1,5 @@
1
- export declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"invalid-injection-token-description", readonly unknown[], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
1
+ import { type TSESLint } from '@typescript-eslint/utils';
2
+ export declare const rule: TSESLint.RuleModule<"invalid-injection-token-description", readonly unknown[], unknown, TSESLint.RuleListener> & {
2
3
  name: string;
3
4
  };
4
5
  export default rule;
@@ -1,4 +1,5 @@
1
- export declare const rule: import("@typescript-eslint/utils/ts-eslint").RuleModule<"implicitPublic", readonly unknown[], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
1
+ import { type TSESLint } from '@typescript-eslint/utils';
2
+ export declare const rule: TSESLint.RuleModule<"implicitPublic", readonly unknown[], unknown, TSESLint.RuleListener> & {
2
3
  name: string;
3
4
  };
4
5
  export default rule;
@@ -6,7 +6,7 @@ export declare function findUntrackedAlias(program: TSESTree.Program): string |
6
6
  * Builds fixer actions that add `untracked` to an existing `@angular/core` import,
7
7
  * or insert a new import declaration when none exists.
8
8
  */
9
- export declare function buildUntrackedImportFixes(program: TSESTree.Program, fixer: RuleFixer): Array<ReturnType<RuleFixer['insertTextBefore']>>;
9
+ export declare function buildUntrackedImportFixes(program: TSESTree.Program, fixer: RuleFixer, sourceCode: SourceCode): Array<ReturnType<RuleFixer['insertTextBefore']>>;
10
10
  /**
11
11
  * Removes the `untracked` import specifier from `@angular/core`.
12
12
  * When it is the last specifier, removes the entire declaration.
@@ -1,6 +1,14 @@
1
1
  import { type TSESTree } from '@typescript-eslint/utils';
2
2
  export { getLeadingIndentation, getLineBreak, getLineStartOffset, hasBlankLine, hasCommentLikeText, isSingleLineNode, } from './spacing';
3
3
  export type FieldLikeMember = TSESTree.PropertyDefinition | TSESTree.TSAbstractPropertyDefinition;
4
+ export type AccessibilityGroup = 'private' | 'protected' | 'public';
5
+ export type AccessibilityClassMember = TSESTree.AccessorProperty | TSESTree.MethodDefinition | TSESTree.PropertyDefinition | TSESTree.TSAbstractAccessorProperty | TSESTree.TSAbstractMethodDefinition | TSESTree.TSAbstractPropertyDefinition | TSESTree.TSIndexSignature;
6
+ export type EcmascriptPrivateClassMember = Exclude<AccessibilityClassMember, TSESTree.TSIndexSignature> & {
7
+ readonly key: TSESTree.PrivateIdentifier;
8
+ };
4
9
  export declare function isFieldLikeMember(member: TSESTree.ClassElement): member is FieldLikeMember;
5
10
  export declare function isAccessorMember(member: TSESTree.ClassElement): member is TSESTree.MethodDefinition;
6
11
  export declare function isRelevantSpacingClassMember(member: TSESTree.ClassElement): member is FieldLikeMember | TSESTree.MethodDefinition;
12
+ export declare function isAccessibilityClassMember(member: TSESTree.ClassElement): member is AccessibilityClassMember;
13
+ export declare function isEcmascriptPrivateClassMember(member: TSESTree.ClassElement): member is EcmascriptPrivateClassMember;
14
+ export declare function getAccessibilityGroup(member: AccessibilityClassMember): AccessibilityGroup;
@@ -1,9 +1,15 @@
1
1
  import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
2
2
  export declare function isSingleLineNode(node: TSESTree.Node): boolean;
3
+ export declare function isLineBreakCharacter(char: string | undefined): boolean;
3
4
  export declare function hasCommentLikeText(text: string): boolean;
4
5
  export declare function hasBlankLine(text: string): boolean;
6
+ export declare function hasBlankLineBetweenNodes(text: string): boolean;
5
7
  export declare function getLineBreak(text: string): string;
8
+ export declare function hasLineBreak(text: string): boolean;
6
9
  export declare function getLeadingIndentation(text: string): string;
7
10
  export declare function getLineStartOffset(text: string, offset: number): number;
11
+ export declare function getLineEndOffset(text: string, lineStartOffset: number): number;
12
+ export declare function getNextLineStartOffset(text: string, offset: number): number;
13
+ export declare function splitLines(text: string): string[];
8
14
  export declare function getIndentAtOffset(text: string, offset: number): string;
9
15
  export declare function getSpacingReplacement(sourceCode: Readonly<TSESLint.SourceCode>, betweenText: string, nextLine: number, blankLineCount: number): string;