@c2-markdown-ui/mdui-lang 0.0.0-stage → 0.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +97 -2
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/parser.d.ts +137 -0
- package/dist/parser.js +2566 -0
- package/dist/serialize.d.ts +7 -0
- package/dist/serialize.js +633 -0
- package/dist/types.d.ts +495 -0
- package/dist/types.js +1 -0
- package/package.json +37 -4
package/README.md
CHANGED
|
@@ -1,3 +1,98 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @c2-markdown-ui/mdui-lang
|
|
2
|
+
**Write widgets 60% faster with concise DSL syntax.**
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
Transform verbose JSON into elegant one-liners that actually make sense.
|
|
5
|
+
|
|
6
|
+
```
|
|
7
|
+
select env [dev staging prod] dev
|
|
8
|
+
```
|
|
9
|
+
↓
|
|
10
|
+
```json
|
|
11
|
+
{"type": "select", "id": "env", "choices": ["dev", "staging", "prod"], "default": "dev"}
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install @c2-markdown-ui/mdui-lang
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { parseDSL } from '@c2-markdown-ui/mdui-lang';
|
|
24
|
+
|
|
25
|
+
const result = parseDSL('text-input username "Username" "Enter username"');
|
|
26
|
+
console.log(result.widget);
|
|
27
|
+
// Perfect JSON output, ready to use
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## DSL patterns
|
|
31
|
+
|
|
32
|
+
**Single-line widgets**
|
|
33
|
+
```
|
|
34
|
+
text-input username "Username" "Enter here"
|
|
35
|
+
button-group env [dev staging prod] dev
|
|
36
|
+
select region [us-east us-west] us-east
|
|
37
|
+
slider cpu 1 32 1 4
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
**Multi-line forms**
|
|
41
|
+
```
|
|
42
|
+
form deploy "Launch"
|
|
43
|
+
text-input name "App Name"
|
|
44
|
+
select env [dev prod] dev
|
|
45
|
+
slider replicas 1 10 1 3
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**Interactive charts**
|
|
49
|
+
```
|
|
50
|
+
chart-line
|
|
51
|
+
title: Monthly Sales
|
|
52
|
+
height: 300
|
|
53
|
+
Month,Sales,Target
|
|
54
|
+
Jan,100,120
|
|
55
|
+
Feb,150,140
|
|
56
|
+
Mar,200,180
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
All parameters after `id` are optional and positional.
|
|
60
|
+
|
|
61
|
+
## Simple rules
|
|
62
|
+
|
|
63
|
+
- **Spaces separate tokens**: `text-input username "User Name"`
|
|
64
|
+
- **Brackets for arrays**: `[dev staging prod]`
|
|
65
|
+
- **Quotes for strings**: `"Enter your name here"`
|
|
66
|
+
- **2-space indentation**: For forms only
|
|
67
|
+
- **Everything optional**: Except widget type and id
|
|
68
|
+
|
|
69
|
+
## API
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
interface ParseResult {
|
|
73
|
+
success: boolean;
|
|
74
|
+
widget?: Widget; // Parsed widget if successful
|
|
75
|
+
error?: string; // Error message if failed
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const result = parseDSL('select env [dev prod]');
|
|
79
|
+
if (result.success) {
|
|
80
|
+
console.log(result.widget); // Ready-to-use JSON
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
**Why DSL beats JSON**
|
|
85
|
+
|
|
86
|
+
❌ **JSON** (130 chars)
|
|
87
|
+
```json
|
|
88
|
+
{"type": "text-input", "id": "username", "label": "Username", "placeholder": "Enter username", "default": "john"}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
✅ **DSL** (52 chars)
|
|
92
|
+
```
|
|
93
|
+
text-input username "Username" "Enter username" "john"
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
**60% fewer keystrokes. 100% more readable.**
|
|
97
|
+
|
|
98
|
+
MIT © 2025
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/dist/parser.d.ts
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { ParseResult, StreamingParseResult } from './types.js';
|
|
2
|
+
export declare class DSLParser {
|
|
3
|
+
parse(input: string): ParseResult;
|
|
4
|
+
private tokenize;
|
|
5
|
+
/** 从位置 i(指向 [ 或 {)开始,按引号感知 + 深度追踪,返回完整 data:[...]/data:{...} token 串。
|
|
6
|
+
* 起始是 { 时按对象深度配平;输入被截断(流式未写完)时取到末尾,由 parseCascadeNodes 报错兜底 */
|
|
7
|
+
private scanDataArray;
|
|
8
|
+
/**
|
|
9
|
+
* Normalize array syntax to handle common AI output variations.
|
|
10
|
+
* Converts formats like ["a","b","c"] or ["a", "b", "c"] to ["a" "b" "c"]
|
|
11
|
+
*/
|
|
12
|
+
private normalizeArraySyntax;
|
|
13
|
+
private parseArray;
|
|
14
|
+
/** 从字段 token 中提取 label:/hint:/pattern:/message: 修饰符(key:value 形式,与位置参数顺序无关)
|
|
15
|
+
* 及 required 布尔标记,返回剩余位置参数(不含类型名)与各修饰值。
|
|
16
|
+
* 含空格的值写作 key:"含 空格",tokenize 剥引号后仍是单 token */
|
|
17
|
+
private extractFieldMods;
|
|
18
|
+
private parseTextInput;
|
|
19
|
+
/** 解析单个按钮:button id "文字" color:#3b82f6 size:large */
|
|
20
|
+
/** 纯文字组件:text [id] "内容" [size:N] [color:xx] [bold] [align:xx]
|
|
21
|
+
* 非参数 token:1 个=纯内容(id 自动生成);≥2 个=第一个是 id,第二个是内容 */
|
|
22
|
+
private parseText;
|
|
23
|
+
private parseButton;
|
|
24
|
+
private parseButtonGroup;
|
|
25
|
+
private parseSelect;
|
|
26
|
+
private parseSelectMulti;
|
|
27
|
+
/** 解析单选组件:radio-group id [choices] [default] [button] [label:xx] [hint:xx] [required]
|
|
28
|
+
* [message:xx] [url:xx] [direction:horizontal|vertical] [columns:N] [disabled]
|
|
29
|
+
* choices 兼容字符串数组(key:label)与对象数组({key|value,label});default 为单值;
|
|
30
|
+
* button 标记切换为按钮组样式(参考 antd Radio optionType:button) */
|
|
31
|
+
private parseRadioGroup;
|
|
32
|
+
/** 解析 select-multi choices:token 以 [{ 开头视为对象数组([{key|value,label} ...]),
|
|
33
|
+
* 容错 JSON 解析(单引号、未引号 key/值、尾逗号、元素间空格分隔、截断补齐)并归一化为
|
|
34
|
+
* {value,label} 数组(key 作为 value 别名,value > key);否则按普通字符串数组解析 */
|
|
35
|
+
private parseObjectChoices;
|
|
36
|
+
/** 容错修复对象数组 choices 文本(整体含外层 []),返回解析结果(失败抛错)。
|
|
37
|
+
* 支持的 AI 风格写法:单引号、\xxx\ 反斜杠引号、未引号 key、未引号字符串值、
|
|
38
|
+
* 尾逗号、元素间空格分隔(} { → },{)、输入截断自动补齐 */
|
|
39
|
+
private repairObjectChoices;
|
|
40
|
+
/** 解析级联选择器:cascade id [路径数组] [default路径] [label:xx] [hint:xx] [required] [disabled] [placeholder:xx]
|
|
41
|
+
* [url:xx] [data:[{...}]]
|
|
42
|
+
* 静态数据源兼容共存:
|
|
43
|
+
* - choices 扁平路径数组:每项用 / 分隔层级,每段支持 key:label(如 zj:浙江/hz:杭州)
|
|
44
|
+
* - data 嵌套对象树:CascadeNode[],如 [{"value":"zj","label":"浙江","children":[...]}](优先于 choices)
|
|
45
|
+
* - data/url 单独出现时(无 choices)也合法:choices 退化为 [] */
|
|
46
|
+
private parseCascade;
|
|
47
|
+
/** 解析树形选择器:tree-select id [路径数组] [default值] [label:xx] [hint:xx] [required] [disabled]
|
|
48
|
+
* [placeholder:xx] [url:xx] [data:[{...}]]
|
|
49
|
+
* [multiple] [checkStrictly] [strategy:all|parent|child] [maxTagCount:N] [treeLine] [searchable]
|
|
50
|
+
* 静态数据源兼容共存(与 cascade 一致);多选/单选对齐 antd(multiple 开启多选,默认单选);
|
|
51
|
+
* searchable 显式开启搜索(默认关闭,对齐 antd showSearch 默认 false) */
|
|
52
|
+
private parseTreeSelect;
|
|
53
|
+
/** 把 data:[...] token 解析为嵌套对象树(CascadeNode[])。token 形如 [{...}] / {...}(data: 前缀已被 extractFieldMods 剥除)。
|
|
54
|
+
* 先按严格 JSON 解析;失败再容错修复 AI 风格写法:
|
|
55
|
+
* - 单引号 → 双引号;反斜杠引号 \xxx\ → "xxx"(键值两侧成对出现时)
|
|
56
|
+
* - 未加引号的 key({value: / ,value: / ,children: → 补双引号)
|
|
57
|
+
* - 行尾/值后多余逗号;输入被截断(末尾缺引号/]/})自动补齐
|
|
58
|
+
* - value/label 支持数字字面量;字段名兼容 key(key 作为 value 别名,由渲染端 nodesToTree 处理)
|
|
59
|
+
* - 顶层是单个对象({...} 或 {data:[...]} 包裹)时提取其内部数组 */
|
|
60
|
+
private parseCascadeNodes;
|
|
61
|
+
/** 容错修复 AI 风格/截断的 data 树文本,返回解析结果(失败抛错) */
|
|
62
|
+
private repairCascadeData;
|
|
63
|
+
private parseSlider;
|
|
64
|
+
/** 解析开关:switch id [true|false] [label:xx] [checkedText:xx] [unCheckedText:xx]
|
|
65
|
+
* [hint:xx] [required] [disabled](default 位置参数接受 true/false 字面量) */
|
|
66
|
+
private parseSwitch;
|
|
67
|
+
/** 解析日期选择框:date-picker id [default] [picker:datetime] [range] [format:YYYY-MM-DD]
|
|
68
|
+
* [disableBeforeNow] [disableAfterNow] [placeholder:xx] [label:xx] [hint:xx] [required]
|
|
69
|
+
* default 接受时间戳(毫秒数字)或格式化时间字符串;range 模式为 [start end] 数组 */
|
|
70
|
+
private parseDatePicker;
|
|
71
|
+
/** 解析数字输入框:number-input id [label] [default] [min:N] [max:N] [step:N] [precision:N]
|
|
72
|
+
* [placeholder:xx] [label:xx] [hint:xx] [required] [message:xx]
|
|
73
|
+
* label/default 均为位置参数:像数字(整数/小数/负数)的当 default,其余当 label(与 date-picker 约定一致) */
|
|
74
|
+
private parseNumberInput;
|
|
75
|
+
/** 从字段行提取尾部 span:N 修饰符(类似 antd Col 的 span),返回 [剩余行, span] */
|
|
76
|
+
private extractFieldSpan;
|
|
77
|
+
/** 从字段行提取尾部 when:字段id:值1,值2 修饰符(form 内联动显隐),返回 [剩余行, when] */
|
|
78
|
+
private extractFieldWhen;
|
|
79
|
+
/** 解析 when 值段的比较运算符前缀(> >= < <= !=):返回 [op, 值列表]。
|
|
80
|
+
* 无前缀或前缀后无有效值时返回 ['eq', 原值列表](向后兼容) */
|
|
81
|
+
private parseWhenOp;
|
|
82
|
+
/** 循环提取字段行尾部的 when/when-any/span 修饰符(支持任意书写顺序),
|
|
83
|
+
* 返回 [剩余行, span, when]。多个 when: 为 AND 组合;多个 when-any: 为 OR 组合;
|
|
84
|
+
* 两组同时存在时取交集(all 且 any)。仅且组时保持对象/数组形态(向后兼容);
|
|
85
|
+
* 含或组时输出 FieldWhenGroup { all, any } */
|
|
86
|
+
private extractFieldModifiers;
|
|
87
|
+
/** 判断字段首行是否为多行块组件(chart 系列)的起始行 */
|
|
88
|
+
private isMultiLineFieldStart;
|
|
89
|
+
/** 从 "row" 行提取 gutter:N 参数(类似 antd Row 的 gutter),返回 [gutter] */
|
|
90
|
+
private parseRowGutter;
|
|
91
|
+
private parseForm;
|
|
92
|
+
/** 解析独立栅格组件:
|
|
93
|
+
* row [id] [gutter:N] [justify:left|center|right|between] [align:top|middle|bottom]
|
|
94
|
+
* col [span:N] [offset:N] [align:top|middle|bottom]
|
|
95
|
+
* <任意 widget DSL>
|
|
96
|
+
*/
|
|
97
|
+
private parseRow;
|
|
98
|
+
private parseChart;
|
|
99
|
+
private parseMultipleChoiceQuestion;
|
|
100
|
+
private parseShortAnswerQuestion;
|
|
101
|
+
private parseQuiz;
|
|
102
|
+
/**
|
|
103
|
+
* Streaming-aware parsing that returns partial results for incomplete input.
|
|
104
|
+
* This is designed for AI streaming scenarios where content arrives incrementally.
|
|
105
|
+
*/
|
|
106
|
+
parseStreaming(input: string): StreamingParseResult;
|
|
107
|
+
/**
|
|
108
|
+
* Detect if input has unclosed brackets or quotes
|
|
109
|
+
*/
|
|
110
|
+
private detectPendingState;
|
|
111
|
+
/**
|
|
112
|
+
* Parse widget with incomplete input, filling in defaults for missing parts
|
|
113
|
+
*/
|
|
114
|
+
private parsePartialWidget;
|
|
115
|
+
/**
|
|
116
|
+
* Auto-complete unclosed arrays by adding closing bracket
|
|
117
|
+
*/
|
|
118
|
+
private autoCompleteArrays;
|
|
119
|
+
/**
|
|
120
|
+
* Parse partial quiz, extracting whatever questions are complete
|
|
121
|
+
*/
|
|
122
|
+
private parsePartialQuiz;
|
|
123
|
+
/**
|
|
124
|
+
* Parse a single question line, handling incomplete input
|
|
125
|
+
*/
|
|
126
|
+
private parsePartialQuestion;
|
|
127
|
+
/**
|
|
128
|
+
* Parse partial form
|
|
129
|
+
*/
|
|
130
|
+
private parsePartialForm;
|
|
131
|
+
/**
|
|
132
|
+
* Parse partial chart
|
|
133
|
+
*/
|
|
134
|
+
private parsePartialChart;
|
|
135
|
+
}
|
|
136
|
+
export declare function parseDSL(input: string): ParseResult;
|
|
137
|
+
export declare function parseDSLStreaming(input: string): StreamingParseResult;
|