1 // Copyright (c) 2019; Facebook; Inc.
2 // All rights reserved.
4 // This source code is licensed under the MIT license found in the
5 // LICENSE file in the "hack" directory of this source tree.
7 //! A Command Line Interface (CLI) adaptor to JSON serde.
9 //! For options that don't parse as strings (excluding flags), this module
10 //! defines to-JSON parse functions returned by [to_json(json_key)].
12 use serde_json::{json, value::Value as Json};
14 use std::collections::HashMap;
16 macro_rules! impl_CANON_BY_ALIAS {
17 ($($name:expr => $field:expr),* ,) => {{
18 let mut m = HashMap::new();
19 $( m.insert($name, $field); )*
25 /// Each config (JSON) key is implicitly: prefix + lower-cased flag name
26 /// the exceptions are overridden here for config list (-v KEY=VAL).
27 pub static ref CANON_BY_ALIAS: HashMap<&'static str, &'static str> =
29 // group 1: obtained by removing underscores from JSON field names
30 "hack.compiler.constantfolding" => "hack.compiler.constant_folding",
31 "hack.compiler.optimizenullcheck" => "hack.compiler.optimize_null_checks",
32 // group 2: also different prefix without any obvious rule
33 "eval.emit_meth_caller_func_pointers" => "hhvm.emit_meth_caller_func_pointers",
34 "eval.jitenablerenamefunction" => "hhvm.jit_enable_rename_function",
35 "eval.logexterncompilerperf" => "hhvm.log_extern_compiler_perf",
36 "eval.enableintrinsicsextension" => "hhvm.enable_intrinsics_extension",
37 // group 3: we could ignore hhvm. part of prefix in deser.
38 "hack.lang.disable_lval_as_an_expression" => "hhvm.hack.lang.disable_lval_as_an_expression",
40 // group 5: we could assume "hack." between "hhvm." and "lang."
41 "hhvm.lang.enable_class_level_where_clauses" => "hhvm.hack.lang.enable_class_level_where_clauses",
42 "hhvm.lang.disable_legacy_soft_typehints" => "hhvm.hack.lang.disable_legacy_soft_typehints",
43 "hhvm.lang.allow_new_attribute_syntax" => "hhvm.hack.lang.allow_new_attribute_syntax",
44 "hhvm.lang.disable_legacy_attribute_syntax" => "hhvm.hack.lang.disable_legacy_attribute_syntax",
45 "hhvm.lang.disallow_func_ptrs_in_constants" => "hhvm.hack.lang.disallow_func_ptrs_in_constants",
46 // group 6: combination of group 5 & 1
47 "hhvm.lang.constdefaultfuncargs" => "hhvm.hack.lang.const_default_func_args",
48 "hhvm.lang.constdefaultlambdaargs" => "hhvm.hack.lang.const_default_lambda_args",
49 "hhvm.lang.abstractstaticprops" => "hhvm.hack.lang.abstract_static_props",
51 // TODO(leoo) use const-concat & unsnakecase macro via proc_macro_hack
54 pub type ParseFn = fn(&str) -> Option<Json>;
56 /// Given a config key as in JSON (not CLI) returns a to-JSON parse function. E.g.,
57 /// for "hhvm.hack_arr_compat_notices" (not "eval.hackarrcompatnotices"), it
58 /// returns a boolean parser.
59 pub fn to_json(key: &str) -> ParseFn {
60 *BY_JSON_KEY.get(key).unwrap_or(&(parse_str as ParseFn))
64 static ref BY_JSON_KEY: HashMap<&'static str, ParseFn> = {
65 let mut m = HashMap::new();
66 m.insert("hhvm.include_roots", parse_csv_keyval_strs as ParseFn);
71 fn parse_str(s: &str) -> Option<Json> {
75 fn parse_csv_keyval_strs(s: &str) -> Option<Json> {
76 let mut ret = json!({});
77 if let Some(m) = ret.as_object_mut() {
78 for keyval in s.split(',') {
79 if let Some(sep_idx) = keyval.find(':') {
80 let (key, val) = keyval.split_at(sep_idx);
82 m.insert(key.to_owned(), json!(val));