openyida 2026.7.19 → 2026.7.21
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 +14 -0
- package/bin/yida.js +107 -18
- package/lib/app/create-app.js +12 -1
- package/lib/app/create-form/args.js +13 -0
- package/lib/app/create-form.js +154 -67
- package/lib/app/create-page.js +45 -9
- package/lib/app/get-schema.js +65 -14
- package/lib/app/import-app.js +92 -41
- package/lib/app/publish.js +289 -556
- package/lib/app/schema-field-resolution.js +370 -0
- package/lib/app/services/app-reader.js +85 -0
- package/lib/app/services/app-service.js +235 -0
- package/lib/app/services/canvas-page-compiler.js +91 -0
- package/lib/app/services/canvas-page-schema-builder.js +149 -0
- package/lib/app/services/field-bindings.js +68 -0
- package/lib/app/services/form-compiler.js +1922 -0
- package/lib/app/services/form-mode-service.js +182 -0
- package/lib/app/services/form-schema-patcher.js +333 -0
- package/lib/app/services/form-schema-reader.js +59 -0
- package/lib/app/services/form-service.js +379 -0
- package/lib/app/services/form-validation.js +562 -0
- package/lib/app/services/native-page-compiler.js +92 -0
- package/lib/app/services/native-page-schema-builder.js +428 -0
- package/lib/app/services/page-resource-service.js +185 -0
- package/lib/app/update-app.js +18 -6
- package/lib/auth/token-auth.js +34 -3
- package/lib/auth/token-store.js +22 -4
- package/lib/bridge/bridge.js +37 -5
- package/lib/core/agent-capabilities.js +5 -3
- package/lib/core/command-manifest.js +40 -0
- package/lib/core/doctor.js +15 -4
- package/lib/core/env-cmd.js +1 -1
- package/lib/core/env.js +7 -6
- package/lib/core/legacy-schema-guard.js +408 -0
- package/lib/core/locales/en.js +8 -46
- package/lib/core/locales/zh.js +8 -46
- package/lib/core/sample.js +1 -1
- package/lib/core/utils.js +334 -66
- package/lib/core/yida-client.js +104 -3
- package/lib/formula/evaluate.js +8 -66
- package/lib/formula/field-refs.js +83 -0
- package/lib/process/configure-process.js +44 -1992
- package/lib/process/create-process.js +54 -87
- package/lib/process/services/process-compiler.js +2056 -0
- package/lib/process/services/process-reader.js +232 -0
- package/lib/process/services/process-resource-service.js +571 -0
- package/lib/process/services/process-service.js +122 -0
- package/lib/process/services/process-stage-checkpoint.js +246 -0
- package/lib/report/append.js +7 -26
- package/lib/report/http.js +31 -5
- package/lib/report/index.js +10 -2
- package/lib/samples/yida-canvas-custom-page/business-list.canvas.jsx +63 -14
- package/lib/samples/yida-canvas-custom-page/dashboard-overview.canvas.jsx +176 -32
- package/lib/samples/yida-canvas-custom-page/data-management.canvas.jsx +228 -14
- package/lib/samples/yida-canvas-custom-page/split-pane-detail.canvas.jsx +204 -8
- package/lib/schema/adapters/app-adapter.js +210 -0
- package/lib/schema/adapters/form-adapter.js +1362 -0
- package/lib/schema/adapters/keys.js +19 -0
- package/lib/schema/adapters/page-adapter.js +566 -0
- package/lib/schema/adapters/process-adapter.js +519 -0
- package/lib/schema/applier.js +1878 -0
- package/lib/schema/apply-store.js +1083 -0
- package/lib/schema/command.js +645 -0
- package/lib/schema/dependency-graph.js +83 -0
- package/lib/schema/errors.js +481 -0
- package/lib/schema/hash.js +9 -0
- package/lib/schema/manifest-limits.js +177 -0
- package/lib/schema/manifest-loader.js +309 -0
- package/lib/schema/manifest-schema-v1.json +193 -0
- package/lib/schema/normalize-manifest.js +281 -0
- package/lib/schema/page-canvas-foundation.js +447 -0
- package/lib/schema/page-data-source-builder.js +561 -0
- package/lib/schema/page-foundation.js +556 -0
- package/lib/schema/page-source-loader.js +314 -0
- package/lib/schema/planner.js +691 -0
- package/lib/schema/remote-dispatch-boundary.js +39 -0
- package/lib/schema/remote-missing.js +21 -0
- package/lib/schema/remote-reader.js +189 -0
- package/lib/schema/resource-registry.js +157 -0
- package/lib/schema/server-revision.js +71 -0
- package/lib/schema/sort.js +28 -0
- package/lib/schema/state-store.js +589 -0
- package/package.json +2 -2
- package/scripts/postinstall.js +8 -12
- package/scripts/validate-package-size.js +1 -1
- package/yida-skills/SKILL.md +114 -29
- package/yida-skills/references/schema-as-code-phase1.md +99 -0
- package/yida-skills/references/setup-and-env.md +59 -59
- package/yida-skills/references/task-retrospective.md +6 -6
- package/yida-skills/skills/yida-app/SKILL.md +60 -14
- package/yida-skills/skills/yida-canvas-custom-page/SKILL.md +18 -7
- package/yida-skills/skills/yida-canvas-custom-page/references/data-bridge-guide.md +3 -3
- package/yida-skills/skills/yida-canvas-custom-page/references/page-generation-guide.md +7 -1
- package/yida-skills/skills/yida-create-app/SKILL.md +21 -3
- package/yida-skills/skills/yida-create-form-page/SKILL.md +19 -1
- package/yida-skills/skills/yida-create-page/SKILL.md +16 -3
- package/yida-skills/skills/yida-create-process/SKILL.md +100 -4
- package/yida-skills/skills/yida-custom-page/SKILL.md +19 -4
- package/yida-skills/skills/yida-dashboard/SKILL.md +1 -1
- package/yida-skills/skills/yida-dashboard/references/pitfalls.md +1 -1
- package/yida-skills/skills/yida-get-schema/SKILL.md +49 -5
- package/yida-skills/skills/yida-i18n/SKILL.md +1 -1
- package/yida-skills/skills/yida-integration/SKILL.md +7 -1
- package/yida-skills/skills/yida-login/SKILL.md +50 -99
- package/yida-skills/skills/yida-page-config/SKILL.md +7 -1
- package/yida-skills/skills/yida-page-uiux/references/app/blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/navigation-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/app/role-journey.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/app-blueprint.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/chart-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/component-contracts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/layout-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/dashboard/theme-recipes.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/object-narrative.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/detail/timeline-and-related.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/assets-workflow.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/industry-playbooks.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/research-levels.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/landing/section-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/drawer-detail.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/empty-loading-error.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/filter-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/list/table-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/scenes/screen.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/entry-patterns.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/portal-layouts.md +0 -1
- package/yida-skills/skills/yida-page-uiux/references/workbench/task-feed.md +0 -1
- package/yida-skills/skills/yida-page-uiux/workflow/output-decision-block.md +1 -1
- package/yida-skills/skills/yida-process-rule/SKILL.md +35 -1
- package/yida-skills/skills/yida-publish-page/SKILL.md +46 -4
- package/yida-skills/skills/yida-report/SKILL.md +7 -1
- package/yida-skills/skills-index.json +14 -46
- package/yida-skills/skills/large-file-write/SKILL.md +0 -93
- package/yida-skills/skills/large-file-write/references/write-patterns.md +0 -147
- package/yida-skills/skills/large-file-write/scripts/write.js +0 -157
- package/yida-skills/skills/sls-log-workbench/SKILL.md +0 -134
- package/yida-skills/skills/sls-log-workbench/references/workbench-reference.md +0 -130
- package/yida-skills/skills/sls-log-workbench/sls-query.js +0 -295
|
@@ -0,0 +1,562 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { buildYidaI18n } = require('../../core/yida-i18n');
|
|
4
|
+
|
|
5
|
+
function i18n(text, enText, jaText) {
|
|
6
|
+
return buildYidaI18n(text, {
|
|
7
|
+
en_US: enText || text,
|
|
8
|
+
ja_JP: jaText || text,
|
|
9
|
+
});
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function deepMerge(target, source) {
|
|
13
|
+
Object.keys(source || {}).forEach(function (key) {
|
|
14
|
+
const sourceValue = source[key];
|
|
15
|
+
if (
|
|
16
|
+
sourceValue &&
|
|
17
|
+
typeof sourceValue === 'object' &&
|
|
18
|
+
!Array.isArray(sourceValue) &&
|
|
19
|
+
target[key] &&
|
|
20
|
+
typeof target[key] === 'object' &&
|
|
21
|
+
!Array.isArray(target[key])
|
|
22
|
+
) {
|
|
23
|
+
deepMerge(target[key], sourceValue);
|
|
24
|
+
} else {
|
|
25
|
+
target[key] = sourceValue;
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return target;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function normalizeValidationType(type) {
|
|
32
|
+
const normalized = String(type || '').trim();
|
|
33
|
+
const lower = normalized.toLowerCase();
|
|
34
|
+
const typeMap = {
|
|
35
|
+
mobile: 'mobile',
|
|
36
|
+
phone: 'mobile',
|
|
37
|
+
tel: 'mobile',
|
|
38
|
+
cellphone: 'mobile',
|
|
39
|
+
regex: 'regex',
|
|
40
|
+
regexp: 'regex',
|
|
41
|
+
pattern: 'regex',
|
|
42
|
+
idcard: 'chineseID',
|
|
43
|
+
id_card: 'chineseID',
|
|
44
|
+
identitycard: 'chineseID',
|
|
45
|
+
identity_card: 'chineseID',
|
|
46
|
+
chineseid: 'chineseID',
|
|
47
|
+
chinese_id: 'chineseID',
|
|
48
|
+
bankcard: 'bankCard',
|
|
49
|
+
bank_card: 'bankCard',
|
|
50
|
+
luhn: 'bankCard',
|
|
51
|
+
uscc: 'unifiedSocialCreditCode',
|
|
52
|
+
creditcode: 'unifiedSocialCreditCode',
|
|
53
|
+
credit_code: 'unifiedSocialCreditCode',
|
|
54
|
+
unifiedsocialcreditcode: 'unifiedSocialCreditCode',
|
|
55
|
+
unified_social_credit_code: 'unifiedSocialCreditCode',
|
|
56
|
+
mail: 'email',
|
|
57
|
+
e_mail: 'email',
|
|
58
|
+
required: 'required',
|
|
59
|
+
compare: 'compare',
|
|
60
|
+
crossfield: 'compare',
|
|
61
|
+
cross_field: 'compare',
|
|
62
|
+
daterange: 'compare',
|
|
63
|
+
date_range: 'compare',
|
|
64
|
+
dateorder: 'compare',
|
|
65
|
+
date_order: 'compare',
|
|
66
|
+
conditionalrequired: 'conditionalRequired',
|
|
67
|
+
conditional_required: 'conditionalRequired',
|
|
68
|
+
expression: 'custom',
|
|
69
|
+
javascript: 'custom',
|
|
70
|
+
js: 'custom',
|
|
71
|
+
customvalidate: 'customValidate',
|
|
72
|
+
custom_validate: 'customValidate',
|
|
73
|
+
async: 'async',
|
|
74
|
+
remote: 'async',
|
|
75
|
+
};
|
|
76
|
+
return typeMap[lower] || normalized;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function defaultValidationMessage(type) {
|
|
80
|
+
const messages = {
|
|
81
|
+
required: i18n('此项为必填项', 'This field is required', 'この項目は必須です'),
|
|
82
|
+
regex: i18n('格式不正确', 'Invalid format', '形式が正しくありません'),
|
|
83
|
+
mobile: i18n('请输入正确的手机号', 'Please enter a valid phone number', '正しい電話番号を入力してください'),
|
|
84
|
+
phone: i18n('请输入正确的手机号', 'Please enter a valid phone number', '正しい電話番号を入力してください'),
|
|
85
|
+
idCard: i18n('身份证号不合法', 'Invalid ID card number', '身分証番号が正しくありません'),
|
|
86
|
+
chineseID: i18n('身份证号不合法', 'Invalid ID card number', '身分証番号が正しくありません'),
|
|
87
|
+
bankCard: i18n('银行卡号不合法', 'Invalid bank card number', '銀行カード番号が正しくありません'),
|
|
88
|
+
unifiedSocialCreditCode: i18n('统一社会信用代码不合法', 'Invalid unified social credit code', '統一社会信用コードが正しくありません'),
|
|
89
|
+
email: i18n('请输入正确的邮箱地址', 'Please enter a valid email address', '正しいメールアドレスを入力してください'),
|
|
90
|
+
compare: i18n('字段间逻辑校验未通过', 'Cross-field validation failed', 'フィールド間検証に失敗しました'),
|
|
91
|
+
conditionalRequired: i18n('此项在当前条件下为必填项', 'This field is required for the current condition', '現在の条件ではこの項目は必須です'),
|
|
92
|
+
custom: i18n('自定义校验未通过', 'Custom validation failed', 'カスタム検証に失敗しました'),
|
|
93
|
+
customValidate: i18n('自定义校验未通过', 'Custom validation failed', 'カスタム検証に失敗しました'),
|
|
94
|
+
async: i18n('异步校验未通过', 'Async validation failed', '非同期検証に失敗しました'),
|
|
95
|
+
};
|
|
96
|
+
return messages[type] || i18n('校验未通过', 'Validation failed', '検証に失敗しました');
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function normalizeDesignerValidationRule(rule) {
|
|
100
|
+
if (!rule) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
if (typeof rule === 'string') {
|
|
104
|
+
return { type: normalizeValidationType(rule), message: defaultValidationMessage(normalizeValidationType(rule)) };
|
|
105
|
+
}
|
|
106
|
+
if (typeof rule !== 'object') {
|
|
107
|
+
return null;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
const type = normalizeValidationType(rule.type || rule.validator || rule.kind || (rule.pattern ? 'regex' : ''));
|
|
111
|
+
if (!type) {
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
const normalized = Object.assign({}, rule, {
|
|
116
|
+
type,
|
|
117
|
+
message: rule.message || rule.errorMessage || rule.tips || defaultValidationMessage(type),
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
if (rule.regex !== undefined && normalized.pattern === undefined) {
|
|
121
|
+
normalized.pattern = rule.regex;
|
|
122
|
+
}
|
|
123
|
+
if (rule.domain_whitelist && !normalized.domainWhitelist) {
|
|
124
|
+
normalized.domainWhitelist = String(rule.domain_whitelist).split(',').map(function (item) {
|
|
125
|
+
return item.trim();
|
|
126
|
+
}).filter(Boolean);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return normalized;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function isNativeFieldValidationRule(rule) {
|
|
133
|
+
if (!rule || rule.condition || rule.when || rule.api || rule.url || rule.endpoint || rule.targetFieldId) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
if (rule.type === 'email' && rule.domainWhitelist && rule.domainWhitelist.length) {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
return [
|
|
140
|
+
'required',
|
|
141
|
+
'number',
|
|
142
|
+
'email',
|
|
143
|
+
'mobile',
|
|
144
|
+
'url',
|
|
145
|
+
'maxLength',
|
|
146
|
+
'minLength',
|
|
147
|
+
'minValue',
|
|
148
|
+
'maxValue',
|
|
149
|
+
'date',
|
|
150
|
+
'money',
|
|
151
|
+
'zipcode',
|
|
152
|
+
'phone',
|
|
153
|
+
'ip',
|
|
154
|
+
'mac',
|
|
155
|
+
'chineseID',
|
|
156
|
+
'customValidate',
|
|
157
|
+
].indexOf(rule.type) !== -1;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function isAdvancedValidationRule(rule) {
|
|
161
|
+
if (!rule || isNativeFieldValidationRule(rule)) {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
return ['bankCard', 'unifiedSocialCreditCode', 'email', 'compare', 'conditionalRequired', 'custom', 'async'].indexOf(rule.type) !== -1;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function jsString(value) {
|
|
168
|
+
return JSON.stringify(value === undefined ? '' : value);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function compileCustomValidateSource(source) {
|
|
172
|
+
const funcSource = String(source || 'function validateRule(value) { return true; }').trim();
|
|
173
|
+
return 'function main(){\n \n "use strict";\n\nvar __compiledFunc__ = '
|
|
174
|
+
+ funcSource
|
|
175
|
+
+ ';\n return __compiledFunc__.apply(this, arguments);\n }';
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function normalizeCustomValidateParam(param) {
|
|
179
|
+
if (param && typeof param === 'object' && param.type === 'js') {
|
|
180
|
+
const source = param.source || 'function validateRule(value) { return true; }';
|
|
181
|
+
return {
|
|
182
|
+
compiled: param.compiled || compileCustomValidateSource(source),
|
|
183
|
+
source: source,
|
|
184
|
+
type: 'js',
|
|
185
|
+
error: param.error || {},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
let funcSource = typeof param === 'string' ? param
|
|
189
|
+
: (param && typeof param === 'object' && param.type === 'JSExpression') ? String(param.value || '')
|
|
190
|
+
: String(param || '');
|
|
191
|
+
if (!funcSource || !/function/.test(funcSource)) {
|
|
192
|
+
funcSource = 'function validateRule(value) { return true; }';
|
|
193
|
+
}
|
|
194
|
+
return {
|
|
195
|
+
compiled: compileCustomValidateSource(funcSource),
|
|
196
|
+
source: funcSource,
|
|
197
|
+
type: 'js',
|
|
198
|
+
error: {},
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
function buildCustomValidateExpressionParam(rule) {
|
|
203
|
+
return normalizeCustomValidateParam(buildCustomValidateParam(rule));
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
function buildCustomValidateParam(rule) {
|
|
207
|
+
if (rule.type === 'customValidate' && rule.param) {
|
|
208
|
+
if (typeof rule.param === 'object' && rule.param.type === 'js') {
|
|
209
|
+
return rule.param;
|
|
210
|
+
}
|
|
211
|
+
return typeof rule.param === 'object' && rule.param.type === 'JSExpression'
|
|
212
|
+
? String(rule.param.value || '')
|
|
213
|
+
: String(rule.param);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
const fieldId = jsString(rule.fieldId);
|
|
217
|
+
const targetFieldId = jsString(rule.targetFieldId || '');
|
|
218
|
+
const operator = jsString(rule.operator || '<=');
|
|
219
|
+
const pattern = jsString(rule.pattern || '');
|
|
220
|
+
const expression = jsString(rule.expression || 'true');
|
|
221
|
+
const condition = JSON.stringify(rule.condition || null);
|
|
222
|
+
const domainWhitelist = JSON.stringify(rule.domainWhitelist || []);
|
|
223
|
+
const api = jsString(rule.api || '');
|
|
224
|
+
const method = jsString(rule.method || 'POST');
|
|
225
|
+
const headers = JSON.stringify(rule.headers || {});
|
|
226
|
+
const body = JSON.stringify(rule.body === undefined ? null : rule.body);
|
|
227
|
+
const validPath = jsString(rule.validPath || '');
|
|
228
|
+
|
|
229
|
+
return `function validateRule(value, currentRule) {
|
|
230
|
+
var FIELD_ID = ${fieldId};
|
|
231
|
+
var TARGET_FIELD_ID = ${targetFieldId};
|
|
232
|
+
var OPERATOR = ${operator};
|
|
233
|
+
var PATTERN = ${pattern};
|
|
234
|
+
var EXPRESSION = ${expression};
|
|
235
|
+
var CONDITION = ${condition};
|
|
236
|
+
var DOMAIN_WHITELIST = ${domainWhitelist};
|
|
237
|
+
var API = ${api};
|
|
238
|
+
var METHOD = ${method};
|
|
239
|
+
var HEADERS = ${headers};
|
|
240
|
+
var BODY = ${body};
|
|
241
|
+
var VALID_PATH = ${validPath};
|
|
242
|
+
var self = this;
|
|
243
|
+
var state = currentRule && currentRule.values || {};
|
|
244
|
+
var ctx = currentRule || {};
|
|
245
|
+
|
|
246
|
+
function isEmpty(input) {
|
|
247
|
+
return input === undefined || input === null || input === '' || (Array.isArray(input) && input.length === 0);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function text(input) {
|
|
251
|
+
if (input === undefined || input === null) { return ''; }
|
|
252
|
+
if (Array.isArray(input)) { return input.join(','); }
|
|
253
|
+
if (typeof input === 'object') {
|
|
254
|
+
if (input.value !== undefined) { return String(input.value).trim(); }
|
|
255
|
+
if (input.label !== undefined) { return String(input.label).trim(); }
|
|
256
|
+
try { return JSON.stringify(input); } catch (err) { return String(input); }
|
|
257
|
+
}
|
|
258
|
+
return String(input).trim();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function getFieldValue(id) {
|
|
262
|
+
if (!id) { return undefined; }
|
|
263
|
+
try {
|
|
264
|
+
if (ctx && ctx.store && typeof ctx.store.get === 'function') {
|
|
265
|
+
var model = ctx.store.get(id);
|
|
266
|
+
if (model) {
|
|
267
|
+
if (typeof model.getVal === 'function') { return model.getVal(); }
|
|
268
|
+
if (typeof model.getValue === 'function') { return model.getValue(); }
|
|
269
|
+
if (typeof model.get === 'function') { return model.get('value'); }
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
} catch (err) {}
|
|
273
|
+
try {
|
|
274
|
+
if (self && typeof self.$ === 'function') {
|
|
275
|
+
var component = self.$(id);
|
|
276
|
+
if (component) {
|
|
277
|
+
if (typeof component.getValue === 'function') { return component.getValue(); }
|
|
278
|
+
if (typeof component.get === 'function') { return component.get('value'); }
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
} catch (err) {}
|
|
282
|
+
try {
|
|
283
|
+
if (typeof $ === 'function') {
|
|
284
|
+
var globalComponent = $(id);
|
|
285
|
+
if (globalComponent) {
|
|
286
|
+
if (typeof globalComponent.getValue === 'function') { return globalComponent.getValue(); }
|
|
287
|
+
if (typeof globalComponent.get === 'function') { return globalComponent.get('value'); }
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
} catch (err) {}
|
|
291
|
+
if (state && Object.prototype.hasOwnProperty.call(state, id)) { return state[id]; }
|
|
292
|
+
return undefined;
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
function comparable(input) {
|
|
296
|
+
if (input instanceof Date) { return input.getTime(); }
|
|
297
|
+
if (typeof input === 'number') { return input; }
|
|
298
|
+
var source = text(input);
|
|
299
|
+
if (/^\\d{13}$/.test(source)) { return Number(source); }
|
|
300
|
+
var parsedDate = Date.parse(source);
|
|
301
|
+
if (!isNaN(parsedDate)) { return parsedDate; }
|
|
302
|
+
var parsedNumber = Number(source);
|
|
303
|
+
return isNaN(parsedNumber) ? source : parsedNumber;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function match(input, condition) {
|
|
307
|
+
if (!condition || condition.operator === 'always') { return true; }
|
|
308
|
+
var conditionValue = condition.value;
|
|
309
|
+
var op = condition.operator || 'eq';
|
|
310
|
+
if (op === 'empty') { return isEmpty(input); }
|
|
311
|
+
if (op === 'notEmpty') { return !isEmpty(input); }
|
|
312
|
+
if (op === 'in') { return (condition.values || []).indexOf(input) !== -1 || (condition.values || []).indexOf(text(input)) !== -1; }
|
|
313
|
+
if (op === 'notIn') { return (condition.values || []).indexOf(input) === -1 && (condition.values || []).indexOf(text(input)) === -1; }
|
|
314
|
+
if (op === 'contains') { return Array.isArray(input) ? input.indexOf(conditionValue) !== -1 : text(input).indexOf(String(conditionValue)) !== -1; }
|
|
315
|
+
if (op === 'notContains') { return Array.isArray(input) ? input.indexOf(conditionValue) === -1 : text(input).indexOf(String(conditionValue)) === -1; }
|
|
316
|
+
if (op === 'ne') { return input !== conditionValue && text(input) !== String(conditionValue); }
|
|
317
|
+
if (op === 'gt') { return Number(input) > Number(conditionValue); }
|
|
318
|
+
if (op === 'gte') { return Number(input) >= Number(conditionValue); }
|
|
319
|
+
if (op === 'lt') { return Number(input) < Number(conditionValue); }
|
|
320
|
+
if (op === 'lte') { return Number(input) <= Number(conditionValue); }
|
|
321
|
+
return input === conditionValue || text(input) === String(conditionValue);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function luhn(input) {
|
|
325
|
+
var digits = text(input).replace(/\\s+/g, '');
|
|
326
|
+
if (!/^\\d{12,19}$/.test(digits)) { return false; }
|
|
327
|
+
var sum = 0;
|
|
328
|
+
var shouldDouble = false;
|
|
329
|
+
for (var i = digits.length - 1; i >= 0; i--) {
|
|
330
|
+
var digit = Number(digits.charAt(i));
|
|
331
|
+
if (shouldDouble) {
|
|
332
|
+
digit *= 2;
|
|
333
|
+
if (digit > 9) { digit -= 9; }
|
|
334
|
+
}
|
|
335
|
+
sum += digit;
|
|
336
|
+
shouldDouble = !shouldDouble;
|
|
337
|
+
}
|
|
338
|
+
return sum % 10 === 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function idCard(input) {
|
|
342
|
+
var valueText = text(input).toUpperCase();
|
|
343
|
+
if (!/^\\d{17}[\\dX]$/.test(valueText)) { return false; }
|
|
344
|
+
var year = Number(valueText.slice(6, 10));
|
|
345
|
+
var month = Number(valueText.slice(10, 12));
|
|
346
|
+
var day = Number(valueText.slice(12, 14));
|
|
347
|
+
var date = new Date(year, month - 1, day);
|
|
348
|
+
if (date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day) { return false; }
|
|
349
|
+
var weights = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2];
|
|
350
|
+
var checks = ['1', '0', 'X', '9', '8', '7', '6', '5', '4', '3', '2'];
|
|
351
|
+
var sum = 0;
|
|
352
|
+
for (var index = 0; index < 17; index++) {
|
|
353
|
+
sum += Number(valueText.charAt(index)) * weights[index];
|
|
354
|
+
}
|
|
355
|
+
return checks[sum % 11] === valueText.charAt(17);
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function uscc(input) {
|
|
359
|
+
var valueText = text(input).toUpperCase();
|
|
360
|
+
var chars = '0123456789ABCDEFGHJKLMNPQRTUWXY';
|
|
361
|
+
if (!/^[0-9ABCDEFGHJKLMNPQRTUWXY]{18}$/.test(valueText)) { return false; }
|
|
362
|
+
var weights = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];
|
|
363
|
+
var sum = 0;
|
|
364
|
+
for (var index = 0; index < 17; index++) {
|
|
365
|
+
var charIndex = chars.indexOf(valueText.charAt(index));
|
|
366
|
+
if (charIndex === -1) { return false; }
|
|
367
|
+
sum += charIndex * weights[index];
|
|
368
|
+
}
|
|
369
|
+
return chars.charAt((31 - (sum % 31)) % 31) === valueText.charAt(17);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
if (CONDITION) {
|
|
373
|
+
var conditionValue = getFieldValue(CONDITION.fieldId);
|
|
374
|
+
if (!match(conditionValue, CONDITION)) { return true; }
|
|
375
|
+
}
|
|
376
|
+
if (${jsString(rule.type)} !== 'required' && ${jsString(rule.type)} !== 'conditionalRequired' && isEmpty(value)) {
|
|
377
|
+
return true;
|
|
378
|
+
}
|
|
379
|
+
if (${jsString(rule.type)} === 'regex') { return new RegExp(PATTERN).test(text(value)); }
|
|
380
|
+
if (${jsString(rule.type)} === 'idCard' || ${jsString(rule.type)} === 'chineseID') { return idCard(value); }
|
|
381
|
+
if (${jsString(rule.type)} === 'bankCard') { return luhn(value); }
|
|
382
|
+
if (${jsString(rule.type)} === 'unifiedSocialCreditCode') { return uscc(value); }
|
|
383
|
+
if (${jsString(rule.type)} === 'email') {
|
|
384
|
+
var email = text(value);
|
|
385
|
+
if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email)) { return false; }
|
|
386
|
+
if (DOMAIN_WHITELIST.length) {
|
|
387
|
+
return DOMAIN_WHITELIST.indexOf(email.split('@').pop()) !== -1;
|
|
388
|
+
}
|
|
389
|
+
return true;
|
|
390
|
+
}
|
|
391
|
+
if (${jsString(rule.type)} === 'compare') {
|
|
392
|
+
var targetValue = getFieldValue(TARGET_FIELD_ID);
|
|
393
|
+
if (isEmpty(value) || isEmpty(targetValue)) { return true; }
|
|
394
|
+
var left = comparable(value);
|
|
395
|
+
var right = comparable(targetValue);
|
|
396
|
+
if (OPERATOR === '<' || OPERATOR === 'lt') { return left < right; }
|
|
397
|
+
if (OPERATOR === '<=' || OPERATOR === 'lte') { return left <= right; }
|
|
398
|
+
if (OPERATOR === '>' || OPERATOR === 'gt') { return left > right; }
|
|
399
|
+
if (OPERATOR === '>=' || OPERATOR === 'gte') { return left >= right; }
|
|
400
|
+
if (OPERATOR === '!=' || OPERATOR === '!==' || OPERATOR === 'ne') { return left !== right; }
|
|
401
|
+
return left === right;
|
|
402
|
+
}
|
|
403
|
+
if (${jsString(rule.type)} === 'conditionalRequired') { return !isEmpty(value); }
|
|
404
|
+
if (${jsString(rule.type)} === 'custom') {
|
|
405
|
+
var fields = {};
|
|
406
|
+
if (FIELD_ID) { fields[FIELD_ID] = value; }
|
|
407
|
+
try {
|
|
408
|
+
var result = (new Function('value', 'fields', 'state', 'ctx', 'getFieldValue', 'return (' + EXPRESSION + ');'))(value, fields, state || {}, ctx || {}, getFieldValue);
|
|
409
|
+
return result === true || (result && result.valid === true);
|
|
410
|
+
} catch (err) {
|
|
411
|
+
return false;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
if (${jsString(rule.type)} === 'async') {
|
|
415
|
+
if (!API) { return true; }
|
|
416
|
+
var payload = BODY || { fieldId: FIELD_ID, value: value };
|
|
417
|
+
return fetch(API, {
|
|
418
|
+
method: METHOD || 'POST',
|
|
419
|
+
headers: Object.assign({ 'Content-Type': 'application/json' }, HEADERS || {}),
|
|
420
|
+
body: String(METHOD || 'POST').toUpperCase() === 'GET' ? undefined : JSON.stringify(payload)
|
|
421
|
+
}).then(function(response) {
|
|
422
|
+
return response.json();
|
|
423
|
+
}).then(function(data) {
|
|
424
|
+
if (VALID_PATH) {
|
|
425
|
+
var current = data;
|
|
426
|
+
String(VALID_PATH).split('.').forEach(function(part) {
|
|
427
|
+
current = current && current[part];
|
|
428
|
+
});
|
|
429
|
+
return current !== false;
|
|
430
|
+
}
|
|
431
|
+
return data.valid !== false && data.success !== false && !data.error;
|
|
432
|
+
}).catch(function() {
|
|
433
|
+
return false;
|
|
434
|
+
});
|
|
435
|
+
}
|
|
436
|
+
return true;
|
|
437
|
+
}`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function toDesignerValidationRule(rule) {
|
|
441
|
+
if (!rule) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (rule.type === 'regex') {
|
|
446
|
+
return {
|
|
447
|
+
type: 'customValidate',
|
|
448
|
+
param: buildCustomValidateExpressionParam(rule),
|
|
449
|
+
message: rule.message,
|
|
450
|
+
};
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
if (isAdvancedValidationRule(rule)) {
|
|
454
|
+
return {
|
|
455
|
+
type: 'customValidate',
|
|
456
|
+
param: buildCustomValidateExpressionParam(rule),
|
|
457
|
+
message: rule.message,
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (!isNativeFieldValidationRule(rule)) {
|
|
462
|
+
return null;
|
|
463
|
+
}
|
|
464
|
+
if (rule.type === 'customValidate' && !rule.param) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
const designerRule = {
|
|
469
|
+
type: rule.type,
|
|
470
|
+
message: rule.message,
|
|
471
|
+
};
|
|
472
|
+
['param', 'minLength', 'maxLength', 'minValue', 'maxValue'].forEach(function (key) {
|
|
473
|
+
if (rule[key] !== undefined) {
|
|
474
|
+
designerRule[key] = key === 'param' && rule.type === 'customValidate'
|
|
475
|
+
? normalizeCustomValidateParam(rule[key])
|
|
476
|
+
: rule[key];
|
|
477
|
+
}
|
|
478
|
+
});
|
|
479
|
+
return designerRule;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
function validationRuleSignature(rule) {
|
|
483
|
+
const param = rule && rule.param && typeof rule.param === 'object'
|
|
484
|
+
? JSON.stringify(rule.param)
|
|
485
|
+
: rule && rule.param;
|
|
486
|
+
return [
|
|
487
|
+
rule && rule.type,
|
|
488
|
+
rule && rule.pattern,
|
|
489
|
+
param,
|
|
490
|
+
rule && rule.targetFieldId,
|
|
491
|
+
rule && rule.operator,
|
|
492
|
+
rule && rule.api,
|
|
493
|
+
rule && rule.expression,
|
|
494
|
+
rule && rule.condition ? JSON.stringify(rule.condition) : '',
|
|
495
|
+
].map(function (value) {
|
|
496
|
+
return value === undefined ? '' : String(value);
|
|
497
|
+
}).join('|');
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function dedupeValidationRules(rules) {
|
|
501
|
+
const seen = new Set();
|
|
502
|
+
return (rules || []).filter(function (rule) {
|
|
503
|
+
const signature = validationRuleSignature(rule);
|
|
504
|
+
if (seen.has(signature)) {
|
|
505
|
+
return false;
|
|
506
|
+
}
|
|
507
|
+
seen.add(signature);
|
|
508
|
+
return true;
|
|
509
|
+
});
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
function collectInputValidationRules(field, options) {
|
|
513
|
+
const rules = [];
|
|
514
|
+
const includeAdvanced = !!(options && options.includeAdvanced);
|
|
515
|
+
const sourceRules = Array.isArray(field && field.validation)
|
|
516
|
+
? field.validation
|
|
517
|
+
: Array.isArray(field && field.validations)
|
|
518
|
+
? field.validations
|
|
519
|
+
: [];
|
|
520
|
+
|
|
521
|
+
if (field && field.required) {
|
|
522
|
+
rules.push({
|
|
523
|
+
type: 'required',
|
|
524
|
+
message: field.requiredMessage || field.message || defaultValidationMessage('required'),
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
if (field && (field.pattern || field.regex)) {
|
|
529
|
+
rules.push({
|
|
530
|
+
type: 'regex',
|
|
531
|
+
pattern: field.pattern || field.regex,
|
|
532
|
+
message: field.message || defaultValidationMessage('regex'),
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
sourceRules.forEach(function (rule) {
|
|
537
|
+
const normalized = normalizeDesignerValidationRule(rule);
|
|
538
|
+
if (normalized && (includeAdvanced || isNativeFieldValidationRule(normalized))) {
|
|
539
|
+
rules.push(normalized);
|
|
540
|
+
}
|
|
541
|
+
});
|
|
542
|
+
|
|
543
|
+
return dedupeValidationRules(rules);
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function normalizeFieldValidationRules(field, options) {
|
|
547
|
+
return dedupeValidationRules(collectInputValidationRules(field, options).map(function (rule) {
|
|
548
|
+
return toDesignerValidationRule(rule);
|
|
549
|
+
}).filter(Boolean));
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
module.exports = {
|
|
553
|
+
collectInputValidationRules,
|
|
554
|
+
dedupeValidationRules,
|
|
555
|
+
deepMerge,
|
|
556
|
+
defaultValidationMessage,
|
|
557
|
+
isNativeFieldValidationRule,
|
|
558
|
+
normalizeDesignerValidationRule,
|
|
559
|
+
normalizeFieldValidationRules,
|
|
560
|
+
normalizeValidationType,
|
|
561
|
+
toDesignerValidationRule,
|
|
562
|
+
};
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('crypto');
|
|
4
|
+
const UglifyJS = require('uglify-js');
|
|
5
|
+
const { default: babelTransform } = require('../../core/babel-transform');
|
|
6
|
+
const { buildPageSource } = require('../page-compat');
|
|
7
|
+
const { schemaError } = require('../../schema/errors');
|
|
8
|
+
const { isLoadedPageSource } = require('../../schema/page-source-loader');
|
|
9
|
+
|
|
10
|
+
const NATIVE_PAGE_PROFILE = 'native/default';
|
|
11
|
+
const COMPILED_PAGES = new WeakSet();
|
|
12
|
+
|
|
13
|
+
function compileNativePageSource(loadedSource) {
|
|
14
|
+
if (!isLoadedPageSource(loadedSource)) {
|
|
15
|
+
compilerError('SCHEMA_PAGE_SOURCE_INVALID', 'Native page compiler requires a trusted page source.');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let buildResult;
|
|
19
|
+
try {
|
|
20
|
+
buildResult = buildPageSource(
|
|
21
|
+
loadedSource.source,
|
|
22
|
+
loadedSource.relativePath,
|
|
23
|
+
{ modern: /\.oyd\.jsx$|\.openyida\.jsx$/i.test(loadedSource.relativePath) }
|
|
24
|
+
);
|
|
25
|
+
} catch (error) {
|
|
26
|
+
compilerError('SCHEMA_PAGE_SOURCE_COMPILE_FAILED', 'Native page source could not be normalized.', {
|
|
27
|
+
stage: 'normalize',
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
if (!buildResult || buildResult.ok !== true || typeof buildResult.code !== 'string' || !buildResult.code) {
|
|
31
|
+
compilerError('SCHEMA_PAGE_SOURCE_COMPILE_FAILED', 'Native page source did not pass local validation.', {
|
|
32
|
+
stage: 'normalize',
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let babelResult;
|
|
37
|
+
try {
|
|
38
|
+
babelResult = babelTransform(buildResult.code, {}, false, { RE_VERSION: '7.4.0' });
|
|
39
|
+
} catch (error) {
|
|
40
|
+
compilerError('SCHEMA_PAGE_SOURCE_COMPILE_FAILED', 'Native page source could not be compiled.', {
|
|
41
|
+
stage: 'babel',
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
if (!babelResult || babelResult.error instanceof Error || typeof babelResult.compiled !== 'string') {
|
|
45
|
+
compilerError('SCHEMA_PAGE_SOURCE_COMPILE_FAILED', 'Native page source could not be compiled.', {
|
|
46
|
+
stage: 'babel',
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
let minified;
|
|
51
|
+
try {
|
|
52
|
+
minified = UglifyJS.minify(babelResult.compiled);
|
|
53
|
+
} catch (error) {
|
|
54
|
+
compilerError('SCHEMA_PAGE_SOURCE_COMPILE_FAILED', 'Native page output could not be minified.', {
|
|
55
|
+
stage: 'minify',
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (!minified || minified.error || typeof minified.code !== 'string' || !minified.code) {
|
|
59
|
+
compilerError('SCHEMA_PAGE_SOURCE_COMPILE_FAILED', 'Native page output could not be minified.', {
|
|
60
|
+
stage: 'minify',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const result = Object.freeze({
|
|
65
|
+
compiled: minified.code,
|
|
66
|
+
compiledHash: createSha256(minified.code),
|
|
67
|
+
inputHash: loadedSource.sourceHash,
|
|
68
|
+
profile: NATIVE_PAGE_PROFILE,
|
|
69
|
+
source: buildResult.code,
|
|
70
|
+
sourceHash: createSha256(buildResult.code),
|
|
71
|
+
});
|
|
72
|
+
COMPILED_PAGES.add(result);
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function isCompiledNativePage(value) {
|
|
77
|
+
return !!(value && typeof value === 'object' && COMPILED_PAGES.has(value));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function createSha256(value) {
|
|
81
|
+
return 'sha256:' + crypto.createHash('sha256').update(value).digest('hex');
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function compilerError(code, message, details) {
|
|
85
|
+
throw schemaError(code, message, details ? { details } : undefined);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
module.exports = {
|
|
89
|
+
NATIVE_PAGE_PROFILE,
|
|
90
|
+
compileNativePageSource,
|
|
91
|
+
isCompiledNativePage,
|
|
92
|
+
};
|