UNPKG

eslint-plugin-export-scope

Version:

Don't leak LOCAL utils, states, components into the global scope

131 lines 5.7 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.checkIsImportable = void 0; const path_1 = __importDefault(require("path")); const fs_1 = __importDefault(require("fs")); const typescript_1 = require("typescript"); const pathUtils_1 = require("./pathUtils"); const constants_1 = require("./constants"); const parseScopeFile_1 = require("./parseScopeFile"); const checkIsImportable = ({ tsProgram, importPath, exportPath, exportName, }) => { if (!importPath || !exportPath || exportPath.includes("node_modules")) return true; const exportFile = tsProgram.getSourceFile(exportPath); const exportDir = path_1.default.dirname(exportPath); let scope; if (!exportFile) return true; const isIndexFile = path_1.default.parse(exportFile.fileName).name === "index"; getLocalScope: { if (!exportName) break getLocalScope; const typeChecker = tsProgram.getTypeChecker(); const fileSymbol = typeChecker.getSymbolAtLocation(exportFile); const exports = fileSymbol && typeChecker.getExportsOfModule(fileSymbol); let exportSymbol = exports?.find((x) => x.name === exportName); if (!exportSymbol) break getLocalScope; if (exportName !== "default" && exportSymbol.flags & typescript_1.SymbolFlags.Alias) { exportSymbol = typeChecker.getImmediateAliasedSymbol(exportSymbol); } const jsDocTags = exportSymbol?.getJsDocTags(); if (!jsDocTags) break getLocalScope; for (const tag of jsDocTags) { if (tag.name === "scopeException") { const exception = tag.text?.at(0)?.text; if (!exception) continue; const exceptionFullPath = (0, pathUtils_1.getFullScopePath)(exportDir, exception); if (exceptionFullPath && (0, pathUtils_1.isSubPath)(exceptionFullPath, importPath)) { return true; } } if (tag.name === "scope") { scope = tag.text?.at(0)?.text; } } } getFileScope: { if (scope) break getFileScope; const firstStatementEndIndex = exportFile.statements[0]?.getEnd() ?? -1; const fileComments = exportFile.getFullText().slice(0, firstStatementEndIndex); [, scope] = fileComments.match(/@scopeDefault\s+([^\s]+)/) ?? []; } getFolderScope: { if (scope) break getFolderScope; let scopeFilePath = null; const rootDir = (0, pathUtils_1.getRootDir)(exportDir); // First, try regular scope files in current directory only for (const fileName of [constants_1.SCOPE_TS_FILE_NAME, constants_1.SCOPE_JS_FILE_NAME]) { const filePath = path_1.default.join(exportDir, fileName); if (fs_1.default.existsSync(filePath)) { scopeFilePath = filePath; break; } } // If index file, also check parent directory for regular scope files if (!scopeFilePath && isIndexFile) { const parentDir = path_1.default.dirname(exportDir); for (const fileName of [constants_1.SCOPE_TS_FILE_NAME, constants_1.SCOPE_JS_FILE_NAME]) { const filePath = path_1.default.join(parentDir, fileName); if (fs_1.default.existsSync(filePath)) { scopeFilePath = filePath; break; } } } // Then, recursively look for default scope files in current directory and ancestors if (!scopeFilePath) { let currentDir = exportDir; while (currentDir !== path_1.default.dirname(currentDir)) { for (const fileName of [constants_1.SCOPE_DEFAULT_TS_FILE_NAME, constants_1.SCOPE_DEFAULT_JS_FILE_NAME]) { const filePath = path_1.default.join(currentDir, fileName); if (fs_1.default.existsSync(filePath)) { scopeFilePath = filePath; break; } } if (scopeFilePath) break; // Stop when we reach or go beyond the root directory if (rootDir && currentDir === rootDir) break; currentDir = path_1.default.dirname(currentDir); } } // Parse the found scope file if (!scopeFilePath) break getFolderScope; try { const exports = (0, parseScopeFile_1.parseScopeFile)(scopeFilePath); scope = exports.scope; for (const exception of exports.exceptions) { const exceptionFullPath = (0, pathUtils_1.getFullScopePath)(exportDir, exception); if (!exceptionFullPath) continue; if ((0, pathUtils_1.isSubPath)(exceptionFullPath, importPath)) { return true; } } } catch { break getFolderScope; } } // handles index files scope ?? (scope = isIndexFile ? ".." : "."); if (scope === "*") return true; const fullScopePath = (0, pathUtils_1.getFullScopePath)(exportDir, scope); if (!fullScopePath) return true; return (0, pathUtils_1.isSubPath)(fullScopePath, importPath); }; exports.checkIsImportable = checkIsImportable; //# sourceMappingURL=checkIsImportable.js.map