@md2do/cli 0.3.1 → 0.5.0
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/CHANGELOG.md +55 -0
- package/README.md +25 -0
- package/coverage/coverage-final.json +5 -4
- package/coverage/index.html +11 -11
- package/coverage/lcov-report/index.html +11 -11
- package/coverage/lcov-report/src/cli.ts.html +10 -4
- package/coverage/lcov-report/src/commands/config.ts.html +2269 -0
- package/coverage/lcov-report/src/commands/index.html +24 -9
- package/coverage/lcov-report/src/commands/index.ts.html +7 -4
- package/coverage/lcov-report/src/commands/list.ts.html +103 -22
- package/coverage/lcov-report/src/commands/stats.ts.html +1 -1
- package/coverage/lcov-report/src/commands/todoist.ts.html +1 -1
- package/coverage/lcov-report/src/formatters/index.html +1 -1
- package/coverage/lcov-report/src/formatters/json.ts.html +1 -1
- package/coverage/lcov-report/src/formatters/pretty.ts.html +1 -1
- package/coverage/lcov-report/src/index.html +7 -7
- package/coverage/lcov-report/src/index.ts.html +1 -1
- package/coverage/lcov-report/src/scanner.ts.html +87 -6
- package/coverage/lcov.info +817 -20
- package/coverage/src/cli.ts.html +10 -4
- package/coverage/src/commands/config.ts.html +2269 -0
- package/coverage/src/commands/index.html +24 -9
- package/coverage/src/commands/index.ts.html +7 -4
- package/coverage/src/commands/list.ts.html +103 -22
- package/coverage/src/commands/stats.ts.html +1 -1
- package/coverage/src/commands/todoist.ts.html +1 -1
- package/coverage/src/formatters/index.html +1 -1
- package/coverage/src/formatters/json.ts.html +1 -1
- package/coverage/src/formatters/pretty.ts.html +1 -1
- package/coverage/src/index.html +7 -7
- package/coverage/src/index.ts.html +1 -1
- package/coverage/src/scanner.ts.html +87 -6
- package/dist/cli.js +488 -12
- package/dist/index.d.ts +6 -1
- package/dist/index.js +483 -6
- package/package.json +7 -4
- package/src/cli.ts +2 -0
- package/src/commands/config.ts +731 -0
- package/src/commands/index.ts +1 -0
- package/src/commands/list.ts +16 -5
- package/src/scanner.ts +23 -1
package/dist/cli.js
CHANGED
|
@@ -24,9 +24,9 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
24
24
|
));
|
|
25
25
|
|
|
26
26
|
// src/cli.ts
|
|
27
|
-
var
|
|
28
|
-
var
|
|
29
|
-
var
|
|
27
|
+
var import_commander5 = require("commander");
|
|
28
|
+
var import_fs2 = require("fs");
|
|
29
|
+
var import_path2 = require("path");
|
|
30
30
|
|
|
31
31
|
// src/commands/list.ts
|
|
32
32
|
var import_commander = require("commander");
|
|
@@ -49,7 +49,10 @@ async function scanMarkdownFiles(options = {}) {
|
|
|
49
49
|
"**/build/**",
|
|
50
50
|
"**/.next/**"
|
|
51
51
|
],
|
|
52
|
-
followSymlinks = false
|
|
52
|
+
followSymlinks = false,
|
|
53
|
+
workdayStartTime,
|
|
54
|
+
workdayEndTime,
|
|
55
|
+
defaultDueTime
|
|
53
56
|
} = options;
|
|
54
57
|
const files = await (0, import_fast_glob.default)(pattern, {
|
|
55
58
|
cwd: root,
|
|
@@ -65,7 +68,11 @@ async function scanMarkdownFiles(options = {}) {
|
|
|
65
68
|
try {
|
|
66
69
|
const fullPath = `${root}/${file}`;
|
|
67
70
|
const content = await (0, import_promises.readFile)(fullPath, "utf-8");
|
|
68
|
-
const result = scanner.scanFile(file, content
|
|
71
|
+
const result = scanner.scanFile(file, content, {
|
|
72
|
+
...workdayStartTime && { workdayStartTime },
|
|
73
|
+
...workdayEndTime && { workdayEndTime },
|
|
74
|
+
...defaultDueTime && { defaultDueTime }
|
|
75
|
+
});
|
|
69
76
|
allTasks.push(...result.tasks);
|
|
70
77
|
allWarnings.push(...result.warnings);
|
|
71
78
|
} catch (error) {
|
|
@@ -299,10 +306,22 @@ function createListCommand() {
|
|
|
299
306
|
"pretty"
|
|
300
307
|
).option("--no-colors", "Disable colors in output").option("--no-paths", "Hide file paths").option("--context", "Show context information (project, person, heading)").option("--no-warnings", "Hide all warnings").option("--all-warnings", "Show all warnings (default shows first 5)").action(async (options) => {
|
|
301
308
|
try {
|
|
309
|
+
const config = await (0, import_config.loadConfig)({
|
|
310
|
+
cwd: options.path || process.cwd()
|
|
311
|
+
});
|
|
302
312
|
const scanResult = await scanMarkdownFiles({
|
|
303
313
|
root: options.path || process.cwd(),
|
|
304
314
|
...options.pattern !== void 0 && { pattern: options.pattern },
|
|
305
|
-
...options.exclude !== void 0 && { exclude: options.exclude }
|
|
315
|
+
...options.exclude !== void 0 && { exclude: options.exclude },
|
|
316
|
+
...config.workday?.startTime && {
|
|
317
|
+
workdayStartTime: config.workday.startTime
|
|
318
|
+
},
|
|
319
|
+
...config.workday?.endTime && {
|
|
320
|
+
workdayEndTime: config.workday.endTime
|
|
321
|
+
},
|
|
322
|
+
...config.workday?.defaultDueTime && {
|
|
323
|
+
defaultDueTime: config.workday.defaultDueTime
|
|
324
|
+
}
|
|
306
325
|
});
|
|
307
326
|
let tasks = scanResult.tasks;
|
|
308
327
|
const taskFilters = [];
|
|
@@ -395,9 +414,6 @@ function createListCommand() {
|
|
|
395
414
|
}
|
|
396
415
|
console.log(output);
|
|
397
416
|
if (options.warnings !== false) {
|
|
398
|
-
const config = await (0, import_config.loadConfig)({
|
|
399
|
-
cwd: options.path || process.cwd()
|
|
400
|
-
});
|
|
401
417
|
const warningConfig = config.warnings ?? import_config.DEFAULT_CONFIG.warnings;
|
|
402
418
|
const filteredWarnings = (0, import_core2.filterWarnings)(
|
|
403
419
|
scanResult.warnings,
|
|
@@ -1186,21 +1202,481 @@ async function todoistSyncAction(options) {
|
|
|
1186
1202
|
console.log("");
|
|
1187
1203
|
}
|
|
1188
1204
|
|
|
1205
|
+
// src/commands/config.ts
|
|
1206
|
+
var import_commander4 = require("commander");
|
|
1207
|
+
var import_config3 = require("@md2do/config");
|
|
1208
|
+
var import_fs = require("fs");
|
|
1209
|
+
var import_path = require("path");
|
|
1210
|
+
var import_os = require("os");
|
|
1211
|
+
var import_child_process = require("child_process");
|
|
1212
|
+
var import_js_yaml = __toESM(require("js-yaml"));
|
|
1213
|
+
function createConfigCommand() {
|
|
1214
|
+
const command = new import_commander4.Command("config");
|
|
1215
|
+
command.description("Manage md2do configuration");
|
|
1216
|
+
command.addCommand(createConfigInitCommand());
|
|
1217
|
+
command.addCommand(createConfigSetCommand());
|
|
1218
|
+
command.addCommand(createConfigGetCommand());
|
|
1219
|
+
command.addCommand(createConfigListCommand());
|
|
1220
|
+
command.addCommand(createConfigEditCommand());
|
|
1221
|
+
command.addCommand(createConfigValidateCommand());
|
|
1222
|
+
return command;
|
|
1223
|
+
}
|
|
1224
|
+
function createConfigInitCommand() {
|
|
1225
|
+
const command = new import_commander4.Command("init");
|
|
1226
|
+
command.description("Initialize md2do configuration with interactive prompts").option("-g, --global", "Create global configuration in home directory").option(
|
|
1227
|
+
"--format <type>",
|
|
1228
|
+
"Config file format (json|yaml|js)",
|
|
1229
|
+
"json"
|
|
1230
|
+
).option("--default-assignee <username>", "Default assignee username").option("--workday-start <time>", "Work day start time (HH:MM)").option("--workday-end <time>", "Work day end time (HH:MM)").option(
|
|
1231
|
+
"--default-due-time <when>",
|
|
1232
|
+
"Default due time (start|end)",
|
|
1233
|
+
"end"
|
|
1234
|
+
).option(
|
|
1235
|
+
"--output-format <type>",
|
|
1236
|
+
"Output format (pretty|table|json)",
|
|
1237
|
+
"pretty"
|
|
1238
|
+
).option("--no-colors", "Disable colored output").option(
|
|
1239
|
+
"--warnings <level>",
|
|
1240
|
+
"Warning level (recommended|strict|off)",
|
|
1241
|
+
"recommended"
|
|
1242
|
+
).action(async (options) => {
|
|
1243
|
+
try {
|
|
1244
|
+
await configInitAction(options);
|
|
1245
|
+
} catch (error) {
|
|
1246
|
+
if (error instanceof Error && error.message === "canceled") {
|
|
1247
|
+
const p = await import("@clack/prompts");
|
|
1248
|
+
p.cancel("Configuration canceled");
|
|
1249
|
+
process.exit(0);
|
|
1250
|
+
}
|
|
1251
|
+
console.error(
|
|
1252
|
+
"Error:",
|
|
1253
|
+
error instanceof Error ? error.message : String(error)
|
|
1254
|
+
);
|
|
1255
|
+
process.exit(1);
|
|
1256
|
+
}
|
|
1257
|
+
});
|
|
1258
|
+
return command;
|
|
1259
|
+
}
|
|
1260
|
+
async function configInitAction(options) {
|
|
1261
|
+
const p = await import("@clack/prompts");
|
|
1262
|
+
p.intro("Welcome to md2do configuration!");
|
|
1263
|
+
const hasAnyOption = options.defaultAssignee !== void 0 || options.workdayStart !== void 0 || options.workdayEnd !== void 0 || options.defaultDueTime !== void 0 || options.outputFormat !== void 0 || options.colors !== void 0 || options.warnings !== void 0;
|
|
1264
|
+
const interactive = !hasAnyOption;
|
|
1265
|
+
const config = {};
|
|
1266
|
+
if (interactive) {
|
|
1267
|
+
const defaultAssignee = await p.text({
|
|
1268
|
+
message: "Your username (for filtering tasks):",
|
|
1269
|
+
placeholder: "Leave empty to skip",
|
|
1270
|
+
validate: (value) => {
|
|
1271
|
+
if (value && !/^[a-zA-Z0-9_-]+$/.test(value)) {
|
|
1272
|
+
return "Username should only contain letters, numbers, dashes, and underscores";
|
|
1273
|
+
}
|
|
1274
|
+
}
|
|
1275
|
+
});
|
|
1276
|
+
const workdayStart = await p.text({
|
|
1277
|
+
message: "Work day start time (HH:MM):",
|
|
1278
|
+
initialValue: "08:00",
|
|
1279
|
+
validate: (value) => {
|
|
1280
|
+
if (typeof value === "string" && !/^\d{2}:\d{2}$/.test(value)) {
|
|
1281
|
+
return "Time must be in HH:MM format";
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
});
|
|
1285
|
+
const workdayEnd = await p.text({
|
|
1286
|
+
message: "Work day end time (HH:MM):",
|
|
1287
|
+
initialValue: "17:00",
|
|
1288
|
+
validate: (value) => {
|
|
1289
|
+
if (typeof value === "string" && !/^\d{2}:\d{2}$/.test(value)) {
|
|
1290
|
+
return "Time must be in HH:MM format";
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
});
|
|
1294
|
+
const defaultDueTime = await p.select({
|
|
1295
|
+
message: "Default due time:",
|
|
1296
|
+
options: [
|
|
1297
|
+
{ value: "end", label: "End of day" },
|
|
1298
|
+
{ value: "start", label: "Start of day" }
|
|
1299
|
+
],
|
|
1300
|
+
initialValue: "end"
|
|
1301
|
+
});
|
|
1302
|
+
const outputFormat = await p.select({
|
|
1303
|
+
message: "Output format:",
|
|
1304
|
+
options: [
|
|
1305
|
+
{ value: "pretty", label: "Pretty (human-readable)" },
|
|
1306
|
+
{ value: "table", label: "Table (structured)" },
|
|
1307
|
+
{ value: "json", label: "JSON (machine-readable)" }
|
|
1308
|
+
],
|
|
1309
|
+
initialValue: "pretty"
|
|
1310
|
+
});
|
|
1311
|
+
const colors = await p.confirm({
|
|
1312
|
+
message: "Enable colored output?",
|
|
1313
|
+
initialValue: true
|
|
1314
|
+
});
|
|
1315
|
+
const warnings = await p.select({
|
|
1316
|
+
message: "Warning level:",
|
|
1317
|
+
options: [
|
|
1318
|
+
{
|
|
1319
|
+
value: "recommended",
|
|
1320
|
+
label: "Recommended (validates format, metadata optional)"
|
|
1321
|
+
},
|
|
1322
|
+
{
|
|
1323
|
+
value: "strict",
|
|
1324
|
+
label: "Strict (enforces complete metadata)"
|
|
1325
|
+
},
|
|
1326
|
+
{ value: "off", label: "Off (no warnings)" }
|
|
1327
|
+
],
|
|
1328
|
+
initialValue: "recommended"
|
|
1329
|
+
});
|
|
1330
|
+
if (defaultAssignee && typeof defaultAssignee === "string") {
|
|
1331
|
+
config.defaultAssignee = defaultAssignee;
|
|
1332
|
+
}
|
|
1333
|
+
config.workday = {
|
|
1334
|
+
startTime: typeof workdayStart === "string" ? workdayStart : "08:00",
|
|
1335
|
+
endTime: typeof workdayEnd === "string" ? workdayEnd : "17:00",
|
|
1336
|
+
defaultDueTime: typeof defaultDueTime === "string" ? defaultDueTime : "end"
|
|
1337
|
+
};
|
|
1338
|
+
config.output = {
|
|
1339
|
+
format: typeof outputFormat === "string" ? outputFormat : "pretty",
|
|
1340
|
+
colors: typeof colors === "boolean" ? colors : true,
|
|
1341
|
+
paths: true
|
|
1342
|
+
};
|
|
1343
|
+
if (typeof warnings === "string" && warnings === "off") {
|
|
1344
|
+
config.warnings = { enabled: false };
|
|
1345
|
+
} else if (typeof warnings === "string" && warnings === "strict") {
|
|
1346
|
+
config.warnings = {
|
|
1347
|
+
enabled: true,
|
|
1348
|
+
rules: {
|
|
1349
|
+
"unsupported-bullet": "warn",
|
|
1350
|
+
"malformed-checkbox": "warn",
|
|
1351
|
+
"missing-space-after": "warn",
|
|
1352
|
+
"missing-space-before": "warn",
|
|
1353
|
+
"relative-date-no-context": "warn",
|
|
1354
|
+
"missing-due-date": "warn",
|
|
1355
|
+
"missing-completed-date": "warn",
|
|
1356
|
+
"duplicate-todoist-id": "error",
|
|
1357
|
+
"file-read-error": "error"
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
}
|
|
1361
|
+
} else {
|
|
1362
|
+
if (options.defaultAssignee) {
|
|
1363
|
+
config.defaultAssignee = options.defaultAssignee;
|
|
1364
|
+
}
|
|
1365
|
+
config.workday = {
|
|
1366
|
+
startTime: options.workdayStart || "08:00",
|
|
1367
|
+
endTime: options.workdayEnd || "17:00",
|
|
1368
|
+
defaultDueTime: options.defaultDueTime || "end"
|
|
1369
|
+
};
|
|
1370
|
+
config.output = {
|
|
1371
|
+
format: options.outputFormat || "pretty",
|
|
1372
|
+
colors: options.colors ?? true,
|
|
1373
|
+
paths: true
|
|
1374
|
+
};
|
|
1375
|
+
if (options.warnings === "off") {
|
|
1376
|
+
config.warnings = { enabled: false };
|
|
1377
|
+
} else if (options.warnings === "strict") {
|
|
1378
|
+
config.warnings = {
|
|
1379
|
+
enabled: true,
|
|
1380
|
+
rules: {
|
|
1381
|
+
"unsupported-bullet": "warn",
|
|
1382
|
+
"malformed-checkbox": "warn",
|
|
1383
|
+
"missing-space-after": "warn",
|
|
1384
|
+
"missing-space-before": "warn",
|
|
1385
|
+
"relative-date-no-context": "warn",
|
|
1386
|
+
"missing-due-date": "warn",
|
|
1387
|
+
"missing-completed-date": "warn",
|
|
1388
|
+
"duplicate-todoist-id": "error",
|
|
1389
|
+
"file-read-error": "error"
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
try {
|
|
1395
|
+
(0, import_config3.validateConfig)(config);
|
|
1396
|
+
} catch (error) {
|
|
1397
|
+
p.cancel(
|
|
1398
|
+
`Invalid configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
1399
|
+
);
|
|
1400
|
+
process.exit(1);
|
|
1401
|
+
}
|
|
1402
|
+
const format = options.format || "json";
|
|
1403
|
+
const configPath = getConfigPath(options.global || false, format);
|
|
1404
|
+
if ((0, import_fs.existsSync)(configPath)) {
|
|
1405
|
+
if (interactive) {
|
|
1406
|
+
const overwrite = await p.confirm({
|
|
1407
|
+
message: `Configuration file already exists at ${configPath}. Overwrite?`,
|
|
1408
|
+
initialValue: false
|
|
1409
|
+
});
|
|
1410
|
+
if (!overwrite) {
|
|
1411
|
+
p.cancel("Configuration canceled");
|
|
1412
|
+
process.exit(0);
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
}
|
|
1416
|
+
writeConfigFile(configPath, config, format);
|
|
1417
|
+
p.outro(`\u2713 Configuration saved to ${configPath}`);
|
|
1418
|
+
}
|
|
1419
|
+
function createConfigSetCommand() {
|
|
1420
|
+
const command = new import_commander4.Command("set");
|
|
1421
|
+
command.description("Set a configuration value").argument("<key>", "Configuration key (e.g., workday.startTime)").argument("<value>", "Configuration value").option("-g, --global", "Set in global configuration").action((key, value, options) => {
|
|
1422
|
+
try {
|
|
1423
|
+
configSetAction(key, value, options);
|
|
1424
|
+
} catch (error) {
|
|
1425
|
+
console.error(
|
|
1426
|
+
"Error:",
|
|
1427
|
+
error instanceof Error ? error.message : String(error)
|
|
1428
|
+
);
|
|
1429
|
+
process.exit(1);
|
|
1430
|
+
}
|
|
1431
|
+
});
|
|
1432
|
+
return command;
|
|
1433
|
+
}
|
|
1434
|
+
function configSetAction(key, value, options) {
|
|
1435
|
+
const isGlobal = options.global || false;
|
|
1436
|
+
const configPath = findExistingConfigPath(isGlobal);
|
|
1437
|
+
let config = {};
|
|
1438
|
+
let format = "json";
|
|
1439
|
+
if (configPath) {
|
|
1440
|
+
format = getConfigFormat(configPath);
|
|
1441
|
+
const content = (0, import_fs.readFileSync)(configPath, "utf-8");
|
|
1442
|
+
config = parseConfigFile(content, format);
|
|
1443
|
+
} else {
|
|
1444
|
+
format = "json";
|
|
1445
|
+
}
|
|
1446
|
+
const parsedValue = parseValue(value);
|
|
1447
|
+
setNestedValue(config, key, parsedValue);
|
|
1448
|
+
try {
|
|
1449
|
+
(0, import_config3.validateConfig)(config);
|
|
1450
|
+
} catch (error) {
|
|
1451
|
+
console.error(
|
|
1452
|
+
`Invalid configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
1453
|
+
);
|
|
1454
|
+
process.exit(1);
|
|
1455
|
+
}
|
|
1456
|
+
const finalPath = configPath || getConfigPath(isGlobal, format);
|
|
1457
|
+
writeConfigFile(finalPath, config, format);
|
|
1458
|
+
console.log(`\u2713 Set ${key} = ${value} in ${finalPath}`);
|
|
1459
|
+
}
|
|
1460
|
+
function createConfigGetCommand() {
|
|
1461
|
+
const command = new import_commander4.Command("get");
|
|
1462
|
+
command.description("Get a configuration value").argument("<key>", "Configuration key (e.g., workday.startTime)").option("-g, --global", "Get from global configuration only").action(async (key, options) => {
|
|
1463
|
+
try {
|
|
1464
|
+
await configGetAction(key, options);
|
|
1465
|
+
} catch (error) {
|
|
1466
|
+
console.error(
|
|
1467
|
+
"Error:",
|
|
1468
|
+
error instanceof Error ? error.message : String(error)
|
|
1469
|
+
);
|
|
1470
|
+
process.exit(1);
|
|
1471
|
+
}
|
|
1472
|
+
});
|
|
1473
|
+
return command;
|
|
1474
|
+
}
|
|
1475
|
+
async function configGetAction(key, options) {
|
|
1476
|
+
const config = options.global ? await (0, import_config3.loadConfig)({ loadGlobal: true, loadEnv: false, cwd: (0, import_os.homedir)() }) : await (0, import_config3.loadConfig)();
|
|
1477
|
+
const value = getNestedValue(config, key);
|
|
1478
|
+
if (value === void 0) {
|
|
1479
|
+
console.log("(not set)");
|
|
1480
|
+
} else if (typeof value === "object") {
|
|
1481
|
+
console.log(JSON.stringify(value, null, 2));
|
|
1482
|
+
} else {
|
|
1483
|
+
console.log(value);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
function createConfigListCommand() {
|
|
1487
|
+
const command = new import_commander4.Command("list");
|
|
1488
|
+
command.description("Show all configuration values").option("--show-origin", "Show where each value comes from").action(async (options) => {
|
|
1489
|
+
try {
|
|
1490
|
+
await configListAction(options);
|
|
1491
|
+
} catch (error) {
|
|
1492
|
+
console.error(
|
|
1493
|
+
"Error:",
|
|
1494
|
+
error instanceof Error ? error.message : String(error)
|
|
1495
|
+
);
|
|
1496
|
+
process.exit(1);
|
|
1497
|
+
}
|
|
1498
|
+
});
|
|
1499
|
+
return command;
|
|
1500
|
+
}
|
|
1501
|
+
async function configListAction(options) {
|
|
1502
|
+
const config = await (0, import_config3.loadConfig)();
|
|
1503
|
+
console.log("");
|
|
1504
|
+
console.log("Current configuration:");
|
|
1505
|
+
console.log("");
|
|
1506
|
+
console.log(JSON.stringify(config, null, 2));
|
|
1507
|
+
console.log("");
|
|
1508
|
+
if (options.showOrigin) {
|
|
1509
|
+
console.log("Configuration sources:");
|
|
1510
|
+
console.log(" 1. Default values (built-in)");
|
|
1511
|
+
console.log(` 2. Global config (${getConfigPath(true, "json")})`);
|
|
1512
|
+
console.log(` 3. Project config (${getConfigPath(false, "json")})`);
|
|
1513
|
+
console.log(" 4. Environment variables");
|
|
1514
|
+
console.log("");
|
|
1515
|
+
}
|
|
1516
|
+
}
|
|
1517
|
+
function createConfigEditCommand() {
|
|
1518
|
+
const command = new import_commander4.Command("edit");
|
|
1519
|
+
command.description("Open configuration file in your default editor").option("-g, --global", "Edit global configuration").action((options) => {
|
|
1520
|
+
try {
|
|
1521
|
+
configEditAction(options);
|
|
1522
|
+
} catch (error) {
|
|
1523
|
+
console.error(
|
|
1524
|
+
"Error:",
|
|
1525
|
+
error instanceof Error ? error.message : String(error)
|
|
1526
|
+
);
|
|
1527
|
+
process.exit(1);
|
|
1528
|
+
}
|
|
1529
|
+
});
|
|
1530
|
+
return command;
|
|
1531
|
+
}
|
|
1532
|
+
function configEditAction(options) {
|
|
1533
|
+
const isGlobal = options.global || false;
|
|
1534
|
+
let configPath = findExistingConfigPath(isGlobal);
|
|
1535
|
+
if (!configPath) {
|
|
1536
|
+
configPath = getConfigPath(isGlobal, "json");
|
|
1537
|
+
writeConfigFile(configPath, {}, "json");
|
|
1538
|
+
console.log(`Created new configuration file: ${configPath}`);
|
|
1539
|
+
}
|
|
1540
|
+
const editor = process.env.VISUAL || process.env.EDITOR || (process.platform === "win32" ? "notepad" : "vi");
|
|
1541
|
+
console.log(`Opening ${configPath} in ${editor}...`);
|
|
1542
|
+
try {
|
|
1543
|
+
(0, import_child_process.execSync)(`${editor} '${configPath}'`, { stdio: "inherit" });
|
|
1544
|
+
} catch (error) {
|
|
1545
|
+
console.error("Failed to open editor");
|
|
1546
|
+
console.error(`You can manually edit the file at: ${configPath}`);
|
|
1547
|
+
process.exit(1);
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
function createConfigValidateCommand() {
|
|
1551
|
+
const command = new import_commander4.Command("validate");
|
|
1552
|
+
command.description("Validate current configuration").action(async () => {
|
|
1553
|
+
try {
|
|
1554
|
+
await configValidateAction();
|
|
1555
|
+
} catch (error) {
|
|
1556
|
+
console.error(
|
|
1557
|
+
"Error:",
|
|
1558
|
+
error instanceof Error ? error.message : String(error)
|
|
1559
|
+
);
|
|
1560
|
+
process.exit(1);
|
|
1561
|
+
}
|
|
1562
|
+
});
|
|
1563
|
+
return command;
|
|
1564
|
+
}
|
|
1565
|
+
async function configValidateAction() {
|
|
1566
|
+
try {
|
|
1567
|
+
const config = await (0, import_config3.loadConfig)();
|
|
1568
|
+
(0, import_config3.validateConfig)(config);
|
|
1569
|
+
console.log("\u2713 Configuration is valid");
|
|
1570
|
+
} catch (error) {
|
|
1571
|
+
console.error(
|
|
1572
|
+
`Invalid configuration: ${error instanceof Error ? error.message : String(error)}`
|
|
1573
|
+
);
|
|
1574
|
+
process.exit(1);
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
function getConfigPath(isGlobal, format) {
|
|
1578
|
+
const base = isGlobal ? (0, import_os.homedir)() : process.cwd();
|
|
1579
|
+
const fileName = format === "json" ? ".md2do.json" : format === "yaml" ? ".md2do.yaml" : ".md2do.js";
|
|
1580
|
+
return (0, import_path.join)(base, fileName);
|
|
1581
|
+
}
|
|
1582
|
+
function findExistingConfigPath(isGlobal) {
|
|
1583
|
+
const base = isGlobal ? (0, import_os.homedir)() : process.cwd();
|
|
1584
|
+
const possibleFiles = [
|
|
1585
|
+
".md2do.json",
|
|
1586
|
+
".md2do.yaml",
|
|
1587
|
+
".md2do.yml",
|
|
1588
|
+
".md2do.js",
|
|
1589
|
+
".md2do.cjs",
|
|
1590
|
+
"md2do.config.js",
|
|
1591
|
+
"md2do.config.cjs"
|
|
1592
|
+
];
|
|
1593
|
+
for (const file of possibleFiles) {
|
|
1594
|
+
const path = (0, import_path.join)(base, file);
|
|
1595
|
+
if ((0, import_fs.existsSync)(path)) {
|
|
1596
|
+
return path;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
return null;
|
|
1600
|
+
}
|
|
1601
|
+
function getConfigFormat(path) {
|
|
1602
|
+
if (path.endsWith(".json")) return "json";
|
|
1603
|
+
if (path.endsWith(".yaml") || path.endsWith(".yml")) return "yaml";
|
|
1604
|
+
return "js";
|
|
1605
|
+
}
|
|
1606
|
+
function parseConfigFile(content, format) {
|
|
1607
|
+
if (format === "json") {
|
|
1608
|
+
return JSON.parse(content);
|
|
1609
|
+
} else if (format === "yaml") {
|
|
1610
|
+
const loaded = import_js_yaml.default.load(content);
|
|
1611
|
+
return loaded || {};
|
|
1612
|
+
} else {
|
|
1613
|
+
return JSON.parse(content);
|
|
1614
|
+
}
|
|
1615
|
+
}
|
|
1616
|
+
function writeConfigFile(path, config, format) {
|
|
1617
|
+
let content;
|
|
1618
|
+
if (format === "json") {
|
|
1619
|
+
content = JSON.stringify(config, null, 2) + "\n";
|
|
1620
|
+
} else if (format === "yaml") {
|
|
1621
|
+
content = import_js_yaml.default.dump(config);
|
|
1622
|
+
} else {
|
|
1623
|
+
content = `module.exports = ${JSON.stringify(config, null, 2)};
|
|
1624
|
+
`;
|
|
1625
|
+
}
|
|
1626
|
+
(0, import_fs.writeFileSync)(path, content, "utf-8");
|
|
1627
|
+
}
|
|
1628
|
+
function parseValue(value) {
|
|
1629
|
+
if (value === "true") return true;
|
|
1630
|
+
if (value === "false") return false;
|
|
1631
|
+
const num = Number(value);
|
|
1632
|
+
if (!isNaN(num)) return num;
|
|
1633
|
+
try {
|
|
1634
|
+
return JSON.parse(value);
|
|
1635
|
+
} catch {
|
|
1636
|
+
return value;
|
|
1637
|
+
}
|
|
1638
|
+
}
|
|
1639
|
+
function getNestedValue(obj, path) {
|
|
1640
|
+
const keys = path.split(".");
|
|
1641
|
+
let current = obj;
|
|
1642
|
+
for (const key of keys) {
|
|
1643
|
+
if (current === null || current === void 0 || typeof current !== "object") {
|
|
1644
|
+
return void 0;
|
|
1645
|
+
}
|
|
1646
|
+
current = current[key];
|
|
1647
|
+
}
|
|
1648
|
+
return current;
|
|
1649
|
+
}
|
|
1650
|
+
function setNestedValue(obj, path, value) {
|
|
1651
|
+
const keys = path.split(".");
|
|
1652
|
+
const lastKey = keys.pop();
|
|
1653
|
+
if (!lastKey) return;
|
|
1654
|
+
let current = obj;
|
|
1655
|
+
for (const key of keys) {
|
|
1656
|
+
if (!(key in current) || typeof current[key] !== "object") {
|
|
1657
|
+
current[key] = {};
|
|
1658
|
+
}
|
|
1659
|
+
current = current[key];
|
|
1660
|
+
}
|
|
1661
|
+
current[lastKey] = value;
|
|
1662
|
+
}
|
|
1663
|
+
|
|
1189
1664
|
// src/cli.ts
|
|
1190
1665
|
var getVersion = () => {
|
|
1191
1666
|
try {
|
|
1192
|
-
const packagePath = (0,
|
|
1193
|
-
const packageJson = JSON.parse((0,
|
|
1667
|
+
const packagePath = (0, import_path2.join)(__dirname, "../package.json");
|
|
1668
|
+
const packageJson = JSON.parse((0, import_fs2.readFileSync)(packagePath, "utf-8"));
|
|
1194
1669
|
return packageJson.version;
|
|
1195
1670
|
} catch {
|
|
1196
1671
|
return "0.0.0";
|
|
1197
1672
|
}
|
|
1198
1673
|
};
|
|
1199
|
-
var program = new
|
|
1674
|
+
var program = new import_commander5.Command();
|
|
1200
1675
|
program.name("md2do").description("Scan and manage TODOs in markdown files").version(getVersion());
|
|
1201
1676
|
program.addCommand(createListCommand());
|
|
1202
1677
|
program.addCommand(createStatsCommand());
|
|
1203
1678
|
program.addCommand(createTodoistCommand());
|
|
1679
|
+
program.addCommand(createConfigCommand());
|
|
1204
1680
|
if (process.argv.length === 2) {
|
|
1205
1681
|
program.help();
|
|
1206
1682
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -9,4 +9,9 @@ declare function createStatsCommand(): Command;
|
|
|
9
9
|
*/
|
|
10
10
|
declare function createTodoistCommand(): Command;
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Create the config command group
|
|
14
|
+
*/
|
|
15
|
+
declare function createConfigCommand(): Command;
|
|
16
|
+
|
|
17
|
+
export { createConfigCommand, createListCommand, createStatsCommand, createTodoistCommand };
|