π― The Problem We All Face
Picture this: You're building a multi-platform application. A React web app, an Android mobile app, a Spring Boot backend, and maybe an iOS app in the pipeline. Everything seems manageable until you hit a familiar wall β validation logic.
Your product manager walks in and says:
"We need to validate that users are 18+ years old, their email matches the company domain, and if they select 'Premium' plan, they must have a valid credit card."
Simple enough, right? Now multiply that across platforms:
// JavaScript (Web/React Native/NodeJS)
if (user.age >= 18 && user.email.endsWith('@company.com') &&
(user.plan !== 'Premium' || user.hasValidCard)) {
// valid
}
// Java (Backend/Android)
if (user.getAge() >= 18 && user.getEmail().endsWith("@company.com") &&
(!user.getPlan().equals("Premium") || user.hasValidCard())) {
// valid
}
// Swift (iOS)
if user.age >= 18 && user.email.hasSuffix("@company.com") &&
(user.plan != "Premium" || user.hasValidCard) {
// valid
}
Now imagine you have 50+ validation rules across your application. Each platform has its own implementation. Each implementation needs to be tested. Each implementation can have subtle bugs.
Welcome to validation hell. π₯
π« The Real Pain Points
1. Code Duplication Nightmare
Every validation rule exists in multiple places. When a business rule changes, you're updating code in 3-4 different repositories. Miss one? Congratulations, you now have inconsistent behavior that will haunt your debugging sessions.
2. Subtle Platform Differences
Each language handles things slightly differently:
- String comparison:
===vs.equals()vs== - Null handling:
undefinedvsnullvsOptional<> - Type coercion: JavaScript's quirky
"5" + 3 = "53"vs Java's strict typing
These subtle differences lead to bugs that only appear on specific platforms β the worst kind of bugs.
3. Hardcoded Logic = Deployment Pain
Need to change a validation rule? That's a code change. Code change means PR review, testing, staging, and deployment. For each platform. Separately.
What if the validation logic could live in your database or configuration? What if non-developers could modify simple rules without touching code?
4. Testing Overhead
50 validation rules Γ 4 platforms = 200 test cases (at minimum). And you need to ensure they all behave identically. Good luck with that.
π‘ What If There Was a Better Way?
What if you could write your validation logic once in a simple, familiar syntax:
user.age >= 18 && endsWith(user.email, "@company.com") && (user.plan != "Premium" || user.hasValidCard)
And have it execute identically on:
- β JavaScript/TypeScript (Browser & Node.js)
- β Java (Android & Backend)
- π§ Swift (iOS) β coming soon!
No platform-specific quirks. No code duplication. No deployment overhead.
This is exactly why I built JexLang.
π Introducing JexLang
JexLang is a lightweight, platform-agnostic expression language with JavaScript-like syntax. It's designed to solve one problem exceptionally well: write logic once, run it everywhere with consistent behavior.
Why JavaScript-Like Syntax?
Let's be honest β most developers are familiar with JavaScript syntax. Even if you're primarily a Java or Swift developer, you've likely encountered JavaScript at some point. By using a familiar syntax, JexLang has virtually zero learning curve.
If you can write this:
user.age >= 18 && user.active === true
You already know JexLang.
π οΈ How JexLang Works
JexLang consists of three core components:
1. Lexer (Tokenizer)
Breaks down your expression into tokens:
"user.age >= 18" β [IDENTIFIER:user, DOT, IDENTIFIER:age, GTE, NUMBER:18]
2. Parser
Converts tokens into an Abstract Syntax Tree (AST):
BinaryExpression {
left: MemberExpression { object: "user", property: "age" },
operator: ">=",
right: NumericLiteral { value: 18 }
}
3. Interpreter
Evaluates the AST against your context data and returns the result.
The magic? The same AST structure and evaluation logic is implemented identically in each language. Same parser rules. Same operator precedence. Same type coercion. Same results.
π Real-World Use Cases
1. Dynamic Form Validations
Store validation rules in your backend and share them across all platforms:
{
"fields": [
{
"name": "email",
"validations": [
{
"rule": "required(email)",
"message": "Email is required"
},
{
"rule": "contains(email, '@')",
"message": "Please enter a valid email"
}
]
},
{
"name": "age",
"validations": [
{
"rule": "age >= 18",
"message": "You must be 18 or older"
}
]
}
]
}
Your React app, Android app, and backend all fetch these rules and evaluate them using JexLang. One source of truth.
2. Business Rule Engines
Configure business logic without code deployments:
// Rules stored in database
const discountRules = [
{ condition: "customer.tier === 'Gold' && cart.total > 100", discount: 20 },
{ condition: "customer.tier === 'Silver' && cart.total > 200", discount: 10 },
{ condition: "cart.items.length > 5", discount: 5 }
];
// Evaluate at runtime
const applicableRule = discountRules.find(rule =>
jexlang.evaluate(rule.condition, { customer, cart })
);
Marketing team wants to change the Gold tier threshold from 100 to 150? Update the database. No deployment needed.
3. Conditional UI Rendering
Show/hide UI elements based on configurable rules:
{
"component": "PremiumBanner",
"showWhen": "user.subscription === 'free' && user.daysActive > 30"
}
4. Workflow Automation
Build workflow engines where conditions are user-configurable:
IF order.total > 1000 AND customer.verified === true
β Route to priority fulfillment
IF order.items.length > 10
β Apply bulk processing
IF contains(order.shippingAddress.country, 'EU')
β Apply VAT calculation
5. Feature Flags with Complex Logic
Go beyond simple boolean flags:
const featureRules = {
"newCheckout": "user.region === 'US' && user.accountAge > 30 && !user.hasActiveIssues",
"betaFeatures": "user.role === 'developer' || contains(user.email, '@internal.com')"
};
β‘ Quick Examples
Basic Expressions
// Arithmetic
jexlang.evaluate("10 + 5 * 2") // 20
// Comparisons
jexlang.evaluate("100 >= 50") // true
// Logical operators
jexlang.evaluate("true && false || true") // true
// String operations
jexlang.evaluate("'Hello' + ' ' + 'World'") // "Hello World"
Working with Context
const context = {
user: {
name: "John Doe",
age: 28,
email: "john@company.com",
roles: ["admin", "editor"]
},
settings: {
maxUploadSize: 100,
allowedFormats: ["jpg", "png", "pdf"]
}
};
// Access nested properties
jexlang.evaluate("user.name", context) // "John Doe"
// Complex conditions
jexlang.evaluate("user.age >= 18 && contains(user.email, '@company.com')", context) // true
Built-in Functions
// String functions
jexlang.evaluate("length('Hello')") // 5
jexlang.evaluate("upper('hello')") // "HELLO"
jexlang.evaluate("startsWith('Hello World', 'Hello')") // true
// Array functions
jexlang.evaluate("length(items)", { items: [1, 2, 3] }) // 3
// Type checking
jexlang.evaluate("isNumber(42)") // true
jexlang.evaluate("isString('hello')") // true
Ternary Expressions
jexlang.evaluate("user.age >= 18 ? 'Adult' : 'Minor'", { user: { age: 25 } }) // "Adult"
π§ Getting Started
JavaScript/TypeScript
Installation:
npm install jexlang-ts
Usage:
import { JexEvaluator } from "jexlang-ts";
const jexlang = new JexEvaluator();
// Simple expression
const result = jexlang.evaluate("1 + 2 * 3"); // 7
// With context
const context = { user: { name: "John", age: 30 } };
const isAdult = jexlang.evaluate("user.age >= 18", context); // true
Java
Gradle:
implementation 'io.github.vinaykumar0339:jexlang-java:1.0.0'
Maven:
<dependency>
<groupId>io.github.vinaykumar0339</groupId>
<artifactId>jexlang-java</artifactId>
<version>1.0.0</version>
</dependency>
Usage:
import io.github.vinaykumar0339.evaluator.JexEvaluator;
JexEvaluator jexlang = new JexEvaluator();
// Simple expression
Object result = jexlang.evaluate("1 + 2 * 3"); // 7
// With context
Map<String, Object> user = Map.of("name", "John", "age", 30);
Map<String, Object> context = Map.of("user", user);
Boolean isAdult = (Boolean) jexlang.evaluate("user.age >= 18", context); // true
π How JexLang Compares
| Feature | JexLang | Hardcoded Logic | JSON Schema | Other Expression Languages |
|---|---|---|---|---|
| Platform Agnostic | β Identical behavior | β Platform-specific | β οΈ Library-dependent | β οΈ Mostly single platform |
| Familiar Syntax | β JavaScript-like | β Native language | β Verbose JSON | β οΈ Varies (SpEL, OGNL, etc.) |
| Runtime Configurable | β | β | β | β |
| Complex Logic Support | β | β | β Limited | β |
| Learning Curve | π’ Low (JS developers) | π’ None | π‘ Medium | π‘ Medium to High |
| Consistent Cross-Platform | β Same AST/Interpreter | β | β οΈ Validator differences | β Usually single platform |
| Custom Functions | β | β | β | β |
| Transforms/Pipes | β
value \ transform
|
β οΈ Manual | β | β οΈ Rare |
πΊοΈ Roadmap
| Platform | Status | Use Cases |
|---|---|---|
| JavaScript/TypeScript | β Production Ready | Browser apps, Node.js APIs, no-code/low-code rule engines |
| Java | β Production Ready | Android apps, backend services, enterprise rule engines |
| Swift | π§ In Progress | iOS apps, macOS automation, workflow logic |
Future considerations:
- Python support
π Call to Action
JexLang is open source and in its early days. I've built it to solve real problems I've faced, but I know the community will find use cases I never imagined.
Here's how you can help:
β Star the repository β It helps with visibility and motivates continued development.
π§ͺ Try it in your projects β Put it through real-world scenarios and see how it holds up.
π Report issues β Found a bug? Edge case that doesn't work? Let me know!
π‘ Suggest features β What would make JexLang more useful for your use case?
π’ Share with your network β Know someone who might benefit? Spread the word!
π Resources
| Resource | Link |
|---|---|
| GitHub Repository | https://github.com/vinaykumar0339/jexlang |
| NPM Package | https://www.npmjs.com/package/jexlang-ts |
| Maven Repository | https://mvnrepository.com/artifact/io.github.vinaykumar0339/jexlang-java |
| Language Reference | https://github.com/vinaykumar0339/jexlang/blob/main/docs/language-reference.md |
| Report Issues | https://github.com/vinaykumar0339/jexlang/issues |
π¬ Final Thoughts
Cross-platform development is hard enough without having to maintain identical logic in multiple languages. JexLang aims to eliminate that pain point by providing a single, consistent way to express logic that works everywhere.
Whether you're building form validations, business rule engines, workflow automation, or config-driven applications, JexLang gives you the power to write once and run everywhere.
I'm excited to see what you build with it.
Have questions or feedback? Drop a comment below or reach out on GitHub. I'd love to hear from you!
#OpenSource #JavaScript #TypeScript #Java #Swift #ExpressionLanguage #FormValidation #CrossPlatform #DeveloperTools #Programming
Top comments (0)