UNPKG

pretty-quick

Version:
485 lines (473 loc) 14.9 kB
import fs from 'fs'; import path from 'path'; import ignore from 'ignore'; import picomatch from 'picomatch'; import fs$1 from 'fs/promises'; import { resolveConfig, getFileInfo, check, format } from 'prettier'; import findUp from 'find-up'; import { exec } from 'tinyexec'; var 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 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 __defProp$2 = Object.defineProperty; var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols; var __hasOwnProp$2 = Object.prototype.hasOwnProperty; var __propIsEnum$2 = Object.prototype.propertyIsEnumerable; var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$2 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); if (__getOwnPropSymbols$2) for (var prop of __getOwnPropSymbols$2(b)) { if (__propIsEnum$2.call(b, prop)) __defNormalProp$2(a, prop, b[prop]); } return a; }; var __async$5 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; var isSupportedExtension = (resolveConfig$1) => (file) => __async$5(void 0, null, function* () { const stat = yield fs$1.stat(file).catch((_error) => null); if (stat == null ? void 0 : stat.isDirectory()) { return false; } const config = yield resolveConfig(file, { editorconfig: true }); const fileInfo = yield getFileInfo(file, __spreadValues$2({ resolveConfig: resolveConfig$1 }, config)); return !!fileInfo.inferredParser; }); var __defProp$1 = Object.defineProperty; var __defProps = Object.defineProperties; var __getOwnPropDescs = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols; var __hasOwnProp$1 = Object.prototype.hasOwnProperty; var __propIsEnum$1 = Object.prototype.propertyIsEnumerable; var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$1 = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); if (__getOwnPropSymbols$1) for (var prop of __getOwnPropSymbols$1(b)) { if (__propIsEnum$1.call(b, prop)) __defNormalProp$1(a, prop, b[prop]); } return a; }; var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); var __async$4 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; var processFiles = (_0, _1, ..._2) => __async$4(void 0, [_0, _1, ..._2], function* (directory, files, { check: check$1, config, onExamineFile, onCheckFile, onWriteFile } = {}) { for (const relative of files) { onExamineFile == null ? void 0 : onExamineFile(relative); const file = path.join(directory, relative); const options = __spreadProps(__spreadValues$1({}, yield resolveConfig(file, { config, editorconfig: true })), { filepath: file }); const input = fs.readFileSync(file, "utf8"); if (check$1) { const isFormatted = yield check(input, options); onCheckFile == null ? void 0 : onCheckFile(relative, isFormatted); continue; } const output = yield format(input, options); if (output !== input) { fs.writeFileSync(file, output); yield onWriteFile == null ? void 0 : onWriteFile(relative); } } }); var __async$3 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const name$1 = "git"; const detect$1 = (directory) => { if (fs.existsSync(path.join(directory, ".git"))) { return directory; } const gitDirectory = findUp.sync(".git", { cwd: directory, type: "directory" }); const gitWorkTreeFile = findUp.sync(".git", { cwd: directory, type: "file" }); if (!gitDirectory && !gitWorkTreeFile) { return null; } if (gitDirectory && !gitWorkTreeFile) { return path.dirname(gitDirectory); } if (gitWorkTreeFile && !gitDirectory) { return path.dirname(gitWorkTreeFile); } const gitRepoDirectory = path.dirname(gitDirectory); const gitWorkTreeDirectory = path.dirname(gitWorkTreeFile); return gitRepoDirectory.length > gitWorkTreeDirectory.length ? gitRepoDirectory : gitWorkTreeDirectory; }; const runGit = (directory, args) => exec("git", args, { nodeOptions: { cwd: directory } }); const getLines$1 = (tinyexecOutput) => tinyexecOutput.stdout.split("\n"); const getSinceRevision$1 = (_0, _1) => __async$3(void 0, [_0, _1], function* (directory, { staged, branch }) { try { let revision = "HEAD"; if (!staged) { const revisionOutput = yield runGit(directory, [ "merge-base", "HEAD", branch || "master" ]); revision = revisionOutput.stdout.trim(); } const revParseOutput = yield 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; } }); const getChangedFiles$1 = (directory, revision, staged) => __async$3(void 0, null, function* () { return [ ...getLines$1( yield runGit( directory, [ "diff", "--name-only", staged ? "--cached" : null, "--diff-filter=ACMRTUB", revision ].filter(Boolean) ) ), ...staged ? [] : getLines$1( yield runGit(directory, [ "ls-files", "--others", "--exclude-standard" ]) ) ].filter(Boolean); }); const getUnstagedChangedFiles$1 = (directory) => { return getChangedFiles$1(directory, null, false); }; const stageFile$1 = (directory, file) => runGit(directory, ["add", file]); var gitScm = /*#__PURE__*/Object.freeze({ __proto__: null, detect: detect$1, getChangedFiles: getChangedFiles$1, getSinceRevision: getSinceRevision$1, getUnstagedChangedFiles: getUnstagedChangedFiles$1, name: name$1, stageFile: stageFile$1 }); var __async$2 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const name = "hg"; const detect = (directory) => { const hgDirectory = findUp.sync(".hg", { cwd: directory, type: "directory" }); if (hgDirectory) { return path.dirname(hgDirectory); } }; const runHg = (directory, args) => exec("hg", args, { nodeOptions: { cwd: directory } }); const getLines = (tinyexecOutput) => tinyexecOutput.stdout.split("\n"); const getSinceRevision = (_0, _1) => __async$2(void 0, [_0, _1], function* (directory, { branch }) { const revisionOutput = yield runHg(directory, [ "debugancestor", "tip", branch || "default" ]); const revision = revisionOutput.stdout.trim(); const hgOutput = yield runHg(directory, ["id", "-i", "-r", revision]); return hgOutput.stdout.trim(); }); const getChangedFiles = (directory, revision, _staged) => __async$2(void 0, null, function* () { return [ ...getLines( yield runHg(directory, [ "status", "-n", "-a", "-m", ...revision ? ["--rev", revision] : [] ]) ) ].filter(Boolean); }); const getUnstagedChangedFiles = () => []; const stageFile = (directory, file) => runHg(directory, ["add", file]); var hgScm = /*#__PURE__*/Object.freeze({ __proto__: null, detect: detect, getChangedFiles: getChangedFiles, getSinceRevision: getSinceRevision, getUnstagedChangedFiles: getUnstagedChangedFiles, name: name, stageFile: stageFile }); var __defProp = Object.defineProperty; var __getOwnPropSymbols = Object.getOwnPropertySymbols; var __hasOwnProp = Object.prototype.hasOwnProperty; var __propIsEnum = Object.prototype.propertyIsEnumerable; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]); if (__getOwnPropSymbols) for (var prop of __getOwnPropSymbols(b)) { if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]); } return a; }; const scms = [gitScm, hgScm]; var scms$1 = (directory) => { for (const scm of scms) { const rootDirectory = scm.detect(directory); if (rootDirectory) { return __spreadValues({ rootDirectory }, scm); } } }; var __async$1 = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; const filterAsync = (items, predicate) => __async$1(void 0, null, function* () { const boolItems = yield Promise.all(items.map(predicate)); return items.filter((_, i) => boolItems[i]); }); var __async = (__this, __arguments, generator) => { return new Promise((resolve, reject) => { var fulfilled = (value) => { try { step(generator.next(value)); } catch (e) { reject(e); } }; var rejected = (value) => { try { step(generator.throw(value)); } catch (e) { reject(e); } }; var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected); step((generator = generator.apply(__this, __arguments)).next()); }); }; module.exports = (_0, ..._1) => __async(undefined, [_0, ..._1], function* (currentDirectory, { config, since, staged, pattern, restage = true, branch, bail, check, ignorePath, verbose, onFoundSinceRevision, onFoundChangedFiles, onPartiallyStagedFile, onExamineFile, onCheckFile, onWriteFile, resolveConfig = true } = {}) { const scm = scms$1(currentDirectory); if (!scm) { throw new Error("Unable to detect a source control manager."); } const directory = scm.rootDirectory; const revision = since || (yield scm.getSinceRevision(directory, { staged, branch })); onFoundSinceRevision == null ? 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(resolveConfig); const unfilteredChangedFiles = yield scm.getChangedFiles( directory, revision, staged ); const changedFiles = yield filterAsync( unfilteredChangedFiles.filter(patternMatcher).filter(rootIgnorer).filter(cwdIgnorer), isFileSupportedExtension ); const unfilteredStagedFiles = yield scm.getUnstagedChangedFiles(directory); const unstagedFiles = staged ? yield filterAsync( unfilteredStagedFiles.filter(patternMatcher).filter(rootIgnorer).filter(cwdIgnorer), isFileSupportedExtension ) : []; const wasFullyStaged = (file) => !unstagedFiles.includes(file); onFoundChangedFiles == null ? void 0 : onFoundChangedFiles(changedFiles); const failReasons = /* @__PURE__ */ new Set(); yield processFiles(directory, changedFiles, { check, config, onWriteFile: (file) => __async(this, null, function* () { yield onWriteFile == null ? void 0 : onWriteFile(file); if (bail) { failReasons.add("BAIL_ON_WRITE"); } if (staged && restage) { if (wasFullyStaged(file)) { yield scm.stageFile(directory, file); } else { onPartiallyStagedFile == null ? void 0 : onPartiallyStagedFile(file); failReasons.add("PARTIALLY_STAGED_FILE"); } } }), onCheckFile: (file, isFormatted) => { onCheckFile == null ? void 0 : onCheckFile(file, isFormatted); if (!isFormatted) { failReasons.add("CHECK_FAILED"); } }, onExamineFile: verbose ? onExamineFile : void 0 }); return { success: failReasons.size === 0, errors: [...failReasons] }; });