@xbeeant/form-engine-designer 0.0.1 → 0.0.3

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.
@@ -1,193 +0,0 @@
1
- import { describe as c, it as o, expect as t } from "/Users/amybee/Codes/xbeeant/nexus-form-engine/node_modules/.bun/vitest@4.1.10+0a9a94c82e2ce81a/node_modules/vitest/dist/index.js";
2
- import { collectDataFieldPaths as n } from "../schemaUtils.js";
3
- import { buildExpression as e, parseExpression as i, stripBraces as p, variableToString as s, parseVariable as d } from "./expressionModel.js";
4
- c("buildExpression", () => {
5
- o("构建基本比较表达式(文本 / 数字 / 布尔 / 变量右值)", () => {
6
- t(
7
- e([
8
- {
9
- id: "1",
10
- logic: "and",
11
- variable: { source: "formData", path: "usePromo" },
12
- operator: "eq",
13
- rightMode: "boolean",
14
- right: "true"
15
- }
16
- ])
17
- ).toBe("{{ formData.usePromo === true }}"), t(
18
- e([
19
- {
20
- id: "1",
21
- logic: "and",
22
- variable: { source: "formData", path: "amount" },
23
- operator: "gte",
24
- rightMode: "number",
25
- right: "100"
26
- }
27
- ])
28
- ).toBe("{{ formData.amount >= 100 }}"), t(
29
- e([
30
- {
31
- id: "1",
32
- logic: "and",
33
- variable: { source: "self", path: "" },
34
- operator: "neq",
35
- rightMode: "string",
36
- right: "special"
37
- }
38
- ])
39
- ).toBe("{{ $self.value !== 'special' }}"), t(
40
- e([
41
- {
42
- id: "1",
43
- logic: "and",
44
- variable: { source: "formData", path: "amount" },
45
- operator: "eq",
46
- rightMode: "variable",
47
- right: "formData.limit"
48
- }
49
- ])
50
- ).toBe("{{ formData.amount === formData.limit }}");
51
- }), o("空右值 / 未选变量视为不完整条件,返回空模板", () => {
52
- t(
53
- e([
54
- {
55
- id: "1",
56
- logic: "and",
57
- variable: { source: "formData", path: "" },
58
- operator: "eq",
59
- rightMode: "string",
60
- right: "x"
61
- }
62
- ])
63
- ).toBe("{{ }}"), t(
64
- e([
65
- {
66
- id: "1",
67
- logic: "and",
68
- variable: { source: "formData", path: "a" },
69
- operator: "eq",
70
- rightMode: "string",
71
- right: ""
72
- }
73
- ])
74
- ).toBe("{{ }}");
75
- }), o("无条件时返回空模板", () => {
76
- t(e([])).toBe("{{ }}");
77
- }), o("按 and/or 连接多条条件", () => {
78
- const a = (u, m) => ({
79
- id: Math.random().toString(),
80
- logic: "and",
81
- variable: { source: "formData", path: "a" },
82
- operator: u,
83
- rightMode: "string",
84
- right: m
85
- }), r = { ...a("eq", "x"), id: "1" }, l = { ...a("neq", "y"), id: "2", logic: "or" };
86
- t(e([r, l])).toBe(
87
- "{{ formData.a === 'x' || formData.a !== 'y' }}"
88
- );
89
- }), o("contains / startsWith / empty / truthy 等操作符", () => {
90
- const a = (r, l = "") => ({
91
- id: "1",
92
- logic: "and",
93
- variable: { source: "formData", path: "code" },
94
- operator: r,
95
- rightMode: "string",
96
- right: l
97
- });
98
- t(e([a("contains", "CN")])).toBe(
99
- "{{ String(formData.code).includes('CN') }}"
100
- ), t(e([a("notEmpty")])).toBe(
101
- "{{ (formData.code != null && String(formData.code).trim() !== '') }}"
102
- ), t(e([a("truthy")])).toBe("{{ !!(formData.code) }}");
103
- });
104
- });
105
- c("parseExpression", () => {
106
- o("解析基本表达式为行模型", () => {
107
- const a = i("{{ formData.usePromo === true }}");
108
- t(a).not.toBeNull(), t(a[0]).toMatchObject({
109
- variable: { source: "formData", path: "usePromo" },
110
- operator: "eq",
111
- rightMode: "boolean",
112
- right: "true"
113
- });
114
- }), o("解析 $deps / $self / 文本字面量", () => {
115
- const a = i("{{ $deps[0] === true }}");
116
- t(a[0].variable).toEqual({ source: "deps", path: "0" });
117
- const r = i("{{ $self.value === 'x' }}");
118
- t(r[0].variable).toEqual({ source: "self", path: "" }), t(r[0].rightMode).toBe("string"), t(r[0].right).toBe("x");
119
- }), o("解析 and/or 连接", () => {
120
- const a = i(
121
- "{{ formData.a === 'x' && formData.b > 3 || formData.c == 'y' }}"
122
- );
123
- t(a.length).toBe(3), t(a[0].logic).toBe("and"), t(a[1].logic).toBe("and"), t(a[2].logic).toBe("or");
124
- }), o("解析空模板 / 空串为 []", () => {
125
- t(i("{{ }}")).toEqual([]), t(i("")).toEqual([]), t(i(void 0)).toEqual([]);
126
- }), o("无法解析的表达式返回 null(回退高级模式)", () => {
127
- t(i("{{ formData.a.toUpperCase() }}")).toBeNull(), t(i("{{ $deps[0] + 1 > 2 }}")).toBeNull();
128
- }), o("round-trip:build → parse → build 保持一致", () => {
129
- const a = "{{ formData.a === 'x' || formData.b >= 3 }}", r = i(a);
130
- t(r.length).toBe(2);
131
- const l = e(r);
132
- t(l).toBe(a);
133
- });
134
- });
135
- c("变量工具", () => {
136
- o("stripBraces 去除包裹", () => {
137
- t(p("{{ a === 1 }}")).toBe("a === 1"), t(p("a === 1")).toBe("a === 1");
138
- }), o("variableToString 各来源", () => {
139
- t(s({ source: "formData", path: "user.name" })).toBe(
140
- "formData.user.name"
141
- ), t(s({ source: "deps", path: "2" })).toBe("$deps[2]"), t(s({ source: "self", path: "" })).toBe("$self.value"), t(s({ source: "index", path: "" })).toBe("$index"), t(s({ source: "root", path: "" })).toBe("rootValue");
142
- }), o("parseVariable 非标识符字段用括号访问", () => {
143
- t(d("formData['a-b']")).toEqual({
144
- source: "formData",
145
- path: "a-b"
146
- }), t(s(d("formData['a-b']"))).toBe(
147
- "formData['a-b']"
148
- );
149
- });
150
- });
151
- c("collectDataFieldPaths", () => {
152
- o("布局节点 Key 不进路径,对象 / 数组透传", () => {
153
- t(n({
154
- properties: {
155
- card: {
156
- type: "card",
157
- title: "卡片",
158
- properties: {
159
- name: { type: "string", widget: "input", title: "姓名" },
160
- address: {
161
- type: "object",
162
- properties: {
163
- city: { type: "string", widget: "input" }
164
- }
165
- },
166
- tags: {
167
- type: "array",
168
- widget: "list",
169
- items: {
170
- type: "object",
171
- properties: {
172
- label: { type: "string", widget: "input" }
173
- }
174
- }
175
- }
176
- }
177
- }
178
- }
179
- })).toEqual([
180
- "name",
181
- "address.city",
182
- "tags",
183
- "tags[0].label"
184
- ]);
185
- }), o("子表单(带 widget 的 object)视为叶子字段", () => {
186
- t(n({
187
- properties: {
188
- sub: { type: "object", widget: "subForm", properties: {} }
189
- }
190
- })).toEqual(["sub"]);
191
- });
192
- });
193
- //# sourceMappingURL=expressionModel.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"expressionModel.test.js","sources":["../../../src/widgets/expressionModel.test.ts"],"sourcesContent":["import type { NexusSchema } from '@xbeeant/form-engine';\nimport { describe, expect, it } from 'vitest';\nimport { collectDataFieldPaths } from '../schemaUtils';\nimport {\n buildExpression,\n type ConditionOperator,\n parseExpression,\n parseVariable,\n stripBraces,\n variableToString,\n} from './expressionModel';\n\ndescribe('buildExpression', () => {\n it('构建基本比较表达式(文本 / 数字 / 布尔 / 变量右值)', () => {\n expect(\n buildExpression([\n {\n id: '1',\n logic: 'and',\n variable: { source: 'formData', path: 'usePromo' },\n operator: 'eq',\n rightMode: 'boolean',\n right: 'true',\n },\n ]),\n ).toBe('{{ formData.usePromo === true }}');\n\n expect(\n buildExpression([\n {\n id: '1',\n logic: 'and',\n variable: { source: 'formData', path: 'amount' },\n operator: 'gte',\n rightMode: 'number',\n right: '100',\n },\n ]),\n ).toBe('{{ formData.amount >= 100 }}');\n\n expect(\n buildExpression([\n {\n id: '1',\n logic: 'and',\n variable: { source: 'self', path: '' },\n operator: 'neq',\n rightMode: 'string',\n right: 'special',\n },\n ]),\n ).toBe(\"{{ $self.value !== 'special' }}\");\n\n expect(\n buildExpression([\n {\n id: '1',\n logic: 'and',\n variable: { source: 'formData', path: 'amount' },\n operator: 'eq',\n rightMode: 'variable',\n right: 'formData.limit',\n },\n ]),\n ).toBe('{{ formData.amount === formData.limit }}');\n });\n\n it('空右值 / 未选变量视为不完整条件,返回空模板', () => {\n expect(\n buildExpression([\n {\n id: '1',\n logic: 'and',\n variable: { source: 'formData', path: '' },\n operator: 'eq',\n rightMode: 'string',\n right: 'x',\n },\n ]),\n ).toBe('{{ }}');\n\n expect(\n buildExpression([\n {\n id: '1',\n logic: 'and',\n variable: { source: 'formData', path: 'a' },\n operator: 'eq',\n rightMode: 'string',\n right: '',\n },\n ]),\n ).toBe('{{ }}');\n });\n\n it('无条件时返回空模板', () => {\n expect(buildExpression([])).toBe('{{ }}');\n });\n\n it('按 and/or 连接多条条件', () => {\n const cond = (op: 'eq' | 'neq', right: string) => ({\n id: Math.random().toString(),\n logic: 'and' as const,\n variable: { source: 'formData' as const, path: 'a' },\n operator: op,\n rightMode: 'string' as const,\n right,\n });\n const c1 = { ...cond('eq', 'x'), id: '1' };\n const c2 = { ...cond('neq', 'y'), id: '2', logic: 'or' as const };\n expect(buildExpression([c1, c2])).toBe(\n \"{{ formData.a === 'x' || formData.a !== 'y' }}\",\n );\n });\n\n it('contains / startsWith / empty / truthy 等操作符', () => {\n const base = (operator: ConditionOperator, right = '') => ({\n id: '1',\n logic: 'and' as const,\n variable: { source: 'formData' as const, path: 'code' },\n operator,\n rightMode: 'string' as const,\n right,\n });\n expect(buildExpression([base('contains', 'CN')])).toBe(\n \"{{ String(formData.code).includes('CN') }}\",\n );\n expect(buildExpression([base('notEmpty')])).toBe(\n \"{{ (formData.code != null && String(formData.code).trim() !== '') }}\",\n );\n expect(buildExpression([base('truthy')])).toBe('{{ !!(formData.code) }}');\n });\n});\n\ndescribe('parseExpression', () => {\n it('解析基本表达式为行模型', () => {\n const conds = parseExpression('{{ formData.usePromo === true }}');\n expect(conds).not.toBeNull();\n expect(conds![0]).toMatchObject({\n variable: { source: 'formData', path: 'usePromo' },\n operator: 'eq',\n rightMode: 'boolean',\n right: 'true',\n });\n });\n\n it('解析 $deps / $self / 文本字面量', () => {\n const conds = parseExpression('{{ $deps[0] === true }}');\n expect(conds![0].variable).toEqual({ source: 'deps', path: '0' });\n\n const self = parseExpression(\"{{ $self.value === 'x' }}\");\n expect(self![0].variable).toEqual({ source: 'self', path: '' });\n expect(self![0].rightMode).toBe('string');\n expect(self![0].right).toBe('x');\n });\n\n it('解析 and/or 连接', () => {\n const conds = parseExpression(\n \"{{ formData.a === 'x' && formData.b > 3 || formData.c == 'y' }}\",\n );\n expect(conds!.length).toBe(3);\n expect(conds![0].logic).toBe('and');\n expect(conds![1].logic).toBe('and');\n expect(conds![2].logic).toBe('or');\n });\n\n it('解析空模板 / 空串为 []', () => {\n expect(parseExpression('{{ }}')).toEqual([]);\n expect(parseExpression('')).toEqual([]);\n expect(parseExpression(undefined)).toEqual([]);\n });\n\n it('无法解析的表达式返回 null(回退高级模式)', () => {\n expect(parseExpression('{{ formData.a.toUpperCase() }}')).toBeNull();\n expect(parseExpression('{{ $deps[0] + 1 > 2 }}')).toBeNull();\n });\n\n it('round-trip:build → parse → build 保持一致', () => {\n const src = \"{{ formData.a === 'x' || formData.b >= 3 }}\";\n const conds = parseExpression(src)!;\n expect(conds.length).toBe(2);\n const rebuilt = buildExpression(conds);\n expect(rebuilt).toBe(src);\n });\n});\n\ndescribe('变量工具', () => {\n it('stripBraces 去除包裹', () => {\n expect(stripBraces('{{ a === 1 }}')).toBe('a === 1');\n expect(stripBraces('a === 1')).toBe('a === 1');\n });\n\n it('variableToString 各来源', () => {\n expect(variableToString({ source: 'formData', path: 'user.name' })).toBe(\n 'formData.user.name',\n );\n expect(variableToString({ source: 'deps', path: '2' })).toBe('$deps[2]');\n expect(variableToString({ source: 'self', path: '' })).toBe('$self.value');\n expect(variableToString({ source: 'index', path: '' })).toBe('$index');\n expect(variableToString({ source: 'root', path: '' })).toBe('rootValue');\n });\n\n it('parseVariable 非标识符字段用括号访问', () => {\n expect(parseVariable(\"formData['a-b']\")).toEqual({\n source: 'formData',\n path: 'a-b',\n });\n expect(variableToString(parseVariable(\"formData['a-b']\"))).toBe(\n \"formData['a-b']\",\n );\n });\n});\n\ndescribe('collectDataFieldPaths', () => {\n it('布局节点 Key 不进路径,对象 / 数组透传', () => {\n const schema = {\n type: 'object',\n properties: {\n card: {\n type: 'card',\n title: '卡片',\n properties: {\n name: { type: 'string', widget: 'input', title: '姓名' },\n address: {\n type: 'object',\n properties: {\n city: { type: 'string', widget: 'input' },\n },\n },\n tags: {\n type: 'array',\n widget: 'list',\n items: {\n type: 'object',\n properties: {\n label: { type: 'string', widget: 'input' },\n },\n },\n },\n },\n },\n },\n } as unknown as NexusSchema;\n\n expect(collectDataFieldPaths(schema)).toEqual([\n 'name',\n 'address.city',\n 'tags',\n 'tags[0].label',\n ]);\n });\n\n it('子表单(带 widget 的 object)视为叶子字段', () => {\n const schema = {\n type: 'object',\n properties: {\n sub: { type: 'object', widget: 'subForm', properties: {} },\n },\n } as unknown as NexusSchema;\n expect(collectDataFieldPaths(schema)).toEqual(['sub']);\n });\n});\n"],"names":["describe","it","expect","buildExpression","cond","op","right","c1","c2","base","operator","conds","parseExpression","self","src","rebuilt","stripBraces","variableToString","parseVariable","collectDataFieldPaths"],"mappings":"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"}