import type { BlockKind, CallFacts, Node } from './contract' import { describe, expect, it, vi } from 'vitest' import { DocumentCallees } from './calleeKinds' /** 一次调用:只用到被调用的表达式原文,和最后那个名字的下标。 */ function call(callee: string, nameAt?: number): CallFacts { const facts = { callee: { text: callee } as Node, argumentList: {} as Node, arguments: [] } return nameAt === undefined ? facts : { ...facts, name: { startIndex: nameAt } as Node } } /** 各下标处名字的定义是哪种块(语言扩展答的;没有的是没答);记下问了哪些下标。 */ function source(kinds: Record): { asked: number[], kindOf: (offset: number) => Promise } { const asked: number[] = [] return { asked, kindOf: async (offset) => { asked.push(offset) return kinds[offset] }, } } describe('调用的名字定义成哪种块(DocumentCallees)', () => { it('第一遍当没查到,按被调用的表达式原文记下问了什么(写法一样的按一处问);查到后叫宿主重排,再排时交出来', async () => { let changed = 0 const callees = new DocumentCallees(() => changed++, []) const first = callees.session() expect(first.calleeKind(call('UserDetailResponse', 40))).toBeUndefined() expect(first.calleeKind(call('UserDetailResponse', 90))).toBeUndefined() expect(first.calleeKind(call('user_service.update_user', 120))).toBeUndefined() expect(first.requests()).toEqual([{ callee: 'UserDetailResponse', offset: 40 }, { callee: 'user_service.update_user', offset: 120 }]) const from = source({ 40: 'class', 120: 'function' }) callees.resolve(1, first.requests(), from.kindOf) await vi.waitFor(() => expect(changed).toBe(1)) const second = callees.session() expect(second.calleeKind(call('UserDetailResponse', 12))).toBe('class') expect(second.calleeKind(call('user_service.update_user', 7))).toBe('function') // 同一版本再发一遍:问过的不再查 callees.resolve(1, first.requests(), from.kindOf) await Promise.resolve() expect(from.asked).toEqual([40, 120]) }) it('revision:查到的答案变了才加一,新版本查到的一样不加(差异按它定旧版本要不要重新解析)', async () => { const callees = new DocumentCallees(() => {}, []) const session = callees.session() session.calleeKind(call('Detail', 40)) session.calleeKind(call('build', 5)) expect(callees.revision).toBe(0) const kinds: Record = { 40: 'class', 5: null } callees.resolve(1, session.requests(), source(kinds).kindOf) await vi.waitFor(() => expect(callees.revision).toBe(1)) const same = source(kinds) callees.resolve(2, session.requests(), same.kindOf) await vi.waitFor(() => expect(same.asked).toEqual([40, 5])) await Promise.resolve() expect(callees.revision).toBe(1) kinds[40] = 'function' callees.resolve(3, session.requests(), source(kinds).kindOf) await vi.waitFor(() => expect(callees.revision).toBe(2)) }) it('被调用的不是名字(没有 name)不问;查了没有(null)不算变了', async () => { let changed = 0 const callees = new DocumentCallees(() => changed++, []) const session = callees.session() expect(session.calleeKind(call('handlers[k]'))).toBeUndefined() session.calleeKind(call('build', 5)) expect(session.requests()).toEqual([{ callee: 'build', offset: 5 }]) const from = source({ 5: null }) callees.resolve(1, session.requests(), from.kindOf) await vi.waitFor(() => expect(from.asked).toEqual([5])) await Promise.resolve() expect(changed).toBe(0) }) it('语言扩展还没起来(没答):隔一会儿只再查没答的,查到了再叫重排', async () => { let changed = 0 const pending: (() => void)[] = [] const scheduled: number[] = [] const callees = new DocumentCallees(() => changed++, [5, 10], (task, ms) => { scheduled.push(ms) pending.push(task) return setTimeout(() => {}, 0) }) const session = callees.session() session.calleeKind(call('Detail', 40)) session.calleeKind(call('run', 60)) const kinds: Record = { 60: 'function' } const from = source(kinds) callees.resolve(1, session.requests(), from.kindOf) await vi.waitFor(() => expect(scheduled).toEqual([5])) expect(changed).toBe(1) kinds[40] = 'class' pending.shift()?.() await vi.waitFor(() => expect(changed).toBe(2)) expect(from.asked).toEqual([40, 60, 40]) expect(callees.session().calleeKind(call('Detail', 40))).toBe('class') }) })