@bshsolutions/git 0.0.1-alpha
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/README.md +41 -0
- package/dist/cli.js +951 -0
- package/dist/cli.js.map +1 -0
- package/package.json +58 -0
package/README.md
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# BSH Git CLI
|
|
2
|
+
|
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
|
4
|
+
[](https://github.com/bsh-devsolutions/git.bsh)
|
|
5
|
+
|
|
6
|
+
A small **Node.js CLI** for everyday Git workflows: quick **`hello`** checks and a **`commit`** command that can install a **`commit-msg`** hook so messages stay consistent.
|
|
7
|
+
|
|
8
|
+
| | |
|
|
9
|
+
| --- | --- |
|
|
10
|
+
| **Binary** | `git` |
|
|
11
|
+
| **Package** | [`@bshsolutions/git`](https://www.npmjs.com/package/@bshsolutions/git) |
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Features
|
|
16
|
+
|
|
17
|
+
- **Smoke-test friendly** — `hello` verifies the CLI runs where you need it.
|
|
18
|
+
- **Structured commits** — validate messages and optionally enforce them via a Git hook.
|
|
19
|
+
- **`npx`-first** — run without a global install, or `npm link` for local development.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Documentation
|
|
24
|
+
|
|
25
|
+
docs/
|
|
26
|
+
- `├──` [**Documentation home**](docs/README.md)
|
|
27
|
+
- `├──` [**Setup**](docs/setup.md)
|
|
28
|
+
- `├──` [**Commands**](docs/commands.md)
|
|
29
|
+
- `└──` [**Commit**](docs/commit.md)
|
|
30
|
+
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
## Quick start
|
|
34
|
+
|
|
35
|
+
```sh
|
|
36
|
+
npm install
|
|
37
|
+
npm run build
|
|
38
|
+
npx @bshsolutions/git hello --name you
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
For local development, linking into other repos, and hook setup, start with [**Setup**](docs/setup.md).
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,951 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command, CommanderError, Option } from 'commander';
|
|
3
|
+
import { readFileSync, mkdirSync, existsSync, unlinkSync, readdirSync, rmdirSync, writeFileSync, chmodSync } from 'fs';
|
|
4
|
+
import { dirname, join, resolve } from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { readFile, access, writeFile, mkdir } from 'fs/promises';
|
|
7
|
+
import pino from 'pino';
|
|
8
|
+
import pinoPretty from 'pino-pretty';
|
|
9
|
+
import { spawnSync, execSync } from 'child_process';
|
|
10
|
+
import prompts2 from 'prompts';
|
|
11
|
+
|
|
12
|
+
// src/config/consts.ts
|
|
13
|
+
var consts = {
|
|
14
|
+
configRelativePath: ".github/bsh.json"
|
|
15
|
+
};
|
|
16
|
+
var defaultConfig = {
|
|
17
|
+
commit: {
|
|
18
|
+
message: {
|
|
19
|
+
format: "{type} ({scope}): {message}",
|
|
20
|
+
types: ["feat", "fix", "docs", "style", "refactor", "perf", "test", "build", "ci", "chore", "revert"],
|
|
21
|
+
scopes: []
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
logger: {
|
|
25
|
+
level: "info",
|
|
26
|
+
file: {
|
|
27
|
+
enable: false,
|
|
28
|
+
path: "logs/bsh-git.log"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
async function loadFromFile() {
|
|
33
|
+
const path = resolve(process.cwd(), consts.configRelativePath);
|
|
34
|
+
try {
|
|
35
|
+
const text = await readFile(path, "utf8");
|
|
36
|
+
try {
|
|
37
|
+
return mergeConfig(JSON.parse(text));
|
|
38
|
+
} catch (err) {
|
|
39
|
+
if (err instanceof SyntaxError) return structuredClone(defaultConfig);
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
} catch (err) {
|
|
43
|
+
if (getNodeErrno(err) === "ENOENT") return structuredClone(defaultConfig);
|
|
44
|
+
throw err;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function deepMerge(target, source) {
|
|
48
|
+
if (typeof source !== "object" || source === null) return target;
|
|
49
|
+
if (typeof target !== "object" || target === null) return target;
|
|
50
|
+
const result = Array.isArray(target) ? [...target] : { ...target };
|
|
51
|
+
for (const key of Object.keys(target)) {
|
|
52
|
+
if (Object.prototype.hasOwnProperty.call(source, key) && typeof key === "string") {
|
|
53
|
+
const sourceVal = source[key];
|
|
54
|
+
const targetVal = target[key];
|
|
55
|
+
if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {
|
|
56
|
+
result[key] = [...sourceVal];
|
|
57
|
+
} else if (typeof targetVal === "object" && targetVal !== null && typeof sourceVal === "object" && sourceVal !== null) {
|
|
58
|
+
result[key] = deepMerge(targetVal, sourceVal);
|
|
59
|
+
} else {
|
|
60
|
+
if (typeof sourceVal === typeof targetVal || Array.isArray(sourceVal)) {
|
|
61
|
+
result[key] = sourceVal;
|
|
62
|
+
} else {
|
|
63
|
+
result[key] = sourceVal !== void 0 && sourceVal !== null ? sourceVal : targetVal;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
function mergeConfig(raw) {
|
|
71
|
+
if (!raw || typeof raw !== "object") {
|
|
72
|
+
return structuredClone(defaultConfig);
|
|
73
|
+
}
|
|
74
|
+
return deepMerge(defaultConfig, raw);
|
|
75
|
+
}
|
|
76
|
+
function getNodeErrno(err) {
|
|
77
|
+
if (!err || typeof err !== "object" || !("code" in err)) return void 0;
|
|
78
|
+
const code = err.code;
|
|
79
|
+
return code;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// src/config/index.ts
|
|
83
|
+
var instance;
|
|
84
|
+
var initPromise;
|
|
85
|
+
async function loadConfig() {
|
|
86
|
+
if (instance) return instance;
|
|
87
|
+
if (!initPromise) {
|
|
88
|
+
initPromise = loadFromFile().then((c) => {
|
|
89
|
+
instance = c;
|
|
90
|
+
return c;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return initPromise;
|
|
94
|
+
}
|
|
95
|
+
function getConfig() {
|
|
96
|
+
if (!instance) instance = defaultConfig;
|
|
97
|
+
return instance;
|
|
98
|
+
}
|
|
99
|
+
function configPathFromCwd() {
|
|
100
|
+
return resolve(process.cwd(), consts.configRelativePath);
|
|
101
|
+
}
|
|
102
|
+
function isRecord(value) {
|
|
103
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
104
|
+
}
|
|
105
|
+
function mergeValue(base, patch) {
|
|
106
|
+
if (Array.isArray(base) && Array.isArray(patch)) return [...patch];
|
|
107
|
+
if (isRecord(base) && isRecord(patch)) {
|
|
108
|
+
const result = { ...base };
|
|
109
|
+
for (const key of Object.keys(base)) {
|
|
110
|
+
if (!Object.prototype.hasOwnProperty.call(patch, key)) continue;
|
|
111
|
+
result[key] = mergeValue(base[key], patch[key]);
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
return patch === void 0 ? base : patch;
|
|
116
|
+
}
|
|
117
|
+
function mergeIntoConfig(base, patch) {
|
|
118
|
+
return mergeValue(base, patch);
|
|
119
|
+
}
|
|
120
|
+
async function writeConfigFile(config) {
|
|
121
|
+
const configPath = configPathFromCwd();
|
|
122
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
123
|
+
await writeFile(configPath, JSON.stringify(config, null, 2), "utf8");
|
|
124
|
+
}
|
|
125
|
+
async function createConfigFileIfNotExists() {
|
|
126
|
+
const configPath = configPathFromCwd();
|
|
127
|
+
try {
|
|
128
|
+
await writeFile(configPath, "", { flag: "wx" });
|
|
129
|
+
} catch (err) {
|
|
130
|
+
const code = getNodeErrno(err);
|
|
131
|
+
if (code !== "ENOENT" && code !== "EEXIST") throw err;
|
|
132
|
+
if (code === "ENOENT") {
|
|
133
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
134
|
+
await writeFile(configPath, "", { flag: "wx" });
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const config = await loadFromFile();
|
|
138
|
+
await writeConfigFile(config);
|
|
139
|
+
return config;
|
|
140
|
+
}
|
|
141
|
+
async function mergeConfigFile(nextData) {
|
|
142
|
+
const current = await loadFromFile();
|
|
143
|
+
const merged = mergeIntoConfig(current, nextData);
|
|
144
|
+
await writeConfigFile(merged);
|
|
145
|
+
instance = merged;
|
|
146
|
+
initPromise = Promise.resolve(merged);
|
|
147
|
+
return merged;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// src/lib/errors/index.ts
|
|
151
|
+
var BshError = class extends Error {
|
|
152
|
+
constructor(code, message, options) {
|
|
153
|
+
super(message);
|
|
154
|
+
this.name = "BshError";
|
|
155
|
+
this.code = code;
|
|
156
|
+
this.context = options?.context;
|
|
157
|
+
if (options?.cause !== void 0) {
|
|
158
|
+
this.cause = options.cause;
|
|
159
|
+
}
|
|
160
|
+
Object.setPrototypeOf(this, new.target.prototype);
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
var loggerConfig = () => getConfig().logger;
|
|
164
|
+
var level = () => loggerConfig().level;
|
|
165
|
+
function resolveLogFilePath() {
|
|
166
|
+
const { file } = loggerConfig();
|
|
167
|
+
if (!file.enable || !file.path.trim()) return void 0;
|
|
168
|
+
return resolve(file.path.trim());
|
|
169
|
+
}
|
|
170
|
+
var PRETTY_BASE = {
|
|
171
|
+
translateTime: "SYS:yyyy-mm-dd'T'HH:MM:ss.l",
|
|
172
|
+
ignore: "pid,hostname",
|
|
173
|
+
singleLine: true,
|
|
174
|
+
messageFormat: "{msg}"
|
|
175
|
+
};
|
|
176
|
+
function createPrettyDestination(destination, opts) {
|
|
177
|
+
return pinoPretty({
|
|
178
|
+
...PRETTY_BASE,
|
|
179
|
+
colorize: opts.colorize,
|
|
180
|
+
destination,
|
|
181
|
+
sync: true,
|
|
182
|
+
...opts.mkdir ? { mkdir: true } : {}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function createDestination() {
|
|
186
|
+
const logFile = resolveLogFilePath();
|
|
187
|
+
if (process.stdout.isTTY) {
|
|
188
|
+
const consoleDest2 = createPrettyDestination(1, { colorize: true });
|
|
189
|
+
if (!logFile) return consoleDest2;
|
|
190
|
+
const fileDest2 = createPrettyDestination(logFile, {
|
|
191
|
+
colorize: false,
|
|
192
|
+
mkdir: true
|
|
193
|
+
});
|
|
194
|
+
return pino.multistream([
|
|
195
|
+
{ level: level(), stream: consoleDest2 },
|
|
196
|
+
{ level: level(), stream: fileDest2 }
|
|
197
|
+
]);
|
|
198
|
+
}
|
|
199
|
+
const consoleDest = pino.destination({ dest: 1, sync: true, minLength: 0 });
|
|
200
|
+
if (!logFile) return consoleDest;
|
|
201
|
+
mkdirSync(dirname(logFile), { recursive: true });
|
|
202
|
+
const fileDest = pino.destination({
|
|
203
|
+
dest: logFile,
|
|
204
|
+
sync: true,
|
|
205
|
+
mkdir: true,
|
|
206
|
+
minLength: 0
|
|
207
|
+
});
|
|
208
|
+
return pino.multistream([
|
|
209
|
+
{ level: level(), stream: consoleDest },
|
|
210
|
+
{ level: level(), stream: fileDest }
|
|
211
|
+
]);
|
|
212
|
+
}
|
|
213
|
+
function serializeErr(err) {
|
|
214
|
+
const base = pino.stdSerializers.err(err);
|
|
215
|
+
if (err instanceof BshError) {
|
|
216
|
+
return {
|
|
217
|
+
...base,
|
|
218
|
+
code: err.code,
|
|
219
|
+
...err.context !== void 0 && { context: err.context }
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
return base;
|
|
223
|
+
}
|
|
224
|
+
function buildBaseOptions() {
|
|
225
|
+
return {
|
|
226
|
+
level: level(),
|
|
227
|
+
serializers: {
|
|
228
|
+
err: serializeErr
|
|
229
|
+
},
|
|
230
|
+
redact: {
|
|
231
|
+
paths: [
|
|
232
|
+
"password",
|
|
233
|
+
"token",
|
|
234
|
+
"accessToken",
|
|
235
|
+
"refreshToken",
|
|
236
|
+
"authorization",
|
|
237
|
+
"cookie",
|
|
238
|
+
"cookies",
|
|
239
|
+
"set-cookie",
|
|
240
|
+
"*.password",
|
|
241
|
+
"*.token",
|
|
242
|
+
"*.authorization"
|
|
243
|
+
],
|
|
244
|
+
censor: "[redacted]"
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
var rootLogger;
|
|
249
|
+
function getRootLogger() {
|
|
250
|
+
if (!rootLogger) {
|
|
251
|
+
rootLogger = pino(buildBaseOptions(), createDestination());
|
|
252
|
+
}
|
|
253
|
+
return rootLogger;
|
|
254
|
+
}
|
|
255
|
+
var logger = new Proxy({}, {
|
|
256
|
+
get(_target, prop) {
|
|
257
|
+
const inst = getRootLogger();
|
|
258
|
+
const value = inst[prop];
|
|
259
|
+
return typeof value === "function" ? value.bind(inst) : value;
|
|
260
|
+
}
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// src/lib/middleware/global-error.ts
|
|
264
|
+
function logMessageFor(err) {
|
|
265
|
+
if (err instanceof BshError) return `[${err.code}] ${err.message}`;
|
|
266
|
+
if (err instanceof Error) return err.message;
|
|
267
|
+
return "command failed";
|
|
268
|
+
}
|
|
269
|
+
async function errorHandlingMiddleware(program2, argv = process.argv) {
|
|
270
|
+
program2.exitOverride();
|
|
271
|
+
try {
|
|
272
|
+
await program2.parseAsync(argv);
|
|
273
|
+
} catch (err) {
|
|
274
|
+
if (err instanceof CommanderError && (err.exitCode === 0 || err.code === "commander.help")) {
|
|
275
|
+
process.exit(0);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
if (err instanceof BshError) {
|
|
279
|
+
logger.error(logMessageFor(err));
|
|
280
|
+
process.exit(err.code);
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
logger.error({ err }, logMessageFor(err));
|
|
284
|
+
process.exit(err instanceof CommanderError ? err.exitCode : 1);
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/lib/middleware/index.ts
|
|
289
|
+
function middleware(program2) {
|
|
290
|
+
return errorHandlingMiddleware(program2);
|
|
291
|
+
}
|
|
292
|
+
async function configExists() {
|
|
293
|
+
const configPath = resolve(process.cwd(), consts.configRelativePath);
|
|
294
|
+
try {
|
|
295
|
+
await access(configPath);
|
|
296
|
+
return true;
|
|
297
|
+
} catch (err) {
|
|
298
|
+
if (getNodeErrno(err) === "ENOENT") return false;
|
|
299
|
+
throw err;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async function runInit() {
|
|
303
|
+
const existed = await configExists();
|
|
304
|
+
await createConfigFileIfNotExists();
|
|
305
|
+
if (!existed) logger.info("Config file created");
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// src/commands/init/cmd.ts
|
|
309
|
+
var cmd_default = {
|
|
310
|
+
name: "init",
|
|
311
|
+
description: "Initialize the environment",
|
|
312
|
+
summary: "Initialize the environment",
|
|
313
|
+
action: async (_options) => {
|
|
314
|
+
await runInit();
|
|
315
|
+
}
|
|
316
|
+
};
|
|
317
|
+
function runRm() {
|
|
318
|
+
rmConfigFile();
|
|
319
|
+
}
|
|
320
|
+
function rmConfigFile() {
|
|
321
|
+
const configPath = resolve(process.cwd(), consts.configRelativePath);
|
|
322
|
+
const configDirPath = dirname(configPath);
|
|
323
|
+
try {
|
|
324
|
+
unlinkSync(configPath);
|
|
325
|
+
} catch (err) {
|
|
326
|
+
if (getNodeErrno2(err) !== "ENOENT") throw err;
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
try {
|
|
330
|
+
if (readdirSync(configDirPath).length === 0) {
|
|
331
|
+
rmdirSync(configDirPath);
|
|
332
|
+
}
|
|
333
|
+
} catch (err) {
|
|
334
|
+
if (getNodeErrno2(err) !== "ENOENT" && getNodeErrno2(err) !== "ENOTEMPTY") {
|
|
335
|
+
throw err;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
logger.info("Config file removed");
|
|
339
|
+
}
|
|
340
|
+
function getNodeErrno2(err) {
|
|
341
|
+
if (!err || typeof err !== "object" || !("code" in err)) return void 0;
|
|
342
|
+
return err.code;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
// src/commands/rm/cmd.ts
|
|
346
|
+
var cmd_default2 = {
|
|
347
|
+
name: "rm",
|
|
348
|
+
description: "Remove CLI config from this project",
|
|
349
|
+
summary: "Undo init by removing project config",
|
|
350
|
+
action: (_options) => {
|
|
351
|
+
runRm();
|
|
352
|
+
}
|
|
353
|
+
};
|
|
354
|
+
|
|
355
|
+
// src/commands/consts.ts
|
|
356
|
+
var consts2 = {
|
|
357
|
+
commit: {
|
|
358
|
+
commitMsgHook: "commit-msg"
|
|
359
|
+
}
|
|
360
|
+
};
|
|
361
|
+
function gitHooksDir() {
|
|
362
|
+
try {
|
|
363
|
+
return execSync("git rev-parse --git-path hooks", {
|
|
364
|
+
encoding: "utf8",
|
|
365
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
366
|
+
}).trim();
|
|
367
|
+
} catch (error) {
|
|
368
|
+
console.error(error);
|
|
369
|
+
throw new BshError(404, "Not a Git repository (or hooks path unavailable).");
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
var messageFormatScript = `#!/bin/sh
|
|
373
|
+
# BSH Git \u2014 commit message format validator
|
|
374
|
+
npx @bshsolutions/git commit msg validate "$1"
|
|
375
|
+
`;
|
|
376
|
+
function canOverwriteHook(path, force) {
|
|
377
|
+
if (!existsSync(path)) return true;
|
|
378
|
+
if (force) return true;
|
|
379
|
+
try {
|
|
380
|
+
const content = readFileSync(path, "utf8");
|
|
381
|
+
if (!content.includes(messageFormatScript)) return true;
|
|
382
|
+
} catch (e) {
|
|
383
|
+
const code = e && typeof e === "object" && "code" in e && typeof e.code === "string" ? e.code : "";
|
|
384
|
+
logger.error(`Could not read ${path}${code ? ` (${code})` : ""}.`);
|
|
385
|
+
process.exitCode = 1;
|
|
386
|
+
return false;
|
|
387
|
+
}
|
|
388
|
+
process.exitCode = 1;
|
|
389
|
+
return false;
|
|
390
|
+
}
|
|
391
|
+
var writeHookFile = (path) => {
|
|
392
|
+
writeFileSync(path, messageFormatScript, { encoding: "utf8" });
|
|
393
|
+
chmodSync(path, 493);
|
|
394
|
+
};
|
|
395
|
+
function toCsv(values) {
|
|
396
|
+
return values.join(", ");
|
|
397
|
+
}
|
|
398
|
+
function fromCsv(value) {
|
|
399
|
+
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
400
|
+
}
|
|
401
|
+
var cancelPrompts = {
|
|
402
|
+
onCancel: () => {
|
|
403
|
+
process.exit(130);
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
async function promptMessageConfig(defaults) {
|
|
407
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) return defaults;
|
|
408
|
+
logger.info("Configure commit message defaults. Press Enter to keep current values.");
|
|
409
|
+
const formatResponse = await prompts2(
|
|
410
|
+
{
|
|
411
|
+
type: "text",
|
|
412
|
+
name: "format",
|
|
413
|
+
message: "Commit format",
|
|
414
|
+
initial: defaults.format
|
|
415
|
+
},
|
|
416
|
+
cancelPrompts
|
|
417
|
+
);
|
|
418
|
+
const typesResponse = await prompts2(
|
|
419
|
+
{
|
|
420
|
+
type: "text",
|
|
421
|
+
name: "types",
|
|
422
|
+
message: "Commit types (comma-separated)",
|
|
423
|
+
initial: toCsv(defaults.types)
|
|
424
|
+
},
|
|
425
|
+
cancelPrompts
|
|
426
|
+
);
|
|
427
|
+
const scopesResponse = await prompts2(
|
|
428
|
+
{
|
|
429
|
+
type: "text",
|
|
430
|
+
name: "scopes",
|
|
431
|
+
message: "Commit scopes (comma-separated)",
|
|
432
|
+
initial: toCsv(defaults.scopes)
|
|
433
|
+
},
|
|
434
|
+
cancelPrompts
|
|
435
|
+
);
|
|
436
|
+
const format = String(formatResponse.format ?? "").trim() || defaults.format;
|
|
437
|
+
const typesStr = String(typesResponse.types ?? "").trim();
|
|
438
|
+
const scopesStr = String(scopesResponse.scopes ?? "").trim();
|
|
439
|
+
return {
|
|
440
|
+
format,
|
|
441
|
+
types: typesStr === "" ? defaults.types : fromCsv(typesStr),
|
|
442
|
+
scopes: scopesStr === "" ? defaults.scopes : fromCsv(scopesStr)
|
|
443
|
+
};
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// src/commands/commit/cmds/msg/cmds/install/impl.ts
|
|
447
|
+
var impl_default = async (options) => {
|
|
448
|
+
const force = options.force === true;
|
|
449
|
+
const hooksDir = gitHooksDir();
|
|
450
|
+
const commitMsgPath = `${hooksDir}/${consts2.commit.commitMsgHook}`;
|
|
451
|
+
if (!canOverwriteHook(commitMsgPath, force)) {
|
|
452
|
+
process.exitCode = 1;
|
|
453
|
+
logger.error(`${consts2.commit.commitMsgHook} already exists at ${commitMsgPath}. Use --force to replace it.`);
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const currentMessageConfig = getConfig().commit.message;
|
|
457
|
+
const messageConfig = await promptMessageConfig(currentMessageConfig);
|
|
458
|
+
await mergeConfigFile({
|
|
459
|
+
commit: {
|
|
460
|
+
message: messageConfig
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
writeHookFile(commitMsgPath);
|
|
464
|
+
logger.info(`Installed ${commitMsgPath}`);
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
// src/commands/commit/cmds/msg/cmds/install/cmd.ts
|
|
468
|
+
var cmd_default3 = {
|
|
469
|
+
name: "install",
|
|
470
|
+
aliases: ["i"],
|
|
471
|
+
description: "Write a commit-msg hook that enforces the message format",
|
|
472
|
+
options: [
|
|
473
|
+
{
|
|
474
|
+
flags: "-f, --force",
|
|
475
|
+
description: "Replace an existing commit-msg hook",
|
|
476
|
+
defaultValue: false
|
|
477
|
+
}
|
|
478
|
+
],
|
|
479
|
+
action: (options) => impl_default(options)
|
|
480
|
+
};
|
|
481
|
+
|
|
482
|
+
// src/commands/commit/cmds/msg/cmds/prompt/format.ts
|
|
483
|
+
function formatTokenOrder(format) {
|
|
484
|
+
const re = /\{(type|scope|message)\}/g;
|
|
485
|
+
const order = [];
|
|
486
|
+
const seen = /* @__PURE__ */ new Set();
|
|
487
|
+
let m;
|
|
488
|
+
while ((m = re.exec(format)) !== null) {
|
|
489
|
+
const t = m[1];
|
|
490
|
+
if (!seen.has(t)) {
|
|
491
|
+
seen.add(t);
|
|
492
|
+
order.push(t);
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
return order;
|
|
496
|
+
}
|
|
497
|
+
function formatTokenUsage(format) {
|
|
498
|
+
const tokens = formatTokenOrder(format);
|
|
499
|
+
return {
|
|
500
|
+
type: tokens.includes("type"),
|
|
501
|
+
scope: tokens.includes("scope"),
|
|
502
|
+
message: tokens.includes("message")
|
|
503
|
+
};
|
|
504
|
+
}
|
|
505
|
+
function buildMessageFromParts(format, parts) {
|
|
506
|
+
return format.replace(/\{type\}/g, parts.type ?? "").replace(/\{scope\}/g, parts.scope ?? "").replace(/\{message\}/g, parts.message ?? "");
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
// src/commands/commit/cmds/msg/cmds/prompt/impl.ts
|
|
510
|
+
var cancelPrompts2 = {
|
|
511
|
+
onCancel: () => {
|
|
512
|
+
process.exit(130);
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
async function chooseFromConfigList(label, allowed) {
|
|
516
|
+
if (allowed.length === 0) {
|
|
517
|
+
const response2 = await prompts2(
|
|
518
|
+
{
|
|
519
|
+
type: "text",
|
|
520
|
+
name: "value",
|
|
521
|
+
message: `${label} (not listed in config \u2014 type a value)`,
|
|
522
|
+
validate: (value) => value.trim().length > 0 ? true : "Required"
|
|
523
|
+
},
|
|
524
|
+
cancelPrompts2
|
|
525
|
+
);
|
|
526
|
+
return String(response2.value).trim();
|
|
527
|
+
}
|
|
528
|
+
const response = await prompts2(
|
|
529
|
+
{
|
|
530
|
+
type: "select",
|
|
531
|
+
name: "value",
|
|
532
|
+
message: label,
|
|
533
|
+
choices: allowed.map((value) => ({ title: value, value })),
|
|
534
|
+
hint: "\u2191/\u2193 to move, Enter to select"
|
|
535
|
+
},
|
|
536
|
+
cancelPrompts2
|
|
537
|
+
);
|
|
538
|
+
return String(response.value);
|
|
539
|
+
}
|
|
540
|
+
async function promptForToken(token, types, scopes) {
|
|
541
|
+
if (token === "type") {
|
|
542
|
+
return chooseFromConfigList("Type", types);
|
|
543
|
+
}
|
|
544
|
+
if (token === "scope") {
|
|
545
|
+
return chooseFromConfigList("Scope", scopes);
|
|
546
|
+
}
|
|
547
|
+
const response = await prompts2(
|
|
548
|
+
{
|
|
549
|
+
type: "text",
|
|
550
|
+
name: "value",
|
|
551
|
+
message: "Message",
|
|
552
|
+
validate: (value) => value.trim().length > 0 ? true : "Message cannot be empty"
|
|
553
|
+
},
|
|
554
|
+
cancelPrompts2
|
|
555
|
+
);
|
|
556
|
+
return String(response.value).trim();
|
|
557
|
+
}
|
|
558
|
+
function assertGitRepo() {
|
|
559
|
+
try {
|
|
560
|
+
const r = spawnSync("git", ["rev-parse", "--git-dir"], {
|
|
561
|
+
encoding: "utf8",
|
|
562
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
563
|
+
});
|
|
564
|
+
if (r.status !== 0) {
|
|
565
|
+
throw new BshError(404, "Not a Git repository.");
|
|
566
|
+
}
|
|
567
|
+
} catch (e) {
|
|
568
|
+
if (e instanceof BshError) throw e;
|
|
569
|
+
throw new BshError(404, "Not a Git repository.");
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
async function run(options = {}) {
|
|
573
|
+
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
574
|
+
process.exitCode = 1;
|
|
575
|
+
logger.error("This command requires an interactive terminal.");
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
const messageConfig = getConfig().commit.message;
|
|
579
|
+
const { format, types, scopes } = messageConfig;
|
|
580
|
+
const order = formatTokenOrder(format);
|
|
581
|
+
if (order.length === 0) {
|
|
582
|
+
process.exitCode = 1;
|
|
583
|
+
logger.error(
|
|
584
|
+
`Commit message format has no placeholders. Add {type}, {scope}, and/or {message} in config. Current format: "${format}"`
|
|
585
|
+
);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
const usage = formatTokenUsage(format);
|
|
589
|
+
logger.info("Commit message format (from config):");
|
|
590
|
+
logger.info(` ${format}`);
|
|
591
|
+
logger.info(
|
|
592
|
+
` Uses: type ${usage.type ? "yes" : "no"}, scope ${usage.scope ? "yes" : "no"}, message ${usage.message ? "yes" : "no"}`
|
|
593
|
+
);
|
|
594
|
+
const parts = {};
|
|
595
|
+
for (const token of order) {
|
|
596
|
+
parts[token] = await promptForToken(token, types, scopes);
|
|
597
|
+
}
|
|
598
|
+
const header = buildMessageFromParts(format, parts);
|
|
599
|
+
if (options.dryRun) {
|
|
600
|
+
logger.info(header);
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
try {
|
|
604
|
+
assertGitRepo();
|
|
605
|
+
} catch (e) {
|
|
606
|
+
process.exitCode = 1;
|
|
607
|
+
if (e instanceof BshError) {
|
|
608
|
+
logger.error(e.message);
|
|
609
|
+
}
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
logger.info("");
|
|
613
|
+
logger.info("Commit message preview:");
|
|
614
|
+
logger.info(` ${header}`);
|
|
615
|
+
logger.info("");
|
|
616
|
+
const confirmResponse = await prompts2(
|
|
617
|
+
{
|
|
618
|
+
type: "confirm",
|
|
619
|
+
name: "proceed",
|
|
620
|
+
message: "Run git commit with this message?",
|
|
621
|
+
initial: true
|
|
622
|
+
},
|
|
623
|
+
cancelPrompts2
|
|
624
|
+
);
|
|
625
|
+
if (!confirmResponse.proceed) {
|
|
626
|
+
logger.info("Commit cancelled.");
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
const gitArgs = ["commit", "-m", header];
|
|
630
|
+
if (options.skipVerify) {
|
|
631
|
+
gitArgs.push("--no-verify");
|
|
632
|
+
}
|
|
633
|
+
const result = spawnSync("git", gitArgs, { stdio: "inherit" });
|
|
634
|
+
if (result.status !== 0 && result.status !== null) {
|
|
635
|
+
process.exitCode = result.status;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// src/commands/commit/cmds/msg/cmds/prompt/cmd.ts
|
|
640
|
+
var cmd_default4 = {
|
|
641
|
+
name: "prompt",
|
|
642
|
+
aliases: ["p"],
|
|
643
|
+
description: "Interactively choose type, scope, and message per your config format, then run git commit",
|
|
644
|
+
summary: "Prompt using configured format and types/scopes, then commit",
|
|
645
|
+
options: [
|
|
646
|
+
{
|
|
647
|
+
flags: "--dry-run",
|
|
648
|
+
description: "Print the composed message without running git commit",
|
|
649
|
+
defaultValue: false
|
|
650
|
+
},
|
|
651
|
+
{
|
|
652
|
+
flags: "--skip-verify",
|
|
653
|
+
description: "Run git commit with --no-verify (skip hooks)",
|
|
654
|
+
defaultValue: false
|
|
655
|
+
}
|
|
656
|
+
],
|
|
657
|
+
action: (options) => {
|
|
658
|
+
void run(options).catch((e) => {
|
|
659
|
+
logger.error(e instanceof Error ? e.message : String(e));
|
|
660
|
+
process.exitCode = 1;
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
};
|
|
664
|
+
var impl_default2 = (options) => {
|
|
665
|
+
const force = options.force === true;
|
|
666
|
+
const hooksDir = gitHooksDir();
|
|
667
|
+
const commitMsgPath = `${hooksDir}/${consts2.commit.commitMsgHook}`;
|
|
668
|
+
if (!existsSync(commitMsgPath)) {
|
|
669
|
+
logger.info(`No ${consts2.commit.commitMsgHook} hook found at ${commitMsgPath}`);
|
|
670
|
+
return;
|
|
671
|
+
}
|
|
672
|
+
if (!force) {
|
|
673
|
+
let content = "";
|
|
674
|
+
try {
|
|
675
|
+
content = readFileSync(commitMsgPath, "utf8");
|
|
676
|
+
} catch (err) {
|
|
677
|
+
const code = err && typeof err === "object" && "code" in err && typeof err.code === "string" ? err.code : "";
|
|
678
|
+
logger.error(`Could not read ${commitMsgPath}${code ? ` (${code})` : ""}.`);
|
|
679
|
+
process.exitCode = 1;
|
|
680
|
+
return;
|
|
681
|
+
}
|
|
682
|
+
if (!content.includes(messageFormatScript)) {
|
|
683
|
+
logger.error(
|
|
684
|
+
`${consts2.commit.commitMsgHook} at ${commitMsgPath} was not installed by this tool. Use --force to remove it.`
|
|
685
|
+
);
|
|
686
|
+
process.exitCode = 1;
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
unlinkSync(commitMsgPath);
|
|
691
|
+
logger.info(`Removed ${commitMsgPath}`);
|
|
692
|
+
};
|
|
693
|
+
|
|
694
|
+
// src/commands/commit/cmds/msg/cmds/uninstall/cmd.ts
|
|
695
|
+
var cmd_default5 = {
|
|
696
|
+
name: "uninstall",
|
|
697
|
+
aliases: ["ui"],
|
|
698
|
+
description: "Remove the commit-msg hook installed by install",
|
|
699
|
+
options: [
|
|
700
|
+
{
|
|
701
|
+
flags: "-f, --force",
|
|
702
|
+
description: "Remove the hook even if it was not installed by this tool",
|
|
703
|
+
defaultValue: false
|
|
704
|
+
}
|
|
705
|
+
],
|
|
706
|
+
action: (options) => impl_default2(options)
|
|
707
|
+
};
|
|
708
|
+
function escapeRegex(value) {
|
|
709
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
710
|
+
}
|
|
711
|
+
function tokenPattern(token) {
|
|
712
|
+
if (token === "type") return "([^\\s(){}:]+)";
|
|
713
|
+
if (token === "scope") return "([^()\\r\\n]+)";
|
|
714
|
+
return "(.+)";
|
|
715
|
+
}
|
|
716
|
+
function compileFormat(format) {
|
|
717
|
+
const tokenRegex = /\{(type|scope|message)\}/g;
|
|
718
|
+
const tokens = [];
|
|
719
|
+
let pattern = "^";
|
|
720
|
+
let lastIdx = 0;
|
|
721
|
+
for (let match = tokenRegex.exec(format); match !== null; match = tokenRegex.exec(format)) {
|
|
722
|
+
const [fullMatch, token] = match;
|
|
723
|
+
const start = match.index;
|
|
724
|
+
pattern += escapeRegex(format.slice(lastIdx, start));
|
|
725
|
+
pattern += tokenPattern(token);
|
|
726
|
+
tokens.push(token);
|
|
727
|
+
lastIdx = start + fullMatch.length;
|
|
728
|
+
}
|
|
729
|
+
pattern += escapeRegex(format.slice(lastIdx));
|
|
730
|
+
pattern += "$";
|
|
731
|
+
return { regex: new RegExp(pattern), tokens };
|
|
732
|
+
}
|
|
733
|
+
function readCommitMessage(input) {
|
|
734
|
+
if (!input) return "";
|
|
735
|
+
if (!existsSync(input)) return input;
|
|
736
|
+
return readFileSync(input, "utf8");
|
|
737
|
+
}
|
|
738
|
+
function headerFromMessage(message) {
|
|
739
|
+
const lines = message.split(/\r?\n/);
|
|
740
|
+
for (const line of lines) {
|
|
741
|
+
const trimmed = line.trim();
|
|
742
|
+
if (!trimmed || trimmed.startsWith("#")) continue;
|
|
743
|
+
return line;
|
|
744
|
+
}
|
|
745
|
+
return "";
|
|
746
|
+
}
|
|
747
|
+
var impl_default3 = (input) => {
|
|
748
|
+
const messageConfig = getConfig().commit.message;
|
|
749
|
+
const message = readCommitMessage(input);
|
|
750
|
+
const header = headerFromMessage(message);
|
|
751
|
+
if (!header.trim()) {
|
|
752
|
+
process.exitCode = 1;
|
|
753
|
+
logger.error("Commit message is empty.");
|
|
754
|
+
return;
|
|
755
|
+
}
|
|
756
|
+
const { regex, tokens } = compileFormat(messageConfig.format);
|
|
757
|
+
const match = regex.exec(header);
|
|
758
|
+
if (!match) {
|
|
759
|
+
process.exitCode = 1;
|
|
760
|
+
logger.error(`Invalid commit message format. Expected: "${messageConfig.format}"`);
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
const extracted = {};
|
|
764
|
+
for (let i = 0; i < tokens.length; i += 1) {
|
|
765
|
+
extracted[tokens[i]] = match[i + 1];
|
|
766
|
+
}
|
|
767
|
+
const type = extracted.type?.trim();
|
|
768
|
+
const scope = extracted.scope?.trim();
|
|
769
|
+
const body = extracted.message?.trim();
|
|
770
|
+
if (type && messageConfig.types.length > 0 && !messageConfig.types.includes(type)) {
|
|
771
|
+
process.exitCode = 1;
|
|
772
|
+
logger.error(`Invalid commit type "${type}". Allowed: ${messageConfig.types.join(", ")}`);
|
|
773
|
+
return;
|
|
774
|
+
}
|
|
775
|
+
if (scope && messageConfig.scopes.length > 0 && !messageConfig.scopes.includes(scope)) {
|
|
776
|
+
process.exitCode = 1;
|
|
777
|
+
logger.error(`Invalid commit scope "${scope}". Allowed: ${messageConfig.scopes.join(", ")}`);
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
if (tokens.includes("message") && (!body || body.length === 0)) {
|
|
781
|
+
process.exitCode = 1;
|
|
782
|
+
logger.error("Commit message body cannot be empty.");
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
|
|
787
|
+
// src/commands/commit/cmds/msg/cmds/validate/cmd.ts
|
|
788
|
+
var cmd_default6 = {
|
|
789
|
+
name: "validate",
|
|
790
|
+
aliases: ["v"],
|
|
791
|
+
description: "Validate a commit message",
|
|
792
|
+
argumentSyntax: "[message-or-file]",
|
|
793
|
+
action: (_options, input) => impl_default3(input)
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
// src/commands/commit/cmds/msg/cmd.ts
|
|
797
|
+
var cmd_default7 = {
|
|
798
|
+
name: "msg",
|
|
799
|
+
description: "Structured commit messages: `<type> (scope): msg`",
|
|
800
|
+
summary: "Validate commits and manage the commit-msg hook",
|
|
801
|
+
subcommands: [
|
|
802
|
+
cmd_default3,
|
|
803
|
+
cmd_default5,
|
|
804
|
+
cmd_default6,
|
|
805
|
+
cmd_default4
|
|
806
|
+
]
|
|
807
|
+
};
|
|
808
|
+
|
|
809
|
+
// src/commands/commit/cmd.ts
|
|
810
|
+
var cmd_default8 = {
|
|
811
|
+
name: "commit",
|
|
812
|
+
aliases: ["c"],
|
|
813
|
+
description: "Structured commit messages: `<type> (scope): msg`",
|
|
814
|
+
summary: "Validate commits and manage the commit-msg hook",
|
|
815
|
+
subcommands: [
|
|
816
|
+
cmd_default7
|
|
817
|
+
]
|
|
818
|
+
};
|
|
819
|
+
|
|
820
|
+
// src/commands/index.ts
|
|
821
|
+
var commands = [
|
|
822
|
+
cmd_default,
|
|
823
|
+
cmd_default2,
|
|
824
|
+
cmd_default8
|
|
825
|
+
];
|
|
826
|
+
var commands_default = commands;
|
|
827
|
+
var nameAndArgs = (name, argumentSyntax) => {
|
|
828
|
+
const extra = argumentSyntax?.trim();
|
|
829
|
+
return extra ? `${name} ${extra}` : name;
|
|
830
|
+
};
|
|
831
|
+
var applyPositional = (cmd, positional) => {
|
|
832
|
+
if (!positional?.length) return;
|
|
833
|
+
for (const p of positional) {
|
|
834
|
+
if (p.description !== void 0 && p.defaultValue !== void 0) {
|
|
835
|
+
cmd.argument(p.spec, p.description, p.defaultValue);
|
|
836
|
+
} else if (p.description !== void 0) {
|
|
837
|
+
cmd.argument(p.spec, p.description);
|
|
838
|
+
} else if (p.defaultValue !== void 0) {
|
|
839
|
+
cmd.argument(p.spec, "", p.defaultValue);
|
|
840
|
+
} else {
|
|
841
|
+
cmd.argument(p.spec);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
};
|
|
845
|
+
var applyOption = (cmd, opt) => {
|
|
846
|
+
const needsCustomOption = (opt.choices?.length ?? 0) > 0 || opt.env != null || opt.hideHelp === true || opt.helpGroup != null || opt.preset !== void 0;
|
|
847
|
+
if (needsCustomOption) {
|
|
848
|
+
const o = new Option(opt.flags, opt.description);
|
|
849
|
+
if (opt.defaultValue !== void 0) {
|
|
850
|
+
o.default(opt.defaultValue);
|
|
851
|
+
}
|
|
852
|
+
if (opt.choices?.length) {
|
|
853
|
+
o.choices(opt.choices);
|
|
854
|
+
}
|
|
855
|
+
if (opt.env) {
|
|
856
|
+
o.env(opt.env);
|
|
857
|
+
}
|
|
858
|
+
if (opt.hideHelp) {
|
|
859
|
+
o.hideHelp(true);
|
|
860
|
+
}
|
|
861
|
+
if (opt.helpGroup) {
|
|
862
|
+
o.helpGroup(opt.helpGroup);
|
|
863
|
+
}
|
|
864
|
+
if (opt.preset !== void 0) {
|
|
865
|
+
o.preset(opt.preset);
|
|
866
|
+
}
|
|
867
|
+
if (opt.mandatory) {
|
|
868
|
+
o.makeOptionMandatory(true);
|
|
869
|
+
}
|
|
870
|
+
cmd.addOption(o);
|
|
871
|
+
return;
|
|
872
|
+
}
|
|
873
|
+
if (opt.mandatory) {
|
|
874
|
+
if (opt.defaultValue !== void 0) {
|
|
875
|
+
cmd.requiredOption(opt.flags, opt.description, opt.defaultValue);
|
|
876
|
+
} else {
|
|
877
|
+
cmd.requiredOption(opt.flags, opt.description);
|
|
878
|
+
}
|
|
879
|
+
return;
|
|
880
|
+
}
|
|
881
|
+
if (opt.defaultValue !== void 0) {
|
|
882
|
+
cmd.option(opt.flags, opt.description, opt.defaultValue);
|
|
883
|
+
} else {
|
|
884
|
+
cmd.option(opt.flags, opt.description);
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
var applyOptions = (cmd, options) => {
|
|
888
|
+
if (!options) return;
|
|
889
|
+
for (const opt of options) {
|
|
890
|
+
applyOption(cmd, opt);
|
|
891
|
+
}
|
|
892
|
+
};
|
|
893
|
+
var applyCommandMeta = (cmd, def) => {
|
|
894
|
+
if (def.usage != null) cmd.usage(def.usage);
|
|
895
|
+
if (def.helpGroup != null) cmd.helpGroup(def.helpGroup);
|
|
896
|
+
if (def.allowUnknownOptions === true) cmd.allowUnknownOption(true);
|
|
897
|
+
if (def.allowExcessArguments !== void 0) cmd.allowExcessArguments(def.allowExcessArguments);
|
|
898
|
+
};
|
|
899
|
+
|
|
900
|
+
// src/lib/cli/index.ts
|
|
901
|
+
var cli_default = (program2, commands2) => {
|
|
902
|
+
const registerCommand = (parent, cmd) => {
|
|
903
|
+
const sub = parent.command(nameAndArgs(cmd.name, cmd.argumentSyntax), {
|
|
904
|
+
hidden: cmd.hidden,
|
|
905
|
+
isDefault: cmd.isDefault
|
|
906
|
+
}).description(cmd.description).summary(cmd.summary ?? "");
|
|
907
|
+
for (const a of cmd.aliases ?? []) sub.alias(a);
|
|
908
|
+
if (cmd.positional?.length) applyPositional(sub, cmd.positional);
|
|
909
|
+
else if (cmd.argumentsPattern) sub.arguments(cmd.argumentsPattern);
|
|
910
|
+
applyCommandMeta(sub, cmd);
|
|
911
|
+
applyOptions(sub, cmd.options);
|
|
912
|
+
if (cmd.subcommands?.length) {
|
|
913
|
+
for (const nested of cmd.subcommands) {
|
|
914
|
+
registerCommand(sub, nested);
|
|
915
|
+
}
|
|
916
|
+
return;
|
|
917
|
+
}
|
|
918
|
+
if (cmd.action) {
|
|
919
|
+
sub.action((...actionArgs) => {
|
|
920
|
+
const options = actionArgs[actionArgs.length - 2];
|
|
921
|
+
const positionals = actionArgs.slice(0, -2);
|
|
922
|
+
const action = cmd.action;
|
|
923
|
+
action(options, ...positionals);
|
|
924
|
+
});
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
throw new BshError(
|
|
928
|
+
500,
|
|
929
|
+
`Command "${cmd.name}" must define action or subcommands`
|
|
930
|
+
);
|
|
931
|
+
};
|
|
932
|
+
for (const cmd of commands2) {
|
|
933
|
+
registerCommand(program2, cmd);
|
|
934
|
+
}
|
|
935
|
+
};
|
|
936
|
+
|
|
937
|
+
// src/cli.ts
|
|
938
|
+
var __filename$1 = fileURLToPath(import.meta.url);
|
|
939
|
+
var __dirname$1 = dirname(__filename$1);
|
|
940
|
+
var packageJson = JSON.parse(
|
|
941
|
+
readFileSync(join(__dirname$1, "../package.json"), "utf-8")
|
|
942
|
+
);
|
|
943
|
+
var program = new Command();
|
|
944
|
+
program.name(`npx ${packageJson.name}`).description("Git workflows with a simpler interface").version(packageJson.version);
|
|
945
|
+
(async () => {
|
|
946
|
+
await loadConfig();
|
|
947
|
+
cli_default(program, commands_default);
|
|
948
|
+
await middleware(program);
|
|
949
|
+
})();
|
|
950
|
+
//# sourceMappingURL=cli.js.map
|
|
951
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/config/consts.ts","../src/config/utils.ts","../src/config/index.ts","../src/lib/errors/index.ts","../src/lib/logger/index.ts","../src/lib/middleware/global-error.ts","../src/lib/middleware/index.ts","../src/commands/init/impl.ts","../src/commands/init/cmd.ts","../src/commands/rm/impl.ts","../src/commands/rm/cmd.ts","../src/commands/consts.ts","../src/commands/commit/cmds/msg/cmds/install/utils.ts","../src/commands/commit/cmds/msg/cmds/install/impl.ts","../src/commands/commit/cmds/msg/cmds/install/cmd.ts","../src/commands/commit/cmds/msg/cmds/prompt/format.ts","../src/commands/commit/cmds/msg/cmds/prompt/impl.ts","../src/commands/commit/cmds/msg/cmds/prompt/cmd.ts","../src/commands/commit/cmds/msg/cmds/uninstall/impl.ts","../src/commands/commit/cmds/msg/cmds/uninstall/cmd.ts","../src/commands/commit/cmds/msg/cmds/validate/impl.ts","../src/commands/commit/cmds/msg/cmds/validate/cmd.ts","../src/commands/commit/cmds/msg/cmd.ts","../src/commands/commit/cmd.ts","../src/commands/index.ts","../src/lib/cli/utils.ts","../src/lib/cli/index.ts","../src/cli.ts"],"names":["resolve","resolvePath","consoleDest","fileDest","dirname","program","getNodeErrno","cmd_default","consts","prompts","cancelPrompts","response","impl_default","existsSync","readFileSync","unlinkSync","commands","__filename","__dirname","Command"],"mappings":"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","file":"cli.js","sourcesContent":["export const consts = {\n configRelativePath: '.github/bsh.json' as const,\n} as const;\n","import { readFile } from 'fs/promises';\nimport { resolve } from 'path';\nimport { consts } from './consts';\nimport type { Config } from './type';\n\nexport const defaultConfig: Config = {\n commit: {\n message: {\n format: '{type} ({scope}): {message}',\n types: ['feat', 'fix', 'docs', 'style', 'refactor', 'perf', 'test', 'build', 'ci', 'chore', 'revert'],\n scopes: [],\n },\n },\n logger: {\n level: 'info',\n file: {\n enable: false,\n path: 'logs/bsh-git.log',\n },\n },\n};\n\nexport async function loadFromFile(): Promise<Config> {\n const path = resolve(process.cwd(), consts.configRelativePath);\n try {\n const text = await readFile(path, 'utf8');\n try {\n return mergeConfig(JSON.parse(text) as unknown);\n } catch (err) {\n if (err instanceof SyntaxError) return structuredClone(defaultConfig);\n throw err;\n }\n } catch (err) {\n if (getNodeErrno(err) === 'ENOENT') return structuredClone(defaultConfig);\n throw err;\n }\n}\n\nfunction deepMerge(target: Config, source: unknown): Config {\n if (typeof source !== 'object' || source === null) return target;\n if (typeof target !== 'object' || target === null) return target;\n\n const result: any = Array.isArray(target) ? [...target] : { ...target };\n\n for (const key of Object.keys(target)) {\n if (\n Object.prototype.hasOwnProperty.call(source, key) &&\n typeof key === 'string'\n ) {\n const sourceVal = (source as Record<string, unknown>)[key];\n const targetVal = (target as any)[key];\n\n if (Array.isArray(targetVal) && Array.isArray(sourceVal)) {\n result[key] = [...sourceVal];\n } else if (\n typeof targetVal === 'object' && targetVal !== null &&\n typeof sourceVal === 'object' && sourceVal !== null\n ) {\n result[key] = deepMerge(targetVal, sourceVal);\n } else {\n if (typeof sourceVal === typeof targetVal || Array.isArray(sourceVal)) {\n result[key] = sourceVal;\n } else {\n result[key] = sourceVal !== undefined && sourceVal !== null ? sourceVal : targetVal;\n }\n }\n }\n }\n\n return result;\n}\n\nexport function mergeConfig(raw: unknown): Config {\n if (!raw || typeof raw !== 'object') {\n return structuredClone(defaultConfig);\n }\n return deepMerge(defaultConfig, raw);\n}\n\nexport function getNodeErrno(err: unknown): NodeJS.ErrnoException['code'] {\n if (!err || typeof err !== 'object' || !('code' in err)) return undefined;\n const code = (err as NodeJS.ErrnoException).code;\n return code;\n}\n","import type { Config } from './type'; \nimport { mkdir, writeFile } from 'fs/promises';\nimport { dirname, resolve } from 'path';\nimport { consts } from './consts';\nimport { defaultConfig, getNodeErrno, loadFromFile } from './utils';\n\nlet instance: Config | undefined;\nlet initPromise: Promise<Config> | undefined;\n\nexport async function loadConfig(): Promise<Config> {\n if (instance) return instance;\n if (!initPromise) {\n initPromise = loadFromFile().then((c) => {\n instance = c;\n return c;\n });\n }\n return initPromise;\n}\n\nexport function getConfig(): Config {\n if (!instance) instance = defaultConfig;\n return instance;\n}\n\nfunction configPathFromCwd(): string {\n return resolve(process.cwd(), consts.configRelativePath);\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction mergeValue(base: unknown, patch: unknown): unknown {\n if (Array.isArray(base) && Array.isArray(patch)) return [...patch];\n if (isRecord(base) && isRecord(patch)) {\n const result: Record<string, unknown> = { ...base };\n for (const key of Object.keys(base)) {\n if (!Object.prototype.hasOwnProperty.call(patch, key)) continue;\n result[key] = mergeValue(base[key], patch[key]);\n }\n return result;\n }\n return patch === undefined ? base : patch;\n}\n\nfunction mergeIntoConfig(base: Config, patch: unknown): Config {\n return mergeValue(base, patch) as Config;\n}\n\nasync function writeConfigFile(config: Config): Promise<void> {\n const configPath = configPathFromCwd();\n await mkdir(dirname(configPath), { recursive: true });\n await writeFile(configPath, JSON.stringify(config, null, 2), 'utf8');\n}\n\nexport async function createConfigFileIfNotExists(): Promise<Config> {\n const configPath = configPathFromCwd();\n try {\n await writeFile(configPath, '', { flag: 'wx' });\n } catch (err) {\n const code = getNodeErrno(err);\n if (code !== 'ENOENT' && code !== 'EEXIST') throw err;\n if (code === 'ENOENT') {\n await mkdir(dirname(configPath), { recursive: true });\n await writeFile(configPath, '', { flag: 'wx' });\n }\n }\n\n const config = await loadFromFile();\n await writeConfigFile(config);\n return config;\n}\n\nexport async function loadConfigFromFile(): Promise<Config> {\n const config = await loadFromFile();\n instance = config;\n initPromise = Promise.resolve(config);\n return config;\n}\n\nexport async function overwriteConfigFile(config: Config): Promise<Config> {\n await writeConfigFile(config);\n instance = config;\n initPromise = Promise.resolve(config);\n return config;\n}\n\nexport async function mergeConfigFile(nextData: unknown): Promise<Config> {\n const current = await loadFromFile();\n const merged = mergeIntoConfig(current, nextData);\n await writeConfigFile(merged);\n instance = merged;\n initPromise = Promise.resolve(merged);\n return merged;\n}\n\nexport { Config, defaultConfig };\n","export class BshError extends Error {\n readonly code: number;\n readonly context?: Record<string, unknown>;\n\n constructor(\n code: number,\n message: string,\n options?: {\n cause?: unknown;\n context?: Record<string, unknown>;\n },\n ) {\n super(message);\n this.name = 'BshError';\n this.code = code;\n this.context = options?.context;\n if (options?.cause !== undefined) {\n (this as Error & { cause?: unknown }).cause = options.cause;\n }\n Object.setPrototypeOf(this, new.target.prototype);\n }\n}\n","import { mkdirSync } from 'fs';\nimport { dirname, resolve as resolvePath } from 'path';\n\nimport pino, { type Logger, type LoggerOptions } from 'pino';\nimport pinoPretty from 'pino-pretty';\n\nimport { getConfig } from '@config';\n\nimport { BshError } from '@lib/errors';\n\nconst loggerConfig = () => getConfig().logger\nconst level = (): LoggerOptions['level'] => loggerConfig().level\n\nfunction resolveLogFilePath(): string | undefined {\n const { file } = loggerConfig();\n if (!file.enable || !file.path.trim()) return undefined;\n return resolvePath(file.path.trim());\n}\n\nconst PRETTY_BASE = {\n translateTime: \"SYS:yyyy-mm-dd'T'HH:MM:ss.l\",\n ignore: 'pid,hostname',\n singleLine: true,\n messageFormat: '{msg}',\n} as const;\n\nfunction createPrettyDestination(\n destination: string | number,\n opts: { colorize: boolean; mkdir?: boolean },\n) {\n return pinoPretty({\n ...PRETTY_BASE,\n colorize: opts.colorize,\n destination,\n sync: true,\n ...(opts.mkdir ? { mkdir: true as const } : {}),\n });\n}\n\nfunction createDestination() {\n const logFile = resolveLogFilePath();\n\n if (process.stdout.isTTY) {\n const consoleDest = createPrettyDestination(1, { colorize: true });\n if (!logFile) return consoleDest;\n\n const fileDest = createPrettyDestination(logFile, {\n colorize: false,\n mkdir: true,\n });\n return pino.multistream([\n { level: level(), stream: consoleDest },\n { level: level(), stream: fileDest },\n ]);\n }\n\n const consoleDest = pino.destination({ dest: 1, sync: true, minLength: 0 });\n if (!logFile) return consoleDest;\n\n mkdirSync(dirname(logFile), { recursive: true });\n const fileDest = pino.destination({\n dest: logFile,\n sync: true,\n mkdir: true,\n minLength: 0,\n });\n return pino.multistream([\n { level: level(), stream: consoleDest },\n { level: level(), stream: fileDest },\n ]);\n}\n\nfunction serializeErr(err: Error): Record<string, unknown> {\n const base = pino.stdSerializers.err(err) as Record<string, unknown>;\n if (err instanceof BshError) {\n return {\n ...base,\n code: err.code,\n ...(err.context !== undefined && { context: err.context }),\n };\n }\n return base;\n}\n\nfunction buildBaseOptions(): LoggerOptions {\n return {\n level: level(),\n serializers: {\n err: serializeErr,\n },\n redact: {\n paths: [\n 'password',\n 'token',\n 'accessToken',\n 'refreshToken',\n 'authorization',\n 'cookie',\n 'cookies',\n 'set-cookie',\n '*.password',\n '*.token',\n '*.authorization',\n ],\n censor: '[redacted]',\n },\n };\n}\n\nlet rootLogger: Logger | undefined;\n\nfunction getRootLogger(): Logger {\n if (!rootLogger) {\n rootLogger = pino(buildBaseOptions(), createDestination());\n }\n return rootLogger;\n}\n\nexport function Logger(name?: string): Logger {\n const root = getRootLogger();\n return name ? root.child({ name }) : root;\n}\n\nexport const logger = new Proxy({} as Logger, {\n get(_target, prop) {\n const inst = getRootLogger();\n const value = (inst as unknown as Record<string | symbol, unknown>)[prop];\n return typeof value === 'function' ? value.bind(inst) : value;\n },\n});\n","import { CommanderError, type Command } from 'commander';\n\nimport { BshError } from '@lib/errors';\nimport { logger } from '@lib/logger';\n\n\nfunction logMessageFor(err: unknown): string {\n if (err instanceof BshError) return `[${err.code}] ${err.message}`;\n if (err instanceof Error) return err.message;\n return 'command failed';\n}\n\nexport async function errorHandlingMiddleware(\n program: Command,\n argv: string[] = process.argv,\n): Promise<void> {\n program.exitOverride();\n try {\n await program.parseAsync(argv);\n } catch (err) {\n if (err instanceof CommanderError && (\n err.exitCode === 0 ||\n err.code === 'commander.help'\n )) {\n process.exit(0);\n return;\n }\n if (err instanceof BshError) {\n logger.error(logMessageFor(err));\n process.exit(err.code);\n return;\n }\n logger.error({ err }, logMessageFor(err));\n process.exit(err instanceof CommanderError ? err.exitCode : 1);\n }\n}\n","import { Command } from 'commander';\nimport { errorHandlingMiddleware } from './global-error';\n\nexport default function middleware(program: Command): Promise<void> {\n return errorHandlingMiddleware(program);\n}\n","import { createConfigFileIfNotExists } from '@config';\nimport { logger } from '@lib/logger';\n\nimport { access } from 'fs/promises';\nimport { resolve } from 'path';\nimport { consts } from '@src/config/consts';\nimport { getNodeErrno } from '@src/config/utils';\n\nasync function configExists(): Promise<boolean> {\n const configPath = resolve(process.cwd(), consts.configRelativePath);\n try {\n await access(configPath);\n return true;\n } catch (err) {\n if (getNodeErrno(err) === 'ENOENT') return false;\n throw err;\n }\n}\n\nexport async function runInit(): Promise<void> {\n const existed = await configExists();\n await createConfigFileIfNotExists();\n if (!existed) logger.info('Config file created');\n}\n","import type { CommandDefinition } from '@definition';\nimport { runInit } from './impl.js';\n\nexport default {\n name: 'init',\n description: 'Initialize the environment',\n summary: 'Initialize the environment',\n action: async (_options) => {\n await runInit();\n },\n} satisfies CommandDefinition;\n","import { readdirSync, rmdirSync, unlinkSync } from 'fs';\nimport { dirname, resolve } from 'path';\nimport { consts } from '@src/config/consts';\nimport { logger } from '@lib/logger';\n\nexport function runRm(): void {\n rmConfigFile();\n}\n\nfunction rmConfigFile(): void {\n const configPath = resolve(process.cwd(), consts.configRelativePath);\n const configDirPath = dirname(configPath);\n\n try {\n unlinkSync(configPath);\n } catch (err) {\n if (getNodeErrno(err) !== 'ENOENT') throw err;\n return;\n }\n\n try {\n if (readdirSync(configDirPath).length === 0) {\n rmdirSync(configDirPath);\n }\n } catch (err) {\n if (\n getNodeErrno(err) !== 'ENOENT' &&\n getNodeErrno(err) !== 'ENOTEMPTY'\n ) {\n throw err;\n }\n }\n\n logger.info('Config file removed');\n}\n\nfunction getNodeErrno(err: unknown): NodeJS.ErrnoException['code'] {\n if (!err || typeof err !== 'object' || !('code' in err)) return undefined;\n return (err as NodeJS.ErrnoException).code;\n}\n","import type { CommandDefinition } from '@definition';\nimport { runRm } from './impl.js';\n\nexport default {\n name: 'rm',\n description: 'Remove CLI config from this project',\n summary: 'Undo init by removing project config',\n action: (_options) => {\n runRm();\n },\n} satisfies CommandDefinition;\n","export const consts = {\n commit: {\n commitMsgHook: 'commit-msg',\n },\n} as const;\n","import { execSync } from 'child_process';\nimport { chmodSync, existsSync, readFileSync, writeFileSync } from 'fs';\nimport prompts from 'prompts';\n\nimport { BshError } from '@lib/errors';\nimport { logger } from '@src/lib/logger';\nimport type { Config } from '@src/config/type';\n\nexport function gitHooksDir(): string {\n try {\n return execSync('git rev-parse --git-path hooks', {\n encoding: 'utf8',\n stdio: ['pipe', 'pipe', 'pipe'],\n }).trim();\n } catch (error) {\n console.error(error);\n throw new BshError(404, 'Not a Git repository (or hooks path unavailable).');\n }\n}\n\nexport const messageFormatScript = `#!/bin/sh\n# BSH Git — commit message format validator\nnpx @bshsolutions/git commit msg validate \"$1\"\n`;\n\nexport function canOverwriteHook(\n path: string,\n force: boolean,\n): boolean {\n if (!existsSync(path)) return true;\n if (force) return true;\n try {\n const content = readFileSync(path, 'utf8');\n if (!content.includes(messageFormatScript)) return true;\n } catch (e) {\n const code =\n e &&\n typeof e === 'object' &&\n 'code' in e &&\n typeof (e as { code: unknown }).code === 'string'\n ? (e as { code: string }).code\n : '';\n logger.error(`Could not read ${path}${code ? ` (${code})` : ''}.`);\n process.exitCode = 1;\n return false;\n }\n process.exitCode = 1;\n return false;\n}\n\nexport const writeHookFile = (path: string) => {\n writeFileSync(path, messageFormatScript, { encoding: 'utf8' });\n chmodSync(path, 0o755);\n};\n\nexport type MessageConfig = Config['commit']['message'];\n\nfunction toCsv(values: string[]): string {\n return values.join(', ');\n}\n\nfunction fromCsv(value: string): string[] {\n return value\n .split(',')\n .map((item) => item.trim())\n .filter(Boolean);\n}\n\nconst cancelPrompts = {\n onCancel: (): never => {\n process.exit(130);\n },\n};\n\nexport async function promptMessageConfig(defaults: MessageConfig): Promise<MessageConfig> {\n if (!process.stdin.isTTY || !process.stdout.isTTY) return defaults;\n\n logger.info('Configure commit message defaults. Press Enter to keep current values.');\n\n const formatResponse = await prompts(\n {\n type: 'text',\n name: 'format',\n message: 'Commit format',\n initial: defaults.format,\n },\n cancelPrompts,\n );\n\n const typesResponse = await prompts(\n {\n type: 'text',\n name: 'types',\n message: 'Commit types (comma-separated)',\n initial: toCsv(defaults.types),\n },\n cancelPrompts,\n );\n\n const scopesResponse = await prompts(\n {\n type: 'text',\n name: 'scopes',\n message: 'Commit scopes (comma-separated)',\n initial: toCsv(defaults.scopes),\n },\n cancelPrompts,\n );\n\n const format =\n String(formatResponse.format ?? '').trim() || defaults.format;\n const typesStr = String(typesResponse.types ?? '').trim();\n const scopesStr = String(scopesResponse.scopes ?? '').trim();\n\n return {\n format,\n types: typesStr === '' ? defaults.types : fromCsv(typesStr),\n scopes: scopesStr === '' ? defaults.scopes : fromCsv(scopesStr),\n };\n}","import { logger } from '@lib/logger';\nimport { getConfig, mergeConfigFile } from '@config';\n\nimport { consts } from '@consts';\nimport type { InstallOptions } from './types.js';\nimport { canOverwriteHook, gitHooksDir, promptMessageConfig, writeHookFile } from './utils.js';\n\nexport default async (options: InstallOptions) => {\n const force = options.force === true;\n const hooksDir = gitHooksDir();\n const commitMsgPath = `${hooksDir}/${consts.commit.commitMsgHook}`;\n\n if (!canOverwriteHook(commitMsgPath, force)) {\n process.exitCode = 1;\n logger.error(`${consts.commit.commitMsgHook} already exists at ${commitMsgPath}. Use --force to replace it.`);\n return;\n }\n\n const currentMessageConfig = getConfig().commit.message;\n const messageConfig = await promptMessageConfig(currentMessageConfig);\n\n await mergeConfigFile({\n commit: {\n message: messageConfig,\n },\n });\n\n writeHookFile(commitMsgPath);\n\n logger.info(`Installed ${commitMsgPath}`);\n};\n","import type { CommandDefinition } from '@definition';\n\nimport run from './impl.js';\nimport type { InstallOptions } from './types.js';\n\nexport default {\n name: 'install',\n aliases: ['i'],\n description: 'Write a commit-msg hook that enforces the message format',\n options: [\n {\n flags: '-f, --force',\n description: 'Replace an existing commit-msg hook',\n defaultValue: false,\n },\n ],\n action: (options) => run(options),\n} satisfies CommandDefinition<InstallOptions>;\n","export type FormatToken = 'type' | 'scope' | 'message';\n\nexport function formatTokenOrder(format: string): FormatToken[] {\n const re = /\\{(type|scope|message)\\}/g;\n const order: FormatToken[] = [];\n const seen = new Set<FormatToken>();\n let m: RegExpExecArray | null;\n while ((m = re.exec(format)) !== null) {\n const t = m[1] as FormatToken;\n if (!seen.has(t)) {\n seen.add(t);\n order.push(t);\n }\n }\n return order;\n}\n\nexport function formatTokenUsage(format: string): {\n type: boolean;\n scope: boolean;\n message: boolean;\n} {\n const tokens = formatTokenOrder(format);\n return {\n type: tokens.includes('type'),\n scope: tokens.includes('scope'),\n message: tokens.includes('message'),\n };\n}\n\nexport function buildMessageFromParts(\n format: string,\n parts: Partial<Record<FormatToken, string>>,\n): string {\n return format\n .replace(/\\{type\\}/g, parts.type ?? '')\n .replace(/\\{scope\\}/g, parts.scope ?? '')\n .replace(/\\{message\\}/g, parts.message ?? '');\n}\n","import { spawnSync } from 'child_process';\nimport prompts from 'prompts';\n\nimport { getConfig } from '@config';\nimport { BshError } from '@lib/errors';\nimport { logger } from '@lib/logger';\n\nimport {\n type FormatToken,\n buildMessageFromParts,\n formatTokenOrder,\n formatTokenUsage,\n} from './format.js';\n\ntype PromptOptions = {\n dryRun?: boolean;\n skipVerify?: boolean;\n};\n\nconst cancelPrompts = {\n onCancel: (): never => {\n process.exit(130);\n },\n};\n\nasync function chooseFromConfigList(label: string, allowed: string[]): Promise<string> {\n if (allowed.length === 0) {\n const response = await prompts(\n {\n type: 'text',\n name: 'value',\n message: `${label} (not listed in config — type a value)`,\n validate: (value: string) => (value.trim().length > 0 ? true : 'Required'),\n },\n cancelPrompts,\n );\n return String(response.value).trim();\n }\n\n const response = await prompts(\n {\n type: 'select',\n name: 'value',\n message: label,\n choices: allowed.map((value) => ({ title: value, value })),\n hint: '↑/↓ to move, Enter to select',\n },\n cancelPrompts,\n );\n\n return String(response.value);\n}\n\nasync function promptForToken(\n token: FormatToken,\n types: string[],\n scopes: string[],\n): Promise<string> {\n if (token === 'type') {\n return chooseFromConfigList('Type', types);\n }\n if (token === 'scope') {\n return chooseFromConfigList('Scope', scopes);\n }\n\n const response = await prompts(\n {\n type: 'text',\n name: 'value',\n message: 'Message',\n validate: (value: string) => (value.trim().length > 0 ? true : 'Message cannot be empty'),\n },\n cancelPrompts,\n );\n\n return String(response.value).trim();\n}\n\nfunction assertGitRepo(): void {\n try {\n const r = spawnSync('git', ['rev-parse', '--git-dir'], {\n encoding: 'utf8',\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n if (r.status !== 0) {\n throw new BshError(404, 'Not a Git repository.');\n }\n } catch (e) {\n if (e instanceof BshError) throw e;\n throw new BshError(404, 'Not a Git repository.');\n }\n}\n\nexport default async function run(options: PromptOptions = {}): Promise<void> {\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n process.exitCode = 1;\n logger.error('This command requires an interactive terminal.');\n return;\n }\n\n const messageConfig = getConfig().commit.message;\n const { format, types, scopes } = messageConfig;\n const order = formatTokenOrder(format);\n\n if (order.length === 0) {\n process.exitCode = 1;\n logger.error(\n `Commit message format has no placeholders. Add {type}, {scope}, and/or {message} in config. Current format: \"${format}\"`,\n );\n return;\n }\n\n const usage = formatTokenUsage(format);\n logger.info('Commit message format (from config):');\n logger.info(` ${format}`);\n logger.info(\n ` Uses: type ${usage.type ? 'yes' : 'no'}, scope ${usage.scope ? 'yes' : 'no'}, message ${usage.message ? 'yes' : 'no'}`,\n );\n\n const parts: Partial<Record<FormatToken, string>> = {};\n for (const token of order) {\n parts[token] = await promptForToken(token, types, scopes);\n }\n\n const header = buildMessageFromParts(format, parts);\n\n if (options.dryRun) {\n logger.info(header);\n return;\n }\n\n try {\n assertGitRepo();\n } catch (e) {\n process.exitCode = 1;\n if (e instanceof BshError) {\n logger.error(e.message);\n }\n return;\n }\n\n logger.info('');\n logger.info('Commit message preview:');\n logger.info(` ${header}`);\n logger.info('');\n\n const confirmResponse = await prompts(\n {\n type: 'confirm',\n name: 'proceed',\n message: 'Run git commit with this message?',\n initial: true,\n },\n cancelPrompts,\n );\n\n if (!confirmResponse.proceed) {\n logger.info('Commit cancelled.');\n return;\n }\n\n const gitArgs = ['commit', '-m', header];\n if (options.skipVerify) {\n gitArgs.push('--no-verify');\n }\n\n const result = spawnSync('git', gitArgs, { stdio: 'inherit' });\n if (result.status !== 0 && result.status !== null) {\n process.exitCode = result.status;\n }\n}\n","import type { CommandDefinition } from '@definition';\n\nimport { logger } from '@lib/logger';\n\nimport run from './impl.js';\n\nexport default {\n name: 'prompt',\n aliases: ['p'],\n description:\n 'Interactively choose type, scope, and message per your config format, then run git commit',\n summary: 'Prompt using configured format and types/scopes, then commit',\n options: [\n {\n flags: '--dry-run',\n description: 'Print the composed message without running git commit',\n defaultValue: false,\n },\n {\n flags: '--skip-verify',\n description: 'Run git commit with --no-verify (skip hooks)',\n defaultValue: false,\n },\n ],\n action: (options: { dryRun?: boolean; skipVerify?: boolean }) => {\n void run(options).catch((e: unknown) => {\n logger.error(e instanceof Error ? e.message : String(e));\n process.exitCode = 1;\n });\n },\n} satisfies CommandDefinition;\n","import type { UninstallOptions } from './types.js';\nimport { logger } from '@lib/logger';\nimport { consts } from '@consts';\nimport { gitHooksDir, messageFormatScript } from '../install/utils.js';\nimport { existsSync, readFileSync, unlinkSync } from 'fs';\n\nexport default (options: UninstallOptions): void => {\n const force = options.force === true;\n const hooksDir = gitHooksDir();\n const commitMsgPath = `${hooksDir}/${consts.commit.commitMsgHook}`;\n\n if (!existsSync(commitMsgPath)) {\n logger.info(`No ${consts.commit.commitMsgHook} hook found at ${commitMsgPath}`);\n return;\n }\n\n if (!force) {\n let content = '';\n try {\n content = readFileSync(commitMsgPath, 'utf8');\n } catch (err) {\n const code =\n err &&\n typeof err === 'object' &&\n 'code' in err &&\n typeof (err as { code: unknown }).code === 'string'\n ? (err as { code: string }).code\n : '';\n logger.error(`Could not read ${commitMsgPath}${code ? ` (${code})` : ''}.`);\n process.exitCode = 1;\n return;\n }\n\n if (!content.includes(messageFormatScript)) {\n logger.error(\n `${consts.commit.commitMsgHook} at ${commitMsgPath} was not installed by this tool. Use --force to remove it.`,\n );\n process.exitCode = 1;\n return;\n }\n }\n\n unlinkSync(commitMsgPath);\n logger.info(`Removed ${commitMsgPath}`);\n}\n","import type { CommandDefinition } from '@definition';\n\nimport run from './impl.js';\nimport type { UninstallOptions } from './types.js';\n\nexport default {\n name: 'uninstall',\n aliases: ['ui'],\n description: 'Remove the commit-msg hook installed by install',\n options: [\n {\n flags: '-f, --force',\n description: 'Remove the hook even if it was not installed by this tool',\n defaultValue: false,\n },\n ],\n action: (options) => run(options),\n} satisfies CommandDefinition<UninstallOptions>;\n","import { existsSync, readFileSync } from 'fs';\nimport { getConfig } from '@config';\nimport { logger } from '@lib/logger';\n\ntype Token = 'type' | 'scope' | 'message';\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction tokenPattern(token: Token): string {\n if (token === 'type') return '([^\\\\s(){}:]+)';\n if (token === 'scope') return '([^()\\\\r\\\\n]+)';\n return '(.+)';\n}\n\nfunction compileFormat(format: string): { regex: RegExp; tokens: Token[] } {\n const tokenRegex = /\\{(type|scope|message)\\}/g;\n const tokens: Token[] = [];\n let pattern = '^';\n let lastIdx = 0;\n\n for (let match = tokenRegex.exec(format); match !== null; match = tokenRegex.exec(format)) {\n const [fullMatch, token] = match;\n const start = match.index;\n\n pattern += escapeRegex(format.slice(lastIdx, start));\n pattern += tokenPattern(token as Token);\n tokens.push(token as Token);\n lastIdx = start + fullMatch.length;\n }\n\n pattern += escapeRegex(format.slice(lastIdx));\n pattern += '$';\n\n return { regex: new RegExp(pattern), tokens };\n}\n\nfunction readCommitMessage(input?: string): string {\n if (!input) return '';\n if (!existsSync(input)) return input;\n return readFileSync(input, 'utf8');\n}\n\nfunction headerFromMessage(message: string): string {\n const lines = message.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n return line;\n }\n return '';\n}\n\nexport default (input?: string): void => {\n const messageConfig = getConfig().commit.message;\n const message = readCommitMessage(input);\n const header = headerFromMessage(message);\n\n if (!header.trim()) {\n process.exitCode = 1;\n logger.error('Commit message is empty.');\n return;\n }\n\n const { regex, tokens } = compileFormat(messageConfig.format);\n const match = regex.exec(header);\n\n if (!match) {\n process.exitCode = 1;\n logger.error(`Invalid commit message format. Expected: \"${messageConfig.format}\"`);\n return;\n }\n\n const extracted: Partial<Record<Token, string>> = {};\n for (let i = 0; i < tokens.length; i += 1) {\n extracted[tokens[i]] = match[i + 1];\n }\n\n const type = extracted.type?.trim();\n const scope = extracted.scope?.trim();\n const body = extracted.message?.trim();\n\n if (type && messageConfig.types.length > 0 && !messageConfig.types.includes(type)) {\n process.exitCode = 1;\n logger.error(`Invalid commit type \"${type}\". Allowed: ${messageConfig.types.join(', ')}`);\n return;\n }\n\n if (scope && messageConfig.scopes.length > 0 && !messageConfig.scopes.includes(scope)) {\n process.exitCode = 1;\n logger.error(`Invalid commit scope \"${scope}\". Allowed: ${messageConfig.scopes.join(', ')}`);\n return;\n }\n\n if (tokens.includes('message') && (!body || body.length === 0)) {\n process.exitCode = 1;\n logger.error('Commit message body cannot be empty.');\n return;\n }\n}\n","import type { CommandDefinition } from '@definition';\n\nimport run from './impl.js';\n\nexport default {\n name: 'validate',\n aliases: ['v'],\n description: 'Validate a commit message',\n argumentSyntax: '[message-or-file]',\n action: (_options, input) => run(input),\n} satisfies CommandDefinition;\n","import type { CommandDefinition } from '@definition';\n\nimport installSubcommand from './cmds/install/cmd.js';\nimport promptSubcommand from './cmds/prompt/cmd.js';\nimport uninstallSubcommand from './cmds/uninstall/cmd.js';\nimport validateSubcommand from './cmds/validate/cmd.js';\n\nexport default {\n name: 'msg',\n description: 'Structured commit messages: `<type> (scope): msg`',\n summary: 'Validate commits and manage the commit-msg hook',\n subcommands: [\n installSubcommand,\n uninstallSubcommand,\n validateSubcommand,\n promptSubcommand,\n ],\n} satisfies CommandDefinition;\n","import type { CommandDefinition } from '@definition';\nimport msgSubcommand from './cmds/msg/cmd.js';\n\nexport default {\n name: 'commit',\n aliases: ['c'],\n description: 'Structured commit messages: `<type> (scope): msg`',\n summary: 'Validate commits and manage the commit-msg hook',\n subcommands: [\n msgSubcommand,\n ],\n} satisfies CommandDefinition;\n","import type { CommandDefinition } from '@definition';\nimport init from '@commands/init';\nimport rm from '@commands/rm';\nimport commitMsg from '@commands/commit';\n\nconst commands: CommandDefinition[] = [\n init,\n rm,\n commitMsg,\n];\nexport default commands;\n","import type { AttachedCommandOptions, CommandOption, PositionalArg } from \"@definition\";\nimport { Command, Option } from \"commander\";\n\nexport const nameAndArgs = (name: string, argumentSyntax?: string): string => {\n const extra = argumentSyntax?.trim();\n return extra ? `${name} ${extra}` : name;\n}\n\nexport const applyPositional = (cmd: Command, positional?: PositionalArg[]): void => {\n if (!positional?.length) return;\n for (const p of positional) {\n if (p.description !== undefined && p.defaultValue !== undefined) {\n cmd.argument(p.spec, p.description, p.defaultValue);\n } else if (p.description !== undefined) {\n cmd.argument(p.spec, p.description);\n } else if (p.defaultValue !== undefined) {\n cmd.argument(p.spec, '', p.defaultValue);\n } else {\n cmd.argument(p.spec);\n }\n }\n}\n\nexport const applyOption = (cmd: Command, opt: CommandOption): void => {\n const needsCustomOption =\n (opt.choices?.length ?? 0) > 0 ||\n opt.env != null ||\n opt.hideHelp === true ||\n opt.helpGroup != null ||\n opt.preset !== undefined;\n\n if (needsCustomOption) {\n const o = new Option(opt.flags, opt.description);\n if (opt.defaultValue !== undefined) {\n o.default(opt.defaultValue);\n }\n if (opt.choices?.length) {\n o.choices(opt.choices);\n }\n if (opt.env) {\n o.env(opt.env);\n }\n if (opt.hideHelp) {\n o.hideHelp(true);\n }\n if (opt.helpGroup) {\n o.helpGroup(opt.helpGroup);\n }\n if (opt.preset !== undefined) {\n o.preset(opt.preset);\n }\n if (opt.mandatory) {\n o.makeOptionMandatory(true);\n }\n cmd.addOption(o);\n return;\n }\n\n if (opt.mandatory) {\n if (opt.defaultValue !== undefined) {\n cmd.requiredOption(opt.flags, opt.description, opt.defaultValue);\n } else {\n cmd.requiredOption(opt.flags, opt.description);\n }\n return;\n }\n\n if (opt.defaultValue !== undefined) {\n cmd.option(opt.flags, opt.description, opt.defaultValue);\n } else {\n cmd.option(opt.flags, opt.description);\n }\n}\n\nexport const applyOptions = (cmd: Command, options?: CommandOption[]): void => {\n if (!options) return;\n for (const opt of options) {\n applyOption(cmd, opt);\n }\n}\n\nexport const applyCommandMeta = (cmd: Command, def: AttachedCommandOptions): void => {\n if (def.usage != null) cmd.usage(def.usage);\n if (def.helpGroup != null) cmd.helpGroup(def.helpGroup);\n if (def.allowUnknownOptions === true) cmd.allowUnknownOption(true);\n if (def.allowExcessArguments !== undefined) cmd.allowExcessArguments(def.allowExcessArguments);\n}\n","import { Command } from \"commander\";\nimport { applyCommandMeta, applyOptions, applyPositional, nameAndArgs } from \"./utils\";\nimport type { CommandDefinition } from \"@definition\";\nimport { BshError } from \"@lib/errors\";\n\nexport default (program: Command, commands: CommandDefinition[]) => {\n const registerCommand = (parent: Command, cmd: CommandDefinition): void => {\n const sub = parent\n .command(nameAndArgs(cmd.name, cmd.argumentSyntax), {\n hidden: cmd.hidden,\n isDefault: cmd.isDefault,\n })\n .description(cmd.description)\n .summary(cmd.summary ?? \"\");\n\n for (const a of cmd.aliases ?? []) sub.alias(a);\n\n if (cmd.positional?.length) applyPositional(sub, cmd.positional);\n else if (cmd.argumentsPattern) sub.arguments(cmd.argumentsPattern);\n\n applyCommandMeta(sub, cmd);\n applyOptions(sub, cmd.options);\n\n if (cmd.subcommands?.length) {\n for (const nested of cmd.subcommands) {\n registerCommand(sub, nested);\n }\n return;\n }\n\n if (cmd.action) {\n sub.action((...actionArgs: unknown[]) => {\n const options = actionArgs[actionArgs.length - 2] as Record<string, unknown>;\n const positionals = actionArgs.slice(0, -2) as string[];\n const action = cmd.action as ((options: unknown, ...args: string[]) => void);\n action(options, ...positionals);\n });\n return;\n }\n\n throw new BshError(\n 500,\n `Command \"${cmd.name}\" must define action or subcommands`,\n );\n };\n\n for (const cmd of commands) {\n registerCommand(program, cmd);\n }\n}\n","import { Command } from 'commander';\nimport { readFileSync } from 'fs';\nimport { dirname, join } from 'path';\nimport { fileURLToPath } from 'url';\nimport { loadConfig } from '@config';\nimport middleware from '@lib/middleware';\nimport commands from '@commands';\nimport cli from '@lib/cli';\n\nconst __filename = fileURLToPath(import.meta.url);\nconst __dirname = dirname(__filename);\n\nconst packageJson = JSON.parse(\n readFileSync(join(__dirname, '../package.json'), 'utf-8'),\n);\n\nconst program = new Command();\n\nprogram\n .name(`npx ${packageJson.name}`)\n .description('Git workflows with a simpler interface')\n .version(packageJson.version);\n\n(async () => {\n await loadConfig();\n cli(program, commands);\n await middleware(program);\n})();\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bshsolutions/git",
|
|
3
|
+
"version": "0.0.1-alpha",
|
|
4
|
+
"description": "A friendly CLI for common Git workflows",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"git-bsh": "./dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"scripts": {
|
|
13
|
+
"build": "tsup && npm run commands:tree",
|
|
14
|
+
"watch": "tsup --watch",
|
|
15
|
+
"commands:tree": "tsx scripts/commands-tree.ts",
|
|
16
|
+
"prepublishOnly": "npm run build",
|
|
17
|
+
"clean": "rm -rf dist",
|
|
18
|
+
"test": "vitest run && npm run commands:tree",
|
|
19
|
+
"test:watch": "vitest",
|
|
20
|
+
"test:coverage": "vitest run --coverage"
|
|
21
|
+
},
|
|
22
|
+
"keywords": [
|
|
23
|
+
"bsh",
|
|
24
|
+
"bsh solutions",
|
|
25
|
+
"git",
|
|
26
|
+
"cli",
|
|
27
|
+
"typescript"
|
|
28
|
+
],
|
|
29
|
+
"author": "Bousalih Hamza <hamza.bousalih@yahoo.com>",
|
|
30
|
+
"homepage": "https://github.com/bsh-devsolutions/git.bsh",
|
|
31
|
+
"repository": {
|
|
32
|
+
"type": "git",
|
|
33
|
+
"url": "https://github.com/bsh-devsolutions/git.bsh.git"
|
|
34
|
+
},
|
|
35
|
+
"bugs": {
|
|
36
|
+
"url": "https://github.com/bsh-devsolutions/git.bsh/issues"
|
|
37
|
+
},
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"commander": "^14.0.2",
|
|
41
|
+
"pino": "^10.3.1",
|
|
42
|
+
"pino-pretty": "^13.1.3",
|
|
43
|
+
"prompts": "^2.4.2"
|
|
44
|
+
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@types/node": "^20.0.0",
|
|
47
|
+
"@types/prompts": "^2.4.9",
|
|
48
|
+
"@vitest/coverage-v8": "^2.0.0",
|
|
49
|
+
"tsup": "^8.0.0",
|
|
50
|
+
"tsx": "^4.0.0",
|
|
51
|
+
"typescript": "^5.0.0",
|
|
52
|
+
"vite-tsconfig-paths": "^5.1.4",
|
|
53
|
+
"vitest": "^2.0.0"
|
|
54
|
+
},
|
|
55
|
+
"overrides": {
|
|
56
|
+
"esbuild": "^0.25.0"
|
|
57
|
+
}
|
|
58
|
+
}
|