Repository: robertkrimen/otto
Pull request #514 (2023-12-19 10:03:11)

Feat: Add `startsWith` to String builtins
- Adds `startsWith` to the String builtins
- Adds a test to ensure it works as intended


Patch:
diff --git a/builtin_string.go b/builtin_string.go
index e32b71f..5b0f927 100644
--- a/builtin_string.go
+++ b/builtin_string.go
@@ -443,6 +443,17 @@ func builtinStringSubstr(call FunctionCall) Value {
 	return stringValue(string(target[start : start+length]))
 }
 
+func builtinStringStartsWith(call FunctionCall) Value {
+	checkObjectCoercible(call.runtime, call.This)
+	target := call.This.string()
+	search := call.Argument(0).string()
+	length := len(search)
+	if length > len(target) {
+		return boolValue(false)
+	}
+	return boolValue(target[:length] == search)
+}
+
 func builtinStringToLowerCase(call FunctionCall) Value {
 	checkObjectCoercible(call.runtime, call.This)
 	return stringValue(strings.ToLower(call.This.string()))
diff --git a/inline.go b/inline.go
index 778a5d0..6edaff6 100644
--- a/inline.go
+++ b/inline.go
@@ -2410,6 +2410,43 @@ func (rt *runtime) newContext() {
 					},
 				},
 			},
+			"startsWith": {
+				mode: 0o101,
+				value: Value{
+					kind: valueObject,
+					value: &object{
+						runtime:     rt,
+						class:       classFunctionName,
+						objectClass: classObject,
+						prototype:   rt.global.FunctionPrototype,
+						extensible:  true,
+						property: map[string]property{
+							propertyLength: {
+								mode: 0,
+								value: Value{
+									kind:  valueNumber,
+									value: 1,
+								},
+							},
+							propertyName: {
+								mode: 0,
+								value: Value{
+									kind:  valueString,
+									value: "startsWith",
+								},
+							},
+						},
+						propertyOrder: []string{
+							propertyLength,
+							propertyName,
+						},
+						value: nativeFunctionObject{
+							name: "startsWith",
+							call: builtinStringStartsWith,
+						},
+					},
+				},
+			},
 			methodToString: {
 				mode: 0o101,
 				value: Value{
@@ -2760,6 +2797,7 @@ func (rt *runtime) newContext() {
 			"split",
 			"substr",
 			"substring",
+			"startsWith",
 			methodToString,
 			"trim",
 			"trimLeft",
diff --git a/tools/gen-jscore/.gen-jscore.yaml b/tools/gen-jscore/.gen-jscore.yaml
index a4d9677..6f523d8 100644
--- a/tools/gen-jscore/.gen-jscore.yaml
+++ b/tools/gen-jscore/.gen-jscore.yaml
@@ -184,6 +184,8 @@ types:
           function: 2
         - name: substring
           function: 2
+        - name: startsWith
+          function: 1
         - name: toString
           function: -1
         - name: trim


Test patch:
diff --git a/inline_test.go b/inline_test.go
index 062d1e8..ed20ba1 100644
--- a/inline_test.go
+++ b/inline_test.go
@@ -102,7 +102,7 @@ func TestGetOwnPropertyNames(t *testing.T) {
 			"substr",
 			"substring",
 			// "sup",
-			// "startsWith",
+			"startsWith",
 			"toString",
 			"trim",
 			// "trimStart",
diff --git a/string_test.go b/string_test.go
index 0fd94a9..cd20799 100644
--- a/string_test.go
+++ b/string_test.go
@@ -470,3 +470,12 @@ func TestString_localeCompare(t *testing.T) {
 		test(`'a'.localeCompare('a');`, 0)
 	})
 }
+
+func TestString_startsWith(t *testing.T) {
+	tt(t, func() {
+		test, _ := test()
+
+		test(`'a'.startsWith('c');`, false)
+		test(`'aa'.startsWith('a');`, true)
+	})
+}