nesoi 3.0.18 → 3.0.20
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/lib/compiler/elements/bucket.element.d.ts +1 -1
- package/lib/compiler/elements/bucket.element.js +25 -27
- package/lib/compiler/elements/message.element.js +50 -20
- package/lib/elements/blocks/block.builder.d.ts +10 -1
- package/lib/elements/blocks/block.builder.js +26 -0
- package/lib/elements/blocks/job/job.builder.d.ts +7 -1
- package/lib/elements/blocks/job/job.builder.js +4 -0
- package/lib/elements/entities/bucket/model/bucket_model.convert.js +11 -9
- package/lib/elements/entities/bucket/model/bucket_model_field.builder.d.ts +1 -1
- package/lib/elements/entities/bucket/model/bucket_model_field.builder.js +11 -8
- package/lib/elements/entities/bucket/view/bucket_view.js +2 -2
- package/lib/elements/entities/message/message_parser.d.ts +0 -4
- package/lib/elements/entities/message/message_parser.js +41 -75
- package/lib/elements/entities/message/template/message_template.schema.d.ts +25 -2
- package/lib/elements/entities/message/template/message_template.schema.js +16 -2
- package/lib/elements/entities/message/template/message_template_field.builder.d.ts +2 -2
- package/lib/elements/entities/message/template/message_template_field.builder.js +12 -10
- package/lib/elements/entities/message/template/message_template_parser.d.ts +6 -2
- package/lib/elements/entities/message/template/message_template_parser.js +121 -76
- package/lib/engine/data/error.d.ts +11 -0
- package/lib/engine/data/error.js +4 -0
- package/lib/engine/util/deep.d.ts +2 -0
- package/lib/engine/util/deep.js +30 -0
- package/lib/engine/util/parse.d.ts +39 -28
- package/lib/engine/util/parse.js +159 -188
- package/package.json +1 -1
- package/tsconfig.build.tsbuildinfo +1 -1
|
@@ -14,7 +14,7 @@ export declare class BucketElement extends Element<$Bucket> {
|
|
|
14
14
|
private buildModelFieldType;
|
|
15
15
|
private buildCompositionType;
|
|
16
16
|
buildModelType(fields?: $BucketModelFields): ObjTypeAsObj;
|
|
17
|
-
buildModelFieldNamesType(model: ObjTypeAsObj, fields?: $BucketModelFields
|
|
17
|
+
buildModelFieldNamesType(model: ObjTypeAsObj, fields?: $BucketModelFields): Record<string, TypeAsObj>;
|
|
18
18
|
private buildGraphType;
|
|
19
19
|
private buildViewsType;
|
|
20
20
|
private buildViewType;
|
|
@@ -64,7 +64,7 @@ class BucketElement extends element_1.Element {
|
|
|
64
64
|
bucket
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
|
-
buildModelFieldType(field) {
|
|
67
|
+
buildModelFieldType(field, isUnion = false) {
|
|
68
68
|
let type = 'unknown';
|
|
69
69
|
if (field.type === 'boolean') {
|
|
70
70
|
type = 'boolean';
|
|
@@ -119,35 +119,38 @@ class BucketElement extends element_1.Element {
|
|
|
119
119
|
'[x in string]': field.children.__dict
|
|
120
120
|
});
|
|
121
121
|
}
|
|
122
|
-
if (!field.required && field.defaultValue === undefined) {
|
|
123
|
-
if (typeof type === 'object') {
|
|
124
|
-
type.__optional = true;
|
|
125
|
-
}
|
|
126
|
-
else {
|
|
127
|
-
type += ' | undefined';
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
if (field.array) {
|
|
131
|
-
if (typeof type === 'object') {
|
|
132
|
-
type.__array = true;
|
|
133
|
-
}
|
|
134
|
-
else {
|
|
135
|
-
type += '[]';
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
122
|
if (field.or) {
|
|
139
|
-
const orType = this.buildModelFieldType(field.or);
|
|
123
|
+
const orType = this.buildModelFieldType(field.or, true);
|
|
140
124
|
if (typeof type === 'object') {
|
|
141
125
|
type.__or = orType;
|
|
142
126
|
}
|
|
143
127
|
else if (typeof orType === 'object') {
|
|
128
|
+
const nonObj = type;
|
|
144
129
|
type = orType;
|
|
145
|
-
type.__or =
|
|
130
|
+
type.__or = nonObj;
|
|
146
131
|
}
|
|
147
132
|
else {
|
|
148
133
|
type = `${type} | ${orType}`;
|
|
149
134
|
}
|
|
150
135
|
}
|
|
136
|
+
if (!isUnion) {
|
|
137
|
+
if (!field.required && field.defaultValue === undefined) {
|
|
138
|
+
if (typeof type === 'object') {
|
|
139
|
+
type.__optional = true;
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
type = `(${type}) | undefined`;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (field.array) {
|
|
146
|
+
if (typeof type === 'object') {
|
|
147
|
+
type.__array = true;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
type = `(${type})[]`;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
151
154
|
return type;
|
|
152
155
|
}
|
|
153
156
|
buildCompositionType() {
|
|
@@ -171,25 +174,20 @@ class BucketElement extends element_1.Element {
|
|
|
171
174
|
});
|
|
172
175
|
return model;
|
|
173
176
|
}
|
|
174
|
-
buildModelFieldNamesType(model, fields = this.schema.model.fields
|
|
177
|
+
buildModelFieldNamesType(model, fields = this.schema.model.fields) {
|
|
175
178
|
const fieldPaths = {};
|
|
176
179
|
Object.entries(fields).forEach(([key, field]) => {
|
|
177
180
|
if (key === '__dict') {
|
|
178
181
|
return;
|
|
179
182
|
}
|
|
180
|
-
|
|
181
|
-
fieldPaths[keyPath] = model[key];
|
|
183
|
+
fieldPaths[field.path] = model[key];
|
|
182
184
|
if (field.children) {
|
|
183
185
|
let nextFields = field.children;
|
|
184
|
-
let nextKey = keyPath;
|
|
185
186
|
if ('__dict' in field.children) {
|
|
186
187
|
nextFields = field.children.__dict.children;
|
|
187
|
-
nextKey += '.#';
|
|
188
188
|
}
|
|
189
|
-
if (field.array)
|
|
190
|
-
nextKey += '.#';
|
|
191
189
|
if (nextFields) {
|
|
192
|
-
Object.assign(fieldPaths, this.buildModelFieldNamesType(model[key], nextFields
|
|
190
|
+
Object.assign(fieldPaths, this.buildModelFieldNamesType(model[key], nextFields));
|
|
193
191
|
}
|
|
194
192
|
}
|
|
195
193
|
});
|
|
@@ -44,7 +44,7 @@ class MessageElement extends element_1.Element {
|
|
|
44
44
|
buildIO(fields = this.schema.template.fields) {
|
|
45
45
|
const input = {};
|
|
46
46
|
const output = {};
|
|
47
|
-
|
|
47
|
+
const buildField = (key, field, isUnion = false) => {
|
|
48
48
|
if (field.type === 'boolean') {
|
|
49
49
|
input[key] = 'boolean';
|
|
50
50
|
output[key] = 'boolean';
|
|
@@ -138,36 +138,66 @@ class MessageElement extends element_1.Element {
|
|
|
138
138
|
input[key] = 'unknown';
|
|
139
139
|
output[key] = 'unknown';
|
|
140
140
|
}
|
|
141
|
-
if (
|
|
141
|
+
if (field.or) {
|
|
142
|
+
const orType = buildField(key, field.or, true);
|
|
142
143
|
if (typeof input[key] === 'object') {
|
|
143
|
-
input[key].
|
|
144
|
+
input[key].__or = orType;
|
|
145
|
+
}
|
|
146
|
+
else if (typeof orType === 'object') {
|
|
147
|
+
const nonObj = input[key];
|
|
148
|
+
input[key] = orType;
|
|
149
|
+
input[key].__or = nonObj;
|
|
144
150
|
}
|
|
145
151
|
else {
|
|
146
|
-
input[key]
|
|
152
|
+
input[key] = `${input[key]} | ${orType}`;
|
|
147
153
|
}
|
|
148
|
-
if (
|
|
149
|
-
|
|
150
|
-
output[key].__optional = true;
|
|
151
|
-
}
|
|
152
|
-
else {
|
|
153
|
-
output[key] += ' | undefined';
|
|
154
|
-
}
|
|
154
|
+
if (typeof output[key] === 'object') {
|
|
155
|
+
output[key].__or = orType;
|
|
155
156
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
157
|
+
else if (typeof orType === 'object') {
|
|
158
|
+
const nonObj = output[key];
|
|
159
|
+
output[key] = orType;
|
|
160
|
+
output[key].__or = nonObj;
|
|
160
161
|
}
|
|
161
162
|
else {
|
|
162
|
-
|
|
163
|
+
output[key] = `${output[key]} | ${orType}`;
|
|
163
164
|
}
|
|
164
|
-
|
|
165
|
-
|
|
165
|
+
}
|
|
166
|
+
if (!isUnion) {
|
|
167
|
+
if (!field.required) {
|
|
168
|
+
if (typeof input[key] === 'object') {
|
|
169
|
+
input[key].__optional = true;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
input[key] = `(${input[key]}) | undefined`;
|
|
173
|
+
}
|
|
174
|
+
if (field.defaultValue === undefined) {
|
|
175
|
+
if (typeof output[key] === 'object') {
|
|
176
|
+
output[key].__optional = true;
|
|
177
|
+
}
|
|
178
|
+
else {
|
|
179
|
+
output[key] = `(${output[key]}) | undefined`;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
166
182
|
}
|
|
167
|
-
|
|
168
|
-
|
|
183
|
+
if (field.array) {
|
|
184
|
+
if (typeof input[key] === 'object') {
|
|
185
|
+
input[key].__array = true;
|
|
186
|
+
}
|
|
187
|
+
else {
|
|
188
|
+
input[key] = `(${input[key]})[]`;
|
|
189
|
+
}
|
|
190
|
+
if (typeof output[key] === 'object') {
|
|
191
|
+
output[key].__array = true;
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
output[key] = `(${output[key]})[]`;
|
|
195
|
+
}
|
|
169
196
|
}
|
|
170
197
|
}
|
|
198
|
+
};
|
|
199
|
+
Object.entries(fields).forEach(([key, field]) => {
|
|
200
|
+
buildField(key, field);
|
|
171
201
|
});
|
|
172
202
|
return { input, output };
|
|
173
203
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { $Module, $Space } from "../../schema";
|
|
2
2
|
import { $BlockOutput, $BlockType } from './block.schema';
|
|
3
|
-
import { MultiMessageTemplateDef } from "../entities/message/template/message_template.builder";
|
|
3
|
+
import { MessageTemplateDef, MultiMessageTemplateDef } from "../entities/message/template/message_template.builder";
|
|
4
4
|
import { $Dependency, BuilderNode } from "../../engine/dependency";
|
|
5
5
|
/**
|
|
6
6
|
* @category Builders
|
|
@@ -19,11 +19,20 @@ export declare abstract class BlockBuilder<Space extends $Space, Module extends
|
|
|
19
19
|
/** Block "human" name */
|
|
20
20
|
as(alias: string): this;
|
|
21
21
|
/**
|
|
22
|
+
* Inline messages. This messages is exposed to the module,
|
|
23
|
+
* with a name prefixed by the block name.
|
|
24
|
+
* @param def A method which takes a field factory as input and outputs a template builder
|
|
25
|
+
* @returns The Builder, for call-chaining
|
|
26
|
+
*/
|
|
27
|
+
protected message<Name extends string, Def extends MessageTemplateDef<Space, Module, Name>>(name: Name, def: Def): unknown;
|
|
28
|
+
/**
|
|
29
|
+
* @deprecated
|
|
22
30
|
* Inline messages. These messages are exposed to the module,
|
|
23
31
|
* with a name prefixed by the block name.
|
|
24
32
|
* @param def A method which takes a field factory as input and outputs a template builder
|
|
25
33
|
* @returns The Builder, for call-chaining
|
|
26
34
|
*/
|
|
35
|
+
/** @deprecated Use `.message` instead. Will be removed on 3.1 */
|
|
27
36
|
protected messages<Def extends MultiMessageTemplateDef<Space, Module>>(def: Def): unknown;
|
|
28
37
|
authn(...providers: string[]): unknown;
|
|
29
38
|
protected _input(...names: string[]): unknown;
|
|
@@ -26,11 +26,37 @@ class BlockBuilder {
|
|
|
26
26
|
}
|
|
27
27
|
// Inline Messages
|
|
28
28
|
/**
|
|
29
|
+
* Inline messages. This messages is exposed to the module,
|
|
30
|
+
* with a name prefixed by the block name.
|
|
31
|
+
* @param def A method which takes a field factory as input and outputs a template builder
|
|
32
|
+
* @returns The Builder, for call-chaining
|
|
33
|
+
*/
|
|
34
|
+
message(name, def) {
|
|
35
|
+
const msgName = `${this.name}${name.length ? ('.' + name) : ''}`;
|
|
36
|
+
this._inputMsgs.push(new dependency_1.$Dependency(this.module, 'message', msgName));
|
|
37
|
+
const builder = new message_builder_1.MessageBuilder(this.module, msgName)
|
|
38
|
+
.template(def);
|
|
39
|
+
this._inlineNodes.push(new dependency_1.BuilderNode({
|
|
40
|
+
module: this.module,
|
|
41
|
+
type: 'message',
|
|
42
|
+
name: msgName,
|
|
43
|
+
builder,
|
|
44
|
+
isInline: true,
|
|
45
|
+
filepath: [], // This is added later by Treeshake.blockInlineNodes()
|
|
46
|
+
dependencies: [] // This is added later by Treeshake.*()
|
|
47
|
+
}));
|
|
48
|
+
const dep = new dependency_1.$Dependency(this.module, 'message', msgName);
|
|
49
|
+
this._inputMsgs.push(dep);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* @deprecated
|
|
29
54
|
* Inline messages. These messages are exposed to the module,
|
|
30
55
|
* with a name prefixed by the block name.
|
|
31
56
|
* @param def A method which takes a field factory as input and outputs a template builder
|
|
32
57
|
* @returns The Builder, for call-chaining
|
|
33
58
|
*/
|
|
59
|
+
/** @deprecated Use `.message` instead. Will be removed on 3.1 */
|
|
34
60
|
messages(def) {
|
|
35
61
|
const factory = new message_template_field_builder_1.MessageTemplateFieldFactory(this.module);
|
|
36
62
|
const schema = def(factory);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { $Module, $Space, ScopedMessage, ScopedMessageName } from "../../../schema";
|
|
2
2
|
import { $Job, $JobAssert, $JobMethod } from './job.schema';
|
|
3
3
|
import { BlockBuilder } from '../block.builder';
|
|
4
|
-
import { MultiMessageTemplateDef } from "../../entities/message/template/message_template.builder";
|
|
4
|
+
import { MessageTemplateDef, MultiMessageTemplateDef } from "../../entities/message/template/message_template.builder";
|
|
5
5
|
import { Overlay } from "../../../engine/util/type";
|
|
6
6
|
import { $MessageInfer } from "../../entities/message/message.infer";
|
|
7
7
|
import { TrxNode } from "../../../engine/transaction/trx_node";
|
|
@@ -33,6 +33,12 @@ export declare class JobBuilder<Space extends $Space, Module extends $Module, Jo
|
|
|
33
33
|
from: keyof Machine["states"] & string;
|
|
34
34
|
to: keyof Machine["states"] & string;
|
|
35
35
|
}>;
|
|
36
|
+
message<Name extends string, Def extends MessageTemplateDef<Space, Module, Name>, FullName extends string = `${Job['name']}${Name extends '' ? '' : '.'}${Name & string}`, Msg extends $Message = $MessageInfer<FullName, ($: any) => ReturnType<Def>>>(name: Name, def: Def): JobBuilder<Space, Overlay<Module, {
|
|
37
|
+
messages: Overlay<Module["messages"], { [K in FullName]: Msg; }>;
|
|
38
|
+
}>, Overlay<Job, {
|
|
39
|
+
"#input": Msg;
|
|
40
|
+
}>, Ctx>;
|
|
41
|
+
/** @deprecated Use `.message` instead. Will be removed on 3.1 */
|
|
36
42
|
messages<Def extends MultiMessageTemplateDef<Space, Module>>(def: Def): JobBuilder<Space, Overlay<Module, {
|
|
37
43
|
messages: Overlay<Module["messages"], { [K in keyof ReturnType<Def> as `${Job["name"]}${K extends "" ? "" : "."}${K & string}`]: $MessageInfer<`${Job["name"]}${K extends "" ? "" : "."}${K & string}`, ($: any) => ReturnType<Def>[K], ReturnType<Def>[K], import("../../entities/message/message.infer").$MessageInputInfer<ReturnType<Def>[K], ReturnType<Def>[K] extends infer T ? { [K_1 in keyof T]: ReturnType<Def>[K][K_1] extends import("../../entities/message/template/message_template_field.builder").MessageTemplateFieldBuilder<any, any, infer I, any, any, infer Opt extends [undefined, undefined], infer Nul extends [null, null]> ? {
|
|
38
44
|
path: `${K_1 & string}${keyof I & string}`;
|
|
@@ -31,6 +31,10 @@ class JobBuilder extends block_builder_1.BlockBuilder {
|
|
|
31
31
|
return this;
|
|
32
32
|
}
|
|
33
33
|
/* [Job] */
|
|
34
|
+
message(name, def) {
|
|
35
|
+
return super.message(name, def);
|
|
36
|
+
}
|
|
37
|
+
/** @deprecated Use `.message` instead. Will be removed on 3.1 */
|
|
34
38
|
messages(def) {
|
|
35
39
|
return super.messages(def);
|
|
36
40
|
}
|
|
@@ -35,21 +35,23 @@ function convertToView(model, name, fields = model.fields, path) {
|
|
|
35
35
|
* @subcategory Entity
|
|
36
36
|
* */
|
|
37
37
|
function convertToMessage(module, model, name, alias, include = [], exclude = []) {
|
|
38
|
+
const convertField = (field) => {
|
|
39
|
+
return new message_template_schema_1.$MessageTemplateField(field.type, field.name, field.alias, field.path, field.path, field.array, field.required, undefined, false, [], {
|
|
40
|
+
enum: field.meta?.enum ? {
|
|
41
|
+
options: field.meta.enum.options,
|
|
42
|
+
dep: field.meta.enum.dep ? new dependency_1.$Dependency(module, 'constants', `${field.meta.enum.dep.module}::${field.meta.enum.dep.name}`) : undefined
|
|
43
|
+
} : undefined
|
|
44
|
+
}, field.children ? convertFields(field.children, include, exclude) : undefined, field.or ? convertField(field.or) : undefined);
|
|
45
|
+
};
|
|
38
46
|
const convertFields = (fields, include = [], exclude = [], root = '') => {
|
|
39
47
|
const msgFields = {};
|
|
40
48
|
for (const f in fields) {
|
|
41
49
|
const field = fields[f];
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|| exclude.includes(path)) {
|
|
50
|
+
if ((include.length && !include.includes(field.path))
|
|
51
|
+
|| exclude.includes(field.path)) {
|
|
45
52
|
continue;
|
|
46
53
|
}
|
|
47
|
-
msgFields[f] =
|
|
48
|
-
enum: field.meta?.enum ? {
|
|
49
|
-
options: field.meta.enum.options,
|
|
50
|
-
dep: field.meta.enum.dep ? new dependency_1.$Dependency(module, 'constants', `${field.meta.enum.dep.module}::${field.meta.enum.dep.name}`) : undefined
|
|
51
|
-
} : undefined
|
|
52
|
-
}, field.children ? convertFields(field.children, include, exclude) : undefined);
|
|
54
|
+
msgFields[f] = convertField(field);
|
|
53
55
|
}
|
|
54
56
|
return msgFields;
|
|
55
57
|
};
|
|
@@ -132,7 +132,7 @@ export declare class BucketModelFieldBuilder<Module extends $Module, DefinedData
|
|
|
132
132
|
*/
|
|
133
133
|
maxLength(val: number | null): void;
|
|
134
134
|
encrypt(key: keyof Module['constants']['values'], algorithm?: string): void;
|
|
135
|
-
static build(builder: BucketModelFieldBuilder<any, any>, name: string,
|
|
135
|
+
static build(builder: BucketModelFieldBuilder<any, any>, name: string, basePath?: string): {
|
|
136
136
|
schema: $BucketModelField;
|
|
137
137
|
hasFile: boolean;
|
|
138
138
|
hasEncrypted: boolean;
|
|
@@ -129,11 +129,15 @@ class BucketModelFieldBuilder {
|
|
|
129
129
|
}
|
|
130
130
|
get array() {
|
|
131
131
|
this._array = true;
|
|
132
|
+
if (this._or) {
|
|
133
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-expressions
|
|
134
|
+
this._or.array;
|
|
135
|
+
}
|
|
132
136
|
return this;
|
|
133
137
|
}
|
|
134
138
|
or(def) {
|
|
135
|
-
|
|
136
|
-
return
|
|
139
|
+
def._or = this;
|
|
140
|
+
return def;
|
|
137
141
|
}
|
|
138
142
|
/**
|
|
139
143
|
* This can be applied to `string` and `enum` fields,
|
|
@@ -153,18 +157,17 @@ class BucketModelFieldBuilder {
|
|
|
153
157
|
};
|
|
154
158
|
}
|
|
155
159
|
// Build
|
|
156
|
-
static build(builder, name,
|
|
157
|
-
path
|
|
160
|
+
static build(builder, name, basePath = '') {
|
|
161
|
+
const path = basePath + name;
|
|
162
|
+
const itemPath = builder._array ? path + '.#.' : path + '.';
|
|
158
163
|
const children = builder.children
|
|
159
|
-
? BucketModelFieldBuilder.buildChildren(builder.module, builder.children,
|
|
160
|
-
? path + '.#.'
|
|
161
|
-
: path + '.')
|
|
164
|
+
? BucketModelFieldBuilder.buildChildren(builder.module, builder.children, itemPath)
|
|
162
165
|
: undefined;
|
|
163
166
|
const defaults = builder._defaultValue && builder.children
|
|
164
167
|
? Object.assign({}, builder._defaultValue, children?.defaults)
|
|
165
168
|
: builder._defaultValue;
|
|
166
169
|
const or = builder._or
|
|
167
|
-
? this.build(builder._or, name)
|
|
170
|
+
? this.build(builder._or, name, basePath)
|
|
168
171
|
: undefined;
|
|
169
172
|
const schema = new bucket_model_schema_1.$BucketModelField(name, path, builder.type, builder.alias || name, builder._array, builder._required, builder.meta, defaults, children?.schema, or?.schema, builder.crypto);
|
|
170
173
|
const hasFile = builder.type === 'file'
|
|
@@ -95,7 +95,6 @@ class BucketView {
|
|
|
95
95
|
}
|
|
96
96
|
parsedObj[k] = await doParse(prop.children || {}, index);
|
|
97
97
|
}
|
|
98
|
-
parsedObj['$v'] = this.schema.name;
|
|
99
98
|
return parsedObj;
|
|
100
99
|
};
|
|
101
100
|
const parseModelProp = async (obj, prop, index, key) => {
|
|
@@ -129,7 +128,8 @@ class BucketView {
|
|
|
129
128
|
}
|
|
130
129
|
return rawValue;
|
|
131
130
|
};
|
|
132
|
-
const parsedObj = await doParse(this.schema.fields
|
|
131
|
+
const parsedObj = await doParse(this.schema.fields);
|
|
132
|
+
parsedObj['$v'] = this.schema.name;
|
|
133
133
|
return {
|
|
134
134
|
id: raw.id,
|
|
135
135
|
...parsedObj
|
|
@@ -12,9 +12,5 @@ export declare class MessageParser<$ extends $Message> {
|
|
|
12
12
|
static parseWithTrxModule(trx: AnyTrxNode, raw: RawMessageInput<any, any>, sigKey?: string): Promise<any>;
|
|
13
13
|
parse(trx: AnyTrxNode, raw: $['#raw'], sigKey?: string): Promise<Message<$>>;
|
|
14
14
|
private sanitize;
|
|
15
|
-
/**
|
|
16
|
-
* Empty values: `{}`, `[]`, `''`, `null`, `undefined`
|
|
17
|
-
*/
|
|
18
|
-
static isEmpty(value: any): boolean;
|
|
19
15
|
}
|
|
20
16
|
export type AnyMessageParser = MessageParser<$Message>;
|
|
@@ -33,80 +33,64 @@ class MessageParser {
|
|
|
33
33
|
// parsing ids etc.
|
|
34
34
|
async parse(trx, raw, sigKey) {
|
|
35
35
|
log_1.Log.debug('trx', trx.globalId, `${(0, log_1.scopeTag)('message', this.schema.name)} Parse${sigKey ? ' (signed)' : ''}`, raw);
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
for (const suffix in parsedField) {
|
|
45
|
-
parsedObj[field.name + suffix] = parsedField[suffix];
|
|
36
|
+
const applyFieldRules = async (field, parent, value, path) => {
|
|
37
|
+
// Apply rules to the field
|
|
38
|
+
// If field is an array, the value passed to the rule is the array itself
|
|
39
|
+
for (const r in field.rules) {
|
|
40
|
+
const rule = field.rules[r];
|
|
41
|
+
const res = await rule({ field, value, path: path.join('.'), msg: parsed });
|
|
42
|
+
if (typeof res === 'object') {
|
|
43
|
+
parent[path.at(-1)] = res.set;
|
|
46
44
|
}
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
};
|
|
50
|
-
const parseField = async (trx, field, value) => {
|
|
51
|
-
// 1. Sanitize input
|
|
52
|
-
this.sanitize(value);
|
|
53
|
-
// 2. Check for required fields
|
|
54
|
-
let parsedValue;
|
|
55
|
-
if (MessageParser.isEmpty(value)) {
|
|
56
|
-
if (field.required) {
|
|
57
|
-
const pathWithSuffix = field.type === 'id' ? `${field.path}_id` : field.path;
|
|
58
|
-
throw error_1.NesoiError.Message.FieldIsRequired({ field: field.alias, path: pathWithSuffix, value });
|
|
45
|
+
else if (res !== true) {
|
|
46
|
+
throw error_1.NesoiError.Message.RuleFailed({ rule, error: res });
|
|
59
47
|
}
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
}
|
|
49
|
+
if (!value)
|
|
50
|
+
return;
|
|
51
|
+
if (field.type === 'obj') {
|
|
52
|
+
if (field.array) {
|
|
53
|
+
for (let i = 0; i < value?.length; i++) {
|
|
54
|
+
await applyRules(field.children, value[i] || {}, [...path, i.toString()]);
|
|
55
|
+
}
|
|
62
56
|
}
|
|
63
57
|
else {
|
|
64
|
-
|
|
58
|
+
await applyRules(field.children, value || {}, path);
|
|
65
59
|
}
|
|
66
60
|
}
|
|
67
|
-
else {
|
|
61
|
+
else if (field.type === 'dict') {
|
|
68
62
|
if (field.array) {
|
|
69
|
-
|
|
70
|
-
|
|
63
|
+
for (let i = 0; i < value?.length; i++) {
|
|
64
|
+
for (const k in value[i]) {
|
|
65
|
+
await applyFieldRules(field.children.__dict, value[i], value[i][k], [...path, i.toString(), k]);
|
|
66
|
+
}
|
|
71
67
|
}
|
|
72
68
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
catch (e) {
|
|
78
|
-
// If this error was not triggered by a nested field,
|
|
79
|
-
// and we have another option, we try that option.
|
|
80
|
-
if (field.or && !e.__msg_deep_error) {
|
|
81
|
-
return parseField(trx, field.or, value);
|
|
69
|
+
else {
|
|
70
|
+
for (const k in value) {
|
|
71
|
+
await applyFieldRules(field.children.__dict, value, value[k], [...path, k]);
|
|
82
72
|
}
|
|
83
|
-
e.__msg_deep_error = true;
|
|
84
|
-
throw e;
|
|
85
73
|
}
|
|
86
74
|
}
|
|
87
|
-
return parsedValue;
|
|
88
75
|
};
|
|
89
|
-
const applyRules = async (fields,
|
|
76
|
+
const applyRules = async (fields, parent, path = []) => {
|
|
90
77
|
for (const f in fields) {
|
|
91
78
|
const field = fields[f];
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
const res = await rule({ field, value, msg: parsed });
|
|
96
|
-
if (typeof res === 'object') {
|
|
97
|
-
parsedValue ?? (parsedValue = {});
|
|
98
|
-
parsedValue[field.name] = res.set;
|
|
99
|
-
}
|
|
100
|
-
else if (res !== true) {
|
|
101
|
-
throw error_1.NesoiError.Message.RuleFailed({ rule, error: res });
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
if (field.children) {
|
|
105
|
-
await applyRules(field.children, parsed, parsedValue?.[field.name]);
|
|
106
|
-
}
|
|
79
|
+
const value = parent[field.name];
|
|
80
|
+
const _path = [...path, field.name];
|
|
81
|
+
await applyFieldRules(field, parent, value, _path);
|
|
107
82
|
}
|
|
108
83
|
};
|
|
109
|
-
const
|
|
84
|
+
const fields = this.schema.template.fields;
|
|
85
|
+
const parsed = {};
|
|
86
|
+
for (const k in fields) {
|
|
87
|
+
const field = fields[k];
|
|
88
|
+
const key_raw = field.path_raw.split('.')[0];
|
|
89
|
+
const key_parsed = field.path_parsed.split('.')[0];
|
|
90
|
+
const value = raw[key_raw];
|
|
91
|
+
this.sanitize(value);
|
|
92
|
+
parsed[key_parsed] = await (0, message_template_parser_1.MessageTemplateFieldParser)(raw, trx, field, value);
|
|
93
|
+
}
|
|
110
94
|
await applyRules(this.schema.template.fields, parsed);
|
|
111
95
|
return message_1.Message.new(this.schema.name, parsed, sigKey);
|
|
112
96
|
}
|
|
@@ -117,23 +101,5 @@ class MessageParser {
|
|
|
117
101
|
});
|
|
118
102
|
}
|
|
119
103
|
}
|
|
120
|
-
/**
|
|
121
|
-
* Empty values: `{}`, `[]`, `''`, `null`, `undefined`
|
|
122
|
-
*/
|
|
123
|
-
static isEmpty(value) {
|
|
124
|
-
if (value === null || value === undefined) {
|
|
125
|
-
return true;
|
|
126
|
-
}
|
|
127
|
-
if (Array.isArray(value)) {
|
|
128
|
-
return value.length === 0;
|
|
129
|
-
}
|
|
130
|
-
if (typeof value === 'object') {
|
|
131
|
-
return Object.keys(value).length === 0;
|
|
132
|
-
}
|
|
133
|
-
if (typeof value === 'string') {
|
|
134
|
-
return value.length === 0;
|
|
135
|
-
}
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
104
|
}
|
|
139
105
|
exports.MessageParser = MessageParser;
|
|
@@ -3,6 +3,7 @@ import { $BucketModelFieldType } from "../../bucket/model/bucket_model.schema";
|
|
|
3
3
|
import { $Dependency } from "../../../../engine/dependency";
|
|
4
4
|
export type $MessageTemplateRule = (def: {
|
|
5
5
|
field: $MessageTemplateField;
|
|
6
|
+
path: string;
|
|
6
7
|
value: any;
|
|
7
8
|
msg: $Message['#raw'];
|
|
8
9
|
}) => {
|
|
@@ -36,10 +37,19 @@ export type $MessageTemplateFieldType = $BucketModelFieldType | 'string_or_numbe
|
|
|
36
37
|
* @subcategory Entity
|
|
37
38
|
* */
|
|
38
39
|
export declare class $MessageTemplateField {
|
|
40
|
+
/** A string representing the type of data carried by the field */
|
|
39
41
|
type: $MessageTemplateFieldType;
|
|
42
|
+
/**
|
|
43
|
+
* - A machine name for the field, unique inside it's parent (either another field or a message).
|
|
44
|
+
* - Matches the relative path for writing the field value on the parent parsed object (key_parsed).
|
|
45
|
+
*/
|
|
40
46
|
name: string;
|
|
47
|
+
/** A human name for the field */
|
|
41
48
|
alias: string;
|
|
42
|
-
path
|
|
49
|
+
/** The absolute path for reading the field value on the raw object */
|
|
50
|
+
path_raw: string;
|
|
51
|
+
/** The absolute path for writing the field value on the parsed object */
|
|
52
|
+
path_parsed: string;
|
|
43
53
|
array: boolean;
|
|
44
54
|
required: boolean;
|
|
45
55
|
defaultValue: any;
|
|
@@ -51,7 +61,20 @@ export declare class $MessageTemplateField {
|
|
|
51
61
|
'#raw': unknown;
|
|
52
62
|
'#parsed': unknown;
|
|
53
63
|
$t: string;
|
|
54
|
-
constructor(
|
|
64
|
+
constructor(
|
|
65
|
+
/** A string representing the type of data carried by the field */
|
|
66
|
+
type: $MessageTemplateFieldType,
|
|
67
|
+
/**
|
|
68
|
+
* - A machine name for the field, unique inside it's parent (either another field or a message).
|
|
69
|
+
* - Matches the relative path for writing the field value on the parent parsed object (key_parsed).
|
|
70
|
+
*/
|
|
71
|
+
name: string,
|
|
72
|
+
/** A human name for the field */
|
|
73
|
+
alias: string,
|
|
74
|
+
/** The absolute path for reading the field value on the raw object */
|
|
75
|
+
path_raw: string,
|
|
76
|
+
/** The absolute path for writing the field value on the parsed object */
|
|
77
|
+
path_parsed: string, array: boolean, required: boolean, defaultValue: any, nullable: boolean, rules: $MessageTemplateRule[], meta: $MessageTemplateFieldMeta, children?: $MessageTemplateFields | undefined, or?: $MessageTemplateField | undefined);
|
|
55
78
|
}
|
|
56
79
|
export type $MessageTemplateFields = {
|
|
57
80
|
[x: string]: $MessageTemplateField;
|
|
@@ -6,11 +6,25 @@ exports.$MessageTemplate = exports.$MessageTemplateField = void 0;
|
|
|
6
6
|
* @subcategory Entity
|
|
7
7
|
* */
|
|
8
8
|
class $MessageTemplateField {
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(
|
|
10
|
+
/** A string representing the type of data carried by the field */
|
|
11
|
+
type,
|
|
12
|
+
/**
|
|
13
|
+
* - A machine name for the field, unique inside it's parent (either another field or a message).
|
|
14
|
+
* - Matches the relative path for writing the field value on the parent parsed object (key_parsed).
|
|
15
|
+
*/
|
|
16
|
+
name,
|
|
17
|
+
/** A human name for the field */
|
|
18
|
+
alias,
|
|
19
|
+
/** The absolute path for reading the field value on the raw object */
|
|
20
|
+
path_raw,
|
|
21
|
+
/** The absolute path for writing the field value on the parsed object */
|
|
22
|
+
path_parsed, array, required, defaultValue, nullable, rules, meta, children, or) {
|
|
10
23
|
this.type = type;
|
|
11
24
|
this.name = name;
|
|
12
25
|
this.alias = alias;
|
|
13
|
-
this.
|
|
26
|
+
this.path_raw = path_raw;
|
|
27
|
+
this.path_parsed = path_parsed;
|
|
14
28
|
this.array = array;
|
|
15
29
|
this.required = required;
|
|
16
30
|
this.defaultValue = defaultValue;
|