import { describe, expect, it } from 'vitest'; import { flattenParameterCandidates, findBackspaceTokenRange, findTokenRangeAtCursor, flattenParameterNames, formatParamToken, getTokenRanges, insertTextAtCursor, parseTokenParts, splitTokenDisplay, } from './paramToken'; describe('paramToken utils', () => { it('should flatten parameter names with nested paths', () => { const result = flattenParameterNames([ { name: 'input', }, { name: 'documents', children: [ { name: 'title', }, { name: 'meta', children: [ { name: 'author', }, ], }, ], }, ]); expect(result).toEqual([ 'input', 'documents', 'documents.title', 'documents.meta', 'documents.meta.author', ]); }); it('should keep unresolved candidates in parameter list', () => { const result = flattenParameterCandidates([ { name: 'input', refType: 'ref', ref: '', }, { name: 'docs', refType: 'ref', ref: 'documents', }, { name: 'runtimeInput', refType: 'input', }, ]); expect(result).toEqual([ { dataType: undefined, disconnected: false, displayName: 'input', name: 'input', resolved: false, }, { dataType: undefined, disconnected: false, displayName: 'docs', name: 'docs', resolved: true, }, { dataType: undefined, disconnected: false, displayName: 'runtimeInput', name: 'runtimeInput', resolved: true, }, ]); }); it('should insert token text in the middle by cursor range', () => { const result = insertTextAtCursor('hello world', '{{input}}', 6, 11); expect(result).toEqual({ value: 'hello {{input}}', cursor: 15, }); }); it('should append token text when cursor info is missing', () => { const result = insertTextAtCursor('hello', '{{name}}'); expect(result).toEqual({ value: 'hello{{name}}', cursor: 13, }); }); it('should parse token parts and mark valid tokens', () => { const parts = parseTokenParts('你好 {{ user.name }} 与 {{unknown}}', [ 'user.name', 'docs', ]); expect(parts).toEqual([ { type: 'text', text: '你好 ', }, { type: 'token', text: '{{ user.name }}', key: 'user.name', valid: true, }, { type: 'text', text: ' 与 ', }, { type: 'token', text: '{{unknown}}', key: 'unknown', valid: false, }, ]); }); it('should keep plain text when token syntax is invalid', () => { const parts = parseTokenParts('abc {{}} def', ['a']); expect(parts).toEqual([ { type: 'text', text: 'abc {{}} def', }, ]); }); it('should split token display and hide braces text', () => { const result = splitTokenDisplay('{{ user.name }}', 'user.name'); expect(result).toEqual({ hiddenPrefix: '{{ ', visibleText: 'user.name', hiddenSuffix: ' }}', }); }); it('should find full token range for backspace delete', () => { const content = 'hello {{input}} world'; const tokenEndCursor = 'hello {{input}}'.length; const range = findBackspaceTokenRange(content, tokenEndCursor); expect(range).toEqual({ start: 6, end: 15, text: '{{input}}', key: 'input', }); }); it('should support boundary match for arrow skip behavior', () => { const content = 'x{{docs}}y'; const tokenStart = 1; const tokenEnd = 9; const rightBoundary = findTokenRangeAtCursor(content, tokenStart, { includeStart: true, includeEnd: false, }); const leftBoundary = findTokenRangeAtCursor(content, tokenEnd, { includeStart: false, includeEnd: true, }); expect(rightBoundary?.key).toBe('docs'); expect(leftBoundary?.key).toBe('docs'); }); it('should format and parse Enjoy parameter tokens', () => { expect(formatParamToken('申请人', 'enjoy')).toBe('#(申请人)'); expect(getTokenRanges('申请:#(申请人)', 'enjoy')).toEqual([ { start: 3, end: 9, text: '#(申请人)', key: '申请人', }, ]); }); it('should keep complex Enjoy expressions as editable text', () => { expect(getTokenRanges('#(申请人 ?? 被申请人)', 'enjoy')).toEqual([]); }); });