@taiga-ui/eslint-plugin-experience-next 0.496.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.
- package/index.esm.js +222 -208
- package/package.json +3 -5
package/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import fs, { readFileSync } from 'node:fs';
|
|
1
|
+
import fs, { globSync, readFileSync } from 'node:fs';
|
|
2
2
|
import markdown from '@eslint/markdown';
|
|
3
3
|
import rxjs from '@smarttools/eslint-plugin-rxjs';
|
|
4
4
|
import stylistic from '@stylistic/eslint-plugin';
|
|
@@ -24,7 +24,6 @@ import unusedImports from 'eslint-plugin-unused-imports';
|
|
|
24
24
|
import globals from 'globals';
|
|
25
25
|
import tseslint from 'typescript-eslint';
|
|
26
26
|
import { createRequire } from 'node:module';
|
|
27
|
-
import { globSync } from 'glob';
|
|
28
27
|
import require$$0$1 from 'eslint';
|
|
29
28
|
import require$$1 from 'eslint/use-at-your-own-risk';
|
|
30
29
|
import path from 'node:path';
|
|
@@ -1480,10 +1479,10 @@ var recommended = defineConfig([
|
|
|
1480
1479
|
]);
|
|
1481
1480
|
|
|
1482
1481
|
const allPackageJSONs = globSync('**/package.json', {
|
|
1483
|
-
|
|
1482
|
+
exclude: ['**/node_modules/**', '**/dist/**'],
|
|
1484
1483
|
}).filter((path) => !readJSON(path).private);
|
|
1485
1484
|
function pattern(type) {
|
|
1486
|
-
return allPackageJSONs.map((p) => p.replaceAll(/\\+/g, '/').replace(
|
|
1485
|
+
return allPackageJSONs.map((p) => p.replaceAll(/\\+/g, '/').replace(/package\.json$/, type));
|
|
1487
1486
|
}
|
|
1488
1487
|
var taigaSpecific = defineConfig([
|
|
1489
1488
|
{
|
|
@@ -1495,7 +1494,7 @@ var taigaSpecific = defineConfig([
|
|
|
1495
1494
|
'error',
|
|
1496
1495
|
{
|
|
1497
1496
|
importFilter: allPackageJSONs
|
|
1498
|
-
.map((
|
|
1497
|
+
.map((packageJsonPath) => readJSON(packageJsonPath).name)
|
|
1499
1498
|
.filter(Boolean),
|
|
1500
1499
|
strict: !!process.env.CI,
|
|
1501
1500
|
},
|
|
@@ -252224,7 +252223,7 @@ function isImportsArrayProperty(property) {
|
|
|
252224
252223
|
return isProperty && hasIdentifierKey && isArray(property.value);
|
|
252225
252224
|
}
|
|
252226
252225
|
|
|
252227
|
-
function getImportedName(spec) {
|
|
252226
|
+
function getImportedName$1(spec) {
|
|
252228
252227
|
if (spec.imported.type === dist$3.AST_NODE_TYPES.Identifier) {
|
|
252229
252228
|
return spec.imported.name;
|
|
252230
252229
|
}
|
|
@@ -252298,7 +252297,7 @@ const rule$8 = createRule({
|
|
|
252298
252297
|
const specifierNames = importDeclaration.specifiers
|
|
252299
252298
|
.filter((clause) => clause.type === dist$3.AST_NODE_TYPES.ImportSpecifier &&
|
|
252300
252299
|
clause.importKind !== 'type')
|
|
252301
|
-
.map((specifier) => getImportedName(specifier));
|
|
252300
|
+
.map((specifier) => getImportedName$1(specifier));
|
|
252302
252301
|
const nextNames = new Set(specifierNames);
|
|
252303
252302
|
nextNames.add(short);
|
|
252304
252303
|
if (shouldDeleteImport) {
|
|
@@ -252308,7 +252307,7 @@ const rule$8 = createRule({
|
|
|
252308
252307
|
.filter((clause) => clause.type === dist$3.AST_NODE_TYPES.ImportSpecifier &&
|
|
252309
252308
|
(clause.importKind === 'type' ||
|
|
252310
252309
|
importDeclaration.importKind === 'type'))
|
|
252311
|
-
.map((specifier) => `type ${getImportedName(specifier)}`);
|
|
252310
|
+
.map((specifier) => `type ${getImportedName$1(specifier)}`);
|
|
252312
252311
|
const allNames = [...typeImports, ...[...nextNames].sort()];
|
|
252313
252312
|
const newImport = `import { ${allNames.join(', ')} } from '${module}';`;
|
|
252314
252313
|
const alreadyHasShort = imports.some((id) => id.name === short);
|
|
@@ -252339,7 +252338,7 @@ const rule$8 = createRule({
|
|
|
252339
252338
|
if (spec.type !== dist$3.AST_NODE_TYPES.ImportSpecifier) {
|
|
252340
252339
|
continue;
|
|
252341
252340
|
}
|
|
252342
|
-
const importedClass = getImportedName(spec);
|
|
252341
|
+
const importedClass = getImportedName$1(spec);
|
|
252343
252342
|
const matchesPattern = /^Tui[A-Z].*(?:Component|Directive)$/.test(importedClass) ||
|
|
252344
252343
|
exceptions.some((exception) => exception.from === importedClass);
|
|
252345
252344
|
if (matchesPattern) {
|
|
@@ -253079,13 +253078,31 @@ const rule$2 = createRule({
|
|
|
253079
253078
|
|
|
253080
253079
|
const MESSAGE_ID = 'prefer-deep-imports';
|
|
253081
253080
|
const ERROR_MESSAGE = 'Import via root entry point is prohibited when nested entry points exist';
|
|
253081
|
+
const sharedStateByProgram = new WeakMap();
|
|
253082
253082
|
const rule$1 = createRule({
|
|
253083
253083
|
create(context, [options]) {
|
|
253084
|
-
const allowedPackages = normalizeImportFilter(options.importFilter);
|
|
253084
|
+
const allowedPackages = new Set(normalizeImportFilter(options.importFilter));
|
|
253085
|
+
if (allowedPackages.size === 0) {
|
|
253086
|
+
return {};
|
|
253087
|
+
}
|
|
253085
253088
|
const isStrictMode = options.strict ?? false;
|
|
253086
|
-
|
|
253087
|
-
|
|
253088
|
-
|
|
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
|
+
}
|
|
253089
253106
|
return {
|
|
253090
253107
|
ImportDeclaration(node) {
|
|
253091
253108
|
const rawImportPath = node.source.value;
|
|
@@ -253094,7 +253111,7 @@ const rule$1 = createRule({
|
|
|
253094
253111
|
}
|
|
253095
253112
|
const rootPackageName = getRootPackageName(rawImportPath);
|
|
253096
253113
|
if (!rootPackageName ||
|
|
253097
|
-
!allowedPackages.
|
|
253114
|
+
!allowedPackages.has(rootPackageName) ||
|
|
253098
253115
|
(!isStrictMode &&
|
|
253099
253116
|
isAlreadyNestedImport(rawImportPath, rootPackageName))) {
|
|
253100
253117
|
return;
|
|
@@ -253103,32 +253120,38 @@ const rule$1 = createRule({
|
|
|
253103
253120
|
if (importedSymbols.length === 0) {
|
|
253104
253121
|
return;
|
|
253105
253122
|
}
|
|
253106
|
-
const
|
|
253107
|
-
const rootEntryDirectory =
|
|
253123
|
+
const currentState = getState();
|
|
253124
|
+
const rootEntryDirectory = getCachedRootEntryDirectory({
|
|
253125
|
+
fromFile: context.getFilename(),
|
|
253126
|
+
importPath: rawImportPath,
|
|
253127
|
+
state: currentState,
|
|
253128
|
+
});
|
|
253108
253129
|
if (!rootEntryDirectory) {
|
|
253109
|
-
context.report({
|
|
253110
|
-
messageId: MESSAGE_ID,
|
|
253111
|
-
node,
|
|
253112
|
-
});
|
|
253113
253130
|
return;
|
|
253114
253131
|
}
|
|
253115
|
-
const nestedEntryPointRelativePaths =
|
|
253132
|
+
const nestedEntryPointRelativePaths = getCachedNestedEntryPointRelativePaths(rootEntryDirectory, currentState.shared.nestedEntryPointPathsByRoot);
|
|
253116
253133
|
if (nestedEntryPointRelativePaths.length === 0) {
|
|
253117
|
-
context.report({
|
|
253118
|
-
messageId: MESSAGE_ID,
|
|
253119
|
-
node,
|
|
253120
|
-
});
|
|
253121
253134
|
return;
|
|
253122
253135
|
}
|
|
253123
|
-
const candidateEntryPointPaths = selectCandidateEntryPointsForMode(nestedEntryPointRelativePaths, isStrictMode);
|
|
253136
|
+
const candidateEntryPointPaths = selectCandidateEntryPointsForMode(nestedEntryPointRelativePaths, currentState.isStrictMode);
|
|
253124
253137
|
if (candidateEntryPointPaths.length === 0) {
|
|
253125
253138
|
return;
|
|
253126
253139
|
}
|
|
253127
|
-
const symbolToEntryPoint = mapSymbolsToEntryPointsUsingTypeChecker(
|
|
253140
|
+
const symbolToEntryPoint = mapSymbolsToEntryPointsUsingTypeChecker({
|
|
253141
|
+
candidateEntryPoints: candidateEntryPointPaths,
|
|
253142
|
+
importedSymbols,
|
|
253143
|
+
rootEntryDirectory,
|
|
253144
|
+
state: currentState,
|
|
253145
|
+
});
|
|
253128
253146
|
if (symbolToEntryPoint.size === 0) {
|
|
253129
253147
|
return;
|
|
253130
253148
|
}
|
|
253131
|
-
const newImportBlock = buildRewrittenImports(
|
|
253149
|
+
const newImportBlock = buildRewrittenImports({
|
|
253150
|
+
baseImportPath: rawImportPath,
|
|
253151
|
+
node,
|
|
253152
|
+
state: currentState,
|
|
253153
|
+
symbolToEntryPoint,
|
|
253154
|
+
});
|
|
253132
253155
|
context.report({
|
|
253133
253156
|
fix(fixer) {
|
|
253134
253157
|
return fixer.replaceTextRange(node.range, newImportBlock);
|
|
@@ -253153,7 +253176,15 @@ const rule$1 = createRule({
|
|
|
253153
253176
|
{
|
|
253154
253177
|
additionalProperties: false,
|
|
253155
253178
|
properties: {
|
|
253156
|
-
importFilter: {
|
|
253179
|
+
importFilter: {
|
|
253180
|
+
oneOf: [
|
|
253181
|
+
{ type: 'string' },
|
|
253182
|
+
{
|
|
253183
|
+
items: { type: 'string' },
|
|
253184
|
+
type: 'array',
|
|
253185
|
+
},
|
|
253186
|
+
],
|
|
253187
|
+
},
|
|
253157
253188
|
strict: { type: 'boolean' },
|
|
253158
253189
|
},
|
|
253159
253190
|
type: 'object',
|
|
@@ -253163,22 +253194,22 @@ const rule$1 = createRule({
|
|
|
253163
253194
|
},
|
|
253164
253195
|
name: 'prefer-deep-imports',
|
|
253165
253196
|
});
|
|
253166
|
-
|
|
253167
|
-
|
|
253168
|
-
|
|
253169
|
-
|
|
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
|
+
}
|
|
253170
253210
|
function normalizeImportFilter(importFilter) {
|
|
253171
|
-
return Array.isArray(importFilter) ? importFilter : [importFilter];
|
|
253211
|
+
return (Array.isArray(importFilter) ? importFilter : [importFilter]).filter(Boolean);
|
|
253172
253212
|
}
|
|
253173
|
-
/**
|
|
253174
|
-
* Extract the package root name from an import specifier.
|
|
253175
|
-
*
|
|
253176
|
-
* Examples:
|
|
253177
|
-
* "@taiga-ui/core" → "@taiga-ui/core"
|
|
253178
|
-
* "@taiga-ui/core/components" → "@taiga-ui/core"
|
|
253179
|
-
* "some-lib" → "some-lib"
|
|
253180
|
-
* "some-lib/utils" → "some-lib"
|
|
253181
|
-
*/
|
|
253182
253213
|
function getRootPackageName(importPath) {
|
|
253183
253214
|
if (importPath.startsWith('@')) {
|
|
253184
253215
|
const segments = importPath.split('/');
|
|
@@ -253190,15 +253221,6 @@ function getRootPackageName(importPath) {
|
|
|
253190
253221
|
const parts = importPath.split('/');
|
|
253191
253222
|
return parts[0] ?? null;
|
|
253192
253223
|
}
|
|
253193
|
-
/**
|
|
253194
|
-
* Check whether the current import path is already nested below the root package.
|
|
253195
|
-
*
|
|
253196
|
-
* Example:
|
|
253197
|
-
* root = "@taiga-ui/core"
|
|
253198
|
-
* "@taiga-ui/core" → false (root import)
|
|
253199
|
-
* "@taiga-ui/core/components" → true
|
|
253200
|
-
* "@taiga-ui/core/components/x" → true
|
|
253201
|
-
*/
|
|
253202
253224
|
function isAlreadyNestedImport(importPath, rootPackageName) {
|
|
253203
253225
|
if (!importPath.startsWith(rootPackageName)) {
|
|
253204
253226
|
return false;
|
|
@@ -253207,81 +253229,49 @@ function isAlreadyNestedImport(importPath, rootPackageName) {
|
|
|
253207
253229
|
const rootSegments = rootPackageName.split('/');
|
|
253208
253230
|
return importSegments.length > rootSegments.length;
|
|
253209
253231
|
}
|
|
253210
|
-
/**
|
|
253211
|
-
* Extract only named imported symbols:
|
|
253212
|
-
*
|
|
253213
|
-
* Examples:
|
|
253214
|
-
* import {A, B as C} from 'x'; → ['A', 'B']
|
|
253215
|
-
*
|
|
253216
|
-
* Namespace imports and default imports are ignored for this rule.
|
|
253217
|
-
*/
|
|
253218
253232
|
function extractNamedImportedSymbols(node) {
|
|
253219
253233
|
return node.specifiers
|
|
253220
253234
|
.filter((specifier) => specifier.type === dist$2.AST_NODE_TYPES.ImportSpecifier)
|
|
253221
|
-
.map(
|
|
253235
|
+
.map(getImportedName);
|
|
253236
|
+
}
|
|
253237
|
+
function getImportedName(specifier) {
|
|
253238
|
+
return specifier.imported.type === dist$2.AST_NODE_TYPES.Identifier
|
|
253222
253239
|
? specifier.imported.name
|
|
253223
|
-
: 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;
|
|
253224
253255
|
}
|
|
253225
|
-
|
|
253226
|
-
|
|
253227
|
-
|
|
253228
|
-
|
|
253229
|
-
function
|
|
253230
|
-
|
|
253231
|
-
|
|
253232
|
-
if (!resolution) {
|
|
253233
|
-
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) ?? [];
|
|
253234
253263
|
}
|
|
253235
|
-
|
|
253264
|
+
const entryPoints = findNestedEntryPointRelativePaths(rootEntryDirectory);
|
|
253265
|
+
cache.set(rootEntryDirectory, entryPoints);
|
|
253266
|
+
return entryPoints;
|
|
253236
253267
|
}
|
|
253237
|
-
/**
|
|
253238
|
-
* Find all nested entry points relative to the given root directory.
|
|
253239
|
-
*
|
|
253240
|
-
* A directory is considered a nested entry point if it contains either:
|
|
253241
|
-
* - "ng-package.json" (Angular library entry)
|
|
253242
|
-
* - "collection.json" (Angular schematics collection)
|
|
253243
|
-
*
|
|
253244
|
-
* Returned paths are relative to "rootEntryDirectory".
|
|
253245
|
-
*
|
|
253246
|
-
* Example:
|
|
253247
|
-
* rootEntryDirectory = ".../core/src"
|
|
253248
|
-
* found:
|
|
253249
|
-
* "utils/ng-package.json" → "utils"
|
|
253250
|
-
* "utils/dom/ng-package.json" → "utils/dom"
|
|
253251
|
-
* "schematics/collection.json" → "schematics"
|
|
253252
|
-
*/
|
|
253253
253268
|
function findNestedEntryPointRelativePaths(rootEntryDirectory) {
|
|
253254
|
-
const
|
|
253255
|
-
|
|
253256
|
-
|
|
253257
|
-
|
|
253258
|
-
|
|
253259
|
-
absolute: false,
|
|
253260
|
-
cwd: rootEntryDirectory,
|
|
253261
|
-
});
|
|
253262
|
-
const directories = [];
|
|
253263
|
-
for (const file of ngPackageJsonFiles) {
|
|
253264
|
-
const normalized = file.replaceAll('\\', '/').replace(/\/ng-package\.json$/, '');
|
|
253265
|
-
if (normalized && normalized !== '.') {
|
|
253266
|
-
directories.push(normalized);
|
|
253267
|
-
}
|
|
253268
|
-
}
|
|
253269
|
-
for (const file of collectionJsonFiles) {
|
|
253270
|
-
const normalized = file.replaceAll('\\', '/').replace(/\/collection\.json$/, '');
|
|
253271
|
-
if (normalized && normalized !== '.') {
|
|
253272
|
-
directories.push(normalized);
|
|
253273
|
-
}
|
|
253274
|
-
}
|
|
253275
|
-
return directories;
|
|
253269
|
+
const files = ['**/ng-package.json', '**/collection.json'].flatMap((pattern) => globSync(pattern, { cwd: rootEntryDirectory }));
|
|
253270
|
+
const directories = files
|
|
253271
|
+
.map((file) => path.posix.dirname(file.replaceAll('\\', '/')))
|
|
253272
|
+
.filter((directory) => directory && directory !== '.');
|
|
253273
|
+
return [...new Set(directories)];
|
|
253276
253274
|
}
|
|
253277
|
-
/**
|
|
253278
|
-
* For strict = false:
|
|
253279
|
-
* Only first-level nested directories are candidates.
|
|
253280
|
-
*
|
|
253281
|
-
* For strict = true:
|
|
253282
|
-
* All nested directories are candidates, sorted from deepest to shallowest
|
|
253283
|
-
* so that the deepest match wins.
|
|
253284
|
-
*/
|
|
253285
253275
|
function selectCandidateEntryPointsForMode(allNestedRelativePaths, strict) {
|
|
253286
253276
|
if (!strict) {
|
|
253287
253277
|
return allNestedRelativePaths.filter((relativePath) => !relativePath.includes('/'));
|
|
@@ -253292,62 +253282,70 @@ function selectCandidateEntryPointsForMode(allNestedRelativePaths, strict) {
|
|
|
253292
253282
|
return depthB - depthA;
|
|
253293
253283
|
});
|
|
253294
253284
|
}
|
|
253295
|
-
|
|
253296
|
-
* Build a map from exported symbol name to nested entry point relative path.
|
|
253297
|
-
*
|
|
253298
|
-
* Implementation strategy:
|
|
253299
|
-
* 1. For each candidate nested entry point:
|
|
253300
|
-
* - Determine its entry file (using ng-package.json or collection.json).
|
|
253301
|
-
* - Ask TypeScript for the module symbol and its exports.
|
|
253302
|
-
* 2. For each imported symbol:
|
|
253303
|
-
* - Find the first entry point whose export table contains that symbol.
|
|
253304
|
-
* - strict = true: candidates were sorted deepest-first.
|
|
253305
|
-
* - strict = false: candidates contain only first-level nested entry points.
|
|
253306
|
-
*/
|
|
253307
|
-
function mapSymbolsToEntryPointsUsingTypeChecker(importedSymbols, candidateEntryPoints, rootEntryDirectory, program, typeChecker) {
|
|
253285
|
+
function mapSymbolsToEntryPointsUsingTypeChecker({ candidateEntryPoints, importedSymbols, rootEntryDirectory, state, }) {
|
|
253308
253286
|
const symbolToEntryPoint = new Map();
|
|
253309
|
-
const
|
|
253310
|
-
|
|
253311
|
-
|
|
253312
|
-
|
|
253313
|
-
|
|
253314
|
-
|
|
253315
|
-
const
|
|
253316
|
-
if (
|
|
253317
|
-
|
|
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);
|
|
253318
253296
|
}
|
|
253319
|
-
|
|
253320
|
-
|
|
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) {
|
|
253321
253323
|
continue;
|
|
253322
253324
|
}
|
|
253323
|
-
const
|
|
253324
|
-
|
|
253325
|
-
|
|
253326
|
-
}
|
|
253327
|
-
for (const importedSymbol of importedSymbols) {
|
|
253328
|
-
for (const relativeEntryDir of candidateEntryPoints) {
|
|
253329
|
-
const exportedNames = exportTableByEntryPoint.get(relativeEntryDir);
|
|
253330
|
-
if (!exportedNames?.has(importedSymbol)) {
|
|
253331
|
-
continue;
|
|
253325
|
+
for (const exportedName of exportedNames) {
|
|
253326
|
+
if (!entryPointBySymbol.has(exportedName)) {
|
|
253327
|
+
entryPointBySymbol.set(exportedName, relativeEntryDir);
|
|
253332
253328
|
}
|
|
253333
|
-
symbolToEntryPoint.set(importedSymbol, relativeEntryDir);
|
|
253334
|
-
break;
|
|
253335
253329
|
}
|
|
253336
253330
|
}
|
|
253337
|
-
return
|
|
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()));
|
|
253338
253348
|
}
|
|
253339
|
-
/**
|
|
253340
|
-
* Determine the physical entry file for a nested entry point.
|
|
253341
|
-
*
|
|
253342
|
-
* Priority:
|
|
253343
|
-
* 1. If "ng-package.json" exists:
|
|
253344
|
-
* - use lib.entryFile if present
|
|
253345
|
-
* - otherwise fall back to "index.ts"
|
|
253346
|
-
* 2. Else if "collection.json" exists:
|
|
253347
|
-
* - treat this directory as a schematic collection package
|
|
253348
|
-
* - entry file is "index.ts" if it exists
|
|
253349
|
-
* 3. Otherwise: no entry file can be determined → return null
|
|
253350
|
-
*/
|
|
253351
253349
|
function getEntryFileForNestedEntryPoint(rootEntryDirectory, relativeEntryDirectory) {
|
|
253352
253350
|
const absoluteDirectory = path.join(rootEntryDirectory, relativeEntryDirectory);
|
|
253353
253351
|
const ngPackageJsonPath = path.join(absoluteDirectory, 'ng-package.json');
|
|
@@ -253370,58 +253368,74 @@ function getEntryFileForNestedEntryPoint(rootEntryDirectory, relativeEntryDirect
|
|
|
253370
253368
|
}
|
|
253371
253369
|
return null;
|
|
253372
253370
|
}
|
|
253373
|
-
|
|
253374
|
-
* Build the final text block with rewritten import declarations.
|
|
253375
|
-
*
|
|
253376
|
-
* Example:
|
|
253377
|
-
* original:
|
|
253378
|
-
* import {A, B as C, D} from '@taiga-ui/core';
|
|
253379
|
-
*
|
|
253380
|
-
* symbolMap (strict = true):
|
|
253381
|
-
* A -> "components/button"
|
|
253382
|
-
* B -> "components/button"
|
|
253383
|
-
* D -> "components/other"
|
|
253384
|
-
*
|
|
253385
|
-
* result:
|
|
253386
|
-
* import {A, B as C} from '@taiga-ui/core/components/button';
|
|
253387
|
-
* import {D} from '@taiga-ui/core/components/other';
|
|
253388
|
-
*/
|
|
253389
|
-
function buildRewrittenImports(node, baseImportPath, symbolToEntryPoint) {
|
|
253390
|
-
const isTypeOnlyImport = node.importKind === 'type';
|
|
253371
|
+
function buildRewrittenImports({ baseImportPath, node, state, symbolToEntryPoint, }) {
|
|
253391
253372
|
const groupedByTarget = new Map();
|
|
253392
|
-
|
|
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
|
+
}
|
|
253393
253385
|
const targetSpecifier = `${baseImportPath}/${relativeEntryPath}`;
|
|
253394
253386
|
if (!groupedByTarget.has(targetSpecifier)) {
|
|
253395
253387
|
groupedByTarget.set(targetSpecifier, []);
|
|
253396
253388
|
}
|
|
253397
|
-
|
|
253398
|
-
if (targetGroup) {
|
|
253399
|
-
targetGroup.push(symbolName);
|
|
253400
|
-
}
|
|
253389
|
+
groupedByTarget.get(targetSpecifier)?.push(specifier);
|
|
253401
253390
|
}
|
|
253402
253391
|
const importStatements = [];
|
|
253403
|
-
for (const [targetSpecifier,
|
|
253404
|
-
|
|
253405
|
-
|
|
253406
|
-
|
|
253407
|
-
|
|
253408
|
-
|
|
253409
|
-
|
|
253410
|
-
|
|
253411
|
-
|
|
253412
|
-
|
|
253413
|
-
|
|
253414
|
-
|
|
253415
|
-
|
|
253416
|
-
|
|
253417
|
-
|
|
253418
|
-
|
|
253419
|
-
});
|
|
253420
|
-
const statement = `import ${isTypeOnlyImport ? 'type ' : ''}{${parts.join(', ')}} from '${targetSpecifier}';`;
|
|
253421
|
-
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);
|
|
253422
253408
|
}
|
|
253423
253409
|
return importStatements.join('\n');
|
|
253424
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
|
+
}
|
|
253425
253439
|
|
|
253426
253440
|
function getTypeName(param) {
|
|
253427
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.
|
|
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,14 +27,13 @@
|
|
|
27
27
|
],
|
|
28
28
|
"type": "module",
|
|
29
29
|
"devDependencies": {
|
|
30
|
-
"
|
|
30
|
+
"@typescript-eslint/rule-tester": "8.59.1"
|
|
31
31
|
},
|
|
32
32
|
"peerDependencies": {
|
|
33
33
|
"@eslint/compat": "^2.0.5",
|
|
34
34
|
"@eslint/markdown": "^8.0.1",
|
|
35
35
|
"@smarttools/eslint-plugin-rxjs": "^1.0.22",
|
|
36
36
|
"@stylistic/eslint-plugin": "^5.10.0",
|
|
37
|
-
"@types/glob": "*",
|
|
38
37
|
"angular-eslint": "^20.7.0",
|
|
39
38
|
"eslint": "^9.39.4",
|
|
40
39
|
"eslint-config-prettier": "^10.1.7",
|
|
@@ -55,9 +54,8 @@
|
|
|
55
54
|
"eslint-plugin-sonarjs": "^4.0.3",
|
|
56
55
|
"eslint-plugin-unicorn": "^64.0.0",
|
|
57
56
|
"eslint-plugin-unused-imports": "^4.4.1",
|
|
58
|
-
"glob": "*",
|
|
59
57
|
"globals": "^17.5.0",
|
|
60
|
-
"typescript-eslint": "^8.59.
|
|
58
|
+
"typescript-eslint": "^8.59.1"
|
|
61
59
|
},
|
|
62
60
|
"publishConfig": {
|
|
63
61
|
"access": "public"
|