@tlog/cli 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +307 -0
  2. package/bin/.gitkeep +0 -0
  3. package/bin/tlog.js +4 -0
  4. package/dist/commands/delete.d.ts +8 -0
  5. package/dist/commands/delete.d.ts.map +1 -0
  6. package/dist/commands/delete.js +104 -0
  7. package/dist/commands/delete.js.map +1 -0
  8. package/dist/commands/init-template.d.ts +12 -0
  9. package/dist/commands/init-template.d.ts.map +1 -0
  10. package/dist/commands/init-template.js +168 -0
  11. package/dist/commands/init-template.js.map +1 -0
  12. package/dist/commands/related.d.ts +13 -0
  13. package/dist/commands/related.d.ts.map +1 -0
  14. package/dist/commands/related.js +193 -0
  15. package/dist/commands/related.js.map +1 -0
  16. package/dist/commands/stats.d.ts +8 -0
  17. package/dist/commands/stats.d.ts.map +1 -0
  18. package/dist/commands/stats.js +62 -0
  19. package/dist/commands/stats.js.map +1 -0
  20. package/dist/commands/suite-case.d.ts +20 -0
  21. package/dist/commands/suite-case.d.ts.map +1 -0
  22. package/dist/commands/suite-case.js +83 -0
  23. package/dist/commands/suite-case.js.map +1 -0
  24. package/dist/commands/update.d.ts +33 -0
  25. package/dist/commands/update.d.ts.map +1 -0
  26. package/dist/commands/update.js +159 -0
  27. package/dist/commands/update.js.map +1 -0
  28. package/dist/commands/validate-list.d.ts +36 -0
  29. package/dist/commands/validate-list.d.ts.map +1 -0
  30. package/dist/commands/validate-list.js +270 -0
  31. package/dist/commands/validate-list.js.map +1 -0
  32. package/dist/core.d.ts +30 -0
  33. package/dist/core.d.ts.map +1 -0
  34. package/dist/core.js +143 -0
  35. package/dist/core.js.map +1 -0
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +218 -0
  39. package/dist/index.js.map +1 -0
  40. package/package.json +39 -0
@@ -0,0 +1,193 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { detectEntityType, normalizeTlogPath, parseYaml, stringifyYaml, validateCase, validateSuite } from "@tlog/shared";
5
+ import { CliError, emitSuccess, ensureDirectory, formatOf, walkYamlFiles } from "../core.js";
6
+ function writeYamlFileAtomicSync(path, value) {
7
+ const content = stringifyYaml(value);
8
+ const parent = dirname(path);
9
+ mkdirSync(parent, { recursive: true });
10
+ const tempPath = `${path}.${randomUUID()}.tmp`;
11
+ writeFileSync(tempPath, content, "utf8");
12
+ renameSync(tempPath, path);
13
+ }
14
+ function unique(values) {
15
+ return Array.from(new Set(values));
16
+ }
17
+ function csvCell(value) {
18
+ if (value.includes(",") || value.includes("\"") || value.includes("\n")) {
19
+ return `"${value.replaceAll("\"", "\"\"")}"`;
20
+ }
21
+ return value;
22
+ }
23
+ function toCsv(headers, rows) {
24
+ return [headers.join(","), ...rows.map((row) => row.map(csvCell).join(","))].join("\n");
25
+ }
26
+ function toAlignedTable(headers, rows) {
27
+ const widths = headers.map((header, index) => Math.max(header.length, ...rows.map((row) => (row[index] ?? "").length)));
28
+ const padRow = (row) => row.map((cell, index) => cell.padEnd(widths[index])).join(" ");
29
+ return [padRow(headers), ...rows.map((row) => padRow(row))].join("\n");
30
+ }
31
+ export function runRelatedSync(cwd, options, globalOptions) {
32
+ const format = formatOf(globalOptions);
33
+ const rootDir = resolve(cwd, options.dir);
34
+ ensureDirectory(rootDir, "Related sync directory does not exist");
35
+ const entities = walkYamlFiles(rootDir)
36
+ .map((path) => {
37
+ const type = detectEntityType(path);
38
+ if (type !== "suite" && type !== "case") {
39
+ return null;
40
+ }
41
+ try {
42
+ const raw = parseYaml(readFileSync(path, "utf8"));
43
+ const id = typeof raw.id === "string" ? raw.id : "";
44
+ const related = Array.isArray(raw.related)
45
+ ? raw.related.filter((value) => typeof value === "string")
46
+ : [];
47
+ if (!id) {
48
+ return null;
49
+ }
50
+ return { id, path, type, related, raw };
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ })
56
+ .filter((item) => item !== null);
57
+ const index = new Map();
58
+ const duplicateIds = [];
59
+ for (const entity of entities) {
60
+ if (index.has(entity.id)) {
61
+ duplicateIds.push(entity.id);
62
+ continue;
63
+ }
64
+ index.set(entity.id, entity);
65
+ }
66
+ if (duplicateIds.length > 0) {
67
+ throw new CliError("Duplicate ids found. related sync requires unique ids.", {
68
+ details: unique(duplicateIds)
69
+ });
70
+ }
71
+ const sources = options.id !== undefined
72
+ ? (() => {
73
+ const entity = index.get(options.id);
74
+ if (!entity) {
75
+ throw new CliError(`id not found: ${options.id}`);
76
+ }
77
+ return [entity];
78
+ })()
79
+ : entities;
80
+ const unresolved = [];
81
+ const additions = new Map();
82
+ for (const source of sources) {
83
+ for (const targetId of source.related) {
84
+ const target = index.get(targetId);
85
+ if (!target) {
86
+ unresolved.push({ sourceId: source.id, targetId });
87
+ continue;
88
+ }
89
+ if (target.id === source.id || target.related.includes(source.id)) {
90
+ continue;
91
+ }
92
+ const set = additions.get(target.path) ?? new Set();
93
+ set.add(source.id);
94
+ additions.set(target.path, set);
95
+ }
96
+ }
97
+ const changedFiles = [];
98
+ for (const [targetPath, sourceIds] of additions.entries()) {
99
+ const entity = entities.find((item) => item.path === targetPath);
100
+ if (!entity) {
101
+ continue;
102
+ }
103
+ const next = {
104
+ ...entity.raw,
105
+ related: unique([...(entity.related ?? []), ...Array.from(sourceIds)])
106
+ };
107
+ const validation = entity.type === "suite" ? validateSuite(next) : validateCase(next);
108
+ if (!validation.ok || !validation.data) {
109
+ throw new CliError(`Related sync validation failed: ${entity.id}`, {
110
+ details: validation.errors.map((item) => `${item.path}: ${item.message}`)
111
+ });
112
+ }
113
+ if (!globalOptions.dryRun) {
114
+ writeYamlFileAtomicSync(targetPath, next);
115
+ }
116
+ changedFiles.push(normalizeTlogPath(targetPath));
117
+ }
118
+ emitSuccess("related sync", {
119
+ dir: normalizeTlogPath(rootDir),
120
+ targetId: options.id ?? null,
121
+ dryRun: globalOptions.dryRun,
122
+ syncedCount: changedFiles.length,
123
+ changedFiles,
124
+ unresolved
125
+ }, format, [
126
+ `${globalOptions.dryRun ? "Would sync" : "Synced"} related links: ${changedFiles.length}`,
127
+ ...(unresolved.length > 0 ? unresolved.map((item) => `UNRESOLVED ${item.sourceId} -> ${item.targetId}`) : [])
128
+ ]);
129
+ }
130
+ export function runRelatedList(cwd, options, globalOptions) {
131
+ const format = formatOf(globalOptions, options.format);
132
+ const rootDir = resolve(cwd, options.dir);
133
+ ensureDirectory(rootDir, "Related list directory does not exist");
134
+ const entities = walkYamlFiles(rootDir)
135
+ .map((path) => {
136
+ const type = detectEntityType(path);
137
+ if (type !== "suite" && type !== "case") {
138
+ return null;
139
+ }
140
+ try {
141
+ const raw = parseYaml(readFileSync(path, "utf8"));
142
+ const id = typeof raw.id === "string" ? raw.id : "";
143
+ const related = Array.isArray(raw.related)
144
+ ? raw.related.filter((value) => typeof value === "string")
145
+ : [];
146
+ if (!id) {
147
+ return null;
148
+ }
149
+ return { id, path, type, related };
150
+ }
151
+ catch {
152
+ return null;
153
+ }
154
+ })
155
+ .filter((item) => item !== null);
156
+ const index = new Map(entities.map((item) => [item.id, item]));
157
+ const source = index.get(options.id);
158
+ if (!source) {
159
+ throw new CliError(`id not found: ${options.id}`);
160
+ }
161
+ const resolved = [];
162
+ const unresolved = [];
163
+ for (const relatedId of source.related) {
164
+ const target = index.get(relatedId);
165
+ if (!target) {
166
+ unresolved.push(relatedId);
167
+ continue;
168
+ }
169
+ resolved.push({
170
+ type: target.type,
171
+ id: target.id,
172
+ path: normalizeTlogPath(target.path)
173
+ });
174
+ }
175
+ const payload = {
176
+ id: source.id,
177
+ path: normalizeTlogPath(source.path),
178
+ resolved,
179
+ unresolved
180
+ };
181
+ if (format === "json") {
182
+ process.stdout.write(`${JSON.stringify({ ok: true, command: "related list", data: payload }, null, 2)}\n`);
183
+ return;
184
+ }
185
+ const headers = ["status", "type", "id", "path"];
186
+ const rows = [
187
+ ...resolved.map((item) => ["resolved", item.type, item.id, item.path]),
188
+ ...unresolved.map((item) => ["unresolved", "-", item, "-"])
189
+ ];
190
+ const content = format === "csv" ? toCsv(headers, rows) : toAlignedTable(headers, rows);
191
+ process.stdout.write(`${content}\n`);
192
+ }
193
+ //# sourceMappingURL=related.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"related.js","sourceRoot":"","sources":["../../src/commands/related.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import { type GlobalOptions } from "../core.js";
2
+ export interface SuiteStatsOptions {
3
+ dir: string;
4
+ id: string;
5
+ format?: string;
6
+ }
7
+ export declare function runSuiteStats(cwd: string, options: SuiteStatsOptions, globalOptions: GlobalOptions): void;
8
+ //# sourceMappingURL=stats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.d.ts","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"AAUA,OAAO,EAAmE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjH,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AA0BD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CA4CzG"}
@@ -0,0 +1,62 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { calculateBurndown, detectEntityType, normalizeTlogPath, parseYaml } from "@tlog/shared";
4
+ import { CliError, emitSuccess, ensureDirectory, formatOf, walkYamlFiles } from "../core.js";
5
+ function findSuitePath(rootDir, id) {
6
+ const matches = walkYamlFiles(rootDir).filter((path) => {
7
+ if (detectEntityType(path) !== "suite") {
8
+ return false;
9
+ }
10
+ try {
11
+ const raw = parseYaml(readFileSync(path, "utf8"));
12
+ return raw.id === id;
13
+ }
14
+ catch {
15
+ return false;
16
+ }
17
+ });
18
+ if (matches.length === 0) {
19
+ throw new CliError(`suite not found: ${id}`);
20
+ }
21
+ if (matches.length > 1) {
22
+ throw new CliError(`Multiple suite entries found for id: ${id}`, {
23
+ details: matches.map((item) => normalizeTlogPath(item))
24
+ });
25
+ }
26
+ return matches[0];
27
+ }
28
+ export function runSuiteStats(cwd, options, globalOptions) {
29
+ const format = formatOf(globalOptions, options.format);
30
+ const rootDir = resolve(cwd, options.dir);
31
+ ensureDirectory(rootDir, "Suite search directory does not exist");
32
+ const suitePath = findSuitePath(rootDir, options.id);
33
+ const suite = parseYaml(readFileSync(suitePath, "utf8"));
34
+ const suiteDir = dirname(suitePath);
35
+ const cases = walkYamlFiles(suiteDir)
36
+ .filter((path) => detectEntityType(path) === "case")
37
+ .map((path) => parseYaml(readFileSync(path, "utf8")));
38
+ const scopedCases = suite.scoped === true ? cases.filter((item) => item.scoped === true) : [];
39
+ const statusCounts = {
40
+ todo: scopedCases.filter((item) => item.status === "todo").length,
41
+ doing: scopedCases.filter((item) => item.status === "doing").length,
42
+ done: scopedCases.filter((item) => item.status === "done").length,
43
+ null: scopedCases.filter((item) => item.status === null).length,
44
+ total: scopedCases.length
45
+ };
46
+ const scheduled = calculateBurndown(scopedCases, suite.duration.scheduled.start, suite.duration.scheduled.end);
47
+ const actual = calculateBurndown(scopedCases, suite.duration.actual.start, suite.duration.actual.end);
48
+ emitSuccess("suite stats", {
49
+ id: suite.id,
50
+ path: normalizeTlogPath(suitePath),
51
+ statusCounts,
52
+ duration: suite.duration,
53
+ scheduled,
54
+ actual
55
+ }, format, [
56
+ `suite=${suite.id}`,
57
+ `status todo=${statusCounts.todo} doing=${statusCounts.doing} done=${statusCounts.done} null=${statusCounts.null} total=${statusCounts.total}`,
58
+ `scheduled ${suite.duration.scheduled.start}..${suite.duration.scheduled.end} buckets=${scheduled.buckets.length}`,
59
+ `actual ${suite.duration.actual.start}..${suite.duration.actual.end} buckets=${actual.buckets.length}`
60
+ ]);
61
+ }
62
+ //# sourceMappingURL=stats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stats.js","sourceRoot":"","sources":["../../src/commands/stats.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EACL,iBAAiB,EACjB,gBAAgB,EAChB,iBAAiB,EACjB,SAAS,EAGV,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,aAAa,EAAsB,MAAM,YAAY,CAAC;AAQjH,SAAS,aAAa,CAAC,OAAe,EAAE,EAAU;IAChD,MAAM,OAAO,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE;QACrD,IAAI,gBAAgB,CAAC,IAAI,CAAC,KAAK,OAAO,EAAE,CAAC;YACvC,OAAO,KAAK,CAAC;QACf,CAAC;QACD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,SAAS,CAA0B,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC;YAC3E,OAAO,GAAG,CAAC,EAAE,KAAK,EAAE,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,IAAI,QAAQ,CAAC,oBAAoB,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,CAAC,wCAAwC,EAAE,EAAE,EAAE;YAC/D,OAAO,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,CAAC,CAAC;SACxD,CAAC,CAAC;IACL,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,OAA0B,EAAE,aAA4B;IACjG,MAAM,MAAM,GAAG,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,CAAC,CAAC;IACvD,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC;IAC1C,eAAe,CAAC,OAAO,EAAE,uCAAuC,CAAC,CAAC;IAElE,MAAM,SAAS,GAAG,aAAa,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,SAAS,CAAQ,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;IAChE,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,CAAC;IAEpC,MAAM,KAAK,GAAG,aAAa,CAAC,QAAQ,CAAC;SAClC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,MAAM,CAAC;SACnD,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,CAAW,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;IAElE,MAAM,WAAW,GAAG,KAAK,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAE9F,MAAM,YAAY,GAAG;QACnB,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM;QACjE,KAAK,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC,MAAM;QACnE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC,MAAM;QACjE,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC,MAAM;QAC/D,KAAK,EAAE,WAAW,CAAC,MAAM;KAC1B,CAAC;IAEF,MAAM,SAAS,GAAG,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAC/G,MAAM,MAAM,GAAG,iBAAiB,CAAC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IAEtG,WAAW,CACT,aAAa,EACb;QACE,EAAE,EAAE,KAAK,CAAC,EAAE;QACZ,IAAI,EAAE,iBAAiB,CAAC,SAAS,CAAC;QAClC,YAAY;QACZ,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,SAAS;QACT,MAAM;KACP,EACD,MAAM,EACN;QACE,SAAS,KAAK,CAAC,EAAE,EAAE;QACnB,eAAe,YAAY,CAAC,IAAI,UAAU,YAAY,CAAC,KAAK,SAAS,YAAY,CAAC,IAAI,SAAS,YAAY,CAAC,IAAI,UAAU,YAAY,CAAC,KAAK,EAAE;QAC9I,aAAa,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,KAAK,KAAK,KAAK,CAAC,QAAQ,CAAC,SAAS,CAAC,GAAG,YAAY,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE;QAClH,UAAU,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,KAAK,KAAK,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC,GAAG,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE;KACvG,CACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ import { type GlobalOptions } from "../core.js";
2
+ export interface SuiteCreateOptions {
3
+ dir: string;
4
+ id: string;
5
+ title: string;
6
+ owners?: string;
7
+ tags?: string;
8
+ scheduledStart?: string;
9
+ scheduledEnd?: string;
10
+ }
11
+ export interface CaseCreateOptions {
12
+ suiteDir: string;
13
+ id: string;
14
+ title: string;
15
+ status?: string;
16
+ tags?: string;
17
+ }
18
+ export declare function runSuiteCreate(cwd: string, options: SuiteCreateOptions, globalOptions: GlobalOptions): void;
19
+ export declare function runCaseCreate(cwd: string, options: CaseCreateOptions, globalOptions: GlobalOptions): void;
20
+ //# sourceMappingURL=suite-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite-case.d.ts","sourceRoot":"","sources":["../../src/commands/suite-case.ts"],"names":[],"mappings":"AAQA,OAAO,EASL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAMD,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAqD3G;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAyCzG"}
@@ -0,0 +1,83 @@
1
+ import { existsSync, mkdirSync, writeFileSync } from "node:fs";
2
+ import { dirname, join, normalize, resolve } from "node:path";
3
+ import { asTlogDateString, buildDefaultCase, buildDefaultSuite, stringifyYaml } from "@tlog/shared";
4
+ import { CliError, emitSuccess, ensureDirectory, ensureValidId, findDuplicateId, formatOf, splitCsv, toStatus } from "../core.js";
5
+ function safePath(path) {
6
+ return normalize(path).split("\\").join("/");
7
+ }
8
+ export function runSuiteCreate(cwd, options, globalOptions) {
9
+ const format = formatOf(globalOptions);
10
+ const rootDir = resolve(cwd, options.dir);
11
+ mkdirSync(rootDir, { recursive: true });
12
+ ensureValidId(options.id, "suite id");
13
+ const existing = findDuplicateId(rootDir, options.id);
14
+ if (existing) {
15
+ throw new CliError(`ID already exists: ${options.id}`, {
16
+ details: [safePath(existing)]
17
+ });
18
+ }
19
+ const suiteDir = join(rootDir, options.id);
20
+ const indexPath = join(suiteDir, "index.yaml");
21
+ if (existsSync(indexPath)) {
22
+ throw new CliError(`Suite file already exists: ${safePath(indexPath)}`);
23
+ }
24
+ const today = new Date().toISOString().slice(0, 10);
25
+ const suite = buildDefaultSuite({
26
+ id: options.id,
27
+ title: options.title,
28
+ owners: splitCsv(options.owners),
29
+ tags: splitCsv(options.tags),
30
+ duration: {
31
+ scheduled: {
32
+ start: asTlogDateString(options.scheduledStart ?? today),
33
+ end: asTlogDateString(options.scheduledEnd ?? options.scheduledStart ?? today)
34
+ },
35
+ actual: {
36
+ start: asTlogDateString(today),
37
+ end: asTlogDateString(today)
38
+ }
39
+ }
40
+ });
41
+ if (!globalOptions.dryRun) {
42
+ mkdirSync(suiteDir, { recursive: true });
43
+ writeFileSync(indexPath, stringifyYaml(suite), "utf8");
44
+ }
45
+ emitSuccess("suite create", {
46
+ id: options.id,
47
+ path: safePath(indexPath),
48
+ dryRun: globalOptions.dryRun
49
+ }, format, [`${globalOptions.dryRun ? "Would create" : "Created"}: ${safePath(indexPath)}`]);
50
+ }
51
+ export function runCaseCreate(cwd, options, globalOptions) {
52
+ const format = formatOf(globalOptions);
53
+ const suiteDir = resolve(cwd, options.suiteDir);
54
+ ensureDirectory(suiteDir, "Suite directory does not exist");
55
+ ensureValidId(options.id, "case id");
56
+ const rootDir = dirname(suiteDir);
57
+ const existing = findDuplicateId(rootDir, options.id);
58
+ if (existing) {
59
+ throw new CliError(`ID already exists: ${options.id}`, {
60
+ details: [safePath(existing)]
61
+ });
62
+ }
63
+ const casePath = join(suiteDir, `${options.id}.testcase.yaml`);
64
+ if (existsSync(casePath)) {
65
+ throw new CliError(`Case file already exists: ${safePath(casePath)}`);
66
+ }
67
+ const status = options.status === undefined ? undefined : toStatus(options.status);
68
+ const testCase = buildDefaultCase({
69
+ id: options.id,
70
+ title: options.title,
71
+ status: status === null ? undefined : status,
72
+ tags: splitCsv(options.tags)
73
+ });
74
+ if (!globalOptions.dryRun) {
75
+ writeFileSync(casePath, stringifyYaml(testCase), "utf8");
76
+ }
77
+ emitSuccess("case create", {
78
+ id: options.id,
79
+ path: safePath(casePath),
80
+ dryRun: globalOptions.dryRun
81
+ }, format, [`${globalOptions.dryRun ? "Would create" : "Created"}: ${safePath(casePath)}`]);
82
+ }
83
+ //# sourceMappingURL=suite-case.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"suite-case.js","sourceRoot":"","sources":["../../src/commands/suite-case.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import { type GlobalOptions } from "../core.js";
2
+ export interface SuiteUpdateOptions {
3
+ dir: string;
4
+ id: string;
5
+ title?: string;
6
+ description?: string;
7
+ tags?: string;
8
+ owners?: string;
9
+ related?: string;
10
+ remarks?: string;
11
+ scoped?: string;
12
+ scheduledStart?: string;
13
+ scheduledEnd?: string;
14
+ actualStart?: string;
15
+ actualEnd?: string;
16
+ }
17
+ export interface CaseUpdateOptions {
18
+ dir: string;
19
+ id: string;
20
+ status?: string;
21
+ tags?: string;
22
+ description?: string;
23
+ operations?: string;
24
+ related?: string;
25
+ remarks?: string;
26
+ scoped?: string;
27
+ completedDay?: string;
28
+ testsFile?: string;
29
+ issuesFile?: string;
30
+ }
31
+ export declare function runSuiteUpdate(cwd: string, options: SuiteUpdateOptions, globalOptions: GlobalOptions): void;
32
+ export declare function runCaseUpdate(cwd: string, options: CaseUpdateOptions, globalOptions: GlobalOptions): void;
33
+ //# sourceMappingURL=update.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"AAgBA,OAAO,EAOL,KAAK,aAAa,EACnB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,kBAAkB;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,GAAG,EAAE,MAAM,CAAC;IACZ,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAsED,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAsD3G;AAED,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,aAAa,GAAG,IAAI,CAmDzG"}
@@ -0,0 +1,159 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import { dirname, resolve } from "node:path";
4
+ import { asTlogDateString, detectEntityType, normalizeTlogPath, parseYaml, stringifyYaml, validateCase, validateSuite } from "@tlog/shared";
5
+ import { CliError, emitSuccess, formatOf, splitCsv, toStatus, walkYamlFiles } from "../core.js";
6
+ function parseOptionalBoolean(value, optionName) {
7
+ if (value === undefined) {
8
+ return undefined;
9
+ }
10
+ if (value === "true") {
11
+ return true;
12
+ }
13
+ if (value === "false") {
14
+ return false;
15
+ }
16
+ throw new CliError(`Invalid ${optionName}: ${value}. Expected true|false.`);
17
+ }
18
+ function writeYamlFileAtomicSync(path, value) {
19
+ const content = stringifyYaml(value);
20
+ const parent = dirname(path);
21
+ mkdirSync(parent, { recursive: true });
22
+ const tempPath = `${path}.${randomUUID()}.tmp`;
23
+ writeFileSync(tempPath, content, "utf8");
24
+ renameSync(tempPath, path);
25
+ }
26
+ function findById(rootDir, id, type) {
27
+ const matches = walkYamlFiles(rootDir).filter((path) => {
28
+ if (detectEntityType(path) !== type) {
29
+ return false;
30
+ }
31
+ try {
32
+ const raw = parseYaml(readFileSync(path, "utf8"));
33
+ return raw.id === id;
34
+ }
35
+ catch {
36
+ return false;
37
+ }
38
+ });
39
+ if (matches.length === 0) {
40
+ throw new CliError(`${type} not found: ${id}`);
41
+ }
42
+ if (matches.length > 1) {
43
+ throw new CliError(`Multiple ${type} entries found for id: ${id}`, {
44
+ details: matches.map((item) => normalizeTlogPath(item))
45
+ });
46
+ }
47
+ return matches[0];
48
+ }
49
+ function readJsonArrayFile(cwd, path, label) {
50
+ if (!path) {
51
+ return undefined;
52
+ }
53
+ const fullPath = resolve(cwd, path);
54
+ if (!existsSync(fullPath)) {
55
+ throw new CliError(`${label} file not found: ${fullPath}`);
56
+ }
57
+ try {
58
+ const data = JSON.parse(readFileSync(fullPath, "utf8"));
59
+ if (!Array.isArray(data)) {
60
+ throw new CliError(`${label} must be an array: ${fullPath}`);
61
+ }
62
+ return data;
63
+ }
64
+ catch (error) {
65
+ if (error instanceof CliError) {
66
+ throw error;
67
+ }
68
+ throw new CliError(`Invalid ${label} JSON: ${fullPath}`);
69
+ }
70
+ }
71
+ export function runSuiteUpdate(cwd, options, globalOptions) {
72
+ const format = formatOf(globalOptions);
73
+ const rootDir = resolve(cwd, options.dir);
74
+ const targetPath = findById(rootDir, options.id, "suite");
75
+ const current = parseYaml(readFileSync(targetPath, "utf8"));
76
+ const scoped = parseOptionalBoolean(options.scoped, "scoped");
77
+ const updated = {
78
+ ...current,
79
+ ...(options.title !== undefined ? { title: options.title } : {}),
80
+ ...(options.description !== undefined ? { description: options.description } : {}),
81
+ ...(options.tags !== undefined ? { tags: splitCsv(options.tags) } : {}),
82
+ ...(options.owners !== undefined ? { owners: splitCsv(options.owners) } : {}),
83
+ ...(options.related !== undefined ? { related: splitCsv(options.related) } : {}),
84
+ ...(options.remarks !== undefined ? { remarks: splitCsv(options.remarks) } : {}),
85
+ ...(scoped !== undefined ? { scoped } : {}),
86
+ duration: {
87
+ scheduled: {
88
+ start: asTlogDateString(options.scheduledStart ?? current.duration.scheduled.start),
89
+ end: asTlogDateString(options.scheduledEnd ?? current.duration.scheduled.end)
90
+ },
91
+ actual: {
92
+ start: asTlogDateString(options.actualStart ?? current.duration.actual.start),
93
+ end: asTlogDateString(options.actualEnd ?? current.duration.actual.end)
94
+ }
95
+ }
96
+ };
97
+ const validation = validateSuite(updated);
98
+ if (!validation.ok || !validation.data) {
99
+ throw new CliError("Suite update validation failed", {
100
+ details: validation.errors.map((item) => `${item.path}: ${item.message}`)
101
+ });
102
+ }
103
+ if (!globalOptions.dryRun) {
104
+ writeYamlFileAtomicSync(targetPath, updated);
105
+ }
106
+ emitSuccess("suite update", {
107
+ id: updated.id,
108
+ path: normalizeTlogPath(targetPath),
109
+ dryRun: globalOptions.dryRun,
110
+ validation: {
111
+ ok: true,
112
+ errorCount: 0,
113
+ warningCount: validation.warnings.length
114
+ }
115
+ }, format, [`${globalOptions.dryRun ? "Would update" : "Updated"}: ${normalizeTlogPath(targetPath)}`]);
116
+ }
117
+ export function runCaseUpdate(cwd, options, globalOptions) {
118
+ const format = formatOf(globalOptions);
119
+ const rootDir = resolve(cwd, options.dir);
120
+ const targetPath = findById(rootDir, options.id, "case");
121
+ const current = parseYaml(readFileSync(targetPath, "utf8"));
122
+ const scoped = parseOptionalBoolean(options.scoped, "scoped");
123
+ const testItems = readJsonArrayFile(cwd, options.testsFile, "tests");
124
+ const issues = readJsonArrayFile(cwd, options.issuesFile, "issues");
125
+ const status = options.status === undefined ? undefined : toStatus(options.status);
126
+ const updated = {
127
+ ...current,
128
+ ...(options.description !== undefined ? { description: options.description } : {}),
129
+ ...(options.tags !== undefined ? { tags: splitCsv(options.tags) } : {}),
130
+ ...(options.operations !== undefined ? { operations: splitCsv(options.operations) } : {}),
131
+ ...(options.related !== undefined ? { related: splitCsv(options.related) } : {}),
132
+ ...(options.remarks !== undefined ? { remarks: splitCsv(options.remarks) } : {}),
133
+ ...(scoped !== undefined ? { scoped } : {}),
134
+ ...(status !== undefined ? { status } : {}),
135
+ ...(options.completedDay !== undefined ? { completedDay: options.completedDay === "null" ? null : asTlogDateString(options.completedDay) } : {}),
136
+ ...(testItems !== undefined ? { tests: testItems } : {}),
137
+ ...(issues !== undefined ? { issues } : {})
138
+ };
139
+ const validation = validateCase(updated);
140
+ if (!validation.ok || !validation.data) {
141
+ throw new CliError("Case update validation failed", {
142
+ details: validation.errors.map((item) => `${item.path}: ${item.message}`)
143
+ });
144
+ }
145
+ if (!globalOptions.dryRun) {
146
+ writeYamlFileAtomicSync(targetPath, updated);
147
+ }
148
+ emitSuccess("case update", {
149
+ id: updated.id,
150
+ path: normalizeTlogPath(targetPath),
151
+ dryRun: globalOptions.dryRun,
152
+ validation: {
153
+ ok: true,
154
+ errorCount: 0,
155
+ warningCount: validation.warnings.length
156
+ }
157
+ }, format, [`${globalOptions.dryRun ? "Would update" : "Updated"}: ${normalizeTlogPath(targetPath)}`]);
158
+ }
159
+ //# sourceMappingURL=update.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"update.js","sourceRoot":"","sources":["../../src/commands/update.ts"],"names":[],"mappings":"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"}