✨ feat(vscode): 代码阅读的解析与模板直译核心

This commit is contained in:
cruldra committed 2026-09-24 21:16:21 +08:00
1 parent af56985d9a
commit 4d34b8c715
24 files changed
+2294

No files matched your search

@@ -0,0 +1,88 @@
import type { Outline } from '../testSupport'
import { describe, expect, it } from 'vitest'
import { outline, readFixture, WASM_DIR, withBlocks } from '../testSupport'
import { createPythonAdapter } from './python'
const adapter = createPythonAdapter(WASM_DIR)
function tree(source: string): Promise<Outline[]> {
return withBlocks(adapter, 'python', source, outline)
}
// fixtures/sample.py:行号 1 起
const SAMPLE: Outline[] = [
{ at: 1, kind: 'comment' },
{ at: 3, kind: 'import' },
{ at: 4, kind: 'import' },
{ at: 6, kind: 'const' },
{ at: 7, kind: 'variable' },
{ at: 10, kind: 'function', kids: [
{ at: 11, kind: 'comment' },
{ at: 12, kind: 'comment' },
{ at: 13, kind: 'variable' },
{ at: 14, kind: 'if', kids: [{ at: 15, kind: 'return' }] },
{ at: 16, kind: 'else', kids: [{ at: 17, kind: 'variable' }] },
{ at: 18, kind: 'else', kids: [{ at: 19, kind: 'statement' }] },
{ at: 20, kind: 'loop', kids: [
{ at: 21, kind: 'if', kids: [{ at: 22, kind: 'statement' }] },
] },
{ at: 23, kind: 'try', kids: [
{ at: 24, kind: 'statement', kids: [{ at: 25, kind: 'statement' }] },
] },
{ at: 26, kind: 'catch', kids: [{ at: 27, kind: 'statement' }] },
{ at: 28, kind: 'finally', kids: [{ at: 29, kind: 'statement' }] },
{ at: 30, kind: 'return' },
] },
{ at: 33, kind: 'class', kids: [
{ at: 34, kind: 'field' },
{ at: 35, kind: 'field' },
{ at: 36, kind: 'field' },
{ at: 37, kind: 'variable' },
{ at: 39, kind: 'function', kids: [{ at: 40, kind: 'return' }] },
] },
]
describe('python 代码块树', () => {
it('样例覆盖 import / def / docstring / if-elif-else / for / try-except-finally / with / 推导式 / class 字段', async () => {
expect(await tree(readFixture('sample.py'))).toEqual(SAMPLE)
})
it('装饰器算进头部;冒号后、主体前的注释归子块;循环的 else 是兄弟块;match 的 case 是子块 if', async () => {
const source = [
'@cache',
'def load(key):',
' # 先查缓存',
' while key:',
' key = key[1:]',
' else:',
' pass',
' match key:',
' case \'a\':',
' return 1',
' case _:',
' return 2',
].join('\n')
expect(await tree(source)).toEqual([
{ at: [1, 2], kind: 'function', kids: [
{ at: 3, kind: 'comment' },
{ at: 4, kind: 'loop', kids: [{ at: 5, kind: 'variable' }] },
{ at: 6, kind: 'else', kids: [{ at: 7, kind: 'statement' }] },
{ at: 8, kind: 'if', kids: [
{ at: 9, kind: 'if', kids: [{ at: 10, kind: 'return' }] },
{ at: 11, kind: 'if', kids: [{ at: 12, kind: 'return' }] },
] },
] },
])
})
it('docstring 只认主体开头;不是开头的字符串表达式是语句', async () => {
const source = [
'def f():',
' x = 1',
' """not a docstring"""',
].join('\n')
expect(await tree(source)).toEqual([
{ at: 1, kind: 'function', kids: [{ at: 2, kind: 'variable' }, { at: 3, kind: 'statement' }] },
])
})
})