lone-format 0.9.6 → 0.10.0

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.
@@ -1,230 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
-
4
- <head>
5
- <meta charset="UTF-8">
6
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
7
- <title>JSON Editor Performance Test</title>
8
- <style>
9
- body {
10
- font-family: Arial, sans-serif;
11
- max-width: 1200px;
12
- margin: 0 auto;
13
- padding: 20px;
14
- }
15
-
16
- .performance-info {
17
- background: #f5f5f5;
18
- padding: 20px;
19
- border-radius: 8px;
20
- margin-bottom: 20px;
21
- }
22
-
23
- .optimization-list {
24
- background: #e8f5e8;
25
- padding: 15px;
26
- border-left: 4px solid #4caf50;
27
- margin: 20px 0;
28
- }
29
-
30
- .comparison {
31
- display: grid;
32
- grid-template-columns: 1fr 1fr;
33
- gap: 20px;
34
- margin: 20px 0;
35
- }
36
-
37
- .method {
38
- background: #f9f9f9;
39
- padding: 15px;
40
- border-radius: 8px;
41
- }
42
-
43
- .old-method {
44
- background: #fff3e0;
45
- border-left: 4px solid #ff9800;
46
- }
47
-
48
- .new-method {
49
- background: #e8f5e8;
50
- border-left: 4px solid #4caf50;
51
- }
52
-
53
- pre {
54
- background: #2d3748;
55
- color: #e2e8f0;
56
- padding: 15px;
57
- border-radius: 8px;
58
- overflow-x: auto;
59
- font-size: 14px;
60
- }
61
- </style>
62
- </head>
63
-
64
- <body>
65
- <h1>🚀 JSON Editor Performance Optimization</h1>
66
-
67
- <div class="performance-info">
68
- <h2>性能优化概览</h2>
69
- <p>我们对 Vue 3 JSON 编辑组件进行了重大性能优化,特别是在处理大型 JSON 对象的 key 重命名操作时。</p>
70
- </div>
71
-
72
- <div class="optimization-list">
73
- <h3>✅ 主要优化措施</h3>
74
- <ul>
75
- <li><strong>浅拷贝策略</strong>:只拷贝修改路径上的对象,而不是整个 JSON 结构</li>
76
- <li><strong>原地重命名</strong>:直接修改对象属性而不重建整个数据结构</li>
77
- <li><strong>路径优化</strong>:精确定位需要修改的对象,避免不必要的遍历</li>
78
- <li><strong>顺序保持</strong>:使用 Object.keys() 遍历保持键的顺序</li>
79
- <li><strong>内存优化</strong>:避免频繁的 JSON.parse(JSON.stringify()) 深拷贝操作</li>
80
- </ul>
81
- </div>
82
-
83
- <div class="comparison">
84
- <div class="method old-method">
85
- <h3>🐌 优化前 (性能问题)</h3>
86
- <pre><code>// 深拷贝整个对象
87
- const result = JSON.parse(JSON.stringify(obj))
88
-
89
- // 重新构建整个父对象
90
- const newParent = {}
91
- for (const key in parent) {
92
- if (key === oldKey) {
93
- newParent[newKey] = parent[key]
94
- } else {
95
- newParent[key] = parent[key]
96
- }
97
- }
98
-
99
- // 清空并重新填充原对象
100
- for (const key in parent) {
101
- delete parent[key]
102
- }
103
- for (const key in newParent) {
104
- parent[key] = newParent[key]
105
- }
106
- </code></pre>
107
- <p><strong>问题:</strong></p>
108
- <ul>
109
- <li>❌ 深拷贝整个 JSON 对象(O(n) 时间和空间复杂度)</li>
110
- <li>❌ 重建不相关的对象</li>
111
- <li>❌ 大量内存分配和垃圾回收</li>
112
- <li>❌ 大型对象时明显延迟</li>
113
- </ul>
114
- </div>
115
-
116
- <div class="method new-method">
117
- <h3>🚀 优化后 (高性能)</h3>
118
- <pre><code>// 只拷贝修改路径上的对象
119
- const result = shallowCopyToPath(obj, keys.slice(0, -1))
120
-
121
- // 直接重新排序对象键
122
- const reorderObjectKeys = (obj, oldKey, newKey) => {
123
- const keys = Object.keys(obj)
124
- const newObj = {}
125
-
126
- for (const key of keys) {
127
- if (key === oldKey) {
128
- newObj[newKey] = obj[key]
129
- } else {
130
- newObj[key] = obj[key]
131
- }
132
- }
133
-
134
- return newObj
135
- }
136
-
137
- // 浅拷贝路径函数
138
- const shallowCopyToPath = (obj, pathKeys) => {
139
- if (pathKeys.length === 0) return obj
140
-
141
- if (Array.isArray(obj)) {
142
- const newArray = [...obj]
143
- // 只拷贝需要修改的路径
144
- } else {
145
- const newObj = { ...obj }
146
- // 只拷贝需要修改的路径
147
- }
148
- }
149
- </code></pre>
150
- <p><strong>优势:</strong></p>
151
- <ul>
152
- <li>✅ 浅拷贝,只拷贝修改路径(O(log n) 复杂度)</li>
153
- <li>✅ 保留不相关对象的引用</li>
154
- <li>✅ 最小化内存使用</li>
155
- <li>✅ 即使大型对象也能瞬时响应</li>
156
- </ul>
157
- </div>
158
- </div>
159
-
160
- <h2>🎯 性能基准测试</h2>
161
- <div class="performance-info">
162
- <h3>测试场景</h3>
163
- <ul>
164
- <li><strong>小型对象</strong> (10-50 个键):两种方法都能快速响应</li>
165
- <li><strong>中型对象</strong> (100-500 个键):优化后的方法明显更快</li>
166
- <li><strong>大型对象</strong> (1000+ 个键):优化前有明显延迟,优化后依然瞬时响应</li>
167
- <li><strong>深度嵌套</strong> (5+ 层深度):优化后显著减少不必要的拷贝操作</li>
168
- </ul>
169
- </div>
170
-
171
- <h2>🧪 实际测试案例</h2>
172
- <p>在上面的演示中,我们成功测试了以下场景:</p>
173
- <ul>
174
- <li>✅ 在包含多个大型嵌套对象的 JSON 中重命名 key</li>
175
- <li>✅ key 顺序保持不变(userProfiles → inventory → orders)</li>
176
- <li>✅ 瞬时响应,无明显延迟</li>
177
- <li>✅ 内存使用优化,避免了不必要的对象重建</li>
178
- </ul>
179
-
180
- <h2>📊 性能对比总结</h2>
181
- <table style="width:100%; border-collapse: collapse; margin: 20px 0;">
182
- <thead>
183
- <tr style="background: #f5f5f5;">
184
- <th style="border: 1px solid #ddd; padding: 12px;">场景</th>
185
- <th style="border: 1px solid #ddd; padding: 12px;">优化前</th>
186
- <th style="border: 1px solid #ddd; padding: 12px;">优化后</th>
187
- <th style="border: 1px solid #ddd; padding: 12px;">改进</th>
188
- </tr>
189
- </thead>
190
- <tbody>
191
- <tr>
192
- <td style="border: 1px solid #ddd; padding: 12px;"><strong>小型对象 (50 keys)</strong></td>
193
- <td style="border: 1px solid #ddd; padding: 12px;">~5ms</td>
194
- <td style="border: 1px solid #ddd; padding: 12px;">~1ms</td>
195
- <td style="border: 1px solid #ddd; padding: 12px; color: green;"><strong>5x 更快</strong></td>
196
- </tr>
197
- <tr>
198
- <td style="border: 1px solid #ddd; padding: 12px;"><strong>中型对象 (500 keys)</strong></td>
199
- <td style="border: 1px solid #ddd; padding: 12px;">~50ms</td>
200
- <td style="border: 1px solid #ddd; padding: 12px;">~2ms</td>
201
- <td style="border: 1px solid #ddd; padding: 12px; color: green;"><strong>25x 更快</strong></td>
202
- </tr>
203
- <tr>
204
- <td style="border: 1px solid #ddd; padding: 12px;"><strong>大型对象 (5000 keys)</strong></td>
205
- <td style="border: 1px solid #ddd; padding: 12px;">~500ms+</td>
206
- <td style="border: 1px solid #ddd; padding: 12px;">~3ms</td>
207
- <td style="border: 1px solid #ddd; padding: 12px; color: green;"><strong>100x+ 更快</strong></td>
208
- </tr>
209
- <tr>
210
- <td style="border: 1px solid #ddd; padding: 12px;"><strong>深度嵌套 (10 levels)</strong></td>
211
- <td style="border: 1px solid #ddd; padding: 12px;">~100ms+</td>
212
- <td style="border: 1px solid #ddd; padding: 12px;">~5ms</td>
213
- <td style="border: 1px solid #ddd; padding: 12px; color: green;"><strong>20x 更快</strong></td>
214
- </tr>
215
- </tbody>
216
- </table>
217
-
218
- <div class="optimization-list">
219
- <h3>🎉 总结</h3>
220
- <p>通过这些优化,我们实现了:</p>
221
- <ul>
222
- <li><strong>显著的性能提升</strong>:大型对象操作速度提升 100 倍以上</li>
223
- <li><strong>更好的用户体验</strong>:即使在复杂的 JSON 结构中也能实现瞬时响应</li>
224
- <li><strong>内存效率</strong>:避免不必要的对象拷贝,减少内存占用</li>
225
- <li><strong>功能完整性</strong>:保持所有原有功能,包括 key 顺序保持</li>
226
- </ul>
227
- </div>
228
- </body>
229
-
230
- </html>
@@ -1,44 +0,0 @@
1
- import { formatSql } from '../src/components/SqlFormat/parser.ts'
2
-
3
- // 这是 App.vue 中的 UPDATE 示例
4
- const appVueSql = `-- UPDATE statement with conditions
5
- UPDATE users SET status = 'inactive', updated_at = NOW (), last_login = NULL WHERE last_login < DATE_SUB (NOW (), INTERVAL 6 MONTH) AND status = 'active';`
6
-
7
- console.log('=== Testing App.vue UPDATE SQL ===\n')
8
- console.log('Input (from App.vue):')
9
- console.log(appVueSql)
10
- console.log('\n' + '='.repeat(60) + '\n')
11
-
12
- const formatted = formatSql(appVueSql, { tabWidth: 2, keywordCase: 'upper' })
13
- console.log('Formatted result:')
14
- console.log(formatted)
15
- console.log('\n' + '='.repeat(60) + '\n')
16
-
17
- // 检查每一行的缩进
18
- const lines = formatted.split('\n')
19
- console.log('Line-by-line analysis:')
20
- lines.forEach((line, idx) => {
21
- const leadingSpaces = line.match(/^(\s*)/)?.[1].length || 0
22
- const trimmed = line.trim()
23
- console.log(`${idx + 1}. (${leadingSpaces} sp) "${line}"`)
24
- })
25
-
26
- console.log('\n' + '='.repeat(60) + '\n')
27
-
28
- // 检查 SET 字段是否有缩进
29
- const setLineIdx = lines.findIndex(l => l.trim() === 'SET')
30
- if (setLineIdx !== -1 && setLineIdx + 1 < lines.length) {
31
- const firstSetField = lines[setLineIdx + 1]
32
- const spaces = firstSetField.match(/^(\s*)/)?.[1].length || 0
33
- console.log(`SET keyword is on line ${setLineIdx + 1}`)
34
- console.log(`First SET field is on line ${setLineIdx + 2}: "${firstSetField}"`)
35
- console.log(`Leading spaces: ${spaces}`)
36
-
37
- if (spaces === 2) {
38
- console.log('✅ Correct! SET fields have 2-space indentation')
39
- } else if (spaces === 0) {
40
- console.log('❌ ERROR! SET fields have NO indentation')
41
- } else {
42
- console.log(`⚠️ WARNING! SET fields have ${spaces}-space indentation (expected 2)`)
43
- }
44
- }
@@ -1,40 +0,0 @@
1
- const columnsDef = ` id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, order_number VARCHAR(50) NOT NULL, total_amount DECIMAL(10, 2) NOT NULL, status ENUM ('pending', 'processing', 'completed', 'cancelled') DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_number (order_number), KEY idx_user_id (user_id), KEY idx_status (status), KEY idx_created_at (created_at), CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE `
2
-
3
- const indent = ' '
4
-
5
- // 分割列定义和约束(排除括号内的逗号,如 ENUM(...) 中的逗号)
6
- const definitions = []
7
- let current = ''
8
- let parenDepth = 0
9
-
10
- for (let i = 0; i < columnsDef.length; i++) {
11
- const char = columnsDef[i]
12
-
13
- if (char === '(') {
14
- parenDepth++
15
- current += char
16
- } else if (char === ')') {
17
- parenDepth--
18
- current += char
19
- } else if (char === ',' && parenDepth === 0) {
20
- // 在括号外的逗号处分割
21
- if (current.trim()) {
22
- console.log(`[Split at ${i}] parenDepth=${parenDepth}, current="${current.trim()}"`)
23
- definitions.push(current.trim())
24
- }
25
- current = ''
26
- } else {
27
- current += char
28
- }
29
- }
30
-
31
- // 添加最后一个定义
32
- if (current.trim()) {
33
- console.log(`[Final] current="${current.trim()}"`)
34
- definitions.push(current.trim())
35
- }
36
-
37
- console.log('\n=== Definitions ===')
38
- definitions.forEach((def, idx) => {
39
- console.log(`${idx + 1}. ${def}`)
40
- })
@@ -1,25 +0,0 @@
1
- import { formatSql, parseSqlClauses } from '../src/components/SqlFormat/parser.ts'
2
-
3
- // 测试场景:用户输入的原始 SQL
4
- const originalSql = `SELECT u.id, u.username FROM users u WHERE status = 'active';`
5
-
6
- console.log('=== 原始输入(modelValue)===')
7
- console.log(originalSql)
8
-
9
- console.log('\n=== 格式化后(页面显示)===')
10
- const formatted = formatSql(originalSql, { tabWidth: 2, keywordCase: 'upper' })
11
- console.log(formatted)
12
-
13
- console.log('\n=== 解析为子句(实际显示内容)===')
14
- const parsed = parseSqlClauses(originalSql)
15
- console.log('子句数量:', parsed.clauses.length)
16
- parsed.clauses.forEach((clause, i) => {
17
- console.log(`\nClause ${i}: ${clause.type}`)
18
- console.log(clause.content)
19
- })
20
-
21
- console.log('\n=== 问题分析 ===')
22
- console.log('当前复制功能复制的是: props.modelValue')
23
- console.log('用户看到的是: 经过 formatSql 格式化的内容')
24
- console.log('是否一致:', originalSql === formatted ? 'YES' : 'NO')
25
- console.log('\n建议: 复制功能应该复制格式化后的内容,而不是原始输入')
@@ -1,52 +0,0 @@
1
- import { formatSql } from '../src/components/SqlFormat/parser.ts'
2
-
3
- const inputSql = `-- CREATE TABLE statement
4
- CREATE TABLE IF NOT EXISTS orders ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, user_id BIGINT UNSIGNED NOT NULL, order_number VARCHAR(50) NOT NULL, total_amount DECIMAL(10, 2) NOT NULL, status ENUM ('pending', 'processing', 'completed', 'cancelled') DEFAULT 'pending', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY uk_order_number (order_number), KEY idx_user_id (user_id), KEY idx_status (status), KEY idx_created_at (created_at), CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;`
5
-
6
- const expectedOutput = `-- CREATE TABLE statement
7
- CREATE TABLE IF NOT EXISTS orders (
8
- id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
9
- user_id BIGINT UNSIGNED NOT NULL,
10
- order_number VARCHAR(50) NOT NULL,
11
- total_amount DECIMAL(10, 2) NOT NULL,
12
- status ENUM ('pending', 'processing', 'completed', 'cancelled') DEFAULT 'pending',
13
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
14
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
15
- PRIMARY KEY (id),
16
- UNIQUE KEY uk_order_number (order_number),
17
- KEY idx_user_id (user_id),
18
- KEY idx_status (status),
19
- KEY idx_created_at (created_at),
20
- CONSTRAINT fk_orders_user FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE
21
- ) ENGINE = InnoDB DEFAULT CHARSET = utf8mb4 COLLATE = utf8mb4_unicode_ci;`
22
-
23
- const result = formatSql(inputSql, { tabWidth: 2, keywordCase: 'upper' })
24
-
25
- console.log('=== 输入 SQL ===')
26
- console.log(inputSql)
27
- console.log('\n=== 当前格式化结果 ===')
28
- console.log(result)
29
- console.log('\n=== 期望结果 ===')
30
- console.log(expectedOutput)
31
- console.log('\n=== 对比 ===')
32
-
33
- const match = result.trim() === expectedOutput.trim()
34
- console.log('是否匹配:', match ? 'YES ✓' : 'NO ✗')
35
-
36
- if (!match) {
37
- console.log('\n=== 差异分析 ===')
38
- const resultLines = result.trim().split('\n')
39
- const expectedLines = expectedOutput.trim().split('\n')
40
- const maxLines = Math.max(resultLines.length, expectedLines.length)
41
-
42
- for (let i = 0; i < maxLines; i++) {
43
- const resultLine = resultLines[i] || '(missing)'
44
- const expectedLine = expectedLines[i] || '(missing)'
45
-
46
- if (resultLine !== expectedLine) {
47
- console.log(`Line ${i + 1} 不同:`)
48
- console.log(` 当前: "${resultLine}"`)
49
- console.log(` 期望: "${expectedLine}"`)
50
- }
51
- }
52
- }
File without changes
@@ -1,57 +0,0 @@
1
- // 测试最终格式化阶段的逻辑
2
-
3
- const finalLines = `INSERT INTO
4
- users (username, email, password, status, created_at)
5
- VALUES
6
- (
7
- 'john_doe',
8
- )`.split('\n')
9
-
10
- const clauseKeywords = [
11
- 'WITH', 'SELECT', 'FROM', 'WHERE', 'GROUP BY', 'HAVING', 'ORDER BY', 'LIMIT', 'OFFSET',
12
- 'INNER JOIN', 'LEFT JOIN', 'RIGHT JOIN', 'FULL JOIN', 'CROSS JOIN', 'OUTER JOIN', 'JOIN',
13
- 'UNION', 'UNION ALL', 'INTERSECT', 'EXCEPT',
14
- 'INSERT INTO', 'UPDATE', 'DELETE FROM',
15
- 'CREATE', 'ALTER', 'DROP'
16
- ].sort((a, b) => b.length - a.length)
17
-
18
- const formatted = []
19
- const indent = ' '
20
-
21
- for (let i = 0; i < finalLines.length; i++) {
22
- const line = finalLines[i]
23
- const trimmed = line.trim()
24
-
25
- const hasIndent = line.startsWith(' ') || line.startsWith('\t')
26
-
27
- console.log(`\nLine ${i + 1}: ${JSON.stringify(line)}`)
28
- console.log(` trimmed: ${JSON.stringify(trimmed)}`)
29
- console.log(` hasIndent: ${hasIndent}`)
30
-
31
- // 如果已经有缩进,保持原样
32
- if (hasIndent) {
33
- console.log(` -> KEEP (has indent)`)
34
- formatted.push(line)
35
- continue
36
- }
37
-
38
- // 检查是否是主子句
39
- const isMainClause = clauseKeywords.some(clause => {
40
- const regex = new RegExp(`^${clause}\\b`, 'i')
41
- return regex.test(trimmed)
42
- })
43
-
44
- console.log(` isMainClause: ${isMainClause}`)
45
-
46
- if (isMainClause) {
47
- console.log(` -> TRIM (main clause)`)
48
- formatted.push(trimmed)
49
- continue
50
- }
51
-
52
- console.log(` -> TRIM (default)`)
53
- formatted.push(trimmed)
54
- }
55
-
56
- console.log('\n=== Final Output ===')
57
- console.log(formatted.join('\n'))
@@ -1,45 +0,0 @@
1
- import { formatSql } from '../src/components/SqlFormat/parser.ts'
2
-
3
- const input = `-- Complex query with subquery and window functions
4
- WITH user_stats AS ( SELECT u.id, u.username, COUNT(DISTINCT o.id) AS order_count, SUM(o.total_amount) AS total_spent, AVG(o.total_amount) AS avg_order_value, ROW_NUMBER() OVER ( ORDER BY SUM(o.total_amount) DESC ) AS spending_rank FROM users u LEFT JOIN orders o ON u.id = o.user_id WHERE u.created_at >= DATE_SUB (NOW (), INTERVAL 1 YEAR) GROUP BY u.id, u.username ) SELECT us.*, CASE WHEN us.spending_rank <= 10 THEN 'VIP' WHEN us.spending_rank <= 50 THEN 'Premium' ELSE 'Regular' END AS customer_tier FROM user_stats us WHERE us.order_count > 0 ORDER BY us.spending_rank;`;
5
-
6
- const result = formatSql(input, { tabWidth: 2, keywordCase: 'upper' });
7
-
8
- console.log('===== Formatted SQL =====');
9
- console.log(result);
10
- console.log('\n===== Expected SQL =====');
11
- console.log(`-- Complex query with subquery and window functions
12
- WITH
13
- user_stats AS (
14
- SELECT
15
- u.id,
16
- u.username,
17
- COUNT(DISTINCT o.id) AS order_count,
18
- SUM(o.total_amount) AS total_spent,
19
- AVG(o.total_amount) AS avg_order_value,
20
- ROW_NUMBER() OVER (
21
- ORDER BY
22
- SUM(o.total_amount) DESC
23
- ) AS spending_rank
24
- FROM
25
- users u
26
- LEFT JOIN orders o ON u.id = o.user_id
27
- WHERE
28
- u.created_at >= DATE_SUB (NOW (), INTERVAL 1 YEAR)
29
- GROUP BY
30
- u.id,
31
- u.username
32
- )
33
- SELECT
34
- us.*,
35
- CASE
36
- WHEN us.spending_rank <= 10 THEN 'VIP'
37
- WHEN us.spending_rank <= 50 THEN 'Premium'
38
- ELSE 'Regular'
39
- END AS customer_tier
40
- FROM
41
- user_stats us
42
- WHERE
43
- us.order_count > 0
44
- ORDER BY
45
- us.spending_rank;`);
@@ -1,62 +0,0 @@
1
- // 简化版的 highlightSql 测试
2
- import { tokenizeSql } from '../src/components/SqlFormat/parser.ts'
3
-
4
- const sql = `SET
5
- status = 'inactive',
6
- updated_at = NOW()`
7
-
8
- console.log('=== Testing highlightSql Logic ===\n')
9
- console.log('Input SQL:')
10
- console.log(sql)
11
- console.log('\n' + '='.repeat(70) + '\n')
12
-
13
- const tokens = tokenizeSql(sql)
14
-
15
- console.log('Tokens:')
16
- tokens.forEach((token, idx) => {
17
- const visual = token.value.replace(/\n/g, '\\n').replace(/ /g, '·')
18
- console.log(`${idx}. [${token.type.padEnd(12)}] "${visual}"`)
19
- })
20
-
21
- console.log('\n' + '='.repeat(70) + '\n')
22
-
23
- // 模拟 highlightSql 的处理
24
- const highlighted = tokens.map((token, idx) => {
25
- if (token.type === 'whitespace') {
26
- const converted = token.value.replace(/ /g, '&nbsp;').replace(/\n/g, '\n')
27
- const visual = converted.replace(/\n/g, '\\n')
28
- console.log(`Token ${idx}: whitespace "${token.value.replace(/\n/g, '\\n').replace(/ /g, '·')}" => "${visual}"`)
29
- return converted
30
- }
31
-
32
- // 其他 token 包装在 span 中
33
- const escaped = token.value
34
- return `<span style="color: #xxx">${escaped}</span>`
35
- }).join('')
36
-
37
- console.log('\n' + '='.repeat(70) + '\n')
38
-
39
- console.log('Highlighted HTML:')
40
- console.log(highlighted)
41
-
42
- console.log('\n' + '='.repeat(70) + '\n')
43
-
44
- // 检查第二行开头是否有 &nbsp;&nbsp;
45
- const lines = highlighted.split('\n')
46
- console.log(`Total HTML lines: ${lines.length}`)
47
- lines.forEach((line, idx) => {
48
- const first20 = line.substring(0, 50)
49
- const hasNbsp = line.startsWith('&nbsp;&nbsp;')
50
- console.log(`Line ${idx + 1} [&nbsp;=${hasNbsp}]: "${first20}..."`)
51
- })
52
-
53
- // 检查具体问题
54
- const line2 = lines[1]
55
- if (line2) {
56
- if (line2.startsWith('&nbsp;&nbsp;')) {
57
- console.log('\n✅ Line 2 starts with &nbsp;&nbsp; (correct indentation)')
58
- } else {
59
- console.log('\n❌ Line 2 does NOT start with &nbsp;&nbsp;')
60
- console.log(`First 100 chars: "${line2.substring(0, 100)}"`)
61
- }
62
- }
@@ -1,15 +0,0 @@
1
- const indent = ' ' // 2 spaces
2
-
3
- const result = []
4
- result.push('INSERT INTO')
5
- result.push(indent + 'users (username, email, password, status, created_at)')
6
- result.push('VALUES')
7
- result.push(indent + '(')
8
- result.push(indent + indent + "'john_doe',")
9
- result.push(indent + ')')
10
-
11
- const output = result.join('\n')
12
- console.log('=== 直接拼接测试 ===')
13
- console.log(output)
14
- console.log('\n=== 转义查看 ===')
15
- console.log(JSON.stringify(output))
@@ -1,66 +0,0 @@
1
- <!DOCTYPE html>
2
- <html lang="en">
3
- <head>
4
- <meta charset="UTF-8">
5
- <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
- <title>缩进测试</title>
7
- <style>
8
- body {
9
- font-family: monospace;
10
- padding: 20px;
11
- }
12
- .test-section {
13
- margin-bottom: 30px;
14
- border: 1px solid #ccc;
15
- padding: 15px;
16
- }
17
- pre {
18
- background: #f5f5f5;
19
- padding: 10px;
20
- border: 1px solid #ddd;
21
- }
22
- .test1 { white-space: pre; }
23
- .test2 { white-space: pre-wrap; }
24
- .test3 { white-space: pre; }
25
- </style>
26
- </head>
27
- <body>
28
- <h1>缩进渲染测试</h1>
29
-
30
- <div class="test-section">
31
- <h2>测试1: white-space: pre + 普通空格</h2>
32
- <pre class="test1" id="test1"></pre>
33
- </div>
34
-
35
- <div class="test-section">
36
- <h2>测试2: white-space: pre-wrap + 普通空格</h2>
37
- <pre class="test2" id="test2"></pre>
38
- </div>
39
-
40
- <div class="test-section">
41
- <h2>测试3: white-space: pre + &nbsp;</h2>
42
- <pre class="test3" id="test3"></pre>
43
- </div>
44
-
45
- <script>
46
- const sqlText = `SELECT
47
- u.id,
48
- u.username,
49
- u.email
50
- FROM users u`;
51
-
52
- // 测试1: 直接 innerHTML 赋值
53
- document.getElementById('test1').innerHTML = sqlText;
54
-
55
- // 测试2: 直接 innerHTML 赋值
56
- document.getElementById('test2').innerHTML = sqlText;
57
-
58
- // 测试3: 空格转 &nbsp;
59
- const sqlWithNbsp = sqlText.replace(/ /g, '&nbsp;');
60
- document.getElementById('test3').innerHTML = sqlWithNbsp;
61
-
62
- console.log('原始文本:', sqlText);
63
- console.log('转换后:', sqlWithNbsp);
64
- </script>
65
- </body>
66
- </html>
@@ -1,29 +0,0 @@
1
- const indent = ' '
2
-
3
- // 模拟 INSERT 格式化函数
4
- const formatInsert = () => {
5
- const insertKeyword = 'INSERT INTO'
6
- const valuesKeyword = 'VALUES'
7
- const tableName = 'users'
8
- const columnList = 'username, email, password, status, created_at'
9
-
10
- let result = `${insertKeyword}\n${indent}${tableName} (${columnList})\n${valuesKeyword}`
11
-
12
- // 第一组值
13
- result += '\n' + indent + '('
14
- result += '\n' + indent + indent + "'john_doe',"
15
- result += '\n' + indent + indent + "'john@example.com',"
16
- result += '\n' + indent + ')'
17
-
18
- return result
19
- }
20
-
21
- const output = formatInsert()
22
- console.log('=== INSERT 格式化函数输出 ===')
23
- console.log(output)
24
-
25
- console.log('\n=== 每行的缩进检查 ===')
26
- output.split('\n').forEach((line, idx) => {
27
- const spaces = line.match(/^( *)/)[1].length
28
- console.log(`Line ${idx + 1}: ${spaces} spaces - ${JSON.stringify(line)}`)
29
- })