@taiga-ui/eslint-plugin-experience-next 0.369.0 → 0.370.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.d.ts +0 -1
- package/index.esm.js +258 -129
- package/package.json +1 -1
- package/rules/prefer-deep-imports.d.ts +2 -3
package/index.d.ts
CHANGED
|
@@ -28,7 +28,6 @@ declare const plugin: {
|
|
|
28
28
|
'prefer-deep-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"prefer-deep-imports", [{
|
|
29
29
|
importFilter: string[] | string;
|
|
30
30
|
strict?: boolean;
|
|
31
|
-
mockPaths?: Record<string, string>;
|
|
32
31
|
}], unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
33
32
|
'short-tui-imports': import("@typescript-eslint/utils/ts-eslint").RuleModule<"replaceTuiImport", import("./rules/short-tui-imports").Options, unknown, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
34
33
|
'standalone-imports-sort': import("@typescript-eslint/utils/ts-eslint").RuleModule<"incorrectOrder", [{
|
package/index.esm.js
CHANGED
|
@@ -1930,37 +1930,63 @@ function getClass(node) {
|
|
|
1930
1930
|
}
|
|
1931
1931
|
|
|
1932
1932
|
const MESSAGE_ID$1 = 'prefer-deep-imports';
|
|
1933
|
-
const ERROR_MESSAGE = 'Import via root
|
|
1933
|
+
const ERROR_MESSAGE = 'Import via root entry point is prohibited when nested entry points exist';
|
|
1934
|
+
const createRule$3 = ESLintUtils.RuleCreator(() => ERROR_MESSAGE);
|
|
1935
|
+
const tsconfigCache = new Map();
|
|
1934
1936
|
const moduleResolutionCache = new Map();
|
|
1935
|
-
const
|
|
1936
|
-
const
|
|
1937
|
-
const
|
|
1937
|
+
const exportCheckCache = new Map();
|
|
1938
|
+
const nearestNgCache = new Map();
|
|
1939
|
+
const tsFileCache = new Map();
|
|
1938
1940
|
var preferDeepImports = createRule$3({
|
|
1939
|
-
create(context, [
|
|
1940
|
-
const
|
|
1941
|
+
create(context, [options]) {
|
|
1942
|
+
const allowedPackages = normalizeFilter(options.importFilter);
|
|
1943
|
+
const strict = options.strict ?? false;
|
|
1941
1944
|
return {
|
|
1942
|
-
|
|
1943
|
-
const
|
|
1944
|
-
|
|
1945
|
-
if (!resolvedFile) {
|
|
1945
|
+
ImportDeclaration(node) {
|
|
1946
|
+
const importPath = node.source.value;
|
|
1947
|
+
if (typeof importPath !== 'string') {
|
|
1946
1948
|
return;
|
|
1947
1949
|
}
|
|
1948
|
-
const
|
|
1949
|
-
|
|
1950
|
-
|
|
1951
|
-
|
|
1952
|
-
if (nested && !hasNested) {
|
|
1953
|
-
return;
|
|
1950
|
+
const shortName = extractPackageName(importPath);
|
|
1951
|
+
const allowed = allowedPackages.some((pkg) => {
|
|
1952
|
+
if (shortName && pkg instanceof RegExp) {
|
|
1953
|
+
return pkg.test(shortName);
|
|
1954
1954
|
}
|
|
1955
|
+
return pkg === shortName;
|
|
1956
|
+
});
|
|
1957
|
+
if (!allowed) {
|
|
1958
|
+
return;
|
|
1959
|
+
}
|
|
1960
|
+
if (!strict && isNestedImport(importPath)) {
|
|
1961
|
+
return;
|
|
1962
|
+
}
|
|
1963
|
+
const symbols = extractImportedSymbols(node);
|
|
1964
|
+
if (symbols.length === 0) {
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
const filename = context.filename;
|
|
1968
|
+
const rootEntry = resolveRootEntryPoint(importPath, filename);
|
|
1969
|
+
if (!rootEntry) {
|
|
1970
|
+
return context.report({
|
|
1971
|
+
messageId: MESSAGE_ID$1,
|
|
1972
|
+
node,
|
|
1973
|
+
});
|
|
1974
|
+
}
|
|
1975
|
+
const nested = findNestedEntryPoints(rootEntry);
|
|
1976
|
+
if (nested.length === 0) {
|
|
1977
|
+
return context.report({
|
|
1978
|
+
messageId: MESSAGE_ID$1,
|
|
1979
|
+
node,
|
|
1980
|
+
});
|
|
1955
1981
|
}
|
|
1956
|
-
const
|
|
1957
|
-
if (
|
|
1958
|
-
context.report({ messageId: MESSAGE_ID$1, node });
|
|
1982
|
+
const symbolMap = mapSymbolsToEntryPoints(rootEntry, nested, symbols, strict);
|
|
1983
|
+
if (symbolMap.size === 0) {
|
|
1959
1984
|
return;
|
|
1960
1985
|
}
|
|
1986
|
+
const newImports = buildImports(node, importPath, symbolMap);
|
|
1961
1987
|
context.report({
|
|
1962
1988
|
fix(fixer) {
|
|
1963
|
-
return fixer.replaceTextRange(
|
|
1989
|
+
return fixer.replaceTextRange(node.range, newImports);
|
|
1964
1990
|
},
|
|
1965
1991
|
messageId: MESSAGE_ID$1,
|
|
1966
1992
|
node,
|
|
@@ -1983,7 +2009,6 @@ var preferDeepImports = createRule$3({
|
|
|
1983
2009
|
additionalProperties: false,
|
|
1984
2010
|
properties: {
|
|
1985
2011
|
importFilter: { type: ['string', 'array'] },
|
|
1986
|
-
mockPaths: { type: 'object' },
|
|
1987
2012
|
strict: { type: 'boolean' },
|
|
1988
2013
|
},
|
|
1989
2014
|
type: 'object',
|
|
@@ -1993,140 +2018,244 @@ var preferDeepImports = createRule$3({
|
|
|
1993
2018
|
},
|
|
1994
2019
|
name: 'prefer-deep-imports',
|
|
1995
2020
|
});
|
|
1996
|
-
function
|
|
1997
|
-
if (
|
|
1998
|
-
return
|
|
2021
|
+
function extractPackageName(importPath) {
|
|
2022
|
+
if (!importPath.startsWith('@')) {
|
|
2023
|
+
return null;
|
|
1999
2024
|
}
|
|
2000
|
-
|
|
2001
|
-
|
|
2025
|
+
const p = importPath.split('/');
|
|
2026
|
+
return p.length >= 2 ? `${p[0]}/${p[1]}` : null;
|
|
2027
|
+
}
|
|
2028
|
+
function isNestedImport(importPath) {
|
|
2029
|
+
return importPath.split('/').length > 2;
|
|
2030
|
+
}
|
|
2031
|
+
function extractImportedSymbols(node) {
|
|
2032
|
+
return node.specifiers
|
|
2033
|
+
.filter((s) => s.type === AST_NODE_TYPES$1.ImportSpecifier)
|
|
2034
|
+
.map((s) => s.imported.type === AST_NODE_TYPES$1.Identifier
|
|
2035
|
+
? s.imported.name
|
|
2036
|
+
: s.imported.value);
|
|
2037
|
+
}
|
|
2038
|
+
function resolveRootEntryPoint(importPath, fromFile) {
|
|
2039
|
+
const key = `${importPath}|${fromFile}`;
|
|
2040
|
+
if (moduleResolutionCache.has(key)) {
|
|
2041
|
+
return moduleResolutionCache.get(key);
|
|
2002
2042
|
}
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
const compilerOptions = program.getCompilerOptions();
|
|
2008
|
-
const resolved = ts.resolveModuleName(specifier, context.filename, compilerOptions, ts.sys);
|
|
2009
|
-
result = resolved.resolvedModule?.resolvedFileName ?? null;
|
|
2043
|
+
const tsconfig = findNearestTsconfig(fromFile);
|
|
2044
|
+
if (!tsconfig) {
|
|
2045
|
+
moduleResolutionCache.set(key, null);
|
|
2046
|
+
return null;
|
|
2010
2047
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2048
|
+
let parsed = tsconfigCache.get(tsconfig);
|
|
2049
|
+
if (!parsed) {
|
|
2050
|
+
const json = ts.readConfigFile(tsconfig, ts.sys.readFile).config;
|
|
2051
|
+
parsed = ts.parseJsonConfigFileContent(json, ts.sys, path.dirname(tsconfig));
|
|
2052
|
+
tsconfigCache.set(tsconfig, parsed);
|
|
2013
2053
|
}
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
return node.type === AST_NODE_TYPES$1.Identifier ? node.name : node.value;
|
|
2054
|
+
const resolved = ts.resolveModuleName(importPath, fromFile, parsed.options, ts.sys).resolvedModule;
|
|
2055
|
+
const value = resolved ? path.dirname(resolved.resolvedFileName) : null;
|
|
2056
|
+
moduleResolutionCache.set(key, value);
|
|
2057
|
+
return value;
|
|
2019
2058
|
}
|
|
2020
|
-
function
|
|
2021
|
-
|
|
2022
|
-
const
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
if (sp.type !== AST_NODE_TYPES$1.ImportSpecifier) {
|
|
2028
|
-
return null;
|
|
2059
|
+
function findNearestTsconfig(start) {
|
|
2060
|
+
let dir = path.dirname(start);
|
|
2061
|
+
const limit = process.cwd();
|
|
2062
|
+
while (dir.startsWith(limit)) {
|
|
2063
|
+
const candidate = path.join(dir, 'tsconfig.json');
|
|
2064
|
+
if (fs.existsSync(candidate)) {
|
|
2065
|
+
return candidate;
|
|
2029
2066
|
}
|
|
2030
|
-
const
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
});
|
|
2036
|
-
return found?.replaceAll(/\\+/g, '/');
|
|
2037
|
-
});
|
|
2038
|
-
if (sourceFiles.some((x) => !x)) {
|
|
2039
|
-
return null;
|
|
2067
|
+
const parent = path.dirname(dir);
|
|
2068
|
+
if (parent === dir) {
|
|
2069
|
+
break;
|
|
2070
|
+
}
|
|
2071
|
+
dir = parent;
|
|
2040
2072
|
}
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2073
|
+
return null;
|
|
2074
|
+
}
|
|
2075
|
+
function findNestedEntryPoints(root) {
|
|
2076
|
+
const cached = tsFileCache.get(`${root}|ng`);
|
|
2077
|
+
if (cached) {
|
|
2078
|
+
return cached;
|
|
2044
2079
|
}
|
|
2045
|
-
const
|
|
2046
|
-
|
|
2047
|
-
|
|
2080
|
+
const found = globSync('**/ng-package.json', { absolute: false, cwd: root })
|
|
2081
|
+
.map((p) => p.replaceAll('\\', '/'))
|
|
2082
|
+
.map((p) => p.replace('/ng-package.json', ''))
|
|
2083
|
+
.filter((dir) => dir !== '.');
|
|
2084
|
+
tsFileCache.set(`${root}|ng`, found);
|
|
2085
|
+
return found;
|
|
2086
|
+
}
|
|
2087
|
+
function mapSymbolsToEntryPoints(root, nested, symbols, strict) {
|
|
2088
|
+
const result = new Map();
|
|
2089
|
+
const remaining = new Set(symbols);
|
|
2090
|
+
for (const np of nested) {
|
|
2091
|
+
if (remaining.size === 0) {
|
|
2092
|
+
break;
|
|
2093
|
+
}
|
|
2094
|
+
const full = path.join(root, np);
|
|
2095
|
+
let files = tsFileCache.get(full);
|
|
2096
|
+
if (!files) {
|
|
2097
|
+
files = globSync('**/*.ts', {
|
|
2098
|
+
absolute: true,
|
|
2099
|
+
cwd: full,
|
|
2100
|
+
ignore: ['**/*.spec.ts', '**/*.cy.ts'],
|
|
2101
|
+
});
|
|
2102
|
+
tsFileCache.set(full, files);
|
|
2103
|
+
}
|
|
2104
|
+
for (const file of files) {
|
|
2105
|
+
const content = safeReadFile(file);
|
|
2106
|
+
if (!content) {
|
|
2107
|
+
continue;
|
|
2108
|
+
}
|
|
2109
|
+
for (const symbol of Array.from(remaining)) {
|
|
2110
|
+
const has = cachedContainsDirectExport(file, content, symbol) ||
|
|
2111
|
+
cachedContainsReExport(file, content, symbol);
|
|
2112
|
+
if (!has) {
|
|
2113
|
+
continue;
|
|
2114
|
+
}
|
|
2115
|
+
const nearest = cachedNearestNg(file, root);
|
|
2116
|
+
if (!nearest) {
|
|
2117
|
+
continue;
|
|
2118
|
+
}
|
|
2119
|
+
let suffix = path.relative(root, nearest).replaceAll('\\', '/');
|
|
2120
|
+
if (!strict && suffix.includes('/')) {
|
|
2121
|
+
suffix = suffix.split('/')[0];
|
|
2122
|
+
}
|
|
2123
|
+
result.set(symbol, suffix);
|
|
2124
|
+
remaining.delete(symbol);
|
|
2125
|
+
}
|
|
2048
2126
|
}
|
|
2049
|
-
const imported = getImportedName$1(sp.imported);
|
|
2050
|
-
const local = sp.local.name;
|
|
2051
|
-
const mapped = imported === local ? imported : `${imported} as ${local}`;
|
|
2052
|
-
return `import ${isTypeOnly ? 'type ' : ''}{${mapped}} from '${entryPoints[i]}';`;
|
|
2053
|
-
});
|
|
2054
|
-
if (newImports.some((x) => x === null)) {
|
|
2055
|
-
return null;
|
|
2056
2127
|
}
|
|
2057
|
-
return
|
|
2128
|
+
return result;
|
|
2058
2129
|
}
|
|
2059
|
-
function
|
|
2060
|
-
|
|
2061
|
-
|
|
2130
|
+
function cachedContainsDirectExport(file, content, symbol) {
|
|
2131
|
+
let cache = exportCheckCache.get(file);
|
|
2132
|
+
if (!cache) {
|
|
2133
|
+
cache = new Map();
|
|
2134
|
+
exportCheckCache.set(file, cache);
|
|
2062
2135
|
}
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
entryRootCache.set(resolvedFile, dir);
|
|
2067
|
-
return dir;
|
|
2068
|
-
}
|
|
2069
|
-
dir = path.dirname(dir);
|
|
2136
|
+
const key = `direct:${symbol}`;
|
|
2137
|
+
if (cache.has(key)) {
|
|
2138
|
+
return cache.get(key);
|
|
2070
2139
|
}
|
|
2071
|
-
|
|
2072
|
-
|
|
2140
|
+
const res = containsDirectExport(content, symbol);
|
|
2141
|
+
cache.set(key, res);
|
|
2142
|
+
return res;
|
|
2073
2143
|
}
|
|
2074
|
-
function
|
|
2075
|
-
|
|
2076
|
-
|
|
2144
|
+
function cachedContainsReExport(file, content, symbol) {
|
|
2145
|
+
let cache = exportCheckCache.get(file);
|
|
2146
|
+
if (!cache) {
|
|
2147
|
+
cache = new Map();
|
|
2148
|
+
exportCheckCache.set(file, cache);
|
|
2077
2149
|
}
|
|
2078
|
-
const
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
if (fs.existsSync(`${candidate}/ng-package.json`)) {
|
|
2082
|
-
return candidate;
|
|
2083
|
-
}
|
|
2150
|
+
const key = `re:${symbol}`;
|
|
2151
|
+
if (cache.has(key)) {
|
|
2152
|
+
return cache.get(key);
|
|
2084
2153
|
}
|
|
2085
|
-
|
|
2154
|
+
const res = containsReExport(file, content, symbol);
|
|
2155
|
+
cache.set(key, res);
|
|
2156
|
+
return res;
|
|
2086
2157
|
}
|
|
2087
|
-
function
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2158
|
+
function containsDirectExport(content, symbol) {
|
|
2159
|
+
const re = new RegExp(String.raw `(?:export\s+(?:function|class|const|let|var)\s+${symbol}\b)|` +
|
|
2160
|
+
String.raw `(?:export\s*\{[^}]*\b${symbol}\b[^}]*\})`);
|
|
2161
|
+
return re.test(content);
|
|
2162
|
+
}
|
|
2163
|
+
function containsReExport(file, content, symbol) {
|
|
2164
|
+
const star = /export\s*\*\s*from\s*['"](.+)['"]/g;
|
|
2165
|
+
let m;
|
|
2166
|
+
while ((m = star.exec(content))) {
|
|
2167
|
+
const resolved = resolveReExport(file, m[1]);
|
|
2168
|
+
if (!resolved) {
|
|
2169
|
+
continue;
|
|
2170
|
+
}
|
|
2171
|
+
const nested = safeReadFile(resolved);
|
|
2172
|
+
if (nested && containsDirectExport(nested, symbol)) {
|
|
2095
2173
|
return true;
|
|
2096
2174
|
}
|
|
2097
2175
|
}
|
|
2098
|
-
|
|
2099
|
-
|
|
2176
|
+
const named = new RegExp(String.raw `export\s*\{[^}]*\b${symbol}\b[^}]*\}\s*from\s*['"](.+)['"]`);
|
|
2177
|
+
const nm = named.exec(content);
|
|
2178
|
+
if (nm) {
|
|
2179
|
+
const resolved = resolveReExport(file, nm[1]);
|
|
2180
|
+
if (!resolved) {
|
|
2181
|
+
return false;
|
|
2182
|
+
}
|
|
2183
|
+
const nested = safeReadFile(resolved);
|
|
2184
|
+
if (nested && containsDirectExport(nested, symbol)) {
|
|
2185
|
+
return true;
|
|
2186
|
+
}
|
|
2100
2187
|
}
|
|
2101
|
-
|
|
2102
|
-
const hasNested = nested.some((path) => path !== `${entryRoot}/ng-package.json`);
|
|
2103
|
-
entryPointCache.set(entryRoot, hasNested);
|
|
2104
|
-
return hasNested;
|
|
2188
|
+
return false;
|
|
2105
2189
|
}
|
|
2106
|
-
function
|
|
2107
|
-
const
|
|
2108
|
-
return
|
|
2190
|
+
function resolveReExport(file, rel) {
|
|
2191
|
+
const full = path.resolve(path.dirname(file), rel);
|
|
2192
|
+
return fs.existsSync(full) ? full : null;
|
|
2109
2193
|
}
|
|
2110
|
-
function
|
|
2111
|
-
|
|
2112
|
-
|
|
2194
|
+
function cachedNearestNg(file, root) {
|
|
2195
|
+
const key = `${file}|${root}`;
|
|
2196
|
+
if (nearestNgCache.has(key)) {
|
|
2197
|
+
return nearestNgCache.get(key);
|
|
2113
2198
|
}
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2199
|
+
let dir = path.dirname(file);
|
|
2200
|
+
while (dir.startsWith(root)) {
|
|
2201
|
+
const candidate = path.join(dir, 'ng-package.json');
|
|
2202
|
+
if (fs.existsSync(candidate)) {
|
|
2203
|
+
nearestNgCache.set(key, dir);
|
|
2204
|
+
return dir;
|
|
2205
|
+
}
|
|
2206
|
+
const parent = path.dirname(dir);
|
|
2207
|
+
if (parent === dir) {
|
|
2208
|
+
break;
|
|
2209
|
+
}
|
|
2210
|
+
dir = parent;
|
|
2211
|
+
}
|
|
2212
|
+
nearestNgCache.set(key, null);
|
|
2213
|
+
return null;
|
|
2119
2214
|
}
|
|
2120
|
-
function
|
|
2121
|
-
const
|
|
2122
|
-
const
|
|
2123
|
-
|
|
2124
|
-
|
|
2215
|
+
function buildImports(node, baseImport, symbolMap) {
|
|
2216
|
+
const isTypeOnly = node.importKind === 'type';
|
|
2217
|
+
const groups = new Map();
|
|
2218
|
+
for (const [symbol, suffix] of symbolMap.entries()) {
|
|
2219
|
+
const target = suffix ? `${baseImport}/${suffix}` : baseImport;
|
|
2220
|
+
if (!groups.has(target)) {
|
|
2221
|
+
groups.set(target, []);
|
|
2222
|
+
}
|
|
2223
|
+
groups.get(target).push(symbol);
|
|
2224
|
+
}
|
|
2225
|
+
const result = [];
|
|
2226
|
+
for (const [target, symbols] of groups.entries()) {
|
|
2227
|
+
const importParts = symbols.map((symbol) => {
|
|
2228
|
+
const sp = node.specifiers.find((s) => s.type === AST_NODE_TYPES$1.ImportSpecifier &&
|
|
2229
|
+
(s.imported.type === AST_NODE_TYPES$1.Identifier
|
|
2230
|
+
? s.imported.name === symbol
|
|
2231
|
+
: s.imported.value === symbol));
|
|
2232
|
+
if (!sp) {
|
|
2233
|
+
return symbol;
|
|
2234
|
+
}
|
|
2235
|
+
const local = sp.local.name;
|
|
2236
|
+
return symbol === local ? symbol : `${symbol} as ${local}`;
|
|
2237
|
+
});
|
|
2238
|
+
result.push(`import ${isTypeOnly ? 'type ' : ''}{${importParts.join(', ')}} from '${target}';`);
|
|
2125
2239
|
}
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2240
|
+
return result.join('\n');
|
|
2241
|
+
}
|
|
2242
|
+
function safeReadFile(file) {
|
|
2243
|
+
try {
|
|
2244
|
+
return fs.readFileSync(file, 'utf8');
|
|
2245
|
+
}
|
|
2246
|
+
catch {
|
|
2247
|
+
return null;
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
function normalizeFilter(filter) {
|
|
2251
|
+
const arr = Array.isArray(filter) ? filter : [filter];
|
|
2252
|
+
return arr.map((item) => {
|
|
2253
|
+
if (typeof item === 'string' && item.startsWith('/') && item.endsWith('/')) {
|
|
2254
|
+
const body = item.slice(1, -1);
|
|
2255
|
+
return new RegExp(body);
|
|
2256
|
+
}
|
|
2257
|
+
return item;
|
|
2258
|
+
});
|
|
2130
2259
|
}
|
|
2131
2260
|
|
|
2132
2261
|
function getImportedName(spec) {
|
package/package.json
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
-
type
|
|
2
|
+
type RuleOptions = [
|
|
3
3
|
{
|
|
4
4
|
importFilter: string[] | string;
|
|
5
5
|
strict?: boolean;
|
|
6
|
-
mockPaths?: Record<string, string>;
|
|
7
6
|
}
|
|
8
7
|
];
|
|
9
|
-
declare const _default: ESLintUtils.RuleModule<"prefer-deep-imports",
|
|
8
|
+
declare const _default: ESLintUtils.RuleModule<"prefer-deep-imports", RuleOptions, unknown, ESLintUtils.RuleListener>;
|
|
10
9
|
export default _default;
|