git-command-helper
Version:
github command helper for nodejs
124 lines (121 loc) • 3.91 kB
JavaScript
// git-command-helper 2.1.0 by Dimas Lanjaka <dimaslanjaka@gmail.com> (https://www.webmanajemen.com)
import Bluebird from 'bluebird';
import fs from 'fs-extra';
import * as glob from 'glob';
import ignore from 'ignore';
import { trueCasePathSync } from 'sbg-utility';
import path from 'upath';
import { getGithubRootDir } from './getGithubRootDir.mjs';
/**
* get all ignored files by .gitignore
* @param param0
* @returns
*/
const getIgnores = async ({
cwd = process.cwd()
}) => {
const searchDir = cwd;
const searchDirRootGit = await getGithubRootDir({
cwd: searchDir
});
if (!searchDirRootGit) throw new Error("cwd/search dir is not git");
const ignores = await getAllIgnoresConfig({
cwd: searchDir
});
const ig = ignore().add(ignores);
const files = await glob.glob("**", {
// Adds a / character to directory matches.
mark: true,
cwd: searchDir,
ignore: ["**/node_modules/**", "**/docs/**"],
posix: true
});
return Bluebird.all(files).map(async file => {
const absolute = trueCasePathSync(path.resolve(searchDir, file));
const dirname = path.dirname(absolute);
const rootGitOfFile = await getGithubRootDir({
cwd: dirname
});
// fail when root git is different
if (searchDirRootGit !== rootGitOfFile) return "";
const relative = path.relative(rootGitOfFile, absolute);
if (ig.ignores(relative)) {
return {
absolute,
relative: "/" + relative
};
} else {
return "";
}
}).filter(item => typeof item === "object");
};
/**
* is file ignored by `.gitignore`?
* @param filePath `absolute` file path, but `relative` path must have `options.cwd`
* @param options
* @returns
*/
async function isIgnored(filePath, options) {
const defaults = Object.assign({
cwd: path.dirname(filePath)
}, options || {});
if (defaults.cwd === ".") defaults.cwd = process.cwd();
// fix UNIX style
if (fs.existsSync(defaults.cwd)) defaults.cwd = trueCasePathSync(defaults.cwd, {
unix: true
});
/** git root directory */
const gitRoot = (await getGithubRootDir(defaults)) || "";
/** setup ignore module */
const patterns = await getAllIgnoresConfig({
cwd: gitRoot
});
const ig = ignore().add(patterns);
const relative = path.relative(gitRoot, filePath);
if (fs.existsSync(path.join(gitRoot, filePath)) || relative.startsWith(".")) {
// filePath parameter is relative to gitRoot
return ig.ignores(filePath.replace(/^[./]+/g, ""));
}
return ig.ignores(relative);
}
/**
* get and parse all `.gitignore` files
*/
async function getAllIgnoresConfig(options) {
const files = await getGitignoreFiles(options);
const lines = files.map(file => fs.readFileSync(file, "utf-8").split(/\r?\n/gm).map(str => str.trim())).flat().filter(str => str.length > 0 && !str.startsWith("#"));
return lines;
}
/**
* get all `.gitignore` files
* @param searchDir
* @returns
*/
function getGitignoreFiles(opt) {
const searchDirRootGit = getGithubRootDir(opt);
return new Bluebird(res => {
const ignore = ["**/node_modules/**"];
if (Array.isArray(opt.ignore)) {
ignore.push(...opt.ignore);
} else if (typeof opt.ignore === "string") {
ignore.push(opt.ignore);
}
Bluebird.resolve(glob.glob("**/.gitignore", Object.assign({
cwd: opt.cwd
}, opt, {
posix: true,
ignore
}))).then(result => {
return Bluebird.all(result.map(async filePath => {
const absolute = path.join(opt.cwd, filePath);
const dirname = path.dirname(absolute);
const rootGitOfFile = await getGithubRootDir({
cwd: dirname
});
if (rootGitOfFile !== (await searchDirRootGit)) return;
return trueCasePathSync(absolute);
})).filter(o => typeof o !== "undefined");
}).then(o => res(o));
});
}
export { getAllIgnoresConfig, getGitignoreFiles, getIgnores, isIgnored };