1
1
local Iter = require (' render-markdown.lib.iter' )
2
2
3
+ --- @alias render.md.debug.SpecKind ' type' | ' value'
4
+
3
5
--- @class render.md.debug.Spec
6
+ --- @field kind render.md.debug.SpecKind
4
7
--- @field message string
5
8
--- @field validation fun ( value : any ): boolean , string ?
6
9
@@ -56,38 +59,39 @@ function Spec:nested(keys, f, nilable)
56
59
end
57
60
58
61
--- @param keys string | string[]
59
- --- @param input_types type | type[]
62
+ --- @param ts type | type[]
60
63
--- @return render.md.debug.ValidatorSpec
61
- function Spec :type (keys , input_types )
62
- local types , message = self :handle_types (input_types , ' ' )
63
- return self :add (keys , message , function (value )
64
+ function Spec :type (keys , ts )
65
+ local types , message = self :handle_types ({}, ts )
66
+ return self :add (keys , ' type ' , message , function (value )
64
67
return vim .tbl_contains (types , type (value ))
65
68
end )
66
69
end
67
70
68
71
--- @param keys string | string[]
69
72
--- @param values string[]
70
- --- @param input_types ? type | type[]
73
+ --- @param ts ? type | type[]
71
74
--- @return render.md.debug.ValidatorSpec
72
- function Spec :one_of (keys , values , input_types )
73
- local types , message = self :handle_types (input_types , ' one of ' .. vim .inspect (values ))
74
- return self :add (keys , message , function (value )
75
+ function Spec :one_of (keys , values , ts )
76
+ local options = Iter .list .map (values , vim .inspect )
77
+ local types , message = self :handle_types (options , ts )
78
+ return self :add (keys , ' value' , message , function (value )
75
79
return vim .tbl_contains (values , value ) or vim .tbl_contains (types , type (value ))
76
80
end )
77
81
end
78
82
79
83
--- @param keys string | string[]
80
- --- @param list_type type
81
- --- @param input_types ? type | type[]
84
+ --- @param t type
85
+ --- @param ts ? type | type[]
82
86
--- @return render.md.debug.ValidatorSpec
83
- function Spec :list (keys , list_type , input_types )
84
- local types , message = self :handle_types (input_types , list_type .. ' list ' )
85
- return self :add (keys , message , function (value )
87
+ function Spec :list (keys , t , ts )
88
+ local types , message = self :handle_types ({ t .. ' [] ' }, ts )
89
+ return self :add (keys , ' type ' , message , function (value )
86
90
if vim .tbl_contains (types , type (value )) then
87
91
return true
88
92
elseif type (value ) == ' table' then
89
93
for i , item in ipairs (value ) do
90
- if type (item ) ~= list_type then
94
+ if type (item ) ~= t then
91
95
return false , string.format (' [%d] is %s' , i , type (item ))
92
96
end
93
97
end
@@ -99,23 +103,23 @@ function Spec:list(keys, list_type, input_types)
99
103
end
100
104
101
105
--- @param keys string | string[]
102
- --- @param list_type type
103
- --- @param input_types ? type | type[]
106
+ --- @param t type
107
+ --- @param ts ? type | type[]
104
108
--- @return render.md.debug.ValidatorSpec
105
- function Spec :list_or_list_of_list (keys , list_type , input_types )
106
- local types , message = self :handle_types (input_types , list_type .. ' list or list of list ' )
107
- return self :add (keys , message , function (value )
108
- if vim .tbl_contains (types , type (value )) then
109
+ function Spec :nested_list (keys , t , ts )
110
+ local types , message = self :handle_types ({ t , t .. ' [] ' , t .. ' [][] ' }, ts )
111
+ return self :add (keys , ' type ' , message , function (value )
112
+ if type ( value ) == t or vim .tbl_contains (types , type (value )) then
109
113
return true
110
114
elseif type (value ) == ' table' then
111
115
for i , item in ipairs (value ) do
112
116
if type (item ) == ' table' then
113
117
for j , nested in ipairs (item ) do
114
- if type (nested ) ~= list_type then
118
+ if type (nested ) ~= t then
115
119
return false , string.format (' [%d][%d] is %s' , i , j , type (nested ))
116
120
end
117
121
end
118
- elseif type (item ) ~= list_type then
122
+ elseif type (item ) ~= t then
119
123
return false , string.format (' [%d] is %s' , i , type (item ))
120
124
end
121
125
end
@@ -128,11 +132,12 @@ end
128
132
129
133
--- @param keys string | string[]
130
134
--- @param values string[]
131
- --- @param input_types ? type | type[]
135
+ --- @param ts ? type | type[]
132
136
--- @return render.md.debug.ValidatorSpec
133
- function Spec :one_or_list_of (keys , values , input_types )
134
- local types , message = self :handle_types (input_types , ' one or list of ' .. vim .inspect (values ))
135
- return self :add (keys , message , function (value )
137
+ function Spec :one_or_list_of (keys , values , ts )
138
+ local options = ' (' .. table.concat (Iter .list .map (values , vim .inspect ), ' |' ) .. ' )'
139
+ local types , message = self :handle_types ({ options , options .. ' []' }, ts )
140
+ return self :add (keys , ' type' , message , function (value )
136
141
if vim .tbl_contains (types , type (value )) then
137
142
return true
138
143
elseif type (value ) == ' string' then
@@ -151,41 +156,35 @@ function Spec:one_or_list_of(keys, values, input_types)
151
156
end
152
157
153
158
--- @private
154
- --- @param input_types ? type | type []
155
- --- @param prefix string
159
+ --- @param custom string []
160
+ --- @param ts ? type | type[]
156
161
--- @return type[] , string
157
- function Spec :handle_types (input_types , prefix )
162
+ function Spec :handle_types (custom , ts )
158
163
local types = nil
159
- if input_types == nil then
164
+ if ts == nil then
160
165
types = {}
161
- elseif type (input_types ) == ' string' then
162
- types = { input_types }
166
+ elseif type (ts ) == ' string' then
167
+ types = { ts }
163
168
else
164
- types = input_types
169
+ types = ts
165
170
end
166
171
if self .nilable and not vim .tbl_contains (types , ' nil' ) then
167
172
table.insert (types , ' nil' )
168
173
end
169
- local message = prefix
170
- if # types > 0 then
171
- if # message > 0 then
172
- message = message .. ' or '
173
- end
174
- message = message .. ' type ' .. table.concat (types , ' or ' )
175
- end
176
- return types , message
174
+ return types , table.concat (vim .list_extend (custom , types ), ' or ' )
177
175
end
178
176
179
177
--- @private
180
178
--- @param keys string | string[]
179
+ --- @param kind render.md.debug.SpecKind
181
180
--- @param message string
182
181
--- @param validation fun ( v : any ): boolean , string ?
183
182
--- @return render.md.debug.ValidatorSpec
184
- function Spec :add (keys , message , validation )
183
+ function Spec :add (keys , kind , message , validation )
185
184
if self .config ~= nil then
186
185
keys = type (keys ) == ' table' and keys or { keys }
187
186
for _ , key in ipairs (keys ) do
188
- self .specs [key ] = { message = message , validation = validation }
187
+ self .specs [key ] = { kind = kind , message = message , validation = validation }
189
188
end
190
189
end
191
190
return self
@@ -223,7 +222,13 @@ function Validator:check(path, config, specs)
223
222
local value = config [key ]
224
223
local ok , info = spec .validation (value )
225
224
if not ok then
226
- local message = string.format (' %s.%s: expected %s, got %s' , path , key , spec .message , type (value ))
225
+ local message = string.format (' %s.%s - expected: %s' , path , key , spec .message )
226
+ if spec .kind == ' type' then
227
+ message = message .. string.format (' , but got: %s' , type (value ))
228
+ end
229
+ if spec .kind == ' value' then
230
+ message = message .. string.format (' , but got: %s' , vim .inspect (value ))
231
+ end
227
232
if info ~= nil then
228
233
message = message .. string.format (' , info: %s' , info )
229
234
end
@@ -232,7 +237,7 @@ function Validator:check(path, config, specs)
232
237
end
233
238
for key , _ in pairs (config ) do
234
239
if specs [key ] == nil then
235
- local message = string.format (' %s.%s: is not a valid key' , path , key )
240
+ local message = string.format (' %s.%s - invalid key' , path , key )
236
241
table.insert (self .errors , message )
237
242
end
238
243
end
0 commit comments