codeharbor 0.1.17 → 0.1.18
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/dist/cli.js +124 -11
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -3128,7 +3128,7 @@ function renderMatrixHtml(body, msgtype) {
|
|
|
3128
3128
|
let match;
|
|
3129
3129
|
while ((match = codeFencePattern.exec(normalized)) !== null) {
|
|
3130
3130
|
const before = normalized.slice(cursor, match.index);
|
|
3131
|
-
const renderedBefore =
|
|
3131
|
+
const renderedBefore = renderMarkdownSection(before);
|
|
3132
3132
|
if (renderedBefore) {
|
|
3133
3133
|
sections.push(renderedBefore);
|
|
3134
3134
|
}
|
|
@@ -3141,29 +3141,142 @@ function renderMatrixHtml(body, msgtype) {
|
|
|
3141
3141
|
cursor = match.index + match[0].length;
|
|
3142
3142
|
}
|
|
3143
3143
|
const tail = normalized.slice(cursor);
|
|
3144
|
-
const renderedTail =
|
|
3144
|
+
const renderedTail = renderMarkdownSection(tail);
|
|
3145
3145
|
if (renderedTail) {
|
|
3146
3146
|
sections.push(renderedTail);
|
|
3147
3147
|
}
|
|
3148
3148
|
if (sections.length === 0) {
|
|
3149
3149
|
sections.push("<p>(\u7A7A\u6D88\u606F)</p>");
|
|
3150
3150
|
}
|
|
3151
|
-
const badge = msgtype === "m.notice" ? `<p><font color="#8a5a00"><b
|
|
3151
|
+
const badge = msgtype === "m.notice" ? `<p><font color="#8a5a00"><b>CodeHarbor \u63D0\u793A</b></font></p>` : `<p><font color="#1f7a5a"><b>CodeHarbor AI \u56DE\u590D</b></font></p>`;
|
|
3152
3152
|
return `<div>${badge}${sections.join("")}</div>`;
|
|
3153
3153
|
}
|
|
3154
|
-
function
|
|
3154
|
+
function renderMarkdownSection(raw) {
|
|
3155
3155
|
if (!raw.trim()) {
|
|
3156
3156
|
return "";
|
|
3157
3157
|
}
|
|
3158
|
-
const
|
|
3159
|
-
const
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
const
|
|
3163
|
-
|
|
3164
|
-
|
|
3158
|
+
const lines = raw.replace(/\r\n/g, "\n").trim().split("\n");
|
|
3159
|
+
const blocks = [];
|
|
3160
|
+
let index = 0;
|
|
3161
|
+
while (index < lines.length) {
|
|
3162
|
+
const line = lines[index];
|
|
3163
|
+
const trimmed = line.trim();
|
|
3164
|
+
if (!trimmed) {
|
|
3165
|
+
index += 1;
|
|
3166
|
+
continue;
|
|
3167
|
+
}
|
|
3168
|
+
const headingMatch = /^(#{1,6})\s+(.+)$/.exec(trimmed);
|
|
3169
|
+
if (headingMatch) {
|
|
3170
|
+
const level = Math.min(6, headingMatch[1].length + 1);
|
|
3171
|
+
blocks.push(`<h${level}>${renderInlineMarkup(headingMatch[2])}</h${level}>`);
|
|
3172
|
+
index += 1;
|
|
3173
|
+
continue;
|
|
3174
|
+
}
|
|
3175
|
+
if (/^(?:-{3,}|\*{3,}|_{3,})$/.test(trimmed)) {
|
|
3176
|
+
blocks.push("<hr/>");
|
|
3177
|
+
index += 1;
|
|
3178
|
+
continue;
|
|
3179
|
+
}
|
|
3180
|
+
if (/^>\s?/.test(trimmed)) {
|
|
3181
|
+
const quoteLines = [];
|
|
3182
|
+
while (index < lines.length) {
|
|
3183
|
+
const current = lines[index].trim();
|
|
3184
|
+
if (!current) {
|
|
3185
|
+
break;
|
|
3186
|
+
}
|
|
3187
|
+
if (!/^>\s?/.test(current)) {
|
|
3188
|
+
break;
|
|
3189
|
+
}
|
|
3190
|
+
quoteLines.push(current.replace(/^>\s?/, ""));
|
|
3191
|
+
index += 1;
|
|
3192
|
+
}
|
|
3193
|
+
if (quoteLines.length > 0) {
|
|
3194
|
+
blocks.push(`<blockquote><p>${quoteLines.map((entry) => renderInlineMarkup(entry)).join("<br/>")}</p></blockquote>`);
|
|
3195
|
+
}
|
|
3196
|
+
continue;
|
|
3197
|
+
}
|
|
3198
|
+
if (/^\s*[-*]\s+/.test(line)) {
|
|
3199
|
+
const items = [];
|
|
3200
|
+
while (index < lines.length && /^\s*[-*]\s+/.test(lines[index])) {
|
|
3201
|
+
items.push(lines[index].replace(/^\s*[-*]\s+/, "").trim());
|
|
3202
|
+
index += 1;
|
|
3203
|
+
}
|
|
3204
|
+
blocks.push(`<ul>${items.map((item) => `<li>${renderInlineMarkup(item)}</li>`).join("")}</ul>`);
|
|
3205
|
+
continue;
|
|
3206
|
+
}
|
|
3207
|
+
if (/^\s*\d+\.\s+/.test(line)) {
|
|
3208
|
+
const items = [];
|
|
3209
|
+
while (index < lines.length && /^\s*\d+\.\s+/.test(lines[index])) {
|
|
3210
|
+
items.push(lines[index].replace(/^\s*\d+\.\s+/, "").trim());
|
|
3211
|
+
index += 1;
|
|
3212
|
+
}
|
|
3213
|
+
blocks.push(`<ol>${items.map((item) => `<li>${renderInlineMarkup(item)}</li>`).join("")}</ol>`);
|
|
3214
|
+
continue;
|
|
3215
|
+
}
|
|
3216
|
+
const paragraphLines = [];
|
|
3217
|
+
while (index < lines.length) {
|
|
3218
|
+
const current = lines[index];
|
|
3219
|
+
if (!current.trim()) {
|
|
3220
|
+
break;
|
|
3221
|
+
}
|
|
3222
|
+
if (isBlockBoundaryLine(current)) {
|
|
3223
|
+
break;
|
|
3224
|
+
}
|
|
3225
|
+
paragraphLines.push(current.trimEnd());
|
|
3226
|
+
index += 1;
|
|
3227
|
+
}
|
|
3228
|
+
if (paragraphLines.length > 0) {
|
|
3229
|
+
blocks.push(`<p>${paragraphLines.map((entry) => renderInlineMarkup(entry)).join("<br/>")}</p>`);
|
|
3230
|
+
continue;
|
|
3231
|
+
}
|
|
3232
|
+
index += 1;
|
|
3233
|
+
}
|
|
3234
|
+
return blocks.join("");
|
|
3235
|
+
}
|
|
3236
|
+
function isBlockBoundaryLine(line) {
|
|
3237
|
+
const trimmed = line.trim();
|
|
3238
|
+
if (!trimmed) {
|
|
3239
|
+
return false;
|
|
3240
|
+
}
|
|
3241
|
+
return /^(#{1,6})\s+/.test(trimmed) || /^(?:-{3,}|\*{3,}|_{3,})$/.test(trimmed) || /^>\s?/.test(trimmed) || /^\s*[-*]\s+/.test(trimmed) || /^\s*\d+\.\s+/.test(trimmed);
|
|
3242
|
+
}
|
|
3243
|
+
function renderInlineMarkup(raw) {
|
|
3244
|
+
if (!raw) {
|
|
3245
|
+
return "";
|
|
3246
|
+
}
|
|
3247
|
+
const inlineCodeSegments = [];
|
|
3248
|
+
const withPlaceholders = raw.replace(/`([^`\n]+)`/g, (_match, code) => {
|
|
3249
|
+
const token = `@@CHCODE${inlineCodeSegments.length}@@`;
|
|
3250
|
+
inlineCodeSegments.push(`<code>${escapeHtml(code)}</code>`);
|
|
3251
|
+
return token;
|
|
3252
|
+
});
|
|
3253
|
+
let rendered = escapeHtml(withPlaceholders);
|
|
3254
|
+
rendered = rendered.replace(/\[([^\]\n]+)\]\((https?:\/\/[^\s)]+)\)/g, (_match, label, url) => {
|
|
3255
|
+
const safeUrl = sanitizeLinkUrl(url);
|
|
3256
|
+
if (!safeUrl) {
|
|
3257
|
+
return escapeHtml(label);
|
|
3258
|
+
}
|
|
3259
|
+
return `<a href="${escapeHtml(safeUrl)}">${escapeHtml(label)}</a>`;
|
|
3260
|
+
});
|
|
3261
|
+
rendered = rendered.replace(/\*\*([^*\n]+)\*\*/g, "<strong>$1</strong>");
|
|
3262
|
+
rendered = rendered.replace(/(^|[^*])\*([^*\n]+)\*/g, "$1<em>$2</em>");
|
|
3263
|
+
rendered = rendered.replace(/(^|[^_])_([^_\n]+)_/g, "$1<em>$2</em>");
|
|
3264
|
+
for (let i = 0; i < inlineCodeSegments.length; i += 1) {
|
|
3265
|
+
rendered = rendered.replace(`@@CHCODE${i}@@`, inlineCodeSegments[i]);
|
|
3266
|
+
}
|
|
3165
3267
|
return rendered;
|
|
3166
3268
|
}
|
|
3269
|
+
function sanitizeLinkUrl(url) {
|
|
3270
|
+
try {
|
|
3271
|
+
const parsed = new URL(url);
|
|
3272
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") {
|
|
3273
|
+
return null;
|
|
3274
|
+
}
|
|
3275
|
+
return parsed.toString();
|
|
3276
|
+
} catch {
|
|
3277
|
+
return null;
|
|
3278
|
+
}
|
|
3279
|
+
}
|
|
3167
3280
|
function escapeHtml(value) {
|
|
3168
3281
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3169
3282
|
}
|