UNPKG

pretty-quick

Version:
284 lines (272 loc) 9.97 kB
import fs from "fs"; import path from "path"; import ignore from "ignore"; import picomatch from "picomatch"; import fs$1 from "fs/promises"; import { check, format, getFileInfo, resolveConfig } from "prettier"; import { findUp } from "@pkgr/core"; import { exec } from "tinyexec"; //#region rolldown:runtime var __defProp = Object.defineProperty; var __getOwnPropNames = Object.getOwnPropertyNames; var __esm = (fn, res) => function() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __commonJS = (cb, mod) => function() { return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; }; var __export = (target, all) => { for (var name$2 in all) __defProp(target, name$2, { get: all[name$2], enumerable: true }); }; //#endregion //#region src/createIgnorer.ts function createIgnorer(directory, filename = ".prettierignore") { const file = path.join(directory, filename); if (fs.existsSync(file)) { const text = fs.readFileSync(file, "utf8"); const filter = ignore().add(text).createFilter(); return (filepath) => filter(path.join(filepath)); } return () => true; } var init_createIgnorer = __esm({ "src/createIgnorer.ts"() {} }); //#endregion //#region src/createMatcher.ts function createMatcher(pattern) { if (typeof pattern !== "string" && !Array.isArray(pattern)) return () => true; const patterns = Array.isArray(pattern) ? pattern : [pattern]; const isMatch = picomatch(patterns, { dot: true }); return (file) => isMatch(path.normalize(file)); } var init_createMatcher = __esm({ "src/createMatcher.ts"() {} }); //#endregion //#region src/isSupportedExtension.ts var isSupportedExtension, isSupportedExtension_default; var init_isSupportedExtension = __esm({ "src/isSupportedExtension.ts"() { isSupportedExtension = (resolveConfig$1) => async (file) => { const stat = await fs$1.stat(file).catch((_error) => null); if (stat === null || stat === void 0 ? void 0 : stat.isDirectory()) return false; const config = await resolveConfig(file, { editorconfig: true }); const fileInfo = await getFileInfo(file, { resolveConfig: resolveConfig$1, ...config }); return !!fileInfo.inferredParser; }; isSupportedExtension_default = isSupportedExtension; } }); //#endregion //#region src/processFiles.ts async function processFiles(directory, files, { check: check$1, config, onExamineFile, onCheckFile, onWriteFile } = {}) { for (const relative of files) { onExamineFile === null || onExamineFile === void 0 || onExamineFile(relative); const file = path.join(directory, relative); const options = { ...await resolveConfig(file, { config, editorconfig: true }), filepath: file }; const input = fs.readFileSync(file, "utf8"); if (check$1) { const isFormatted = await check(input, options); onCheckFile === null || onCheckFile === void 0 || onCheckFile(relative, isFormatted); continue; } const output = await format(input, options); if (output !== input) { fs.writeFileSync(file, output); await (onWriteFile === null || onWriteFile === void 0 ? void 0 : onWriteFile(relative)); } } } var init_processFiles = __esm({ "src/processFiles.ts"() {} }); //#endregion //#region src/scms/git.ts var git_exports = {}; __export(git_exports, { detect: () => detect$1, getChangedFiles: () => getChangedFiles$1, getSinceRevision: () => getSinceRevision$1, getUnstagedChangedFiles: () => getUnstagedChangedFiles$1, name: () => name$1, stageFile: () => stageFile$1 }); var name$1, detect$1, runGit, getLines$1, getSinceRevision$1, getChangedFiles$1, getUnstagedChangedFiles$1, stageFile$1; var init_git = __esm({ "src/scms/git.ts"() { name$1 = "git"; detect$1 = (directory) => { const found = findUp(path.resolve(directory), ".git", true); return found ? path.dirname(found) : null; }; runGit = (directory, args) => exec("git", args, { nodeOptions: { cwd: directory } }); getLines$1 = (tinyexecOutput) => tinyexecOutput.stdout.split("\n"); getSinceRevision$1 = async (directory, { staged, branch }) => { try { let revision = "HEAD"; if (!staged) { const revisionOutput = await runGit(directory, [ "merge-base", "HEAD", branch || "master" ]); revision = revisionOutput.stdout.trim(); } const revParseOutput = await runGit(directory, [ "rev-parse", "--short", revision ]); return revParseOutput.stdout.trim(); } catch (err) { const error = err; if (/HEAD/.test(error.message) || staged && /Needed a single revision/.test(error.message)) return null; throw error; } }; getChangedFiles$1 = async (directory, revision, staged) => [...getLines$1(await runGit(directory, [ "diff", "--name-only", staged ? "--cached" : null, "--diff-filter=ACMRTUB", revision ].filter(Boolean))), ...staged ? [] : getLines$1(await runGit(directory, [ "ls-files", "--others", "--exclude-standard" ]))].filter(Boolean); getUnstagedChangedFiles$1 = (directory) => { return getChangedFiles$1(directory, null, false); }; stageFile$1 = (directory, file) => runGit(directory, ["add", file]); } }); //#endregion //#region src/scms/hg.ts var hg_exports = {}; __export(hg_exports, { detect: () => detect, getChangedFiles: () => getChangedFiles, getSinceRevision: () => getSinceRevision, getUnstagedChangedFiles: () => getUnstagedChangedFiles, name: () => name, stageFile: () => stageFile }); var name, detect, runHg, getLines, getSinceRevision, getChangedFiles, getUnstagedChangedFiles, stageFile; var init_hg = __esm({ "src/scms/hg.ts"() { name = "hg"; detect = (directory) => { const found = findUp(path.resolve(directory), ".hg", true); if (found && fs.statSync(found).isDirectory()) return path.dirname(found); }; runHg = (directory, args) => exec("hg", args, { nodeOptions: { cwd: directory } }); getLines = (tinyexecOutput) => tinyexecOutput.stdout.split("\n"); getSinceRevision = async (directory, { branch }) => { const revisionOutput = await runHg(directory, [ "debugancestor", "tip", branch || "default" ]); const revision = revisionOutput.stdout.trim(); const hgOutput = await runHg(directory, [ "id", "-i", "-r", revision ]); return hgOutput.stdout.trim(); }; getChangedFiles = async (directory, revision, _staged) => [...getLines(await runHg(directory, [ "status", "-n", "-a", "-m", ...revision ? ["--rev", revision] : [] ]))].filter(Boolean); getUnstagedChangedFiles = () => []; stageFile = (directory, file) => runHg(directory, ["add", file]); } }); //#endregion //#region src/scms/index.ts function detectScm(directory) { for (const scm of scms) { const rootDirectory = scm.detect(directory); if (rootDirectory) return { rootDirectory, ...scm }; } } var scms; var init_scms = __esm({ "src/scms/index.ts"() { init_git(); init_hg(); scms = [git_exports, hg_exports]; } }); //#endregion //#region src/utils.ts var filterAsync; var init_utils = __esm({ "src/utils.ts"() { filterAsync = async (items, predicate) => { const boolItems = await Promise.all(items.map(predicate)); return items.filter((_, i) => boolItems[i]); }; } }); //#endregion //#region src/index.ts var require_src = __commonJS({ "src/index.ts"(exports, module) { init_createIgnorer(); init_createMatcher(); init_isSupportedExtension(); init_processFiles(); init_scms(); init_utils(); module.exports = async function prettyQuick(currentDirectory, { config, since, staged, pattern, restage = true, branch, bail, check: check$1, ignorePath, verbose, onFoundSinceRevision, onFoundChangedFiles, onPartiallyStagedFile, onExamineFile, onCheckFile, onWriteFile, resolveConfig: resolveConfig$1 = true } = {}) { const scm = detectScm(currentDirectory); if (!scm) throw new Error("Unable to detect a source control manager."); const directory = scm.rootDirectory; const revision = since || await scm.getSinceRevision(directory, { staged, branch }); onFoundSinceRevision === null || onFoundSinceRevision === void 0 || onFoundSinceRevision(scm.name, revision); const rootIgnorer = createIgnorer(directory, ignorePath); const cwdIgnorer = currentDirectory === directory ? () => true : createIgnorer(currentDirectory, ignorePath); const patternMatcher = createMatcher(pattern); const isFileSupportedExtension = isSupportedExtension_default(resolveConfig$1); const unfilteredChangedFiles = await scm.getChangedFiles(directory, revision, staged); const changedFiles = await filterAsync(unfilteredChangedFiles.filter(patternMatcher).filter(rootIgnorer).filter(cwdIgnorer), isFileSupportedExtension); const unfilteredStagedFiles = await scm.getUnstagedChangedFiles(directory); const unstagedFiles = staged ? await filterAsync(unfilteredStagedFiles.filter(patternMatcher).filter(rootIgnorer).filter(cwdIgnorer), isFileSupportedExtension) : []; const wasFullyStaged = (file) => !unstagedFiles.includes(file); onFoundChangedFiles === null || onFoundChangedFiles === void 0 || onFoundChangedFiles(changedFiles); const failReasons = /* @__PURE__ */ new Set(); await processFiles(directory, changedFiles, { check: check$1, config, onWriteFile: async (file) => { await (onWriteFile === null || onWriteFile === void 0 ? void 0 : onWriteFile(file)); if (bail) failReasons.add("BAIL_ON_WRITE"); if (staged && restage) if (wasFullyStaged(file)) await scm.stageFile(directory, file); else { onPartiallyStagedFile === null || onPartiallyStagedFile === void 0 || onPartiallyStagedFile(file); failReasons.add("PARTIALLY_STAGED_FILE"); } }, onCheckFile: (file, isFormatted) => { onCheckFile === null || onCheckFile === void 0 || onCheckFile(file, isFormatted); if (!isFormatted) failReasons.add("CHECK_FAILED"); }, onExamineFile: verbose ? onExamineFile : void 0 }); return { success: failReasons.size === 0, errors: [...failReasons] }; }; } }); //#endregion export default require_src();