@taiga-ui/eslint-plugin-experience-next 0.383.0 → 0.384.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 +127 -27
- package/package.json +4 -4
package/index.esm.js
CHANGED
|
@@ -1749,54 +1749,154 @@ var noDeepImportsToIndexedPackages = createRule$5({
|
|
|
1749
1749
|
const parserServices = ESLintUtils.getParserServices(context);
|
|
1750
1750
|
const program = parserServices.program;
|
|
1751
1751
|
const compilerHost = ts.createCompilerHost(program.getCompilerOptions(), true);
|
|
1752
|
+
function resolveTypescriptModule(moduleSpecifier) {
|
|
1753
|
+
const resolved = ts.resolveModuleName(moduleSpecifier, context.filename, program.getCompilerOptions(), compilerHost);
|
|
1754
|
+
return resolved.resolvedModule?.resolvedFileName ?? null;
|
|
1755
|
+
}
|
|
1752
1756
|
return {
|
|
1753
1757
|
ImportDeclaration(node) {
|
|
1754
|
-
const
|
|
1755
|
-
if (typeof
|
|
1758
|
+
const importSpecifier = node.source.value;
|
|
1759
|
+
if (typeof importSpecifier !== 'string') {
|
|
1756
1760
|
return;
|
|
1757
1761
|
}
|
|
1758
|
-
|
|
1759
|
-
const { resolvedModule } = ts.resolveModuleName(importPath, containingFile, program.getCompilerOptions(), compilerHost);
|
|
1760
|
-
const resolvedPath = resolvedModule?.resolvedFileName;
|
|
1761
|
-
if (!resolvedPath || resolvedPath.endsWith('index.ts')) {
|
|
1762
|
+
if (!isExternalModuleSpecifier(importSpecifier)) {
|
|
1762
1763
|
return;
|
|
1763
1764
|
}
|
|
1764
|
-
const
|
|
1765
|
-
const
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
const
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1765
|
+
const packageRootSpecifier = getPackageRootSpecifier(importSpecifier);
|
|
1766
|
+
const importSubpath = getSubpath(importSpecifier, packageRootSpecifier);
|
|
1767
|
+
if (!importSubpath) {
|
|
1768
|
+
return;
|
|
1769
|
+
}
|
|
1770
|
+
const resolvedRootModuleFilePath = resolveTypescriptModule(packageRootSpecifier);
|
|
1771
|
+
if (!resolvedRootModuleFilePath) {
|
|
1772
|
+
return;
|
|
1773
|
+
}
|
|
1774
|
+
const packageMarkerFilePath = pickPackageMarkerFile(resolvedRootModuleFilePath);
|
|
1775
|
+
if (!packageMarkerFilePath) {
|
|
1776
|
+
return;
|
|
1777
|
+
}
|
|
1778
|
+
const packageDirectory = path.dirname(packageMarkerFilePath);
|
|
1779
|
+
const indexFilePath = pickIndexFileInDirectory(packageDirectory);
|
|
1780
|
+
if (!indexFilePath) {
|
|
1781
|
+
return;
|
|
1782
|
+
}
|
|
1783
|
+
const hasMatchingReExport = indexExportsSubpath(indexFilePath, importSubpath);
|
|
1784
|
+
if (!hasMatchingReExport) {
|
|
1785
|
+
return;
|
|
1783
1786
|
}
|
|
1787
|
+
context.report({
|
|
1788
|
+
data: {
|
|
1789
|
+
importPath: importSpecifier,
|
|
1790
|
+
suggestedImport: packageRootSpecifier,
|
|
1791
|
+
},
|
|
1792
|
+
messageId: 'deepImport',
|
|
1793
|
+
node: node.source,
|
|
1794
|
+
});
|
|
1784
1795
|
},
|
|
1785
1796
|
};
|
|
1786
1797
|
},
|
|
1787
1798
|
defaultOptions: [],
|
|
1788
1799
|
meta: {
|
|
1789
1800
|
docs: {
|
|
1790
|
-
description: 'Disallow deep imports
|
|
1801
|
+
description: 'Disallow deep imports only when package root index.ts (or index.d.ts) re-exports that subpath, and the package is marked by ng-package.json or package.json',
|
|
1791
1802
|
},
|
|
1792
1803
|
messages: {
|
|
1793
|
-
deepImport: 'Import "{{importPath}}" should go through the package
|
|
1804
|
+
deepImport: 'Import "{{importPath}}" should go through the package root export (use "{{suggestedImport}}").',
|
|
1794
1805
|
},
|
|
1795
1806
|
schema: [],
|
|
1796
1807
|
type: 'problem',
|
|
1797
1808
|
},
|
|
1798
1809
|
name: 'no-deep-imports-to-indexed-packages',
|
|
1799
1810
|
});
|
|
1811
|
+
function isExternalModuleSpecifier(moduleSpecifier) {
|
|
1812
|
+
if (!moduleSpecifier || moduleSpecifier.startsWith('.')) {
|
|
1813
|
+
return false;
|
|
1814
|
+
}
|
|
1815
|
+
return !path.isAbsolute(moduleSpecifier);
|
|
1816
|
+
}
|
|
1817
|
+
function pickPackageMarkerFile(resolvedRootFilePath) {
|
|
1818
|
+
const resolvedRootDirectory = path.dirname(resolvedRootFilePath);
|
|
1819
|
+
const nearestNgPackageJson = findNearestFileUpwards(resolvedRootDirectory, 'ng-package.json');
|
|
1820
|
+
const nearestPackageJson = findNearestFileUpwards(resolvedRootDirectory, 'package.json');
|
|
1821
|
+
return nearestNgPackageJson ?? nearestPackageJson ?? null;
|
|
1822
|
+
}
|
|
1823
|
+
function pickIndexFileInDirectory(packageDirectory) {
|
|
1824
|
+
const indexTypescriptPath = path.join(packageDirectory, 'index.ts');
|
|
1825
|
+
const indexTypesDeclarationPath = path.join(packageDirectory, 'index.d.ts');
|
|
1826
|
+
if (fs.existsSync(indexTypescriptPath)) {
|
|
1827
|
+
return indexTypescriptPath;
|
|
1828
|
+
}
|
|
1829
|
+
if (fs.existsSync(indexTypesDeclarationPath)) {
|
|
1830
|
+
return indexTypesDeclarationPath;
|
|
1831
|
+
}
|
|
1832
|
+
return null;
|
|
1833
|
+
}
|
|
1834
|
+
function isScopedPackage(importSpecifier) {
|
|
1835
|
+
return importSpecifier.startsWith('@');
|
|
1836
|
+
}
|
|
1837
|
+
function getPackageRootSpecifier(importSpecifier) {
|
|
1838
|
+
const pathParts = importSpecifier.split('/');
|
|
1839
|
+
if (isScopedPackage(importSpecifier)) {
|
|
1840
|
+
if (pathParts.length >= 2) {
|
|
1841
|
+
return `${pathParts[0]}/${pathParts[1]}`;
|
|
1842
|
+
}
|
|
1843
|
+
return importSpecifier;
|
|
1844
|
+
}
|
|
1845
|
+
return pathParts[0] ?? importSpecifier;
|
|
1846
|
+
}
|
|
1847
|
+
function getSubpath(importSpecifier, packageRootSpecifier) {
|
|
1848
|
+
if (importSpecifier === packageRootSpecifier) {
|
|
1849
|
+
return null;
|
|
1850
|
+
}
|
|
1851
|
+
if (!importSpecifier.startsWith(`${packageRootSpecifier}/`)) {
|
|
1852
|
+
return null;
|
|
1853
|
+
}
|
|
1854
|
+
return importSpecifier.slice(packageRootSpecifier.length + 1);
|
|
1855
|
+
}
|
|
1856
|
+
function findNearestFileUpwards(startDirectory, fileName) {
|
|
1857
|
+
let currentDirectory = startDirectory;
|
|
1858
|
+
while (currentDirectory.length > 0) {
|
|
1859
|
+
const candidatePath = path.join(currentDirectory, fileName);
|
|
1860
|
+
if (fs.existsSync(candidatePath)) {
|
|
1861
|
+
return candidatePath;
|
|
1862
|
+
}
|
|
1863
|
+
const parentDirectory = path.dirname(currentDirectory);
|
|
1864
|
+
if (parentDirectory === currentDirectory) {
|
|
1865
|
+
break;
|
|
1866
|
+
}
|
|
1867
|
+
currentDirectory = parentDirectory;
|
|
1868
|
+
}
|
|
1869
|
+
return null;
|
|
1870
|
+
}
|
|
1871
|
+
function normalizeModuleSpecifier(moduleSpecifier) {
|
|
1872
|
+
return moduleSpecifier.replaceAll('\\', '/');
|
|
1873
|
+
}
|
|
1874
|
+
function stripKnownExtensions(filePathOrSpecifier) {
|
|
1875
|
+
return filePathOrSpecifier.replace(/\.(d\.ts|ts|tsx|js|jsx|mjs|cjs)$/, '');
|
|
1876
|
+
}
|
|
1877
|
+
function indexExportsSubpath(indexFilePath, subpath) {
|
|
1878
|
+
const fileText = fs.readFileSync(indexFilePath, 'utf8');
|
|
1879
|
+
const sourceFile = ts.createSourceFile(indexFilePath, fileText, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
1880
|
+
const expectedSpecifier = normalizeModuleSpecifier(stripKnownExtensions(`./${subpath}`));
|
|
1881
|
+
const expectedIndexSpecifier = normalizeModuleSpecifier(stripKnownExtensions(`./${subpath}/index`));
|
|
1882
|
+
let isReExportFound = false;
|
|
1883
|
+
sourceFile.forEachChild((astNode) => {
|
|
1884
|
+
if (isReExportFound) {
|
|
1885
|
+
return;
|
|
1886
|
+
}
|
|
1887
|
+
if (ts.isExportDeclaration(astNode)) {
|
|
1888
|
+
const moduleSpecifierNode = astNode.moduleSpecifier;
|
|
1889
|
+
if (moduleSpecifierNode && ts.isStringLiteral(moduleSpecifierNode)) {
|
|
1890
|
+
const exportedSpecifier = normalizeModuleSpecifier(stripKnownExtensions(moduleSpecifierNode.text));
|
|
1891
|
+
if (exportedSpecifier === expectedSpecifier ||
|
|
1892
|
+
exportedSpecifier === expectedIndexSpecifier) {
|
|
1893
|
+
isReExportFound = true;
|
|
1894
|
+
}
|
|
1895
|
+
}
|
|
1896
|
+
}
|
|
1897
|
+
});
|
|
1898
|
+
return isReExportFound;
|
|
1899
|
+
}
|
|
1800
1900
|
|
|
1801
1901
|
const MESSAGE_ID$2 = 'no-href-with-router-link';
|
|
1802
1902
|
const ERROR_MESSAGE$1 = 'Do not use href and routerLink attributes together on the same element';
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@taiga-ui/eslint-plugin-experience-next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.384.0",
|
|
4
4
|
"description": "An ESLint plugin to enforce a consistent code styles across taiga-ui projects",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"devDependencies": {
|
|
8
|
-
"@typescript-eslint/rule-tester": "8.
|
|
8
|
+
"@typescript-eslint/rule-tester": "8.53.0",
|
|
9
9
|
"glob": "13.0.0"
|
|
10
10
|
},
|
|
11
11
|
"peerDependencies": {
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"@smarttools/eslint-plugin-rxjs": "^1.0.22",
|
|
17
17
|
"@stylistic/eslint-plugin": "^5.6.1",
|
|
18
18
|
"@types/glob": "*",
|
|
19
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
19
|
+
"@typescript-eslint/eslint-plugin": "^8.53.0",
|
|
20
20
|
"angular-eslint": "^20.7.0",
|
|
21
21
|
"eslint": "^9.39.2",
|
|
22
22
|
"eslint-config-prettier": "^10.1.7",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"eslint-plugin-jest": "^29.5.0",
|
|
29
29
|
"eslint-plugin-package-json": "^0.85.0",
|
|
30
30
|
"eslint-plugin-perfectionist": "^4.15.1",
|
|
31
|
-
"eslint-plugin-playwright": "^2.
|
|
31
|
+
"eslint-plugin-playwright": "^2.5.0",
|
|
32
32
|
"eslint-plugin-prettier": "^5.5.4",
|
|
33
33
|
"eslint-plugin-promise": "^7.2.1",
|
|
34
34
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|