Repository: harttle/liquidjs (ts)

Issue:
Enhance `isComparable` function for full Comparable interface implementation
Hello, this is my first created issue, if there is something wrong just tell me! 

The current implementation of the [isComparable](https://github.com/harttle/liquidjs/blob/master/src/drop/comparable.ts#L11) function only checks if the `equals` method is present on the object. This is leading me to issues when I'm using a custom Drop class that casually also has an implementation of `equals`, but I don't want to make it an implementation of the `Comparable` interface.

When I use the operators `<`, `>`, `<=`, and `>=` the class is detected as an implementation of Comparable and tries to execute the related functions. This happens in the [operator code](https://github.com/harttle/liquidjs/blob/master/src/render/operator.ts#L16).

### Proposed Solution
Enhance the `isComparable` function to check for the complete implementation of the `Comparable` interface, ensuring that the methods `equals`, `gt`, `geq`, `lt`, and `leq` are present on the object.

I made a fork and a PR for this. I will link it right now.

### Benefits
This will ensure that objects are properly evaluated and that they will use the proper comparison functions, improving the robustness of the template evaluation for the operators `<`, `>`, `<=`, and `>=`.

Please let me know if this enhancement is acceptable or if there are any changes or additional considerations I should take into account.


Pull request:
fix: isComparable full interface check
### Summary

This pull request enhances the `isComparable` function to ensure it fully implements the `Comparable` interface, which includes the methods `equals`, `gt`, `geq`, `lt`, and `leq`.

#### Enhancement of `isComparable` Function
The `isComparable` function has been improved to check for the complete implementation of the `Comparable` interface. This ensures that the function correctly identifies objects that are meant to be compared using the methods of the `Comparable` interface.

- **Modified File**: `src/drop/comparable.ts`
- **Function Modified**: `isComparable`

### Related Issues

Fixes #700

---


Patch:
diff --git a/src/drop/comparable.ts b/src/drop/comparable.ts
index 9e7cd69a9..b950dc310 100644
--- a/src/drop/comparable.ts
+++ b/src/drop/comparable.ts
@@ -9,5 +9,12 @@ export interface Comparable {
 }
 
 export function isComparable (arg: any): arg is Comparable {
-  return arg && isFunction(arg.equals)
+  return (
+    arg &&
+    isFunction(arg.equals) &&
+    isFunction(arg.gt) &&
+    isFunction(arg.geq) &&
+    isFunction(arg.lt) &&
+    isFunction(arg.leq)
+  )
 }


Test patch:
diff --git a/test/integration/drop/drop.spec.ts b/test/integration/drop/drop.spec.ts
index bf299cefe..8ca0fb1c6 100644
--- a/test/integration/drop/drop.spec.ts
+++ b/test/integration/drop/drop.spec.ts
@@ -83,6 +83,26 @@ describe('drop/drop', function () {
     const html = await liquid.parseAndRender(tpl, { address, customer })
     expect(html).toBe('test')
   })
+  it('should correctly evaluate custom Drop objects with equals function without full Comparable implementation', async () => {
+    class TestDrop extends Drop {
+      value: string;
+      constructor () {
+        super()
+        this.value = 'test'
+      }
+      equals (rhs: string): boolean {
+        return this.valueOf() === rhs
+      }
+      valueOf (): string {
+        return this.value
+      }
+    }
+    const address = new TestDrop()
+    const customer = { default_address: new TestDrop() }
+    const tpl = `{{ address >= customer.default_address }}`
+    const html = await liquid.parseAndRender(tpl, { address, customer })
+    expect(html).toBe('true')
+  })
   it('should support returning supported value types from liquidMethodMissing', async function () {
     class DynamicTypeDrop extends Drop {
       liquidMethodMissing (key: string) {