eslint-plugin-export-scope
Version:
Don't leak LOCAL utils, states, components into the global scope
106 lines • 5.18 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.checkIsImportable = exports.SCOPE_JS_FILE_NAME = exports.SCOPE_TS_FILE_NAME = void 0;
const path_1 = __importDefault(require("path"));
const typescript_1 = require("typescript");
const utils_1 = require("./utils");
const tsUtils_1 = require("./tsPlugin/tsUtils");
exports.SCOPE_TS_FILE_NAME = ".scope.ts";
exports.SCOPE_JS_FILE_NAME = ".scope.js";
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, utils_1.getFullScopePath)(exportDir, exception);
if (exceptionFullPath && (0, utils_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(/ \s+([^\s]+)/) ?? [];
}
getFolderScope: {
if (scope)
break getFolderScope;
let scopeFile = tsProgram.getSourceFile(path_1.default.join(exportDir, exports.SCOPE_TS_FILE_NAME));
scopeFile ?? (scopeFile = tsProgram.getSourceFile(path_1.default.join(exportDir, exports.SCOPE_JS_FILE_NAME)));
if (isIndexFile) {
const parentDir = path_1.default.dirname(exportDir);
scopeFile ?? (scopeFile = tsProgram.getSourceFile(path_1.default.join(parentDir, exports.SCOPE_TS_FILE_NAME)));
scopeFile ?? (scopeFile = tsProgram.getSourceFile(path_1.default.join(parentDir, exports.SCOPE_JS_FILE_NAME)));
}
if (!scopeFile) {
const rootDir = (0, utils_1.getRootDir)(exportDir);
if (rootDir) {
scopeFile ?? (scopeFile = tsProgram.getSourceFile(path_1.default.join(rootDir, exports.SCOPE_TS_FILE_NAME)));
scopeFile ?? (scopeFile = tsProgram.getSourceFile(path_1.default.join(rootDir, exports.SCOPE_JS_FILE_NAME)));
}
}
if (!scopeFile)
break getFolderScope;
const symbols = tsProgram.getTypeChecker().getSymbolAtLocation(scopeFile);
const defaultExportValDecl = symbols?.exports?.get("default")?.valueDeclaration;
const exceptionsValDecl = symbols?.exports?.get("exceptions")?.valueDeclaration;
if ((0, tsUtils_1.isExportAssignment)(defaultExportValDecl)) {
scope = defaultExportValDecl.expression.getText().slice(1, -1);
}
if ((0, tsUtils_1.isVariableDeclaration)(exceptionsValDecl) && (0, tsUtils_1.isArrayLiteralExpression)(exceptionsValDecl.initializer)) {
const exceptions = exceptionsValDecl.initializer.elements.map((x) => x.getText());
for (const exception of exceptions) {
const exceptionFullPath = (0, utils_1.getFullScopePath)(exportDir, exception.slice(1, -1));
if (!exceptionFullPath)
continue;
if ((0, utils_1.isSubPath)(exceptionFullPath, importPath)) {
return true;
}
}
}
}
// handles index files
scope ?? (scope = isIndexFile ? ".." : ".");
if (scope === "*")
return true;
const fullScopePath = (0, utils_1.getFullScopePath)(exportDir, scope);
if (!fullScopePath)
return true;
return (0, utils_1.isSubPath)(fullScopePath, importPath);
};
exports.checkIsImportable = checkIsImportable;
//# sourceMappingURL=checkIsImportable.js.map