claude-code-workflow 6.3.24 → 6.3.25
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/.claude/skills/text-formatter/SKILL.md +196 -0
- package/.claude/skills/text-formatter/phases/01-input-collection.md +111 -0
- package/.claude/skills/text-formatter/phases/02-content-analysis.md +248 -0
- package/.claude/skills/text-formatter/phases/03-format-transform.md +245 -0
- package/.claude/skills/text-formatter/phases/04-output-preview.md +183 -0
- package/.claude/skills/text-formatter/specs/callout-types.md +293 -0
- package/.claude/skills/text-formatter/specs/element-mapping.md +226 -0
- package/.claude/skills/text-formatter/specs/format-rules.md +273 -0
- package/.claude/skills/text-formatter/templates/bbcode-template.md +350 -0
- package/package.json +91 -91
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: text-formatter
|
|
3
|
+
description: Transform and optimize text content with intelligent formatting. Output BBCode + Markdown hybrid format optimized for forums. Triggers on "format text", "text formatter", "排版", "格式化文本", "BBCode".
|
|
4
|
+
allowed-tools: Task, AskUserQuestion, Read, Write, Bash, Glob
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# Text Formatter
|
|
8
|
+
|
|
9
|
+
Transform and optimize text content with intelligent structure analysis. Output format: **BBCode + Markdown hybrid** optimized for forum publishing.
|
|
10
|
+
|
|
11
|
+
## Architecture Overview
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
┌─────────────────────────────────────────────────────────────────┐
|
|
15
|
+
│ Text Formatter Architecture (BBCode + MD Mode) │
|
|
16
|
+
├─────────────────────────────────────────────────────────────────┤
|
|
17
|
+
│ │
|
|
18
|
+
│ Phase 1: Input Collection → 接收文本/文件 │
|
|
19
|
+
│ ↓ │
|
|
20
|
+
│ Phase 2: Content Analysis → 分析结构、识别 Callout/Admonition │
|
|
21
|
+
│ ↓ │
|
|
22
|
+
│ Phase 3: Format Transform → 转换为 BBCode+MD 格式 │
|
|
23
|
+
│ ↓ │
|
|
24
|
+
│ Phase 4: Output & Preview → 保存文件 + 预览 │
|
|
25
|
+
│ │
|
|
26
|
+
└─────────────────────────────────────────────────────────────────┘
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Key Design Principles
|
|
30
|
+
|
|
31
|
+
1. **Single Format Output**: BBCode + Markdown hybrid (forum optimized)
|
|
32
|
+
2. **Pixel-Based Sizing**: size=150/120/100/80 (not 1-7 levels)
|
|
33
|
+
3. **Forum Compatibility**: Only use widely-supported BBCode tags
|
|
34
|
+
4. **Markdown Separators**: Use `---` for horizontal rules (not `[hr]`)
|
|
35
|
+
5. **No Alignment Tags**: `[align]` not supported, avoid usage
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Format Specification
|
|
40
|
+
|
|
41
|
+
### Supported BBCode Tags
|
|
42
|
+
|
|
43
|
+
| Tag | Usage | Example |
|
|
44
|
+
|-----|-------|---------|
|
|
45
|
+
| `[size=N]` | Font size (pixels) | `[size=120]Title[/size]` |
|
|
46
|
+
| `[color=X]` | Text color (hex/name) | `[color=#2196F3]Blue[/color]` 或 `[color=blue]` |
|
|
47
|
+
| `[b]` | Bold | `[b]Bold text[/b]` |
|
|
48
|
+
| `[i]` | Italic | `[i]Italic[/i]` |
|
|
49
|
+
| `[s]` | Strikethrough | `[s]deleted[/s]` |
|
|
50
|
+
| `[u]` | Underline | `[u]underlined[/u]` |
|
|
51
|
+
| `[quote]` | Quote block | `[quote]Content[/quote]` |
|
|
52
|
+
| `[code]` | Code block | `[code]code[/code]` |
|
|
53
|
+
| `[img]` | Image | `[img]url[/img]` |
|
|
54
|
+
| `[url]` | Link | `[url=link]text[/url]` |
|
|
55
|
+
| `[list]` | List container | `[list][*]item[/list]` |
|
|
56
|
+
| `[spoiler]` | Collapsible content | `[spoiler=标题]隐藏内容[/spoiler]` |
|
|
57
|
+
|
|
58
|
+
### HTML to BBCode Conversion
|
|
59
|
+
|
|
60
|
+
| HTML Input | BBCode Output |
|
|
61
|
+
|------------|---------------|
|
|
62
|
+
| `<mark>高亮</mark>` | `[color=yellow]高亮[/color]` |
|
|
63
|
+
| `<u>下划线</u>` | `[u]下划线[/u]` |
|
|
64
|
+
| `<details><summary>标题</summary>内容</details>` | `[spoiler=标题]内容[/spoiler]` |
|
|
65
|
+
|
|
66
|
+
### Unsupported Tags (Avoid!)
|
|
67
|
+
|
|
68
|
+
| Tag | Reason | Alternative |
|
|
69
|
+
|-----|--------|-------------|
|
|
70
|
+
| `[align]` | Not rendered | Remove or use default left |
|
|
71
|
+
| `[hr]` | Shows as text | Use Markdown `---` |
|
|
72
|
+
| `<div>` | HTML not supported | Use BBCode only |
|
|
73
|
+
| `[table]` | Limited support | Use list or code block |
|
|
74
|
+
|
|
75
|
+
### Size Hierarchy (Pixels)
|
|
76
|
+
|
|
77
|
+
| Element | Size | Color | Usage |
|
|
78
|
+
|---------|------|-------|-------|
|
|
79
|
+
| **Main Title** | 150 | #2196F3 | Document title |
|
|
80
|
+
| **Section Title** | 120 | #2196F3 | Major sections (## H2) |
|
|
81
|
+
| **Subsection** | 100 | #333 | Sub-sections (### H3) |
|
|
82
|
+
| **Normal Text** | (default) | - | Body content |
|
|
83
|
+
| **Notes/Gray** | 80 | gray | Footnotes, metadata |
|
|
84
|
+
|
|
85
|
+
### Color Palette
|
|
86
|
+
|
|
87
|
+
| Color | Hex | Semantic Usage |
|
|
88
|
+
|-------|-----|----------------|
|
|
89
|
+
| **Blue** | #2196F3 | Titles, links, info |
|
|
90
|
+
| **Green** | #4CAF50 | Success, tips, features |
|
|
91
|
+
| **Orange** | #FF9800 | Warnings, caution |
|
|
92
|
+
| **Red** | #F44336 | Errors, danger, important |
|
|
93
|
+
| **Purple** | #9C27B0 | Examples, code |
|
|
94
|
+
| **Gray** | gray | Notes, metadata |
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
98
|
+
## Mandatory Prerequisites
|
|
99
|
+
|
|
100
|
+
> Read before execution:
|
|
101
|
+
|
|
102
|
+
| Document | Purpose | Priority |
|
|
103
|
+
|----------|---------|----------|
|
|
104
|
+
| [specs/format-rules.md](specs/format-rules.md) | Format conversion rules | **P0** |
|
|
105
|
+
| [specs/element-mapping.md](specs/element-mapping.md) | Element type mappings | P1 |
|
|
106
|
+
| [specs/callout-types.md](specs/callout-types.md) | Callout/Admonition types | P1 |
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
## Execution Flow
|
|
111
|
+
|
|
112
|
+
```
|
|
113
|
+
┌────────────────────────────────────────────────────────────────┐
|
|
114
|
+
│ Phase 1: Input Collection │
|
|
115
|
+
│ - Ask: paste text OR file path │
|
|
116
|
+
│ - Output: input-config.json │
|
|
117
|
+
├────────────────────────────────────────────────────────────────┤
|
|
118
|
+
│ Phase 2: Content Analysis │
|
|
119
|
+
│ - Detect structure: headings, lists, code blocks, tables │
|
|
120
|
+
│ - Identify Callouts/Admonitions (>[!type]) │
|
|
121
|
+
│ - Output: analysis.json │
|
|
122
|
+
├────────────────────────────────────────────────────────────────┤
|
|
123
|
+
│ Phase 3: Format Transform │
|
|
124
|
+
│ - Apply BBCode + MD rules from specs/format-rules.md │
|
|
125
|
+
│ - Convert elements with pixel-based sizes │
|
|
126
|
+
│ - Use Markdown --- for separators │
|
|
127
|
+
│ - Output: formatted content │
|
|
128
|
+
├────────────────────────────────────────────────────────────────┤
|
|
129
|
+
│ Phase 4: Output & Preview │
|
|
130
|
+
│ - Save to .bbcode.txt file │
|
|
131
|
+
│ - Display preview │
|
|
132
|
+
│ - Output: final file │
|
|
133
|
+
└────────────────────────────────────────────────────────────────┘
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Callout/Admonition Support
|
|
137
|
+
|
|
138
|
+
支持 Obsidian 风格的 Callout 语法,转换为 BBCode quote:
|
|
139
|
+
|
|
140
|
+
```markdown
|
|
141
|
+
> [!NOTE]
|
|
142
|
+
> 这是一个提示信息
|
|
143
|
+
|
|
144
|
+
> [!WARNING]
|
|
145
|
+
> 这是一个警告信息
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
转换结果:
|
|
149
|
+
|
|
150
|
+
```bbcode
|
|
151
|
+
[quote]
|
|
152
|
+
[size=100][color=#2196F3][b]📝 注意[/b][/color][/size]
|
|
153
|
+
|
|
154
|
+
这是一个提示信息
|
|
155
|
+
[/quote]
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
| Type | Color | Icon |
|
|
159
|
+
|------|-------|------|
|
|
160
|
+
| NOTE/INFO | #2196F3 | 📝 |
|
|
161
|
+
| TIP/HINT | #4CAF50 | 💡 |
|
|
162
|
+
| SUCCESS | #4CAF50 | ✅ |
|
|
163
|
+
| WARNING/CAUTION | #FF9800 | ⚠️ |
|
|
164
|
+
| DANGER/ERROR | #F44336 | ❌ |
|
|
165
|
+
| EXAMPLE | #9C27B0 | 📋 |
|
|
166
|
+
|
|
167
|
+
## Directory Setup
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
const timestamp = new Date().toISOString().slice(0,10).replace(/-/g, '');
|
|
171
|
+
const workDir = `.workflow/.scratchpad/text-formatter-${timestamp}`;
|
|
172
|
+
|
|
173
|
+
Bash(`mkdir -p "${workDir}"`);
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
## Output Structure
|
|
177
|
+
|
|
178
|
+
```
|
|
179
|
+
.workflow/.scratchpad/text-formatter-{date}/
|
|
180
|
+
├── input-config.json # 输入配置
|
|
181
|
+
├── analysis.json # 内容分析结果
|
|
182
|
+
└── output.bbcode.txt # BBCode+MD 输出
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
## Reference Documents
|
|
186
|
+
|
|
187
|
+
| Document | Purpose |
|
|
188
|
+
|----------|---------|
|
|
189
|
+
| [phases/01-input-collection.md](phases/01-input-collection.md) | 收集输入内容 |
|
|
190
|
+
| [phases/02-content-analysis.md](phases/02-content-analysis.md) | 分析内容结构 |
|
|
191
|
+
| [phases/03-format-transform.md](phases/03-format-transform.md) | 格式转换 |
|
|
192
|
+
| [phases/04-output-preview.md](phases/04-output-preview.md) | 输出和预览 |
|
|
193
|
+
| [specs/format-rules.md](specs/format-rules.md) | 格式转换规则 |
|
|
194
|
+
| [specs/element-mapping.md](specs/element-mapping.md) | 元素映射表 |
|
|
195
|
+
| [specs/callout-types.md](specs/callout-types.md) | Callout 类型定义 |
|
|
196
|
+
| [templates/bbcode-template.md](templates/bbcode-template.md) | BBCode 模板 |
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# Phase 1: Input Collection
|
|
2
|
+
|
|
3
|
+
收集用户输入的文本内容。
|
|
4
|
+
|
|
5
|
+
## Objective
|
|
6
|
+
|
|
7
|
+
- 获取用户输入内容(直接粘贴或文件路径)
|
|
8
|
+
- 生成输入配置文件
|
|
9
|
+
|
|
10
|
+
**注意**: 输出格式固定为 BBCode + Markdown 混合格式(论坛优化),无需选择。
|
|
11
|
+
|
|
12
|
+
## Input
|
|
13
|
+
|
|
14
|
+
- 来源: 用户交互
|
|
15
|
+
- 配置: 无前置依赖
|
|
16
|
+
|
|
17
|
+
## Execution Steps
|
|
18
|
+
|
|
19
|
+
### Step 1: 询问输入方式
|
|
20
|
+
|
|
21
|
+
```javascript
|
|
22
|
+
const inputMethod = await AskUserQuestion({
|
|
23
|
+
questions: [
|
|
24
|
+
{
|
|
25
|
+
question: "请选择输入方式",
|
|
26
|
+
header: "输入方式",
|
|
27
|
+
multiSelect: false,
|
|
28
|
+
options: [
|
|
29
|
+
{ label: "直接粘贴文本", description: "在对话中粘贴要格式化的内容" },
|
|
30
|
+
{ label: "指定文件路径", description: "读取指定文件的内容" }
|
|
31
|
+
]
|
|
32
|
+
}
|
|
33
|
+
]
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Step 2: 获取内容
|
|
38
|
+
|
|
39
|
+
```javascript
|
|
40
|
+
let content = '';
|
|
41
|
+
|
|
42
|
+
if (inputMethod["输入方式"] === "直接粘贴文本") {
|
|
43
|
+
// 提示用户粘贴内容
|
|
44
|
+
const textInput = await AskUserQuestion({
|
|
45
|
+
questions: [
|
|
46
|
+
{
|
|
47
|
+
question: "请粘贴要格式化的文本内容(粘贴后选择确认)",
|
|
48
|
+
header: "文本内容",
|
|
49
|
+
multiSelect: false,
|
|
50
|
+
options: [
|
|
51
|
+
{ label: "已粘贴完成", description: "确认已在上方粘贴内容" }
|
|
52
|
+
]
|
|
53
|
+
}
|
|
54
|
+
]
|
|
55
|
+
});
|
|
56
|
+
// 从用户消息中提取文本内容
|
|
57
|
+
content = extractUserText();
|
|
58
|
+
} else {
|
|
59
|
+
// 询问文件路径
|
|
60
|
+
const filePath = await AskUserQuestion({
|
|
61
|
+
questions: [
|
|
62
|
+
{
|
|
63
|
+
question: "请输入文件路径",
|
|
64
|
+
header: "文件路径",
|
|
65
|
+
multiSelect: false,
|
|
66
|
+
options: [
|
|
67
|
+
{ label: "已输入路径", description: "确认路径已在上方输入" }
|
|
68
|
+
]
|
|
69
|
+
}
|
|
70
|
+
]
|
|
71
|
+
});
|
|
72
|
+
content = Read(extractedFilePath);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Step 3: 保存配置
|
|
77
|
+
|
|
78
|
+
```javascript
|
|
79
|
+
const config = {
|
|
80
|
+
input_method: inputMethod["输入方式"],
|
|
81
|
+
target_format: "BBCode+MD", // 固定格式
|
|
82
|
+
original_content: content,
|
|
83
|
+
timestamp: new Date().toISOString()
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
Write(`${workDir}/input-config.json`, JSON.stringify(config, null, 2));
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Output
|
|
90
|
+
|
|
91
|
+
- **File**: `input-config.json`
|
|
92
|
+
- **Format**: JSON
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
{
|
|
96
|
+
"input_method": "直接粘贴文本",
|
|
97
|
+
"target_format": "BBCode+MD",
|
|
98
|
+
"original_content": "...",
|
|
99
|
+
"timestamp": "2026-01-13T..."
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Quality Checklist
|
|
104
|
+
|
|
105
|
+
- [ ] 成功获取用户输入内容
|
|
106
|
+
- [ ] 内容非空且有效
|
|
107
|
+
- [ ] 配置文件已保存
|
|
108
|
+
|
|
109
|
+
## Next Phase
|
|
110
|
+
|
|
111
|
+
→ [Phase 2: Content Analysis](02-content-analysis.md)
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# Phase 2: Content Analysis
|
|
2
|
+
|
|
3
|
+
分析输入内容的结构和语义元素。
|
|
4
|
+
|
|
5
|
+
## Objective
|
|
6
|
+
|
|
7
|
+
- 识别内容结构(标题、段落、列表等)
|
|
8
|
+
- 检测特殊元素(代码块、表格、链接等)
|
|
9
|
+
- 生成结构化分析结果
|
|
10
|
+
|
|
11
|
+
## Input
|
|
12
|
+
|
|
13
|
+
- 依赖: `input-config.json`
|
|
14
|
+
- 配置: `{workDir}/input-config.json`
|
|
15
|
+
|
|
16
|
+
## Execution Steps
|
|
17
|
+
|
|
18
|
+
### Step 1: 加载输入
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
const config = JSON.parse(Read(`${workDir}/input-config.json`));
|
|
22
|
+
const content = config.original_content;
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Step 2: 结构分析
|
|
26
|
+
|
|
27
|
+
```javascript
|
|
28
|
+
function analyzeStructure(text) {
|
|
29
|
+
const analysis = {
|
|
30
|
+
elements: [],
|
|
31
|
+
stats: {
|
|
32
|
+
headings: 0,
|
|
33
|
+
paragraphs: 0,
|
|
34
|
+
lists: 0,
|
|
35
|
+
code_blocks: 0,
|
|
36
|
+
tables: 0,
|
|
37
|
+
links: 0,
|
|
38
|
+
images: 0,
|
|
39
|
+
quotes: 0,
|
|
40
|
+
callouts: 0
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
// Callout 检测正则 (Obsidian 风格)
|
|
45
|
+
const CALLOUT_PATTERN = /^>\s*\[!(\w+)\](?:\s+(.+))?$/;
|
|
46
|
+
|
|
47
|
+
const lines = text.split('\n');
|
|
48
|
+
let currentElement = null;
|
|
49
|
+
let inCodeBlock = false;
|
|
50
|
+
let inList = false;
|
|
51
|
+
|
|
52
|
+
for (let i = 0; i < lines.length; i++) {
|
|
53
|
+
const line = lines[i];
|
|
54
|
+
|
|
55
|
+
// 检测代码块
|
|
56
|
+
if (line.match(/^```/)) {
|
|
57
|
+
inCodeBlock = !inCodeBlock;
|
|
58
|
+
if (inCodeBlock) {
|
|
59
|
+
analysis.elements.push({
|
|
60
|
+
type: 'code_block',
|
|
61
|
+
start: i,
|
|
62
|
+
language: line.replace(/^```/, '').trim()
|
|
63
|
+
});
|
|
64
|
+
analysis.stats.code_blocks++;
|
|
65
|
+
}
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
if (inCodeBlock) continue;
|
|
70
|
+
|
|
71
|
+
// 检测标题 (Markdown 或纯文本模式)
|
|
72
|
+
if (line.match(/^#{1,6}\s/)) {
|
|
73
|
+
const level = line.match(/^(#+)/)[1].length;
|
|
74
|
+
analysis.elements.push({
|
|
75
|
+
type: 'heading',
|
|
76
|
+
level: level,
|
|
77
|
+
content: line.replace(/^#+\s*/, ''),
|
|
78
|
+
line: i
|
|
79
|
+
});
|
|
80
|
+
analysis.stats.headings++;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// 检测列表
|
|
85
|
+
if (line.match(/^[\s]*[-*+]\s/) || line.match(/^[\s]*\d+\.\s/)) {
|
|
86
|
+
if (!inList) {
|
|
87
|
+
analysis.elements.push({
|
|
88
|
+
type: 'list',
|
|
89
|
+
start: i,
|
|
90
|
+
ordered: line.match(/^\d+\./) !== null
|
|
91
|
+
});
|
|
92
|
+
analysis.stats.lists++;
|
|
93
|
+
inList = true;
|
|
94
|
+
}
|
|
95
|
+
continue;
|
|
96
|
+
} else {
|
|
97
|
+
inList = false;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// 检测 Callout (Obsidian 风格) - 优先于普通引用
|
|
101
|
+
const calloutMatch = line.match(CALLOUT_PATTERN);
|
|
102
|
+
if (calloutMatch) {
|
|
103
|
+
const calloutType = calloutMatch[1].toLowerCase();
|
|
104
|
+
const calloutTitle = calloutMatch[2] || null;
|
|
105
|
+
// 收集 Callout 内容行
|
|
106
|
+
const calloutContent = [];
|
|
107
|
+
let j = i + 1;
|
|
108
|
+
while (j < lines.length && lines[j].startsWith('>')) {
|
|
109
|
+
calloutContent.push(lines[j].replace(/^>\s*/, ''));
|
|
110
|
+
j++;
|
|
111
|
+
}
|
|
112
|
+
analysis.elements.push({
|
|
113
|
+
type: 'callout',
|
|
114
|
+
calloutType: calloutType,
|
|
115
|
+
title: calloutTitle,
|
|
116
|
+
content: calloutContent.join('\n'),
|
|
117
|
+
start: i,
|
|
118
|
+
end: j - 1
|
|
119
|
+
});
|
|
120
|
+
analysis.stats.callouts++;
|
|
121
|
+
i = j - 1; // 跳过已处理的行
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// 检测普通引用
|
|
126
|
+
if (line.match(/^>\s/)) {
|
|
127
|
+
analysis.elements.push({
|
|
128
|
+
type: 'quote',
|
|
129
|
+
content: line.replace(/^>\s*/, ''),
|
|
130
|
+
line: i
|
|
131
|
+
});
|
|
132
|
+
analysis.stats.quotes++;
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// 检测表格
|
|
137
|
+
if (line.match(/^\|.*\|$/)) {
|
|
138
|
+
analysis.elements.push({
|
|
139
|
+
type: 'table_row',
|
|
140
|
+
line: i
|
|
141
|
+
});
|
|
142
|
+
if (!analysis.elements.find(e => e.type === 'table')) {
|
|
143
|
+
analysis.stats.tables++;
|
|
144
|
+
}
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// 检测链接
|
|
149
|
+
const links = line.match(/\[([^\]]+)\]\(([^)]+)\)/g);
|
|
150
|
+
if (links) {
|
|
151
|
+
analysis.stats.links += links.length;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 检测图片
|
|
155
|
+
const images = line.match(/!\[([^\]]*)\]\(([^)]+)\)/g);
|
|
156
|
+
if (images) {
|
|
157
|
+
analysis.stats.images += images.length;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// 普通段落
|
|
161
|
+
if (line.trim() && !line.match(/^[-=]{3,}$/)) {
|
|
162
|
+
analysis.elements.push({
|
|
163
|
+
type: 'paragraph',
|
|
164
|
+
line: i,
|
|
165
|
+
preview: line.substring(0, 50)
|
|
166
|
+
});
|
|
167
|
+
analysis.stats.paragraphs++;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
return analysis;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const analysis = analyzeStructure(content);
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Step 3: 语义增强
|
|
178
|
+
|
|
179
|
+
```javascript
|
|
180
|
+
// 识别特殊语义
|
|
181
|
+
function enhanceSemantics(text, analysis) {
|
|
182
|
+
const enhanced = { ...analysis };
|
|
183
|
+
|
|
184
|
+
// 检测关键词强调
|
|
185
|
+
const boldPatterns = text.match(/\*\*[^*]+\*\*/g) || [];
|
|
186
|
+
const italicPatterns = text.match(/\*[^*]+\*/g) || [];
|
|
187
|
+
|
|
188
|
+
enhanced.semantics = {
|
|
189
|
+
emphasis: {
|
|
190
|
+
bold: boldPatterns.length,
|
|
191
|
+
italic: italicPatterns.length
|
|
192
|
+
},
|
|
193
|
+
estimated_reading_time: Math.ceil(text.split(/\s+/).length / 200) // 200 words/min
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
return enhanced;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const enhancedAnalysis = enhanceSemantics(content, analysis);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Step 4: 保存分析结果
|
|
203
|
+
|
|
204
|
+
```javascript
|
|
205
|
+
Write(`${workDir}/analysis.json`, JSON.stringify(enhancedAnalysis, null, 2));
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Output
|
|
209
|
+
|
|
210
|
+
- **File**: `analysis.json`
|
|
211
|
+
- **Format**: JSON
|
|
212
|
+
|
|
213
|
+
```json
|
|
214
|
+
{
|
|
215
|
+
"elements": [
|
|
216
|
+
{ "type": "heading", "level": 1, "content": "Title", "line": 0 },
|
|
217
|
+
{ "type": "paragraph", "line": 2, "preview": "..." },
|
|
218
|
+
{ "type": "callout", "calloutType": "warning", "title": "注意事项", "content": "...", "start": 4, "end": 6 },
|
|
219
|
+
{ "type": "code_block", "start": 8, "language": "javascript" }
|
|
220
|
+
],
|
|
221
|
+
"stats": {
|
|
222
|
+
"headings": 3,
|
|
223
|
+
"paragraphs": 10,
|
|
224
|
+
"lists": 2,
|
|
225
|
+
"code_blocks": 1,
|
|
226
|
+
"tables": 0,
|
|
227
|
+
"links": 5,
|
|
228
|
+
"images": 0,
|
|
229
|
+
"quotes": 1,
|
|
230
|
+
"callouts": 2
|
|
231
|
+
},
|
|
232
|
+
"semantics": {
|
|
233
|
+
"emphasis": { "bold": 5, "italic": 3 },
|
|
234
|
+
"estimated_reading_time": 2
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
## Quality Checklist
|
|
240
|
+
|
|
241
|
+
- [ ] 所有结构元素已识别
|
|
242
|
+
- [ ] 统计信息准确
|
|
243
|
+
- [ ] 语义增强完成
|
|
244
|
+
- [ ] 分析文件已保存
|
|
245
|
+
|
|
246
|
+
## Next Phase
|
|
247
|
+
|
|
248
|
+
→ [Phase 3: Format Transform](03-format-transform.md)
|