@xihe-lab/tapd-core 2.0.0-rc.1 → 2.0.0-rc.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.
- package/README.md +23 -0
- package/dist/advisor/index.d.ts.map +1 -1
- package/dist/advisor/index.js +2 -0
- package/dist/advisor/index.js.map +1 -1
- package/dist/cache/read-cache.d.ts +136 -0
- package/dist/cache/read-cache.d.ts.map +1 -0
- package/dist/cache/read-cache.js +322 -0
- package/dist/cache/read-cache.js.map +1 -0
- package/dist/cache/read-cache.test.d.ts +2 -0
- package/dist/cache/read-cache.test.d.ts.map +1 -0
- package/dist/cache/read-cache.test.js +429 -0
- package/dist/cache/read-cache.test.js.map +1 -0
- package/dist/errors/index.d.ts +120 -0
- package/dist/errors/index.d.ts.map +1 -0
- package/dist/errors/index.js +429 -0
- package/dist/errors/index.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/registry/registry.d.ts +7 -0
- package/dist/registry/registry.d.ts.map +1 -1
- package/dist/registry/registry.js +9 -3
- package/dist/registry/registry.js.map +1 -1
- package/dist/registry/registry.test.js +293 -2
- package/dist/registry/registry.test.js.map +1 -1
- package/dist/registry/richtext-manifests.generated.d.ts +1 -1
- package/dist/registry/richtext-manifests.generated.d.ts.map +1 -1
- package/dist/registry/richtext-manifests.generated.js +1 -1
- package/dist/registry/richtext-manifests.generated.js.map +1 -1
- package/dist/registry/richtext.d.ts +9 -0
- package/dist/registry/richtext.d.ts.map +1 -1
- package/dist/registry/richtext.js +33 -15
- package/dist/registry/richtext.js.map +1 -1
- package/dist/registry/richtext.test.js +70 -7
- package/dist/registry/richtext.test.js.map +1 -1
- package/dist/richtext/attachment-anchor.d.ts +58 -0
- package/dist/richtext/attachment-anchor.d.ts.map +1 -0
- package/dist/richtext/attachment-anchor.js +221 -0
- package/dist/richtext/attachment-anchor.js.map +1 -0
- package/dist/richtext/attachment-anchor.test.d.ts +2 -0
- package/dist/richtext/attachment-anchor.test.d.ts.map +1 -0
- package/dist/richtext/attachment-anchor.test.js +149 -0
- package/dist/richtext/attachment-anchor.test.js.map +1 -0
- package/dist/richtext/escape.d.ts +7 -0
- package/dist/richtext/escape.d.ts.map +1 -0
- package/dist/richtext/escape.js +60 -0
- package/dist/richtext/escape.js.map +1 -0
- package/dist/richtext/index.d.ts +15 -0
- package/dist/richtext/index.d.ts.map +1 -0
- package/dist/richtext/index.js +35 -0
- package/dist/richtext/index.js.map +1 -0
- package/dist/richtext/mention.d.ts +49 -0
- package/dist/richtext/mention.d.ts.map +1 -0
- package/dist/richtext/mention.js +179 -0
- package/dist/richtext/mention.js.map +1 -0
- package/dist/richtext/mention.test.d.ts +2 -0
- package/dist/richtext/mention.test.d.ts.map +1 -0
- package/dist/richtext/mention.test.js +123 -0
- package/dist/richtext/mention.test.js.map +1 -0
- package/dist/richtext/pipeline.d.ts +5 -0
- package/dist/richtext/pipeline.d.ts.map +1 -0
- package/dist/richtext/pipeline.js +199 -0
- package/dist/richtext/pipeline.js.map +1 -0
- package/dist/richtext/round-trip.test.d.ts +2 -0
- package/dist/richtext/round-trip.test.d.ts.map +1 -0
- package/dist/richtext/round-trip.test.js +105 -0
- package/dist/richtext/round-trip.test.js.map +1 -0
- package/dist/sdk-routes.d.ts.map +1 -1
- package/dist/sdk-routes.js +4 -0
- package/dist/sdk-routes.js.map +1 -1
- package/dist/tapd-client.d.ts +79 -2
- package/dist/tapd-client.d.ts.map +1 -1
- package/dist/tapd-client.js +177 -24
- package/dist/tapd-client.js.map +1 -1
- package/dist/tools/attachment.d.ts +47 -0
- package/dist/tools/attachment.d.ts.map +1 -1
- package/dist/tools/attachment.js +278 -32
- package/dist/tools/attachment.js.map +1 -1
- package/dist/tools/attachment.test.d.ts +2 -0
- package/dist/tools/attachment.test.d.ts.map +1 -0
- package/dist/tools/attachment.test.js +432 -0
- package/dist/tools/attachment.test.js.map +1 -0
- package/dist/tools/board.js +22 -22
- package/dist/tools/board.js.map +1 -1
- package/dist/tools/bug.d.ts.map +1 -1
- package/dist/tools/bug.js +262 -259
- package/dist/tools/bug.js.map +1 -1
- package/dist/tools/changes.js +20 -20
- package/dist/tools/changes.js.map +1 -1
- package/dist/tools/comment.d.ts.map +1 -1
- package/dist/tools/comment.js +26 -23
- package/dist/tools/comment.js.map +1 -1
- package/dist/tools/custom-fields.js +16 -16
- package/dist/tools/custom-fields.js.map +1 -1
- package/dist/tools/image.js +2 -2
- package/dist/tools/image.js.map +1 -1
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/iteration.js +50 -50
- package/dist/tools/iteration.js.map +1 -1
- package/dist/tools/media.d.ts +9 -0
- package/dist/tools/media.d.ts.map +1 -0
- package/dist/tools/media.js +45 -0
- package/dist/tools/media.js.map +1 -0
- package/dist/tools/mini-comment.js +27 -27
- package/dist/tools/mini-comment.js.map +1 -1
- package/dist/tools/mini-item.js +83 -83
- package/dist/tools/mini-item.js.map +1 -1
- package/dist/tools/mini-workspace.js +5 -5
- package/dist/tools/mini-workspace.js.map +1 -1
- package/dist/tools/program.js +7 -7
- package/dist/tools/program.js.map +1 -1
- package/dist/tools/relations.js +14 -14
- package/dist/tools/relations.js.map +1 -1
- package/dist/tools/release.js +53 -53
- package/dist/tools/release.js.map +1 -1
- package/dist/tools/report.js +8 -8
- package/dist/tools/report.js.map +1 -1
- package/dist/tools/richtext-wiring.test.d.ts +2 -0
- package/dist/tools/richtext-wiring.test.d.ts.map +1 -0
- package/dist/tools/richtext-wiring.test.js +302 -0
- package/dist/tools/richtext-wiring.test.js.map +1 -0
- package/dist/tools/settings.js +77 -77
- package/dist/tools/settings.js.map +1 -1
- package/dist/tools/source.js +14 -14
- package/dist/tools/source.js.map +1 -1
- package/dist/tools/story.d.ts.map +1 -1
- package/dist/tools/story.js +123 -120
- package/dist/tools/story.js.map +1 -1
- package/dist/tools/task.d.ts.map +1 -1
- package/dist/tools/task.js +126 -123
- package/dist/tools/task.js.map +1 -1
- package/dist/tools/test.js +117 -117
- package/dist/tools/test.js.map +1 -1
- package/dist/tools/timesheet.js +23 -23
- package/dist/tools/timesheet.js.map +1 -1
- package/dist/tools/user.js +8 -8
- package/dist/tools/user.js.map +1 -1
- package/dist/tools/utility.d.ts +17 -0
- package/dist/tools/utility.d.ts.map +1 -1
- package/dist/tools/utility.js +204 -88
- package/dist/tools/utility.js.map +1 -1
- package/dist/tools/wiki.d.ts.map +1 -1
- package/dist/tools/wiki.js +71 -56
- package/dist/tools/wiki.js.map +1 -1
- package/dist/tools/workflow.js +26 -26
- package/dist/tools/workflow.js.map +1 -1
- package/dist/tools/workspace.js +16 -16
- package/dist/tools/workspace.js.map +1 -1
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +15 -11
- package/dist/tools/zz-acceptance-echo.d.ts +0 -3
- package/dist/tools/zz-acceptance-echo.d.ts.map +0 -1
- package/dist/tools/zz-acceptance-echo.js +0 -9
- package/dist/tools/zz-acceptance-echo.js.map +0 -1
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
// TAPD 2.0 rc.2 P3 接线(需求 1139814312001001548)—— 富文本保真转换主管道。
|
|
2
|
+
//
|
|
3
|
+
// B 侧语义库(core/richtext,纯函数)在转换器「token / 规则级」接入(B 的接线警告):
|
|
4
|
+
// - md→html(markdown-it core 规则,token 级):
|
|
5
|
+
// * `attach:` 链接(link_open..link_close 纯文本运行)→ 整段替换为 R6 data 五件套锚点
|
|
6
|
+
// (html_inline token;html:false 只影响解析不影响程序化 token 的渲染);
|
|
7
|
+
// * `@昵称` / `@@` 语义只在 inline children 的 **text token** 内替换(mention/escape 各自成 token);
|
|
8
|
+
// * code_inline / fence / html_* / image(含 alt)/ 链接内部(含 URL)一律跳过;
|
|
9
|
+
// 裸 URL(https://.../@name)内的 @ 由「连续非空白段含 ://」护栏跳过。
|
|
10
|
+
// * 禁止对整段输入直接调 fragment 级函数上线(会误伤代码段与 URL)——本模块即正确接线层。
|
|
11
|
+
// - html→md(turndown 规则级):
|
|
12
|
+
// * at-who <b> → `@昵称`(永不降级 **粗体**,R7);附件锚点 <a> → `[📎 name](attach:ws/id)`;
|
|
13
|
+
// 识别失败(href 缺失等)保留原节点 HTML,绝不猜测改写。
|
|
14
|
+
// * 保真规则先于 GFM 注册(FSD §8):turndown addRule 为 unshift 语义(后注册者先匹配),
|
|
15
|
+
// 故在 use(gfm) 之后再 addRule 即获得最高匹配优先级,并有规则优先级测试固化。
|
|
16
|
+
// * 文本节点字面 @ 保护走 turndown 实例 escape 钩子(escapeAtLiteralsForMd;
|
|
17
|
+
// CODE 内文本 isCode 天然绕过 escape,代码段 @ 不被加倍)。
|
|
18
|
+
//
|
|
19
|
+
// 单一实例共享给 md_to_html/html_to_md 工具(tools/utility.ts)与写管道
|
|
20
|
+
// (registry/richtext.ts 的 transformWriteArgs/transformReadData)——FSD §3.7:
|
|
21
|
+
// 所有富文本写工具与 pm 层场景共用同一条管道,免费获得 @/附件/图片能力。
|
|
22
|
+
import MarkdownIt from 'markdown-it';
|
|
23
|
+
import TurndownService from 'turndown';
|
|
24
|
+
import { gfm } from 'turndown-plugin-gfm';
|
|
25
|
+
import { attachmentAnchorHtml, attachmentAnchorNodeToMd, atWhoNodeToMd, escapeAtLiteralsForMd, findMentions, isAttachmentAnchorNode, isAtWhoNode, renderMentionHtml, } from './index.js';
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// md → html(markdown-it,token 级)
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/** `attach:<ws>/<id>`(与 richtext md 扩展语法的 ws/id 文法一致:排除空白、()、/)。 */
|
|
30
|
+
const ATTACH_HREF_RE = /^attach:([^()\s/]+)\/([^()\s/]+)$/i;
|
|
31
|
+
/**
|
|
32
|
+
* 裸 URL 防误伤:mention 候选往前回溯同一连续非空白段,段内含 `://` 视为 URL 的一部分
|
|
33
|
+
* (如 `https://e.com/@zhang`)。md 链接语法 `[t](url)` 的 URL 在 token attrs 里天然不进本层。
|
|
34
|
+
*/
|
|
35
|
+
function insideBareUrl(content, atIndex) {
|
|
36
|
+
let start = atIndex;
|
|
37
|
+
while (start > 0 && !/\s/.test(content[start - 1]))
|
|
38
|
+
start -= 1;
|
|
39
|
+
return content.slice(start, atIndex).includes('://');
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* 把一个 text token 的内容按 @ 语义拆分为 [text | html_inline] 串
|
|
43
|
+
* (镜像 richtext scanAtTokens 规则:@@ 优先、findMentions 已内建左边界判定)。
|
|
44
|
+
* 无任何语义变化时返回 null(调用方保留原 token,避免无谓重排)。
|
|
45
|
+
*/
|
|
46
|
+
function splitTextTokenAtSemantics(TokenCtor, token) {
|
|
47
|
+
const content = token.content;
|
|
48
|
+
const mentions = findMentions(content);
|
|
49
|
+
if (mentions.length === 0 && !content.includes('@@'))
|
|
50
|
+
return null;
|
|
51
|
+
const mentionByStart = new Map(mentions.map(m => [m.start, m]));
|
|
52
|
+
const out = [];
|
|
53
|
+
let plain = '';
|
|
54
|
+
const flush = () => {
|
|
55
|
+
if (plain === '')
|
|
56
|
+
return;
|
|
57
|
+
const text = new TokenCtor('text', '', 0);
|
|
58
|
+
text.content = plain;
|
|
59
|
+
out.push(text);
|
|
60
|
+
plain = '';
|
|
61
|
+
};
|
|
62
|
+
let i = 0;
|
|
63
|
+
let changed = false;
|
|
64
|
+
while (i < content.length) {
|
|
65
|
+
if (content[i] === '@') {
|
|
66
|
+
if (content[i + 1] === '@') {
|
|
67
|
+
plain += '@'; // md 转义 @@ → 字面 @
|
|
68
|
+
changed = true;
|
|
69
|
+
i += 2;
|
|
70
|
+
continue;
|
|
71
|
+
}
|
|
72
|
+
const mention = mentionByStart.get(i);
|
|
73
|
+
if (mention && !insideBareUrl(content, i)) {
|
|
74
|
+
flush();
|
|
75
|
+
const html = new TokenCtor('html_inline', '', 0);
|
|
76
|
+
html.content = renderMentionHtml(mention.name);
|
|
77
|
+
out.push(html);
|
|
78
|
+
changed = true;
|
|
79
|
+
i = mention.end;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
plain += content[i];
|
|
84
|
+
i += 1;
|
|
85
|
+
}
|
|
86
|
+
flush();
|
|
87
|
+
if (!changed || (out.length === 1 && out[0].type === 'text' && out[0].content === content))
|
|
88
|
+
return null;
|
|
89
|
+
return out;
|
|
90
|
+
}
|
|
91
|
+
/** inline children 内的 `attach:` 链接 → R6 锚点(整段替换为单个 html_inline token)。 */
|
|
92
|
+
function convertAttachmentLinks(TokenCtor, tokens) {
|
|
93
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
94
|
+
const open = tokens[i];
|
|
95
|
+
if (open.type !== 'link_open')
|
|
96
|
+
continue;
|
|
97
|
+
const href = String(open.attrGet('href') ?? '');
|
|
98
|
+
const refMatch = ATTACH_HREF_RE.exec(href.trim());
|
|
99
|
+
if (!refMatch)
|
|
100
|
+
continue;
|
|
101
|
+
// link_open..link_close 之间必须是纯文本运行(含嵌套/换行则保守跳过,保留原链接)
|
|
102
|
+
let text = '';
|
|
103
|
+
let closeIdx = -1;
|
|
104
|
+
for (let j = i + 1; j < tokens.length; j++) {
|
|
105
|
+
const t = tokens[j];
|
|
106
|
+
if (t.type === 'link_close') {
|
|
107
|
+
closeIdx = j;
|
|
108
|
+
break;
|
|
109
|
+
}
|
|
110
|
+
if (t.type !== 'text')
|
|
111
|
+
break;
|
|
112
|
+
text += t.content;
|
|
113
|
+
}
|
|
114
|
+
if (closeIdx < 0)
|
|
115
|
+
continue;
|
|
116
|
+
const name = text.replace(/^\s*📎\s*/, '');
|
|
117
|
+
if (name === '')
|
|
118
|
+
continue;
|
|
119
|
+
let anchor;
|
|
120
|
+
try {
|
|
121
|
+
anchor = attachmentAnchorHtml({ workspaceId: refMatch[1], id: refMatch[2], name });
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
continue; // ws/id 含空白或非法字符 → 原样保留(绝不猜测改写)
|
|
125
|
+
}
|
|
126
|
+
const htmlToken = new TokenCtor('html_inline', '', 0);
|
|
127
|
+
htmlToken.content = anchor;
|
|
128
|
+
tokens.splice(i, closeIdx - i + 1, htmlToken);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
/** inline children 内 text token 的 @ 语义替换(链接内部跳过;code/html/image token 天然跳过)。 */
|
|
132
|
+
function convertMentions(TokenCtor, tokens) {
|
|
133
|
+
let linkDepth = 0;
|
|
134
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
135
|
+
const token = tokens[i];
|
|
136
|
+
if (token.type === 'link_open') {
|
|
137
|
+
linkDepth += 1;
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
if (token.type === 'link_close') {
|
|
141
|
+
linkDepth = Math.max(0, linkDepth - 1);
|
|
142
|
+
continue;
|
|
143
|
+
}
|
|
144
|
+
if (linkDepth > 0)
|
|
145
|
+
continue; // 链接文本内 @ 不转换(URL 已天然不在 text token)
|
|
146
|
+
if (token.type !== 'text')
|
|
147
|
+
continue;
|
|
148
|
+
const replacement = splitTextTokenAtSemantics(TokenCtor, token);
|
|
149
|
+
if (replacement) {
|
|
150
|
+
tokens.splice(i, 1, ...replacement);
|
|
151
|
+
i += replacement.length - 1;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
function tapdRichtextCoreRule(state) {
|
|
156
|
+
const TokenCtor = state.Token;
|
|
157
|
+
for (const token of state.tokens) {
|
|
158
|
+
// fence/code_block/html_block 等 block token 内容不经过 inline 层,天然跳过
|
|
159
|
+
if (token.type !== 'inline' || !token.children)
|
|
160
|
+
continue;
|
|
161
|
+
convertAttachmentLinks(TokenCtor, token.children);
|
|
162
|
+
convertMentions(TokenCtor, token.children);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const markdownIt = new MarkdownIt({ html: false, breaks: true });
|
|
166
|
+
// push 到 core 链尾(text_join 之后):不再有规则会合并/重排我们的 token 切分
|
|
167
|
+
markdownIt.core.ruler.push('tapd_richtext_semantics', tapdRichtextCoreRule);
|
|
168
|
+
/** md → TAPD 富文本 html(@昵称/@@转义/attach: 附件引用/图片与普通 md 全兼容)。 */
|
|
169
|
+
export function mdToHtml(md) {
|
|
170
|
+
return markdownIt.render(md);
|
|
171
|
+
}
|
|
172
|
+
// ---------------------------------------------------------------------------
|
|
173
|
+
// html → md(turndown,规则级)
|
|
174
|
+
// ---------------------------------------------------------------------------
|
|
175
|
+
const turndown = new TurndownService({ headingStyle: 'atx', codeBlockStyle: 'fenced' });
|
|
176
|
+
turndown.use(gfm);
|
|
177
|
+
// 保真规则先于 GFM/内建规则匹配:addRule 是 unshift 语义(后注册者先匹配),
|
|
178
|
+
// 在 use(gfm) 之后注册即拿到最高优先级(FSD §8,规则优先级由测试固化)。
|
|
179
|
+
turndown.addRule('tapdAtWho', {
|
|
180
|
+
filter: node => isAtWhoNode(node),
|
|
181
|
+
replacement: (_content, node) => atWhoNodeToMd(node),
|
|
182
|
+
});
|
|
183
|
+
turndown.addRule('tapdAttachmentAnchor', {
|
|
184
|
+
filter: node => isAttachmentAnchorNode(node),
|
|
185
|
+
replacement: (_content, node) => {
|
|
186
|
+
const md = attachmentAnchorNodeToMd(node);
|
|
187
|
+
// 识别条件不满足(缺 href 等)→ 保留原节点 HTML,绝不猜测改写
|
|
188
|
+
return md ?? node.outerHTML ?? '';
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
// 文本节点字面 @ 保护(round-trip 稳定:命中 mention 规则的 @名字 加倍为 @@名字)。
|
|
192
|
+
// CODE 内文本 isCode 天然绕过 escape 钩子(turndown process 分支),代码段 @ 不被加倍。
|
|
193
|
+
const baseEscape = TurndownService.prototype.escape.bind(TurndownService.prototype);
|
|
194
|
+
turndown.escape = (text) => baseEscape(escapeAtLiteralsForMd(text));
|
|
195
|
+
/** TAPD 富文本 html → md(at-who → @昵称、附件锚点 → attach: 引用、/tfl/ 图片走 GFM 内建规则)。 */
|
|
196
|
+
export function htmlToMd(html) {
|
|
197
|
+
return turndown.turndown(html);
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=pipeline.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pipeline.js","sourceRoot":"","sources":["../../src/richtext/pipeline.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"round-trip.test.d.ts","sourceRoot":"","sources":["../../src/richtext/round-trip.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
// round-trip 契约测试:六类样本(@/附件/链接/图片/混合/纯文本)md→html→md 与原文等价(空白规约内)。
|
|
2
|
+
// 只覆盖纯函数语义层(本目录 fragment 函数),不经过工具/注册表转换主链路(接线归 Wave 2)。
|
|
3
|
+
import assert from 'node:assert/strict';
|
|
4
|
+
import { htmlToMdFragment, mdToHtmlFragment } from './index.js';
|
|
5
|
+
const WS = '39814312';
|
|
6
|
+
const AT = (name) => `<b class="at-who" contenteditable="false" data-userid="${name}" data-type="user">@${name}</b>`;
|
|
7
|
+
const ANCHOR = (id, name, fileType) => `<a data-is-tapd-attachment="true" data-can-preview="true" data-file-type="${fileType}" ` +
|
|
8
|
+
`data-name="${name}" target="_blank" rel="noopener" ` +
|
|
9
|
+
`href="/${WS}/attachments/preview_attachments/${id}/story_description_attachment">${name}</a>`;
|
|
10
|
+
// 空白规约:允许转换层的空白差异(本层本不应产生,防御性归一)
|
|
11
|
+
const normalize = (value) => value.replace(/\s+/g, ' ').trim();
|
|
12
|
+
const SAMPLES = [
|
|
13
|
+
{
|
|
14
|
+
name: '样本1 @(中英文昵称、CJK 标点边界)',
|
|
15
|
+
md: '请 @徐昭 今天内确认,备份联系 @bob_dev。',
|
|
16
|
+
html: `请 ${AT('徐昭')} 今天内确认,备份联系 ${AT('bob_dev')}。`,
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: '样本2 附件(pdf/text/other 映射)',
|
|
20
|
+
md: `评审材料 [📎 接口设计.pdf](attach:${WS}/1139814312001000001),日志 [📎 app.log](attach:${WS}/1139814312001000002)`,
|
|
21
|
+
html: `评审材料 ${ANCHOR('1139814312001000001', '接口设计.pdf', 'pdf')},日志 ${ANCHOR('1139814312001000002', 'app.log', 'other')}`,
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: '样本3 链接(语义层零干预透传,基础转换器职责)',
|
|
25
|
+
md: `需求详情见 [TAPD 1139814312001001548](https://www.tapd.cn/${WS}/prong/stories/view/1139814312001001548)`,
|
|
26
|
+
html: `需求详情见 [TAPD 1139814312001001548](https://www.tapd.cn/${WS}/prong/stories/view/1139814312001001548)`,
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: '样本4 图片(/tfl/ 远端路径,语义层零干预透传)',
|
|
30
|
+
md: '效果图 ',
|
|
31
|
+
html: '效果图 ',
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: '样本5 混合(@ + @@转义 + 附件@名 + 图片 + 链接 + 粗体)',
|
|
35
|
+
md: [
|
|
36
|
+
'# rc.2 评审',
|
|
37
|
+
'',
|
|
38
|
+
'负责人 @徐昭,抄送 @@everyone(字面量)。',
|
|
39
|
+
`材料 [📎 报表@v2.txt](attach:${WS}/1139814312001000003),截图 。`,
|
|
40
|
+
`线索 [需求](https://www.tapd.cn/${WS}/prong/stories/view/1139814312001001548) 与 **加粗**。`,
|
|
41
|
+
].join('\n'),
|
|
42
|
+
html: [
|
|
43
|
+
'# rc.2 评审',
|
|
44
|
+
'',
|
|
45
|
+
`负责人 ${AT('徐昭')},抄送 @everyone(字面量)。`,
|
|
46
|
+
`材料 ${ANCHOR('1139814312001000003', '报表@v2.txt', 'text')},截图 。`,
|
|
47
|
+
`线索 [需求](https://www.tapd.cn/${WS}/prong/stories/view/1139814312001001548) 与 **加粗**。`,
|
|
48
|
+
].join('\n'),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
name: '样本6 纯文本(邮箱/工单号/孤立 @ 不误伤,@@转义不触发 mention,FSD §8)',
|
|
52
|
+
md: '版本 v1.2 已发布。联系邮箱 user@example.com;工单号 T-100@QA 由 support@test 处理;单独的 @ 保持原样,转义 @@support 也不触发 mention。',
|
|
53
|
+
html: '版本 v1.2 已发布。联系邮箱 user@example.com;工单号 T-100@QA 由 support@test 处理;单独的 @ 保持原样,转义 @support 也不触发 mention。',
|
|
54
|
+
},
|
|
55
|
+
];
|
|
56
|
+
const checks = [
|
|
57
|
+
...SAMPLES.map((sample) => [
|
|
58
|
+
`md→html: ${sample.name}`,
|
|
59
|
+
() => {
|
|
60
|
+
assert.equal(normalize(mdToHtmlFragment(sample.md)), normalize(sample.html));
|
|
61
|
+
},
|
|
62
|
+
]),
|
|
63
|
+
...SAMPLES.map((sample) => [
|
|
64
|
+
`html→md: ${sample.name}`,
|
|
65
|
+
() => {
|
|
66
|
+
assert.equal(normalize(htmlToMdFragment(sample.html)), normalize(sample.md));
|
|
67
|
+
},
|
|
68
|
+
]),
|
|
69
|
+
...SAMPLES.map((sample) => [
|
|
70
|
+
`round-trip: ${sample.name}`,
|
|
71
|
+
() => {
|
|
72
|
+
assert.equal(normalize(htmlToMdFragment(mdToHtmlFragment(sample.md))), normalize(sample.md));
|
|
73
|
+
// 二次往返幂等(转换稳定点)
|
|
74
|
+
const once = htmlToMdFragment(mdToHtmlFragment(sample.md));
|
|
75
|
+
assert.equal(normalize(htmlToMdFragment(mdToHtmlFragment(once))), normalize(once));
|
|
76
|
+
},
|
|
77
|
+
]),
|
|
78
|
+
['R7 回归: @昵称 产出 at-who 标记而非降级形态', () => {
|
|
79
|
+
const html = mdToHtmlFragment('呼叫 @徐昭');
|
|
80
|
+
assert.ok(html.includes('<b class="at-who" contenteditable="false" data-userid="徐昭" data-type="user">@徐昭</b>'));
|
|
81
|
+
const md = htmlToMdFragment('<p><b class="at-who" contenteditable="false" data-userid="徐昭" data-type="user">@徐昭</b></p>');
|
|
82
|
+
assert.equal(md, '<p>@徐昭</p>');
|
|
83
|
+
assert.ok(!md.includes('**'));
|
|
84
|
+
}],
|
|
85
|
+
];
|
|
86
|
+
let failed = 0;
|
|
87
|
+
for (const [name, check] of checks) {
|
|
88
|
+
try {
|
|
89
|
+
check();
|
|
90
|
+
console.log(`PASS ${name}`);
|
|
91
|
+
}
|
|
92
|
+
catch (error) {
|
|
93
|
+
failed += 1;
|
|
94
|
+
console.error(`FAIL ${name}`);
|
|
95
|
+
console.error(` ${error instanceof Error ? error.message : String(error)}`);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (failed > 0) {
|
|
99
|
+
console.error(`\n${failed}/${checks.length} failed`);
|
|
100
|
+
process.exitCode = 1;
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
console.log(`\n${checks.length}/${checks.length} passed`);
|
|
104
|
+
}
|
|
105
|
+
//# sourceMappingURL=round-trip.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"round-trip.test.js","sourceRoot":"","sources":["../../src/richtext/round-trip.test.ts"],"names":[],"mappings":"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"}
|
package/dist/sdk-routes.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-routes.d.ts","sourceRoot":"","sources":["../src/sdk-routes.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,GAAG,KAAK,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"sdk-routes.d.ts","sourceRoot":"","sources":["../src/sdk-routes.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,QAAQ,GAAG,GAAG,KAAK,GAAG,MAAM,IAAI,MAAM,EAAE,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAqLxD,CAAC"}
|
package/dist/sdk-routes.js
CHANGED
|
@@ -8,6 +8,10 @@ export const SDK_ROUTES = {
|
|
|
8
8
|
// attachments
|
|
9
9
|
'GET /attachments': 'getAttachments',
|
|
10
10
|
'GET /attachments/down': 'downloadAttachment',
|
|
11
|
+
'POST /open_app_obj_attachment': 'addOpenAppObjAttachment',
|
|
12
|
+
// files (upload channel — multipart via TapdClient.postFile)
|
|
13
|
+
'POST /files/upload_attachment': 'uploadAttachment',
|
|
14
|
+
'POST /files/upload_image': 'uploadImage',
|
|
11
15
|
// board-cards
|
|
12
16
|
'GET /board_cards': 'getBoardCards',
|
|
13
17
|
// board-columns
|
package/dist/sdk-routes.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sdk-routes.js","sourceRoot":"","sources":["../src/sdk-routes.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,UAAU,GAAsC;IAC3D,cAAc;IACd,kBAAkB,EAAE,gBAAgB;IACpC,uBAAuB,EAAE,oBAAoB;
|
|
1
|
+
{"version":3,"file":"sdk-routes.js","sourceRoot":"","sources":["../src/sdk-routes.ts"],"names":[],"mappings":"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"}
|
package/dist/tapd-client.d.ts
CHANGED
|
@@ -1,3 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TAPD API Client
|
|
3
|
+
*
|
|
4
|
+
* Supports dual authentication modes:
|
|
5
|
+
* - Basic Auth: using api_user + api_password
|
|
6
|
+
* - OAuth/Bearer Token: using access_token
|
|
7
|
+
*
|
|
8
|
+
* Routes requests through @opentapd/tapd-node-sdk when the method+path is
|
|
9
|
+
* listed in SDK_ROUTES, otherwise falls back to the custom fetch client.
|
|
10
|
+
* - GET SDK failures fall back to fetch (read-only, idempotent)
|
|
11
|
+
* - POST SDK failures throw directly (never fallback, avoid duplicate writes)
|
|
12
|
+
* - Set TAPD_SDK_DISABLED=1 to bypass the SDK entirely (rollback switch)
|
|
13
|
+
*
|
|
14
|
+
* GET 通道前置只读数据 TTL 缓存(cache/read-cache.ts):仅 allowlist 内低频端点
|
|
15
|
+
* (workitem_types / workflow / 成员 / 自定义字段配置 / settings 系 / 分类 / 角色)
|
|
16
|
+
* 参与缓存(TTL + LRU + in-flight 去重 + 深拷贝返回),其余请求一律直连。
|
|
17
|
+
* TAPD_CACHE=off 关闭;TAPD_CACHE_DEBUG=1 打命中日志;失效用 invalidateCache()。
|
|
18
|
+
*/
|
|
19
|
+
import { ReadStream } from 'node:fs';
|
|
20
|
+
/**
|
|
21
|
+
* A param value accepted by the multipart upload channel (TapdClient.postFile).
|
|
22
|
+
* The file itself MUST be an fs.ReadStream (i.e. fs.createReadStream):
|
|
23
|
+
* the SDK only switches to multipart/form-data for ReadStream/FILE values
|
|
24
|
+
* (node-sdk/src/sdk.js:159) — Buffers / Readable.from() silently degrade to
|
|
25
|
+
* plain form fields.
|
|
26
|
+
*/
|
|
27
|
+
export type FileUploadParam = string | number | boolean | undefined | ReadStream;
|
|
1
28
|
export declare class TapdClient {
|
|
2
29
|
private authHeader;
|
|
3
30
|
private baseUrl;
|
|
@@ -8,6 +35,15 @@ export declare class TapdClient {
|
|
|
8
35
|
private sdk?;
|
|
9
36
|
private readonly sdkEnabled;
|
|
10
37
|
private readonly verbose;
|
|
38
|
+
/**
|
|
39
|
+
* GET 重试指数退避基数(毫秒):延迟 = base * 2^attempt(1s, 2s, 4s)。
|
|
40
|
+
* 公开静态以便测试注入小值加速、运维按需调参;429 携带 Retry-After 时优先采用其值(上限 30s)。
|
|
41
|
+
*/
|
|
42
|
+
static retryBackoffBaseMs: number;
|
|
43
|
+
private static readonly MAX_RETRIES;
|
|
44
|
+
private static readonly RETRYABLE_STATUS;
|
|
45
|
+
/** Retry-After 退避上限:避免服务端给出超长等待时占死工具超时预算(原始值仍透出在错误详情)。 */
|
|
46
|
+
private static readonly RETRY_AFTER_CAP_MS;
|
|
11
47
|
private constructor();
|
|
12
48
|
/**
|
|
13
49
|
* Create client from OAuth access token
|
|
@@ -74,11 +110,29 @@ export declare class TapdClient {
|
|
|
74
110
|
*/
|
|
75
111
|
private getSdk;
|
|
76
112
|
/**
|
|
77
|
-
*
|
|
78
|
-
*
|
|
113
|
+
* 请求入口:GET 先过只读缓存门面(allowlist 内端点命中即返,未命中并发去重),
|
|
114
|
+
* 再走 SDK/fetch 网络通道;POST 与 multipart 不参与缓存,直连网络通道。
|
|
115
|
+
* 返回值形态与直连完全一致(命中为深拷贝,防消费方 mutate 污染缓存)。
|
|
79
116
|
*/
|
|
80
117
|
private route;
|
|
118
|
+
/**
|
|
119
|
+
* Network channel: route a request through the SDK when the method+path is
|
|
120
|
+
* mapped, otherwise (and on read-only SDK failure) through the fetch client.
|
|
121
|
+
*/
|
|
122
|
+
private routeNetwork;
|
|
123
|
+
/**
|
|
124
|
+
* Make HTTP request to TAPD API with retry support
|
|
125
|
+
*
|
|
126
|
+
* Retry policy:
|
|
127
|
+
* - Retry on 429/500/502/503 status codes and network-level failures
|
|
128
|
+
* - Max 3 retries with exponential backoff (1s, 2s, 4s); 429 的 Retry-After 优先(上限 30s)
|
|
129
|
+
* - POST requests do NOT retry (avoid duplicate creation)
|
|
130
|
+
* - 非 2xx 的确定性错误(400/401/403/404...)立即抛出,不做无谓重试
|
|
131
|
+
* - 所有错误统一抛 TapdError(结构化详情见 errors/index.ts)
|
|
132
|
+
*/
|
|
81
133
|
request<T>(method: 'GET' | 'POST', path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
|
|
134
|
+
/** 单次重试等待:429 的 Retry-After 优先(封顶 30s),否则指数退避 base * 2^attempt。 */
|
|
135
|
+
private retryDelayMs;
|
|
82
136
|
/**
|
|
83
137
|
* GET request to TAPD API
|
|
84
138
|
*/
|
|
@@ -87,6 +141,29 @@ export declare class TapdClient {
|
|
|
87
141
|
* POST request to TAPD API
|
|
88
142
|
*/
|
|
89
143
|
post<T>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
|
|
144
|
+
/**
|
|
145
|
+
* POST a multipart (file upload) request — the streaming channel for upload
|
|
146
|
+
* endpoints (`/files/upload_attachment`, `/files/upload_image`, ...).
|
|
147
|
+
*
|
|
148
|
+
* Keeps registry.exec the single execution path (FSD §2 ruling: streaming
|
|
149
|
+
* calls never bypass TapdClient, so audit / timeout / read-only gating and
|
|
150
|
+
* auth stay unified).
|
|
151
|
+
*
|
|
152
|
+
* Routing mirrors route() POST semantics:
|
|
153
|
+
* - When `POST <path>` is mapped in SDK_ROUTES and the SDK is enabled, the
|
|
154
|
+
* request goes through the SDK, which builds multipart/form-data when any
|
|
155
|
+
* param value is an fs.ReadStream (node-sdk/src/sdk.js:159).
|
|
156
|
+
* - POST failures throw directly (never fall back / retry — a flaky network
|
|
157
|
+
* must not duplicate an upload).
|
|
158
|
+
* - Without an SDK route (or with TAPD_SDK_DISABLED=1 rollback switch on),
|
|
159
|
+
* falls back to a fetch-based multipart upload (Node 20+ global FormData).
|
|
160
|
+
*/
|
|
161
|
+
postFile<T>(path: string, params: Record<string, FileUploadParam>): Promise<T>;
|
|
162
|
+
/**
|
|
163
|
+
* fetch-based multipart fallback (no SDK route / SDK disabled). Node 20+
|
|
164
|
+
* global fetch serializes FormData bodies (boundary included) automatically.
|
|
165
|
+
*/
|
|
166
|
+
private postMultipartViaFetch;
|
|
90
167
|
}
|
|
91
168
|
/**
|
|
92
169
|
* TAPD API response structure
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tapd-client.d.ts","sourceRoot":"","sources":["../src/tapd-client.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"tapd-client.d.ts","sourceRoot":"","sources":["../src/tapd-client.ts"],"names":[],"mappings":"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"}
|