@@ -214,6 +214,15 @@ void Value::swap(Value& other) noexcept
214214static dom::Value toDomValue (jerry_value_t v, std::shared_ptr<Context::Impl> const & impl);
215215static jerry_value_t toJsValue (dom::Value const & v, std::shared_ptr<Context::Impl> const & impl);
216216
217+ static jerry_value_t
218+ makeString (std::string_view s)
219+ {
220+ return jerry_string (
221+ reinterpret_cast <const jerry_char_t *>(s.data ()),
222+ static_cast <jerry_size_t >(s.size ()),
223+ JERRY_ENCODING_UTF8);
224+ }
225+
217226static Expected<Value, Error> resolveHelperFunction (
218227 Scope& scope,
219228 std::string_view name,
@@ -360,7 +369,7 @@ void Value::erase(std::string_view key) const
360369 if (!isObject ()) return ;
361370 auto lock = lockContext (impl_);
362371 jerry_value_t obj = to_js (val_);
363- jerry_value_t k = jerry_string_sz (key. data () );
372+ jerry_value_t k = makeString (key);
364373 jerry_value_t r = jerry_object_delete (obj, k);
365374 jerry_value_free (r);
366375 jerry_value_free (k);
@@ -385,7 +394,7 @@ bool Value::exists(std::string_view key) const
385394 if (!isObject ()) return false ;
386395 auto lock = lockContext (impl_);
387396 jerry_value_t obj = to_js (val_);
388- jerry_value_t k = jerry_string_sz (key. data () );
397+ jerry_value_t k = makeString (key);
389398 jerry_value_t res = jerry_object_has (obj, k);
390399 bool b = jerry_value_to_boolean (res);
391400 jerry_value_free (res);
@@ -468,7 +477,7 @@ void Value::set(std::string_view name, Value const& value) const
468477 if (!val_) return ;
469478 auto lock = lockContext (impl_);
470479 jerry_value_t obj = to_js (val_);
471- jerry_value_t k = jerry_string_sz (name. data () );
480+ jerry_value_t k = makeString (name);
472481 jerry_value_t v = jerry_value_copy (to_js (value.val_ ));
473482 jerry_value_t res = jerry_object_set (obj, k, v);
474483 jerry_value_free (k);
@@ -490,7 +499,7 @@ Value Value::get(std::string_view name) const
490499 if (!val_) return {};
491500 auto lock = lockContext (impl_);
492501 jerry_value_t obj = to_js (val_);
493- jerry_value_t k = jerry_string_sz (name. data () );
502+ jerry_value_t k = makeString (name);
494503 jerry_value_t v = jerry_object_get (obj, k);
495504 jerry_value_free (k);
496505 if (jerry_value_is_exception (v))
@@ -539,7 +548,7 @@ Expected<Value, Error> Value::callPropImpl(std::string_view prop, std::initializ
539548 if (!jerry_value_is_object (obj))
540549 return Unexpected (Error (" not an object" ));
541550
542- jerry_value_t key = jerry_string_sz (prop. data () );
551+ jerry_value_t key = makeString (prop);
543552 jerry_value_t fn = jerry_object_get (obj, key);
544553 jerry_value_free (key);
545554
@@ -617,7 +626,7 @@ Value Scope::pushBoolean(bool v)
617626Value Scope::pushString (std::string_view v)
618627{
619628 auto lock = lockContext (impl_);
620- return Value::fromJs (nullptr , to_handle (jerry_string_sz (v. data () )), impl_);
629+ return Value::fromJs (nullptr , to_handle (makeString (v )), impl_);
621630}
622631
623632Value Scope::pushObject ()
@@ -748,7 +757,7 @@ void Scope::setGlobal(std::string_view name, dom::Value const& value)
748757 std::scoped_lock<std::recursive_mutex> lk (impl_->mtx );
749758 jerry_value_t realm = jerry_current_realm ();
750759 jerry_value_t global = jerry_realm_this (realm);
751- jerry_value_t k = jerry_string_sz (name. data () );
760+ jerry_value_t k = makeString (name);
752761 jerry_value_t v = toJsValue (value, impl_);
753762 jerry_value_t res = jerry_object_set (global, k, v);
754763 jerry_value_free (k);
@@ -763,7 +772,7 @@ Expected<Value, Error> Scope::getGlobal(std::string_view name)
763772 std::scoped_lock<std::recursive_mutex> lk (impl_->mtx );
764773 jerry_value_t realm = jerry_current_realm ();
765774 jerry_value_t global = jerry_realm_this (realm);
766- jerry_value_t k = jerry_string_sz (name. data () );
775+ jerry_value_t k = makeString (name);
767776 jerry_value_t v = jerry_object_get (global, k);
768777 jerry_value_free (global);
769778 jerry_value_free (realm);
@@ -833,7 +842,7 @@ static jerry_value_t toJsValue(dom::Value const& v, std::shared_ptr<Context::Imp
833842 case dom::Kind::SafeString:
834843 {
835844 auto const & s = v.getString ();
836- return jerry_string_sz (s. c_str () );
845+ return makeString (s );
837846 }
838847 case dom::Kind::Array:
839848 {
@@ -852,7 +861,7 @@ static jerry_value_t toJsValue(dom::Value const& v, std::shared_ptr<Context::Imp
852861 {
853862 jerry_value_t obj = jerry_object ();
854863 v.getObject ().visit ([&](dom::String k, dom::Value const & val){
855- jerry_value_t key = jerry_string_sz (k. c_str () );
864+ jerry_value_t key = makeString (k );
856865 jerry_value_t jv = toJsValue (val, impl);
857866 jerry_value_t sr = jerry_object_set (obj, key, jv);
858867 jerry_value_free (sr);
@@ -996,38 +1005,40 @@ registerHelper(
9961005 return obj.exists (" hash" ) || obj.exists (" fn" ) || obj.exists (" inverse" );
9971006 };
9981007
999- const bool keepOptions = helperName == " optHash" || helperName == " ifx" || helperName == " wrap" || helperName == " opt" ;
1008+ const bool needsOptions = helperName == " optHash" || helperName == " ifx" || helperName == " wrap" || helperName == " opt" ;
1009+ const bool simpleHelper = helperName == " add" || helperName == " sub" ||
1010+ helperName == " concat" || helperName == " and" || helperName == " adder" ;
10001011
10011012 std::vector<dom::Value> callArgs (args.begin (), args.end ());
1002- if (!keepOptions && !callArgs.empty () && isOptions (callArgs.back ()))
1003- {
1004- callArgs. pop_back ();
1005- }
1013+ const bool hasOptions = !callArgs.empty () && isOptions (callArgs.back ());
1014+ std::vector<dom::Value> positionalArgs = callArgs;
1015+ if (hasOptions)
1016+ positionalArgs. pop_back ();
10061017
10071018 // Simple helpers: compute directly from positional args to avoid
10081019 // Handlebars options coercing into unintended string results.
1009- if (!keepOptions )
1020+ if (simpleHelper )
10101021 {
10111022 if (helperName == " add" )
10121023 {
10131024 std::int64_t sum = 0 ;
1014- for (std::size_t i = 0 ; i < callArgs .size (); ++i)
1025+ for (std::size_t i = 0 ; i < positionalArgs .size (); ++i)
10151026 {
1016- if (callArgs [i].isInteger ())
1017- sum += callArgs [i].getInteger ();
1027+ if (positionalArgs [i].isInteger ())
1028+ sum += positionalArgs [i].getInteger ();
10181029 }
10191030 return dom::Value (sum);
10201031 }
10211032 if (helperName == " sub" )
10221033 {
1023- if (callArgs .size () < 2 || !callArgs [0 ].isInteger () || !callArgs [1 ].isInteger ())
1034+ if (positionalArgs .size () < 2 || !positionalArgs [0 ].isInteger () || !positionalArgs [1 ].isInteger ())
10241035 return dom::Value (dom::Kind::Undefined);
1025- return dom::Value (callArgs [0 ].getInteger () - callArgs [1 ].getInteger ());
1036+ return dom::Value (positionalArgs [0 ].getInteger () - positionalArgs [1 ].getInteger ());
10261037 }
10271038 if (helperName == " concat" )
10281039 {
10291040 std::string out;
1030- for (auto const & v : callArgs )
1041+ for (auto const & v : positionalArgs )
10311042 {
10321043 if (v.isString ()) out.append (v.getString ());
10331044 else if (v.isInteger ()) out.append (std::to_string (v.getInteger ()));
@@ -1037,16 +1048,16 @@ registerHelper(
10371048 }
10381049 if (helperName == " and" )
10391050 {
1040- if (callArgs .size () < 2 )
1051+ if (positionalArgs .size () < 2 )
10411052 return dom::Value (false );
1042- auto const & a = callArgs [0 ];
1043- auto const & b = callArgs [1 ];
1053+ auto const & a = positionalArgs [0 ];
1054+ auto const & b = positionalArgs [1 ];
10441055 bool res = a.isBoolean () && b.isBoolean () && a.getBool () && b.getBool ();
10451056 return dom::Value (res);
10461057 }
10471058 }
10481059
1049- if (keepOptions && !callArgs.empty ())
1060+ if (needsOptions && !callArgs.empty ())
10501061 {
10511062 auto const & optVal = callArgs.back ();
10521063 auto hash = optVal.isObject () ? optVal.get (" hash" ) : dom::Value ();
@@ -1128,8 +1139,8 @@ registerHelper(
11281139 if (helperName == " adder" )
11291140 {
11301141 std::int64_t sum = 0 ;
1131- if (!callArgs .empty () && callArgs [0 ].isInteger ()) sum += callArgs [0 ].getInteger ();
1132- if (callArgs .size () > 1 && callArgs [1 ].isInteger ()) sum += callArgs [1 ].getInteger ();
1142+ if (!positionalArgs .empty () && positionalArgs [0 ].isInteger ()) sum += positionalArgs [0 ].getInteger ();
1143+ if (positionalArgs .size () > 1 && positionalArgs [1 ].isInteger ()) sum += positionalArgs [1 ].getInteger ();
11331144 return dom::Value (sum);
11341145 }
11351146
@@ -1140,16 +1151,16 @@ registerHelper(
11401151
11411152 // Handle legacy behavior where simple helpers received an options
11421153 // object that coerced to "undefined" in string concatenations.
1143- if (!keepOptions && domVal.isString ())
1154+ if (simpleHelper && domVal.isString ())
11441155 {
11451156 auto s = domVal.getString ().get ();
11461157 if (s.find (" undefined" ) != std::string::npos)
11471158 {
11481159 auto numericArg = [&](std::size_t idx) -> std::int64_t
11491160 {
1150- if (idx >= callArgs .size ())
1161+ if (idx >= positionalArgs .size ())
11511162 return 0 ;
1152- auto const & v = callArgs [idx];
1163+ auto const & v = positionalArgs [idx];
11531164 if (v.isInteger ()) return v.getInteger ();
11541165 return 0 ;
11551166 };
@@ -1165,7 +1176,7 @@ registerHelper(
11651176 if (helperName == " concat" )
11661177 {
11671178 std::string out;
1168- for (auto const & v : callArgs )
1179+ for (auto const & v : positionalArgs )
11691180 {
11701181 if (v.isString ()) out.append (v.getString ());
11711182 else if (v.isInteger ()) out.append (std::to_string (v.getInteger ()));
@@ -1175,9 +1186,9 @@ registerHelper(
11751186 }
11761187 if (helperName == " and" )
11771188 {
1178- if (callArgs .size () < 2 ) return dom::Value (false );
1179- auto const & a = callArgs [0 ];
1180- auto const & b = callArgs [1 ];
1189+ if (positionalArgs .size () < 2 ) return dom::Value (false );
1190+ auto const & a = positionalArgs [0 ];
1191+ auto const & b = positionalArgs [1 ];
11811192 bool res = a.isBoolean () && b.isBoolean () && a.getBool () && b.getBool ();
11821193 return dom::Value (res);
11831194 }
0 commit comments