luacats_grammar_spec.lua 6.6 KB

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