diff --git a/src/find-issue.ts b/src/find-issue.ts index 2b45474..88f19fc 100644 --- a/src/find-issue.ts +++ b/src/find-issue.ts @@ -1,13 +1,18 @@ // src/find-issue.ts -import { readFileSync } from 'node:fs'; import { findMarkedIssue } from './issue.js'; +import { readJsonOrNull } from './finalize.js'; import { ISSUE_MARKER } from './report-issue.js'; import type { IssueRef } from './issue.js'; +// 畸形輸入(缺檔、壞 JSON、非陣列)一律降級為「找不到」→ 空字串 +export function findIssueNumber(input: unknown): string { + if (!Array.isArray(input)) return ''; + const n = findMarkedIssue(input as IssueRef[], ISSUE_MARKER); + return n === null ? '' : String(n); +} + // CLI: find-issue.ts // 檔內容為 `gh issue list --json number,body` 的 JSON 陣列;印出帶 marker 的 number(無則印空字串) if (import.meta.url === `file://${process.argv[1]}`) { - const issues = JSON.parse(readFileSync(process.argv[2], 'utf8')) as IssueRef[]; - const n = findMarkedIssue(issues, ISSUE_MARKER); - process.stdout.write(n === null ? '' : String(n)); + process.stdout.write(findIssueNumber(readJsonOrNull(process.argv[2]))); } diff --git a/test/find-issue.test.ts b/test/find-issue.test.ts new file mode 100644 index 0000000..538dd75 --- /dev/null +++ b/test/find-issue.test.ts @@ -0,0 +1,28 @@ +// test/find-issue.test.ts +import { describe, it, expect } from 'vitest'; +import { writeFileSync, mkdtempSync } from 'node:fs'; +import { tmpdir } from 'node:os'; +import { join } from 'node:path'; +import { findIssueNumber } from '../src/find-issue.js'; +import { readJsonOrNull } from '../src/finalize.js'; +import { ISSUE_MARKER } from '../src/report-issue.js'; + +describe('findIssueNumber', () => { + it('returns the marked issue number as a string', () => { + expect(findIssueNumber([{ number: 7, body: `x\n${ISSUE_MARKER}` }, { number: 1, body: 'y' }])).toBe('7'); + }); + it('returns empty string when no issue carries the marker', () => { + expect(findIssueNumber([{ number: 1, body: 'x' }])).toBe(''); + }); + it('degrades to empty string on null input (missing/malformed file)', () => { + expect(findIssueNumber(null)).toBe(''); + }); + it('degrades to empty string on non-array JSON', () => { + expect(findIssueNumber({ number: 7, body: ISSUE_MARKER })).toBe(''); + }); + it('degrades instead of throwing when fed a malformed JSON file via readJsonOrNull', () => { + const file = join(mkdtempSync(join(tmpdir(), 'find-issue-')), 'issues.json'); + writeFileSync(file, '{not json'); + expect(findIssueNumber(readJsonOrNull(file))).toBe(''); + }); +});