eslint-plugin-export-scope
Version:
Don't leak LOCAL utils, states, components into the global scope
173 lines • 6.85 kB
JavaScript
Object.defineProperty(exports, "__esModule", { value: true });
exports.isSubPath = exports.getPathContext = exports.PathContextType = exports.generateAncestorPaths = exports.validateExceptionPath = exports.validateScopePath = exports.isAncestorPath = exports.getFullScopePath = exports.getRootDir = exports.getPathOfTheNearestConfig = exports.toPosix = exports.sameOrSubPath = void 0;
const fs_1 = require("fs");
const path_1 = require("path");
// Platform-aware path operations
const isWin = process.platform === "win32";
const fold = (s) => (isWin ? s.toLowerCase() : s);
/** child is same as base or inside base (logical tree only). */
const sameOrSubPath = (base, child) => {
const a = fold((0, path_1.resolve)(base));
const b = fold((0, path_1.resolve)(child));
if (a === b)
return true;
const rel = (0, path_1.relative)(a, b);
return rel !== "" && !rel.startsWith("..") && !(0, path_1.isAbsolute)(rel);
};
exports.sameOrSubPath = sameOrSubPath;
exports.isSubPath = exports.sameOrSubPath;
const toPosix = (p) => p.replace(/\\/g, "/");
exports.toPosix = toPosix;
// Config and root directory utilities
const nearestConfigMap = new Map();
const getPathOfTheNearestConfig = (originPath, configFileName) => {
const configFileNames = Array.isArray(configFileName) ? configFileName : [configFileName];
const key = [originPath, configFileNames.join("_")].join("_");
if (nearestConfigMap.has(key)) {
return nearestConfigMap.get(key);
}
const cacheResult = (result) => {
nearestConfigMap.set(key, result);
// clear cache after 1 second
setTimeout(() => nearestConfigMap.delete(key), 1000);
return result;
};
let currentDir = originPath;
while (currentDir !== "/") {
const fileNames = (0, fs_1.readdirSync)(currentDir);
const fileName = fileNames.find((x) => configFileNames.includes(x));
if (fileName) {
return cacheResult((0, path_1.resolve)(currentDir, fileName));
}
if (fileNames.includes("package.json")) {
return cacheResult(null);
}
currentDir = (0, path_1.dirname)(currentDir);
}
return cacheResult(null);
};
exports.getPathOfTheNearestConfig = getPathOfTheNearestConfig;
const getRootDir = (originPath) => {
const configPath = (0, exports.getPathOfTheNearestConfig)(originPath, "package.json");
return configPath ? (0, path_1.dirname)(configPath) : null;
};
exports.getRootDir = getRootDir;
const getFullScopePath = (exportDir, scope) => {
if (scope.startsWith(".")) {
return (0, path_1.resolve)(exportDir, scope);
}
const rootDir = (0, exports.getRootDir)(exportDir);
if (!rootDir)
return null;
return (0, path_1.resolve)(rootDir, scope);
};
exports.getFullScopePath = getFullScopePath;
/**
* Check if a path is an ancestor of the current directory (or is the current directory)
*/
const isAncestorPath = (currentDir, targetPath) => {
// Use sameOrSubPath: target is ancestor if current is same or sub path of target
return (0, exports.sameOrSubPath)(targetPath, currentDir);
};
exports.isAncestorPath = isAncestorPath;
/**
* Validate a scope path for export default, @scope, and @scopeDefault
* These should only allow ancestor directories or "*"
*/
const validateScopePath = (currentDir, scopePath) => {
// Always allow wildcard
if (scopePath === "*") {
return { isValid: true };
}
// Always allow current directory
if (scopePath === ".") {
return { isValid: true, resolvedPath: currentDir, isAncestor: true };
}
const fullPath = (0, exports.getFullScopePath)(currentDir, scopePath);
if (!fullPath) {
return { isValid: false };
}
const isAncestor = (0, exports.isAncestorPath)(currentDir, fullPath);
return {
isValid: isAncestor,
resolvedPath: fullPath,
isAncestor,
};
};
exports.validateScopePath = validateScopePath;
/**
* Validate an exception path - can be any valid filesystem path
*/
const validateExceptionPath = (currentDir, exceptionPath) => {
const fullPath = (0, exports.getFullScopePath)(currentDir, exceptionPath);
if (!fullPath) {
return { isValid: false };
}
return {
isValid: (0, fs_1.existsSync)(fullPath),
resolvedPath: fullPath,
isAncestor: (0, exports.isAncestorPath)(currentDir, fullPath),
};
};
exports.validateExceptionPath = validateExceptionPath;
/**
* Generate all possible ancestor paths for autocompletion
*/
const generateAncestorPaths = (currentDir, rootDir) => {
const paths = ["."];
let current = currentDir;
let levelsUp = 0;
const maxLevels = 10; // Reasonable limit
while (current !== rootDir && levelsUp < maxLevels) {
current = (0, path_1.dirname)(current);
levelsUp++;
// Add relative path (../, ../../, etc.)
const relativePath = Array(levelsUp).fill("..").join("/");
paths.push(relativePath);
// Add absolute path from root
const relativeToRoot = (0, path_1.relative)(rootDir, current);
if (relativeToRoot && relativeToRoot !== ".") {
paths.push(relativeToRoot);
}
}
return paths;
};
exports.generateAncestorPaths = generateAncestorPaths;
/**
* Get path type for determining completion behavior
*/
var PathContextType;
(function (PathContextType) {
PathContextType["SCOPE_DEFAULT_EXPORT"] = "scope_default_export";
PathContextType["SCOPE_JSDOC"] = "scope_jsdoc";
PathContextType["SCOPE_DEFAULT_JSDOC"] = "scope_default_jsdoc";
PathContextType["SCOPE_EXCEPTION_JSDOC"] = "scope_exception_jsdoc";
PathContextType["EXCEPTIONS_ARRAY"] = "exceptions_array";
})(PathContextType || (exports.PathContextType = PathContextType = {}));
const getPathContext = (text, position) => {
const textBeforePosition = text.substring(0, position);
// Check for export default in .scope files
if (textBeforePosition.includes("export default") && text.includes(".scope.")) {
return PathContextType.SCOPE_DEFAULT_EXPORT;
}
// Check for JSDoc contexts
if (textBeforePosition.includes("@scope ") &&
!textBeforePosition.includes("@scopeDefault") &&
!textBeforePosition.includes("@scopeException")) {
return PathContextType.SCOPE_JSDOC;
}
if (textBeforePosition.includes("@scopeDefault")) {
return PathContextType.SCOPE_DEFAULT_JSDOC;
}
if (textBeforePosition.includes("@scopeException")) {
return PathContextType.SCOPE_EXCEPTION_JSDOC;
}
// Check for exceptions array
if (textBeforePosition.includes("export const exceptions")) {
return PathContextType.EXCEPTIONS_ARRAY;
}
return null;
};
exports.getPathContext = getPathContext;
//# sourceMappingURL=pathUtils.js.map
;