11// Copyright (c) Sony Pictures Imageworks, et al.
22// SPDX-License-Identifier: Apache-2.0
33// https://github.com/imageworks/spk
4+ use ngrammatic:: CorpusBuilder ;
45use serde:: { Deserialize , Serialize } ;
56use spk_schema_foundation:: option_map:: Stringified ;
67
@@ -18,7 +19,7 @@ const OP_COMMENT: &str = "comment";
1819const OP_PREPEND : & str = "prepend" ;
1920const OP_PRIORITY : & str = "priority" ;
2021const 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 ] ;
2223
2324/// The set of operation types for use in deserialization
2425#[ derive( Copy , Clone , Debug , PartialEq ) ]
@@ -126,6 +127,7 @@ impl<'de> Deserialize<'de> for EnvOp {
126127 op_and_var : Option < ( OpKind , ConfKind ) > ,
127128 value : Option < String > ,
128129 separator : Option < String > ,
130+ lints : Vec < String > ,
129131 }
130132
131133 impl < ' de > serde:: de:: Visitor < ' de > for EnvOpVisitor {
@@ -175,7 +177,24 @@ impl<'de> Deserialize<'de> for EnvOp {
175177 "separator" => {
176178 self . separator = map. next_value :: < Option < Stringified > > ( ) ?. map ( |s| s. 0 )
177179 }
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+
179198 // ignore any unknown field for the sake of
180199 // forward compatibility
181200 map. next_value :: < serde:: de:: IgnoredAny > ( ) ?;
@@ -184,12 +203,15 @@ impl<'de> Deserialize<'de> for EnvOp {
184203 }
185204
186205 // 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 ( "" ) ,
193215 } ;
194216
195217 let value = shellexpand:: env ( & value)
@@ -198,30 +220,34 @@ impl<'de> Deserialize<'de> for EnvOp {
198220
199221 match self . op_and_var . take ( ) {
200222 Some ( ( op, var) ) => match op {
201- OpKind :: Prepend => Ok ( EnvOp :: Prepend ( PrependEnv {
223+ OpKind :: Prepend => Ok ( EnvOp :: Prepend ( PrependEnv {
202224 prepend : var. get_op ( ) ,
203225 separator : self . separator . take ( ) ,
204- value
226+ value,
205227 } ) ) ,
206- OpKind :: Append => Ok ( EnvOp :: Append ( AppendEnv {
228+ OpKind :: Append => Ok ( EnvOp :: Append ( AppendEnv {
207229 append : var. get_op ( ) ,
208230 separator : self . separator . take ( ) ,
209- value
231+ value,
210232 } ) ) ,
211- OpKind :: Set => Ok ( EnvOp :: Set ( SetEnv {
233+ OpKind :: Set => Ok ( EnvOp :: Set ( SetEnv {
212234 set : var. get_op ( ) ,
213- value
235+ value,
236+ } ) ) ,
237+ OpKind :: Comment => Ok ( EnvOp :: Comment ( CommentEnv {
238+ comment : var. get_op ( ) ,
214239 } ) ) ,
215- OpKind :: Comment => Ok ( EnvOp :: Comment ( CommentEnv {
216- comment : var. get_op ( )
240+ OpKind :: Priority => Ok ( EnvOp :: Priority ( Priority {
241+ priority : var. get_priority ( ) ,
217242 } ) ) ,
218- OpKind :: Priority => Ok ( EnvOp :: Priority ( Priority {
219- priority : var. get_priority ( )
220- } ) )
221243 } ,
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+ }
225251 }
226252 }
227253 }
0 commit comments