Skip to main content

Ядро и типы 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.

Ключевые типы:

  • StaticValue
  • ExpressionValue
  • PropValue
  • ComponentNode
  • ComponentLayout
  • PageSchema
  • AppStateSchema / PageStateSchema
  • DataSource
  • EventHandler

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"
}

Поддерживаемые типы:

  • string
  • number
  • boolean
  • enum

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:

  • dataSourceCallStarted
  • dataSourceChanged

9. Где используется DSL

МодульИспользование
builder-webредактирование дерева, PropertiesPanel v2, layout-редактор
dsl-compilertyped генерация React TSX, преобразование layout
runtime-coreинтерпретация DSL, вычисление выражений, DataSource v2
runtime-hostвыполнение приложения
apiстрогая структурная валидация DSL

10. Ключевые идеи DSL

  1. DSL — основной формат приложения.
  2. Typed props + layout формируют структуру UI.
  3. ExpressionValue связывает UI, state и данные.
  4. Реестр компонент — единый источник правды.
  5. Runtime полностью воспроизводит приложение из DSL.
  6. Любое расширение начинается с расширения DSL.