Ядро и типы DSL
(обновлено: typed props v2, layout-пропсы, ExpressionValue в layout, AppState/PageState v2, DataSource v2)
🎯 Цель страницы
Эта страница описывает фундаментальные части DSL-подсистемы Lowcode Platform:
- базовые типы DSL;
- структуру
AppSchema,PageSchema,ComponentNode; - свойства компонент (static value, expression, типизированные props, native props);
- layout-пропсы (
layout); - встроенный реестр компонент DSL и метаданные пропсов;
- модель состояния (appState/page.state);
- источники данных DataSource и их влияние на runtime;
- как DSL используется редактором, компилятором и runtime.
Страница служит эталонным справочником для всех модулей платформы.
1. Что такое DSL
DSL (Domain-Specific Language) — структурированное JSON-описание приложения, включающее:
- список страниц;
- дерево компонент;
- свойства компонент — typed props + native props;
- layout-пропсы (
layout); - выражения (
ExpressionValue); - глобальное и локальное состояние (appState / page.state);
- источники данных (
DataSource); - обработчики событий (
EventHandler).
DSL должен быть:
- простым — безопасно редактируется builder-web,
- строгим — валидируется типами из реестра и схемами DSL,
- расширяемым — новые компоненты и типы добавляются декларативно.
Пример минимального DSL-дерева
const root: ComponentNode = {
id: 'container-1',
type: 'Container',
props: {},
layout: { width: 200, height: 80 },
children: [
{ id: 'text-1', type: 'Text', props: { text: 'Hello' } },
{ id: 'btn-1', type: 'Button', props: { label: 'Click' } },
],
};
2. Базовые типы DSL
Основные типы находятся в schema.ts.
Ключевые типы:
StaticValueExpressionValuePropValueComponentNodeComponentLayoutPageSchemaAppStateSchema/PageStateSchemaDataSourceEventHandler
2.1. StaticValue
Простые JSON-значения: строки, числа, boolean, null, объекты, массивы.
2.2. ExpressionValue
{ kind: "expression", expression: "state.user.name" }
Поддерживает доступ к:
state.*— переменные приложения и страницы,data.*— данные DataSource.
2.3. PropValue
type PropValue = StaticValue | ExpressionValue;
Используется в:
propsкомпонент,layout.
3. AppSchema
Корневой объект DSL приложения:
interface AppSchema {
id: string;
name: string;
version: 1;
pages: PageSchema[];
appState?: AppStateSchema;
dataSources?: DataSource[];
eventHandlers?: EventHandler[];
theme?: AppTheme;
}
4. ComponentNode — UI-компонент DSL
interface ComponentNode {
id: ID;
type: string;
props?: Record<string, PropValue>;
layout?: Record<string, PropValue>; // width, height, margin, padding, flex и т.п.
children?: ComponentNode[];
}
4.1. props — typed + native
Typed props берутся из ComponentDefinition.props.
Native props (например, className, style) передаются напрямую в runtime.
4.2. layout
Layout — отдельный канал для визуальных параметров компонента.
Поддерживает:
- StaticValue;
- ExpressionValue;
- валидируется и компилируется отдельно от props.
Пример:
layout: {
width: 200,
height: { kind: "expression", expression: "state.cardHeight" },
margin: 8
}
5. Typed props v2 и реестр компонент DSL
Реестр компонент определён в @lowcode/dsl/components.
Содержит:
- типы описаний пропсов (
ComponentPropDefinition), - описание компонента (
ComponentDefinition), - встроенный реестр (
builtinComponentRegistry).
Эти данные используются:
- builder-web — PropertiesPanel v2;
- dsl-compiler — typed генерация React TSX;
- runtime-core — интерпретация дерева.
5.1. ComponentPropDefinition
{
name: "label",
kind: "string",
label: "Label",
required: true,
defaultValue: "Click me",
allowExpression: true,
format: "singleline"
}
Поддерживаемые типы:
stringnumberbooleanenum
5.2. ComponentDefinition
interface ComponentDefinition {
type: string;
displayName?: string;
category?: string;
canHaveChildren?: boolean;
props: Record<string, ComponentPropDefinition>;
}
5.3. Реестр компонент
builtinComponentRegistry: Record<string, ComponentDefinition>;
Реестр — единый источник истины для всех модулей.
6. Expression-пропсы (в props и layout)
ExpressionValue теперь поддерживается:
- в обычных props,
- в layout.
Пример:
layout: {
width: { kind: "expression", expression: "state.cardWidth" }
}
В runtime выражения вычисляются в контексте:
{
(state, data);
}
7. AppState и PageState v2
7.1. Формат
interface StateVariable {
key: string;
type: 'string' | 'number' | 'boolean' | 'any';
initialValue?: StaticValue;
}
7.2. Использование
- Переменные доступны в выражениях через
state.*. - runtime-core создаёт snapshot на основе схемы DSL.
Пример:
appState: {
variables: [
{ key: 'username', type: 'string' },
{ key: 'counter', type: 'number', initialValue: 10 },
];
}
8. DataSource v2
DSL описывает источники данных:
interface DataSource {
id: string;
name: string;
kind: "static" | "rest" | ...;
config: object;
}
8.1. static
{
id: "users",
kind: "static",
config: { data: ["A", "B"] }
}
Runtime инициализирует snapshot сразу.
8.2. rest и другие источники
Во время выполнения runtime добавляет служебные поля:
__lastCallAt__lastResultAt__lastError__lastPayload__value
8.3. События Runtime
При работе с DataSource генерируются причины изменения snapshot:
dataSourceCallStarteddataSourceChanged
9. Где используется DSL
| Модуль | Использование |
|---|---|
| builder-web | редактирование дерева, PropertiesPanel v2, layout-редактор |
| dsl-compiler | typed генерация React TSX, преобразование layout |
| runtime-core | интерпретация DSL, вычисление выражений, DataSource v2 |
| runtime-host | выполнение приложения |
| api | строгая структурная валидация DSL |
10. Ключевые идеи DSL
- DSL — основной формат приложения.
- Typed props + layout формируют структуру UI.
- ExpressionValue связывает UI, state и данные.
- Реестр компонент — единый источник правды.
- Runtime полностью воспроизводит приложение из DSL.
- Любое расширение начинается с расширения DSL.