@taiga-ui/eslint-plugin-experience-next 0.497.0 → 0.498.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.
Files changed (2) hide show
  1. package/index.esm.js +216 -183
  2. package/package.json +2 -2
package/index.esm.js CHANGED
@@ -252223,7 +252223,7 @@ function isImportsArrayProperty(property) {
252223
252223
  return isProperty && hasIdentifierKey && isArray(property.value);
252224
252224
  }
252225
252225
 
252226
- function getImportedName(spec) {
252226
+ function getImportedName$1(spec) {
252227
252227
  if (spec.imported.type === dist$3.AST_NODE_TYPES.Identifier) {
252228
252228
  return spec.imported.name;
252229
252229
  }
@@ -252297,7 +252297,7 @@ const rule$8 = createRule({
252297
252297
  const specifierNames = importDeclaration.specifiers
252298
252298
  .filter((clause) => clause.type === dist$3.AST_NODE_TYPES.ImportSpecifier &&
252299
252299
  clause.importKind !== 'type')
252300
- .map((specifier) => getImportedName(specifier));
252300
+ .map((specifier) => getImportedName$1(specifier));
252301
252301
  const nextNames = new Set(specifierNames);
252302
252302
  nextNames.add(short);
252303
252303
  if (shouldDeleteImport) {
@@ -252307,7 +252307,7 @@ const rule$8 = createRule({
252307
252307
  .filter((clause) => clause.type === dist$3.AST_NODE_TYPES.ImportSpecifier &&
252308
252308
  (clause.importKind === 'type' ||
252309
252309
  importDeclaration.importKind === 'type'))
252310
- .map((specifier) => `type ${getImportedName(specifier)}`);
252310
+ .map((specifier) => `type ${getImportedName$1(specifier)}`);
252311
252311
  const allNames = [...typeImports, ...[...nextNames].sort()];
252312
252312
  const newImport = `import { ${allNames.join(', ')} } from '${module}';`;
252313
252313
  const alreadyHasShort = imports.some((id) => id.name === short);
@@ -252338,7 +252338,7 @@ const rule$8 = createRule({
252338
252338
  if (spec.type !== dist$3.AST_NODE_TYPES.ImportSpecifier) {
252339
252339
  continue;
252340
252340
  }
252341
- const importedClass = getImportedName(spec);
252341
+ const importedClass = getImportedName$1(spec);
252342
252342
  const matchesPattern = /^Tui[A-Z].*(?:Component|Directive)$/.test(importedClass) ||
252343
252343
  exceptions.some((exception) => exception.from === importedClass);
252344
252344
  if (matchesPattern) {
@@ -253078,13 +253078,31 @@ const rule$2 = createRule({
253078
253078
 
253079
253079
  const MESSAGE_ID = 'prefer-deep-imports';
253080
253080
  const ERROR_MESSAGE = 'Import via root entry point is prohibited when nested entry points exist';
253081
+ const sharedStateByProgram = new WeakMap();
253081
253082
  const rule$1 = createRule({
253082
253083
  create(context, [options]) {
253083
- const allowedPackages = normalizeImportFilter(options.importFilter);
253084
+ const allowedPackages = new Set(normalizeImportFilter(options.importFilter));
253085
+ if (allowedPackages.size === 0) {
253086
+ return {};
253087
+ }
253084
253088
  const isStrictMode = options.strict ?? false;
253085
- const parserServices = dist$3.ESLintUtils.getParserServices(context);
253086
- const program = parserServices.program;
253087
- const typeChecker = program.getTypeChecker();
253089
+ let state = null;
253090
+ function getState() {
253091
+ if (state) {
253092
+ return state;
253093
+ }
253094
+ const parserServices = dist$3.ESLintUtils.getParserServices(context);
253095
+ const program = parserServices.program;
253096
+ state = {
253097
+ allowedPackages,
253098
+ isStrictMode,
253099
+ program,
253100
+ shared: getSharedState(program),
253101
+ sourceCode: context.sourceCode,
253102
+ typeChecker: program.getTypeChecker(),
253103
+ };
253104
+ return state;
253105
+ }
253088
253106
  return {
253089
253107
  ImportDeclaration(node) {
253090
253108
  const rawImportPath = node.source.value;
@@ -253093,7 +253111,7 @@ const rule$1 = createRule({
253093
253111
  }
253094
253112
  const rootPackageName = getRootPackageName(rawImportPath);
253095
253113
  if (!rootPackageName ||
253096
- !allowedPackages.includes(rootPackageName) ||
253114
+ !allowedPackages.has(rootPackageName) ||
253097
253115
  (!isStrictMode &&
253098
253116
  isAlreadyNestedImport(rawImportPath, rootPackageName))) {
253099
253117
  return;
@@ -253102,32 +253120,38 @@ const rule$1 = createRule({
253102
253120
  if (importedSymbols.length === 0) {
253103
253121
  return;
253104
253122
  }
253105
- const currentFileName = context.getFilename();
253106
- const rootEntryDirectory = resolveRootEntryDirectory(rawImportPath, currentFileName, program);
253123
+ const currentState = getState();
253124
+ const rootEntryDirectory = getCachedRootEntryDirectory({
253125
+ fromFile: context.getFilename(),
253126
+ importPath: rawImportPath,
253127
+ state: currentState,
253128
+ });
253107
253129
  if (!rootEntryDirectory) {
253108
- context.report({
253109
- messageId: MESSAGE_ID,
253110
- node,
253111
- });
253112
253130
  return;
253113
253131
  }
253114
- const nestedEntryPointRelativePaths = findNestedEntryPointRelativePaths(rootEntryDirectory);
253132
+ const nestedEntryPointRelativePaths = getCachedNestedEntryPointRelativePaths(rootEntryDirectory, currentState.shared.nestedEntryPointPathsByRoot);
253115
253133
  if (nestedEntryPointRelativePaths.length === 0) {
253116
- context.report({
253117
- messageId: MESSAGE_ID,
253118
- node,
253119
- });
253120
253134
  return;
253121
253135
  }
253122
- const candidateEntryPointPaths = selectCandidateEntryPointsForMode(nestedEntryPointRelativePaths, isStrictMode);
253136
+ const candidateEntryPointPaths = selectCandidateEntryPointsForMode(nestedEntryPointRelativePaths, currentState.isStrictMode);
253123
253137
  if (candidateEntryPointPaths.length === 0) {
253124
253138
  return;
253125
253139
  }
253126
- const symbolToEntryPoint = mapSymbolsToEntryPointsUsingTypeChecker(importedSymbols, candidateEntryPointPaths, rootEntryDirectory, program, typeChecker);
253140
+ const symbolToEntryPoint = mapSymbolsToEntryPointsUsingTypeChecker({
253141
+ candidateEntryPoints: candidateEntryPointPaths,
253142
+ importedSymbols,
253143
+ rootEntryDirectory,
253144
+ state: currentState,
253145
+ });
253127
253146
  if (symbolToEntryPoint.size === 0) {
253128
253147
  return;
253129
253148
  }
253130
- const newImportBlock = buildRewrittenImports(node, rawImportPath, symbolToEntryPoint);
253149
+ const newImportBlock = buildRewrittenImports({
253150
+ baseImportPath: rawImportPath,
253151
+ node,
253152
+ state: currentState,
253153
+ symbolToEntryPoint,
253154
+ });
253131
253155
  context.report({
253132
253156
  fix(fixer) {
253133
253157
  return fixer.replaceTextRange(node.range, newImportBlock);
@@ -253152,7 +253176,15 @@ const rule$1 = createRule({
253152
253176
  {
253153
253177
  additionalProperties: false,
253154
253178
  properties: {
253155
- importFilter: { type: ['string', 'array'] },
253179
+ importFilter: {
253180
+ oneOf: [
253181
+ { type: 'string' },
253182
+ {
253183
+ items: { type: 'string' },
253184
+ type: 'array',
253185
+ },
253186
+ ],
253187
+ },
253156
253188
  strict: { type: 'boolean' },
253157
253189
  },
253158
253190
  type: 'object',
@@ -253162,22 +253194,22 @@ const rule$1 = createRule({
253162
253194
  },
253163
253195
  name: 'prefer-deep-imports',
253164
253196
  });
253165
- /**
253166
- * Normalize "importFilter" option to a flat array of package names.
253167
- * The rule expects concrete package names, not regular expression strings.
253168
- */
253197
+ function getSharedState(program) {
253198
+ const cached = sharedStateByProgram.get(program);
253199
+ if (cached) {
253200
+ return cached;
253201
+ }
253202
+ const state = {
253203
+ entryPointBySymbolCache: new Map(),
253204
+ nestedEntryPointPathsByRoot: new Map(),
253205
+ rootEntryDirectoryByImport: new Map(),
253206
+ };
253207
+ sharedStateByProgram.set(program, state);
253208
+ return state;
253209
+ }
253169
253210
  function normalizeImportFilter(importFilter) {
253170
- return Array.isArray(importFilter) ? importFilter : [importFilter];
253211
+ return (Array.isArray(importFilter) ? importFilter : [importFilter]).filter(Boolean);
253171
253212
  }
253172
- /**
253173
- * Extract the package root name from an import specifier.
253174
- *
253175
- * Examples:
253176
- * "@taiga-ui/core" → "@taiga-ui/core"
253177
- * "@taiga-ui/core/components" → "@taiga-ui/core"
253178
- * "some-lib" → "some-lib"
253179
- * "some-lib/utils" → "some-lib"
253180
- */
253181
253213
  function getRootPackageName(importPath) {
253182
253214
  if (importPath.startsWith('@')) {
253183
253215
  const segments = importPath.split('/');
@@ -253189,15 +253221,6 @@ function getRootPackageName(importPath) {
253189
253221
  const parts = importPath.split('/');
253190
253222
  return parts[0] ?? null;
253191
253223
  }
253192
- /**
253193
- * Check whether the current import path is already nested below the root package.
253194
- *
253195
- * Example:
253196
- * root = "@taiga-ui/core"
253197
- * "@taiga-ui/core" → false (root import)
253198
- * "@taiga-ui/core/components" → true
253199
- * "@taiga-ui/core/components/x" → true
253200
- */
253201
253224
  function isAlreadyNestedImport(importPath, rootPackageName) {
253202
253225
  if (!importPath.startsWith(rootPackageName)) {
253203
253226
  return false;
@@ -253206,63 +253229,49 @@ function isAlreadyNestedImport(importPath, rootPackageName) {
253206
253229
  const rootSegments = rootPackageName.split('/');
253207
253230
  return importSegments.length > rootSegments.length;
253208
253231
  }
253209
- /**
253210
- * Extract only named imported symbols:
253211
- *
253212
- * Examples:
253213
- * import {A, B as C} from 'x'; → ['A', 'B']
253214
- *
253215
- * Namespace imports and default imports are ignored for this rule.
253216
- */
253217
253232
  function extractNamedImportedSymbols(node) {
253218
253233
  return node.specifiers
253219
253234
  .filter((specifier) => specifier.type === dist$2.AST_NODE_TYPES.ImportSpecifier)
253220
- .map((specifier) => specifier.imported.type === dist$2.AST_NODE_TYPES.Identifier
253235
+ .map(getImportedName);
253236
+ }
253237
+ function getImportedName(specifier) {
253238
+ return specifier.imported.type === dist$2.AST_NODE_TYPES.Identifier
253221
253239
  ? specifier.imported.name
253222
- : specifier.imported.value);
253240
+ : specifier.imported.value;
253241
+ }
253242
+ function getCachedRootEntryDirectory({ fromFile, importPath, state, }) {
253243
+ const cacheKey = `${path.dirname(fromFile)}\0${importPath}`;
253244
+ const cache = state.shared.rootEntryDirectoryByImport;
253245
+ if (cache.has(cacheKey)) {
253246
+ return cache.get(cacheKey) ?? null;
253247
+ }
253248
+ const rootEntryDirectory = resolveRootEntryDirectory({
253249
+ fromFile,
253250
+ importPath,
253251
+ program: state.program,
253252
+ });
253253
+ cache.set(cacheKey, rootEntryDirectory);
253254
+ return rootEntryDirectory;
253223
253255
  }
253224
- /**
253225
- * Resolve the physical directory of the module being imported.
253226
- * We rely on the same module resolution that TypeScript uses for the program.
253227
- */
253228
- function resolveRootEntryDirectory(importPath, fromFile, program) {
253229
- const compilerOptions = program.getCompilerOptions();
253230
- const resolution = ts.resolveModuleName(importPath, fromFile, compilerOptions, ts.sys).resolvedModule;
253231
- if (!resolution) {
253232
- return null;
253256
+ function resolveRootEntryDirectory({ fromFile, importPath, program, }) {
253257
+ const resolution = ts.resolveModuleName(importPath, fromFile, program.getCompilerOptions(), ts.sys).resolvedModule;
253258
+ return resolution ? path.dirname(resolution.resolvedFileName) : null;
253259
+ }
253260
+ function getCachedNestedEntryPointRelativePaths(rootEntryDirectory, cache) {
253261
+ if (cache.has(rootEntryDirectory)) {
253262
+ return cache.get(rootEntryDirectory) ?? [];
253233
253263
  }
253234
- return path.dirname(resolution.resolvedFileName);
253264
+ const entryPoints = findNestedEntryPointRelativePaths(rootEntryDirectory);
253265
+ cache.set(rootEntryDirectory, entryPoints);
253266
+ return entryPoints;
253235
253267
  }
253236
- /**
253237
- * Find all nested entry points relative to the given root directory.
253238
- *
253239
- * A directory is considered a nested entry point if it contains either:
253240
- * - "ng-package.json" (Angular library entry)
253241
- * - "collection.json" (Angular schematics collection)
253242
- *
253243
- * Returned paths are relative to "rootEntryDirectory".
253244
- *
253245
- * Example:
253246
- * rootEntryDirectory = ".../core/src"
253247
- * found:
253248
- * "utils/ng-package.json" → "utils"
253249
- * "utils/dom/ng-package.json" → "utils/dom"
253250
- * "schematics/collection.json" → "schematics"
253251
- */
253252
253268
  function findNestedEntryPointRelativePaths(rootEntryDirectory) {
253253
253269
  const files = ['**/ng-package.json', '**/collection.json'].flatMap((pattern) => globSync(pattern, { cwd: rootEntryDirectory }));
253254
- return files
253255
- .map((file) => path.dirname(file).replaceAll('\\', '/'))
253270
+ const directories = files
253271
+ .map((file) => path.posix.dirname(file.replaceAll('\\', '/')))
253256
253272
  .filter((directory) => directory && directory !== '.');
253273
+ return [...new Set(directories)];
253257
253274
  }
253258
- /**
253259
- * For strict = false:
253260
- * Only first-level nested directories are candidates.
253261
- *
253262
- * For strict = true:
253263
- * All nested directories are candidates, sorted from deepest to shallowest
253264
- * so that the deepest match wins.
253265
- */
253266
253275
  function selectCandidateEntryPointsForMode(allNestedRelativePaths, strict) {
253267
253276
  if (!strict) {
253268
253277
  return allNestedRelativePaths.filter((relativePath) => !relativePath.includes('/'));
@@ -253273,62 +253282,70 @@ function selectCandidateEntryPointsForMode(allNestedRelativePaths, strict) {
253273
253282
  return depthB - depthA;
253274
253283
  });
253275
253284
  }
253276
- /**
253277
- * Build a map from exported symbol name to nested entry point relative path.
253278
- *
253279
- * Implementation strategy:
253280
- * 1. For each candidate nested entry point:
253281
- * - Determine its entry file (using ng-package.json or collection.json).
253282
- * - Ask TypeScript for the module symbol and its exports.
253283
- * 2. For each imported symbol:
253284
- * - Find the first entry point whose export table contains that symbol.
253285
- * - strict = true: candidates were sorted deepest-first.
253286
- * - strict = false: candidates contain only first-level nested entry points.
253287
- */
253288
- function mapSymbolsToEntryPointsUsingTypeChecker(importedSymbols, candidateEntryPoints, rootEntryDirectory, program, typeChecker) {
253285
+ function mapSymbolsToEntryPointsUsingTypeChecker({ candidateEntryPoints, importedSymbols, rootEntryDirectory, state, }) {
253289
253286
  const symbolToEntryPoint = new Map();
253290
- const exportTableByEntryPoint = new Map();
253291
- for (const relativeEntryDir of candidateEntryPoints) {
253292
- const entryFile = getEntryFileForNestedEntryPoint(rootEntryDirectory, relativeEntryDir);
253293
- if (!entryFile) {
253294
- continue;
253295
- }
253296
- const sourceFile = program.getSourceFile(entryFile);
253297
- if (!sourceFile) {
253298
- continue;
253287
+ const entryPointBySymbol = getCachedEntryPointBySymbol({
253288
+ candidateEntryPoints,
253289
+ rootEntryDirectory,
253290
+ state,
253291
+ });
253292
+ for (const importedSymbol of importedSymbols) {
253293
+ const entryPoint = entryPointBySymbol.get(importedSymbol);
253294
+ if (entryPoint) {
253295
+ symbolToEntryPoint.set(importedSymbol, entryPoint);
253299
253296
  }
253300
- const moduleSymbol = typeChecker.getSymbolAtLocation(sourceFile);
253301
- if (!moduleSymbol) {
253297
+ }
253298
+ return symbolToEntryPoint;
253299
+ }
253300
+ function getCachedEntryPointBySymbol({ candidateEntryPoints, rootEntryDirectory, state, }) {
253301
+ const cacheKey = `${rootEntryDirectory}\0${candidateEntryPoints.join('\0')}`;
253302
+ const cache = state.shared.entryPointBySymbolCache;
253303
+ if (cache.has(cacheKey)) {
253304
+ return cache.get(cacheKey) ?? new Map();
253305
+ }
253306
+ const entryPointBySymbol = buildEntryPointBySymbolIndex({
253307
+ candidateEntryPoints,
253308
+ rootEntryDirectory,
253309
+ state,
253310
+ });
253311
+ cache.set(cacheKey, entryPointBySymbol);
253312
+ return entryPointBySymbol;
253313
+ }
253314
+ function buildEntryPointBySymbolIndex({ candidateEntryPoints, rootEntryDirectory, state, }) {
253315
+ const entryPointBySymbol = new Map();
253316
+ for (const relativeEntryDir of candidateEntryPoints) {
253317
+ const exportedNames = getExportedNamesForEntryPoint({
253318
+ relativeEntryDirectory: relativeEntryDir,
253319
+ rootEntryDirectory,
253320
+ state,
253321
+ });
253322
+ if (!exportedNames) {
253302
253323
  continue;
253303
253324
  }
253304
- const exports$1 = typeChecker.getExportsOfModule(moduleSymbol);
253305
- const exportedNames = new Set(exports$1.map((symbol) => symbol.getName()));
253306
- exportTableByEntryPoint.set(relativeEntryDir, exportedNames);
253307
- }
253308
- for (const importedSymbol of importedSymbols) {
253309
- for (const relativeEntryDir of candidateEntryPoints) {
253310
- const exportedNames = exportTableByEntryPoint.get(relativeEntryDir);
253311
- if (!exportedNames?.has(importedSymbol)) {
253312
- continue;
253325
+ for (const exportedName of exportedNames) {
253326
+ if (!entryPointBySymbol.has(exportedName)) {
253327
+ entryPointBySymbol.set(exportedName, relativeEntryDir);
253313
253328
  }
253314
- symbolToEntryPoint.set(importedSymbol, relativeEntryDir);
253315
- break;
253316
253329
  }
253317
253330
  }
253318
- return symbolToEntryPoint;
253331
+ return entryPointBySymbol;
253332
+ }
253333
+ function getExportedNamesForEntryPoint({ relativeEntryDirectory, rootEntryDirectory, state, }) {
253334
+ const entryFile = getEntryFileForNestedEntryPoint(rootEntryDirectory, relativeEntryDirectory);
253335
+ if (!entryFile) {
253336
+ return null;
253337
+ }
253338
+ const sourceFile = state.program.getSourceFile(entryFile);
253339
+ if (!sourceFile) {
253340
+ return null;
253341
+ }
253342
+ const moduleSymbol = state.typeChecker.getSymbolAtLocation(sourceFile);
253343
+ if (!moduleSymbol) {
253344
+ return null;
253345
+ }
253346
+ const exports$1 = state.typeChecker.getExportsOfModule(moduleSymbol);
253347
+ return new Set(exports$1.map((symbol) => symbol.getName()));
253319
253348
  }
253320
- /**
253321
- * Determine the physical entry file for a nested entry point.
253322
- *
253323
- * Priority:
253324
- * 1. If "ng-package.json" exists:
253325
- * - use lib.entryFile if present
253326
- * - otherwise fall back to "index.ts"
253327
- * 2. Else if "collection.json" exists:
253328
- * - treat this directory as a schematic collection package
253329
- * - entry file is "index.ts" if it exists
253330
- * 3. Otherwise: no entry file can be determined → return null
253331
- */
253332
253349
  function getEntryFileForNestedEntryPoint(rootEntryDirectory, relativeEntryDirectory) {
253333
253350
  const absoluteDirectory = path.join(rootEntryDirectory, relativeEntryDirectory);
253334
253351
  const ngPackageJsonPath = path.join(absoluteDirectory, 'ng-package.json');
@@ -253351,58 +253368,74 @@ function getEntryFileForNestedEntryPoint(rootEntryDirectory, relativeEntryDirect
253351
253368
  }
253352
253369
  return null;
253353
253370
  }
253354
- /**
253355
- * Build the final text block with rewritten import declarations.
253356
- *
253357
- * Example:
253358
- * original:
253359
- * import {A, B as C, D} from '@taiga-ui/core';
253360
- *
253361
- * symbolMap (strict = true):
253362
- * A -> "components/button"
253363
- * B -> "components/button"
253364
- * D -> "components/other"
253365
- *
253366
- * result:
253367
- * import {A, B as C} from '@taiga-ui/core/components/button';
253368
- * import {D} from '@taiga-ui/core/components/other';
253369
- */
253370
- function buildRewrittenImports(node, baseImportPath, symbolToEntryPoint) {
253371
- const isTypeOnlyImport = node.importKind === 'type';
253371
+ function buildRewrittenImports({ baseImportPath, node, state, symbolToEntryPoint, }) {
253372
253372
  const groupedByTarget = new Map();
253373
- for (const [symbolName, relativeEntryPath] of symbolToEntryPoint.entries()) {
253373
+ const remainingSpecifiers = [];
253374
+ for (const specifier of node.specifiers) {
253375
+ if (specifier.type !== dist$2.AST_NODE_TYPES.ImportSpecifier) {
253376
+ remainingSpecifiers.push(specifier);
253377
+ continue;
253378
+ }
253379
+ const importedName = getImportedName(specifier);
253380
+ const relativeEntryPath = symbolToEntryPoint.get(importedName);
253381
+ if (!relativeEntryPath) {
253382
+ remainingSpecifiers.push(specifier);
253383
+ continue;
253384
+ }
253374
253385
  const targetSpecifier = `${baseImportPath}/${relativeEntryPath}`;
253375
253386
  if (!groupedByTarget.has(targetSpecifier)) {
253376
253387
  groupedByTarget.set(targetSpecifier, []);
253377
253388
  }
253378
- const targetGroup = groupedByTarget.get(targetSpecifier);
253379
- if (targetGroup) {
253380
- targetGroup.push(symbolName);
253381
- }
253389
+ groupedByTarget.get(targetSpecifier)?.push(specifier);
253382
253390
  }
253383
253391
  const importStatements = [];
253384
- for (const [targetSpecifier, symbols] of groupedByTarget.entries()) {
253385
- const parts = symbols.map((symbolName) => {
253386
- const matchingSpecifier = node.specifiers.find((specifier) => specifier.type === dist$2.AST_NODE_TYPES.ImportSpecifier &&
253387
- (specifier.imported.type === dist$2.AST_NODE_TYPES.Identifier
253388
- ? specifier.imported.name === symbolName
253389
- : specifier.imported.value === symbolName));
253390
- if (!matchingSpecifier) {
253391
- return symbolName;
253392
- }
253393
- const importedName = matchingSpecifier.imported.type === dist$2.AST_NODE_TYPES.Identifier
253394
- ? matchingSpecifier.imported.name
253395
- : matchingSpecifier.imported.value;
253396
- const localName = matchingSpecifier.local.name;
253397
- return importedName === localName
253398
- ? importedName
253399
- : `${importedName} as ${localName}`;
253400
- });
253401
- const statement = `import ${isTypeOnlyImport ? 'type ' : ''}{${parts.join(', ')}} from '${targetSpecifier}';`;
253402
- importStatements.push(statement);
253392
+ for (const [targetSpecifier, specifiers] of groupedByTarget.entries()) {
253393
+ importStatements.push(buildNamedImportStatement({
253394
+ importKind: node.importKind,
253395
+ importPath: targetSpecifier,
253396
+ specifiers,
253397
+ state,
253398
+ }));
253399
+ }
253400
+ const remainingImportStatement = buildImportStatement({
253401
+ importKind: node.importKind,
253402
+ importPath: baseImportPath,
253403
+ specifiers: remainingSpecifiers,
253404
+ state,
253405
+ });
253406
+ if (remainingImportStatement) {
253407
+ importStatements.push(remainingImportStatement);
253403
253408
  }
253404
253409
  return importStatements.join('\n');
253405
253410
  }
253411
+ function buildNamedImportStatement({ importKind, importPath, specifiers, state, }) {
253412
+ const importKeyword = importKind === 'type' ? 'import type' : 'import';
253413
+ const parts = specifiers.map((specifier) => state.sourceCode.getText(specifier));
253414
+ return `${importKeyword} {${parts.join(', ')}} from '${importPath}';`;
253415
+ }
253416
+ function buildImportStatement({ importKind, importPath, specifiers, state, }) {
253417
+ if (specifiers.length === 0) {
253418
+ return null;
253419
+ }
253420
+ const importKeyword = importKind === 'type' ? 'import type' : 'import';
253421
+ const defaultSpecifier = specifiers.find((specifier) => specifier.type === dist$2.AST_NODE_TYPES.ImportDefaultSpecifier);
253422
+ const namespaceSpecifier = specifiers.find((specifier) => specifier.type === dist$2.AST_NODE_TYPES.ImportNamespaceSpecifier);
253423
+ const namedSpecifiers = specifiers.filter((specifier) => specifier.type === dist$2.AST_NODE_TYPES.ImportSpecifier);
253424
+ const clauses = [];
253425
+ if (defaultSpecifier) {
253426
+ clauses.push(state.sourceCode.getText(defaultSpecifier));
253427
+ }
253428
+ if (namespaceSpecifier) {
253429
+ clauses.push(state.sourceCode.getText(namespaceSpecifier));
253430
+ }
253431
+ if (namedSpecifiers.length > 0) {
253432
+ clauses.push(`{${namedSpecifiers.map((specifier) => state.sourceCode.getText(specifier)).join(', ')}}`);
253433
+ }
253434
+ if (clauses.length === 0) {
253435
+ return null;
253436
+ }
253437
+ return `${importKeyword} ${clauses.join(', ')} from '${importPath}';`;
253438
+ }
253406
253439
 
253407
253440
  function getTypeName(param) {
253408
253441
  const typeAnnotation = param?.parameter?.typeAnnotation ?? param?.typeAnnotation;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@taiga-ui/eslint-plugin-experience-next",
3
- "version": "0.497.0",
3
+ "version": "0.498.0",
4
4
  "description": "An ESLint plugin to enforce a consistent code styles across taiga-ui projects",
5
5
  "repository": {
6
6
  "type": "git",
@@ -27,7 +27,7 @@
27
27
  ],
28
28
  "type": "module",
29
29
  "devDependencies": {
30
- "@typescript-eslint/rule-tester": "^8.59.1"
30
+ "@typescript-eslint/rule-tester": "8.59.1"
31
31
  },
32
32
  "peerDependencies": {
33
33
  "@eslint/compat": "^2.0.5",