KodiScript Dart SDK
A lightweight, embeddable scripting language interpreter for Dart/Flutter applications.
📖 Documentation complète : docs-kodiscript.dickode.net
Installation
Add to your pubspec.yaml:
dependencies:
kodi_script: ^0.4.0
Quick Start
import 'package:kodi_script/kodi_script.dart';
void main() {
// Simple evaluation
final result = KodiScript.eval('2 + 3 * 4');
print(result); // 14.0
// With variables
final greeting = KodiScript.run(
'greeting + ", " + name + "!"',
variables: {'greeting': 'Hello', 'name': 'World'},
);
print(greeting.value); // "Hello, World!"
// Capture output
final output = KodiScript.run('''
let items = ["apple", "banana", "cherry"]
for (item in items) {
print(item)
}
''');
print(output.output); // ["apple", "banana", "cherry"]
}
Features
- Variables:
let x = 10 - Functions:
fn(a, b) { return a + b } - Control Flow:
if,else,for-in - Data Types: numbers, strings, booleans, arrays, objects
- Null Safety:
?.(safe access),?:(elvis operator) - 48+ Native Functions: string, math, random, type, array, JSON, encoding, crypto
🔌 Extensibilité
KodiScript est conçu pour être extensible. Vous pouvez enrichir le langage en ajoutant vos propres fonctions natives.
Fonctions personnalisées
final result = KodiScript.builder('greet("Dart")')
.registerFunction('greet', (args) => 'Hello, ${args[0]}!')
.execute();
print(result.value); // "Hello, Dart!"
Exemple : intégration Flutter
class ScriptEngine {
final UserRepository userRepo;
final NotificationService notifications;
ScriptEngine(this.userRepo, this.notifications);
Future<ScriptResult> execute(String script, Map<String, dynamic> context) {
return KodiScript.builder(script)
.withVariables(context)
.registerFunction('fetchUser', (args) async {
return await userRepo.findById(args[0] as int);
})
.registerFunction('sendPush', (args) {
notifications.send(
title: args[0] as String,
body: args[1] as String,
);
return true;
})
.registerFunction('calculatePrice', (args) {
final quantity = args[0] as num;
final unitPrice = args[1] as num;
final discount = args.length > 2 ? args[2] as num : 0;
return quantity * unitPrice * (1 - discount / 100);
})
.execute();
}
}
Cela permet à vos utilisateurs d'écrire des scripts puissants tout en gardant le contrôle sur les fonctionnalités exposées.
API Reference
KodiScript.eval(source)
Evaluates a script and returns the result value.
KodiScript.run(source, {variables})
Runs a script with optional variables and returns ScriptResult.
KodiScript.builder(source)
Creates a builder for advanced configuration.
Native Functions
| Category | Functions |
|---|---|
| String | toString, toNumber, length, substring, toUpperCase, toLowerCase, trim, split, join, replace, contains, startsWith, endsWith, indexOf |
| Math | abs, floor, ceil, round, min, max, pow, sqrt, sin, cos, tan, log, log10, exp |
| Random | random, randomInt, randomUUID |
| Type | typeOf, isNull, isNumber, isString, isBool |
| Array | size, first, last, reverse, slice, sort, chunk, compact, pluck, zip, fromEntries, difference, intersection, union |
| JSON | jsonParse, jsonStringify |
| Encoding | base64Encode, base64Decode, urlEncode, urlDecode |
| Crypto | md5, sha1, sha256 |
| Date/Time | see below |
Array utilities
A null list argument behaves as an empty list; any other value that is not a list raises.
Every function returns a new list or object and leaves its arguments untouched. All of them
also work as methods: items.pluck("name").
| Function | Result |
|---|---|
chunk(list, size) |
Consecutive lists of size elements, the last one possibly shorter. size below 1 raises |
compact(list) |
The list without its null elements |
pluck(list, path) |
The value at path for each element |
zip(list1, list2, …) |
[[a0, b0, …], [a1, b1, …], …], as long as the shortest list |
fromEntries(pairs) |
Object built from [[key, value], …]; a later pair wins |
difference(a, b) |
Elements of a not in b, duplicates of a kept |
intersection(a, b) |
Elements of a also in b, first occurrence only |
union(list1, list2, …) |
Every element of every list, first occurrence only |
A path is a string of segments separated by .: an object key, or a zero-based list index
written in digits ("client.addresses.0.city"). A missing step gives null; "" designates
the element itself.
Two values are equal when they have the same typeOf and the same canonical text, so 1
equals 1.0 but not "1", and {a: 1, b: 2} equals {b: 2, a: 1}.
Grouping and aggregation
These are interpreter builtins (like map and filter). The key is either a path string or a
function fn(item, index); anything else raises. The group key of a value is its canonical text
(null gives "null").
| Function | Result |
|---|---|
groupBy(list, key) |
{groupKey: [items…]}, items in list order |
countBy(list, key) |
{groupKey: count} |
indexBy(list, key) |
{groupKey: item}, the last item of a key wins |
uniqueBy(list, key) |
The first item of each distinct key |
sumBy(list, key) |
Sum of the keys; null keys are skipped, a non-number key raises, empty gives 0 |
minBy(list, key), maxBy(list, key) |
The item with the smallest / largest key; null keys are skipped, the first wins on ties, null when nothing is left |
partition(list, key) |
[[items whose key is truthy], [the others]] |
Dates
A date argument is either a number of milliseconds since 1970-01-01T00:00:00Z (fraction
truncated toward zero) or ISO-8601 text: 2026-10-19, 2026-10-19T08:30,
2026-10-19T08:30:00.250Z, 2026-10-19 08:30:00+01:00. Without a zone the time is UTC.
Fields are validated (2026-02-29 is not a date). A date that cannot be read (null, an
unreadable string, a boolean, a list, an object) makes a date function return null; it never
raises. A wrong non-date argument, such as a count that is not a number, still raises.
Every calendar computation is done in UTC, whatever the host's time zone. A function that
produces a date returns milliseconds; use toISO or formatDate to render it.
| Function | Result |
|---|---|
now() |
Current instant, in ms |
date(), time(), datetime() |
Current UTC date YYYY-MM-DD, time HH:mm:ss, instant (same as toISO(now())) |
timestamp([date]) |
The date in ms (now without argument) |
isDate(value) |
true if the value reads as a date |
toISO(date) |
YYYY-MM-DDTHH:mm:ss.SSSZ |
formatDate(date, [format]) |
Format with the tokens below (default YYYY-MM-DD) |
parseDate(text, format) |
ms, or null: each token reads exactly its width in digits, literals must match, the whole text must be consumed. Missing fields default to 1970, month 1, day 1, 00:00:00.000 |
year, month, day, hour, minute, second ([date]) |
Calendar field (now without argument) |
dayOfWeek([date]) |
0 = Sunday … 6 = Saturday |
daysInMonth(date) |
28 to 31 |
isWeekend(date) |
true on Saturday or Sunday |
addDays, addHours, addMinutes, addSeconds (date, n) |
Shifted date, in ms; n is truncated toward zero |
addMonths(date, n), addYears(date, n) |
Calendar shift; a day missing from the target month becomes its last day (2026-01-31 + 1 month is 2026-02-28) |
diffDays, diffHours, diffMinutes (a, b) |
Whole units from a to b, truncated toward zero (negative when b is before a) |
diffMonths(a, b), diffYears(a, b) |
Whole calendar months / years from a to b |
age(birth, [at]) |
Completed years; at defaults to now |
startOfDay, endOfDay, startOfMonth, endOfMonth (date) |
Bounds of the period, in ms (endOf… is 23:59:59.999) |
Format tokens, longest first at each position; any other character is copied (formatting) or must match exactly (parsing):
| Token | Meaning |
|---|---|
YYYY |
4-digit year |
YY |
Last 2 digits of the year (formatting only; read as literal text when parsing) |
MM |
Month 01–12 |
DD |
Day 01–31 |
HH |
Hour 00–23 |
mm |
Minute 00–59 |
ss |
Second 00–59 |
SSS |
Millisecond 000–999 |
Other Implementations
| Language | Package |
|---|---|
| Kotlin | Maven Central |
| Go | pkg.go.dev |
| TypeScript | npm |
License
MIT
Libraries
- kodi_script
- KodiScript - A lightweight, embeddable scripting language for Dart.