brch 0.0.1 → 0.0.3

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/index.js CHANGED
@@ -2338,7 +2338,8 @@ var {
2338
2338
  } = import__.default;
2339
2339
 
2340
2340
  // src/services/configService.ts
2341
- import { readFileSync, writeFileSync, existsSync } from "fs";
2341
+ import { readFile, writeFile, access, mkdir } from "fs/promises";
2342
+ import { constants } from "fs";
2342
2343
 
2343
2344
  // node_modules/chalk/source/vendor/ansi-styles/index.js
2344
2345
  var ANSI_BACKGROUND_OFFSET = 10;
@@ -2835,103 +2836,185 @@ var import_ini = __toESM(require_ini(), 1);
2835
2836
  // src/utils/constants.ts
2836
2837
  import { homedir } from "os";
2837
2838
  var VCS_NAME = "brch";
2838
- var VCS_CONFIG = ".brchconfig";
2839
- var HOME_DIR = homedir();
2840
- var GLOBAL_CONFIG_PATH = `${HOME_DIR}/${VCS_CONFIG}`;
2841
2839
  var VCS_DIR = ".brch";
2842
- var OBJECT_DIR = `${VCS_DIR}/objects`;
2843
- var HEAD_FILE = `${VCS_DIR}/HEAD`;
2840
+ var VCS_PATH = `${process.cwd()}/${VCS_DIR}`;
2841
+ var OBJECTS_PATH = `${VCS_DIR}/objects`;
2842
+ var REFS_PATH = `${VCS_DIR}/refs`;
2843
+ var REFS_HEAD_PATH = `${REFS_PATH}/heads`;
2844
+ var HEAD_PATH = `${VCS_DIR}/HEAD`;
2845
+ var GLOBAL_CONFIG_FILE = ".brchconfig";
2846
+ var HOME_DIR = homedir();
2847
+ var GLOBAL_CONFIG_PATH = `${HOME_DIR}/${GLOBAL_CONFIG_FILE}`;
2848
+ var LOCAL_CONFIG_FILE = "config";
2849
+ var LOCAL_CONFIG_PATH = `${process.cwd()}/${VCS_DIR}/${LOCAL_CONFIG_FILE}`;
2850
+ var INDEX_FILE = "index.json";
2851
+ var INDEX_PATH = `${process.cwd()}/${VCS_DIR}/${INDEX_FILE}`;
2852
+ var IGNORE_FILE = ".brchignore";
2853
+ var IGNORE_PATH = `${process.cwd()}/${IGNORE_FILE}`;
2844
2854
 
2845
2855
  // src/services/configService.ts
2856
+ import { dirname } from "path";
2846
2857
  var setConfig = async ({ scopeKey, value, isGlobal }) => {
2847
- const configPath = isGlobal ? GLOBAL_CONFIG_PATH : VCS_CONFIG;
2848
- if (!existsSync(configPath)) {
2849
- writeFileSync(configPath, "");
2850
- }
2851
- const configFileContent = readConfigFile({ isGlobal });
2852
- const configFileJson = import_ini.parse(configFileContent || "");
2853
- const scopeKeyAttrs = scopeKey.split(".");
2854
- const scope = scopeKeyAttrs[0];
2855
- const key = scopeKeyAttrs[1];
2856
- if (!configFileJson[scope]) {
2857
- configFileJson[scope] = {};
2858
- }
2859
- configFileJson[scope][key] = value;
2860
- const configFileString = import_ini.stringify(configFileJson);
2861
- writeFileSync(configPath, configFileString);
2862
- console.log(source_default.green("Configuration set successfully."));
2863
- };
2864
- var readConfigFile = ({ isGlobal }) => {
2865
- return readFileSync(isGlobal ? GLOBAL_CONFIG_PATH : VCS_CONFIG, {
2866
- encoding: "utf-8"
2867
- });
2858
+ try {
2859
+ const configPath = isGlobal ? GLOBAL_CONFIG_PATH : LOCAL_CONFIG_PATH;
2860
+ if (!isGlobal) {
2861
+ try {
2862
+ await access(VCS_DIR, constants.F_OK);
2863
+ } catch {
2864
+ console.log(source_default.red("No local configuration file found. Run `brch config set --global <scopeKey> <value>` to set global configuration or run `brch init` to initialize a new repository."));
2865
+ process.exit(1);
2866
+ }
2867
+ }
2868
+ try {
2869
+ await access(configPath, constants.F_OK);
2870
+ } catch {
2871
+ await mkdir(dirname(configPath), { recursive: true });
2872
+ await writeFile(configPath, "");
2873
+ }
2874
+ const configFileContent = await readConfigFile({ isGlobal });
2875
+ const configFileJson = import_ini.parse(configFileContent || "");
2876
+ const scopeKeyAttrs = scopeKey.split(".");
2877
+ const scope = scopeKeyAttrs[0];
2878
+ const key = scopeKeyAttrs[1];
2879
+ if (!configFileJson[scope]) {
2880
+ configFileJson[scope] = {};
2881
+ }
2882
+ configFileJson[scope][key] = value;
2883
+ const configFileString = import_ini.stringify(configFileJson);
2884
+ await writeFile(configPath, configFileString);
2885
+ console.log(source_default.green("Configuration set successfully."));
2886
+ } catch (error) {
2887
+ console.error(source_default.red(`Failed to set configuration: ${error instanceof Error ? error.message : String(error)}`));
2888
+ process.exit(1);
2889
+ }
2890
+ };
2891
+ var readConfigFile = async ({ isGlobal }) => {
2892
+ try {
2893
+ return await readFile(isGlobal ? GLOBAL_CONFIG_PATH : LOCAL_CONFIG_PATH, {
2894
+ encoding: "utf-8"
2895
+ });
2896
+ } catch (error) {
2897
+ console.error(source_default.red(`Failed to read config file: ${error instanceof Error ? error.message : String(error)}`));
2898
+ process.exit(1);
2899
+ }
2868
2900
  };
2869
2901
 
2870
2902
  // src/commands/configCommand.ts
2871
- var configCommand = new Command("config").description("Manage repository or global configuration").option("--global", "Set global configuration").addCommand(new Command("set").argument("<scopeKey>", "Configuration key (e.g. user.name)").argument("<value>", "Configuration value").description("Set a configuration value").action(async function(scopeKey, value) {
2903
+ var configCommand = new Command("config").description("Manage repository or global configuration settings").option("--global", "Set global configuration (applies to all repositories)").addHelpText("after", `
2904
+ Examples:
2905
+ $ brch config set user.name "John Doe" Set local config
2906
+ $ brch config set user.email "john@example.com" --global Set global config
2907
+
2908
+ Configuration is stored in:
2909
+ - Local: .brch/config (repository-specific)
2910
+ - Global: ~/.brchconfig (applies to all repositories)
2911
+
2912
+ Common configuration keys:
2913
+ - user.name: Your name
2914
+ - user.email: Your email address
2915
+ `).addCommand(new Command("set").argument("<scopeKey>", "Configuration key (e.g. user.name)").argument("<value>", "Configuration value").description("Set a configuration value").addHelpText("after", `
2916
+ Examples:
2917
+ $ brch config set user.name "John Doe"
2918
+ $ brch config set user.email "john@example.com" --global
2919
+ `).action(async function(scopeKey, value) {
2872
2920
  await setConfig({ scopeKey, value, isGlobal: this.parent?.opts().global ?? false });
2873
2921
  }));
2874
2922
 
2875
2923
  // src/services/initService.ts
2876
- import { mkdirSync, writeFileSync as writeFileSync2 } from "fs";
2924
+ import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
2877
2925
  var initRepo = async () => {
2878
2926
  try {
2879
- mkdirSync(VCS_DIR);
2880
- mkdirSync(OBJECT_DIR);
2881
- writeFileSync2(HEAD_FILE, "ref: refs/heads/master");
2882
- console.log("Initialized empty " + source_default.green("dlt") + " repository in " + source_default.green(process.cwd() + "/" + VCS_DIR));
2927
+ await mkdir2(VCS_DIR, { recursive: true });
2928
+ await mkdir2(OBJECTS_PATH, { recursive: true });
2929
+ await mkdir2(REFS_PATH, { recursive: true });
2930
+ await mkdir2(REFS_PATH + "/heads", { recursive: true });
2931
+ await writeFile2(HEAD_PATH, "ref: refs/heads/master");
2932
+ console.log("Initialized empty " + source_default.green("brch") + " repository in " + source_default.green(process.cwd() + "/" + VCS_DIR));
2883
2933
  } catch (error) {
2884
2934
  if (error.code === "EEXIST") {
2885
- console.log(source_default.red("dlt repository already initialized."));
2886
- return;
2935
+ console.log(source_default.red("brch repository already initialized."));
2887
2936
  }
2888
2937
  console.error("Error initializing repository:", error);
2938
+ process.exit(1);
2889
2939
  }
2890
2940
  };
2891
2941
 
2892
2942
  // src/commands/initCommand.ts
2893
- var initCommand = new Command("init").description("Initialize a new repository").action(async () => {
2894
- initRepo();
2895
- });
2943
+ var initCommand = new Command("init").description("Initialize a new brch repository in the current directory").addHelpText("after", `
2944
+ Examples:
2945
+ $ brch init
2946
+
2947
+ This command creates a .brch directory with the necessary structure for version control.
2948
+ The repository will track changes in the current directory and its subdirectories.
2949
+ `).action(initRepo);
2950
+
2951
+ // src/services/addService.ts
2952
+ import { mkdir as mkdir3, readdir, readFile as readFile2, stat, writeFile as writeFile3, access as access2 } from "node:fs/promises";
2953
+ import { constants as constants2 } from "node:fs";
2954
+ import { join as join2, relative, resolve, sep } from "node:path";
2955
+
2956
+ // src/utils/hash.ts
2957
+ import { createHash } from "crypto";
2958
+ var hashContent = (content) => {
2959
+ const hash = createHash("sha1");
2960
+ if (typeof content === "string") {
2961
+ hash.update(content, "utf-8");
2962
+ } else {
2963
+ hash.update(content);
2964
+ }
2965
+ return hash.digest("hex");
2966
+ };
2967
+
2968
+ // src/utils/objectPath.ts
2969
+ import { join } from "node:path";
2970
+ var getObjectPath = (hash, objectsDir) => {
2971
+ const objectDir = join(objectsDir, hash.slice(0, 2));
2972
+ const objectPath = join(objectDir, hash.slice(2));
2973
+ return { objectDir, objectPath };
2974
+ };
2896
2975
 
2897
2976
  // src/services/addService.ts
2898
- import { createHash } from "node:crypto";
2899
- import { existsSync as existsSync2 } from "node:fs";
2900
- import { mkdir, readdir, readFile, stat, writeFile } from "node:fs/promises";
2901
- import { join, relative, resolve, sep } from "node:path";
2902
- var INDEX_FILE = "index.json";
2903
2977
  var addFiles = async (paths) => {
2904
2978
  const repoRoot = process.cwd();
2905
- const brchPath = join(repoRoot, VCS_DIR);
2906
- if (!existsSync2(brchPath)) {
2979
+ try {
2980
+ await access2(VCS_PATH, constants2.F_OK);
2981
+ } catch {
2907
2982
  throw new Error("Not a brch repository (or any of the parent directories). Run `brch init` first.");
2908
2983
  }
2909
- const objectDir = join(repoRoot, OBJECT_DIR);
2910
- await mkdir(objectDir, { recursive: true });
2911
- const { filesToStage, missing } = await collectFiles(paths, repoRoot);
2912
- const indexPath = join(brchPath, INDEX_FILE);
2913
- const indexEntries = await readIndex(indexPath);
2984
+ const objectsDir = join2(repoRoot, OBJECTS_PATH);
2985
+ await mkdir3(objectsDir, { recursive: true });
2986
+ const ignorePatterns = await loadIgnorePatterns(repoRoot);
2987
+ const { filesToStage, missing } = await collectFiles(paths, repoRoot, ignorePatterns);
2988
+ const indexEntries = await readIndex(INDEX_PATH);
2914
2989
  const staged = [];
2915
2990
  const skipped = [...missing];
2916
2991
  for (const absPath of filesToStage) {
2917
2992
  const relPath = normalizeRelativePath(relative(repoRoot, absPath));
2918
- const fileBuffer = await readFile(absPath);
2919
- const hash = createHash("sha1").update(fileBuffer).digest("hex");
2920
- const objectPath = join(objectDir, hash);
2921
- if (!existsSync2(objectPath)) {
2922
- await writeFile(objectPath, fileBuffer);
2993
+ const fileBuffer = await readFile2(absPath);
2994
+ const hash = hashContent(fileBuffer);
2995
+ const { objectDir, objectPath } = getObjectPath(hash, objectsDir);
2996
+ try {
2997
+ await access2(objectPath, constants2.F_OK);
2998
+ } catch {
2999
+ await mkdir3(objectDir, { recursive: true });
3000
+ await writeFile3(objectPath, fileBuffer);
2923
3001
  }
2924
- if (indexEntries[relPath] === hash) {
3002
+ const existingEntry = indexEntries.find((entry) => entry.path === relPath);
3003
+ if (existingEntry && existingEntry.hash === hash) {
2925
3004
  skipped.push(relPath);
2926
3005
  continue;
2927
3006
  }
2928
- indexEntries[relPath] = hash;
3007
+ if (existingEntry) {
3008
+ existingEntry.hash = hash;
3009
+ } else {
3010
+ indexEntries.push({ path: relPath, hash });
3011
+ }
2929
3012
  staged.push(relPath);
2930
3013
  }
2931
- await writeFile(indexPath, JSON.stringify(indexEntries, null, 2));
3014
+ await writeFile3(INDEX_PATH, JSON.stringify(indexEntries, null, 2));
2932
3015
  return { staged, skipped };
2933
3016
  };
2934
- var collectFiles = async (targets, repoRoot) => {
3017
+ var collectFiles = async (targets, repoRoot, ignorePatterns) => {
2935
3018
  const filesToStage = new Set;
2936
3019
  const missing = [];
2937
3020
  for (const target of targets) {
@@ -2943,9 +3026,11 @@ var collectFiles = async (targets, repoRoot) => {
2943
3026
  try {
2944
3027
  const targetStat = await stat(absTargetPath);
2945
3028
  if (targetStat.isDirectory()) {
2946
- await walkDirectory(absTargetPath, repoRoot, filesToStage);
3029
+ await walkDirectory(absTargetPath, repoRoot, filesToStage, ignorePatterns);
2947
3030
  } else if (targetStat.isFile()) {
2948
- filesToStage.add(absTargetPath);
3031
+ if (!matchesIgnorePattern(absTargetPath, repoRoot, ignorePatterns)) {
3032
+ filesToStage.add(absTargetPath);
3033
+ }
2949
3034
  }
2950
3035
  } catch (error) {
2951
3036
  missing.push(target);
@@ -2953,26 +3038,107 @@ var collectFiles = async (targets, repoRoot) => {
2953
3038
  }
2954
3039
  return { filesToStage, missing };
2955
3040
  };
2956
- var walkDirectory = async (dir, repoRoot, collector) => {
3041
+ var walkDirectory = async (dir, repoRoot, collector, ignorePatterns) => {
2957
3042
  const entries = await readdir(dir, { withFileTypes: true });
2958
3043
  for (const entry of entries) {
2959
- const entryPath = join(dir, entry.name);
2960
- if (shouldIgnore(entryPath, repoRoot)) {
3044
+ const entryPath = join2(dir, entry.name);
3045
+ if (shouldIgnore(entryPath, repoRoot, ignorePatterns)) {
2961
3046
  continue;
2962
3047
  }
2963
3048
  if (entry.isDirectory()) {
2964
- await walkDirectory(entryPath, repoRoot, collector);
3049
+ await walkDirectory(entryPath, repoRoot, collector, ignorePatterns);
2965
3050
  } else if (entry.isFile()) {
2966
- collector.add(entryPath);
3051
+ if (!matchesIgnorePattern(entryPath, repoRoot, ignorePatterns)) {
3052
+ collector.add(entryPath);
3053
+ }
3054
+ }
3055
+ }
3056
+ };
3057
+ var loadIgnorePatterns = async (repoRoot) => {
3058
+ const ignorePath = join2(repoRoot, IGNORE_FILE);
3059
+ try {
3060
+ await access2(ignorePath, constants2.F_OK);
3061
+ } catch {
3062
+ return [];
3063
+ }
3064
+ try {
3065
+ const content = await readFile2(ignorePath, "utf-8");
3066
+ const patterns = [];
3067
+ for (const line of content.split(`
3068
+ `)) {
3069
+ const trimmed = line.trim();
3070
+ if (!trimmed || trimmed.startsWith("#")) {
3071
+ continue;
3072
+ }
3073
+ const negated = trimmed.startsWith("!");
3074
+ const pattern = negated ? trimmed.slice(1) : trimmed;
3075
+ const isDirectory = pattern.endsWith("/");
3076
+ const normalizedPattern = isDirectory ? pattern.slice(0, -1) : pattern;
3077
+ patterns.push({
3078
+ pattern: normalizedPattern,
3079
+ negated,
3080
+ isDirectory
3081
+ });
3082
+ }
3083
+ return patterns;
3084
+ } catch (error) {
3085
+ return [];
3086
+ }
3087
+ };
3088
+ var matchesIgnorePattern = (absPath, repoRoot, patterns) => {
3089
+ const relPath = normalizeRelativePath(relative(repoRoot, absPath));
3090
+ if (relPath === "") {
3091
+ return false;
3092
+ }
3093
+ let matched = false;
3094
+ let matchedNegated = false;
3095
+ for (const { pattern, negated, isDirectory } of patterns) {
3096
+ if (matchesPattern(relPath, pattern, isDirectory)) {
3097
+ if (negated) {
3098
+ matchedNegated = true;
3099
+ } else {
3100
+ matched = true;
3101
+ }
3102
+ }
3103
+ }
3104
+ return matched && !matchedNegated;
3105
+ };
3106
+ var matchesPattern = (relPath, pattern, isDirectoryPattern) => {
3107
+ let regexPattern = pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*\*/g, "___DOUBLE_STAR___").replace(/\*/g, "[^/]*").replace(/\?/g, "[^/]").replace(/___DOUBLE_STAR___/g, ".*");
3108
+ if (pattern.startsWith("/")) {
3109
+ regexPattern = "^" + regexPattern.slice(1);
3110
+ } else {
3111
+ regexPattern = "(^|/)" + regexPattern;
3112
+ }
3113
+ if (isDirectoryPattern) {
3114
+ regexPattern = regexPattern + "/";
3115
+ const regex = new RegExp(regexPattern);
3116
+ if (regex.test(relPath + "/")) {
3117
+ return true;
3118
+ }
3119
+ const pathParts = relPath.split("/");
3120
+ for (let i = 1;i <= pathParts.length; i++) {
3121
+ const subPath = pathParts.slice(0, i).join("/");
3122
+ if (regex.test(subPath + "/")) {
3123
+ return true;
3124
+ }
2967
3125
  }
3126
+ return false;
3127
+ } else {
3128
+ regexPattern = regexPattern + "$";
3129
+ const regex = new RegExp(regexPattern);
3130
+ return regex.test(relPath);
2968
3131
  }
2969
3132
  };
2970
- var shouldIgnore = (absPath, repoRoot) => {
3133
+ var shouldIgnore = (absPath, repoRoot, ignorePatterns) => {
2971
3134
  const relPath = normalizeRelativePath(relative(repoRoot, absPath));
2972
3135
  if (relPath === "") {
2973
3136
  return false;
2974
3137
  }
2975
- return relPath === VCS_DIR || relPath.startsWith(`${VCS_DIR}/`);
3138
+ if (relPath === VCS_DIR || relPath.startsWith(`${VCS_DIR}/`) || relPath === `./${VCS_DIR}` || relPath.startsWith(`./${VCS_DIR}/`)) {
3139
+ return true;
3140
+ }
3141
+ return matchesIgnorePattern(absPath, repoRoot, ignorePatterns);
2976
3142
  };
2977
3143
  var isWithinRepo = (absPath, repoRoot) => {
2978
3144
  const relPath = relative(repoRoot, absPath);
@@ -2982,30 +3148,60 @@ var isWithinRepo = (absPath, repoRoot) => {
2982
3148
  return !relPath.startsWith("..") && !relPath.includes(`..${sep}`);
2983
3149
  };
2984
3150
  var normalizeRelativePath = (pathValue) => {
2985
- return pathValue.split("\\").join("/");
3151
+ const normalized = pathValue.split("\\").join("/");
3152
+ if (normalized && !normalized.startsWith("./") && !normalized.startsWith("../") && !normalized.startsWith("/")) {
3153
+ return "./" + normalized;
3154
+ }
3155
+ return normalized;
2986
3156
  };
2987
3157
  var readIndex = async (indexPath) => {
2988
3158
  try {
2989
- const content = await readFile(indexPath, "utf-8");
2990
- return content ? JSON.parse(content) : {};
3159
+ const content = await readFile2(indexPath, "utf-8");
3160
+ if (!content) {
3161
+ return [];
3162
+ }
3163
+ const parsed = JSON.parse(content);
3164
+ if (Array.isArray(parsed)) {
3165
+ return parsed.map((entry) => ({
3166
+ ...entry,
3167
+ path: normalizeRelativePath(entry.path)
3168
+ }));
3169
+ } else if (typeof parsed === "object" && parsed !== null) {
3170
+ return Object.entries(parsed).map(([path, hash]) => ({
3171
+ path: normalizeRelativePath(path),
3172
+ hash
3173
+ }));
3174
+ }
3175
+ return [];
2991
3176
  } catch (error) {
2992
- return {};
3177
+ return [];
2993
3178
  }
2994
3179
  };
2995
3180
 
2996
3181
  // src/commands/addCommand.ts
2997
- var addCommand = new Command("add").argument("<paths...>", 'Files or directories to add to staging (supports "." for current directory)').description("Add files to the staging area").action(async (paths) => {
3182
+ var addCommand = new Command("add").argument("<paths...>", 'Files or directories to add to staging (supports "." for current directory)').description("Add files to the staging area for the next commit").addHelpText("after", `
3183
+ Examples:
3184
+ $ brch add file.txt Stage a single file
3185
+ $ brch add src/ Stage all files in src directory
3186
+ $ brch add . Stage all files in current directory
3187
+ $ brch add file1.txt file2.js Stage multiple files
3188
+
3189
+ The add command stages files for commit. Files that haven't changed since the last
3190
+ commit will be skipped. Only files that exist and have been modified will be staged.
3191
+ `).action(async (paths) => {
2998
3192
  const targets = paths;
2999
3193
  try {
3000
3194
  const { staged, skipped } = await addFiles(targets);
3001
3195
  if (staged.length > 0) {
3002
3196
  console.log(source_default.green("Staged:"));
3003
- staged.forEach((path) => console.log(` ${path}`));
3197
+ staged.forEach((path) => console.log(source_default.green(" - ") + path));
3004
3198
  }
3199
+ console.log();
3005
3200
  if (skipped.length > 0) {
3006
3201
  console.log(source_default.yellow("Skipped (unchanged or not found):"));
3007
- skipped.forEach((path) => console.log(` ${path}`));
3202
+ skipped.forEach((path) => console.log(source_default.yellow(" - ") + path));
3008
3203
  }
3204
+ console.log();
3009
3205
  if (staged.length === 0 && skipped.length === 0) {
3010
3206
  console.log(source_default.yellow("Nothing to add."));
3011
3207
  }
@@ -3015,14 +3211,2795 @@ var addCommand = new Command("add").argument("<paths...>", 'Files or directories
3015
3211
  }
3016
3212
  });
3017
3213
 
3018
- // src/commands/index.ts
3019
- var registerCommands = (program2) => {
3020
- program2.addCommand(configCommand);
3021
- program2.addCommand(initCommand);
3022
- program2.addCommand(addCommand);
3214
+ // src/services/commitService.ts
3215
+ import fs2 from "fs/promises";
3216
+ var import_ini2 = __toESM(require_ini(), 1);
3217
+ import path2 from "path";
3218
+ import { writeFile as writeFile4, mkdir as mkdir4 } from "fs/promises";
3219
+
3220
+ // src/utils/head.ts
3221
+ import fs from "fs/promises";
3222
+ import path from "path";
3223
+ var getCurrentBranchName = async () => {
3224
+ try {
3225
+ const headContent = await fs.readFile(HEAD_PATH, "utf-8");
3226
+ const headContentTrimmed = headContent.trim();
3227
+ if (headContentTrimmed.startsWith("ref: ")) {
3228
+ const refPath = headContentTrimmed.substring(5).trim();
3229
+ return refPath.replace("refs/heads/", "");
3230
+ }
3231
+ return null;
3232
+ } catch (error) {
3233
+ return null;
3234
+ }
3235
+ };
3236
+ var getCurrentHead = async () => {
3237
+ try {
3238
+ const headContent = await fs.readFile(HEAD_PATH, "utf-8");
3239
+ const headContentTrimmed = headContent.trim();
3240
+ if (headContentTrimmed.startsWith("ref: ")) {
3241
+ const refPath = headContentTrimmed.substring(5).trim();
3242
+ const branchName = refPath.replace("refs/heads/", "");
3243
+ const branchRefPath = path.join(process.cwd(), REFS_HEAD_PATH, branchName);
3244
+ try {
3245
+ const commitHash = await fs.readFile(branchRefPath, "utf-8");
3246
+ return commitHash.trim();
3247
+ } catch (error) {
3248
+ return null;
3249
+ }
3250
+ }
3251
+ return headContentTrimmed;
3252
+ } catch (error) {
3253
+ return null;
3254
+ }
3023
3255
  };
3024
3256
 
3025
- // src/index.ts
3026
- program.name(VCS_NAME).description("A simple VCS").version("0.0.1");
3257
+ // src/services/commitService.ts
3258
+ var commitChanges = async (message) => {
3259
+ try {
3260
+ const userData = await getUserData();
3261
+ const indexEntries = await readIndex2(INDEX_PATH);
3262
+ const parentCommit = await getCurrentHead();
3263
+ let branchName = await getCurrentBranchName();
3264
+ const commitData = {
3265
+ timeStamp: new Date().toISOString(),
3266
+ message,
3267
+ files: indexEntries,
3268
+ parent: parentCommit || "",
3269
+ author: {
3270
+ name: userData.user.name,
3271
+ email: userData.user.email
3272
+ }
3273
+ };
3274
+ const commitHash = hashContent(JSON.stringify(commitData));
3275
+ const repoRoot = process.cwd();
3276
+ const objectsDir = path2.join(repoRoot, OBJECTS_PATH);
3277
+ const { objectDir, objectPath } = getObjectPath(commitHash, objectsDir);
3278
+ await mkdir4(objectDir, { recursive: true });
3279
+ await writeFile4(objectPath, JSON.stringify(commitData));
3280
+ if (!branchName) {
3281
+ branchName = "master";
3282
+ await writeFile4(HEAD_PATH, `ref: refs/heads/${branchName}`);
3283
+ }
3284
+ const branchRefPath = path2.join(repoRoot, REFS_HEAD_PATH, branchName);
3285
+ await mkdir4(path2.dirname(branchRefPath), { recursive: true });
3286
+ await writeFile4(branchRefPath, commitHash);
3287
+ console.log(`Commit successfully created: ${commitHash}`);
3288
+ } catch (error) {
3289
+ const message2 = error instanceof Error ? error.message : String(error);
3290
+ console.log(source_default.red("Error creating commit:"), message2);
3291
+ process.exit(1);
3292
+ }
3293
+ };
3294
+ var normalizeRelativePath2 = (pathValue) => {
3295
+ const normalized = pathValue.split("\\").join("/");
3296
+ if (normalized && !normalized.startsWith("./") && !normalized.startsWith("../") && !normalized.startsWith("/")) {
3297
+ return "./" + normalized;
3298
+ }
3299
+ return normalized;
3300
+ };
3301
+ var readIndex2 = async (indexPath) => {
3302
+ try {
3303
+ const content = await fs2.readFile(indexPath, "utf-8");
3304
+ if (!content) {
3305
+ return [];
3306
+ }
3307
+ const parsed = JSON.parse(content);
3308
+ if (Array.isArray(parsed)) {
3309
+ return parsed.map((entry) => ({
3310
+ ...entry,
3311
+ path: normalizeRelativePath2(entry.path)
3312
+ }));
3313
+ } else if (typeof parsed === "object" && parsed !== null) {
3314
+ return Object.entries(parsed).map(([path3, hash]) => ({
3315
+ path: normalizeRelativePath2(path3),
3316
+ hash
3317
+ }));
3318
+ }
3319
+ return [];
3320
+ } catch (error) {
3321
+ return [];
3322
+ }
3323
+ };
3324
+ var getUserData = async () => {
3325
+ const readConfigFile2 = async (configPath) => {
3326
+ try {
3327
+ const configData = await fs2.readFile(configPath, "utf-8");
3328
+ return import_ini2.parse(configData);
3329
+ } catch (error) {
3330
+ return null;
3331
+ }
3332
+ };
3333
+ const localConfig = await readConfigFile2(LOCAL_CONFIG_PATH);
3334
+ if (localConfig) {
3335
+ return localConfig;
3336
+ }
3337
+ const globalConfig = await readConfigFile2(GLOBAL_CONFIG_PATH);
3338
+ if (globalConfig) {
3339
+ return globalConfig;
3340
+ }
3341
+ throw new Error("No config file found");
3342
+ };
3343
+
3344
+ // src/commands/commitCommand.ts
3345
+ var commitCommand = new Command("commit").description("Commit staged changes to the repository").option("-m, --message <message>", "Commit message describing the changes").addHelpText("after", `
3346
+ Examples:
3347
+ $ brch commit -m "Add new feature" Commit with a message
3348
+ $ brch commit --message "Fix bug" Commit with a message (alternative syntax)
3349
+
3350
+ The commit command creates a new commit with all currently staged files. You must
3351
+ provide a commit message using the -m or --message option. Only staged files will
3352
+ be included in the commit.
3353
+ `).action(async (options) => {
3354
+ commitChanges(options.message);
3355
+ });
3356
+
3357
+ // src/services/logService.ts
3358
+ import fs3 from "fs/promises";
3359
+ import path3 from "path";
3360
+
3361
+ // node_modules/date-fns/constants.js
3362
+ var daysInYear = 365.2425;
3363
+ var maxTime = Math.pow(10, 8) * 24 * 60 * 60 * 1000;
3364
+ var minTime = -maxTime;
3365
+ var millisecondsInWeek = 604800000;
3366
+ var millisecondsInDay = 86400000;
3367
+ var secondsInHour = 3600;
3368
+ var secondsInDay = secondsInHour * 24;
3369
+ var secondsInWeek = secondsInDay * 7;
3370
+ var secondsInYear = secondsInDay * daysInYear;
3371
+ var secondsInMonth = secondsInYear / 12;
3372
+ var secondsInQuarter = secondsInMonth * 3;
3373
+ var constructFromSymbol = Symbol.for("constructDateFrom");
3374
+
3375
+ // node_modules/date-fns/constructFrom.js
3376
+ function constructFrom(date, value) {
3377
+ if (typeof date === "function")
3378
+ return date(value);
3379
+ if (date && typeof date === "object" && constructFromSymbol in date)
3380
+ return date[constructFromSymbol](value);
3381
+ if (date instanceof Date)
3382
+ return new date.constructor(value);
3383
+ return new Date(value);
3384
+ }
3385
+
3386
+ // node_modules/date-fns/toDate.js
3387
+ function toDate(argument, context) {
3388
+ return constructFrom(context || argument, argument);
3389
+ }
3390
+
3391
+ // node_modules/date-fns/_lib/defaultOptions.js
3392
+ var defaultOptions = {};
3393
+ function getDefaultOptions() {
3394
+ return defaultOptions;
3395
+ }
3396
+
3397
+ // node_modules/date-fns/startOfWeek.js
3398
+ function startOfWeek(date, options) {
3399
+ const defaultOptions2 = getDefaultOptions();
3400
+ const weekStartsOn = options?.weekStartsOn ?? options?.locale?.options?.weekStartsOn ?? defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
3401
+ const _date = toDate(date, options?.in);
3402
+ const day = _date.getDay();
3403
+ const diff = (day < weekStartsOn ? 7 : 0) + day - weekStartsOn;
3404
+ _date.setDate(_date.getDate() - diff);
3405
+ _date.setHours(0, 0, 0, 0);
3406
+ return _date;
3407
+ }
3408
+
3409
+ // node_modules/date-fns/startOfISOWeek.js
3410
+ function startOfISOWeek(date, options) {
3411
+ return startOfWeek(date, { ...options, weekStartsOn: 1 });
3412
+ }
3413
+
3414
+ // node_modules/date-fns/getISOWeekYear.js
3415
+ function getISOWeekYear(date, options) {
3416
+ const _date = toDate(date, options?.in);
3417
+ const year = _date.getFullYear();
3418
+ const fourthOfJanuaryOfNextYear = constructFrom(_date, 0);
3419
+ fourthOfJanuaryOfNextYear.setFullYear(year + 1, 0, 4);
3420
+ fourthOfJanuaryOfNextYear.setHours(0, 0, 0, 0);
3421
+ const startOfNextYear = startOfISOWeek(fourthOfJanuaryOfNextYear);
3422
+ const fourthOfJanuaryOfThisYear = constructFrom(_date, 0);
3423
+ fourthOfJanuaryOfThisYear.setFullYear(year, 0, 4);
3424
+ fourthOfJanuaryOfThisYear.setHours(0, 0, 0, 0);
3425
+ const startOfThisYear = startOfISOWeek(fourthOfJanuaryOfThisYear);
3426
+ if (_date.getTime() >= startOfNextYear.getTime()) {
3427
+ return year + 1;
3428
+ } else if (_date.getTime() >= startOfThisYear.getTime()) {
3429
+ return year;
3430
+ } else {
3431
+ return year - 1;
3432
+ }
3433
+ }
3434
+
3435
+ // node_modules/date-fns/_lib/getTimezoneOffsetInMilliseconds.js
3436
+ function getTimezoneOffsetInMilliseconds(date) {
3437
+ const _date = toDate(date);
3438
+ const utcDate = new Date(Date.UTC(_date.getFullYear(), _date.getMonth(), _date.getDate(), _date.getHours(), _date.getMinutes(), _date.getSeconds(), _date.getMilliseconds()));
3439
+ utcDate.setUTCFullYear(_date.getFullYear());
3440
+ return +date - +utcDate;
3441
+ }
3442
+
3443
+ // node_modules/date-fns/_lib/normalizeDates.js
3444
+ function normalizeDates(context, ...dates) {
3445
+ const normalize = constructFrom.bind(null, context || dates.find((date) => typeof date === "object"));
3446
+ return dates.map(normalize);
3447
+ }
3448
+
3449
+ // node_modules/date-fns/startOfDay.js
3450
+ function startOfDay(date, options) {
3451
+ const _date = toDate(date, options?.in);
3452
+ _date.setHours(0, 0, 0, 0);
3453
+ return _date;
3454
+ }
3455
+
3456
+ // node_modules/date-fns/differenceInCalendarDays.js
3457
+ function differenceInCalendarDays(laterDate, earlierDate, options) {
3458
+ const [laterDate_, earlierDate_] = normalizeDates(options?.in, laterDate, earlierDate);
3459
+ const laterStartOfDay = startOfDay(laterDate_);
3460
+ const earlierStartOfDay = startOfDay(earlierDate_);
3461
+ const laterTimestamp = +laterStartOfDay - getTimezoneOffsetInMilliseconds(laterStartOfDay);
3462
+ const earlierTimestamp = +earlierStartOfDay - getTimezoneOffsetInMilliseconds(earlierStartOfDay);
3463
+ return Math.round((laterTimestamp - earlierTimestamp) / millisecondsInDay);
3464
+ }
3465
+
3466
+ // node_modules/date-fns/startOfISOWeekYear.js
3467
+ function startOfISOWeekYear(date, options) {
3468
+ const year = getISOWeekYear(date, options);
3469
+ const fourthOfJanuary = constructFrom(options?.in || date, 0);
3470
+ fourthOfJanuary.setFullYear(year, 0, 4);
3471
+ fourthOfJanuary.setHours(0, 0, 0, 0);
3472
+ return startOfISOWeek(fourthOfJanuary);
3473
+ }
3474
+
3475
+ // node_modules/date-fns/isDate.js
3476
+ function isDate(value) {
3477
+ return value instanceof Date || typeof value === "object" && Object.prototype.toString.call(value) === "[object Date]";
3478
+ }
3479
+
3480
+ // node_modules/date-fns/isValid.js
3481
+ function isValid(date) {
3482
+ return !(!isDate(date) && typeof date !== "number" || isNaN(+toDate(date)));
3483
+ }
3484
+
3485
+ // node_modules/date-fns/startOfYear.js
3486
+ function startOfYear(date, options) {
3487
+ const date_ = toDate(date, options?.in);
3488
+ date_.setFullYear(date_.getFullYear(), 0, 1);
3489
+ date_.setHours(0, 0, 0, 0);
3490
+ return date_;
3491
+ }
3492
+
3493
+ // node_modules/date-fns/locale/en-US/_lib/formatDistance.js
3494
+ var formatDistanceLocale = {
3495
+ lessThanXSeconds: {
3496
+ one: "less than a second",
3497
+ other: "less than {{count}} seconds"
3498
+ },
3499
+ xSeconds: {
3500
+ one: "1 second",
3501
+ other: "{{count}} seconds"
3502
+ },
3503
+ halfAMinute: "half a minute",
3504
+ lessThanXMinutes: {
3505
+ one: "less than a minute",
3506
+ other: "less than {{count}} minutes"
3507
+ },
3508
+ xMinutes: {
3509
+ one: "1 minute",
3510
+ other: "{{count}} minutes"
3511
+ },
3512
+ aboutXHours: {
3513
+ one: "about 1 hour",
3514
+ other: "about {{count}} hours"
3515
+ },
3516
+ xHours: {
3517
+ one: "1 hour",
3518
+ other: "{{count}} hours"
3519
+ },
3520
+ xDays: {
3521
+ one: "1 day",
3522
+ other: "{{count}} days"
3523
+ },
3524
+ aboutXWeeks: {
3525
+ one: "about 1 week",
3526
+ other: "about {{count}} weeks"
3527
+ },
3528
+ xWeeks: {
3529
+ one: "1 week",
3530
+ other: "{{count}} weeks"
3531
+ },
3532
+ aboutXMonths: {
3533
+ one: "about 1 month",
3534
+ other: "about {{count}} months"
3535
+ },
3536
+ xMonths: {
3537
+ one: "1 month",
3538
+ other: "{{count}} months"
3539
+ },
3540
+ aboutXYears: {
3541
+ one: "about 1 year",
3542
+ other: "about {{count}} years"
3543
+ },
3544
+ xYears: {
3545
+ one: "1 year",
3546
+ other: "{{count}} years"
3547
+ },
3548
+ overXYears: {
3549
+ one: "over 1 year",
3550
+ other: "over {{count}} years"
3551
+ },
3552
+ almostXYears: {
3553
+ one: "almost 1 year",
3554
+ other: "almost {{count}} years"
3555
+ }
3556
+ };
3557
+ var formatDistance = (token, count, options) => {
3558
+ let result;
3559
+ const tokenValue = formatDistanceLocale[token];
3560
+ if (typeof tokenValue === "string") {
3561
+ result = tokenValue;
3562
+ } else if (count === 1) {
3563
+ result = tokenValue.one;
3564
+ } else {
3565
+ result = tokenValue.other.replace("{{count}}", count.toString());
3566
+ }
3567
+ if (options?.addSuffix) {
3568
+ if (options.comparison && options.comparison > 0) {
3569
+ return "in " + result;
3570
+ } else {
3571
+ return result + " ago";
3572
+ }
3573
+ }
3574
+ return result;
3575
+ };
3576
+
3577
+ // node_modules/date-fns/locale/_lib/buildFormatLongFn.js
3578
+ function buildFormatLongFn(args) {
3579
+ return (options = {}) => {
3580
+ const width = options.width ? String(options.width) : args.defaultWidth;
3581
+ const format = args.formats[width] || args.formats[args.defaultWidth];
3582
+ return format;
3583
+ };
3584
+ }
3585
+
3586
+ // node_modules/date-fns/locale/en-US/_lib/formatLong.js
3587
+ var dateFormats = {
3588
+ full: "EEEE, MMMM do, y",
3589
+ long: "MMMM do, y",
3590
+ medium: "MMM d, y",
3591
+ short: "MM/dd/yyyy"
3592
+ };
3593
+ var timeFormats = {
3594
+ full: "h:mm:ss a zzzz",
3595
+ long: "h:mm:ss a z",
3596
+ medium: "h:mm:ss a",
3597
+ short: "h:mm a"
3598
+ };
3599
+ var dateTimeFormats = {
3600
+ full: "{{date}} 'at' {{time}}",
3601
+ long: "{{date}} 'at' {{time}}",
3602
+ medium: "{{date}}, {{time}}",
3603
+ short: "{{date}}, {{time}}"
3604
+ };
3605
+ var formatLong = {
3606
+ date: buildFormatLongFn({
3607
+ formats: dateFormats,
3608
+ defaultWidth: "full"
3609
+ }),
3610
+ time: buildFormatLongFn({
3611
+ formats: timeFormats,
3612
+ defaultWidth: "full"
3613
+ }),
3614
+ dateTime: buildFormatLongFn({
3615
+ formats: dateTimeFormats,
3616
+ defaultWidth: "full"
3617
+ })
3618
+ };
3619
+
3620
+ // node_modules/date-fns/locale/en-US/_lib/formatRelative.js
3621
+ var formatRelativeLocale = {
3622
+ lastWeek: "'last' eeee 'at' p",
3623
+ yesterday: "'yesterday at' p",
3624
+ today: "'today at' p",
3625
+ tomorrow: "'tomorrow at' p",
3626
+ nextWeek: "eeee 'at' p",
3627
+ other: "P"
3628
+ };
3629
+ var formatRelative = (token, _date, _baseDate, _options) => formatRelativeLocale[token];
3630
+
3631
+ // node_modules/date-fns/locale/_lib/buildLocalizeFn.js
3632
+ function buildLocalizeFn(args) {
3633
+ return (value, options) => {
3634
+ const context = options?.context ? String(options.context) : "standalone";
3635
+ let valuesArray;
3636
+ if (context === "formatting" && args.formattingValues) {
3637
+ const defaultWidth = args.defaultFormattingWidth || args.defaultWidth;
3638
+ const width = options?.width ? String(options.width) : defaultWidth;
3639
+ valuesArray = args.formattingValues[width] || args.formattingValues[defaultWidth];
3640
+ } else {
3641
+ const defaultWidth = args.defaultWidth;
3642
+ const width = options?.width ? String(options.width) : args.defaultWidth;
3643
+ valuesArray = args.values[width] || args.values[defaultWidth];
3644
+ }
3645
+ const index = args.argumentCallback ? args.argumentCallback(value) : value;
3646
+ return valuesArray[index];
3647
+ };
3648
+ }
3649
+
3650
+ // node_modules/date-fns/locale/en-US/_lib/localize.js
3651
+ var eraValues = {
3652
+ narrow: ["B", "A"],
3653
+ abbreviated: ["BC", "AD"],
3654
+ wide: ["Before Christ", "Anno Domini"]
3655
+ };
3656
+ var quarterValues = {
3657
+ narrow: ["1", "2", "3", "4"],
3658
+ abbreviated: ["Q1", "Q2", "Q3", "Q4"],
3659
+ wide: ["1st quarter", "2nd quarter", "3rd quarter", "4th quarter"]
3660
+ };
3661
+ var monthValues = {
3662
+ narrow: ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"],
3663
+ abbreviated: [
3664
+ "Jan",
3665
+ "Feb",
3666
+ "Mar",
3667
+ "Apr",
3668
+ "May",
3669
+ "Jun",
3670
+ "Jul",
3671
+ "Aug",
3672
+ "Sep",
3673
+ "Oct",
3674
+ "Nov",
3675
+ "Dec"
3676
+ ],
3677
+ wide: [
3678
+ "January",
3679
+ "February",
3680
+ "March",
3681
+ "April",
3682
+ "May",
3683
+ "June",
3684
+ "July",
3685
+ "August",
3686
+ "September",
3687
+ "October",
3688
+ "November",
3689
+ "December"
3690
+ ]
3691
+ };
3692
+ var dayValues = {
3693
+ narrow: ["S", "M", "T", "W", "T", "F", "S"],
3694
+ short: ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"],
3695
+ abbreviated: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
3696
+ wide: [
3697
+ "Sunday",
3698
+ "Monday",
3699
+ "Tuesday",
3700
+ "Wednesday",
3701
+ "Thursday",
3702
+ "Friday",
3703
+ "Saturday"
3704
+ ]
3705
+ };
3706
+ var dayPeriodValues = {
3707
+ narrow: {
3708
+ am: "a",
3709
+ pm: "p",
3710
+ midnight: "mi",
3711
+ noon: "n",
3712
+ morning: "morning",
3713
+ afternoon: "afternoon",
3714
+ evening: "evening",
3715
+ night: "night"
3716
+ },
3717
+ abbreviated: {
3718
+ am: "AM",
3719
+ pm: "PM",
3720
+ midnight: "midnight",
3721
+ noon: "noon",
3722
+ morning: "morning",
3723
+ afternoon: "afternoon",
3724
+ evening: "evening",
3725
+ night: "night"
3726
+ },
3727
+ wide: {
3728
+ am: "a.m.",
3729
+ pm: "p.m.",
3730
+ midnight: "midnight",
3731
+ noon: "noon",
3732
+ morning: "morning",
3733
+ afternoon: "afternoon",
3734
+ evening: "evening",
3735
+ night: "night"
3736
+ }
3737
+ };
3738
+ var formattingDayPeriodValues = {
3739
+ narrow: {
3740
+ am: "a",
3741
+ pm: "p",
3742
+ midnight: "mi",
3743
+ noon: "n",
3744
+ morning: "in the morning",
3745
+ afternoon: "in the afternoon",
3746
+ evening: "in the evening",
3747
+ night: "at night"
3748
+ },
3749
+ abbreviated: {
3750
+ am: "AM",
3751
+ pm: "PM",
3752
+ midnight: "midnight",
3753
+ noon: "noon",
3754
+ morning: "in the morning",
3755
+ afternoon: "in the afternoon",
3756
+ evening: "in the evening",
3757
+ night: "at night"
3758
+ },
3759
+ wide: {
3760
+ am: "a.m.",
3761
+ pm: "p.m.",
3762
+ midnight: "midnight",
3763
+ noon: "noon",
3764
+ morning: "in the morning",
3765
+ afternoon: "in the afternoon",
3766
+ evening: "in the evening",
3767
+ night: "at night"
3768
+ }
3769
+ };
3770
+ var ordinalNumber = (dirtyNumber, _options) => {
3771
+ const number = Number(dirtyNumber);
3772
+ const rem100 = number % 100;
3773
+ if (rem100 > 20 || rem100 < 10) {
3774
+ switch (rem100 % 10) {
3775
+ case 1:
3776
+ return number + "st";
3777
+ case 2:
3778
+ return number + "nd";
3779
+ case 3:
3780
+ return number + "rd";
3781
+ }
3782
+ }
3783
+ return number + "th";
3784
+ };
3785
+ var localize = {
3786
+ ordinalNumber,
3787
+ era: buildLocalizeFn({
3788
+ values: eraValues,
3789
+ defaultWidth: "wide"
3790
+ }),
3791
+ quarter: buildLocalizeFn({
3792
+ values: quarterValues,
3793
+ defaultWidth: "wide",
3794
+ argumentCallback: (quarter) => quarter - 1
3795
+ }),
3796
+ month: buildLocalizeFn({
3797
+ values: monthValues,
3798
+ defaultWidth: "wide"
3799
+ }),
3800
+ day: buildLocalizeFn({
3801
+ values: dayValues,
3802
+ defaultWidth: "wide"
3803
+ }),
3804
+ dayPeriod: buildLocalizeFn({
3805
+ values: dayPeriodValues,
3806
+ defaultWidth: "wide",
3807
+ formattingValues: formattingDayPeriodValues,
3808
+ defaultFormattingWidth: "wide"
3809
+ })
3810
+ };
3811
+
3812
+ // node_modules/date-fns/locale/_lib/buildMatchFn.js
3813
+ function buildMatchFn(args) {
3814
+ return (string, options = {}) => {
3815
+ const width = options.width;
3816
+ const matchPattern = width && args.matchPatterns[width] || args.matchPatterns[args.defaultMatchWidth];
3817
+ const matchResult = string.match(matchPattern);
3818
+ if (!matchResult) {
3819
+ return null;
3820
+ }
3821
+ const matchedString = matchResult[0];
3822
+ const parsePatterns = width && args.parsePatterns[width] || args.parsePatterns[args.defaultParseWidth];
3823
+ const key = Array.isArray(parsePatterns) ? findIndex(parsePatterns, (pattern) => pattern.test(matchedString)) : findKey(parsePatterns, (pattern) => pattern.test(matchedString));
3824
+ let value;
3825
+ value = args.valueCallback ? args.valueCallback(key) : key;
3826
+ value = options.valueCallback ? options.valueCallback(value) : value;
3827
+ const rest = string.slice(matchedString.length);
3828
+ return { value, rest };
3829
+ };
3830
+ }
3831
+ function findKey(object, predicate) {
3832
+ for (const key in object) {
3833
+ if (Object.prototype.hasOwnProperty.call(object, key) && predicate(object[key])) {
3834
+ return key;
3835
+ }
3836
+ }
3837
+ return;
3838
+ }
3839
+ function findIndex(array, predicate) {
3840
+ for (let key = 0;key < array.length; key++) {
3841
+ if (predicate(array[key])) {
3842
+ return key;
3843
+ }
3844
+ }
3845
+ return;
3846
+ }
3847
+
3848
+ // node_modules/date-fns/locale/_lib/buildMatchPatternFn.js
3849
+ function buildMatchPatternFn(args) {
3850
+ return (string, options = {}) => {
3851
+ const matchResult = string.match(args.matchPattern);
3852
+ if (!matchResult)
3853
+ return null;
3854
+ const matchedString = matchResult[0];
3855
+ const parseResult = string.match(args.parsePattern);
3856
+ if (!parseResult)
3857
+ return null;
3858
+ let value = args.valueCallback ? args.valueCallback(parseResult[0]) : parseResult[0];
3859
+ value = options.valueCallback ? options.valueCallback(value) : value;
3860
+ const rest = string.slice(matchedString.length);
3861
+ return { value, rest };
3862
+ };
3863
+ }
3864
+
3865
+ // node_modules/date-fns/locale/en-US/_lib/match.js
3866
+ var matchOrdinalNumberPattern = /^(\d+)(th|st|nd|rd)?/i;
3867
+ var parseOrdinalNumberPattern = /\d+/i;
3868
+ var matchEraPatterns = {
3869
+ narrow: /^(b|a)/i,
3870
+ abbreviated: /^(b\.?\s?c\.?|b\.?\s?c\.?\s?e\.?|a\.?\s?d\.?|c\.?\s?e\.?)/i,
3871
+ wide: /^(before christ|before common era|anno domini|common era)/i
3872
+ };
3873
+ var parseEraPatterns = {
3874
+ any: [/^b/i, /^(a|c)/i]
3875
+ };
3876
+ var matchQuarterPatterns = {
3877
+ narrow: /^[1234]/i,
3878
+ abbreviated: /^q[1234]/i,
3879
+ wide: /^[1234](th|st|nd|rd)? quarter/i
3880
+ };
3881
+ var parseQuarterPatterns = {
3882
+ any: [/1/i, /2/i, /3/i, /4/i]
3883
+ };
3884
+ var matchMonthPatterns = {
3885
+ narrow: /^[jfmasond]/i,
3886
+ abbreviated: /^(jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec)/i,
3887
+ wide: /^(january|february|march|april|may|june|july|august|september|october|november|december)/i
3888
+ };
3889
+ var parseMonthPatterns = {
3890
+ narrow: [
3891
+ /^j/i,
3892
+ /^f/i,
3893
+ /^m/i,
3894
+ /^a/i,
3895
+ /^m/i,
3896
+ /^j/i,
3897
+ /^j/i,
3898
+ /^a/i,
3899
+ /^s/i,
3900
+ /^o/i,
3901
+ /^n/i,
3902
+ /^d/i
3903
+ ],
3904
+ any: [
3905
+ /^ja/i,
3906
+ /^f/i,
3907
+ /^mar/i,
3908
+ /^ap/i,
3909
+ /^may/i,
3910
+ /^jun/i,
3911
+ /^jul/i,
3912
+ /^au/i,
3913
+ /^s/i,
3914
+ /^o/i,
3915
+ /^n/i,
3916
+ /^d/i
3917
+ ]
3918
+ };
3919
+ var matchDayPatterns = {
3920
+ narrow: /^[smtwf]/i,
3921
+ short: /^(su|mo|tu|we|th|fr|sa)/i,
3922
+ abbreviated: /^(sun|mon|tue|wed|thu|fri|sat)/i,
3923
+ wide: /^(sunday|monday|tuesday|wednesday|thursday|friday|saturday)/i
3924
+ };
3925
+ var parseDayPatterns = {
3926
+ narrow: [/^s/i, /^m/i, /^t/i, /^w/i, /^t/i, /^f/i, /^s/i],
3927
+ any: [/^su/i, /^m/i, /^tu/i, /^w/i, /^th/i, /^f/i, /^sa/i]
3928
+ };
3929
+ var matchDayPeriodPatterns = {
3930
+ narrow: /^(a|p|mi|n|(in the|at) (morning|afternoon|evening|night))/i,
3931
+ any: /^([ap]\.?\s?m\.?|midnight|noon|(in the|at) (morning|afternoon|evening|night))/i
3932
+ };
3933
+ var parseDayPeriodPatterns = {
3934
+ any: {
3935
+ am: /^a/i,
3936
+ pm: /^p/i,
3937
+ midnight: /^mi/i,
3938
+ noon: /^no/i,
3939
+ morning: /morning/i,
3940
+ afternoon: /afternoon/i,
3941
+ evening: /evening/i,
3942
+ night: /night/i
3943
+ }
3944
+ };
3945
+ var match = {
3946
+ ordinalNumber: buildMatchPatternFn({
3947
+ matchPattern: matchOrdinalNumberPattern,
3948
+ parsePattern: parseOrdinalNumberPattern,
3949
+ valueCallback: (value) => parseInt(value, 10)
3950
+ }),
3951
+ era: buildMatchFn({
3952
+ matchPatterns: matchEraPatterns,
3953
+ defaultMatchWidth: "wide",
3954
+ parsePatterns: parseEraPatterns,
3955
+ defaultParseWidth: "any"
3956
+ }),
3957
+ quarter: buildMatchFn({
3958
+ matchPatterns: matchQuarterPatterns,
3959
+ defaultMatchWidth: "wide",
3960
+ parsePatterns: parseQuarterPatterns,
3961
+ defaultParseWidth: "any",
3962
+ valueCallback: (index) => index + 1
3963
+ }),
3964
+ month: buildMatchFn({
3965
+ matchPatterns: matchMonthPatterns,
3966
+ defaultMatchWidth: "wide",
3967
+ parsePatterns: parseMonthPatterns,
3968
+ defaultParseWidth: "any"
3969
+ }),
3970
+ day: buildMatchFn({
3971
+ matchPatterns: matchDayPatterns,
3972
+ defaultMatchWidth: "wide",
3973
+ parsePatterns: parseDayPatterns,
3974
+ defaultParseWidth: "any"
3975
+ }),
3976
+ dayPeriod: buildMatchFn({
3977
+ matchPatterns: matchDayPeriodPatterns,
3978
+ defaultMatchWidth: "any",
3979
+ parsePatterns: parseDayPeriodPatterns,
3980
+ defaultParseWidth: "any"
3981
+ })
3982
+ };
3983
+
3984
+ // node_modules/date-fns/locale/en-US.js
3985
+ var enUS = {
3986
+ code: "en-US",
3987
+ formatDistance,
3988
+ formatLong,
3989
+ formatRelative,
3990
+ localize,
3991
+ match,
3992
+ options: {
3993
+ weekStartsOn: 0,
3994
+ firstWeekContainsDate: 1
3995
+ }
3996
+ };
3997
+ // node_modules/date-fns/getDayOfYear.js
3998
+ function getDayOfYear(date, options) {
3999
+ const _date = toDate(date, options?.in);
4000
+ const diff = differenceInCalendarDays(_date, startOfYear(_date));
4001
+ const dayOfYear = diff + 1;
4002
+ return dayOfYear;
4003
+ }
4004
+
4005
+ // node_modules/date-fns/getISOWeek.js
4006
+ function getISOWeek(date, options) {
4007
+ const _date = toDate(date, options?.in);
4008
+ const diff = +startOfISOWeek(_date) - +startOfISOWeekYear(_date);
4009
+ return Math.round(diff / millisecondsInWeek) + 1;
4010
+ }
4011
+
4012
+ // node_modules/date-fns/getWeekYear.js
4013
+ function getWeekYear(date, options) {
4014
+ const _date = toDate(date, options?.in);
4015
+ const year = _date.getFullYear();
4016
+ const defaultOptions2 = getDefaultOptions();
4017
+ const firstWeekContainsDate = options?.firstWeekContainsDate ?? options?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
4018
+ const firstWeekOfNextYear = constructFrom(options?.in || date, 0);
4019
+ firstWeekOfNextYear.setFullYear(year + 1, 0, firstWeekContainsDate);
4020
+ firstWeekOfNextYear.setHours(0, 0, 0, 0);
4021
+ const startOfNextYear = startOfWeek(firstWeekOfNextYear, options);
4022
+ const firstWeekOfThisYear = constructFrom(options?.in || date, 0);
4023
+ firstWeekOfThisYear.setFullYear(year, 0, firstWeekContainsDate);
4024
+ firstWeekOfThisYear.setHours(0, 0, 0, 0);
4025
+ const startOfThisYear = startOfWeek(firstWeekOfThisYear, options);
4026
+ if (+_date >= +startOfNextYear) {
4027
+ return year + 1;
4028
+ } else if (+_date >= +startOfThisYear) {
4029
+ return year;
4030
+ } else {
4031
+ return year - 1;
4032
+ }
4033
+ }
4034
+
4035
+ // node_modules/date-fns/startOfWeekYear.js
4036
+ function startOfWeekYear(date, options) {
4037
+ const defaultOptions2 = getDefaultOptions();
4038
+ const firstWeekContainsDate = options?.firstWeekContainsDate ?? options?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
4039
+ const year = getWeekYear(date, options);
4040
+ const firstWeek = constructFrom(options?.in || date, 0);
4041
+ firstWeek.setFullYear(year, 0, firstWeekContainsDate);
4042
+ firstWeek.setHours(0, 0, 0, 0);
4043
+ const _date = startOfWeek(firstWeek, options);
4044
+ return _date;
4045
+ }
4046
+
4047
+ // node_modules/date-fns/getWeek.js
4048
+ function getWeek(date, options) {
4049
+ const _date = toDate(date, options?.in);
4050
+ const diff = +startOfWeek(_date, options) - +startOfWeekYear(_date, options);
4051
+ return Math.round(diff / millisecondsInWeek) + 1;
4052
+ }
4053
+
4054
+ // node_modules/date-fns/_lib/addLeadingZeros.js
4055
+ function addLeadingZeros(number, targetLength) {
4056
+ const sign = number < 0 ? "-" : "";
4057
+ const output = Math.abs(number).toString().padStart(targetLength, "0");
4058
+ return sign + output;
4059
+ }
4060
+
4061
+ // node_modules/date-fns/_lib/format/lightFormatters.js
4062
+ var lightFormatters = {
4063
+ y(date, token) {
4064
+ const signedYear = date.getFullYear();
4065
+ const year = signedYear > 0 ? signedYear : 1 - signedYear;
4066
+ return addLeadingZeros(token === "yy" ? year % 100 : year, token.length);
4067
+ },
4068
+ M(date, token) {
4069
+ const month = date.getMonth();
4070
+ return token === "M" ? String(month + 1) : addLeadingZeros(month + 1, 2);
4071
+ },
4072
+ d(date, token) {
4073
+ return addLeadingZeros(date.getDate(), token.length);
4074
+ },
4075
+ a(date, token) {
4076
+ const dayPeriodEnumValue = date.getHours() / 12 >= 1 ? "pm" : "am";
4077
+ switch (token) {
4078
+ case "a":
4079
+ case "aa":
4080
+ return dayPeriodEnumValue.toUpperCase();
4081
+ case "aaa":
4082
+ return dayPeriodEnumValue;
4083
+ case "aaaaa":
4084
+ return dayPeriodEnumValue[0];
4085
+ case "aaaa":
4086
+ default:
4087
+ return dayPeriodEnumValue === "am" ? "a.m." : "p.m.";
4088
+ }
4089
+ },
4090
+ h(date, token) {
4091
+ return addLeadingZeros(date.getHours() % 12 || 12, token.length);
4092
+ },
4093
+ H(date, token) {
4094
+ return addLeadingZeros(date.getHours(), token.length);
4095
+ },
4096
+ m(date, token) {
4097
+ return addLeadingZeros(date.getMinutes(), token.length);
4098
+ },
4099
+ s(date, token) {
4100
+ return addLeadingZeros(date.getSeconds(), token.length);
4101
+ },
4102
+ S(date, token) {
4103
+ const numberOfDigits = token.length;
4104
+ const milliseconds = date.getMilliseconds();
4105
+ const fractionalSeconds = Math.trunc(milliseconds * Math.pow(10, numberOfDigits - 3));
4106
+ return addLeadingZeros(fractionalSeconds, token.length);
4107
+ }
4108
+ };
4109
+
4110
+ // node_modules/date-fns/_lib/format/formatters.js
4111
+ var dayPeriodEnum = {
4112
+ am: "am",
4113
+ pm: "pm",
4114
+ midnight: "midnight",
4115
+ noon: "noon",
4116
+ morning: "morning",
4117
+ afternoon: "afternoon",
4118
+ evening: "evening",
4119
+ night: "night"
4120
+ };
4121
+ var formatters = {
4122
+ G: function(date, token, localize2) {
4123
+ const era = date.getFullYear() > 0 ? 1 : 0;
4124
+ switch (token) {
4125
+ case "G":
4126
+ case "GG":
4127
+ case "GGG":
4128
+ return localize2.era(era, { width: "abbreviated" });
4129
+ case "GGGGG":
4130
+ return localize2.era(era, { width: "narrow" });
4131
+ case "GGGG":
4132
+ default:
4133
+ return localize2.era(era, { width: "wide" });
4134
+ }
4135
+ },
4136
+ y: function(date, token, localize2) {
4137
+ if (token === "yo") {
4138
+ const signedYear = date.getFullYear();
4139
+ const year = signedYear > 0 ? signedYear : 1 - signedYear;
4140
+ return localize2.ordinalNumber(year, { unit: "year" });
4141
+ }
4142
+ return lightFormatters.y(date, token);
4143
+ },
4144
+ Y: function(date, token, localize2, options) {
4145
+ const signedWeekYear = getWeekYear(date, options);
4146
+ const weekYear = signedWeekYear > 0 ? signedWeekYear : 1 - signedWeekYear;
4147
+ if (token === "YY") {
4148
+ const twoDigitYear = weekYear % 100;
4149
+ return addLeadingZeros(twoDigitYear, 2);
4150
+ }
4151
+ if (token === "Yo") {
4152
+ return localize2.ordinalNumber(weekYear, { unit: "year" });
4153
+ }
4154
+ return addLeadingZeros(weekYear, token.length);
4155
+ },
4156
+ R: function(date, token) {
4157
+ const isoWeekYear = getISOWeekYear(date);
4158
+ return addLeadingZeros(isoWeekYear, token.length);
4159
+ },
4160
+ u: function(date, token) {
4161
+ const year = date.getFullYear();
4162
+ return addLeadingZeros(year, token.length);
4163
+ },
4164
+ Q: function(date, token, localize2) {
4165
+ const quarter = Math.ceil((date.getMonth() + 1) / 3);
4166
+ switch (token) {
4167
+ case "Q":
4168
+ return String(quarter);
4169
+ case "QQ":
4170
+ return addLeadingZeros(quarter, 2);
4171
+ case "Qo":
4172
+ return localize2.ordinalNumber(quarter, { unit: "quarter" });
4173
+ case "QQQ":
4174
+ return localize2.quarter(quarter, {
4175
+ width: "abbreviated",
4176
+ context: "formatting"
4177
+ });
4178
+ case "QQQQQ":
4179
+ return localize2.quarter(quarter, {
4180
+ width: "narrow",
4181
+ context: "formatting"
4182
+ });
4183
+ case "QQQQ":
4184
+ default:
4185
+ return localize2.quarter(quarter, {
4186
+ width: "wide",
4187
+ context: "formatting"
4188
+ });
4189
+ }
4190
+ },
4191
+ q: function(date, token, localize2) {
4192
+ const quarter = Math.ceil((date.getMonth() + 1) / 3);
4193
+ switch (token) {
4194
+ case "q":
4195
+ return String(quarter);
4196
+ case "qq":
4197
+ return addLeadingZeros(quarter, 2);
4198
+ case "qo":
4199
+ return localize2.ordinalNumber(quarter, { unit: "quarter" });
4200
+ case "qqq":
4201
+ return localize2.quarter(quarter, {
4202
+ width: "abbreviated",
4203
+ context: "standalone"
4204
+ });
4205
+ case "qqqqq":
4206
+ return localize2.quarter(quarter, {
4207
+ width: "narrow",
4208
+ context: "standalone"
4209
+ });
4210
+ case "qqqq":
4211
+ default:
4212
+ return localize2.quarter(quarter, {
4213
+ width: "wide",
4214
+ context: "standalone"
4215
+ });
4216
+ }
4217
+ },
4218
+ M: function(date, token, localize2) {
4219
+ const month = date.getMonth();
4220
+ switch (token) {
4221
+ case "M":
4222
+ case "MM":
4223
+ return lightFormatters.M(date, token);
4224
+ case "Mo":
4225
+ return localize2.ordinalNumber(month + 1, { unit: "month" });
4226
+ case "MMM":
4227
+ return localize2.month(month, {
4228
+ width: "abbreviated",
4229
+ context: "formatting"
4230
+ });
4231
+ case "MMMMM":
4232
+ return localize2.month(month, {
4233
+ width: "narrow",
4234
+ context: "formatting"
4235
+ });
4236
+ case "MMMM":
4237
+ default:
4238
+ return localize2.month(month, { width: "wide", context: "formatting" });
4239
+ }
4240
+ },
4241
+ L: function(date, token, localize2) {
4242
+ const month = date.getMonth();
4243
+ switch (token) {
4244
+ case "L":
4245
+ return String(month + 1);
4246
+ case "LL":
4247
+ return addLeadingZeros(month + 1, 2);
4248
+ case "Lo":
4249
+ return localize2.ordinalNumber(month + 1, { unit: "month" });
4250
+ case "LLL":
4251
+ return localize2.month(month, {
4252
+ width: "abbreviated",
4253
+ context: "standalone"
4254
+ });
4255
+ case "LLLLL":
4256
+ return localize2.month(month, {
4257
+ width: "narrow",
4258
+ context: "standalone"
4259
+ });
4260
+ case "LLLL":
4261
+ default:
4262
+ return localize2.month(month, { width: "wide", context: "standalone" });
4263
+ }
4264
+ },
4265
+ w: function(date, token, localize2, options) {
4266
+ const week = getWeek(date, options);
4267
+ if (token === "wo") {
4268
+ return localize2.ordinalNumber(week, { unit: "week" });
4269
+ }
4270
+ return addLeadingZeros(week, token.length);
4271
+ },
4272
+ I: function(date, token, localize2) {
4273
+ const isoWeek = getISOWeek(date);
4274
+ if (token === "Io") {
4275
+ return localize2.ordinalNumber(isoWeek, { unit: "week" });
4276
+ }
4277
+ return addLeadingZeros(isoWeek, token.length);
4278
+ },
4279
+ d: function(date, token, localize2) {
4280
+ if (token === "do") {
4281
+ return localize2.ordinalNumber(date.getDate(), { unit: "date" });
4282
+ }
4283
+ return lightFormatters.d(date, token);
4284
+ },
4285
+ D: function(date, token, localize2) {
4286
+ const dayOfYear = getDayOfYear(date);
4287
+ if (token === "Do") {
4288
+ return localize2.ordinalNumber(dayOfYear, { unit: "dayOfYear" });
4289
+ }
4290
+ return addLeadingZeros(dayOfYear, token.length);
4291
+ },
4292
+ E: function(date, token, localize2) {
4293
+ const dayOfWeek = date.getDay();
4294
+ switch (token) {
4295
+ case "E":
4296
+ case "EE":
4297
+ case "EEE":
4298
+ return localize2.day(dayOfWeek, {
4299
+ width: "abbreviated",
4300
+ context: "formatting"
4301
+ });
4302
+ case "EEEEE":
4303
+ return localize2.day(dayOfWeek, {
4304
+ width: "narrow",
4305
+ context: "formatting"
4306
+ });
4307
+ case "EEEEEE":
4308
+ return localize2.day(dayOfWeek, {
4309
+ width: "short",
4310
+ context: "formatting"
4311
+ });
4312
+ case "EEEE":
4313
+ default:
4314
+ return localize2.day(dayOfWeek, {
4315
+ width: "wide",
4316
+ context: "formatting"
4317
+ });
4318
+ }
4319
+ },
4320
+ e: function(date, token, localize2, options) {
4321
+ const dayOfWeek = date.getDay();
4322
+ const localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7;
4323
+ switch (token) {
4324
+ case "e":
4325
+ return String(localDayOfWeek);
4326
+ case "ee":
4327
+ return addLeadingZeros(localDayOfWeek, 2);
4328
+ case "eo":
4329
+ return localize2.ordinalNumber(localDayOfWeek, { unit: "day" });
4330
+ case "eee":
4331
+ return localize2.day(dayOfWeek, {
4332
+ width: "abbreviated",
4333
+ context: "formatting"
4334
+ });
4335
+ case "eeeee":
4336
+ return localize2.day(dayOfWeek, {
4337
+ width: "narrow",
4338
+ context: "formatting"
4339
+ });
4340
+ case "eeeeee":
4341
+ return localize2.day(dayOfWeek, {
4342
+ width: "short",
4343
+ context: "formatting"
4344
+ });
4345
+ case "eeee":
4346
+ default:
4347
+ return localize2.day(dayOfWeek, {
4348
+ width: "wide",
4349
+ context: "formatting"
4350
+ });
4351
+ }
4352
+ },
4353
+ c: function(date, token, localize2, options) {
4354
+ const dayOfWeek = date.getDay();
4355
+ const localDayOfWeek = (dayOfWeek - options.weekStartsOn + 8) % 7 || 7;
4356
+ switch (token) {
4357
+ case "c":
4358
+ return String(localDayOfWeek);
4359
+ case "cc":
4360
+ return addLeadingZeros(localDayOfWeek, token.length);
4361
+ case "co":
4362
+ return localize2.ordinalNumber(localDayOfWeek, { unit: "day" });
4363
+ case "ccc":
4364
+ return localize2.day(dayOfWeek, {
4365
+ width: "abbreviated",
4366
+ context: "standalone"
4367
+ });
4368
+ case "ccccc":
4369
+ return localize2.day(dayOfWeek, {
4370
+ width: "narrow",
4371
+ context: "standalone"
4372
+ });
4373
+ case "cccccc":
4374
+ return localize2.day(dayOfWeek, {
4375
+ width: "short",
4376
+ context: "standalone"
4377
+ });
4378
+ case "cccc":
4379
+ default:
4380
+ return localize2.day(dayOfWeek, {
4381
+ width: "wide",
4382
+ context: "standalone"
4383
+ });
4384
+ }
4385
+ },
4386
+ i: function(date, token, localize2) {
4387
+ const dayOfWeek = date.getDay();
4388
+ const isoDayOfWeek = dayOfWeek === 0 ? 7 : dayOfWeek;
4389
+ switch (token) {
4390
+ case "i":
4391
+ return String(isoDayOfWeek);
4392
+ case "ii":
4393
+ return addLeadingZeros(isoDayOfWeek, token.length);
4394
+ case "io":
4395
+ return localize2.ordinalNumber(isoDayOfWeek, { unit: "day" });
4396
+ case "iii":
4397
+ return localize2.day(dayOfWeek, {
4398
+ width: "abbreviated",
4399
+ context: "formatting"
4400
+ });
4401
+ case "iiiii":
4402
+ return localize2.day(dayOfWeek, {
4403
+ width: "narrow",
4404
+ context: "formatting"
4405
+ });
4406
+ case "iiiiii":
4407
+ return localize2.day(dayOfWeek, {
4408
+ width: "short",
4409
+ context: "formatting"
4410
+ });
4411
+ case "iiii":
4412
+ default:
4413
+ return localize2.day(dayOfWeek, {
4414
+ width: "wide",
4415
+ context: "formatting"
4416
+ });
4417
+ }
4418
+ },
4419
+ a: function(date, token, localize2) {
4420
+ const hours = date.getHours();
4421
+ const dayPeriodEnumValue = hours / 12 >= 1 ? "pm" : "am";
4422
+ switch (token) {
4423
+ case "a":
4424
+ case "aa":
4425
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4426
+ width: "abbreviated",
4427
+ context: "formatting"
4428
+ });
4429
+ case "aaa":
4430
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4431
+ width: "abbreviated",
4432
+ context: "formatting"
4433
+ }).toLowerCase();
4434
+ case "aaaaa":
4435
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4436
+ width: "narrow",
4437
+ context: "formatting"
4438
+ });
4439
+ case "aaaa":
4440
+ default:
4441
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4442
+ width: "wide",
4443
+ context: "formatting"
4444
+ });
4445
+ }
4446
+ },
4447
+ b: function(date, token, localize2) {
4448
+ const hours = date.getHours();
4449
+ let dayPeriodEnumValue;
4450
+ if (hours === 12) {
4451
+ dayPeriodEnumValue = dayPeriodEnum.noon;
4452
+ } else if (hours === 0) {
4453
+ dayPeriodEnumValue = dayPeriodEnum.midnight;
4454
+ } else {
4455
+ dayPeriodEnumValue = hours / 12 >= 1 ? "pm" : "am";
4456
+ }
4457
+ switch (token) {
4458
+ case "b":
4459
+ case "bb":
4460
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4461
+ width: "abbreviated",
4462
+ context: "formatting"
4463
+ });
4464
+ case "bbb":
4465
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4466
+ width: "abbreviated",
4467
+ context: "formatting"
4468
+ }).toLowerCase();
4469
+ case "bbbbb":
4470
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4471
+ width: "narrow",
4472
+ context: "formatting"
4473
+ });
4474
+ case "bbbb":
4475
+ default:
4476
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4477
+ width: "wide",
4478
+ context: "formatting"
4479
+ });
4480
+ }
4481
+ },
4482
+ B: function(date, token, localize2) {
4483
+ const hours = date.getHours();
4484
+ let dayPeriodEnumValue;
4485
+ if (hours >= 17) {
4486
+ dayPeriodEnumValue = dayPeriodEnum.evening;
4487
+ } else if (hours >= 12) {
4488
+ dayPeriodEnumValue = dayPeriodEnum.afternoon;
4489
+ } else if (hours >= 4) {
4490
+ dayPeriodEnumValue = dayPeriodEnum.morning;
4491
+ } else {
4492
+ dayPeriodEnumValue = dayPeriodEnum.night;
4493
+ }
4494
+ switch (token) {
4495
+ case "B":
4496
+ case "BB":
4497
+ case "BBB":
4498
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4499
+ width: "abbreviated",
4500
+ context: "formatting"
4501
+ });
4502
+ case "BBBBB":
4503
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4504
+ width: "narrow",
4505
+ context: "formatting"
4506
+ });
4507
+ case "BBBB":
4508
+ default:
4509
+ return localize2.dayPeriod(dayPeriodEnumValue, {
4510
+ width: "wide",
4511
+ context: "formatting"
4512
+ });
4513
+ }
4514
+ },
4515
+ h: function(date, token, localize2) {
4516
+ if (token === "ho") {
4517
+ let hours = date.getHours() % 12;
4518
+ if (hours === 0)
4519
+ hours = 12;
4520
+ return localize2.ordinalNumber(hours, { unit: "hour" });
4521
+ }
4522
+ return lightFormatters.h(date, token);
4523
+ },
4524
+ H: function(date, token, localize2) {
4525
+ if (token === "Ho") {
4526
+ return localize2.ordinalNumber(date.getHours(), { unit: "hour" });
4527
+ }
4528
+ return lightFormatters.H(date, token);
4529
+ },
4530
+ K: function(date, token, localize2) {
4531
+ const hours = date.getHours() % 12;
4532
+ if (token === "Ko") {
4533
+ return localize2.ordinalNumber(hours, { unit: "hour" });
4534
+ }
4535
+ return addLeadingZeros(hours, token.length);
4536
+ },
4537
+ k: function(date, token, localize2) {
4538
+ let hours = date.getHours();
4539
+ if (hours === 0)
4540
+ hours = 24;
4541
+ if (token === "ko") {
4542
+ return localize2.ordinalNumber(hours, { unit: "hour" });
4543
+ }
4544
+ return addLeadingZeros(hours, token.length);
4545
+ },
4546
+ m: function(date, token, localize2) {
4547
+ if (token === "mo") {
4548
+ return localize2.ordinalNumber(date.getMinutes(), { unit: "minute" });
4549
+ }
4550
+ return lightFormatters.m(date, token);
4551
+ },
4552
+ s: function(date, token, localize2) {
4553
+ if (token === "so") {
4554
+ return localize2.ordinalNumber(date.getSeconds(), { unit: "second" });
4555
+ }
4556
+ return lightFormatters.s(date, token);
4557
+ },
4558
+ S: function(date, token) {
4559
+ return lightFormatters.S(date, token);
4560
+ },
4561
+ X: function(date, token, _localize) {
4562
+ const timezoneOffset = date.getTimezoneOffset();
4563
+ if (timezoneOffset === 0) {
4564
+ return "Z";
4565
+ }
4566
+ switch (token) {
4567
+ case "X":
4568
+ return formatTimezoneWithOptionalMinutes(timezoneOffset);
4569
+ case "XXXX":
4570
+ case "XX":
4571
+ return formatTimezone(timezoneOffset);
4572
+ case "XXXXX":
4573
+ case "XXX":
4574
+ default:
4575
+ return formatTimezone(timezoneOffset, ":");
4576
+ }
4577
+ },
4578
+ x: function(date, token, _localize) {
4579
+ const timezoneOffset = date.getTimezoneOffset();
4580
+ switch (token) {
4581
+ case "x":
4582
+ return formatTimezoneWithOptionalMinutes(timezoneOffset);
4583
+ case "xxxx":
4584
+ case "xx":
4585
+ return formatTimezone(timezoneOffset);
4586
+ case "xxxxx":
4587
+ case "xxx":
4588
+ default:
4589
+ return formatTimezone(timezoneOffset, ":");
4590
+ }
4591
+ },
4592
+ O: function(date, token, _localize) {
4593
+ const timezoneOffset = date.getTimezoneOffset();
4594
+ switch (token) {
4595
+ case "O":
4596
+ case "OO":
4597
+ case "OOO":
4598
+ return "GMT" + formatTimezoneShort(timezoneOffset, ":");
4599
+ case "OOOO":
4600
+ default:
4601
+ return "GMT" + formatTimezone(timezoneOffset, ":");
4602
+ }
4603
+ },
4604
+ z: function(date, token, _localize) {
4605
+ const timezoneOffset = date.getTimezoneOffset();
4606
+ switch (token) {
4607
+ case "z":
4608
+ case "zz":
4609
+ case "zzz":
4610
+ return "GMT" + formatTimezoneShort(timezoneOffset, ":");
4611
+ case "zzzz":
4612
+ default:
4613
+ return "GMT" + formatTimezone(timezoneOffset, ":");
4614
+ }
4615
+ },
4616
+ t: function(date, token, _localize) {
4617
+ const timestamp = Math.trunc(+date / 1000);
4618
+ return addLeadingZeros(timestamp, token.length);
4619
+ },
4620
+ T: function(date, token, _localize) {
4621
+ return addLeadingZeros(+date, token.length);
4622
+ }
4623
+ };
4624
+ function formatTimezoneShort(offset, delimiter = "") {
4625
+ const sign = offset > 0 ? "-" : "+";
4626
+ const absOffset = Math.abs(offset);
4627
+ const hours = Math.trunc(absOffset / 60);
4628
+ const minutes = absOffset % 60;
4629
+ if (minutes === 0) {
4630
+ return sign + String(hours);
4631
+ }
4632
+ return sign + String(hours) + delimiter + addLeadingZeros(minutes, 2);
4633
+ }
4634
+ function formatTimezoneWithOptionalMinutes(offset, delimiter) {
4635
+ if (offset % 60 === 0) {
4636
+ const sign = offset > 0 ? "-" : "+";
4637
+ return sign + addLeadingZeros(Math.abs(offset) / 60, 2);
4638
+ }
4639
+ return formatTimezone(offset, delimiter);
4640
+ }
4641
+ function formatTimezone(offset, delimiter = "") {
4642
+ const sign = offset > 0 ? "-" : "+";
4643
+ const absOffset = Math.abs(offset);
4644
+ const hours = addLeadingZeros(Math.trunc(absOffset / 60), 2);
4645
+ const minutes = addLeadingZeros(absOffset % 60, 2);
4646
+ return sign + hours + delimiter + minutes;
4647
+ }
4648
+
4649
+ // node_modules/date-fns/_lib/format/longFormatters.js
4650
+ var dateLongFormatter = (pattern, formatLong2) => {
4651
+ switch (pattern) {
4652
+ case "P":
4653
+ return formatLong2.date({ width: "short" });
4654
+ case "PP":
4655
+ return formatLong2.date({ width: "medium" });
4656
+ case "PPP":
4657
+ return formatLong2.date({ width: "long" });
4658
+ case "PPPP":
4659
+ default:
4660
+ return formatLong2.date({ width: "full" });
4661
+ }
4662
+ };
4663
+ var timeLongFormatter = (pattern, formatLong2) => {
4664
+ switch (pattern) {
4665
+ case "p":
4666
+ return formatLong2.time({ width: "short" });
4667
+ case "pp":
4668
+ return formatLong2.time({ width: "medium" });
4669
+ case "ppp":
4670
+ return formatLong2.time({ width: "long" });
4671
+ case "pppp":
4672
+ default:
4673
+ return formatLong2.time({ width: "full" });
4674
+ }
4675
+ };
4676
+ var dateTimeLongFormatter = (pattern, formatLong2) => {
4677
+ const matchResult = pattern.match(/(P+)(p+)?/) || [];
4678
+ const datePattern = matchResult[1];
4679
+ const timePattern = matchResult[2];
4680
+ if (!timePattern) {
4681
+ return dateLongFormatter(pattern, formatLong2);
4682
+ }
4683
+ let dateTimeFormat;
4684
+ switch (datePattern) {
4685
+ case "P":
4686
+ dateTimeFormat = formatLong2.dateTime({ width: "short" });
4687
+ break;
4688
+ case "PP":
4689
+ dateTimeFormat = formatLong2.dateTime({ width: "medium" });
4690
+ break;
4691
+ case "PPP":
4692
+ dateTimeFormat = formatLong2.dateTime({ width: "long" });
4693
+ break;
4694
+ case "PPPP":
4695
+ default:
4696
+ dateTimeFormat = formatLong2.dateTime({ width: "full" });
4697
+ break;
4698
+ }
4699
+ return dateTimeFormat.replace("{{date}}", dateLongFormatter(datePattern, formatLong2)).replace("{{time}}", timeLongFormatter(timePattern, formatLong2));
4700
+ };
4701
+ var longFormatters = {
4702
+ p: timeLongFormatter,
4703
+ P: dateTimeLongFormatter
4704
+ };
4705
+
4706
+ // node_modules/date-fns/_lib/protectedTokens.js
4707
+ var dayOfYearTokenRE = /^D+$/;
4708
+ var weekYearTokenRE = /^Y+$/;
4709
+ var throwTokens = ["D", "DD", "YY", "YYYY"];
4710
+ function isProtectedDayOfYearToken(token) {
4711
+ return dayOfYearTokenRE.test(token);
4712
+ }
4713
+ function isProtectedWeekYearToken(token) {
4714
+ return weekYearTokenRE.test(token);
4715
+ }
4716
+ function warnOrThrowProtectedError(token, format, input) {
4717
+ const _message = message(token, format, input);
4718
+ console.warn(_message);
4719
+ if (throwTokens.includes(token))
4720
+ throw new RangeError(_message);
4721
+ }
4722
+ function message(token, format, input) {
4723
+ const subject = token[0] === "Y" ? "years" : "days of the month";
4724
+ return `Use \`${token.toLowerCase()}\` instead of \`${token}\` (in \`${format}\`) for formatting ${subject} to the input \`${input}\`; see: https://github.com/date-fns/date-fns/blob/master/docs/unicodeTokens.md`;
4725
+ }
4726
+
4727
+ // node_modules/date-fns/format.js
4728
+ var formattingTokensRegExp = /[yYQqMLwIdDecihHKkms]o|(\w)\1*|''|'(''|[^'])+('|$)|./g;
4729
+ var longFormattingTokensRegExp = /P+p+|P+|p+|''|'(''|[^'])+('|$)|./g;
4730
+ var escapedStringRegExp = /^'([^]*?)'?$/;
4731
+ var doubleQuoteRegExp = /''/g;
4732
+ var unescapedLatinCharacterRegExp = /[a-zA-Z]/;
4733
+ function format(date, formatStr, options) {
4734
+ const defaultOptions2 = getDefaultOptions();
4735
+ const locale = options?.locale ?? defaultOptions2.locale ?? enUS;
4736
+ const firstWeekContainsDate = options?.firstWeekContainsDate ?? options?.locale?.options?.firstWeekContainsDate ?? defaultOptions2.firstWeekContainsDate ?? defaultOptions2.locale?.options?.firstWeekContainsDate ?? 1;
4737
+ const weekStartsOn = options?.weekStartsOn ?? options?.locale?.options?.weekStartsOn ?? defaultOptions2.weekStartsOn ?? defaultOptions2.locale?.options?.weekStartsOn ?? 0;
4738
+ const originalDate = toDate(date, options?.in);
4739
+ if (!isValid(originalDate)) {
4740
+ throw new RangeError("Invalid time value");
4741
+ }
4742
+ let parts = formatStr.match(longFormattingTokensRegExp).map((substring) => {
4743
+ const firstCharacter = substring[0];
4744
+ if (firstCharacter === "p" || firstCharacter === "P") {
4745
+ const longFormatter = longFormatters[firstCharacter];
4746
+ return longFormatter(substring, locale.formatLong);
4747
+ }
4748
+ return substring;
4749
+ }).join("").match(formattingTokensRegExp).map((substring) => {
4750
+ if (substring === "''") {
4751
+ return { isToken: false, value: "'" };
4752
+ }
4753
+ const firstCharacter = substring[0];
4754
+ if (firstCharacter === "'") {
4755
+ return { isToken: false, value: cleanEscapedString(substring) };
4756
+ }
4757
+ if (formatters[firstCharacter]) {
4758
+ return { isToken: true, value: substring };
4759
+ }
4760
+ if (firstCharacter.match(unescapedLatinCharacterRegExp)) {
4761
+ throw new RangeError("Format string contains an unescaped latin alphabet character `" + firstCharacter + "`");
4762
+ }
4763
+ return { isToken: false, value: substring };
4764
+ });
4765
+ if (locale.localize.preprocessor) {
4766
+ parts = locale.localize.preprocessor(originalDate, parts);
4767
+ }
4768
+ const formatterOptions = {
4769
+ firstWeekContainsDate,
4770
+ weekStartsOn,
4771
+ locale
4772
+ };
4773
+ return parts.map((part) => {
4774
+ if (!part.isToken)
4775
+ return part.value;
4776
+ const token = part.value;
4777
+ if (!options?.useAdditionalWeekYearTokens && isProtectedWeekYearToken(token) || !options?.useAdditionalDayOfYearTokens && isProtectedDayOfYearToken(token)) {
4778
+ warnOrThrowProtectedError(token, formatStr, String(date));
4779
+ }
4780
+ const formatter = formatters[token[0]];
4781
+ return formatter(originalDate, token, locale.localize, formatterOptions);
4782
+ }).join("");
4783
+ }
4784
+ function cleanEscapedString(input) {
4785
+ const matched = input.match(escapedStringRegExp);
4786
+ if (!matched) {
4787
+ return input;
4788
+ }
4789
+ return matched[1].replace(doubleQuoteRegExp, "'");
4790
+ }
4791
+
4792
+ // src/utils/date.ts
4793
+ var formatDateLog = (isoDateString) => {
4794
+ const date = new Date(isoDateString);
4795
+ const formatted = format(date, "EEE MMM d HH:mm:ss yyyy XXX");
4796
+ return formatted.replace(/([+-]\d{2}):(\d{2})$/, "$1$2");
4797
+ };
4798
+
4799
+ // src/services/logService.ts
4800
+ var log = async (options) => {
4801
+ try {
4802
+ const currentBranch = await getCurrentBranchName();
4803
+ let currentCommitHash = await getCurrentHead();
4804
+ const limit = options?.limit ? parseInt(options.limit, 10) : undefined;
4805
+ let commitCount = 0;
4806
+ console.log(currentCommitHash);
4807
+ while (currentCommitHash && (!limit || commitCount < limit)) {
4808
+ commitCount++;
4809
+ const commitData = JSON.parse(await fs3.readFile(path3.join(OBJECTS_PATH, currentCommitHash.substring(0, 2), currentCommitHash.substring(2)), "utf-8"));
4810
+ console.log(source_default.yellow(`commit ${currentCommitHash} (` + source_default.cyan.bold("HEAD") + source_default.yellow(` -> `) + source_default.green.bold(currentBranch) + source_default.yellow(", ") + source_default.redBright.bold(`origin/${currentBranch}`) + source_default.yellow(", ") + source_default.redBright.bold("origin/HEAD") + source_default.yellow(")")));
4811
+ console.log(`Author: ${commitData.author.name} <${commitData.author.email}>`);
4812
+ console.log(`Date: ${formatDateLog(commitData.timeStamp)}`);
4813
+ console.log(`
4814
+ ${commitData.message}
4815
+ `);
4816
+ if (!limit || commitCount < limit) {
4817
+ currentCommitHash = commitData.parent;
4818
+ } else {
4819
+ currentCommitHash = null;
4820
+ }
4821
+ }
4822
+ } catch (error) {
4823
+ const message2 = error instanceof Error ? error.message : String(error);
4824
+ console.log(source_default.red("Error logging:"), message2);
4825
+ process.exit(1);
4826
+ }
4827
+ };
4828
+
4829
+ // src/commands/logCommand.ts
4830
+ var logCommand = new Command("log").description("Show commit history for the current repository in reverse chronological order").option("-L, --limit <number>", "Limit the number of commits to display").addHelpText("after", `
4831
+ Examples:
4832
+ $ brch log Show all commits
4833
+ $ brch log -L 5 Show the last 5 commits
4834
+ $ brch log --limit 10 Show the last 10 commits
4835
+
4836
+ Displays each commit with author, date, hash, and message.
4837
+ Commits are shown from newest to oldest.
4838
+ `).action(log);
4839
+
4840
+ // src/services/statusService.ts
4841
+ import fs4 from "fs/promises";
4842
+ import path4 from "path";
4843
+ var getIgnorePatterns = async () => {
4844
+ try {
4845
+ const ignoreContent = await fs4.readFile(IGNORE_PATH, "utf-8");
4846
+ return ignoreContent.split(`
4847
+ `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
4848
+ } catch (error) {
4849
+ return [];
4850
+ }
4851
+ };
4852
+ var shouldIgnore2 = (name, patterns) => {
4853
+ return patterns.some((pattern) => {
4854
+ if (pattern === name || pattern === `${name}/`) {
4855
+ return true;
4856
+ }
4857
+ if (pattern.startsWith("*.")) {
4858
+ const ext = pattern.slice(1);
4859
+ return name.endsWith(ext);
4860
+ }
4861
+ if (pattern.endsWith("/") && name === pattern.slice(0, -1)) {
4862
+ return true;
4863
+ }
4864
+ return false;
4865
+ });
4866
+ };
4867
+ var getTrackedFiles = async (commitHash) => {
4868
+ const trackedFiles = new Map;
4869
+ if (!commitHash)
4870
+ return trackedFiles;
4871
+ try {
4872
+ const commitPath = path4.join(OBJECTS_PATH, commitHash.substring(0, 2), commitHash.substring(2));
4873
+ const commitData = JSON.parse(await fs4.readFile(commitPath, "utf-8"));
4874
+ if (commitData.files && Array.isArray(commitData.files)) {
4875
+ for (const entry of commitData.files) {
4876
+ trackedFiles.set(entry.path, entry.hash);
4877
+ }
4878
+ }
4879
+ } catch (error) {}
4880
+ return trackedFiles;
4881
+ };
4882
+ var readIndex3 = async () => {
4883
+ try {
4884
+ const content = await fs4.readFile(INDEX_PATH, "utf-8");
4885
+ if (!content)
4886
+ return [];
4887
+ const parsed = JSON.parse(content);
4888
+ if (Array.isArray(parsed))
4889
+ return parsed.map((e) => ({ path: e.path, hash: e.hash }));
4890
+ if (parsed && typeof parsed === "object")
4891
+ return Object.entries(parsed).map(([p, h]) => ({ path: p, hash: h }));
4892
+ return [];
4893
+ } catch {
4894
+ return [];
4895
+ }
4896
+ };
4897
+ var normalizeRelativePath3 = (pathValue) => {
4898
+ const normalized = pathValue.split("\\").join("/");
4899
+ if (normalized && !normalized.startsWith("./") && !normalized.startsWith("../") && !normalized.startsWith("/")) {
4900
+ return "./" + normalized;
4901
+ }
4902
+ return normalized;
4903
+ };
4904
+ var walk = async (dir, repoRoot, ignorePatterns) => {
4905
+ let files = [];
4906
+ const entries = await fs4.readdir(dir, { withFileTypes: true });
4907
+ for (const entry of entries) {
4908
+ const res = path4.resolve(dir, entry.name);
4909
+ if (entry.name === VCS_DIR || shouldIgnore2(entry.name, ignorePatterns))
4910
+ continue;
4911
+ if (entry.isDirectory()) {
4912
+ files = files.concat(await walk(res, repoRoot, ignorePatterns));
4913
+ } else {
4914
+ files.push(normalizeRelativePath3(path4.relative(repoRoot, res)));
4915
+ }
4916
+ }
4917
+ return files;
4918
+ };
4919
+ var status = async () => {
4920
+ try {
4921
+ const currentBranch = await getCurrentBranchName();
4922
+ const currentHead = await getCurrentHead();
4923
+ const trackedFiles = await getTrackedFiles(currentHead);
4924
+ const ignorePatterns = await getIgnorePatterns();
4925
+ const indexEntries = await readIndex3();
4926
+ const indexMap = new Map;
4927
+ for (const entry of indexEntries) {
4928
+ indexMap.set(entry.path, entry.hash);
4929
+ }
4930
+ console.log(`On branch ${source_default.cyan(currentBranch || "detached HEAD")}`);
4931
+ const repoRoot = process.cwd();
4932
+ const allFiles = await walk(repoRoot, repoRoot, ignorePatterns);
4933
+ const stagedAdditions = [];
4934
+ const stagedModifications = [];
4935
+ const stagedDeletions = [];
4936
+ const modifiedFiles = [];
4937
+ const deletedFiles = [];
4938
+ const untrackedFiles = [];
4939
+ const allKnownPaths = new Set([
4940
+ ...allFiles,
4941
+ ...indexMap.keys(),
4942
+ ...trackedFiles.keys()
4943
+ ]);
4944
+ const worktreeSet = new Set(allFiles);
4945
+ for (const relPath of allKnownPaths) {
4946
+ const indexHash = indexMap.get(relPath);
4947
+ const headHash = trackedFiles.get(relPath);
4948
+ const isWorktree = worktreeSet.has(relPath);
4949
+ if (indexHash !== headHash) {
4950
+ if (!headHash && indexHash) {
4951
+ stagedAdditions.push(relPath);
4952
+ } else if (headHash && !indexHash) {
4953
+ stagedDeletions.push(relPath);
4954
+ } else if (headHash && indexHash && headHash !== indexHash) {
4955
+ stagedModifications.push(relPath);
4956
+ }
4957
+ }
4958
+ if (isWorktree) {
4959
+ const fileBuffer = await fs4.readFile(path4.join(repoRoot, relPath));
4960
+ const fileHash = hashContent(fileBuffer);
4961
+ const baseHash = indexHash || headHash;
4962
+ if (baseHash) {
4963
+ if (fileHash !== indexHash && indexHash) {
4964
+ modifiedFiles.push(relPath);
4965
+ } else if (fileHash !== headHash && !indexHash) {
4966
+ modifiedFiles.push(relPath);
4967
+ }
4968
+ } else {
4969
+ untrackedFiles.push(relPath);
4970
+ }
4971
+ } else {
4972
+ if (indexHash || headHash) {
4973
+ if (indexHash) {
4974
+ deletedFiles.push(relPath);
4975
+ }
4976
+ }
4977
+ }
4978
+ }
4979
+ if (stagedAdditions.length > 0 || stagedModifications.length > 0 || stagedDeletions.length > 0) {
4980
+ console.log(`
4981
+ ${source_default.green("Changes to be committed:")}`);
4982
+ console.log(` (use "${source_default.cyan("brch reset")}" to unstage)`);
4983
+ for (const file of stagedAdditions)
4984
+ console.log(` ${source_default.green("new file:")} ${file}`);
4985
+ for (const file of stagedModifications)
4986
+ console.log(` ${source_default.green("modified:")} ${file}`);
4987
+ for (const file of stagedDeletions)
4988
+ console.log(` ${source_default.green("deleted:")} ${file}`);
4989
+ }
4990
+ if (modifiedFiles.length > 0 || deletedFiles.length > 0) {
4991
+ console.log(`
4992
+ ${source_default.red("Changes not staged for commit:")}`);
4993
+ console.log(` (use "${source_default.cyan("brch add")}" to stage changes)`);
4994
+ for (const file of modifiedFiles)
4995
+ console.log(` ${source_default.red("modified:")} ${file}`);
4996
+ for (const file of deletedFiles)
4997
+ console.log(` ${source_default.red("deleted:")} ${file}`);
4998
+ }
4999
+ if (untrackedFiles.length > 0) {
5000
+ console.log(`
5001
+ ${source_default.red("Untracked files:")}`);
5002
+ console.log(` (use "${source_default.cyan("brch add")}" to include in what will be committed)`);
5003
+ for (const file of untrackedFiles) {
5004
+ console.log(` ${file}`);
5005
+ }
5006
+ }
5007
+ if (stagedAdditions.length === 0 && stagedModifications.length === 0 && stagedDeletions.length === 0 && modifiedFiles.length === 0 && deletedFiles.length === 0 && untrackedFiles.length === 0) {
5008
+ console.log(source_default.green("nothing to commit, working tree clean"));
5009
+ }
5010
+ } catch (error) {
5011
+ const message2 = error instanceof Error ? error.message : String(error);
5012
+ console.log("Error getting status:", message2);
5013
+ process.exit(1);
5014
+ }
5015
+ };
5016
+
5017
+ // src/commands/statusCommand.ts
5018
+ var statusCommand = new Command("status").description("Show the working tree status").addHelpText("after", `
5019
+ Examples:
5020
+ $ brch status
5021
+
5022
+ Displays:
5023
+ - Changes to be committed (staged files)
5024
+ - Changes not staged for commit (modified tracked files)
5025
+ - Untracked files (new files not yet added)
5026
+
5027
+ Use 'brch add <file>...' to stage files for commit.
5028
+ `).action(async () => {
5029
+ status();
5030
+ });
5031
+
5032
+ // src/services/diffService.ts
5033
+ import fs5 from "fs/promises";
5034
+ import path5 from "path";
5035
+
5036
+ // node_modules/diff/libesm/diff/base.js
5037
+ class Diff {
5038
+ diff(oldStr, newStr, options = {}) {
5039
+ let callback;
5040
+ if (typeof options === "function") {
5041
+ callback = options;
5042
+ options = {};
5043
+ } else if ("callback" in options) {
5044
+ callback = options.callback;
5045
+ }
5046
+ const oldString = this.castInput(oldStr, options);
5047
+ const newString = this.castInput(newStr, options);
5048
+ const oldTokens = this.removeEmpty(this.tokenize(oldString, options));
5049
+ const newTokens = this.removeEmpty(this.tokenize(newString, options));
5050
+ return this.diffWithOptionsObj(oldTokens, newTokens, options, callback);
5051
+ }
5052
+ diffWithOptionsObj(oldTokens, newTokens, options, callback) {
5053
+ var _a;
5054
+ const done = (value) => {
5055
+ value = this.postProcess(value, options);
5056
+ if (callback) {
5057
+ setTimeout(function() {
5058
+ callback(value);
5059
+ }, 0);
5060
+ return;
5061
+ } else {
5062
+ return value;
5063
+ }
5064
+ };
5065
+ const newLen = newTokens.length, oldLen = oldTokens.length;
5066
+ let editLength = 1;
5067
+ let maxEditLength = newLen + oldLen;
5068
+ if (options.maxEditLength != null) {
5069
+ maxEditLength = Math.min(maxEditLength, options.maxEditLength);
5070
+ }
5071
+ const maxExecutionTime = (_a = options.timeout) !== null && _a !== undefined ? _a : Infinity;
5072
+ const abortAfterTimestamp = Date.now() + maxExecutionTime;
5073
+ const bestPath = [{ oldPos: -1, lastComponent: undefined }];
5074
+ let newPos = this.extractCommon(bestPath[0], newTokens, oldTokens, 0, options);
5075
+ if (bestPath[0].oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
5076
+ return done(this.buildValues(bestPath[0].lastComponent, newTokens, oldTokens));
5077
+ }
5078
+ let minDiagonalToConsider = -Infinity, maxDiagonalToConsider = Infinity;
5079
+ const execEditLength = () => {
5080
+ for (let diagonalPath = Math.max(minDiagonalToConsider, -editLength);diagonalPath <= Math.min(maxDiagonalToConsider, editLength); diagonalPath += 2) {
5081
+ let basePath;
5082
+ const removePath = bestPath[diagonalPath - 1], addPath = bestPath[diagonalPath + 1];
5083
+ if (removePath) {
5084
+ bestPath[diagonalPath - 1] = undefined;
5085
+ }
5086
+ let canAdd = false;
5087
+ if (addPath) {
5088
+ const addPathNewPos = addPath.oldPos - diagonalPath;
5089
+ canAdd = addPath && 0 <= addPathNewPos && addPathNewPos < newLen;
5090
+ }
5091
+ const canRemove = removePath && removePath.oldPos + 1 < oldLen;
5092
+ if (!canAdd && !canRemove) {
5093
+ bestPath[diagonalPath] = undefined;
5094
+ continue;
5095
+ }
5096
+ if (!canRemove || canAdd && removePath.oldPos < addPath.oldPos) {
5097
+ basePath = this.addToPath(addPath, true, false, 0, options);
5098
+ } else {
5099
+ basePath = this.addToPath(removePath, false, true, 1, options);
5100
+ }
5101
+ newPos = this.extractCommon(basePath, newTokens, oldTokens, diagonalPath, options);
5102
+ if (basePath.oldPos + 1 >= oldLen && newPos + 1 >= newLen) {
5103
+ return done(this.buildValues(basePath.lastComponent, newTokens, oldTokens)) || true;
5104
+ } else {
5105
+ bestPath[diagonalPath] = basePath;
5106
+ if (basePath.oldPos + 1 >= oldLen) {
5107
+ maxDiagonalToConsider = Math.min(maxDiagonalToConsider, diagonalPath - 1);
5108
+ }
5109
+ if (newPos + 1 >= newLen) {
5110
+ minDiagonalToConsider = Math.max(minDiagonalToConsider, diagonalPath + 1);
5111
+ }
5112
+ }
5113
+ }
5114
+ editLength++;
5115
+ };
5116
+ if (callback) {
5117
+ (function exec() {
5118
+ setTimeout(function() {
5119
+ if (editLength > maxEditLength || Date.now() > abortAfterTimestamp) {
5120
+ return callback(undefined);
5121
+ }
5122
+ if (!execEditLength()) {
5123
+ exec();
5124
+ }
5125
+ }, 0);
5126
+ })();
5127
+ } else {
5128
+ while (editLength <= maxEditLength && Date.now() <= abortAfterTimestamp) {
5129
+ const ret = execEditLength();
5130
+ if (ret) {
5131
+ return ret;
5132
+ }
5133
+ }
5134
+ }
5135
+ }
5136
+ addToPath(path5, added, removed, oldPosInc, options) {
5137
+ const last = path5.lastComponent;
5138
+ if (last && !options.oneChangePerToken && last.added === added && last.removed === removed) {
5139
+ return {
5140
+ oldPos: path5.oldPos + oldPosInc,
5141
+ lastComponent: { count: last.count + 1, added, removed, previousComponent: last.previousComponent }
5142
+ };
5143
+ } else {
5144
+ return {
5145
+ oldPos: path5.oldPos + oldPosInc,
5146
+ lastComponent: { count: 1, added, removed, previousComponent: last }
5147
+ };
5148
+ }
5149
+ }
5150
+ extractCommon(basePath, newTokens, oldTokens, diagonalPath, options) {
5151
+ const newLen = newTokens.length, oldLen = oldTokens.length;
5152
+ let oldPos = basePath.oldPos, newPos = oldPos - diagonalPath, commonCount = 0;
5153
+ while (newPos + 1 < newLen && oldPos + 1 < oldLen && this.equals(oldTokens[oldPos + 1], newTokens[newPos + 1], options)) {
5154
+ newPos++;
5155
+ oldPos++;
5156
+ commonCount++;
5157
+ if (options.oneChangePerToken) {
5158
+ basePath.lastComponent = { count: 1, previousComponent: basePath.lastComponent, added: false, removed: false };
5159
+ }
5160
+ }
5161
+ if (commonCount && !options.oneChangePerToken) {
5162
+ basePath.lastComponent = { count: commonCount, previousComponent: basePath.lastComponent, added: false, removed: false };
5163
+ }
5164
+ basePath.oldPos = oldPos;
5165
+ return newPos;
5166
+ }
5167
+ equals(left, right, options) {
5168
+ if (options.comparator) {
5169
+ return options.comparator(left, right);
5170
+ } else {
5171
+ return left === right || !!options.ignoreCase && left.toLowerCase() === right.toLowerCase();
5172
+ }
5173
+ }
5174
+ removeEmpty(array) {
5175
+ const ret = [];
5176
+ for (let i = 0;i < array.length; i++) {
5177
+ if (array[i]) {
5178
+ ret.push(array[i]);
5179
+ }
5180
+ }
5181
+ return ret;
5182
+ }
5183
+ castInput(value, options) {
5184
+ return value;
5185
+ }
5186
+ tokenize(value, options) {
5187
+ return Array.from(value);
5188
+ }
5189
+ join(chars) {
5190
+ return chars.join("");
5191
+ }
5192
+ postProcess(changeObjects, options) {
5193
+ return changeObjects;
5194
+ }
5195
+ get useLongestToken() {
5196
+ return false;
5197
+ }
5198
+ buildValues(lastComponent, newTokens, oldTokens) {
5199
+ const components = [];
5200
+ let nextComponent;
5201
+ while (lastComponent) {
5202
+ components.push(lastComponent);
5203
+ nextComponent = lastComponent.previousComponent;
5204
+ delete lastComponent.previousComponent;
5205
+ lastComponent = nextComponent;
5206
+ }
5207
+ components.reverse();
5208
+ const componentLen = components.length;
5209
+ let componentPos = 0, newPos = 0, oldPos = 0;
5210
+ for (;componentPos < componentLen; componentPos++) {
5211
+ const component = components[componentPos];
5212
+ if (!component.removed) {
5213
+ if (!component.added && this.useLongestToken) {
5214
+ let value = newTokens.slice(newPos, newPos + component.count);
5215
+ value = value.map(function(value2, i) {
5216
+ const oldValue = oldTokens[oldPos + i];
5217
+ return oldValue.length > value2.length ? oldValue : value2;
5218
+ });
5219
+ component.value = this.join(value);
5220
+ } else {
5221
+ component.value = this.join(newTokens.slice(newPos, newPos + component.count));
5222
+ }
5223
+ newPos += component.count;
5224
+ if (!component.added) {
5225
+ oldPos += component.count;
5226
+ }
5227
+ } else {
5228
+ component.value = this.join(oldTokens.slice(oldPos, oldPos + component.count));
5229
+ oldPos += component.count;
5230
+ }
5231
+ }
5232
+ return components;
5233
+ }
5234
+ }
5235
+
5236
+ // node_modules/diff/libesm/diff/character.js
5237
+ class CharacterDiff extends Diff {
5238
+ }
5239
+ var characterDiff = new CharacterDiff;
5240
+
5241
+ // node_modules/diff/libesm/util/string.js
5242
+ function longestCommonPrefix(str1, str2) {
5243
+ let i;
5244
+ for (i = 0;i < str1.length && i < str2.length; i++) {
5245
+ if (str1[i] != str2[i]) {
5246
+ return str1.slice(0, i);
5247
+ }
5248
+ }
5249
+ return str1.slice(0, i);
5250
+ }
5251
+ function longestCommonSuffix(str1, str2) {
5252
+ let i;
5253
+ if (!str1 || !str2 || str1[str1.length - 1] != str2[str2.length - 1]) {
5254
+ return "";
5255
+ }
5256
+ for (i = 0;i < str1.length && i < str2.length; i++) {
5257
+ if (str1[str1.length - (i + 1)] != str2[str2.length - (i + 1)]) {
5258
+ return str1.slice(-i);
5259
+ }
5260
+ }
5261
+ return str1.slice(-i);
5262
+ }
5263
+ function replacePrefix(string, oldPrefix, newPrefix) {
5264
+ if (string.slice(0, oldPrefix.length) != oldPrefix) {
5265
+ throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);
5266
+ }
5267
+ return newPrefix + string.slice(oldPrefix.length);
5268
+ }
5269
+ function replaceSuffix(string, oldSuffix, newSuffix) {
5270
+ if (!oldSuffix) {
5271
+ return string + newSuffix;
5272
+ }
5273
+ if (string.slice(-oldSuffix.length) != oldSuffix) {
5274
+ throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);
5275
+ }
5276
+ return string.slice(0, -oldSuffix.length) + newSuffix;
5277
+ }
5278
+ function removePrefix(string, oldPrefix) {
5279
+ return replacePrefix(string, oldPrefix, "");
5280
+ }
5281
+ function removeSuffix(string, oldSuffix) {
5282
+ return replaceSuffix(string, oldSuffix, "");
5283
+ }
5284
+ function maximumOverlap(string1, string2) {
5285
+ return string2.slice(0, overlapCount(string1, string2));
5286
+ }
5287
+ function overlapCount(a, b) {
5288
+ let startA = 0;
5289
+ if (a.length > b.length) {
5290
+ startA = a.length - b.length;
5291
+ }
5292
+ let endB = b.length;
5293
+ if (a.length < b.length) {
5294
+ endB = a.length;
5295
+ }
5296
+ const map = Array(endB);
5297
+ let k = 0;
5298
+ map[0] = 0;
5299
+ for (let j = 1;j < endB; j++) {
5300
+ if (b[j] == b[k]) {
5301
+ map[j] = map[k];
5302
+ } else {
5303
+ map[j] = k;
5304
+ }
5305
+ while (k > 0 && b[j] != b[k]) {
5306
+ k = map[k];
5307
+ }
5308
+ if (b[j] == b[k]) {
5309
+ k++;
5310
+ }
5311
+ }
5312
+ k = 0;
5313
+ for (let i = startA;i < a.length; i++) {
5314
+ while (k > 0 && a[i] != b[k]) {
5315
+ k = map[k];
5316
+ }
5317
+ if (a[i] == b[k]) {
5318
+ k++;
5319
+ }
5320
+ }
5321
+ return k;
5322
+ }
5323
+ function trailingWs(string) {
5324
+ let i;
5325
+ for (i = string.length - 1;i >= 0; i--) {
5326
+ if (!string[i].match(/\s/)) {
5327
+ break;
5328
+ }
5329
+ }
5330
+ return string.substring(i + 1);
5331
+ }
5332
+ function leadingWs(string) {
5333
+ const match2 = string.match(/^\s*/);
5334
+ return match2 ? match2[0] : "";
5335
+ }
5336
+
5337
+ // node_modules/diff/libesm/diff/word.js
5338
+ var extendedWordChars = "a-zA-Z0-9_\\u{C0}-\\u{FF}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}";
5339
+ var tokenizeIncludingWhitespace = new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`, "ug");
5340
+
5341
+ class WordDiff extends Diff {
5342
+ equals(left, right, options) {
5343
+ if (options.ignoreCase) {
5344
+ left = left.toLowerCase();
5345
+ right = right.toLowerCase();
5346
+ }
5347
+ return left.trim() === right.trim();
5348
+ }
5349
+ tokenize(value, options = {}) {
5350
+ let parts;
5351
+ if (options.intlSegmenter) {
5352
+ const segmenter = options.intlSegmenter;
5353
+ if (segmenter.resolvedOptions().granularity != "word") {
5354
+ throw new Error('The segmenter passed must have a granularity of "word"');
5355
+ }
5356
+ parts = Array.from(segmenter.segment(value), (segment) => segment.segment);
5357
+ } else {
5358
+ parts = value.match(tokenizeIncludingWhitespace) || [];
5359
+ }
5360
+ const tokens = [];
5361
+ let prevPart = null;
5362
+ parts.forEach((part) => {
5363
+ if (/\s/.test(part)) {
5364
+ if (prevPart == null) {
5365
+ tokens.push(part);
5366
+ } else {
5367
+ tokens.push(tokens.pop() + part);
5368
+ }
5369
+ } else if (prevPart != null && /\s/.test(prevPart)) {
5370
+ if (tokens[tokens.length - 1] == prevPart) {
5371
+ tokens.push(tokens.pop() + part);
5372
+ } else {
5373
+ tokens.push(prevPart + part);
5374
+ }
5375
+ } else {
5376
+ tokens.push(part);
5377
+ }
5378
+ prevPart = part;
5379
+ });
5380
+ return tokens;
5381
+ }
5382
+ join(tokens) {
5383
+ return tokens.map((token, i) => {
5384
+ if (i == 0) {
5385
+ return token;
5386
+ } else {
5387
+ return token.replace(/^\s+/, "");
5388
+ }
5389
+ }).join("");
5390
+ }
5391
+ postProcess(changes, options) {
5392
+ if (!changes || options.oneChangePerToken) {
5393
+ return changes;
5394
+ }
5395
+ let lastKeep = null;
5396
+ let insertion = null;
5397
+ let deletion = null;
5398
+ changes.forEach((change) => {
5399
+ if (change.added) {
5400
+ insertion = change;
5401
+ } else if (change.removed) {
5402
+ deletion = change;
5403
+ } else {
5404
+ if (insertion || deletion) {
5405
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
5406
+ }
5407
+ lastKeep = change;
5408
+ insertion = null;
5409
+ deletion = null;
5410
+ }
5411
+ });
5412
+ if (insertion || deletion) {
5413
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
5414
+ }
5415
+ return changes;
5416
+ }
5417
+ }
5418
+ var wordDiff = new WordDiff;
5419
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
5420
+ if (deletion && insertion) {
5421
+ const oldWsPrefix = leadingWs(deletion.value);
5422
+ const oldWsSuffix = trailingWs(deletion.value);
5423
+ const newWsPrefix = leadingWs(insertion.value);
5424
+ const newWsSuffix = trailingWs(insertion.value);
5425
+ if (startKeep) {
5426
+ const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
5427
+ startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
5428
+ deletion.value = removePrefix(deletion.value, commonWsPrefix);
5429
+ insertion.value = removePrefix(insertion.value, commonWsPrefix);
5430
+ }
5431
+ if (endKeep) {
5432
+ const commonWsSuffix = longestCommonSuffix(oldWsSuffix, newWsSuffix);
5433
+ endKeep.value = replacePrefix(endKeep.value, newWsSuffix, commonWsSuffix);
5434
+ deletion.value = removeSuffix(deletion.value, commonWsSuffix);
5435
+ insertion.value = removeSuffix(insertion.value, commonWsSuffix);
5436
+ }
5437
+ } else if (insertion) {
5438
+ if (startKeep) {
5439
+ const ws = leadingWs(insertion.value);
5440
+ insertion.value = insertion.value.substring(ws.length);
5441
+ }
5442
+ if (endKeep) {
5443
+ const ws = leadingWs(endKeep.value);
5444
+ endKeep.value = endKeep.value.substring(ws.length);
5445
+ }
5446
+ } else if (startKeep && endKeep) {
5447
+ const newWsFull = leadingWs(endKeep.value), delWsStart = leadingWs(deletion.value), delWsEnd = trailingWs(deletion.value);
5448
+ const newWsStart = longestCommonPrefix(newWsFull, delWsStart);
5449
+ deletion.value = removePrefix(deletion.value, newWsStart);
5450
+ const newWsEnd = longestCommonSuffix(removePrefix(newWsFull, newWsStart), delWsEnd);
5451
+ deletion.value = removeSuffix(deletion.value, newWsEnd);
5452
+ endKeep.value = replacePrefix(endKeep.value, newWsFull, newWsEnd);
5453
+ startKeep.value = replaceSuffix(startKeep.value, newWsFull, newWsFull.slice(0, newWsFull.length - newWsEnd.length));
5454
+ } else if (endKeep) {
5455
+ const endKeepWsPrefix = leadingWs(endKeep.value);
5456
+ const deletionWsSuffix = trailingWs(deletion.value);
5457
+ const overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
5458
+ deletion.value = removeSuffix(deletion.value, overlap);
5459
+ } else if (startKeep) {
5460
+ const startKeepWsSuffix = trailingWs(startKeep.value);
5461
+ const deletionWsPrefix = leadingWs(deletion.value);
5462
+ const overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
5463
+ deletion.value = removePrefix(deletion.value, overlap);
5464
+ }
5465
+ }
5466
+
5467
+ class WordsWithSpaceDiff extends Diff {
5468
+ tokenize(value) {
5469
+ const regex = new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`, "ug");
5470
+ return value.match(regex) || [];
5471
+ }
5472
+ }
5473
+ var wordsWithSpaceDiff = new WordsWithSpaceDiff;
5474
+
5475
+ // node_modules/diff/libesm/diff/line.js
5476
+ class LineDiff extends Diff {
5477
+ constructor() {
5478
+ super(...arguments);
5479
+ this.tokenize = tokenize;
5480
+ }
5481
+ equals(left, right, options) {
5482
+ if (options.ignoreWhitespace) {
5483
+ if (!options.newlineIsToken || !left.includes(`
5484
+ `)) {
5485
+ left = left.trim();
5486
+ }
5487
+ if (!options.newlineIsToken || !right.includes(`
5488
+ `)) {
5489
+ right = right.trim();
5490
+ }
5491
+ } else if (options.ignoreNewlineAtEof && !options.newlineIsToken) {
5492
+ if (left.endsWith(`
5493
+ `)) {
5494
+ left = left.slice(0, -1);
5495
+ }
5496
+ if (right.endsWith(`
5497
+ `)) {
5498
+ right = right.slice(0, -1);
5499
+ }
5500
+ }
5501
+ return super.equals(left, right, options);
5502
+ }
5503
+ }
5504
+ var lineDiff = new LineDiff;
5505
+ function diffLines(oldStr, newStr, options) {
5506
+ return lineDiff.diff(oldStr, newStr, options);
5507
+ }
5508
+ function tokenize(value, options) {
5509
+ if (options.stripTrailingCr) {
5510
+ value = value.replace(/\r\n/g, `
5511
+ `);
5512
+ }
5513
+ const retLines = [], linesAndNewlines = value.split(/(\n|\r\n)/);
5514
+ if (!linesAndNewlines[linesAndNewlines.length - 1]) {
5515
+ linesAndNewlines.pop();
5516
+ }
5517
+ for (let i = 0;i < linesAndNewlines.length; i++) {
5518
+ const line = linesAndNewlines[i];
5519
+ if (i % 2 && !options.newlineIsToken) {
5520
+ retLines[retLines.length - 1] += line;
5521
+ } else {
5522
+ retLines.push(line);
5523
+ }
5524
+ }
5525
+ return retLines;
5526
+ }
5527
+
5528
+ // node_modules/diff/libesm/diff/sentence.js
5529
+ function isSentenceEndPunct(char) {
5530
+ return char == "." || char == "!" || char == "?";
5531
+ }
5532
+
5533
+ class SentenceDiff extends Diff {
5534
+ tokenize(value) {
5535
+ var _a;
5536
+ const result = [];
5537
+ let tokenStartI = 0;
5538
+ for (let i = 0;i < value.length; i++) {
5539
+ if (i == value.length - 1) {
5540
+ result.push(value.slice(tokenStartI));
5541
+ break;
5542
+ }
5543
+ if (isSentenceEndPunct(value[i]) && value[i + 1].match(/\s/)) {
5544
+ result.push(value.slice(tokenStartI, i + 1));
5545
+ i = tokenStartI = i + 1;
5546
+ while ((_a = value[i + 1]) === null || _a === undefined ? undefined : _a.match(/\s/)) {
5547
+ i++;
5548
+ }
5549
+ result.push(value.slice(tokenStartI, i + 1));
5550
+ tokenStartI = i + 1;
5551
+ }
5552
+ }
5553
+ return result;
5554
+ }
5555
+ }
5556
+ var sentenceDiff = new SentenceDiff;
5557
+
5558
+ // node_modules/diff/libesm/diff/css.js
5559
+ class CssDiff extends Diff {
5560
+ tokenize(value) {
5561
+ return value.split(/([{}:;,]|\s+)/);
5562
+ }
5563
+ }
5564
+ var cssDiff = new CssDiff;
5565
+
5566
+ // node_modules/diff/libesm/diff/json.js
5567
+ class JsonDiff extends Diff {
5568
+ constructor() {
5569
+ super(...arguments);
5570
+ this.tokenize = tokenize;
5571
+ }
5572
+ get useLongestToken() {
5573
+ return true;
5574
+ }
5575
+ castInput(value, options) {
5576
+ const { undefinedReplacement, stringifyReplacer = (k, v) => typeof v === "undefined" ? undefinedReplacement : v } = options;
5577
+ return typeof value === "string" ? value : JSON.stringify(canonicalize(value, null, null, stringifyReplacer), null, " ");
5578
+ }
5579
+ equals(left, right, options) {
5580
+ return super.equals(left.replace(/,([\r\n])/g, "$1"), right.replace(/,([\r\n])/g, "$1"), options);
5581
+ }
5582
+ }
5583
+ var jsonDiff = new JsonDiff;
5584
+ function canonicalize(obj, stack, replacementStack, replacer, key) {
5585
+ stack = stack || [];
5586
+ replacementStack = replacementStack || [];
5587
+ if (replacer) {
5588
+ obj = replacer(key === undefined ? "" : key, obj);
5589
+ }
5590
+ let i;
5591
+ for (i = 0;i < stack.length; i += 1) {
5592
+ if (stack[i] === obj) {
5593
+ return replacementStack[i];
5594
+ }
5595
+ }
5596
+ let canonicalizedObj;
5597
+ if (Object.prototype.toString.call(obj) === "[object Array]") {
5598
+ stack.push(obj);
5599
+ canonicalizedObj = new Array(obj.length);
5600
+ replacementStack.push(canonicalizedObj);
5601
+ for (i = 0;i < obj.length; i += 1) {
5602
+ canonicalizedObj[i] = canonicalize(obj[i], stack, replacementStack, replacer, String(i));
5603
+ }
5604
+ stack.pop();
5605
+ replacementStack.pop();
5606
+ return canonicalizedObj;
5607
+ }
5608
+ if (obj && obj.toJSON) {
5609
+ obj = obj.toJSON();
5610
+ }
5611
+ if (typeof obj === "object" && obj !== null) {
5612
+ stack.push(obj);
5613
+ canonicalizedObj = {};
5614
+ replacementStack.push(canonicalizedObj);
5615
+ const sortedKeys = [];
5616
+ let key2;
5617
+ for (key2 in obj) {
5618
+ if (Object.prototype.hasOwnProperty.call(obj, key2)) {
5619
+ sortedKeys.push(key2);
5620
+ }
5621
+ }
5622
+ sortedKeys.sort();
5623
+ for (i = 0;i < sortedKeys.length; i += 1) {
5624
+ key2 = sortedKeys[i];
5625
+ canonicalizedObj[key2] = canonicalize(obj[key2], stack, replacementStack, replacer, key2);
5626
+ }
5627
+ stack.pop();
5628
+ replacementStack.pop();
5629
+ } else {
5630
+ canonicalizedObj = obj;
5631
+ }
5632
+ return canonicalizedObj;
5633
+ }
5634
+
5635
+ // node_modules/diff/libesm/diff/array.js
5636
+ class ArrayDiff extends Diff {
5637
+ tokenize(value) {
5638
+ return value.slice();
5639
+ }
5640
+ join(value) {
5641
+ return value;
5642
+ }
5643
+ removeEmpty(value) {
5644
+ return value;
5645
+ }
5646
+ }
5647
+ var arrayDiff = new ArrayDiff;
5648
+
5649
+ // node_modules/diff/libesm/patch/create.js
5650
+ function structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
5651
+ let optionsObj;
5652
+ if (!options) {
5653
+ optionsObj = {};
5654
+ } else if (typeof options === "function") {
5655
+ optionsObj = { callback: options };
5656
+ } else {
5657
+ optionsObj = options;
5658
+ }
5659
+ if (typeof optionsObj.context === "undefined") {
5660
+ optionsObj.context = 4;
5661
+ }
5662
+ const context = optionsObj.context;
5663
+ if (optionsObj.newlineIsToken) {
5664
+ throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");
5665
+ }
5666
+ if (!optionsObj.callback) {
5667
+ return diffLinesResultToPatch(diffLines(oldStr, newStr, optionsObj));
5668
+ } else {
5669
+ const { callback } = optionsObj;
5670
+ diffLines(oldStr, newStr, Object.assign(Object.assign({}, optionsObj), { callback: (diff) => {
5671
+ const patch = diffLinesResultToPatch(diff);
5672
+ callback(patch);
5673
+ } }));
5674
+ }
5675
+ function diffLinesResultToPatch(diff) {
5676
+ if (!diff) {
5677
+ return;
5678
+ }
5679
+ diff.push({ value: "", lines: [] });
5680
+ function contextLines(lines) {
5681
+ return lines.map(function(entry) {
5682
+ return " " + entry;
5683
+ });
5684
+ }
5685
+ const hunks = [];
5686
+ let oldRangeStart = 0, newRangeStart = 0, curRange = [], oldLine = 1, newLine = 1;
5687
+ for (let i = 0;i < diff.length; i++) {
5688
+ const current = diff[i], lines = current.lines || splitLines(current.value);
5689
+ current.lines = lines;
5690
+ if (current.added || current.removed) {
5691
+ if (!oldRangeStart) {
5692
+ const prev = diff[i - 1];
5693
+ oldRangeStart = oldLine;
5694
+ newRangeStart = newLine;
5695
+ if (prev) {
5696
+ curRange = context > 0 ? contextLines(prev.lines.slice(-context)) : [];
5697
+ oldRangeStart -= curRange.length;
5698
+ newRangeStart -= curRange.length;
5699
+ }
5700
+ }
5701
+ for (const line of lines) {
5702
+ curRange.push((current.added ? "+" : "-") + line);
5703
+ }
5704
+ if (current.added) {
5705
+ newLine += lines.length;
5706
+ } else {
5707
+ oldLine += lines.length;
5708
+ }
5709
+ } else {
5710
+ if (oldRangeStart) {
5711
+ if (lines.length <= context * 2 && i < diff.length - 2) {
5712
+ for (const line of contextLines(lines)) {
5713
+ curRange.push(line);
5714
+ }
5715
+ } else {
5716
+ const contextSize = Math.min(lines.length, context);
5717
+ for (const line of contextLines(lines.slice(0, contextSize))) {
5718
+ curRange.push(line);
5719
+ }
5720
+ const hunk = {
5721
+ oldStart: oldRangeStart,
5722
+ oldLines: oldLine - oldRangeStart + contextSize,
5723
+ newStart: newRangeStart,
5724
+ newLines: newLine - newRangeStart + contextSize,
5725
+ lines: curRange
5726
+ };
5727
+ hunks.push(hunk);
5728
+ oldRangeStart = 0;
5729
+ newRangeStart = 0;
5730
+ curRange = [];
5731
+ }
5732
+ }
5733
+ oldLine += lines.length;
5734
+ newLine += lines.length;
5735
+ }
5736
+ }
5737
+ for (const hunk of hunks) {
5738
+ for (let i = 0;i < hunk.lines.length; i++) {
5739
+ if (hunk.lines[i].endsWith(`
5740
+ `)) {
5741
+ hunk.lines[i] = hunk.lines[i].slice(0, -1);
5742
+ } else {
5743
+ hunk.lines.splice(i + 1, 0, "\");
5744
+ i++;
5745
+ }
5746
+ }
5747
+ }
5748
+ return {
5749
+ oldFileName,
5750
+ newFileName,
5751
+ oldHeader,
5752
+ newHeader,
5753
+ hunks
5754
+ };
5755
+ }
5756
+ }
5757
+ function formatPatch(patch) {
5758
+ if (Array.isArray(patch)) {
5759
+ return patch.map(formatPatch).join(`
5760
+ `);
5761
+ }
5762
+ const ret = [];
5763
+ if (patch.oldFileName == patch.newFileName) {
5764
+ ret.push("Index: " + patch.oldFileName);
5765
+ }
5766
+ ret.push("===================================================================");
5767
+ ret.push("--- " + patch.oldFileName + (typeof patch.oldHeader === "undefined" ? "" : "\t" + patch.oldHeader));
5768
+ ret.push("+++ " + patch.newFileName + (typeof patch.newHeader === "undefined" ? "" : "\t" + patch.newHeader));
5769
+ for (let i = 0;i < patch.hunks.length; i++) {
5770
+ const hunk = patch.hunks[i];
5771
+ if (hunk.oldLines === 0) {
5772
+ hunk.oldStart -= 1;
5773
+ }
5774
+ if (hunk.newLines === 0) {
5775
+ hunk.newStart -= 1;
5776
+ }
5777
+ ret.push("@@ -" + hunk.oldStart + "," + hunk.oldLines + " +" + hunk.newStart + "," + hunk.newLines + " @@");
5778
+ for (const line of hunk.lines) {
5779
+ ret.push(line);
5780
+ }
5781
+ }
5782
+ return ret.join(`
5783
+ `) + `
5784
+ `;
5785
+ }
5786
+ function createTwoFilesPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options) {
5787
+ if (typeof options === "function") {
5788
+ options = { callback: options };
5789
+ }
5790
+ if (!(options === null || options === undefined ? undefined : options.callback)) {
5791
+ const patchObj = structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, options);
5792
+ if (!patchObj) {
5793
+ return;
5794
+ }
5795
+ return formatPatch(patchObj);
5796
+ } else {
5797
+ const { callback } = options;
5798
+ structuredPatch(oldFileName, newFileName, oldStr, newStr, oldHeader, newHeader, Object.assign(Object.assign({}, options), { callback: (patchObj) => {
5799
+ if (!patchObj) {
5800
+ callback(undefined);
5801
+ } else {
5802
+ callback(formatPatch(patchObj));
5803
+ }
5804
+ } }));
5805
+ }
5806
+ }
5807
+ function splitLines(text) {
5808
+ const hasTrailingNl = text.endsWith(`
5809
+ `);
5810
+ const result = text.split(`
5811
+ `).map((line) => line + `
5812
+ `);
5813
+ if (hasTrailingNl) {
5814
+ result.pop();
5815
+ } else {
5816
+ result.push(result.pop().slice(0, -1));
5817
+ }
5818
+ return result;
5819
+ }
5820
+
5821
+ // src/services/diffService.ts
5822
+ var getIgnorePatterns2 = async () => {
5823
+ try {
5824
+ const ignoreContent = await fs5.readFile(IGNORE_PATH, "utf-8");
5825
+ return ignoreContent.split(`
5826
+ `).map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
5827
+ } catch (error) {
5828
+ return [];
5829
+ }
5830
+ };
5831
+ var shouldIgnore3 = (name, patterns) => {
5832
+ return patterns.some((pattern) => {
5833
+ if (pattern === name || pattern === `${name}/`) {
5834
+ return true;
5835
+ }
5836
+ if (pattern.startsWith("*.")) {
5837
+ const ext = pattern.slice(1);
5838
+ return name.endsWith(ext);
5839
+ }
5840
+ if (pattern.endsWith("/") && name === pattern.slice(0, -1)) {
5841
+ return true;
5842
+ }
5843
+ return false;
5844
+ });
5845
+ };
5846
+ var getTrackedFiles2 = async (commitHash) => {
5847
+ const trackedFiles = new Map;
5848
+ if (!commitHash)
5849
+ return trackedFiles;
5850
+ try {
5851
+ const commitPath = path5.join(OBJECTS_PATH, commitHash.substring(0, 2), commitHash.substring(2));
5852
+ const commitData = JSON.parse(await fs5.readFile(commitPath, "utf-8"));
5853
+ if (commitData.files && Array.isArray(commitData.files)) {
5854
+ for (const entry of commitData.files) {
5855
+ trackedFiles.set(entry.path, entry.hash);
5856
+ }
5857
+ }
5858
+ } catch (error) {}
5859
+ return trackedFiles;
5860
+ };
5861
+ var getFileContentFromHash = async (hash) => {
5862
+ try {
5863
+ const objectPath = path5.join(OBJECTS_PATH, hash.substring(0, 2), hash.substring(2));
5864
+ return await fs5.readFile(objectPath, "utf-8");
5865
+ } catch (error) {
5866
+ return "";
5867
+ }
5868
+ };
5869
+ var colorDiffLine = (line) => {
5870
+ if (line.startsWith("+") && !line.startsWith("+++")) {
5871
+ return source_default.green(line);
5872
+ } else if (line.startsWith("-") && !line.startsWith("---")) {
5873
+ return source_default.red(line);
5874
+ } else if (line.startsWith("@@")) {
5875
+ return source_default.cyan(line);
5876
+ } else if (line.startsWith("diff") || line.startsWith("index") || line.startsWith("---") || line.startsWith("+++")) {
5877
+ return source_default.bold(line);
5878
+ }
5879
+ return line;
5880
+ };
5881
+ var normalizeRelativePath4 = (pathValue) => {
5882
+ const normalized = pathValue.split("\\").join("/");
5883
+ if (normalized && !normalized.startsWith("./") && !normalized.startsWith("../") && !normalized.startsWith("/")) {
5884
+ return "./" + normalized;
5885
+ }
5886
+ return normalized;
5887
+ };
5888
+ var walk2 = async (dir, repoRoot, ignorePatterns) => {
5889
+ let files = [];
5890
+ const entries = await fs5.readdir(dir, { withFileTypes: true });
5891
+ for (const entry of entries) {
5892
+ const res = path5.resolve(dir, entry.name);
5893
+ if (entry.name === VCS_DIR || shouldIgnore3(entry.name, ignorePatterns))
5894
+ continue;
5895
+ if (entry.isDirectory()) {
5896
+ files = files.concat(await walk2(res, repoRoot, ignorePatterns));
5897
+ } else {
5898
+ files.push(normalizeRelativePath4(path5.relative(repoRoot, res)));
5899
+ }
5900
+ }
5901
+ return files;
5902
+ };
5903
+ var diff = async (filePaths) => {
5904
+ try {
5905
+ const currentHead = await getCurrentHead();
5906
+ const trackedFiles = await getTrackedFiles2(currentHead);
5907
+ const ignorePatterns = await getIgnorePatterns2();
5908
+ if (!currentHead) {
5909
+ console.log(source_default.yellow("No commits yet. Nothing to diff."));
5910
+ return;
5911
+ }
5912
+ const repoRoot = process.cwd();
5913
+ let filesToCompare = [];
5914
+ if (filePaths && filePaths.length > 0) {
5915
+ for (const p of filePaths) {
5916
+ const absolutePath = path5.resolve(repoRoot, p);
5917
+ try {
5918
+ const stats = await fs5.stat(absolutePath);
5919
+ if (stats.isDirectory()) {
5920
+ const dirFiles = await walk2(absolutePath, repoRoot, ignorePatterns);
5921
+ filesToCompare.push(...dirFiles);
5922
+ } else {
5923
+ const relativeToRoot = path5.relative(repoRoot, absolutePath);
5924
+ filesToCompare.push(normalizeRelativePath4(relativeToRoot));
5925
+ }
5926
+ } catch (error) {
5927
+ const relativeToRoot = path5.relative(repoRoot, absolutePath);
5928
+ filesToCompare.push(normalizeRelativePath4(relativeToRoot));
5929
+ }
5930
+ }
5931
+ filesToCompare = [...new Set(filesToCompare)];
5932
+ } else {
5933
+ filesToCompare = await walk2(repoRoot, repoRoot, ignorePatterns);
5934
+ }
5935
+ let hasDiffs = false;
5936
+ for (const relPath of filesToCompare) {
5937
+ try {
5938
+ const fullPath = path5.join(repoRoot, relPath);
5939
+ const fileBuffer = await fs5.readFile(fullPath);
5940
+ const fileHash = hashContent(fileBuffer);
5941
+ const trackedHash = trackedFiles.get(relPath);
5942
+ if (trackedHash && fileHash !== trackedHash) {
5943
+ const oldContent = await getFileContentFromHash(trackedHash);
5944
+ const newContent = fileBuffer.toString("utf-8");
5945
+ const patch = createTwoFilesPatch(`a/${relPath}`, `b/${relPath}`, oldContent, newContent, "HEAD", "Working Directory");
5946
+ const lines = patch.split(`
5947
+ `);
5948
+ for (const line of lines) {
5949
+ console.log(colorDiffLine(line));
5950
+ }
5951
+ console.log("");
5952
+ hasDiffs = true;
5953
+ }
5954
+ } catch (error) {}
5955
+ }
5956
+ if (!hasDiffs) {
5957
+ console.log(source_default.green("No changes detected."));
5958
+ }
5959
+ } catch (error) {
5960
+ const message2 = error instanceof Error ? error.message : String(error);
5961
+ console.log("Error generating diff:", message2);
5962
+ process.exit(1);
5963
+ }
5964
+ };
5965
+
5966
+ // src/commands/diffCommand.ts
5967
+ var diffCommand = new Command("diff").description("Show changes between working directory and last commit").argument("[files...]", "Specific files to show differences for").addHelpText("after", `
5968
+ Examples:
5969
+ $ brch diff Show changes for all modified files
5970
+ $ brch diff file.txt Show changes for a specific file
5971
+ $ brch diff src/ Show changes for all files in a directory
5972
+
5973
+ Displays line-by-line differences between your current files and the last committed version.
5974
+ Deleted lines are shown in red, and added lines are shown in green.
5975
+ `).action(async (files) => {
5976
+ await diff(files);
5977
+ });
5978
+
5979
+ // src/commands/index.ts
5980
+ var registerCommands = (program2) => {
5981
+ program2.addCommand(configCommand);
5982
+ program2.addCommand(initCommand);
5983
+ program2.addCommand(addCommand);
5984
+ program2.addCommand(commitCommand);
5985
+ program2.addCommand(logCommand);
5986
+ program2.addCommand(statusCommand);
5987
+ program2.addCommand(diffCommand);
5988
+ };
5989
+
5990
+ // src/index.ts
5991
+ program.name(VCS_NAME).description("brch - A simple version control system for tracking changes in your project").version("0.0.1").addHelpText("after", `
5992
+ Examples:
5993
+ $ brch init Initialize a new repository
5994
+ $ brch add . Stage all files in current directory
5995
+ $ brch status Show current repository status
5996
+ $ brch commit -m "Commit msg" Commit staged changes
5997
+ $ brch log Show commit history
5998
+ $ brch diff Show changes in working tree
5999
+ $ brch config set user.name "John Doe" Set configuration
6000
+
6001
+ For more information about a specific command, use:
6002
+ $ brch <command> --help
6003
+ `);
3027
6004
  registerCommands(program);
3028
6005
  program.parse(process.argv);