Skip to content

Commit 94e85d0

Browse files
authored
Merge pull request totaljs#581 from totaljs/2.9.0
v2.9.0
2 parents c79d89b + 25119c1 commit 94e85d0

14 files changed

Lines changed: 1949 additions & 645 deletions

.editorconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# http://editorconfig.org/
2+
3+
# Top-most EditorConfig file
4+
root = true
5+
6+
[*.js]
7+
indent_style = tab
8+
indent_size = 2
9+
end_of_line = lf
10+
charset = utf-8
11+
trim_trailing_whitespace = true
12+
insert_final_newline = false
13+
max_line_length = 120
14+
15+
[*.json]
16+
indent_style = space
17+
indent_size = 2

builders.js

Lines changed: 155 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121

2222
/**
2323
* @module FrameworkBuilders
24-
* @version 2.8.0
24+
* @version 2.9.0
2525
*/
2626

2727
'use strict';
@@ -30,8 +30,8 @@ const REQUIRED = 'The field "@" is invalid.';
3030
const DEFAULT_SCHEMA = 'default';
3131
const SKIP = { $$schema: true, $$result: true, $$callback: true, $$async: true, $$index: true, $$repository: true, $$can: true, $$controller: true };
3232
const REGEXP_CLEAN_EMAIL = /\s/g;
33-
const REGEXP_CLEAN_PHONE = /\s|\.|\-|\(|\)/g;
34-
const REGEXP_NEWOPERATION = /^function(\s)?\([a-zA-Z0-9\$]+\)/;
33+
const REGEXP_CLEAN_PHONE = /\s|\.|-|\(|\)/g;
34+
const REGEXP_NEWOPERATION = /^function(\s)?\([a-zA-Z0-9$]+\)/;
3535
const hasOwnProperty = Object.prototype.hasOwnProperty;
3636
const Qs = require('querystring');
3737

@@ -50,10 +50,33 @@ function SchemaOptions(error, model, options, callback, controller) {
5050
this.options = options;
5151
this.callback = this.next = callback;
5252
this.controller = controller;
53+
54+
if (controller) {
55+
56+
if (controller.user)
57+
this.user = controller.user;
58+
59+
if (controller.session)
60+
this.session = controller.session;
61+
62+
this.language = controller.language || '';
63+
this.ip = controller.ip;
64+
this.id = controller.id;
65+
this.query = controller.query;
66+
this.body = controller.body;
67+
this.files = controller.files;
68+
} else
69+
this.language = '';
5370
}
5471

55-
SchemaOptions.prototype.throw = function(name, error, path, index) {
72+
SchemaOptions.prototype.success = function(a, b) {
73+
this.callback(SUCCESS(a === undefined ? true : a, b));
74+
return this;
75+
};
76+
77+
SchemaOptions.prototype.invalid = function(name, error, path, index) {
5678
this.error.push(name, error, path, index);
79+
this.callback();
5780
return this;
5881
};
5982

@@ -152,6 +175,44 @@ SchemaBuilderEntity.prototype.allow = function() {
152175
return self;
153176
};
154177

178+
SchemaBuilderEntity.prototype.required = function(name, fn) {
179+
180+
var self = this;
181+
182+
if (!name)
183+
return self;
184+
185+
if (name.indexOf(',') !== -1) {
186+
var arr = name.split(',');
187+
for (var i = 0; i < arr.length; i++)
188+
self.required(arr[i].trim(), fn);
189+
return self;
190+
}
191+
192+
if (fn === false) {
193+
self.properties && (self.properties = self.properties.remove(name));
194+
return self;
195+
}
196+
197+
var prop = self.schema[name];
198+
if (!prop)
199+
throw new Error('Property "{0}" doesn\'t exist in "{1}" schema.'.format(name, self.name));
200+
201+
var is = prop.required;
202+
203+
prop.can = typeof(fn) === 'function' ? fn : null;
204+
205+
if (!prop.required) {
206+
prop.required = true;
207+
if (self.properties) {
208+
self.properties.indexOf(name) === -1 && self.properties.push(name);
209+
} else
210+
self.properties = [name];
211+
}
212+
213+
return self;
214+
};
215+
155216
/**
156217
* Define type in schema
157218
* @param {String|String[]} name
@@ -168,7 +229,9 @@ SchemaBuilderEntity.prototype.define = function(name, type, required, custom) {
168229
return this;
169230
}
170231

171-
if (required !== undefined && typeof(required) !== 'boolean') {
232+
var rt = typeof(required);
233+
234+
if (required !== undefined && rt === 'string') {
172235
custom = required;
173236
required = false;
174237
}
@@ -189,13 +252,12 @@ SchemaBuilderEntity.prototype.define = function(name, type, required, custom) {
189252

190253
this.fields = Object.keys(this.schema);
191254

192-
if (!required)
193-
return this;
194-
195-
if (this.properties == null)
196-
this.properties = [];
255+
if (required) {
256+
if (this.properties == null)
257+
this.properties = [];
258+
this.properties.indexOf(name) === -1 && this.properties.push(name);
259+
}
197260

198-
this.properties.indexOf(name) === -1 && this.properties.push(name);
199261
return this;
200262
};
201263

@@ -364,10 +426,10 @@ SchemaBuilderEntity.prototype.filter = function(custom, model, reverse) {
364426
function parseLength(lower, result) {
365427
result.raw = 'string';
366428
var beg = lower.indexOf('(');
367-
if (beg === -1)
368-
return result;
369-
result.length = lower.substring(beg + 1, lower.length - 1).parseInt();
370-
result.raw = lower.substring(0, beg);
429+
if (beg !== -1) {
430+
result.length = lower.substring(beg + 1, lower.length - 1).parseInt();
431+
result.raw = lower.substring(0, beg);
432+
}
371433
return result;
372434
}
373435

@@ -380,6 +442,8 @@ SchemaBuilderEntity.prototype.$parse = function(name, value, required, custom) {
380442
result.type = 0;
381443
result.length = 0;
382444
result.required = required ? true : false;
445+
result.validate = typeof(required) === 'function' ? required : null;
446+
result.can = null;
383447
result.isArray = false;
384448
result.custom = custom || '';
385449

@@ -1178,18 +1242,22 @@ SchemaBuilderEntity.prototype.validate = function(model, resourcePrefix, resourc
11781242
var s = self.parent.collection[schema.raw];
11791243

11801244
if (!s) {
1181-
F.error(new Error('Schema "' + schema.raw + '" not found (validation).'));
1245+
F.error(new Error('Schema "{0}" not found (validation).'.format(schema.raw)));
11821246
continue;
11831247
}
11841248

1185-
if (!schema.isArray) {
1186-
(model[key] != null || schema.required) && s.validate(model[key], resourcePrefix, resourceName, builder, filter, path + key, -1);
1187-
continue;
1249+
if (schema.isArray) {
1250+
var arr = model[key];
1251+
for (var j = 0, jl = arr.length; j < jl; j++) {
1252+
if (model[key][j] != null || schema.required) {
1253+
if (!schema.can || schema.can(model))
1254+
s.validate(model[key][j], resourcePrefix, resourceName, builder, filter, path + key + '[' + j + ']', j);
1255+
}
1256+
}
1257+
} else if (model[key] != null || schema.required) {
1258+
if (!schema.can || schema.can(model))
1259+
s.validate(model[key], resourcePrefix, resourceName, builder, filter, path + key, -1);
11881260
}
1189-
1190-
var arr = model[key];
1191-
for (var j = 0, jl = arr.length; j < jl; j++)
1192-
(model[key][j] != null || schema.required) && s.validate(model[key][j], resourcePrefix, resourceName, builder, filter, path + key + '[' + j + ']', j);
11931261
}
11941262

11951263
return builder;
@@ -1423,6 +1491,7 @@ SchemaBuilderEntity.prototype.prepare = function(model, dependencies) {
14231491
val = val();
14241492

14251493
if (!type.isArray) {
1494+
14261495
switch (type.type) {
14271496
// undefined
14281497
case 0:
@@ -1438,7 +1507,16 @@ SchemaBuilderEntity.prototype.prepare = function(model, dependencies) {
14381507

14391508
// string
14401509
case 3:
1441-
tmp = val == null ? '' : autotrim(self, val.toString());
1510+
1511+
var tv = typeof(val);
1512+
1513+
if (val == null || tv === 'object')
1514+
tmp = '';
1515+
else if (tv === 'string')
1516+
tmp = autotrim(self, val);
1517+
else
1518+
tmp = autotrim(self, val.toString());
1519+
14421520
if (type.length && type.length < tmp.length)
14431521
tmp = tmp.substring(0, type.length);
14441522

@@ -2650,6 +2728,7 @@ exports.validate = function(name, model, resourcePrefix, resourceName) {
26502728
if (schema === undefined)
26512729
return null;
26522730
schema = schema.get(name);
2731+
model = schema.prepare(model);
26532732
return schema === undefined ? null : schema.validate(model, resourcePrefix, resourceName);
26542733
};
26552734

@@ -2755,7 +2834,7 @@ ErrorBuilder.prototype._resource = function() {
27552834

27562835
ErrorBuilder.prototype._resource_handler = function(name) {
27572836
var self = this;
2758-
return typeof(framework) !== 'undefined' ? F.resource(self.resourceName || 'default', self.resourcePrefix + name) : '';
2837+
return typeof(F) !== 'undefined' ? F.resource(self.resourceName || 'default', name) : '';
27592838
};
27602839

27612840
ErrorBuilder.prototype.exception = function(message) {
@@ -2783,7 +2862,8 @@ ErrorBuilder.prototype.add = function(name, error, path, index) {
27832862
* @param {Number} index Array Index, optional.
27842863
* @return {ErrorBuilder}
27852864
*/
2786-
ErrorBuilder.prototype.push = function(name, error, path, index) {
2865+
ErrorBuilder.prototype.push = function(name, error, path, index, prefix) {
2866+
27872867
this.isPrepared = false;
27882868

27892869
if (name instanceof ErrorBuilder) {
@@ -2797,13 +2877,13 @@ ErrorBuilder.prototype.push = function(name, error, path, index) {
27972877

27982878
if (name instanceof Array) {
27992879
for (var i = 0, length = name.length; i < length; i++)
2800-
this.push(name[i], undefined, path, index);
2880+
this.push(name[i], undefined, path, index, prefix);
28012881
return this;
28022882
}
28032883

28042884
if (error instanceof Array) {
28052885
for (var i = 0, length = error.length; i < length; i++)
2806-
this.push(name, error[i], path, index);
2886+
this.push(name, error[i], path, index, prefix);
28072887
return this;
28082888
}
28092889

@@ -2825,7 +2905,7 @@ ErrorBuilder.prototype.push = function(name, error, path, index) {
28252905
error = error.toString();
28262906
}
28272907

2828-
this.items.push({ name: name, error: typeof(error) === 'string' ? error : error.toString(), path: path, index: index });
2908+
this.items.push({ name: name, error: typeof(error) === 'string' ? error : error.toString(), path: path, index: index, prefix: prefix });
28292909
this.count = this.items.length;
28302910
return this;
28312911
};
@@ -2925,11 +3005,12 @@ ErrorBuilder.prototype._prepare = function() {
29253005
for (var i = 0, length = arr.length; i < length; i++) {
29263006

29273007
var o = arr[i];
3008+
29283009
if (o.error[0] !== '@')
29293010
continue;
29303011

29313012
if (o.error.length === 1)
2932-
o.error = this.onResource(o.name);
3013+
o.error = this.onResource(o.prefix ? o.prefix : (this.resourcePrefix + o.name));
29333014
else
29343015
o.error = this.onResource(o.error.substring(1));
29353016

@@ -3646,6 +3727,8 @@ RESTBuilder.prototype.auth = function(user, password) {
36463727

36473728
RESTBuilder.prototype.schema = function(group, name) {
36483729
this.$schema = exports.getschema(group, name);
3730+
if (!this.$schema)
3731+
throw Error('RESTBuilder: Schema "{0}" not found.'.format(name ? (group + '/' + name) : group));
36493732
return this;
36503733
};
36513734

@@ -4005,7 +4088,7 @@ global.NEWOPERATION = function(name, fn) {
40054088

40064089
global.OPERATION = function(name, value, callback, param) {
40074090

4008-
if (callback === undefined) {
4091+
if (typeof(value) === 'function') {
40094092
callback = value;
40104093
value = EMPTYOBJECT;
40114094
}
@@ -4015,31 +4098,55 @@ global.OPERATION = function(name, value, callback, param) {
40154098

40164099
if (fn) {
40174100
if (fn.$newversion) {
4018-
var opt = {};
4019-
opt.error = error;
4020-
opt.value = opt.model = value;
4021-
opt.callback = function(value) {
4022-
if (value instanceof Error) {
4023-
error.push(value);
4024-
value = EMPTYOBJECT;
4025-
}
4026-
callback(error.hasError() ? error : null, value, param);
4027-
};
4028-
fn(opt);
4101+
fn(new OperationOptions(error, value, callback, param));
40294102
} else
40304103
fn(error, value, function(value) {
4031-
if (value instanceof Error) {
4032-
error.push(value);
4033-
value = EMPTYOBJECT;
4104+
if (callback) {
4105+
if (value instanceof Error) {
4106+
error.push(value);
4107+
value = EMPTYOBJECT;
4108+
}
4109+
callback(error.hasError() ? error : null, value, param);
40344110
}
4035-
callback(error.hasError() ? error : null, value, param);
40364111
});
40374112
} else {
40384113
error.push('Operation "{0}" not found.'.format(name));
4039-
callback(error, EMPTYOBJECT, param);
4114+
callback && callback(error, EMPTYOBJECT, param);
40404115
}
40414116
};
40424117

4118+
function OperationOptions(error, value, callback, options) {
4119+
this.model = this.value = value;
4120+
this.error = error;
4121+
this.$callback = callback;
4122+
this.options = options;
4123+
}
4124+
4125+
OperationOptions.prototype.callback = function(value) {
4126+
var self = this;
4127+
4128+
if (self.$callback) {
4129+
if (value instanceof Error) {
4130+
self.error.push(value);
4131+
value = EMPTYOBJECT;
4132+
}
4133+
self.$callback(self.error.hasError() ? self.error : null, value, self.options);
4134+
}
4135+
4136+
return self;
4137+
};
4138+
4139+
OperationOptions.prototype.success = function(a, b) {
4140+
this.callback(SUCCESS(a === undefined ? true : a, b));
4141+
return this;
4142+
};
4143+
4144+
OperationOptions.prototype.invalid = function(name, error, path, index) {
4145+
this.error.push(name, error, path, index);
4146+
this.callback();
4147+
return this;
4148+
};
4149+
40434150
// ======================================================
40444151
// EXPORTS
40454152
// ======================================================
@@ -4052,6 +4159,7 @@ exports.Page = Page;
40524159
exports.UrlBuilder = UrlBuilder;
40534160
exports.TransformBuilder = TransformBuilder;
40544161
exports.SchemaOptions = SchemaOptions;
4162+
exports.OperationOptions = OperationOptions;
40554163
exports.RESTBuilderResponse = RESTBuilderResponse;
40564164
global.RESTBuilder = RESTBuilder;
40574165
global.RESTBuilderResponse = RESTBuilderResponse;

0 commit comments

Comments
 (0)