watskeburt 2.0.0 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +73 -3
- package/dist/formatters/format.js +5 -3
- package/dist/formatters/json.js +1 -1
- package/dist/formatters/regex.js +34 -30
- package/dist/git-primitives.js +76 -55
- package/dist/main.js +16 -12
- package/dist/map-change-type.js +12 -12
- package/dist/parse-diff-lines.js +20 -18
- package/dist/parse-status-lines.js +27 -23
- package/dist/run-cli.js +3 -0
- package/dist/version.js +1 -1
- package/package.json +21 -17
- package/dist/execute-cli.js +0 -63
    
        package/dist/cli.js
    CHANGED
    
    | @@ -1,3 +1,73 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            import {  | 
| 3 | 
            -
             | 
| 1 | 
            +
            import { EOL } from "node:os";
         | 
| 2 | 
            +
            import { parseArgs } from "node:util";
         | 
| 3 | 
            +
            import { list } from "./main.js";
         | 
| 4 | 
            +
            import { VERSION } from "./version.js";
         | 
| 5 | 
            +
            const HELP_MESSAGE = `Usage: watskeburt [options] [old-revision] [new-revision]
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            lists files & their statuses since [old-revision] or between [old-revision] and [new-revision].
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            -> When you don't pass a revision at all old-revision defaults to the current one.
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            Options:
         | 
| 12 | 
            +
              -T, --outputType <type>  what format to emit (choices: "json", "regex", default: "regex")
         | 
| 13 | 
            +
              --trackedOnly            only take tracked files into account (default: false)
         | 
| 14 | 
            +
              -V, --version            output the version number
         | 
| 15 | 
            +
              -h, --help               display help for command${EOL}`;
         | 
| 16 | 
            +
            export async function cli(
         | 
| 17 | 
            +
              pArguments = process.argv.slice(2),
         | 
| 18 | 
            +
              pOutStream = process.stdout,
         | 
| 19 | 
            +
              pErrorStream = process.stderr,
         | 
| 20 | 
            +
              pErrorExitCode = 1,
         | 
| 21 | 
            +
            ) {
         | 
| 22 | 
            +
              try {
         | 
| 23 | 
            +
                const lArguments = getArguments(pArguments);
         | 
| 24 | 
            +
                if (lArguments.values.help) {
         | 
| 25 | 
            +
                  pOutStream.write(HELP_MESSAGE);
         | 
| 26 | 
            +
                  return;
         | 
| 27 | 
            +
                }
         | 
| 28 | 
            +
                if (lArguments.values.version) {
         | 
| 29 | 
            +
                  pOutStream.write(`${VERSION}${EOL}`);
         | 
| 30 | 
            +
                  return;
         | 
| 31 | 
            +
                }
         | 
| 32 | 
            +
                if (!outputTypeIsValid(lArguments.values.outputType)) {
         | 
| 33 | 
            +
                  pErrorStream.write(
         | 
| 34 | 
            +
                    `error: option '-T, --outputType <type>' argument '${lArguments.values.outputType}' is invalid. Allowed choices are json, regex.${EOL}`,
         | 
| 35 | 
            +
                  );
         | 
| 36 | 
            +
                  process.exitCode = pErrorExitCode;
         | 
| 37 | 
            +
                  return;
         | 
| 38 | 
            +
                }
         | 
| 39 | 
            +
                const lResult = await list(
         | 
| 40 | 
            +
                  lArguments.positionals[0],
         | 
| 41 | 
            +
                  lArguments.positionals[1],
         | 
| 42 | 
            +
                  lArguments.values,
         | 
| 43 | 
            +
                );
         | 
| 44 | 
            +
                pOutStream.write(`${lResult}${EOL}`);
         | 
| 45 | 
            +
              } catch (pError) {
         | 
| 46 | 
            +
                pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
         | 
| 47 | 
            +
                process.exitCode = pErrorExitCode;
         | 
| 48 | 
            +
              }
         | 
| 49 | 
            +
            }
         | 
| 50 | 
            +
            function getArguments(pArguments) {
         | 
| 51 | 
            +
              return parseArgs({
         | 
| 52 | 
            +
                args: pArguments,
         | 
| 53 | 
            +
                options: {
         | 
| 54 | 
            +
                  outputType: {
         | 
| 55 | 
            +
                    type: "string",
         | 
| 56 | 
            +
                    short: "T",
         | 
| 57 | 
            +
                    default: "regex",
         | 
| 58 | 
            +
                  },
         | 
| 59 | 
            +
                  trackedOnly: {
         | 
| 60 | 
            +
                    type: "boolean",
         | 
| 61 | 
            +
                    default: false,
         | 
| 62 | 
            +
                  },
         | 
| 63 | 
            +
                  help: { type: "boolean", short: "h", default: false },
         | 
| 64 | 
            +
                  version: { type: "boolean", short: "V", default: false },
         | 
| 65 | 
            +
                },
         | 
| 66 | 
            +
                strict: true,
         | 
| 67 | 
            +
                allowPositionals: true,
         | 
| 68 | 
            +
                tokens: false,
         | 
| 69 | 
            +
              });
         | 
| 70 | 
            +
            }
         | 
| 71 | 
            +
            function outputTypeIsValid(pOutputType) {
         | 
| 72 | 
            +
              return ["json", "regex"].includes(pOutputType);
         | 
| 73 | 
            +
            }
         | 
| @@ -2,9 +2,11 @@ import formatToRegex from "./regex.js"; | |
| 2 2 | 
             
            import formatToJSON from "./json.js";
         | 
| 3 3 | 
             
            const identity = (pX) => pX;
         | 
| 4 4 | 
             
            const OUTPUT_TYPE_TO_FUNCTION = new Map([
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 5 | 
            +
              ["regex", formatToRegex],
         | 
| 6 | 
            +
              ["json", formatToJSON],
         | 
| 7 7 | 
             
            ]);
         | 
| 8 8 | 
             
            export default function format(pChanges, pOutputType) {
         | 
| 9 | 
            -
             | 
| 9 | 
            +
              return (OUTPUT_TYPE_TO_FUNCTION.get(pOutputType ?? "unknown") || identity)(
         | 
| 10 | 
            +
                pChanges,
         | 
| 11 | 
            +
              );
         | 
| 10 12 | 
             
            }
         | 
    
        package/dist/formatters/json.js
    CHANGED
    
    
    
        package/dist/formatters/regex.js
    CHANGED
    
    | @@ -1,36 +1,40 @@ | |
| 1 1 | 
             
            import { extname } from "node:path";
         | 
| 2 2 | 
             
            const DEFAULT_EXTENSIONS = new Set([
         | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 3 | 
            +
              ".cjs",
         | 
| 4 | 
            +
              ".cjsx",
         | 
| 5 | 
            +
              ".coffee",
         | 
| 6 | 
            +
              ".csx",
         | 
| 7 | 
            +
              ".cts",
         | 
| 8 | 
            +
              ".js",
         | 
| 9 | 
            +
              ".json",
         | 
| 10 | 
            +
              ".jsx",
         | 
| 11 | 
            +
              ".litcoffee",
         | 
| 12 | 
            +
              ".ls",
         | 
| 13 | 
            +
              ".mjs",
         | 
| 14 | 
            +
              ".mts",
         | 
| 15 | 
            +
              ".svelte",
         | 
| 16 | 
            +
              ".ts",
         | 
| 17 | 
            +
              ".tsx",
         | 
| 18 | 
            +
              ".vue",
         | 
| 19 | 
            +
              ".vuex",
         | 
| 20 20 | 
             
            ]);
         | 
| 21 21 | 
             
            const DEFAULT_CHANGE_TYPES = new Set([
         | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 22 | 
            +
              "modified",
         | 
| 23 | 
            +
              "added",
         | 
| 24 | 
            +
              "renamed",
         | 
| 25 | 
            +
              "copied",
         | 
| 26 | 
            +
              "untracked",
         | 
| 27 27 | 
             
            ]);
         | 
| 28 | 
            -
            export default function formatToRegex( | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
             | 
| 34 | 
            -
             | 
| 35 | 
            -
                 | 
| 28 | 
            +
            export default function formatToRegex(
         | 
| 29 | 
            +
              pChanges,
         | 
| 30 | 
            +
              pExtensions = DEFAULT_EXTENSIONS,
         | 
| 31 | 
            +
              pChangeTypes = DEFAULT_CHANGE_TYPES,
         | 
| 32 | 
            +
            ) {
         | 
| 33 | 
            +
              const lChanges = pChanges
         | 
| 34 | 
            +
                .filter((pChange) => pChangeTypes.has(pChange.changeType))
         | 
| 35 | 
            +
                .map(({ name }) => name)
         | 
| 36 | 
            +
                .filter((pName) => pExtensions.has(extname(pName)))
         | 
| 37 | 
            +
                .map((pName) => pName.replace(/\\/g, "\\\\").replace(/\./g, "\\."))
         | 
| 38 | 
            +
                .join("|");
         | 
| 39 | 
            +
              return `^(${lChanges})$`;
         | 
| 36 40 | 
             
            }
         | 
    
        package/dist/git-primitives.js
    CHANGED
    
    | @@ -1,67 +1,88 @@ | |
| 1 1 | 
             
            import { spawn } from "node:child_process";
         | 
| 2 2 | 
             
            export async function getStatusShort(pSpawnFunction = spawn) {
         | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
                 | 
| 3 | 
            +
              const lErrorMap = new Map([
         | 
| 4 | 
            +
                [129, `'${process.cwd()}' does not seem to be a git repository`],
         | 
| 5 | 
            +
              ]);
         | 
| 6 | 
            +
              const lResult = await getGitResult(
         | 
| 7 | 
            +
                ["status", "--porcelain"],
         | 
| 8 | 
            +
                lErrorMap,
         | 
| 9 | 
            +
                pSpawnFunction,
         | 
| 10 | 
            +
              );
         | 
| 11 | 
            +
              return lResult;
         | 
| 8 12 | 
             
            }
         | 
| 9 | 
            -
            export async function getDiffLines( | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
                    ?  | 
| 19 | 
            -
             | 
| 20 | 
            -
                 | 
| 13 | 
            +
            export async function getDiffLines(
         | 
| 14 | 
            +
              pOldRevision,
         | 
| 15 | 
            +
              pNewRevision,
         | 
| 16 | 
            +
              pSpawnFunction = spawn,
         | 
| 17 | 
            +
            ) {
         | 
| 18 | 
            +
              const lErrorMap = new Map([
         | 
| 19 | 
            +
                [
         | 
| 20 | 
            +
                  128,
         | 
| 21 | 
            +
                  `revision '${pOldRevision}' ${
         | 
| 22 | 
            +
                    pNewRevision ? `(or '${pNewRevision}') ` : ""
         | 
| 23 | 
            +
                  }unknown`,
         | 
| 24 | 
            +
                ],
         | 
| 25 | 
            +
                [129, `'${process.cwd()}' does not seem to be a git repository`],
         | 
| 26 | 
            +
              ]);
         | 
| 27 | 
            +
              const lResult = await getGitResult(
         | 
| 28 | 
            +
                pNewRevision
         | 
| 29 | 
            +
                  ? ["diff", pOldRevision, pNewRevision, "--name-status"]
         | 
| 30 | 
            +
                  : ["diff", pOldRevision, "--name-status"],
         | 
| 31 | 
            +
                lErrorMap,
         | 
| 32 | 
            +
                pSpawnFunction,
         | 
| 33 | 
            +
              );
         | 
| 34 | 
            +
              return lResult;
         | 
| 21 35 | 
             
            }
         | 
| 22 36 | 
             
            export async function getSHA(pSpawnFunction = spawn) {
         | 
| 23 | 
            -
             | 
| 24 | 
            -
             | 
| 25 | 
            -
                 | 
| 37 | 
            +
              const lSha1Length = 40;
         | 
| 38 | 
            +
              const lResult = await getGitResult(
         | 
| 39 | 
            +
                ["rev-parse", "HEAD"],
         | 
| 40 | 
            +
                new Map(),
         | 
| 41 | 
            +
                pSpawnFunction,
         | 
| 42 | 
            +
              );
         | 
| 43 | 
            +
              return lResult.slice(0, lSha1Length);
         | 
| 26 44 | 
             
            }
         | 
| 27 45 | 
             
            function getGitResult(pArguments, pErrorMap, pSpawnFunction) {
         | 
| 28 | 
            -
             | 
| 29 | 
            -
             | 
| 30 | 
            -
             | 
| 46 | 
            +
              const lGit = pSpawnFunction("git", pArguments, {
         | 
| 47 | 
            +
                cwd: process.cwd(),
         | 
| 48 | 
            +
                env: process.env,
         | 
| 49 | 
            +
              });
         | 
| 50 | 
            +
              let lStdOutData = "";
         | 
| 51 | 
            +
              let lStdErrorData = "";
         | 
| 52 | 
            +
              return new Promise((pResolve, pReject) => {
         | 
| 53 | 
            +
                lGit.stdout?.on("data", (pData) => {
         | 
| 54 | 
            +
                  lStdOutData = lStdOutData.concat(pData);
         | 
| 31 55 | 
             
                });
         | 
| 32 | 
            -
                 | 
| 33 | 
            -
             | 
| 34 | 
            -
                return new Promise((pResolve, pReject) => {
         | 
| 35 | 
            -
                    lGit.stdout?.on("data", (pData) => {
         | 
| 36 | 
            -
                        lStdOutData = lStdOutData.concat(pData);
         | 
| 37 | 
            -
                    });
         | 
| 38 | 
            -
                    lGit.stderr?.on("data", (pData) => {
         | 
| 39 | 
            -
                        lStdErrorData = lStdErrorData.concat(pData);
         | 
| 40 | 
            -
                    });
         | 
| 41 | 
            -
                    lGit.on("close", (pCode) => {
         | 
| 42 | 
            -
                        if (pCode === 0) {
         | 
| 43 | 
            -
                            pResolve(stringifyOutStream(lStdOutData));
         | 
| 44 | 
            -
                        }
         | 
| 45 | 
            -
                        else {
         | 
| 46 | 
            -
                            pReject(new Error(pErrorMap.get(pCode ?? 0) ||
         | 
| 47 | 
            -
                                `internal git error: ${pCode} (${stringifyOutStream(lStdErrorData)})`));
         | 
| 48 | 
            -
                        }
         | 
| 49 | 
            -
                    });
         | 
| 50 | 
            -
                    lGit.on("error", (pError) => {
         | 
| 51 | 
            -
                        if (pError?.code === "ENOENT") {
         | 
| 52 | 
            -
                            pReject(new Error("git executable not found"));
         | 
| 53 | 
            -
                        }
         | 
| 54 | 
            -
                        else {
         | 
| 55 | 
            -
                            pReject(new Error(`internal spawn error: ${pError}`));
         | 
| 56 | 
            -
                        }
         | 
| 57 | 
            -
                    });
         | 
| 56 | 
            +
                lGit.stderr?.on("data", (pData) => {
         | 
| 57 | 
            +
                  lStdErrorData = lStdErrorData.concat(pData);
         | 
| 58 58 | 
             
                });
         | 
| 59 | 
            +
                lGit.on("close", (pCode) => {
         | 
| 60 | 
            +
                  if (pCode === 0) {
         | 
| 61 | 
            +
                    pResolve(stringifyOutStream(lStdOutData));
         | 
| 62 | 
            +
                  } else {
         | 
| 63 | 
            +
                    pReject(
         | 
| 64 | 
            +
                      new Error(
         | 
| 65 | 
            +
                        pErrorMap.get(pCode ?? 0) ||
         | 
| 66 | 
            +
                          `internal git error: ${pCode} (${stringifyOutStream(
         | 
| 67 | 
            +
                            lStdErrorData,
         | 
| 68 | 
            +
                          )})`,
         | 
| 69 | 
            +
                      ),
         | 
| 70 | 
            +
                    );
         | 
| 71 | 
            +
                  }
         | 
| 72 | 
            +
                });
         | 
| 73 | 
            +
                lGit.on("error", (pError) => {
         | 
| 74 | 
            +
                  if (pError?.code === "ENOENT") {
         | 
| 75 | 
            +
                    pReject(new Error("git executable not found"));
         | 
| 76 | 
            +
                  } else {
         | 
| 77 | 
            +
                    pReject(new Error(`internal spawn error: ${pError}`));
         | 
| 78 | 
            +
                  }
         | 
| 79 | 
            +
                });
         | 
| 80 | 
            +
              });
         | 
| 59 81 | 
             
            }
         | 
| 60 82 | 
             
            function stringifyOutStream(pBufferOrString) {
         | 
| 61 | 
            -
             | 
| 62 | 
            -
             | 
| 63 | 
            -
             | 
| 64 | 
            -
                 | 
| 65 | 
            -
             | 
| 66 | 
            -
                }
         | 
| 83 | 
            +
              if (pBufferOrString instanceof Buffer) {
         | 
| 84 | 
            +
                return pBufferOrString.toString("utf8");
         | 
| 85 | 
            +
              } else {
         | 
| 86 | 
            +
                return pBufferOrString;
         | 
| 87 | 
            +
              }
         | 
| 67 88 | 
             
            }
         | 
    
        package/dist/main.js
    CHANGED
    
    | @@ -3,18 +3,22 @@ import { parseStatusLines } from "./parse-status-lines.js"; | |
| 3 3 | 
             
            import * as primitives from "./git-primitives.js";
         | 
| 4 4 | 
             
            import format from "./formatters/format.js";
         | 
| 5 5 | 
             
            export async function list(pOldRevision, pNewRevision, pOptions) {
         | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 6 | 
            +
              const lOldRevision = pOldRevision || (await primitives.getSHA());
         | 
| 7 | 
            +
              const lOptions = pOptions || {};
         | 
| 8 | 
            +
              const [lDiffLines, lStatusLines] = await Promise.all([
         | 
| 9 | 
            +
                primitives.getDiffLines(lOldRevision, pNewRevision),
         | 
| 10 | 
            +
                !lOptions.trackedOnly ? primitives.getStatusShort() : "",
         | 
| 11 | 
            +
              ]);
         | 
| 12 | 
            +
              let lChanges = parseDiffLines(lDiffLines);
         | 
| 13 | 
            +
              if (!lOptions.trackedOnly) {
         | 
| 14 | 
            +
                lChanges = lChanges.concat(
         | 
| 15 | 
            +
                  parseStatusLines(lStatusLines).filter(
         | 
| 16 | 
            +
                    ({ changeType }) => changeType === "untracked",
         | 
| 17 | 
            +
                  ),
         | 
| 18 | 
            +
                );
         | 
| 19 | 
            +
              }
         | 
| 20 | 
            +
              return format(lChanges, lOptions.outputType);
         | 
| 17 21 | 
             
            }
         | 
| 18 22 | 
             
            export function getSHA() {
         | 
| 19 | 
            -
             | 
| 23 | 
            +
              return primitives.getSHA();
         | 
| 20 24 | 
             
            }
         | 
    
        package/dist/map-change-type.js
    CHANGED
    
    | @@ -1,16 +1,16 @@ | |
| 1 1 | 
             
            const CHANGE_CHAR_2_CHANGE_TYPE = new Map([
         | 
| 2 | 
            -
             | 
| 3 | 
            -
             | 
| 4 | 
            -
             | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 10 | 
            -
             | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 2 | 
            +
              ["A", "added"],
         | 
| 3 | 
            +
              ["C", "copied"],
         | 
| 4 | 
            +
              ["D", "deleted"],
         | 
| 5 | 
            +
              ["M", "modified"],
         | 
| 6 | 
            +
              ["R", "renamed"],
         | 
| 7 | 
            +
              ["T", "type changed"],
         | 
| 8 | 
            +
              ["U", "unmerged"],
         | 
| 9 | 
            +
              ["B", "pairing broken"],
         | 
| 10 | 
            +
              [" ", "unmodified"],
         | 
| 11 | 
            +
              ["?", "untracked"],
         | 
| 12 | 
            +
              ["!", "ignored"],
         | 
| 13 13 | 
             
            ]);
         | 
| 14 14 | 
             
            export function changeChar2ChangeType(pChar) {
         | 
| 15 | 
            -
             | 
| 15 | 
            +
              return CHANGE_CHAR_2_CHANGE_TYPE.get(pChar) ?? "unknown";
         | 
| 16 16 | 
             
            }
         | 
    
        package/dist/parse-diff-lines.js
    CHANGED
    
    | @@ -1,25 +1,27 @@ | |
| 1 1 | 
             
            import { EOL } from "node:os";
         | 
| 2 2 | 
             
            import { changeChar2ChangeType } from "./map-change-type.js";
         | 
| 3 | 
            -
            const DIFF_NAME_STATUS_LINE_PATTERN = | 
| 3 | 
            +
            const DIFF_NAME_STATUS_LINE_PATTERN =
         | 
| 4 | 
            +
              /^(?<changeType>[ACDMRTUXB])(?<similarity>[0-9]{3})?[ \t]+(?<name>[^ \t]+)[ \t]*(?<newName>[^ \t]+)?$/;
         | 
| 4 5 | 
             
            export function parseDiffLines(pString) {
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 6 | 
            +
              return pString
         | 
| 7 | 
            +
                .split(EOL)
         | 
| 8 | 
            +
                .filter(Boolean)
         | 
| 9 | 
            +
                .map(parseDiffLine)
         | 
| 10 | 
            +
                .filter(({ name, changeType }) => Boolean(name) && Boolean(changeType));
         | 
| 10 11 | 
             
            }
         | 
| 11 12 | 
             
            export function parseDiffLine(pString) {
         | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 13 | 
            +
              const lMatchResult = pString.match(DIFF_NAME_STATUS_LINE_PATTERN);
         | 
| 14 | 
            +
              const lReturnValue = {};
         | 
| 15 | 
            +
              if (lMatchResult?.groups) {
         | 
| 16 | 
            +
                lReturnValue.changeType = changeChar2ChangeType(
         | 
| 17 | 
            +
                  lMatchResult.groups.changeType,
         | 
| 18 | 
            +
                );
         | 
| 19 | 
            +
                if (lMatchResult.groups.newName) {
         | 
| 20 | 
            +
                  lReturnValue.name = lMatchResult.groups.newName;
         | 
| 21 | 
            +
                  lReturnValue.oldName = lMatchResult.groups.name;
         | 
| 22 | 
            +
                } else {
         | 
| 23 | 
            +
                  lReturnValue.name = lMatchResult.groups.name;
         | 
| 23 24 | 
             
                }
         | 
| 24 | 
            -
             | 
| 25 | 
            +
              }
         | 
| 26 | 
            +
              return lReturnValue;
         | 
| 25 27 | 
             
            }
         | 
| @@ -1,30 +1,34 @@ | |
| 1 1 | 
             
            import { EOL } from "node:os";
         | 
| 2 2 | 
             
            import { changeChar2ChangeType } from "./map-change-type.js";
         | 
| 3 | 
            -
            const DIFF_SHORT_STATUS_LINE_PATTERN = | 
| 3 | 
            +
            const DIFF_SHORT_STATUS_LINE_PATTERN =
         | 
| 4 | 
            +
              /^(?<stagedChangeType>[ ACDMRTUXB?!])(?<unStagedChangeType>[ ACDMRTUXB?!])[ \t]+(?<name>[^ \t]+)(( -> )(?<newName>[^ \t]+))?$/;
         | 
| 4 5 | 
             
            export function parseStatusLines(pString) {
         | 
| 5 | 
            -
             | 
| 6 | 
            -
             | 
| 7 | 
            -
             | 
| 8 | 
            -
             | 
| 9 | 
            -
             | 
| 6 | 
            +
              return pString
         | 
| 7 | 
            +
                .split(EOL)
         | 
| 8 | 
            +
                .filter(Boolean)
         | 
| 9 | 
            +
                .map(parseStatusLine)
         | 
| 10 | 
            +
                .filter(({ name, changeType }) => Boolean(name) && Boolean(changeType));
         | 
| 10 11 | 
             
            }
         | 
| 11 12 | 
             
            export function parseStatusLine(pString) {
         | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 20 | 
            -
             | 
| 21 | 
            -
             | 
| 22 | 
            -
             | 
| 23 | 
            -
             | 
| 24 | 
            -
                     | 
| 25 | 
            -
             | 
| 26 | 
            -
             | 
| 27 | 
            -
             | 
| 13 | 
            +
              const lMatchResult = pString.match(DIFF_SHORT_STATUS_LINE_PATTERN);
         | 
| 14 | 
            +
              const lReturnValue = {};
         | 
| 15 | 
            +
              if (lMatchResult?.groups) {
         | 
| 16 | 
            +
                const lStagedChangeType = changeChar2ChangeType(
         | 
| 17 | 
            +
                  lMatchResult.groups.stagedChangeType,
         | 
| 18 | 
            +
                );
         | 
| 19 | 
            +
                const lUnStagedChangeType = changeChar2ChangeType(
         | 
| 20 | 
            +
                  lMatchResult.groups.unStagedChangeType,
         | 
| 21 | 
            +
                );
         | 
| 22 | 
            +
                lReturnValue.changeType =
         | 
| 23 | 
            +
                  lStagedChangeType === "unmodified"
         | 
| 24 | 
            +
                    ? lUnStagedChangeType
         | 
| 25 | 
            +
                    : lStagedChangeType;
         | 
| 26 | 
            +
                if (lMatchResult.groups.newName) {
         | 
| 27 | 
            +
                  lReturnValue.name = lMatchResult.groups.newName;
         | 
| 28 | 
            +
                  lReturnValue.oldName = lMatchResult.groups.name;
         | 
| 29 | 
            +
                } else {
         | 
| 30 | 
            +
                  lReturnValue.name = lMatchResult.groups.name;
         | 
| 28 31 | 
             
                }
         | 
| 29 | 
            -
             | 
| 32 | 
            +
              }
         | 
| 33 | 
            +
              return lReturnValue;
         | 
| 30 34 | 
             
            }
         | 
    
        package/dist/run-cli.js
    ADDED
    
    
    
        package/dist/version.js
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            export const VERSION = "2.0. | 
| 1 | 
            +
            export const VERSION = "2.0.2";
         | 
    
        package/package.json
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            {
         | 
| 2 2 | 
             
              "name": "watskeburt",
         | 
| 3 | 
            -
              "version": "2.0. | 
| 3 | 
            +
              "version": "2.0.2",
         | 
| 4 4 | 
             
              "description": "List files changed since a git revision",
         | 
| 5 5 | 
             
              "keywords": [
         | 
| 6 6 | 
             
                "git",
         | 
| @@ -9,7 +9,7 @@ | |
| 9 9 | 
             
              "homepage": "https://github.com/sverweij/watskeburt",
         | 
| 10 10 | 
             
              "repository": {
         | 
| 11 11 | 
             
                "type": "git",
         | 
| 12 | 
            -
                "url": "git+https://github.com/sverweij/watskeburt"
         | 
| 12 | 
            +
                "url": "git+https://github.com/sverweij/watskeburt.git"
         | 
| 13 13 | 
             
              },
         | 
| 14 14 | 
             
              "bugs": {
         | 
| 15 15 | 
             
                "url": "https://github.com/sverweij/watskeburt/issues"
         | 
| @@ -19,7 +19,9 @@ | |
| 19 19 | 
             
                "url": "https://sverweij.github.io"
         | 
| 20 20 | 
             
              },
         | 
| 21 21 | 
             
              "license": "MIT",
         | 
| 22 | 
            -
              "bin":  | 
| 22 | 
            +
              "bin": {
         | 
| 23 | 
            +
                "watskeburt": "dist/run-cli.js"
         | 
| 24 | 
            +
              },
         | 
| 23 25 | 
             
              "main": "dist/main.js",
         | 
| 24 26 | 
             
              "module": "dist/main.js",
         | 
| 25 27 | 
             
              "type": "module",
         | 
| @@ -27,6 +29,7 @@ | |
| 27 29 | 
             
              "exports": {
         | 
| 28 30 | 
             
                ".": [
         | 
| 29 31 | 
             
                  {
         | 
| 32 | 
            +
                    "types": "./types/watskeburt.d.ts",
         | 
| 30 33 | 
             
                    "import": "./dist/main.js"
         | 
| 31 34 | 
             
                  },
         | 
| 32 35 | 
             
                  "./dist/main.js"
         | 
| @@ -42,34 +45,35 @@ | |
| 42 45 | 
             
                "README.md"
         | 
| 43 46 | 
             
              ],
         | 
| 44 47 | 
             
              "devDependencies": {
         | 
| 45 | 
            -
                "@types/node": "20. | 
| 46 | 
            -
                "@typescript-eslint/eslint-plugin": "6. | 
| 48 | 
            +
                "@types/node": "20.9.3",
         | 
| 49 | 
            +
                "@typescript-eslint/eslint-plugin": "6.12.0",
         | 
| 47 50 | 
             
                "c8": "8.0.1",
         | 
| 48 | 
            -
                "dependency-cruiser": " | 
| 49 | 
            -
                "eslint": "8. | 
| 51 | 
            +
                "dependency-cruiser": "15.3.0",
         | 
| 52 | 
            +
                "eslint": "8.54.0",
         | 
| 50 53 | 
             
                "eslint-config-moving-meadow": "4.0.2",
         | 
| 51 54 | 
             
                "eslint-config-prettier": "9.0.0",
         | 
| 52 | 
            -
                "eslint-plugin-budapestian": " | 
| 55 | 
            +
                "eslint-plugin-budapestian": "6.0.0",
         | 
| 53 56 | 
             
                "eslint-plugin-eslint-comments": "3.2.0",
         | 
| 54 | 
            -
                "eslint-plugin-import": "2. | 
| 57 | 
            +
                "eslint-plugin-import": "2.29.0",
         | 
| 55 58 | 
             
                "eslint-plugin-mocha": "10.2.0",
         | 
| 56 59 | 
             
                "eslint-plugin-node": "11.1.0",
         | 
| 57 60 | 
             
                "eslint-plugin-security": "1.7.1",
         | 
| 58 | 
            -
                "eslint-plugin-unicorn": " | 
| 61 | 
            +
                "eslint-plugin-unicorn": "49.0.0",
         | 
| 59 62 | 
             
                "npm-run-all": "4.1.5",
         | 
| 60 | 
            -
                "prettier": "3.0 | 
| 61 | 
            -
                "tsx": " | 
| 62 | 
            -
                "typescript": "5. | 
| 63 | 
            -
                "upem": " | 
| 63 | 
            +
                "prettier": "3.1.0",
         | 
| 64 | 
            +
                "tsx": "4.2.0",
         | 
| 65 | 
            +
                "typescript": "5.3.2",
         | 
| 66 | 
            +
                "upem": "9.0.2"
         | 
| 64 67 | 
             
              },
         | 
| 65 68 | 
             
              "engines": {
         | 
| 66 69 | 
             
                "node": "^18||>=20"
         | 
| 67 70 | 
             
              },
         | 
| 68 71 | 
             
              "scripts": {
         | 
| 69 | 
            -
                "build": "npm-run-all --sequential build:clean build:version build:dist",
         | 
| 72 | 
            +
                "build": "npm-run-all --sequential build:clean build:version build:dist build:format",
         | 
| 70 73 | 
             
                "build:version": "tsx tools/get-version.ts > src/version.ts",
         | 
| 71 74 | 
             
                "build:clean": "rm -rf dist/*",
         | 
| 72 75 | 
             
                "build:dist": "tsc",
         | 
| 76 | 
            +
                "build:format": "prettier --log-level warn --write dist/",
         | 
| 73 77 | 
             
                "check": "npm-run-all --parallel --aggregate-output lint depcruise test:cover",
         | 
| 74 78 | 
             
                "clean": "rm -rf dist",
         | 
| 75 79 | 
             
                "test": "tsx --test-reporter ./tools/dot-with-summary.reporter.js --test src/*.spec.ts src/**/*.spec.ts",
         | 
| @@ -78,8 +82,8 @@ | |
| 78 82 | 
             
                "depcruise:graph": "depcruise src types --include-only '^(dist|src|types)' --output-type dot | dot -T svg | tee docs/dependency-graph.svg | depcruise-wrap-stream-in-html > docs/dependency-graph.html",
         | 
| 79 83 | 
             
                "depcruise:graph:archi": "depcruise src --include-only '^(dist|src|types)' --output-type archi | dot -T svg | depcruise-wrap-stream-in-html > docs/high-level-dependency-graph.html",
         | 
| 80 84 | 
             
                "depcruise:graph:dev": "depcruise dist src types --include-only '^(dist|src|types)' --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser",
         | 
| 81 | 
            -
                "depcruise:graph:diff:dev": "depcruise dist src types --include-only '^(dist|src|types)' --highlight \"$(node dist/cli.js main -T regex)\" --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser",
         | 
| 82 | 
            -
                "depcruise:graph:diff:mermaid": "depcruise dist src types --include-only '^(dist|src|types)' --output-type mermaid --output-to - --highlight \"$(node dist/cli.js $SHA -T regex)\"",
         | 
| 85 | 
            +
                "depcruise:graph:diff:dev": "depcruise dist src types --include-only '^(dist|src|types)' --highlight \"$(node dist/run-cli.js main -T regex)\" --prefix vscode://file/$(pwd)/ --output-type dot | dot -T svg | depcruise-wrap-stream-in-html | browser",
         | 
| 86 | 
            +
                "depcruise:graph:diff:mermaid": "depcruise dist src types --include-only '^(dist|src|types)' --output-type mermaid --output-to - --highlight \"$(node dist/run-cli.js $SHA -T regex)\"",
         | 
| 83 87 | 
             
                "depcruise:html": "depcruise src types --progress --output-type err-html --output-to dependency-violation-report.html",
         | 
| 84 88 | 
             
                "depcruise:text": "depcruise src types --progress --output-type text",
         | 
| 85 89 | 
             
                "depcruise:focus": "depcruise src types --progress --output-type text --focus",
         | 
    
        package/dist/execute-cli.js
    DELETED
    
    | @@ -1,63 +0,0 @@ | |
| 1 | 
            -
            import { EOL } from "node:os";
         | 
| 2 | 
            -
            import { parseArgs } from "node:util";
         | 
| 3 | 
            -
            import { list } from "./main.js";
         | 
| 4 | 
            -
            import { VERSION } from "./version.js";
         | 
| 5 | 
            -
            const HELP_MESSAGE = `Usage: watskeburt [options] [old-revision] [new-revision]
         | 
| 6 | 
            -
             | 
| 7 | 
            -
            lists files & their statuses since [old-revision] or between [old-revision] and [new-revision].
         | 
| 8 | 
            -
             | 
| 9 | 
            -
            -> When you don't pass a revision at all old-revision defaults to the current one.
         | 
| 10 | 
            -
             | 
| 11 | 
            -
            Options:
         | 
| 12 | 
            -
              -T, --outputType <type>  what format to emit (choices: "json", "regex", default: "regex")
         | 
| 13 | 
            -
              --trackedOnly            only take tracked files into account (default: false)
         | 
| 14 | 
            -
              -V, --version            output the version number
         | 
| 15 | 
            -
              -h, --help               display help for command${EOL}`;
         | 
| 16 | 
            -
            export async function cli(pArguments = process.argv.slice(2), pOutStream = process.stdout, pErrorStream = process.stderr, pErrorExitCode = 1) {
         | 
| 17 | 
            -
                try {
         | 
| 18 | 
            -
                    const lArguments = getArguments(pArguments);
         | 
| 19 | 
            -
                    if (lArguments.values.help) {
         | 
| 20 | 
            -
                        pOutStream.write(HELP_MESSAGE);
         | 
| 21 | 
            -
                        return;
         | 
| 22 | 
            -
                    }
         | 
| 23 | 
            -
                    if (lArguments.values.version) {
         | 
| 24 | 
            -
                        pOutStream.write(`${VERSION}${EOL}`);
         | 
| 25 | 
            -
                        return;
         | 
| 26 | 
            -
                    }
         | 
| 27 | 
            -
                    if (!outputTypeIsValid(lArguments.values.outputType)) {
         | 
| 28 | 
            -
                        pErrorStream.write(`error: option '-T, --outputType <type>' argument '${lArguments.values.outputType}' is invalid. Allowed choices are json, regex.${EOL}`);
         | 
| 29 | 
            -
                        process.exitCode = pErrorExitCode;
         | 
| 30 | 
            -
                        return;
         | 
| 31 | 
            -
                    }
         | 
| 32 | 
            -
                    const lResult = await list(lArguments.positionals[0], lArguments.positionals[1], lArguments.values);
         | 
| 33 | 
            -
                    pOutStream.write(`${lResult}${EOL}`);
         | 
| 34 | 
            -
                }
         | 
| 35 | 
            -
                catch (pError) {
         | 
| 36 | 
            -
                    pErrorStream.write(`${EOL}ERROR: ${pError.message}${EOL}${EOL}`);
         | 
| 37 | 
            -
                    process.exitCode = pErrorExitCode;
         | 
| 38 | 
            -
                }
         | 
| 39 | 
            -
            }
         | 
| 40 | 
            -
            function getArguments(pArguments) {
         | 
| 41 | 
            -
                return parseArgs({
         | 
| 42 | 
            -
                    args: pArguments,
         | 
| 43 | 
            -
                    options: {
         | 
| 44 | 
            -
                        outputType: {
         | 
| 45 | 
            -
                            type: "string",
         | 
| 46 | 
            -
                            short: "T",
         | 
| 47 | 
            -
                            default: "regex",
         | 
| 48 | 
            -
                        },
         | 
| 49 | 
            -
                        trackedOnly: {
         | 
| 50 | 
            -
                            type: "boolean",
         | 
| 51 | 
            -
                            default: false,
         | 
| 52 | 
            -
                        },
         | 
| 53 | 
            -
                        help: { type: "boolean", short: "h", default: false },
         | 
| 54 | 
            -
                        version: { type: "boolean", short: "V", default: false },
         | 
| 55 | 
            -
                    },
         | 
| 56 | 
            -
                    strict: true,
         | 
| 57 | 
            -
                    allowPositionals: true,
         | 
| 58 | 
            -
                    tokens: false,
         | 
| 59 | 
            -
                });
         | 
| 60 | 
            -
            }
         | 
| 61 | 
            -
            function outputTypeIsValid(pOutputType) {
         | 
| 62 | 
            -
                return ["json", "regex"].includes(pOutputType);
         | 
| 63 | 
            -
            }
         |