mirror of
https://github.com/duhanbalci/dexpr.git
synced 2026-07-01 16:19:16 +00:00
152 lines
6.0 KiB
TypeScript
152 lines
6.0 KiB
TypeScript
import { EditorView, basicSetup } from "codemirror";
|
|
import { EditorState } from "@codemirror/state";
|
|
import { dexpr, DexprLanguageInfo } from "./src/index";
|
|
|
|
// ── Simulate: this JSON comes from Rust's LanguageInfo::to_json() ──
|
|
// In a real app:
|
|
// Rust: info.add_value("customer", &Value::from_json(json)?, None);
|
|
// let metadata = info.to_json();
|
|
// HTTP: GET /api/editor-metadata → metadata
|
|
// JS: const languageInfo = await fetch(...).then(r => r.json());
|
|
//
|
|
// Here we inline it for the demo:
|
|
|
|
const languageInfo: DexprLanguageInfo = {
|
|
functions: [
|
|
{ name: "log", signature: "(...args) -> null", doc: "Print values to output" },
|
|
{ name: "rand", signature: "(min, max) -> Number", doc: "Random integer between min and max" },
|
|
{ name: "getRate", signature: "(code: String) -> Number", doc: "Get exchange rate for currency" },
|
|
],
|
|
methods: {
|
|
String: [
|
|
{ name: "upper", signature: "() -> String" },
|
|
{ name: "lower", signature: "() -> String" },
|
|
{ name: "trim", signature: "() -> String" },
|
|
{ name: "trimStart", signature: "() -> String" },
|
|
{ name: "trimEnd", signature: "() -> String" },
|
|
{ name: "split", signature: "(delim: String) -> StringList" },
|
|
{ name: "replace", signature: "(old: String, new: String) -> String" },
|
|
{ name: "contains", signature: "(substr: String) -> Boolean" },
|
|
{ name: "startsWith", signature: "(prefix: String) -> Boolean" },
|
|
{ name: "endsWith", signature: "(suffix: String) -> Boolean" },
|
|
{ name: "length", signature: "() -> Number" },
|
|
{ name: "charAt", signature: "(index: Number) -> String" },
|
|
{ name: "substring", signature: "(start: Number, end?: Number) -> String" },
|
|
],
|
|
Number: [],
|
|
Boolean: [],
|
|
Object: [
|
|
{ name: "keys", signature: "() -> StringList", doc: "Get all keys" },
|
|
{ name: "values", signature: "() -> StringList | NumberList", doc: "Get all values (must be same type)" },
|
|
{ name: "length", signature: "() -> Number", doc: "Number of entries" },
|
|
{ name: "len", signature: "() -> Number" },
|
|
{ name: "contains", signature: "(key: String) -> Boolean", doc: "Check if key exists" },
|
|
{ name: "get", signature: "(key: String) -> any", doc: "Get value by key" },
|
|
],
|
|
NumberList: [
|
|
{ name: "length", signature: "() -> Number" },
|
|
{ name: "len", signature: "() -> Number" },
|
|
{ name: "isEmpty", signature: "() -> Boolean" },
|
|
{ name: "first", signature: "() -> Number" },
|
|
{ name: "last", signature: "() -> Number" },
|
|
{ name: "get", signature: "(index: Number) -> Number" },
|
|
{ name: "contains", signature: "(value: Number) -> Boolean" },
|
|
{ name: "indexOf", signature: "(value: Number) -> Number" },
|
|
{ name: "slice", signature: "(start: Number, end?: Number) -> NumberList" },
|
|
{ name: "reverse", signature: "() -> NumberList" },
|
|
{ name: "sort", signature: "() -> NumberList" },
|
|
{ name: "sum", signature: "() -> Number" },
|
|
{ name: "avg", signature: "() -> Number" },
|
|
{ name: "min", signature: "() -> Number" },
|
|
{ name: "max", signature: "() -> Number" },
|
|
],
|
|
StringList: [
|
|
{ name: "length", signature: "() -> Number" },
|
|
{ name: "len", signature: "() -> Number" },
|
|
{ name: "isEmpty", signature: "() -> Boolean" },
|
|
{ name: "first", signature: "() -> String" },
|
|
{ name: "last", signature: "() -> String" },
|
|
{ name: "get", signature: "(index: Number) -> String" },
|
|
{ name: "contains", signature: "(value: String) -> Boolean" },
|
|
{ name: "indexOf", signature: "(value: String) -> Number" },
|
|
{ name: "slice", signature: "(start: Number, end?: Number) -> StringList" },
|
|
{ name: "reverse", signature: "() -> StringList" },
|
|
{ name: "sort", signature: "() -> StringList" },
|
|
{ name: "join", signature: "(delim?: String) -> String" },
|
|
],
|
|
},
|
|
// ── Variables: as if Rust did info.add_value("customer", &Value::from_json(...), ...) ──
|
|
variables: [
|
|
// info.add_value("discount", &Value::Number(10), None)
|
|
{ name: "discount", type: "Number", doc: "Discount percentage" },
|
|
// info.add_value("customer", &Value::from_json(r#"{"name":"Alice",...}"#)?, None)
|
|
// → from_json auto-detects field types from the JSON values
|
|
{
|
|
name: "customer", type: "Object", doc: "Customer — from JSON via Value::from_json()",
|
|
fields: [
|
|
{ name: "name", type: "String" },
|
|
{ name: "email", type: "String" },
|
|
{ name: "city", type: "String" },
|
|
{ name: "age", type: "Number" },
|
|
{ name: "active", type: "Boolean" },
|
|
{ name: "tags", type: "StringList" },
|
|
],
|
|
},
|
|
// info.add_value("order", &Value::from_json(r#"{"amount":1500,...}"#)?, None)
|
|
{
|
|
name: "order", type: "Object", doc: "Order — from JSON via Value::from_json()",
|
|
fields: [
|
|
{ name: "amount", type: "Number" },
|
|
{ name: "currency", type: "String" },
|
|
{ name: "status", type: "String" },
|
|
{ name: "items", type: "StringList" },
|
|
],
|
|
},
|
|
],
|
|
};
|
|
|
|
const sampleCode = `// dexpr demo
|
|
// customer and order come from JSON via Value::from_json()
|
|
// Rust side:
|
|
// let customer = Value::from_json(api_response)?;
|
|
// vm.set_global("customer", customer.clone());
|
|
// info.add_value("customer", &customer, None);
|
|
|
|
// Property access — type-aware autocomplete
|
|
name = customer.name
|
|
city = customer.city
|
|
|
|
// Object fields in expressions
|
|
net = order.amount * (1 - discount / 100)
|
|
|
|
// Method chaining: obj.field → String methods
|
|
upper_name = customer.name.upper()
|
|
domain = customer.email.split("@").last()
|
|
|
|
// Object methods
|
|
fields = customer.keys()
|
|
fieldCount = customer.length()
|
|
|
|
// in operator — check key existence
|
|
if "email" in customer then
|
|
log(customer.email)
|
|
end
|
|
|
|
// Property assignment
|
|
customer.city = "Ankara"
|
|
|
|
// List field methods
|
|
first_tag = customer.tags.first()
|
|
tag_count = customer.tags.length()
|
|
|
|
log(upper_name, net, first_tag)
|
|
`;
|
|
|
|
new EditorView({
|
|
state: EditorState.create({
|
|
doc: sampleCode,
|
|
extensions: [basicSetup, dexpr(languageInfo)],
|
|
}),
|
|
parent: document.getElementById("editor")!,
|
|
});
|