nesoi 3.0.20 → 3.0.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.
@@ -36,7 +36,7 @@ function convertToView(model, name, fields = model.fields, path) {
36
36
  * */
37
37
  function convertToMessage(module, model, name, alias, include = [], exclude = []) {
38
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, [], {
39
+ return new message_template_schema_1.$MessageTemplateField(field.type, field.name, field.alias, field.alias, field.path, field.path, field.array, field.required, undefined, false, [], [], {
40
40
  enum: field.meta?.enum ? {
41
41
  options: field.meta.enum.options,
42
42
  dep: field.meta.enum.dep ? new dependency_1.$Dependency(module, 'constants', `${field.meta.enum.dep.module}::${field.meta.enum.dep.name}`) : undefined
@@ -21,8 +21,8 @@ class MessageBuilder {
21
21
  return this;
22
22
  }
23
23
  template($) {
24
- const fieldBuilder = new message_template_field_builder_1.MessageTemplateFieldFactory(this.module);
25
- const fields = $(fieldBuilder);
24
+ const factory = new message_template_field_builder_1.MessageTemplateFieldFactory(this.module);
25
+ const fields = $(factory);
26
26
  this._template.fields(fields);
27
27
  return this;
28
28
  }
@@ -11,6 +11,5 @@ export declare class MessageParser<$ extends $Message> {
11
11
  constructor(schema: $);
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
- private sanitize;
15
14
  }
16
15
  export type AnyMessageParser = MessageParser<$Message>;
@@ -28,78 +28,11 @@ class MessageParser {
28
28
  }
29
29
  return parser.parse(trx, raw, sigKey);
30
30
  }
31
- // TODO: OPTIMIZATION
32
- // Parse everything that's static first, then move on to
33
- // parsing ids etc.
34
31
  async parse(trx, raw, sigKey) {
35
32
  log_1.Log.debug('trx', trx.globalId, `${(0, log_1.scopeTag)('message', this.schema.name)} Parse${sigKey ? ' (signed)' : ''}`, raw);
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;
44
- }
45
- else if (res !== true) {
46
- throw error_1.NesoiError.Message.RuleFailed({ rule, error: res });
47
- }
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
- }
56
- }
57
- else {
58
- await applyRules(field.children, value || {}, path);
59
- }
60
- }
61
- else if (field.type === 'dict') {
62
- if (field.array) {
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
- }
67
- }
68
- }
69
- else {
70
- for (const k in value) {
71
- await applyFieldRules(field.children.__dict, value, value[k], [...path, k]);
72
- }
73
- }
74
- }
75
- };
76
- const applyRules = async (fields, parent, path = []) => {
77
- for (const f in fields) {
78
- const field = fields[f];
79
- const value = parent[field.name];
80
- const _path = [...path, field.name];
81
- await applyFieldRules(field, parent, value, _path);
82
- }
83
- };
84
33
  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
- }
94
- await applyRules(this.schema.template.fields, parsed);
34
+ const parsed = await (0, message_template_parser_1.MessageTemplateFieldParser)(trx, fields, raw);
95
35
  return message_1.Message.new(this.schema.name, parsed, sigKey);
96
36
  }
97
- sanitize(value) {
98
- if (typeof value === 'function') {
99
- throw error_1.NesoiError.Message.UnsanitaryValue({
100
- details: 'Functions not allowed as message inputs.'
101
- });
102
- }
103
- }
104
37
  }
105
38
  exports.MessageParser = MessageParser;
@@ -6,6 +6,7 @@ export type $MessageTemplateRule = (def: {
6
6
  path: string;
7
7
  value: any;
8
8
  msg: $Message['#raw'];
9
+ inject: Record<string, any>;
9
10
  }) => {
10
11
  set: any;
11
12
  } | true | string | Promise<{
@@ -46,6 +47,10 @@ export declare class $MessageTemplateField {
46
47
  name: string;
47
48
  /** A human name for the field */
48
49
  alias: string;
50
+ /** A human name for the field union, assigned before the type.
51
+ * This is only relevant when using .obj.or, to allow for different
52
+ * aliases for the union and the root object */
53
+ preAlias: string;
49
54
  /** The absolute path for reading the field value on the raw object */
50
55
  path_raw: string;
51
56
  /** The absolute path for writing the field value on the parsed object */
@@ -55,6 +60,7 @@ export declare class $MessageTemplateField {
55
60
  defaultValue: any;
56
61
  nullable: boolean;
57
62
  rules: $MessageTemplateRule[];
63
+ arrayRules: $MessageTemplateRule[];
58
64
  meta: $MessageTemplateFieldMeta;
59
65
  children?: $MessageTemplateFields | undefined;
60
66
  or?: $MessageTemplateField | undefined;
@@ -71,10 +77,14 @@ export declare class $MessageTemplateField {
71
77
  name: string,
72
78
  /** A human name for the field */
73
79
  alias: string,
80
+ /** A human name for the field union, assigned before the type.
81
+ * This is only relevant when using .obj.or, to allow for different
82
+ * aliases for the union and the root object */
83
+ preAlias: string,
74
84
  /** The absolute path for reading the field value on the raw object */
75
85
  path_raw: string,
76
86
  /** 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);
87
+ path_parsed: string, array: boolean, required: boolean, defaultValue: any, nullable: boolean, rules: $MessageTemplateRule[], arrayRules: $MessageTemplateRule[], meta: $MessageTemplateFieldMeta, children?: $MessageTemplateFields | undefined, or?: $MessageTemplateField | undefined);
78
88
  }
79
89
  export type $MessageTemplateFields = {
80
90
  [x: string]: $MessageTemplateField;
@@ -16,13 +16,18 @@ class $MessageTemplateField {
16
16
  name,
17
17
  /** A human name for the field */
18
18
  alias,
19
+ /** A human name for the field union, assigned before the type.
20
+ * This is only relevant when using .obj.or, to allow for different
21
+ * aliases for the union and the root object */
22
+ preAlias,
19
23
  /** The absolute path for reading the field value on the raw object */
20
24
  path_raw,
21
25
  /** The absolute path for writing the field value on the parsed object */
22
- path_parsed, array, required, defaultValue, nullable, rules, meta, children, or) {
26
+ path_parsed, array, required, defaultValue, nullable, rules, arrayRules, meta, children, or) {
23
27
  this.type = type;
24
28
  this.name = name;
25
29
  this.alias = alias;
30
+ this.preAlias = preAlias;
26
31
  this.path_raw = path_raw;
27
32
  this.path_parsed = path_parsed;
28
33
  this.array = array;
@@ -30,6 +35,7 @@ class $MessageTemplateField {
30
35
  this.defaultValue = defaultValue;
31
36
  this.nullable = nullable;
32
37
  this.rules = rules;
38
+ this.arrayRules = arrayRules;
33
39
  this.meta = meta;
34
40
  this.children = children;
35
41
  this.or = or;
@@ -18,6 +18,13 @@ export declare class MessageTemplateFieldFactory<Space extends $Space, Module ex
18
18
  private module;
19
19
  private alias?;
20
20
  constructor(module: string);
21
+ /**
22
+ * Specifies an alias for the field.
23
+ * - If this field is a union (.or), this alias is used when
24
+ * referring to the union and it's first option.
25
+ * - You can specify a different alias for the first options
26
+ * by also using the .as() after the type
27
+ */
21
28
  as(alias: string): Omit<typeof this, "as">;
22
29
  get any(): MessageTemplateFieldBuilder<Module, Message, {
23
30
  '': any;
@@ -227,7 +234,9 @@ Nullable extends [null | never, null | never] = [never, never]> {
227
234
  private _defaultValue?;
228
235
  private _nullable;
229
236
  private _rules;
237
+ private _arrayRules;
230
238
  private _or?;
239
+ private preAlias?;
231
240
  constructor(type: $MessageTemplateFieldType, value: $MessageTemplateFieldMeta, alias?: string | undefined, children?: Children | undefined);
232
241
  as(alias: string): this;
233
242
  get optional(): MessageTemplateFieldBuilder<Module, Message, DefinedInput, DefinedOutput, Children, [undefined, undefined], Nullable>;
@@ -245,8 +254,10 @@ export type MessageTemplateFieldBuilders = {
245
254
  export type AnyMessageTemplateFieldBuilder = MessageTemplateFieldBuilder<any, any, any, any, any>;
246
255
  export type MessageTemplateRuleDef<I, Msg> = (def: {
247
256
  field: $MessageTemplateField;
257
+ path: string;
248
258
  value: I;
249
259
  msg: Msg;
260
+ inject: Record<string, any>;
250
261
  }) => {
251
262
  set: I;
252
263
  } | true | string | Promise<{
@@ -12,9 +12,17 @@ class MessageTemplateFieldFactory {
12
12
  constructor(module) {
13
13
  this.module = module;
14
14
  }
15
+ /**
16
+ * Specifies an alias for the field.
17
+ * - If this field is a union (.or), this alias is used when
18
+ * referring to the union and it's first option.
19
+ * - You can specify a different alias for the first options
20
+ * by also using the .as() after the type
21
+ */
15
22
  as(alias) {
16
- this.alias = alias;
17
- return this;
23
+ const chain = new MessageTemplateFieldFactory(this.module);
24
+ chain.alias = alias;
25
+ return chain;
18
26
  }
19
27
  get any() {
20
28
  return new MessageTemplateFieldBuilder('unknown', {}, this.alias);
@@ -106,6 +114,8 @@ class MessageTemplateFieldBuilder {
106
114
  this._defaultValue = undefined;
107
115
  this._nullable = true;
108
116
  this._rules = [];
117
+ this._arrayRules = [];
118
+ this.preAlias = alias;
109
119
  }
110
120
  as(alias) {
111
121
  this.alias = alias;
@@ -136,7 +146,12 @@ class MessageTemplateFieldBuilder {
136
146
  return this;
137
147
  }
138
148
  rule(rule) {
139
- this._rules.push(rule);
149
+ if (this._array) {
150
+ this._arrayRules.push(rule);
151
+ }
152
+ else {
153
+ this._rules.push(rule);
154
+ }
140
155
  return this;
141
156
  }
142
157
  get array() {
@@ -149,11 +164,12 @@ class MessageTemplateFieldBuilder {
149
164
  }
150
165
  or(def) {
151
166
  this._or = def;
167
+ this._or.preAlias = this.preAlias;
152
168
  this._or._array = this._array;
153
169
  this._or._defaultValue = this._defaultValue;
154
170
  this._or._nullable = this._nullable;
155
171
  this._or._required = this._required;
156
- this._or._rules = this._rules;
172
+ this._or._arrayRules = this._arrayRules;
157
173
  return this;
158
174
  }
159
175
  // Build
@@ -171,7 +187,7 @@ class MessageTemplateFieldBuilder {
171
187
  const bucket = tree.getSchema(builder.value.id.bucket);
172
188
  builder.value.id.type = bucket.model.fields.id.type;
173
189
  }
174
- return new message_template_schema_1.$MessageTemplateField(builder.type, name, builder.alias || name, pathRaw, pathParsed, builder._array, builder._required, builder._defaultValue, builder._nullable, builder._rules, builder.value, builder.children ? MessageTemplateFieldBuilder.buildChildren(builder.children, tree, module, childrenBasePathRaw, childrenBasePathParsed) : undefined, or);
190
+ return new message_template_schema_1.$MessageTemplateField(builder.type, name, builder.alias || name, builder.preAlias || name, pathRaw, pathParsed, builder._array, builder._required, builder._defaultValue, builder._nullable, builder._rules, builder._arrayRules, builder.value, builder.children ? MessageTemplateFieldBuilder.buildChildren(builder.children, tree, module, childrenBasePathRaw, childrenBasePathParsed) : undefined, or);
175
191
  }
176
192
  static buildChildren(fields, tree, module, basePathRaw = '', basePathParsed = '') {
177
193
  const schema = {};
@@ -1,6 +1,6 @@
1
- import { $MessageTemplateField } from './message_template.schema';
1
+ import { $MessageTemplateFields } from './message_template.schema';
2
2
  import { AnyTrxNode } from "../../../../engine/transaction/trx_node";
3
- export declare function MessageTemplateFieldParser(raw: Record<string, any>, trx: AnyTrxNode, field: $MessageTemplateField, value: any): Promise<any>;
3
+ export declare function MessageTemplateFieldParser(trx: AnyTrxNode, fields: $MessageTemplateFields, raw: Record<string, any>): Promise<Record<string, any>>;
4
4
  /**
5
5
  * Empty values: `{}`, `[]`, `''`, `null`, `undefined`
6
6
  */
@@ -4,19 +4,34 @@ exports.MessageTemplateFieldParser = MessageTemplateFieldParser;
4
4
  exports.isEmpty = isEmpty;
5
5
  const parse_1 = require("../../../../engine/util/parse");
6
6
  const error_1 = require("../../../../engine/data/error");
7
- async function MessageTemplateFieldParser(raw, trx, field, value) {
8
- return parseFieldValue(trx, field, raw, value, 0);
7
+ // TODO: OPTIMIZATION
8
+ // Parse everything that's static first, then move on to
9
+ // parsing ids etc.
10
+ async function MessageTemplateFieldParser(trx, fields, raw) {
11
+ const parsed = {};
12
+ const inject = {};
13
+ for (const k in fields) {
14
+ const field = fields[k];
15
+ const key_raw = field.path_raw.split('.')[0];
16
+ const key_parsed = field.path_parsed.split('.')[0];
17
+ const value = raw[key_raw];
18
+ parsed[key_parsed] = await parseFieldValue(trx, field, [field.name], raw, value, inject);
19
+ }
20
+ Object.assign(parsed, inject);
21
+ return parsed;
9
22
  }
10
- // Attempt to parse a field value
11
- // - If field is an array, this method is run for each value, sequentially
12
- // - If not, it's run for the original value, once
13
- //
14
- // - This method stacks with the .or options
15
- //
16
- async function parseFieldValue(trx, field, raw, value, path_idx) {
23
+ /**
24
+ * [Parser Step 1]
25
+ *
26
+ * - Check for empty fields ({}, [], '', null, undefined)
27
+ * - If it's array, run step 2 for each value (with this field and path+i)
28
+ * - If not, run step 2 for the original value (with this field and path)
29
+ */
30
+ async function parseFieldValue(trx, field, path, raw, value, inject) {
31
+ sanitize(field, path, value);
17
32
  if (isEmpty(value)) {
18
33
  if (field.required) {
19
- throw error_1.NesoiError.Message.FieldIsRequired({ field: field.alias, path: field.path_raw, value });
34
+ throw error_1.NesoiError.Message.FieldIsRequired({ alias: field.alias, path: path.join('.'), value });
20
35
  }
21
36
  else if (field.defaultValue !== undefined) {
22
37
  return field.defaultValue;
@@ -25,95 +40,132 @@ async function parseFieldValue(trx, field, raw, value, path_idx) {
25
40
  return undefined;
26
41
  }
27
42
  }
43
+ let output;
28
44
  if (field.array) {
29
45
  if (!Array.isArray(value)) {
30
- throw error_1.NesoiError.Message.InvalidFieldType({ field: field.alias, path: field.path_raw, value, type: 'list' });
31
- }
32
- if (field.required && !value.length) {
33
- throw error_1.NesoiError.Message.FieldIsRequired({ field: field.alias, path: field.path_raw, value });
46
+ throw error_1.NesoiError.Message.InvalidFieldType({ alias: field.alias, path: path.join('.'), value, type: 'list' });
34
47
  }
35
- const parsedValue = [];
48
+ output = [];
36
49
  for (let i = 0; i < value.length; i++) {
37
50
  const v = value[i];
38
- const parsed = await _attemptUnion(trx, field, raw, v, path_idx + 1);
39
- parsedValue.push(parsed);
51
+ const parsedValue = await _attemptUnion(trx, field, [...path, i.toString()], raw, v, inject);
52
+ output.push(parsedValue);
40
53
  }
41
- return parsedValue;
54
+ output = await applyFieldRules('array', field, path, raw, output, inject);
42
55
  }
43
- return _attemptUnion(trx, field, raw, value, path_idx);
56
+ else {
57
+ output = await _attemptUnion(trx, field, path, raw, value, inject);
58
+ }
59
+ return output;
44
60
  }
45
- async function _attemptUnion(trx, field, raw, value, path_idx, unionErrors = []) {
61
+ /**
62
+ * [Parser Step 2]
63
+ *
64
+ * - Attempt to run parse method (step 3) for field.
65
+ * - If it fails, attempt other union options (step 2) (if available), with same path
66
+ * - If it works, apply field rules.
67
+ */
68
+ async function _attemptUnion(trx, field, path, raw, value, inject, unionErrors = []) {
69
+ let output = undefined;
46
70
  try {
47
- return await _runParseMethod(trx, field, raw, value, path_idx);
71
+ output = await _runParseMethod(trx, field, path, raw, value, inject);
48
72
  }
49
73
  catch (e) {
74
+ const ue = [
75
+ ...unionErrors,
76
+ {
77
+ option: field.alias,
78
+ name: e.name,
79
+ status: e.status,
80
+ message: e.message,
81
+ data: e.data,
82
+ }
83
+ ];
50
84
  // If failed and there's a second option, atempt it
51
85
  if (field.or) {
52
- return await _attemptUnion(trx, field.or, raw, value, path_idx, [...unionErrors, e]);
86
+ return await _attemptUnion(trx, field.or, path, raw, value, inject, ue);
53
87
  }
54
88
  // If this error was not the first attempt, and we have no other option
55
89
  // we throw a specific error
56
90
  // This avoid confusion for the client when parsing unions
57
91
  if (unionErrors.length) {
58
- throw error_1.NesoiError.Message.ValueDoesntMatchUnion({ field: field.alias, path: field.path_raw, value, unionErrors: [...unionErrors, e] });
92
+ throw error_1.NesoiError.Message.ValueDoesntMatchUnion({ alias: field.preAlias, path: path.join('.'), value, unionErrors: ue });
59
93
  }
60
94
  throw e;
61
95
  }
96
+ output = await applyFieldRules('item', field, path, raw, output, inject);
97
+ return output;
62
98
  }
63
- async function _runParseMethod(trx, field, raw, value, path_idx) {
99
+ /**
100
+ * [Parser Step 3]
101
+ *
102
+ * - Run a specific parsing method based on the field type
103
+ */
104
+ async function _runParseMethod(trx, field, path, raw, value, inject) {
64
105
  switch (field.type) {
65
106
  case 'obj':
66
107
  case 'dict':
67
- return await parseParentField(trx, field, raw, value, path_idx);
108
+ return await parseParentField(trx, field, path, raw, value, inject);
68
109
  case 'unknown':
69
110
  return value;
70
111
  case 'boolean':
71
- return (0, parse_1.parseBoolean)(field, value);
112
+ return (0, parse_1.parseBoolean)(field, path, value);
72
113
  case 'date':
73
- return (0, parse_1.parseDate)(field, value);
114
+ return (0, parse_1.parseDate)(field, path, value);
74
115
  case 'datetime':
75
- return (0, parse_1.parseDatetime)(field, value);
116
+ return (0, parse_1.parseDatetime)(field, path, value);
76
117
  case 'duration':
77
- return (0, parse_1.parseDuration)(field, value);
118
+ return (0, parse_1.parseDuration)(field, path, value);
78
119
  case 'decimal':
79
- return (0, parse_1.parseDecimal)(field, value);
120
+ return (0, parse_1.parseDecimal)(field, path, value);
80
121
  case 'enum':
81
- return (0, parse_1.parseEnum)(raw, field, value, field.meta.enum.options, trx);
122
+ return (0, parse_1.parseEnum)(raw, field, path, value, field.meta.enum.options, trx);
82
123
  case 'file':
83
- return (0, parse_1.parseFile)(field, value, field.meta.file);
124
+ return (0, parse_1.parseFile)(field, path, value, field.meta.file);
84
125
  case 'float':
85
- return (0, parse_1.parseFloat_)(field, value);
126
+ return (0, parse_1.parseFloat_)(field, path, value);
86
127
  case 'int':
87
- return (0, parse_1.parseInt_)(field, value);
128
+ return (0, parse_1.parseInt_)(field, path, value);
88
129
  case 'string':
89
- return (0, parse_1.parseString)(field, value);
130
+ return (0, parse_1.parseString)(field, path, value);
90
131
  case 'string_or_number':
91
- return (0, parse_1.parseStringOrNumber)(field, value);
132
+ return (0, parse_1.parseStringOrNumber)(field, path, value);
92
133
  case 'id':
93
- return await parseIdField(trx, field, value);
134
+ return await parseIdField(trx, field, path, value);
94
135
  }
95
136
  throw error_1.NesoiError.Builder.Message.UnknownTemplateFieldType(field.type);
96
137
  }
97
- async function parseParentField(trx, field, raw, value, path_idx) {
138
+ /**
139
+ * [Parser Step 3-b]: 'obj' or 'dict'
140
+ *
141
+ * - The parser methods only return a tuple of field and value, to be parsed again by (step 1)
142
+ * - When calling step 1, the child property name is appended to the path
143
+ */
144
+ async function parseParentField(trx, field, path, raw, value, inject) {
98
145
  let children;
99
146
  if (field.type === 'obj') {
100
- children = (0, parse_1.parseObj)(field, value, path_idx);
147
+ children = (0, parse_1.parseObj)(field, path, value);
101
148
  }
102
149
  else {
103
- children = (0, parse_1.parseDict)(field, value);
150
+ children = (0, parse_1.parseDict)(field, path, value);
104
151
  }
105
- const parsed = {};
152
+ const parsedParent = {};
106
153
  for (const key in children) {
107
154
  const child = children[key];
108
- parsed[key] = await parseFieldValue(trx, child.field, raw, child.value, path_idx + 1);
155
+ parsedParent[key] = await parseFieldValue(trx, child.field, [...path, key], raw, child.value, inject);
109
156
  }
110
- return parsed;
157
+ return parsedParent;
111
158
  }
112
- async function parseIdField(trx, field, value) {
159
+ /**
160
+ * [Parser Step 3-b]: 'id'
161
+ *
162
+ * - Gathers the data for parsing a id
163
+ */
164
+ async function parseIdField(trx, field, path, value) {
113
165
  const bucket = field.meta.id.bucket;
114
166
  const type = field.meta.id.type;
115
167
  const view = field.meta.id.view;
116
- const parsed = await (0, parse_1.parseId)(field, value, trx, bucket.refName, type, view);
168
+ const parsed = await (0, parse_1.parseId)(field, path, value, trx, bucket.refName, type, view);
117
169
  if (field.array) {
118
170
  return parsed.map((p) => p.obj);
119
171
  }
@@ -121,6 +173,13 @@ async function parseIdField(trx, field, value) {
121
173
  return parsed.obj;
122
174
  }
123
175
  }
176
+ function sanitize(field, path, value) {
177
+ if (typeof value === 'function') {
178
+ throw error_1.NesoiError.Message.UnsanitaryValue({
179
+ alias: field.alias, path: path.join('.'), details: 'Functions not allowed as message inputs.'
180
+ });
181
+ }
182
+ }
124
183
  /**
125
184
  * Empty values: `{}`, `[]`, `''`, `null`, `undefined`
126
185
  */
@@ -139,3 +198,25 @@ function isEmpty(value) {
139
198
  }
140
199
  return false;
141
200
  }
201
+ /**
202
+ * Rules
203
+ */
204
+ async function applyFieldRules(mode, field, path, raw, value, inject) {
205
+ let output = value;
206
+ // If mode is item, the value received is not an array
207
+ // - This comes from a .rule *before* .array
208
+ // If mode is array, the value received is an array
209
+ // - This comes from a .rule *after* .array
210
+ const rules = mode === 'item' ? field.rules : field.arrayRules;
211
+ for (const r in rules) {
212
+ const rule = rules[r];
213
+ const res = await rule({ field, value, path: path.join('.'), msg: raw, inject });
214
+ if (typeof res === 'object') {
215
+ output = res.set;
216
+ }
217
+ else if (res !== true) {
218
+ throw error_1.NesoiError.Message.RuleFailed({ alias: field.alias, path: path.join('.'), rule, error: res });
219
+ }
220
+ }
221
+ return output;
222
+ }
@@ -169,53 +169,54 @@ export declare namespace NesoiError {
169
169
  module: string;
170
170
  }): BaseError;
171
171
  function InvalidEnumScope($: {
172
+ alias: string;
172
173
  path: string;
173
- name: string;
174
- alias?: string;
175
174
  value: any;
176
175
  fieldpath: string;
177
176
  }): BaseError;
178
177
  function InvalidFieldEnumValue($: {
179
- field: string;
178
+ alias: string;
180
179
  path: string;
181
180
  value: any;
182
181
  type: string;
183
182
  options: string[];
184
183
  }): BaseError;
185
184
  function InvalidFieldType($: {
186
- field: string;
185
+ alias: string;
187
186
  path: string;
188
187
  value: any;
189
188
  type: string;
190
189
  }): BaseError;
191
190
  function ValueDoesntMatchUnion($: {
192
- field: string;
191
+ alias: string;
193
192
  path: string;
194
193
  value: any;
195
- unionErrors: string[];
194
+ unionErrors: Record<string, any>[];
196
195
  }): BaseError;
197
196
  function UnsanitaryValue($: {
197
+ alias: string;
198
+ path: string;
198
199
  details: string;
199
200
  }): BaseError;
200
201
  function FieldIsRequired($: {
201
- field: string;
202
+ alias: string;
202
203
  path: string;
203
204
  value: any;
204
205
  }): BaseError;
205
206
  function RuleFailed($: {
207
+ alias: string;
208
+ path: string;
206
209
  rule: $MessageTemplateRule;
207
210
  error: string;
208
211
  }): BaseError;
209
212
  function FileTooBig($: {
213
+ alias: string;
210
214
  path: string;
211
- name: string;
212
- alias?: string;
213
215
  maxsize: number;
214
216
  }): BaseError;
215
217
  function FileExtNotAllowed($: {
218
+ alias: string;
216
219
  path: string;
217
- name: string;
218
- alias?: string;
219
220
  options: string[];
220
221
  }): BaseError;
221
222
  }
@@ -302,19 +302,19 @@ var NesoiError;
302
302
  }
303
303
  Message.NotSupportedByModule = NotSupportedByModule;
304
304
  function InvalidEnumScope($) {
305
- return new BaseError('Message.InvalidEnumScope', `${$.alias || $.name} is an enum with dynamic scope, and the path '${$.fieldpath}' of the message has an invalid value '${$.value}'`, Status.BAD_REQUEST, $);
305
+ return new BaseError('Message.InvalidEnumScope', `${$.alias} is an enum with dynamic scope, and the path '${$.fieldpath}' of the message has an invalid value '${$.value}'`, Status.BAD_REQUEST, $);
306
306
  }
307
307
  Message.InvalidEnumScope = InvalidEnumScope;
308
308
  function InvalidFieldEnumValue($) {
309
- return new BaseError('Message.InvalidFieldEnumValue', `Message field '${$.field}' value '${$.value}' should be one of the following: ${$.options?.join(',')}`, Status.BAD_REQUEST, $);
309
+ return new BaseError('Message.InvalidFieldEnumValue', `Message field '${$.alias}' value '${$.value}' should be one of the following: ${$.options?.join(',')}`, Status.BAD_REQUEST, $);
310
310
  }
311
311
  Message.InvalidFieldEnumValue = InvalidFieldEnumValue;
312
312
  function InvalidFieldType($) {
313
- return new BaseError('Message.InvalidFieldType', `Message field '${$.field}' value '${$.value}' is not of type '${$.type}'`, Status.BAD_REQUEST, $);
313
+ return new BaseError('Message.InvalidFieldType', `Message field '${$.alias}' value '${$.value}' is not of type '${$.type}'`, Status.BAD_REQUEST, $);
314
314
  }
315
315
  Message.InvalidFieldType = InvalidFieldType;
316
316
  function ValueDoesntMatchUnion($) {
317
- return new BaseError('Message.ValueDoesntMatchUnion', `Message field '${$.field}' (${$.path}) value '${$.value}' doesn't match any of the union options'`, Status.BAD_REQUEST, $);
317
+ return new BaseError('Message.ValueDoesntMatchUnion', `Message field '${$.alias}' (${$.path}) value '${$.value}' doesn't match any of the union options'`, Status.BAD_REQUEST, $);
318
318
  }
319
319
  Message.ValueDoesntMatchUnion = ValueDoesntMatchUnion;
320
320
  function UnsanitaryValue($) {
@@ -322,7 +322,7 @@ var NesoiError;
322
322
  }
323
323
  Message.UnsanitaryValue = UnsanitaryValue;
324
324
  function FieldIsRequired($) {
325
- return new BaseError('Message.FieldIsRequired', `Field ${$.field} (${$.path}) is required`, Status.BAD_REQUEST, $);
325
+ return new BaseError('Message.FieldIsRequired', `Field ${$.alias} (${$.path}) is required`, Status.BAD_REQUEST, $);
326
326
  }
327
327
  Message.FieldIsRequired = FieldIsRequired;
328
328
  function RuleFailed($) {
@@ -330,11 +330,11 @@ var NesoiError;
330
330
  }
331
331
  Message.RuleFailed = RuleFailed;
332
332
  function FileTooBig($) {
333
- return new BaseError('Message.FileTooBig', `${$.alias || $.name} size exceeds max (${$.maxsize})`, Status.BAD_REQUEST, $);
333
+ return new BaseError('Message.FileTooBig', `${$.alias} size exceeds max (${$.maxsize})`, Status.BAD_REQUEST, $);
334
334
  }
335
335
  Message.FileTooBig = FileTooBig;
336
336
  function FileExtNotAllowed($) {
337
- return new BaseError('Message.FileExtNotAllowed', `${$.alias || $.name} extension not allowed. Options: ${$.options}`, Status.BAD_REQUEST, $);
337
+ return new BaseError('Message.FileExtNotAllowed', `${$.alias} extension not allowed. Options: ${$.options}`, Status.BAD_REQUEST, $);
338
338
  }
339
339
  Message.FileExtNotAllowed = FileExtNotAllowed;
340
340
  })(Message = NesoiError.Message || (NesoiError.Message = {}));