1
1
// Copyright (c) Sony Pictures Imageworks, et al.
2
2
// SPDX-License-Identifier: Apache-2.0
3
3
// https://github.com/imageworks/spk
4
+ use ngrammatic:: CorpusBuilder ;
4
5
use serde:: { Deserialize , Serialize } ;
5
6
use spk_schema_foundation:: option_map:: Stringified ;
6
7
@@ -18,7 +19,7 @@ const OP_COMMENT: &str = "comment";
18
19
const OP_PREPEND : & str = "prepend" ;
19
20
const OP_PRIORITY : & str = "priority" ;
20
21
const OP_SET : & str = "set" ;
21
- const OP_NAMES : & [ & str ] = & [ OP_APPEND , OP_COMMENT , OP_PREPEND , OP_SET ] ;
22
+ const OP_NAMES : & [ & str ] = & [ OP_APPEND , OP_COMMENT , OP_PREPEND , OP_SET , OP_PRIORITY ] ;
22
23
23
24
/// The set of operation types for use in deserialization
24
25
#[ derive( Copy , Clone , Debug , PartialEq ) ]
@@ -126,6 +127,7 @@ impl<'de> Deserialize<'de> for EnvOp {
126
127
op_and_var : Option < ( OpKind , ConfKind ) > ,
127
128
value : Option < String > ,
128
129
separator : Option < String > ,
130
+ lints : Vec < String > ,
129
131
}
130
132
131
133
impl < ' de > serde:: de:: Visitor < ' de > for EnvOpVisitor {
@@ -175,7 +177,24 @@ impl<'de> Deserialize<'de> for EnvOp {
175
177
"separator" => {
176
178
self . separator = map. next_value :: < Option < Stringified > > ( ) ?. map ( |s| s. 0 )
177
179
}
178
- _ => {
180
+ unknown_config => {
181
+ self . lints
182
+ . push ( format ! ( "Unknown config: {unknown_config}. " ) ) ;
183
+ let mut corpus = CorpusBuilder :: new ( ) . finish ( ) ;
184
+ for op_name in OP_NAMES . iter ( ) {
185
+ corpus. add_text ( op_name) ;
186
+ }
187
+
188
+ match corpus. search ( unknown_config, 0.6 ) . first ( ) {
189
+ Some ( s) => self
190
+ . lints
191
+ . push ( format ! ( "The most similar config is: {}" , s. text) ) ,
192
+ None => self . lints . push ( format ! (
193
+ "No similar config found for: {}." ,
194
+ unknown_config
195
+ ) ) ,
196
+ } ;
197
+
179
198
// ignore any unknown field for the sake of
180
199
// forward compatibility
181
200
map. next_value :: < serde:: de:: IgnoredAny > ( ) ?;
@@ -184,12 +203,15 @@ impl<'de> Deserialize<'de> for EnvOp {
184
203
}
185
204
186
205
// Comments and priority configs don't have any values.
187
- let value = match self . op_and_var . as_ref ( ) . unwrap ( ) . 0 {
188
- OpKind :: Comment | OpKind :: Priority => String :: from ( "" ) ,
189
- _ => self
190
- . value
191
- . take ( )
192
- . ok_or_else ( || serde:: de:: Error :: missing_field ( "value" ) ) ?,
206
+ let value = match self . op_and_var . as_ref ( ) {
207
+ Some ( v) => match v. 0 {
208
+ OpKind :: Comment | OpKind :: Priority => String :: from ( "" ) ,
209
+ _ => self
210
+ . value
211
+ . take ( )
212
+ . ok_or_else ( || serde:: de:: Error :: missing_field ( "value" ) ) ?,
213
+ } ,
214
+ None => String :: from ( "" ) ,
193
215
} ;
194
216
195
217
let value = shellexpand:: env ( & value)
@@ -198,30 +220,34 @@ impl<'de> Deserialize<'de> for EnvOp {
198
220
199
221
match self . op_and_var . take ( ) {
200
222
Some ( ( op, var) ) => match op {
201
- OpKind :: Prepend => Ok ( EnvOp :: Prepend ( PrependEnv {
223
+ OpKind :: Prepend => Ok ( EnvOp :: Prepend ( PrependEnv {
202
224
prepend : var. get_op ( ) ,
203
225
separator : self . separator . take ( ) ,
204
- value
226
+ value,
205
227
} ) ) ,
206
- OpKind :: Append => Ok ( EnvOp :: Append ( AppendEnv {
228
+ OpKind :: Append => Ok ( EnvOp :: Append ( AppendEnv {
207
229
append : var. get_op ( ) ,
208
230
separator : self . separator . take ( ) ,
209
- value
231
+ value,
210
232
} ) ) ,
211
- OpKind :: Set => Ok ( EnvOp :: Set ( SetEnv {
233
+ OpKind :: Set => Ok ( EnvOp :: Set ( SetEnv {
212
234
set : var. get_op ( ) ,
213
- value
235
+ value,
236
+ } ) ) ,
237
+ OpKind :: Comment => Ok ( EnvOp :: Comment ( CommentEnv {
238
+ comment : var. get_op ( ) ,
214
239
} ) ) ,
215
- OpKind :: Comment => Ok ( EnvOp :: Comment ( CommentEnv {
216
- comment : var. get_op ( )
240
+ OpKind :: Priority => Ok ( EnvOp :: Priority ( Priority {
241
+ priority : var. get_priority ( ) ,
217
242
} ) ) ,
218
- OpKind :: Priority => Ok ( EnvOp :: Priority ( Priority {
219
- priority : var. get_priority ( )
220
- } ) )
221
243
} ,
222
- None => Err ( serde:: de:: Error :: custom ( format ! (
223
- "missing field to define operation and variable, expected one of {OP_NAMES:?}" ,
224
- ) ) ) ,
244
+ None => {
245
+ let mut err_msg = String :: from ( "" ) ;
246
+ for lint in self . lints . iter ( ) {
247
+ err_msg = err_msg + lint;
248
+ }
249
+ Err ( serde:: de:: Error :: custom ( err_msg) )
250
+ }
225
251
}
226
252
}
227
253
}
0 commit comments