@@ -28,23 +28,32 @@ fn read_file(path: impl AsRef<str>) -> Result<String, BuildError> {
2828
2929fn parse_content ( content : & str ) -> Result < HashMap < String , JsonValue > , BuildError > {
3030 #[ cfg( all( feature = "ason" , feature = "toml" ) ) ]
31- eprintln ! ( "Warning: both `ason` and `toml` features are enabled. Using `json` parser." ) ;
31+ eprintln ! (
32+ "Warning: any two of `ason`, `toml` or `jsonc` features are enabled. Using `json` parser."
33+ ) ;
3234
33- #[ cfg( all( feature = "ason" , not( feature = "toml" ) ) ) ]
35+ #[ cfg( all( feature = "ason" , not( any ( feature = "toml" , feature = "jsonc" ) ) ) ) ]
3436 {
3537 let json: ason:: ast:: AsonNode = ason:: parse_from_str ( content) ?;
3638 return ason_node_to_json_value ( json) ;
3739 }
3840
39- #[ cfg( all( feature = "toml" , not( feature = "ason" ) ) ) ]
41+ #[ cfg( all( feature = "toml" , not( any ( feature = "ason" , feature = "jsonc" ) ) ) ) ]
4042 {
4143 let value = toml_span:: parse ( content) ?. take ( ) ;
4244 return toml_value_to_json_value ( value) ;
4345 }
4446
47+ #[ cfg( all( feature = "jsonc" , not( any( feature = "ason" , feature = "toml" ) ) ) ) ]
48+ {
49+ let opts = jsonc_parser:: ParseOptions :: default ( ) ;
50+ let value = jsonc_parser:: parse_to_value ( content, & opts) ?;
51+ jsonc_value_to_json_value ( value. ok_or ( BuildError :: Parse ( Error :: ExpectedObject ) ) ?)
52+ }
53+
4554 #[ cfg( any(
46- not( any( feature = "ason" , feature = "toml" ) ) ,
47- all( feature = "ason" , feature = "toml" )
55+ not( any( feature = "ason" , feature = "toml" , feature = "jsonc" ) ) ,
56+ all( feature = "ason" , feature = "toml" , feature = "jsonc" )
4857 ) ) ]
4958 return content
5059 . parse :: < JsonValue > ( ) ?
@@ -114,16 +123,16 @@ fn deep_merge(target: &mut HashMap<String, JsonValue>, source: HashMap<String, J
114123 }
115124}
116125
117- #[ cfg( all( feature = "toml" , not( feature = "ason" ) ) ) ]
126+ #[ cfg( all( feature = "toml" , not( any ( feature = "ason" , feature = "jsonc" ) ) ) ) ]
118127fn toml_value_to_json_value (
119128 value : toml_span:: value:: ValueInner < ' _ > ,
120129) -> Result < HashMap < String , JsonValue > , BuildError > {
121130 use toml_span:: value:: ValueInner ;
122131
123132 match value {
124- ValueInner :: Table ( table ) => {
133+ ValueInner :: Table ( v ) => {
125134 let mut map = HashMap :: new ( ) ;
126- for ( key, mut value) in table {
135+ for ( key, mut value) in v {
127136 map. insert ( key. name . to_string ( ) , convert_value ( value. take ( ) ) ?) ;
128137 }
129138 Ok ( map)
@@ -132,50 +141,50 @@ fn toml_value_to_json_value(
132141 }
133142}
134143
135- #[ cfg( all( feature = "toml" , not( feature = "ason" ) ) ) ]
144+ #[ cfg( all( feature = "toml" , not( any ( feature = "ason" , feature = "jsonc" ) ) ) ) ]
136145fn convert_value ( value : toml_span:: value:: ValueInner < ' _ > ) -> Result < JsonValue , BuildError > {
137146 use toml_span:: value:: ValueInner ;
138147
139148 match value {
140- ValueInner :: String ( s ) => Ok ( JsonValue :: String ( s . to_string ( ) ) ) ,
149+ ValueInner :: String ( v ) => Ok ( JsonValue :: String ( v . to_string ( ) ) ) ,
141150 #[ allow( clippy:: cast_precision_loss) ]
142- ValueInner :: Integer ( i ) => Ok ( JsonValue :: Number ( i as f64 ) ) ,
143- ValueInner :: Float ( f ) => Ok ( JsonValue :: Number ( f ) ) ,
144- ValueInner :: Boolean ( b ) => Ok ( JsonValue :: Boolean ( b ) ) ,
145- ValueInner :: Array ( arr ) => {
146- let mut json_arr = Vec :: new ( ) ;
147- for mut item in arr {
148- json_arr . push ( convert_value ( item. take ( ) ) ?) ;
151+ ValueInner :: Integer ( v ) => Ok ( JsonValue :: Number ( v as f64 ) ) ,
152+ ValueInner :: Float ( v ) => Ok ( JsonValue :: Number ( v ) ) ,
153+ ValueInner :: Boolean ( v ) => Ok ( JsonValue :: Boolean ( v ) ) ,
154+ ValueInner :: Array ( v ) => {
155+ let mut arr = Vec :: new ( ) ;
156+ for mut item in v {
157+ arr . push ( convert_value ( item. take ( ) ) ?) ;
149158 }
150- Ok ( JsonValue :: Array ( json_arr ) )
159+ Ok ( JsonValue :: Array ( arr ) )
151160 }
152- ValueInner :: Table ( table ) => {
161+ ValueInner :: Table ( v ) => {
153162 let mut map = HashMap :: new ( ) ;
154- for ( key, mut value) in table {
163+ for ( key, mut value) in v {
155164 map. insert ( key. name . to_string ( ) , convert_value ( value. take ( ) ) ?) ;
156165 }
157166 Ok ( JsonValue :: Object ( map) )
158167 }
159168 }
160169}
161170
162- #[ cfg( all( feature = "ason" , not( feature = "toml" ) ) ) ]
171+ #[ cfg( all( feature = "ason" , not( any ( feature = "toml" , feature = "jsonc" ) ) ) ) ]
163172pub fn ason_node_to_json_value (
164173 node : ason:: ast:: AsonNode ,
165174) -> Result < HashMap < String , JsonValue > , BuildError > {
166175 use ason:: ast:: AsonNode ;
167176
168177 match node {
169- AsonNode :: Object ( pairs ) => {
178+ AsonNode :: Object ( v ) => {
170179 let mut map = HashMap :: new ( ) ;
171- for pair in pairs {
180+ for pair in v {
172181 map. insert ( pair. key , convert_node ( * pair. value ) ?) ;
173182 }
174183 Ok ( map)
175184 }
176- AsonNode :: Map ( pairs ) => {
185+ AsonNode :: Map ( v ) => {
177186 let mut map = HashMap :: new ( ) ;
178- for pair in pairs {
187+ for pair in v {
179188 match convert_node ( * pair. name ) ? {
180189 JsonValue :: String ( key) => {
181190 map. insert ( key, convert_node ( * pair. value ) ?) ;
@@ -189,31 +198,31 @@ pub fn ason_node_to_json_value(
189198 }
190199}
191200
192- #[ cfg( all( feature = "ason" , not( feature = "toml" ) ) ) ]
201+ #[ cfg( all( feature = "ason" , not( any ( feature = "toml" , feature = "jsonc" ) ) ) ) ]
193202fn convert_node ( node : ason:: ast:: AsonNode ) -> Result < JsonValue , BuildError > {
194203 use ason:: ast:: AsonNode ;
195204
196205 match node {
197- AsonNode :: Number ( num ) => Ok ( JsonValue :: Number ( convert_number ( num ) ) ) ,
198- AsonNode :: Boolean ( b ) => Ok ( JsonValue :: Boolean ( b ) ) ,
199- AsonNode :: String ( s ) => Ok ( JsonValue :: String ( s ) ) ,
200- AsonNode :: List ( items ) => {
201- let mut json_arr = Vec :: new ( ) ;
202- for item in items {
203- json_arr . push ( convert_node ( item) ?) ;
206+ AsonNode :: Number ( v ) => Ok ( JsonValue :: Number ( convert_number ( v ) ) ) ,
207+ AsonNode :: Boolean ( v ) => Ok ( JsonValue :: Boolean ( v ) ) ,
208+ AsonNode :: String ( v ) => Ok ( JsonValue :: String ( v ) ) ,
209+ AsonNode :: List ( v ) => {
210+ let mut arr = Vec :: new ( ) ;
211+ for item in v {
212+ arr . push ( convert_node ( item) ?) ;
204213 }
205- Ok ( JsonValue :: Array ( json_arr ) )
214+ Ok ( JsonValue :: Array ( arr ) )
206215 }
207- AsonNode :: Object ( pairs ) => {
216+ AsonNode :: Object ( v ) => {
208217 let mut map = HashMap :: new ( ) ;
209- for pair in pairs {
218+ for pair in v {
210219 map. insert ( pair. key , convert_node ( * pair. value ) ?) ;
211220 }
212221 Ok ( JsonValue :: Object ( map) )
213222 }
214- AsonNode :: Map ( pairs ) => {
223+ AsonNode :: Map ( v ) => {
215224 let mut map = HashMap :: new ( ) ;
216- for pair in pairs {
225+ for pair in v {
217226 match convert_node ( * pair. name ) ? {
218227 JsonValue :: String ( key) => {
219228 map. insert ( key, convert_node ( * pair. value ) ?) ;
@@ -228,26 +237,81 @@ fn convert_node(node: ason::ast::AsonNode) -> Result<JsonValue, BuildError> {
228237 }
229238}
230239
231- #[ cfg( all( feature = "ason" , not( feature = "toml" ) ) ) ]
240+ #[ cfg( all( feature = "ason" , not( any ( feature = "toml" , feature = "jsonc" ) ) ) ) ]
232241fn convert_number ( num : ason:: ast:: Number ) -> f64 {
233242 use ason:: ast:: Number ;
234243
235244 match num {
236- Number :: I8 ( n ) => n as f64 ,
237- Number :: U8 ( n ) => n as f64 ,
238- Number :: I16 ( n ) => n as f64 ,
239- Number :: U16 ( n ) => n as f64 ,
240- Number :: I32 ( n ) => n as f64 ,
241- Number :: U32 ( n ) => n as f64 ,
245+ Number :: I8 ( v ) => v as f64 ,
246+ Number :: U8 ( v ) => v as f64 ,
247+ Number :: I16 ( v ) => v as f64 ,
248+ Number :: U16 ( v ) => v as f64 ,
249+ Number :: I32 ( v ) => v as f64 ,
250+ Number :: U32 ( v ) => v as f64 ,
242251 #[ allow( clippy:: cast_precision_loss) ]
243- Number :: I64 ( n ) => n as f64 ,
252+ Number :: I64 ( v ) => v as f64 ,
244253 #[ allow( clippy:: cast_precision_loss) ]
245- Number :: U64 ( n ) => n as f64 ,
246- Number :: F32 ( n ) => n as f64 ,
247- Number :: F64 ( n ) => n ,
254+ Number :: U64 ( v ) => v as f64 ,
255+ Number :: F32 ( v ) => v as f64 ,
256+ Number :: F64 ( v ) => v ,
248257 }
249258}
250259
260+ #[ cfg( all( feature = "jsonc" , not( any( feature = "ason" , feature = "toml" ) ) ) ) ]
261+ fn jsonc_value_to_json_value (
262+ value : jsonc_parser:: JsonValue < ' _ > ,
263+ ) -> Result < HashMap < String , JsonValue > , BuildError > {
264+ match value {
265+ jsonc_parser:: JsonValue :: Object ( v) => {
266+ let mut map = HashMap :: new ( ) ;
267+ for ( key, value) in v {
268+ map. insert ( key, convert_jsonc_value ( value) ?) ;
269+ }
270+ Ok ( map)
271+ }
272+
273+ _ => Err ( BuildError :: Parse ( Error :: ExpectedObject ) ) ,
274+ }
275+ }
276+
277+ #[ cfg( all( feature = "jsonc" , not( any( feature = "ason" , feature = "toml" ) ) ) ) ]
278+ fn convert_jsonc_value ( value : jsonc_parser:: JsonValue < ' _ > ) -> Result < JsonValue , BuildError > {
279+ match value {
280+ jsonc_parser:: JsonValue :: String ( v) => Ok ( JsonValue :: String ( v. into_owned ( ) ) ) ,
281+ jsonc_parser:: JsonValue :: Number ( v) => convert_number ( v) ,
282+ jsonc_parser:: JsonValue :: Boolean ( v) => Ok ( JsonValue :: Boolean ( v) ) ,
283+ jsonc_parser:: JsonValue :: Object ( v) => {
284+ let mut map = HashMap :: new ( ) ;
285+ for ( key, value) in v {
286+ map. insert ( key, convert_jsonc_value ( value) ?) ;
287+ }
288+ Ok ( JsonValue :: Object ( map) )
289+ }
290+ jsonc_parser:: JsonValue :: Array ( v) => {
291+ let mut arr = Vec :: new ( ) ;
292+ for item in v {
293+ arr. push ( convert_jsonc_value ( item) ?) ;
294+ }
295+ Ok ( JsonValue :: Array ( arr) )
296+ }
297+ jsonc_parser:: JsonValue :: Null => Ok ( JsonValue :: Null ) ,
298+ }
299+ }
300+
301+ #[ cfg( all( feature = "jsonc" , not( any( feature = "ason" , feature = "toml" ) ) ) ) ]
302+ fn convert_number ( n : & str ) -> Result < JsonValue , BuildError > {
303+ if let Ok ( num) = n. parse :: < i64 > ( ) {
304+ #[ allow( clippy:: cast_precision_loss) ]
305+ return Ok ( JsonValue :: Number ( num as f64 ) ) ;
306+ }
307+
308+ if let Ok ( num) = n. parse :: < f64 > ( ) {
309+ return Ok ( JsonValue :: Number ( num) ) ;
310+ }
311+
312+ Err ( BuildError :: Parse ( Error :: ExpectedNumber ) )
313+ }
314+
251315fn generate ( tokens : & DesignTokens ) -> TokenStream {
252316 Generator :: new ( tokens) . generate ( )
253317}
@@ -558,8 +622,8 @@ mod tests {
558622 use super :: * ;
559623
560624 #[ cfg( any(
561- not( any( feature = "ason" , feature = "toml" ) ) ,
562- all( feature = "ason" , feature = "toml" )
625+ not( any( feature = "ason" , feature = "toml" , feature = "jsonc" ) ) ,
626+ all( feature = "ason" , feature = "toml" , feature = "jsonc" )
563627 ) ) ]
564628 #[ test]
565629 fn test_json ( ) {
@@ -590,7 +654,7 @@ mod tests {
590654 }
591655 }
592656
593- #[ cfg( all( feature = "toml" , not( feature = "ason" ) ) ) ]
657+ #[ cfg( all( feature = "toml" , not( any ( feature = "ason" , feature = "jsonc" ) ) ) ) ]
594658 #[ test]
595659 fn test_toml ( ) {
596660 let test_cases = [ indoc ! { r#"
@@ -617,7 +681,7 @@ mod tests {
617681 }
618682 }
619683
620- #[ cfg( all( feature = "ason" , not( feature = "toml" ) ) ) ]
684+ #[ cfg( all( feature = "ason" , not( any ( feature = "toml" , feature = "jsonc" ) ) ) ) ]
621685 #[ test]
622686 fn test_ason ( ) {
623687 let test_cases = [ indoc ! { r#"
@@ -647,6 +711,41 @@ mod tests {
647711 }
648712 }
649713
714+ #[ cfg( all( feature = "jsonc" , not( any( feature = "ason" , feature = "toml" ) ) ) ) ]
715+ #[ test]
716+ fn test_jsonc ( ) {
717+ let test_cases = [ indoc ! { r#"
718+ {
719+ "group name": {
720+ "token name": {
721+ "$value": 1234,
722+ "$type": "number",
723+ },
724+ },
725+ // A comment
726+ "alias name": { // Another comment
727+ "$value": "{group name.token name}",
728+ },
729+ }
730+ "# } ] ;
731+
732+ for ( i, case) in test_cases. iter ( ) . enumerate ( ) {
733+ let map: HashMap < String , JsonValue > = parse_content ( case) . unwrap ( ) ;
734+ let tokens = DesignTokens :: from_map ( & map) . unwrap ( ) ;
735+
736+ let tokens = generate ( & tokens) ;
737+ let abstract_file: File =
738+ syn:: parse2 ( tokens. clone ( ) ) . unwrap_or_else ( |err| panic ! ( "{err}:\n \n {tokens}" ) ) ;
739+ let code = prettyplease:: unparse ( & abstract_file) ;
740+
741+ insta:: assert_snapshot!( format!( "json case {i}" ) , code. to_string( ) ) ;
742+ }
743+ }
744+
745+ #[ cfg( any(
746+ not( any( feature = "ason" , feature = "toml" , feature = "jsonc" ) ) ,
747+ all( feature = "ason" , feature = "toml" , feature = "jsonc" )
748+ ) ) ]
650749 #[ test]
651750 fn test_merged_content ( ) {
652751 let contents = [
0 commit comments