hardhat
Version:
Hardhat is an extensible developer tool that helps smart contract developers increase productivity by reliably bringing together the tools they want.
201 lines • 7.96 kB
JavaScript
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.includesOwnPackageName = exports.replaceBackslashes = exports.isAbsolutePathSourceName = exports.normalizeSourceName = exports.localSourceNameToPath = exports.localPathToSourceName = exports.validateSourceNameExistenceAndCasing = exports.isLocalSourceName = exports.validateSourceNameFormat = void 0;
const path_1 = __importDefault(require("path"));
const errors_1 = require("../internal/core/errors");
const errors_list_1 = require("../internal/core/errors-list");
const fs_utils_1 = require("../internal/util/fs-utils");
const packageInfo_1 = require("../internal/util/packageInfo");
const NODE_MODULES = "node_modules";
/**
* This function validates the source name's format.
*
* It throws if the format is invalid.
* If it doesn't throw all you know is that the format is valid.
*/
function validateSourceNameFormat(sourceName) {
if (isAbsolutePathSourceName(sourceName)) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.INVALID_SOURCE_NAME_ABSOLUTE_PATH, {
name: sourceName,
});
}
if (isExplicitRelativePath(sourceName)) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.INVALID_SOURCE_NAME_RELATIVE_PATH, {
name: sourceName,
});
}
// We check this before normalizing so we are sure that the difference
// comes from slash vs backslash
if (replaceBackslashes(sourceName) !== sourceName) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.INVALID_SOURCE_NAME_BACKSLASHES, {
name: sourceName,
});
}
if (normalizeSourceName(sourceName) !== sourceName) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.INVALID_SOURCE_NOT_NORMALIZED, {
name: sourceName,
});
}
}
exports.validateSourceNameFormat = validateSourceNameFormat;
/**
* This function returns true if the sourceName is, potentially, from a local
* file. It doesn't validate that the file actually exists.
*
* The source name must be in a valid format.
*/
async function isLocalSourceName(projectRoot, sourceName) {
// Note that we consider "hardhat/console.sol" as a special case here.
// This lets someone have a "hardhat" directory within their project without
// it impacting their use of `console.log`.
// See issue https://github.com/nomiclabs/hardhat/issues/998
if (sourceName.includes(NODE_MODULES) ||
sourceName === "hardhat/console.sol") {
return false;
}
const slashIndex = sourceName.indexOf("/");
const firstDirOrFileName = slashIndex !== -1 ? sourceName.substring(0, slashIndex) : sourceName;
try {
await (0, fs_utils_1.getFileTrueCase)(projectRoot, firstDirOrFileName);
}
catch (error) {
if (error instanceof fs_utils_1.FileNotFoundError) {
return false;
}
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
throw error;
}
return true;
}
exports.isLocalSourceName = isLocalSourceName;
/**
* Validates that a source name exists, starting from `fromDir`, and has the
* right casing.
*
* The source name must be in a valid format.
*/
async function validateSourceNameExistenceAndCasing(fromDir, sourceName) {
const trueCaseSourceName = await getSourceNameTrueCase(fromDir, sourceName);
if (trueCaseSourceName !== sourceName) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.WRONG_CASING, {
incorrect: sourceName,
correct: trueCaseSourceName,
});
}
}
exports.validateSourceNameExistenceAndCasing = validateSourceNameExistenceAndCasing;
/**
* Returns the source name of an existing local file's absolute path.
*
* Throws is the file doesn't exist, it's not inside the project, or belongs
* to a library.
*/
async function localPathToSourceName(projectRoot, localFileAbsolutePath) {
const relativePath = path_1.default.relative(projectRoot, localFileAbsolutePath);
const normalized = normalizeSourceName(relativePath);
if (normalized.startsWith("..")) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.EXTERNAL_AS_LOCAL, {
path: localFileAbsolutePath,
});
}
if (normalized.includes(NODE_MODULES)) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.NODE_MODULES_AS_LOCAL, {
path: localFileAbsolutePath,
});
}
return getSourceNameTrueCase(projectRoot, relativePath);
}
exports.localPathToSourceName = localPathToSourceName;
/**
* This function takes a valid local source name and returns its path. The
* source name doesn't need to point to an existing file.
*/
function localSourceNameToPath(projectRoot, sourceName) {
return path_1.default.join(projectRoot, sourceName);
}
exports.localSourceNameToPath = localSourceNameToPath;
/**
* Normalizes the source name, for example, by replacing `a/./b` with `a/b`.
*
* The sourceName param doesn't have to be a valid source name. It can,
* for example, be denormalized.
*/
function normalizeSourceName(sourceName) {
return replaceBackslashes(path_1.default.normalize(sourceName));
}
exports.normalizeSourceName = normalizeSourceName;
/**
* This function returns true if the sourceName is a unix absolute path or a
* platform-dependent one.
*
* This function is used instead of just `path.isAbsolute` to ensure that
* source names never start with `/`, even on Windows.
*/
function isAbsolutePathSourceName(sourceName) {
return path_1.default.isAbsolute(sourceName) || sourceName.startsWith("/");
}
exports.isAbsolutePathSourceName = isAbsolutePathSourceName;
/**
* This function returns true if the sourceName is a unix path that is based on
* the current directory `./`.
*/
function isExplicitRelativePath(sourceName) {
const [base] = sourceName.split("/", 1);
return base === "." || base === "..";
}
/**
* This function replaces backslashes (\\) with slashes (/).
*
* Note that a source name must not contain backslashes.
*/
function replaceBackslashes(str) {
// Based in the npm module slash
const isExtendedLengthPath = /^\\\\\?\\/.test(str);
const hasNonAscii = /[^\u0000-\u0080]+/.test(str);
if (isExtendedLengthPath || hasNonAscii) {
return str;
}
return str.replace(/\\/g, "/");
}
exports.replaceBackslashes = replaceBackslashes;
function slashesToPathSeparator(str) {
if (path_1.default.sep === "/") {
return str;
}
return str.replace(/\//g, path_1.default.sep);
}
/**
* Returns the true casing of `p` as a relative path from `fromDir`. Throws if
* `p` doesn't exist. `p` MUST be in source name format.
*/
async function getSourceNameTrueCase(fromDir, p) {
try {
const realCase = await (0, fs_utils_1.getFileTrueCase)(fromDir, slashesToPathSeparator(p));
return normalizeSourceName(realCase);
}
catch (error) {
if (error instanceof fs_utils_1.FileNotFoundError) {
throw new errors_1.HardhatError(errors_list_1.ERRORS.SOURCE_NAMES.FILE_NOT_FOUND, {
name: p,
}, error);
}
// eslint-disable-next-line @nomicfoundation/hardhat-internal-rules/only-hardhat-error
throw error;
}
}
/**
* This function returns true if the sourceName contains the current package's name
* as a substring
*/
async function includesOwnPackageName(sourceName) {
const packageName = await (0, packageInfo_1.getPackageName)(sourceName);
if (packageName !== "") {
return sourceName.startsWith(`${packageName}/`);
}
return false;
}
exports.includesOwnPackageName = includesOwnPackageName;
//# sourceMappingURL=source-names.js.map
;