Referencia DSL
Coders genera código multi-lenguaje y multi-plataforma desde un DSL (.jssp). Los recursos declarados (controller, mapper, message, error, etc.) se convierten 1:1 con plantillas por plataforma.
Para empezar, ver Inicio rápido y Resumen.
Notas de configuración
config.yml controla el comportamiento del CLI.
entry: archivo.jsspraízprojects:platform,name,outPath,entry,target,language,optionsllmOptions:provider,model,url,apiKey,timeoutSeconds,stream
Resumen DSL
El DSL de Coders se compone de:
- declaraciones:
domain,table,entity,mapper,struct,class,controller,api,define - ejecución:
func,main,@prompt - recursos:
message,error,property,css - UI:
html+template
Modelado de datos
Domain
js
domain Url string(512);
domain Name string(32);Table
js
table user {
user_id int64 auto;
name Name;
create_at datetime = now();
key(user_id);
index(create_at);
unique index(name);
}Data
js
data user(name) {
('user1');
('user2');
}Entity
js
entity UserVo from @table.user {}
entity UserProfileVo {
var userId int64;
var name Name;
var avatarUrl Url;
}Mapper
js
mapper UserMapper {
query insertUser(name Name) int32 {
insert user(name)
values(:name);
}
query updateUser(userId int64, name Name) int32 {
update user set name = :name
where user_id = :userId;
}
}Procedimientos/Funciones DB
js
dbproc sample(userId string(10), out name string(100)) {
var _name string(100);
var c cursor = select name into _name from user_id = userId;
c.open();
c.fetch();
name = _name;
c.close();
}
dbfunc countUser() int32 {
var _count int32;
select count(*) into _count from user;
return _count;
}Estructura de la app
Struct / Class / Interface
js
struct SignupRequest {
var email string;
var password string;
}
abstract class BaseSample {
func hello() void;
}
class Sample extends BaseSample {
var name string;
constructor(name string) {
this.name = name;
}
func hello() void {
@console.log("hello");
}
}js
[alias='console']
interface Console {
static func log(message string) void;
static func error(message string) void;
static func warn(message string) void;
}Enum
js
define enum Status {
READY 1,
RUNNING 2,
DONE 3
}API y servicios
Controller
js
[baseUrl='/api/v1', comment='Controlador de usuarios']
controller UserController {
[method=post, route='/signup']
func signup(@body req SignupRequest) SignupResponse {
var res = SignupResponse();
var n = @mapper.UserMapper.insertUser(req.email, req.password);
if (n <= 0) {
res.code = AppErrors.failed.code;
res.message = AppErrors.failed.message;
return res;
}
res.code = AppErrors.success.code;
return res;
}
}Api (Client)
js
[comment='API de usuarios']
api UserApi from @controller.UserController {}Objetivos front-end
La clase html se convierte en componentes front-end.
ref var-> estado@model-> binding de entrada@click-> handler de evento
DSL de login
js
define css {
text.primary {
text-gray-800
}
}
html LoginPage {
ref var nickname string = "";
ref var password string = "";
func login() {
var res = @api.login(nickname, password);
@console.log(res.code);
}
template {
div class="@css.text.primary" {
input @model="nickname";
input @model="password";
button @click="login" { "Login" }
}
}
}Widgets Flutter
Flutter usa la clase widget.
js
widget LoginPage {
ref var nickname string = "";
ref var password string = "";
func login() {
var res = @api.login(nickname, password);
@console.log(res.code);
}
// definir UI en el bloque widget layout
}Definiciones de recursos
Property
js
define property app {
baseUrl = "https://api.example.com";
}
define property [profile='dev'] app {
baseUrl = "https://dev.api.example.com";
}Message + Message Class
js
define message[locale='en'] app {
hello: "Hello"
welcome: "Welcome {name}"
}
message MessageApp from @message.app {
static func setLocale(locale string) void;
static var hello string;
static func welcome(name string) string;
}Error + Error Class
js
define error[locale='en'] app {
not_found (100) = "Resource not found"
server_error (200) = "Internal server error"
}
error AppErrors from @error.app {}@prompt
@prompt agrega instrucciones en lenguaje natural para la lógica nativa.
js
func main() {
@prompt `Imprimir "Hello, World!"`
}Ejemplo de @prompt (Rust/Go/Java)
js
func main(args list<string>) {
@prompt `Imprimir los primos hasta args[0] (criba de Eratóstenes)`
}rust
use std::env;
fn main() {
let args: Vec<String> = env::args().collect();
let n: usize = args.get(1).unwrap_or(&"0".to_string()).parse().unwrap_or(0);
if n < 2 {
return;
}
let mut is_prime = vec![true; n + 1];
is_prime[0] = false;
if n >= 1 {
is_prime[1] = false;
}
let mut p = 2;
while p * p <= n {
if is_prime[p] {
let mut multiple = p * p;
while multiple <= n {
is_prime[multiple] = false;
multiple += p;
}
}
p += 1;
}
for i in 2..=n {
if is_prime[i] {
println!("{i}");
}
}
}go
package main
import (
"fmt"
"os"
"strconv"
)
func main() {
n := 0
if len(os.Args) > 1 {
if v, err := strconv.Atoi(os.Args[1]); err == nil {
n = v
}
}
if n < 2 {
return
}
isPrime := make([]bool, n+1)
for i := range isPrime {
isPrime[i] = true
}
isPrime[0] = false
if n >= 1 {
isPrime[1] = false
}
for p := 2; p*p <= n; p++ {
if isPrime[p] {
for m := p * p; m <= n; m += p {
isPrime[m] = false
}
}
}
for i := 2; i <= n; i++ {
if isPrime[i] {
fmt.Println(i)
}
}
}java
public class Main {
public static void main(String[] args) {
int n = 0;
if (args.length > 0) {
try {
n = Integer.parseInt(args[0]);
} catch (NumberFormatException ignored) {
n = 0;
}
}
if (n < 2) {
return;
}
boolean[] isPrime = new boolean[n + 1];
for (int i = 0; i <= n; i++) {
isPrime[i] = true;
}
isPrime[0] = false;
if (n >= 1) {
isPrime[1] = false;
}
for (int p = 2; p * p <= n; p++) {
if (isPrime[p]) {
for (int m = p * p; m <= n; m += p) {
isPrime[m] = false;
}
}
}
for (int i = 2; i <= n; i++) {
if (isPrime[i]) {
System.out.println(i);
}
}
}
}Bash/PowerShell
shell se convierte en funciones de script con llamada de ejecución.
Bash
- agregar
set -euo pipefailal inicio shellse vuelve función Bash
dsl
shell download_file(url string, dest string) {
@prompt `Descargar archivo con curl`
}bash
set -euo pipefail
download_file() {
local url="$1"
local dest="$2"
curl -fsSL "$url" -o "$dest"
}
main() {
download_file "$@"
}
main "$@"PowerShell
shellse vuelve function PowerShell
dsl
shell download_file(url string, dest string) {
@prompt `Descargar con Invoke-WebRequest`
}powershell
function Download-File {
param (
[Parameter(Mandatory = $true)]
[string]$Url,
[Parameter(Mandatory = $true)]
[string]$Dest
)
Invoke-WebRequest -Uri $Url -OutFile $Dest
}
Download-File -Url $Url -Dest $DestResumen de conversión
- analizar declaraciones (controller, mapper, html/widget)
- generar esqueletos por recurso
- expandir @prompt a código nativo
Ejemplo end-to-end
js
domain Email string(320);
domain Password string(128);
struct SignupRequest {
var email Email;
var password Password;
}
struct SignupResponse {
var code int32;
var message string;
}
table user {
user_id int64 auto;
email Email unique;
password Password;
key(user_id);
}
mapper UserMapper {
query insertUser(email Email, password Password) int32 {
insert user(email, password)
values (:email, :password);
}
}
define error[locale='en'] app {
success (0) = "OK"
failed (100) = "Failed"
}
error AppErrors from @error.app {}
[baseUrl='/api/v1']
controller UserController {
[method=post, route='/signup']
func signup(@body req SignupRequest) SignupResponse {
var res = SignupResponse();
var n = @mapper.UserMapper.insertUser(req.email, req.password);
if (n <= 0) {
res.code = AppErrors.failed.code;
res.message = AppErrors.failed.message;
return res;
}
res.code = AppErrors.success.code;
res.message = AppErrors.success.message;
return res;
}
}