ObjectOS
Referencia

Expresiones CEL

El lenguaje de expresiones usado para fórmulas, predicados, programaciones y cadenas con plantilla — expuesto mediante cinco plantillas etiquetadas.

Expresiones CEL

ObjectOS usa CEL (Common Expression Language) para cada lugar donde necesitas una expresión pequeña, segura y aislada: campos de fórmula, reglas de validación, predicados de visibilidad, condiciones de compartición, guardas de flujo, programaciones y cadenas con plantilla.

La autoría se realiza a través de cinco plantillas etiquetadas importadas desde @objectstack/spec. Todas producen un pequeño objeto JSON que el runtime analiza:

{ dialect: 'cel' | 'template' | 'cron', source: string }

Fuente del esquema: packages/spec/src/shared/expression.zod.ts.

Las cinco plantillas etiquetadas

PlantillaDialectoÚsala paraEjemplo
F`...`celCampos de fórmula — valores derivados almacenados junto al registroF`record.amount * 0.1`
P`...`celPredicados — booleanos para validación / compartición / visibilidad / condicionesP`record.status == "open"`
cel`...`celCEL general — cuando ni F ni P encajan (p. ej. el valor de un parámetro)cel`now() + duration("P30D")`
tmpl`...`templatePlantillas de cadenas con interpolación {{var}}tmpl`Order from {{record.customer.name}}`
cron`...`cronProgramaciones — sintaxis cron estándar de 5 camposcron`0 9 * * 1-5`

No hay diferencia funcional entre F, P y cel en el momento de la evaluación — todas ejecutan CEL. La división existe para que los esquemas (y los agentes de IA) sepan qué rol desempeña la expresión y para que el editor pueda comprobar tipos (las fórmulas deben devolver un valor, los predicados deben devolver un bool).

Importación

import { F, P, cel, tmpl, cron } from '@objectstack/spec'

Dónde se usa cada una

Campo en una specEtiquetaUbicación de ejemplo
Field.expression (tipo fórmula)Fcampos de fórmula en *.object.ts
Field.conditionalRequiredPcampos de objeto
Validation.predicatePvalidaciones de objeto
SharingRule.conditionPreglas de compartición
View.conditionalFormatting[].conditionPvistas
Flow.step.when / Flow.transition.whenPflujos
Action.guardPacciones
Asuntos de notificaciones / cuerpos de mensajetmplnotificaciones
Schedule.croncronflujos / informes programados
Cualquier parámetro de valorcelentradas de pasos de flujo

Ámbito de variables

Las expresiones CEL se evalúan en un contexto con estas variables de nivel superior:

VariableDisponible cuandoContenido
recordcasi siempreEl registro actual que se está evaluando
previousen hooks de actualización / detección de cambiosEl estado del registro previo al cambio (o null)
inputacciones, pasos de flujoLa carga útil de entrada proporcionada por el usuario
os.usersiempre{ id, roles: string[], permissions: string[] }
os.orgsiempreContexto de organización / tenant
os.envsiempreVariables de entorno expuestas a las expresiones

Las variables heredadas OLD / NEW se eliminaron en M9.5. Usa previous y record.

Biblioteca estándar

Registrada en packages/formula/src/stdlib.ts. Las funciones integradas más usadas:

Tiempo

FunciónDevuelveNotas
now()TimestampFijada al contexto de evaluación — estable dentro de una consulta
today()TimestampInicio del día UTC
daysFromNow(int)TimestampFecha futura
daysAgo(int)TimestampFecha pasada

CEL también incluye los nativos timestamp(...), duration(...), date.getDayOfWeek(), etc. — consulta la especificación de CEL.

Utilidad

FunciónPropósito
isBlank(x)true si es null, undefined, "" o una lista vacía
coalesce(a, b)Primer valor no nulo
trim(s)Elimina espacios en blanco
joinNonEmpty(list, sep)Concatena las entradas no vacías

Los ayudantes de cadenas nativos de CEL (.contains(...), .startsWith(...), .matches(...), .size()) siempre están disponibles.

Ejemplos

Campo de fórmula — total de línea de artículo:

{ name: 'subtotal', type: 'formula', expression: F`record.quantity * record.unit_price` }

Validación — la fecha de cierre debe ser posterior a hoy:

{ message: 'Close date must be in the future', predicate: P`record.close_date > today()` }

Visibilidad — mostrar el campo solo a los gerentes:

{ visibleIf: P`'manager' in os.user.roles` }

Guarda de flujo — omitir el paso cuando el importe es pequeño:

{ when: P`record.amount >= 1000` }

Programación — días laborables a las 9 a. m.:

{ schedule: cron`0 9 * * 1-5` }

Plantilla — asunto de notificación:

{ subject: tmpl`[{{record.priority}}] {{record.subject}}` }

Errores

Las expresiones se compilan en el momento de la carga. Los fallos aparecen como VALIDATION_ERROR con la ubicación en la fuente:

{ "code": "VALIDATION_ERROR", "message": "CEL: unknown field 'amout' on Record", "details": { "field": "subtotal", "expression": "record.amout * 0.1" } }

Las expresiones inválidas no fallan en silencio. Una expresión mal formada o con un campo desconocido hace fallar os compile con el mensaje localizado de arriba (incluida una sugerencia «quizás quisiste decir» para un campo mal escrito). En tiempo de ejecución, una expresión incorrecta lanza un error atribuido en lugar de evaluarse silenciosamente a null o false, de modo que el fallo es visible en los logs y en el registro de auditoría en lugar de corromper de forma silenciosa el valor de una fórmula o la decisión de una guarda.

Véase también

On this page