@pnpm/package-bins
Version:
Returns bins of a package
62 lines • 2.26 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getBinsFromPackageManifest = getBinsFromPackageManifest;
const path_1 = __importDefault(require("path"));
const tinyglobby_1 = require("tinyglobby");
const is_subdir_1 = __importDefault(require("is-subdir"));
async function getBinsFromPackageManifest(manifest, pkgPath) {
if (manifest.bin) {
return commandsFromBin(manifest.bin, manifest.name, pkgPath);
}
if (manifest.directories?.bin) {
const binDir = path_1.default.join(pkgPath, manifest.directories.bin);
// Validate: directories.bin must be within the package root
if (!(0, is_subdir_1.default)(pkgPath, binDir)) {
return [];
}
const files = await findFiles(binDir);
return files.map((file) => ({
name: path_1.default.basename(file),
path: path_1.default.join(binDir, file),
}));
}
return [];
}
async function findFiles(dir) {
try {
return await (0, tinyglobby_1.glob)('**', {
cwd: dir,
onlyFiles: true,
followSymbolicLinks: false,
expandDirectories: false,
});
}
catch (err) { // eslint-disable-line
if (err.code !== 'ENOENT') {
throw err;
}
return [];
}
}
function commandsFromBin(bin, pkgName, pkgPath) {
const cmds = [];
for (const [commandName, binRelativePath] of typeof bin === 'string' ? [[pkgName, bin]] : Object.entries(bin)) {
const binName = commandName[0] === '@'
? commandName.slice(commandName.indexOf('/') + 1)
: commandName;
// Validate: must be safe (no path traversal) - only allow URL-safe chars or $
if (binName !== encodeURIComponent(binName) && binName !== '$') {
continue;
}
const binPath = path_1.default.join(pkgPath, binRelativePath);
if (!(0, is_subdir_1.default)(pkgPath, binPath)) {
continue;
}
cmds.push({ name: binName, path: binPath });
}
return cmds;
}
//# sourceMappingURL=index.js.map