diff --git a/pages/components/HighlightSyntax.module.css b/pages/components/HighlightSyntax.module.css
index 75f0b81..2c2f614 100644
--- a/pages/components/HighlightSyntax.module.css
+++ b/pages/components/HighlightSyntax.module.css
@@ -10,6 +10,7 @@
color: #e0e0e0;
}
+/* JavaScript/TypeScript 关键字 */
.keyword {
color: #d73a49;
font-weight: 600;
@@ -19,6 +20,27 @@
color: #ff6b6b;
}
+/* TypeScript 特定关键字 (interface, type, enum, etc.) */
+.tsKeyword {
+ color: #af00db;
+ font-weight: 600;
+}
+
+:global(.dark) .tsKeyword {
+ color: #c792ea;
+}
+
+/* TypeScript 内置类型 */
+.type {
+ color: #267f99;
+ font-weight: 500;
+}
+
+:global(.dark) .type {
+ color: #4ec9b0;
+}
+
+/* 字符串 */
.string {
color: #1d6eca;
}
@@ -27,6 +49,7 @@
color: #4fc3f7;
}
+/* 数字 */
.number {
color: #00c583;
}
@@ -35,6 +58,17 @@
color: #66bb6a;
}
+/* 布尔值和字面量 (true, false, null, undefined) */
+.literal {
+ color: #0000ff;
+ font-weight: 500;
+}
+
+:global(.dark) .literal {
+ color: #569cd6;
+}
+
+/* 注释 */
.comment {
color: #6a737d;
font-style: italic;
@@ -43,3 +77,51 @@
:global(.dark) .comment {
color: #9e9e9e;
}
+
+/* 装饰器 (@decorator) */
+.decorator {
+ color: #e0aa00;
+ font-weight: 500;
+}
+
+:global(.dark) .decorator {
+ color: #dcdcaa;
+}
+
+
+/* 箭头函数 (=>) */
+.arrow {
+ color: #d73a49;
+ font-weight: bold;
+}
+
+:global(.dark) .arrow {
+ color: #ff6b6b;
+}
+
+/* 标识符(变量名、函数名等) */
+.identifier {
+ color: #171717;
+}
+
+:global(.dark) .identifier {
+ color: #e0e0e0;
+}
+
+/* 属性访问 (.property) */
+.property {
+ color: #0550ae;
+}
+
+:global(.dark) .property {
+ color: #9cdcfe;
+}
+
+/* 运算符 */
+.operator {
+ color: #5a5a5a;
+}
+
+:global(.dark) .operator {
+ color: #d4d4d4;
+}
diff --git a/pages/components/HighlightSyntax.tsx b/pages/components/HighlightSyntax.tsx
index 6d0d671..7632500 100644
--- a/pages/components/HighlightSyntax.tsx
+++ b/pages/components/HighlightSyntax.tsx
@@ -9,58 +9,157 @@ interface HighlightSyntaxProps {
code: string
}
+// JavaScript/TypeScript 关键字
const keywords =
- 'async|await|function|const|let|var|if|else|for|while|return|try|catch|finally|class|extends|from|import|export|default|undefined|throw|true|false|null|this|new|in|of|instanceof|break|continue|switch|case|default|do|while|with|yield'
+ 'async|await|function|const|let|var|if|else|for|while|return|try|catch|finally|class|extends|from|import|export|default|undefined|throw|break|continue|switch|case|do|with|yield|delete|typeof|void|static|get|set|super|debugger'
-// 语法高亮函数,先整体提取字符串/注释等token再高亮
+// TypeScript 特定关键字
+const tsKeywords =
+ 'interface|type|enum|namespace|module|declare|abstract|implements|public|private|protected|readonly|as|satisfies|infer|keyof|is'
+
+// 布尔值和空值
+const literals = 'true|false|null|undefined|NaN|Infinity'
+
+// TypeScript 内置类型
+const tsTypes =
+ 'string|number|boolean|any|unknown|never|void|object|symbol|bigint|Array|Promise|Record|Partial|Required|Readonly|Pick|Omit|Exclude|Extract|NonNullable|ReturnType|Parameters|ConstructorParameters|InstanceType|ThisType|Uppercase|Lowercase|Capitalize|Uncapitalize'
+
+// 辅助函数:转义 HTML 特殊字符
+function escapeHtml(text: string): string {
+ return text.replace(/&/g, '&').replace(//g, '>')
+}
+
+// 语法高亮函数,先提取 token 再转义和高亮
function highlightSyntax(code: string): string {
- // 先转义HTML特殊字符
- const escaped = code.replace(/&/g, '&').replace(//g, '>')
-
- // 单行字符串,所有反斜杠双重转义,保证正则安全
+ // 构建正则模式,包含更多 token 类型(在原始文本上匹配)
const pattern = new RegExp(
- '("([^"\\\\]|\\\\.)*"|\'([^\'\\\\]|\\\\.)*\'|`([^`\\\\]|\\\\.)*`|//[^\\n]*|/\\*[\\s\\S]*?\\*/|\\b\\d+\\.?\\d*\\b|\\b(?:' +
+ '(' +
+ // 1. 字符串(双引号、单引号、模板字符串)
+ '"([^"\\\\]|\\\\.)*"|' +
+ "'([^'\\\\]|\\\\.)*'|" +
+ '`([^`\\\\]|\\\\.)*`|' +
+ // 2. 注释(单行和多行)
+ '//[^\\n]*|' +
+ '/\\*[\\s\\S]*?\\*/|' +
+ // 3. 装饰器
+ '@[a-zA-Z_$][\\w$]*|' +
+ // 4. 数字(包括小数、十六进制、科学计数法)
+ '\\b0[xX][0-9a-fA-F]+\\b|' +
+ '\\b\\d+\\.?\\d*(?:[eE][+-]?\\d+)?\\b|' +
+ // 5. TypeScript/JavaScript 关键字
+ '\\b(?:' +
keywords +
- ')\\b)',
+ '|' +
+ tsKeywords +
+ '|' +
+ literals +
+ ')\\b|' +
+ // 6. TypeScript 内置类型
+ '\\b(?:' +
+ tsTypes +
+ ')\\b|' +
+ // 7. 箭头函数
+ '=>|' +
+ // 8. 函数调用(函数名后跟括号)
+ '\\b[a-zA-Z_$][\\w$]*(?=\\()|' +
+ // 9. 属性访问
+ '\\.[a-zA-Z_$][\\w$]*|' +
+ // 10. 运算符和特殊符号
+ '[+\\-*/%&|^!~<>=?:]+|' +
+ '[{}\\[\\]();,.]' +
+ ')',
'g'
)
const tokens: string[] = []
let lastIndex = 0
let match: RegExpExecArray | null
- while ((match = pattern.exec(escaped)) !== null) {
+ while ((match = pattern.exec(code)) !== null) {
if (match.index > lastIndex) {
- tokens.push(...escaped.slice(lastIndex, match.index).split(/([ \t\n\r.])/))
+ const gap = code.slice(lastIndex, match.index)
+ // 将间隙按空白符分割,保留空白符
+ tokens.push(...gap.split(/(\s+)/))
}
tokens.push(match[0])
lastIndex = pattern.lastIndex
}
- if (lastIndex < escaped.length) {
- tokens.push(...escaped.slice(lastIndex).split(/([ \t\n\r.])/))
+ if (lastIndex < code.length) {
+ tokens.push(...code.slice(lastIndex).split(/(\s+)/))
}
const highlighted = tokens
.map((token) => {
+ // 空白符直接返回
+ if (/^\s+$/.test(token)) {
+ return token
+ }
+
+ // 1. 注释(单行和多行)
+ if (/^\/\/.*$/.test(token) || /^\/\*[\s\S]*?\*\/$/.test(token)) {
+ return ``
+ }
+
+ // 2. 字符串
if (
/^"([^"\\]|\\.)*"$/.test(token) ||
/^'([^'\\]|\\.)*'$/.test(token) ||
/^`([^`\\]|\\.)*`$/.test(token)
) {
- return `${token}`
+ return `${escapeHtml(token)}`
}
- if (/^\b\d+\.?\d*\b$/.test(token)) {
- return `${token}`
+
+ // 3. 数字
+ if (/^(0[xX][0-9a-fA-F]+|\d+\.?\d*(?:[eE][+-]?\d+)?)$/.test(token)) {
+ return `${escapeHtml(token)}`
}
- if (/^\/\/.*$/.test(token)) {
- return ``
+
+ // 4. 布尔值和特殊字面量
+ if (new RegExp(`^(?:${literals})$`).test(token)) {
+ return `${escapeHtml(token)}`
}
- if (/^\/\*[\s\S]*?\*\/$/.test(token)) {
- return ``
+
+ // 5. JavaScript/TypeScript 关键字
+ if (new RegExp(`^(?:${keywords})$`).test(token)) {
+ return `${escapeHtml(token)}`
}
- if (new RegExp(`\\b(?:${keywords})\\b`).test(token)) {
- return `${token}`
+
+ // 6. TypeScript 特定关键字
+ if (new RegExp(`^(?:${tsKeywords})$`).test(token)) {
+ return `${escapeHtml(token)}`
}
- return token
+
+ // 7. TypeScript 内置类型
+ if (new RegExp(`^(?:${tsTypes})$`).test(token)) {
+ return `${escapeHtml(token)}`
+ }
+
+ // 8. 装饰器
+ if (/^@[a-zA-Z_$][\w$]*$/.test(token)) {
+ return `${escapeHtml(token)}`
+ }
+
+ // 9. 箭头函数
+ if (token === '=>') {
+ return `${escapeHtml(token)}`
+ }
+
+ // 10. 函数调用和标识符
+ if (/^[a-zA-Z_$][\w$]*$/.test(token)) {
+ return `${escapeHtml(token)}`
+ }
+
+ // 11. 属性访问
+ if (/^\.[a-zA-Z_$][\w$]*$/.test(token)) {
+ return `${escapeHtml(token)}`
+ }
+
+ // 12. 运算符
+ if (/^[+\-*/%&|^!~<>=?:]+$/.test(token)) {
+ return `${escapeHtml(token)}`
+ }
+
+ // 13. 其他符号,需要转义
+ return escapeHtml(token)
})
.join('')