@taiga-ui/eslint-plugin-experience-next 0.538.0 → 0.540.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
@@ -104,6 +104,7 @@ from third-party plugins. The exact severities and file globs live in
104
104
  | [no-playwright-empty-fill](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-playwright-empty-fill.md) | Enforce `clear()` over `fill('')` in Playwright tests | ✅ | 🔧 | |
105
105
  | [no-project-as-in-ng-template](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-project-as-in-ng-template.md) | `ngProjectAs` has no effect inside `<ng-template>` or dynamic outlets | ✅ | | |
106
106
  | [no-restricted-attr-values](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-restricted-attr-values.md) | Disallow configured attribute values in Angular templates | | | |
107
+ | [no-redundant-fs-encoding](https://github.com/taiga-family/toolkit/tree/main/projects/eslint-plugin-experience-next/docs/no-redundant-fs-encoding.md) | Remove redundant default utf8 encoding from Node.js file write calls | ✅ | 🔧 | |
107
108
  | [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 | ✅ | 🔧 | |
108
109
  | [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 | ✅ | 🔧 | |
109
110
  | [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 | ✅ | | |
@@ -0,0 +1 @@
1
+ export declare function getDefaultParserOptions(): Record<string, unknown>;
package/index.d.ts CHANGED
@@ -123,6 +123,9 @@ declare const plugin: {
123
123
  'no-project-as-in-ng-template': import("eslint").Rule.RuleModule & {
124
124
  name: string;
125
125
  };
126
+ 'no-redundant-fs-encoding': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noRedundantFsEncoding", [], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
127
+ name: string;
128
+ };
126
129
  'no-redundant-type-annotation': import("@typescript-eslint/utils/ts-eslint").RuleModule<"redundantTypeAnnotation", [({
127
130
  ignoreTupleContextualTyping?: boolean;
128
131
  } | undefined)?], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener> & {
package/index.esm.js CHANGED
@@ -599,9 +599,33 @@ var npmrcParser = /*#__PURE__*/Object.freeze({
599
599
  });
600
600
 
601
601
  const require$2 = createRequire(import.meta.url);
602
+ function projectJsonExist(filename) {
603
+ try {
604
+ const path = require$2('node:path').resolve(filename);
605
+ return require$2('node:fs').existsSync(path) ? path : '';
606
+ }
607
+ catch {
608
+ return '';
609
+ }
610
+ }
611
+
612
+ function getDefaultParserOptions() {
613
+ const tsconfig = projectJsonExist('tsconfig.eslint.json');
614
+ if (tsconfig) {
615
+ return { project: [tsconfig] };
616
+ }
617
+ return projectJsonExist('tsconfig.json')
618
+ ? {
619
+ projectService: true,
620
+ tsconfigRootDir: process.cwd(),
621
+ }
622
+ : { projectService: false };
623
+ }
624
+
625
+ const require$1 = createRequire(import.meta.url);
602
626
  function getAngularVersion() {
603
627
  try {
604
- const { major } = require$2('@angular/cli').VERSION;
628
+ const { major } = require$1('@angular/cli').VERSION;
605
629
  return Number.parseInt(major, 10);
606
630
  }
607
631
  catch {
@@ -618,25 +642,7 @@ const modernAngularRules = {
618
642
  templateLiteral: 19,
619
643
  };
620
644
 
621
- const require$1 = createRequire(import.meta.url);
622
- function projectJsonExist(filename) {
623
- try {
624
- const path = require$1('node:path').resolve(filename);
625
- return require$1('node:fs').existsSync(path) ? path : '';
626
- }
627
- catch {
628
- return '';
629
- }
630
- }
631
-
632
645
  const ALL_TS_JS_FILES = ['**/*.{js,mjs,ts,cjs,tsx,jsx}'];
633
- const tsconfig = projectJsonExist('tsconfig.eslint.json');
634
- const parserOptions$1 = tsconfig
635
- ? { project: [tsconfig] }
636
- : {
637
- projectService: true,
638
- tsconfigRootDir: process.cwd(),
639
- };
640
646
  var recommended = defineConfig([
641
647
  progress.configs['recommended-ci'],
642
648
  {
@@ -698,7 +704,7 @@ var recommended = defineConfig([
698
704
  errorOnUnknownASTType: true,
699
705
  sourceType: 'module',
700
706
  warnOnUnsupportedTypeScriptVersion: false,
701
- ...parserOptions$1,
707
+ ...getDefaultParserOptions(),
702
708
  },
703
709
  },
704
710
  settings: {
@@ -931,6 +937,7 @@ var recommended = defineConfig([
931
937
  '@typescript-eslint/prefer-destructuring': 'off',
932
938
  '@typescript-eslint/prefer-find': 'error',
933
939
  '@typescript-eslint/prefer-for-of': 'error',
940
+ '@typescript-eslint/prefer-function-type': 'off',
934
941
  '@typescript-eslint/prefer-includes': 'error',
935
942
  '@typescript-eslint/prefer-nullish-coalescing': 'off', // TODO: ['error', {ignorePrimitives: {boolean: true, number: true, string: true}}]
936
943
  '@typescript-eslint/prefer-optional-chain': 'error',
@@ -1319,6 +1326,7 @@ var recommended = defineConfig([
1319
1326
  '@taiga-ui/experience-next/no-implicit-public': 'error',
1320
1327
  '@taiga-ui/experience-next/no-import-assertions': 'error',
1321
1328
  '@taiga-ui/experience-next/no-infinite-loop': 'error',
1329
+ '@taiga-ui/experience-next/no-redundant-fs-encoding': 'error',
1322
1330
  '@taiga-ui/experience-next/no-redundant-type-annotation': 'error',
1323
1331
  '@taiga-ui/experience-next/no-repeated-signal-in-conditional': 'error',
1324
1332
  '@taiga-ui/experience-next/no-side-effects-in-computed': 'error',
@@ -15661,7 +15669,7 @@ function getLastIndexFix(fixer, sourceCode, node, call) {
15661
15669
  }
15662
15670
  return null;
15663
15671
  }
15664
- const rule$Y = createRule({
15672
+ const rule$Z = createRule({
15665
15673
  create(context) {
15666
15674
  const typeAwareContext = getTypeAwareRuleContext(context);
15667
15675
  const compilerOptions = typeAwareContext.tsProgram.getCompilerOptions();
@@ -47467,7 +47475,7 @@ function buildMultilineStartTag(node, sourceText) {
47467
47475
  closing,
47468
47476
  ].join(lineBreak);
47469
47477
  }
47470
- const rule$X = createRule({
47478
+ const rule$Y = createRule({
47471
47479
  name: 'attrs-newline',
47472
47480
  rule: {
47473
47481
  create(context) {
@@ -47553,7 +47561,7 @@ const rule$X = createRule({
47553
47561
  },
47554
47562
  });
47555
47563
 
47556
- const rule$W = createRule({
47564
+ const rule$X = createRule({
47557
47565
  create(context) {
47558
47566
  const sourceCode = context.sourceCode;
47559
47567
  return {
@@ -47656,7 +47664,7 @@ function sameOrder(a, b) {
47656
47664
  return a.length === b.length && a.every((value, index) => value === b[index]);
47657
47665
  }
47658
47666
 
47659
- const rule$V = createRule({
47667
+ const rule$W = createRule({
47660
47668
  create(context, [order]) {
47661
47669
  const decorators = new Set(Object.keys(order));
47662
47670
  return {
@@ -47792,7 +47800,7 @@ function getNodeLabel(node) {
47792
47800
  }
47793
47801
  return node instanceof dist.TmplAstBoundText ? 'binding' : 'text';
47794
47802
  }
47795
- const rule$U = createRule({
47803
+ const rule$V = createRule({
47796
47804
  name: 'element-newline',
47797
47805
  rule: {
47798
47806
  create(context) {
@@ -47932,7 +47940,7 @@ const PRESETS = {
47932
47940
  $VUE: ['$CLASS', '$ID', '$VUE_ATTRIBUTE'],
47933
47941
  $VUE_ATTRIBUTE: /^v-/,
47934
47942
  };
47935
- const rule$T = createRule({
47943
+ const rule$U = createRule({
47936
47944
  create(context, [options]) {
47937
47945
  const sourceCode = context.sourceCode;
47938
47946
  const settings = {
@@ -48263,7 +48271,7 @@ const config$4 = {
48263
48271
  type: 'suggestion',
48264
48272
  },
48265
48273
  };
48266
- const rule$S = createRule({
48274
+ const rule$T = createRule({
48267
48275
  name: 'html-logical-properties',
48268
48276
  rule: config$4,
48269
48277
  });
@@ -48841,7 +48849,7 @@ function isImportUsedOnlyAsAngularDiFirstArg(node, sourceCode) {
48841
48849
  }
48842
48850
  return hasSafeRuntimeUsage;
48843
48851
  }
48844
- const rule$R = createRule({
48852
+ const rule$S = createRule({
48845
48853
  create(context) {
48846
48854
  const { checker, esTreeNodeToTSNodeMap, sourceCode, tsProgram } = getTypeAwareRuleContext(context);
48847
48855
  const checkCycles = context.options[0]?.checkCycles ?? true;
@@ -49563,7 +49571,7 @@ function getNgDevModeDeclarationFix(program, fixer, sourceCode) {
49563
49571
  ? fixer.insertTextBefore(firstStatement, `declare const ngDevMode: boolean;${lineBreak}${lineBreak}`)
49564
49572
  : fixer.insertTextBeforeRange([0, 0], `declare const ngDevMode: boolean;${lineBreak}`);
49565
49573
  }
49566
- const rule$Q = createRule({
49574
+ const rule$R = createRule({
49567
49575
  create(context) {
49568
49576
  const { sourceCode } = context;
49569
49577
  const program = sourceCode.ast;
@@ -49612,7 +49620,7 @@ const rule$Q = createRule({
49612
49620
  name: 'injection-token-description',
49613
49621
  });
49614
49622
 
49615
- const rule$P = createRule({
49623
+ const rule$Q = createRule({
49616
49624
  create(context) {
49617
49625
  const { sourceCode } = context;
49618
49626
  const namespaceImports = new Map();
@@ -49707,7 +49715,7 @@ const DEFAULT_OPTIONS = {
49707
49715
  importDeclaration: '^@taiga-ui*',
49708
49716
  projectName: String.raw `(?<=^@taiga-ui/)([-\w]+)`,
49709
49717
  };
49710
- const rule$O = createRule({
49718
+ const rule$P = createRule({
49711
49719
  create(context) {
49712
49720
  const { currentProject, deepImport, ignoreImports, importDeclaration, projectName, } = { ...DEFAULT_OPTIONS, ...context.options[0] };
49713
49721
  const hasNonCodeExtension = (source) => {
@@ -49799,7 +49807,7 @@ const nearestFileUpCache = new Map();
49799
49807
  const markerCache = new Map();
49800
49808
  const indexFileCache = new Map();
49801
49809
  const indexExportsCache = new Map();
49802
- const rule$N = createRule({
49810
+ const rule$O = createRule({
49803
49811
  create(context) {
49804
49812
  const parserServices = dist$4.ESLintUtils.getParserServices(context);
49805
49813
  const program = parserServices.program;
@@ -49993,13 +50001,13 @@ const noDuplicateAttributesRule = angular.templatePlugin.rules?.['no-duplicate-a
49993
50001
  if (!noDuplicateAttributesRule) {
49994
50002
  throw new Error('angular-eslint template rule "no-duplicate-attributes" is not available');
49995
50003
  }
49996
- const rule$M = createRule({
50004
+ const rule$N = createRule({
49997
50005
  name: 'no-duplicate-attrs',
49998
50006
  rule: noDuplicateAttributesRule,
49999
50007
  });
50000
50008
 
50001
50009
  const MESSAGE_ID$e = 'duplicateId';
50002
- const rule$L = createRule({
50010
+ const rule$M = createRule({
50003
50011
  name: 'no-duplicate-id',
50004
50012
  rule: {
50005
50013
  create(context) {
@@ -50057,7 +50065,7 @@ function getTrackingKey(node) {
50057
50065
  ? 'link[rel=canonical]'
50058
50066
  : null;
50059
50067
  }
50060
- const rule$K = createRule({
50068
+ const rule$L = createRule({
50061
50069
  name: 'no-duplicate-in-head',
50062
50070
  rule: {
50063
50071
  create(context) {
@@ -50113,7 +50121,7 @@ const rule$K = createRule({
50113
50121
  });
50114
50122
 
50115
50123
  const COMPONENT_DECORATORS = new Set(['Component']);
50116
- const rule$J = createRule({
50124
+ const rule$K = createRule({
50117
50125
  create(context) {
50118
50126
  const { sourceCode } = context;
50119
50127
  return {
@@ -50592,7 +50600,7 @@ const ANGULAR_SIGNALS_UNTRACKED_GUIDE_URL = 'https://angular.dev/guide/signals#r
50592
50600
  const ANGULAR_SIGNALS_ASYNC_GUIDE_URL = 'https://angular.dev/guide/signals#reactive-context-and-async-operations';
50593
50601
  const createUntrackedRule = createRule;
50594
50602
 
50595
- const rule$I = createUntrackedRule({
50603
+ const rule$J = createUntrackedRule({
50596
50604
  create(context) {
50597
50605
  const { checker, esTreeNodeToTSNodeMap, program } = getTypeAwareRuleContext(context);
50598
50606
  const signalNodeMap = esTreeNodeToTSNodeMap;
@@ -50665,7 +50673,7 @@ const config$3 = {
50665
50673
  type: 'problem',
50666
50674
  },
50667
50675
  };
50668
- const rule$H = createRule({
50676
+ const rule$I = createRule({
50669
50677
  name: 'no-href-with-router-link',
50670
50678
  rule: config$3,
50671
50679
  });
@@ -50716,7 +50724,7 @@ function getPublicModifierInsertion(options) {
50716
50724
  text: 'public ',
50717
50725
  };
50718
50726
  }
50719
- const rule$G = createRule({
50727
+ const rule$H = createRule({
50720
50728
  create(context) {
50721
50729
  const sourceCode = context.sourceCode;
50722
50730
  const checkImplicitPublic = (node) => {
@@ -50770,7 +50778,7 @@ const rule$G = createRule({
50770
50778
  name: 'no-implicit-public',
50771
50779
  });
50772
50780
 
50773
- const rule$F = createRule({
50781
+ const rule$G = createRule({
50774
50782
  create(context) {
50775
50783
  const { sourceCode } = context;
50776
50784
  return {
@@ -50810,7 +50818,7 @@ function isInfiniteLoopLiteral(node) {
50810
50818
  function isInfiniteLoopTest(test) {
50811
50819
  return test == null || isInfiniteLoopLiteral(test);
50812
50820
  }
50813
- const rule$E = createRule({
50821
+ const rule$F = createRule({
50814
50822
  create(context) {
50815
50823
  return {
50816
50824
  DoWhileStatement(node) {
@@ -50855,7 +50863,7 @@ const rule$E = createRule({
50855
50863
  });
50856
50864
 
50857
50865
  const LEGACY_PEER_DEPS_PATTERN = /^legacy-peer-deps\s*=\s*true$/i;
50858
- const rule$D = createRule({
50866
+ const rule$E = createRule({
50859
50867
  create(context) {
50860
50868
  return {
50861
50869
  Program(node) {
@@ -50947,7 +50955,7 @@ function getAvailableLabelParent(stack, node, labelsWithControl) {
50947
50955
  ? parent
50948
50956
  : null;
50949
50957
  }
50950
- const rule$C = createRule({
50958
+ const rule$D = createRule({
50951
50959
  name: 'no-nested-interactive',
50952
50960
  rule: {
50953
50961
  create(context) {
@@ -51168,7 +51176,7 @@ function createLetFixes(node, baseName, unavailableNames, text) {
51168
51176
  reference: name,
51169
51177
  };
51170
51178
  }
51171
- const rule$B = createRule({
51179
+ const rule$C = createRule({
51172
51180
  name: 'no-nested-ternary-in-template',
51173
51181
  rule: {
51174
51182
  create(context) {
@@ -51706,7 +51714,7 @@ const OBSOLETE_HTML_ATTRS = {
51706
51714
  };
51707
51715
 
51708
51716
  const MESSAGE_ID$9 = 'obsolete';
51709
- const rule$A = createRule({
51717
+ const rule$B = createRule({
51710
51718
  name: 'no-obsolete-attrs',
51711
51719
  rule: {
51712
51720
  create(context) {
@@ -51784,7 +51792,7 @@ const OBSOLETE_HTML_TAGS = new Set([
51784
51792
  ]);
51785
51793
 
51786
51794
  const MESSAGE_ID$8 = 'unexpected';
51787
- const rule$z = createRule({
51795
+ const rule$A = createRule({
51788
51796
  name: 'no-obsolete-tags',
51789
51797
  rule: {
51790
51798
  create(context) {
@@ -51811,7 +51819,7 @@ const rule$z = createRule({
51811
51819
  },
51812
51820
  });
51813
51821
 
51814
- const rule$y = createRule({
51822
+ const rule$z = createRule({
51815
51823
  create(context) {
51816
51824
  const { checker, esTreeNodeToTSNodeMap, sourceCode } = getTypeAwareRuleContext(context);
51817
51825
  return {
@@ -51955,11 +51963,175 @@ const config$2 = {
51955
51963
  type: 'problem',
51956
51964
  },
51957
51965
  };
51958
- const rule$x = createRule({
51966
+ const rule$y = createRule({
51959
51967
  name: 'no-project-as-in-ng-template',
51960
51968
  rule: config$2,
51961
51969
  });
51962
51970
 
51971
+ function getCommaAfter(sourceCode, node) {
51972
+ const token = sourceCode.getTokenAfter(node);
51973
+ return token?.value === ',' ? token : null;
51974
+ }
51975
+ function getCommaBefore(sourceCode, node) {
51976
+ const token = sourceCode.getTokenBefore(node);
51977
+ return token?.value === ',' ? token : null;
51978
+ }
51979
+ function removeStandaloneLine(sourceCode, fixer, node) {
51980
+ const lineStart = getLineStartOffset(sourceCode.text, node.range[0]);
51981
+ const nextLineStart = getNextLineStartOffset(sourceCode.text, node.range[1]);
51982
+ return fixer.removeRange([lineStart, nextLineStart]);
51983
+ }
51984
+ function isStandaloneListItem(node, previousNode, nextNode) {
51985
+ const startsOwnLine = previousNode === null || previousNode.loc.end.line < node.loc.start.line;
51986
+ const endsOwnLine = nextNode === null || nextNode.loc.start.line > node.loc.end.line;
51987
+ return startsOwnLine && endsOwnLine;
51988
+ }
51989
+ function removeCommaSeparatedNode(sourceCode, fixer, node, previousNode, nextNode) {
51990
+ if (isStandaloneListItem(node, previousNode, nextNode)) {
51991
+ return removeStandaloneLine(sourceCode, fixer, node);
51992
+ }
51993
+ const commaAfter = getCommaAfter(sourceCode, node);
51994
+ if (nextNode && commaAfter) {
51995
+ return fixer.removeRange([node.range[0], nextNode.range[0]]);
51996
+ }
51997
+ const commaBefore = getCommaBefore(sourceCode, node);
51998
+ if (commaBefore) {
51999
+ return fixer.removeRange([
52000
+ commaBefore.range[0],
52001
+ commaAfter?.range[1] ?? node.range[1],
52002
+ ]);
52003
+ }
52004
+ return commaAfter ? fixer.removeRange([node.range[0], commaAfter.range[1]]) : null;
52005
+ }
52006
+
52007
+ const WRITE_METHODS = new Set([
52008
+ 'appendFile',
52009
+ 'appendFileSync',
52010
+ 'writeFile',
52011
+ 'writeFileSync',
52012
+ ]);
52013
+ const FS_NAMESPACE_NAMES = new Set(['fs', 'fsPromises']);
52014
+ function isWriteMethod(name) {
52015
+ return name !== null && WRITE_METHODS.has(name);
52016
+ }
52017
+ function isFsNamespaceObject(node) {
52018
+ if (node.type === dist$4.AST_NODE_TYPES.Identifier) {
52019
+ return FS_NAMESPACE_NAMES.has(node.name);
52020
+ }
52021
+ if (node.type !== dist$4.AST_NODE_TYPES.MemberExpression) {
52022
+ return false;
52023
+ }
52024
+ const isFsPromisesNamespace = node.object.type === dist$4.AST_NODE_TYPES.Identifier &&
52025
+ node.object.name === 'fs' &&
52026
+ getMemberExpressionPropertyName(node) === 'promises';
52027
+ return isFsPromisesNamespace;
52028
+ }
52029
+ function getWriteMethodName(callee) {
52030
+ if (callee.type === dist$4.AST_NODE_TYPES.Identifier) {
52031
+ return callee.name;
52032
+ }
52033
+ return callee.type === dist$4.AST_NODE_TYPES.MemberExpression &&
52034
+ isFsNamespaceObject(callee.object)
52035
+ ? getMemberExpressionPropertyName(callee)
52036
+ : null;
52037
+ }
52038
+ function isRedundantUtf8Encoding(node) {
52039
+ const value = getStaticStringValue(node);
52040
+ if (value === null) {
52041
+ return false;
52042
+ }
52043
+ const normalizedValue = value.toLowerCase();
52044
+ return normalizedValue === 'utf8' || normalizedValue === 'utf-8';
52045
+ }
52046
+ function hasSpreadProperty(node) {
52047
+ return node.properties.some((property) => property.type === dist$4.AST_NODE_TYPES.SpreadElement);
52048
+ }
52049
+ function findRedundantEncodingProperty(node) {
52050
+ if (hasSpreadProperty(node)) {
52051
+ return null;
52052
+ }
52053
+ const encodingProperties = node.properties.filter((property) => property.type === dist$4.AST_NODE_TYPES.Property &&
52054
+ getObjectPropertyName(property) === 'encoding');
52055
+ if (encodingProperties.length !== 1) {
52056
+ return null;
52057
+ }
52058
+ const encodingProperty = encodingProperties[0];
52059
+ return encodingProperty && isRedundantUtf8Encoding(encodingProperty.value)
52060
+ ? encodingProperty
52061
+ : null;
52062
+ }
52063
+ function getObjectPropertyFix(sourceCode, fixer, objectExpression, property) {
52064
+ const propertyIndex = objectExpression.properties.indexOf(property);
52065
+ const previousProperty = objectExpression.properties[propertyIndex - 1] ?? null;
52066
+ const nextProperty = objectExpression.properties[propertyIndex + 1] ?? null;
52067
+ return removeCommaSeparatedNode(sourceCode, fixer, property, previousProperty, nextProperty);
52068
+ }
52069
+ function getOptionsArgumentFix(sourceCode, fixer, callExpression, options) {
52070
+ const argumentIndex = callExpression.arguments.indexOf(options);
52071
+ const previousArgument = callExpression.arguments[argumentIndex - 1] ?? null;
52072
+ const nextArgument = callExpression.arguments[argumentIndex + 1] ?? null;
52073
+ return removeCommaSeparatedNode(sourceCode, fixer, options, previousArgument, nextArgument);
52074
+ }
52075
+ const rule$x = createRule({
52076
+ create(context) {
52077
+ const { sourceCode } = context;
52078
+ function reportRedundantEncodingArgument(callExpression, encodingArgument) {
52079
+ context.report({
52080
+ fix(fixer) {
52081
+ return getOptionsArgumentFix(sourceCode, fixer, callExpression, encodingArgument);
52082
+ },
52083
+ messageId: 'noRedundantFsEncoding',
52084
+ node: encodingArgument,
52085
+ });
52086
+ }
52087
+ function reportRedundantEncodingProperty(callExpression, options, encodingProperty) {
52088
+ context.report({
52089
+ fix(fixer) {
52090
+ const hasOnlyEncodingProperty = options.properties.length === 1;
52091
+ return hasOnlyEncodingProperty
52092
+ ? getOptionsArgumentFix(sourceCode, fixer, callExpression, options)
52093
+ : getObjectPropertyFix(sourceCode, fixer, options, encodingProperty);
52094
+ },
52095
+ messageId: 'noRedundantFsEncoding',
52096
+ node: encodingProperty,
52097
+ });
52098
+ }
52099
+ return {
52100
+ CallExpression(node) {
52101
+ if (!isWriteMethod(getWriteMethodName(node.callee))) {
52102
+ return;
52103
+ }
52104
+ const options = node.arguments[2];
52105
+ if (!options || options.type === dist$4.AST_NODE_TYPES.SpreadElement) {
52106
+ return;
52107
+ }
52108
+ if (options.type !== dist$4.AST_NODE_TYPES.ObjectExpression) {
52109
+ if (isRedundantUtf8Encoding(options)) {
52110
+ reportRedundantEncodingArgument(node, options);
52111
+ }
52112
+ return;
52113
+ }
52114
+ const encodingProperty = findRedundantEncodingProperty(options);
52115
+ if (encodingProperty) {
52116
+ reportRedundantEncodingProperty(node, options, encodingProperty);
52117
+ }
52118
+ },
52119
+ };
52120
+ },
52121
+ meta: {
52122
+ docs: {
52123
+ description: 'Disallow redundant default utf8 encoding in Node.js file write calls.',
52124
+ },
52125
+ fixable: 'code',
52126
+ messages: {
52127
+ noRedundantFsEncoding: 'Remove redundant utf8 encoding. Node.js file write methods use utf8 by default for string data.',
52128
+ },
52129
+ schema: [],
52130
+ type: 'suggestion',
52131
+ },
52132
+ name: 'no-redundant-fs-encoding',
52133
+ });
52134
+
51963
52135
  function collectArrayExpressions(node) {
51964
52136
  const result = [];
51965
52137
  if (node.type === dist$4.AST_NODE_TYPES.ArrayExpression) {
@@ -56434,36 +56606,37 @@ const plugin = {
56434
56606
  },
56435
56607
  rules: {
56436
56608
  'array-as-const': rule$5,
56437
- 'at-compat': rule$Y,
56438
- 'attrs-newline': rule$X,
56439
- 'class-accessibility-spacing': rule$W,
56609
+ 'at-compat': rule$Z,
56610
+ 'attrs-newline': rule$Y,
56611
+ 'class-accessibility-spacing': rule$X,
56440
56612
  'class-property-naming': rule$4,
56441
- 'decorator-key-sort': rule$V,
56442
- 'element-newline': rule$U,
56613
+ 'decorator-key-sort': rule$W,
56614
+ 'element-newline': rule$V,
56443
56615
  'flat-exports': rule$3,
56444
- 'host-attributes-sort': rule$T,
56445
- 'html-logical-properties': rule$S,
56446
- 'import-integrity': rule$R,
56447
- 'injection-token-description': rule$Q,
56448
- 'no-commonjs-import-patterns': rule$P,
56449
- 'no-deep-imports': rule$O,
56450
- 'no-deep-imports-to-indexed-packages': rule$N,
56451
- 'no-duplicate-attrs': rule$M,
56452
- 'no-duplicate-id': rule$L,
56453
- 'no-duplicate-in-head': rule$K,
56454
- 'no-empty-style-metadata': rule$J,
56455
- 'no-fully-untracked-effect': rule$I,
56456
- 'no-href-with-router-link': rule$H,
56457
- 'no-implicit-public': rule$G,
56458
- 'no-import-assertions': rule$F,
56459
- 'no-infinite-loop': rule$E,
56460
- 'no-legacy-peer-deps': rule$D,
56461
- 'no-nested-interactive': rule$C,
56462
- 'no-nested-ternary-in-template': rule$B,
56463
- 'no-obsolete-attrs': rule$A,
56464
- 'no-obsolete-tags': rule$z,
56465
- 'no-playwright-empty-fill': rule$y,
56466
- 'no-project-as-in-ng-template': rule$x,
56616
+ 'host-attributes-sort': rule$U,
56617
+ 'html-logical-properties': rule$T,
56618
+ 'import-integrity': rule$S,
56619
+ 'injection-token-description': rule$R,
56620
+ 'no-commonjs-import-patterns': rule$Q,
56621
+ 'no-deep-imports': rule$P,
56622
+ 'no-deep-imports-to-indexed-packages': rule$O,
56623
+ 'no-duplicate-attrs': rule$N,
56624
+ 'no-duplicate-id': rule$M,
56625
+ 'no-duplicate-in-head': rule$L,
56626
+ 'no-empty-style-metadata': rule$K,
56627
+ 'no-fully-untracked-effect': rule$J,
56628
+ 'no-href-with-router-link': rule$I,
56629
+ 'no-implicit-public': rule$H,
56630
+ 'no-import-assertions': rule$G,
56631
+ 'no-infinite-loop': rule$F,
56632
+ 'no-legacy-peer-deps': rule$E,
56633
+ 'no-nested-interactive': rule$D,
56634
+ 'no-nested-ternary-in-template': rule$C,
56635
+ 'no-obsolete-attrs': rule$B,
56636
+ 'no-obsolete-tags': rule$A,
56637
+ 'no-playwright-empty-fill': rule$z,
56638
+ 'no-project-as-in-ng-template': rule$y,
56639
+ 'no-redundant-fs-encoding': rule$x,
56467
56640
  'no-redundant-type-annotation': rule$w,
56468
56641
  'no-repeated-signal-in-conditional': rule$v,
56469
56642
  'no-restricted-attr-values': rule$2,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ui/eslint-plugin-experience-next",
3
- "version": "0.538.0",
3
+ "version": "0.540.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": {
@@ -0,0 +1,5 @@
1
+ import { type TSESLint } from '@typescript-eslint/utils';
2
+ export declare const rule: TSESLint.RuleModule<"noRedundantFsEncoding", [], unknown, TSESLint.RuleListener> & {
3
+ name: string;
4
+ };
5
+ export default rule;
@@ -0,0 +1,3 @@
1
+ import { type TSESLint, type TSESTree } from '@typescript-eslint/utils';
2
+ export type CommaSeparatedNode = TSESTree.Expression | TSESTree.Property | TSESTree.SpreadElement;
3
+ export declare function removeCommaSeparatedNode(sourceCode: Readonly<TSESLint.SourceCode>, fixer: TSESLint.RuleFixer, node: CommaSeparatedNode, previousNode: CommaSeparatedNode | null, nextNode: CommaSeparatedNode | null): TSESLint.RuleFix | null;