@@ -8,6 +8,7 @@ use std::convert::TryInto;
88use std:: path:: Path ;
99
1010use itertools:: Itertools ;
11+ use ngrammatic:: CorpusBuilder ;
1112use serde:: { Deserialize , Serialize } ;
1213use spk_schema_foundation:: name:: PkgNameBuf ;
1314use spk_schema_foundation:: option_map:: Stringified ;
@@ -730,7 +731,9 @@ where
730731 where
731732 D : serde:: de:: Deserializer < ' de > ,
732733 {
733- Ok ( std:: convert:: Into :: < Spec < VersionIdent > > :: into ( deserializer. deserialize_map ( SpecVisitor :: recipe ( ) ) ?) )
734+ Ok ( std:: convert:: Into :: < Spec < VersionIdent > > :: into (
735+ deserializer. deserialize_map ( SpecVisitor :: recipe ( ) ) ?,
736+ ) )
734737 }
735738}
736739
@@ -761,7 +764,8 @@ where
761764 where
762765 D : serde:: de:: Deserializer < ' de > ,
763766 {
764- let mut spec: Spec < BuildIdent > = deserializer. deserialize_map ( SpecVisitor :: package ( ) ) ?. into ( ) ;
767+ let mut spec: Spec < BuildIdent > =
768+ deserializer. deserialize_map ( SpecVisitor :: package ( ) ) ?. into ( ) ;
765769 if spec. pkg . is_source ( ) {
766770 // for backward-compatibility with older publishes, prune out anything
767771 // that is not relevant to a source package, since now source packages
@@ -781,7 +785,9 @@ where
781785 where
782786 D : serde:: de:: Deserializer < ' de > ,
783787 {
784- Ok ( std:: convert:: Into :: < LintedSpec < VersionIdent > > :: into ( deserializer. deserialize_map ( SpecVisitor :: recipe ( ) ) ?) )
788+ Ok ( std:: convert:: Into :: < LintedSpec < VersionIdent > > :: into (
789+ deserializer. deserialize_map ( SpecVisitor :: recipe ( ) ) ?,
790+ ) )
785791 }
786792}
787793
@@ -793,7 +799,8 @@ where
793799 where
794800 D : serde:: de:: Deserializer < ' de > ,
795801 {
796- let mut spec: LintedSpec < AnyIdent > = deserializer. deserialize_map ( SpecVisitor :: default ( ) ) ?. into ( ) ;
802+ let mut spec: LintedSpec < AnyIdent > =
803+ deserializer. deserialize_map ( SpecVisitor :: default ( ) ) ?. into ( ) ;
797804 if spec. spec . pkg . is_source ( ) {
798805 // for backward-compatibility with older publishes, prune out anything
799806 // that is not relevant to a source package, since now source packages
@@ -812,7 +819,8 @@ where
812819 where
813820 D : serde:: de:: Deserializer < ' de > ,
814821 {
815- let mut spec: LintedSpec < BuildIdent > = deserializer. deserialize_map ( SpecVisitor :: package ( ) ) ?. into ( ) ;
822+ let mut spec: LintedSpec < BuildIdent > =
823+ deserializer. deserialize_map ( SpecVisitor :: package ( ) ) ?. into ( ) ;
816824 if spec. spec . pkg . is_source ( ) {
817825 // for backward-compatibility with older publishes, prune out anything
818826 // that is not relevant to a source package, since now source packages
@@ -858,7 +866,7 @@ impl<B, T> From<SpecVisitor<B, T>> for LintedSpec<Ident<B, T>>
858866where
859867 Ident < B , T > : serde:: de:: DeserializeOwned ,
860868{
861- fn from ( mut value : SpecVisitor < B , T > ) -> Self {
869+ fn from ( mut value : SpecVisitor < B , T > ) -> Self {
862870 Self {
863871 spec : Spec {
864872 pkg : value. pkg . expect ( "Missing field: pkg" ) ,
@@ -874,18 +882,16 @@ where
874882 // Safety: see the SpecVisitor::package constructor
875883 unsafe { build_spec. into_inner ( ) }
876884 }
877- Some ( build_spec) => {
878- match build_spec. try_into ( ) {
879- Ok ( b) => b,
880- Err ( _) => BuildSpec :: default ( ) ,
881- }
885+ Some ( build_spec) => match build_spec. try_into ( ) {
886+ Ok ( b) => b,
887+ Err ( _) => BuildSpec :: default ( ) ,
882888 } ,
883889 None => Default :: default ( ) ,
884890 } ,
885891 tests : value. tests . take ( ) . unwrap_or_default ( ) ,
886892 install : value. install . take ( ) . unwrap_or_default ( ) ,
887893 } ,
888- lints : value. lints
894+ lints : value. lints ,
889895 }
890896 }
891897}
@@ -894,7 +900,7 @@ impl<B, T> From<SpecVisitor<B, T>> for Spec<Ident<B, T>>
894900where
895901 Ident < B , T > : serde:: de:: DeserializeOwned ,
896902{
897- fn from ( mut value : SpecVisitor < B , T > ) -> Self {
903+ fn from ( mut value : SpecVisitor < B , T > ) -> Self {
898904 Self {
899905 pkg : value. pkg . expect ( "Missing field pkg" ) ,
900906 meta : value. meta . take ( ) . unwrap_or_default ( ) ,
@@ -909,11 +915,9 @@ where
909915 // Safety: see the SpecVisitor::package constructor
910916 unsafe { build_spec. into_inner ( ) }
911917 }
912- Some ( build_spec) => {
913- match build_spec. try_into ( ) {
914- Ok ( b) => b,
915- Err ( _) => BuildSpec :: default ( ) ,
916- }
918+ Some ( build_spec) => match build_spec. try_into ( ) {
919+ Ok ( b) => b,
920+ Err ( _) => BuildSpec :: default ( ) ,
917921 } ,
918922 None => Default :: default ( ) ,
919923 } ,
@@ -923,7 +927,6 @@ where
923927 }
924928}
925929
926-
927930impl SpecVisitor < PkgNameBuf , Version > {
928931 pub fn recipe ( ) -> Self {
929932 Self :: default ( )
@@ -968,25 +971,45 @@ where
968971 "build" => self . build = Some ( map. next_value :: < UncheckedBuildSpec > ( ) ?) ,
969972 "tests" => self . tests = Some ( map. next_value :: < Vec < TestSpec > > ( ) ?) ,
970973 "install" => self . install = Some ( map. next_value :: < InstallSpec > ( ) ?) ,
971- unrecognized_string => {
972- self . lints . push ( format ! ( "unrecognized string {unrecognized_string}" ) ) ;
974+ "api" => {
975+ map. next_value :: < serde:: de:: IgnoredAny > ( ) ?;
976+ }
977+ unknown_config => {
978+ self . lints . push ( format ! ( "Unknown config: {unknown_config}" ) ) ;
979+ let mut corpus = CorpusBuilder :: new ( ) . finish ( ) ;
980+
981+ corpus. add_text ( "pkg" ) ;
982+ corpus. add_text ( "meta" ) ;
983+ corpus. add_text ( "compat" ) ;
984+ corpus. add_text ( "deprecated" ) ;
985+ corpus. add_text ( "sources" ) ;
986+ corpus. add_text ( "build" ) ;
987+ corpus. add_text ( "tests" ) ;
988+ corpus. add_text ( "install" ) ;
989+ corpus. add_text ( "api" ) ;
990+
991+ let results = corpus. search ( unknown_config, 0.6 ) ;
992+ let no_match = format ! ( "No similar config found for: {}" , unknown_config) ;
993+ let top_match = match results. first ( ) {
994+ Some ( s) => & s. text ,
995+ None => & no_match,
996+ } ;
997+
998+ self . lints
999+ . push ( format ! ( "The most similar config is: {}" , top_match) ) ;
1000+
9731001 // ignore any unrecognized field, but consume the value anyway
9741002 // TODO: could we warn about fields that look like typos?
9751003 map. next_value :: < serde:: de:: IgnoredAny > ( ) ?;
9761004 }
9771005 }
9781006 }
9791007
980- self . pkg . as_ref ( ) . ok_or_else ( || serde:: de:: Error :: missing_field ( "pkg" ) ) ?;
981- // match self.build {
982- // Some(build_spec) if !self.check_build_spec => {
983- // // Safety: see the SpecVisitor::package constructor
984- // unsafe { build_spec.into_inner(); }
985- // },
986- // Some(build_spec) => build_spec.try_into().map_err(serde::de::Error::custom)?,
987- // _ => (),
988- // }
989- Ok ( self . into ( ) )
1008+ self . pkg
1009+ . as_ref ( )
1010+ . ok_or_else ( || serde:: de:: Error :: missing_field ( "pkg" ) ) ?;
1011+
1012+ Ok ( self )
9901013
9911014 // let pkg = self
9921015 // .pkg
@@ -1014,4 +1037,3 @@ where
10141037 // })
10151038 }
10161039}
1017-
0 commit comments