From 71f2f3d6e66e6c0070d460aff99807d7e2f95b28 Mon Sep 17 00:00:00 2001 From: jackwener Date: Sun, 15 Mar 2026 15:43:33 +0800 Subject: [PATCH] fix: integrate community bugfixes for PRs 1, 4, 6 and Issue 7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix zhihu id truncation issue beyond safe integer - Add json filter to template engine - Escape evaluate args in browser scripts using json filter - Resolve module not found bug for index.ts Co-authored-by: 袁鑫 Co-authored-by: zhenxing jiang Co-authored-by: wangruotian Co-authored-by: 滕文证 <83223457+tenwz@users.noreply.github.com> --- src/clis/reddit/hot.yaml | 5 +++-- src/clis/zhihu/hot.yaml | 8 ++++++-- src/clis/zhihu/search.yaml | 4 +++- src/pipeline/template.test.ts | 6 ++++++ src/pipeline/template.ts | 4 +++- 5 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/clis/reddit/hot.yaml b/src/clis/reddit/hot.yaml index 53e65f8..b1b53a1 100644 --- a/src/clis/reddit/hot.yaml +++ b/src/clis/reddit/hot.yaml @@ -18,9 +18,10 @@ pipeline: - evaluate: | (async () => { - const sub = '${{ args.subreddit }}'; + const sub = ${{ args.subreddit | json }}; const path = sub ? '/r/' + sub + '/hot.json' : '/hot.json'; - const res = await fetch(path + '?limit=${{ args.limit }}&raw_json=1', { + const limit = ${{ args.limit }}; + const res = await fetch(path + '?limit=' + limit + '&raw_json=1', { credentials: 'include' }); const d = await res.json(); diff --git a/src/clis/zhihu/hot.yaml b/src/clis/zhihu/hot.yaml index a754d1c..1802f96 100644 --- a/src/clis/zhihu/hot.yaml +++ b/src/clis/zhihu/hot.yaml @@ -17,12 +17,16 @@ pipeline: const res = await fetch('https://www.zhihu.com/api/v3/feed/topstory/hot-lists/total?limit=50', { credentials: 'include' }); - const d = await res.json(); + const text = await res.text(); + const d = JSON.parse( + text.replace(/("id"\s*:\s*)(\d{16,})/g, '$1"$2"') + ); return (d?.data || []).map((item) => { const t = item.target || {}; + const questionId = t.id == null ? '' : String(t.id); return { title: t.title, - url: 'https://www.zhihu.com/question/' + t.id, + url: 'https://www.zhihu.com/question/' + questionId, answer_count: t.answer_count, follower_count: t.follower_count, heat: item.detail_text || '', diff --git a/src/clis/zhihu/search.yaml b/src/clis/zhihu/search.yaml index ab43d94..a192bcc 100644 --- a/src/clis/zhihu/search.yaml +++ b/src/clis/zhihu/search.yaml @@ -19,7 +19,9 @@ pipeline: - evaluate: | (async () => { const strip = (html) => (html || '').replace(/<[^>]+>/g, '').replace(/ /g, ' ').replace(/</g, '<').replace(/>/g, '>').replace(/&/g, '&').replace(//g, '').replace(/<\/em>/g, '').trim(); - const res = await fetch('https://www.zhihu.com/api/v4/search_v3?q=' + encodeURIComponent('${{ args.keyword }}') + '&t=general&offset=0&limit=${{ args.limit }}', { + const keyword = ${{ args.keyword | json }}; + const limit = ${{ args.limit }}; + const res = await fetch('https://www.zhihu.com/api/v4/search_v3?q=' + encodeURIComponent(keyword) + '&t=general&offset=0&limit=' + limit, { credentials: 'include' }); const d = await res.json(); diff --git a/src/pipeline/template.test.ts b/src/pipeline/template.test.ts index b74c30d..ef02d8b 100644 --- a/src/pipeline/template.test.ts +++ b/src/pipeline/template.test.ts @@ -75,6 +75,12 @@ describe('evalExpr', () => { it('applies length filter', () => { expect(evalExpr('item.items | length', { item: { items: [1, 2, 3] } })).toBe(3); }); + it('applies json filter to strings with quotes', () => { + expect(evalExpr('args.keyword | json', { args: { keyword: "O'Reilly" } })).toBe('"O\'Reilly"'); + }); + it('applies json filter to nullish values', () => { + expect(evalExpr('args.keyword | json', { args: {} })).toBe('null'); + }); }); describe('render', () => { diff --git a/src/pipeline/template.ts b/src/pipeline/template.ts index 7cf0279..49ae588 100644 --- a/src/pipeline/template.ts +++ b/src/pipeline/template.ts @@ -75,7 +75,7 @@ export function evalExpr(expr: string, ctx: RenderContext): any { * Apply a named filter to a value. * Supported filters: * default(val), join(sep), upper, lower, truncate(n), trim, - * replace(old,new), keys, length, first, last + * replace(old,new), keys, length, first, last, json */ function applyFilter(filterExpr: string, value: any): any { const match = filterExpr.match(/^(\w+)(?:\((.+)\))?$/); @@ -117,6 +117,8 @@ function applyFilter(filterExpr: string, value: any): any { return Array.isArray(value) ? value[0] : value; case 'last': return Array.isArray(value) ? value[value.length - 1] : value; + case 'json': + return JSON.stringify(value ?? null); default: return value; }