luacats_grammar_spec.lua (6785B)
1 local t = require('test.testutil') 2 3 local eq = t.eq 4 5 local grammar = require('gen.luacats_grammar') 6 7 describe('luacats grammar', function() 8 --- @param text string 9 --- @param exp table<string,string> 10 local function test(text, exp) 11 it(string.format('can parse %q', text), function() 12 eq(exp, grammar:match(text)) 13 end) 14 end 15 16 test('@param hello vim.type', { 17 kind = 'param', 18 name = 'hello', 19 type = 'vim.type', 20 }) 21 22 test('@param hello vim.type this is a description', { 23 kind = 'param', 24 name = 'hello', 25 type = 'vim.type', 26 desc = 'this is a description', 27 }) 28 29 test('@param hello vim.type|string this is a description', { 30 kind = 'param', 31 name = 'hello', 32 type = 'vim.type|string', 33 desc = 'this is a description', 34 }) 35 36 test('@param hello vim.type?|string? this is a description', { 37 kind = 'param', 38 name = 'hello', 39 type = 'vim.type?|string?', 40 desc = 'this is a description', 41 }) 42 43 test('@return string hello this is a description', { 44 kind = 'return', 45 { 46 name = 'hello', 47 type = 'string', 48 }, 49 desc = 'this is a description', 50 }) 51 52 test('@return fun() hello this is a description', { 53 kind = 'return', 54 { 55 name = 'hello', 56 type = 'fun()', 57 }, 58 desc = 'this is a description', 59 }) 60 61 test('@return fun(a: string[]): string hello this is a description', { 62 kind = 'return', 63 { 64 name = 'hello', 65 type = 'fun(a: string[]): string', 66 }, 67 desc = 'this is a description', 68 }) 69 70 test('@return fun(a: table<string,any>): string hello this is a description', { 71 kind = 'return', 72 { 73 name = 'hello', 74 type = 'fun(a: table<string,any>): string', 75 }, 76 desc = 'this is a description', 77 }) 78 79 test('@param ... string desc', { 80 kind = 'param', 81 name = '...', 82 type = 'string', 83 desc = 'desc', 84 }) 85 86 test('@param level (integer|string) desc', { 87 kind = 'param', 88 name = 'level', 89 type = 'integer|string', 90 desc = 'desc', 91 }) 92 93 test('@return (string command) the command and arguments', { 94 kind = 'return', 95 { 96 name = 'command', 97 type = 'string', 98 }, 99 desc = 'the command and arguments', 100 }) 101 102 test('@return (string command, string[] args) the command and arguments', { 103 kind = 'return', 104 { 105 name = 'command', 106 type = 'string', 107 }, 108 { 109 name = 'args', 110 type = 'string[]', 111 }, 112 desc = 'the command and arguments', 113 }) 114 115 test('@param rfc "rfc2396" | "rfc2732" | "rfc3986" | nil', { 116 kind = 'param', 117 name = 'rfc', 118 type = '"rfc2396" | "rfc2732" | "rfc3986" | nil', 119 }) 120 121 test('@param position_encoding "utf-8" | "utf-16" | "utf-32" | nil', { 122 kind = 'param', 123 name = 'position_encoding', 124 type = '"utf-8" | "utf-16" | "utf-32" | nil', 125 }) 126 127 -- handle a : after the param type 128 test('@param a b: desc', { 129 kind = 'param', 130 name = 'a', 131 type = 'b', 132 desc = 'desc', 133 }) 134 135 test( 136 '@field prefix? string|table|(fun(diagnostic:vim.Diagnostic,i:integer,total:integer): string, string)', 137 { 138 kind = 'field', 139 name = 'prefix?', 140 type = 'string|table|(fun(diagnostic:vim.Diagnostic,i:integer,total:integer): string, string)', 141 } 142 ) 143 144 test('@field [integer] integer', { 145 kind = 'field', 146 name = '[integer]', 147 type = 'integer', 148 }) 149 150 test('@field [1] integer', { 151 kind = 'field', 152 name = '[1]', 153 type = 'integer', 154 }) 155 156 test('@param type `T` this is a generic type', { 157 desc = 'this is a generic type', 158 kind = 'param', 159 name = 'type', 160 type = '`T`', 161 }) 162 163 test('@param type [number,string,"good"|"bad"] this is a tuple type', { 164 desc = 'this is a tuple type', 165 kind = 'param', 166 name = 'type', 167 type = '[number,string,"good"|"bad"]', 168 }) 169 170 test('@class vim.diagnostic.JumpOpts', { 171 kind = 'class', 172 name = 'vim.diagnostic.JumpOpts', 173 }) 174 175 test('@class vim.diagnostic.JumpOpts : vim.diagnostic.GetOpts', { 176 kind = 'class', 177 name = 'vim.diagnostic.JumpOpts', 178 parent = 'vim.diagnostic.GetOpts', 179 }) 180 181 test('@param opt? { cmd?: string[] } Options', { 182 kind = 'param', 183 name = 'opt?', 184 type = '{ cmd?: string[] }', 185 desc = 'Options', 186 }) 187 188 ---@type [string, string?][] 189 local test_cases = { 190 { 'foo' }, 191 { 'foo ', 'foo' }, -- trims whitespace 192 { 'true' }, 193 { 'vim.type' }, 194 { 'vim-type' }, 195 { 'vim_type' }, 196 { 'foo.bar-baz_baz' }, 197 { '`ABC`' }, 198 { '42' }, 199 { '-42' }, 200 { '(foo)', 'foo' }, -- removes unnecessary parens 201 { 'true?' }, 202 { '(true)?' }, 203 { 'string[]' }, 204 { 'string|number' }, 205 { '(string)[]' }, 206 { '(string|number)[]' }, 207 { 'coalesce??', 'coalesce?' }, -- removes unnecessary ? 208 { 'number?|string' }, 209 { "'foo'|'bar'|'baz'" }, 210 { '"foo"|"bar"|"baz"' }, 211 { '(number)?|string' }, -- 212 { 'number[]|string' }, 213 { 'string[]?' }, 214 { 'foo?[]' }, 215 { 'vim.type?|string? ', 'vim.type?|string?' }, 216 { 'number[][]' }, 217 { 'number[][][]' }, 218 { 'number[][]?' }, 219 { 'string|integer[][]?' }, 220 221 -- tuples 222 { '[string]' }, 223 { '[1]' }, 224 { '[string, number]' }, 225 { '[string, number]?' }, 226 { '[string, number][]' }, 227 { '[string, number]|string' }, 228 { '[string|number, number?]' }, 229 { 'string|[string, number]' }, 230 { '(true)?|[foo]' }, 231 { '[fun(a: string):boolean]' }, 232 233 -- dict 234 { '{[string]:string}' }, 235 { '{ [ string ] : string }' }, 236 { '{ [ string|any ] : string }' }, 237 { '{[string]: string, [number]: boolean}' }, 238 239 -- key-value table 240 { 'table<string,any>' }, 241 { 'table' }, 242 { 'string|table|boolean' }, 243 { 'string|table|(boolean)' }, 244 245 -- table literal 246 { '{foo: number}' }, 247 { '{foo: string, bar: [number, boolean]?}' }, 248 { 'boolean|{reverse?:boolean}' }, 249 { '{ cmd?: string[] }' }, 250 251 -- function 252 { 'fun(a: string, b:foo|bar): string' }, 253 { 'fun(a?: string): string' }, 254 { 'fun(a?: string): number?,string?' }, 255 { '(fun(a: string, b:foo|bar): string)?' }, 256 { 'fun(a: string, b:foo|bar): string, string' }, 257 { 'fun(a: string, b:foo|bar)' }, 258 { 'fun(_, foo, bar): string' }, 259 { 'fun(...): number' }, 260 { 'fun( ... ): number' }, 261 { 'fun(...:number): number' }, 262 { 'fun( ... : number): number' }, 263 264 -- generics 265 { 'elem_or_list<string>' }, 266 { 267 'elem_or_list<fun(client: vim.lsp.Client, init_result: lsp.InitializeResult)>', 268 nil, 269 }, 270 } 271 272 for _, tc in ipairs(test_cases) do 273 local ty, exp_ty = tc[1], tc[2] 274 if exp_ty == nil then 275 exp_ty = ty 276 end 277 278 local var, desc = 'x', 'some desc' 279 local param = string.format('@param %s %s %s', var, ty, desc) 280 test(param, { 281 kind = 'param', 282 name = var, 283 type = exp_ty, 284 desc = desc, 285 }) 286 end 287 end)