]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - jssource/src_files/include/javascript/yui3/build/dataschema/dataschema-json.js
Release 6.2.0beta4
[Github/sugarcrm.git] / jssource / src_files / include / javascript / yui3 / build / dataschema / dataschema-json.js
1 /*
2 Copyright (c) 2009, Yahoo! Inc. All rights reserved.
3 Code licensed under the BSD License:
4 http://developer.yahoo.net/yui/license.txt
5 version: 3.0.0
6 build: 1549
7 */
8 YUI.add('dataschema-json', function(Y) {
9
10 /**
11  * Provides a DataSchema implementation which can be used to work with JSON data.
12  *
13  * @module dataschema
14  * @submodule dataschema-json
15  */
16
17 /**
18  * JSON subclass for the DataSchema Utility.
19  * @class DataSchema.JSON
20  * @extends DataSchema.Base
21  * @static
22  */
23 var LANG = Y.Lang,
24
25     SchemaJSON = {
26
27         /////////////////////////////////////////////////////////////////////////////
28         //
29         // DataSchema.JSON static methods
30         //
31         /////////////////////////////////////////////////////////////////////////////
32         /**
33          * Utility function converts JSON locator strings into walkable paths
34          *
35          * @method DataSchema.JSON.getPath
36          * @param locator {String} JSON value locator.
37          * @return {String[]} Walkable path to data value.
38          * @static
39          */
40         getPath: function(locator) {
41             var path = null,
42                 keys = [],
43                 i = 0;
44
45             if (locator) {
46                 // Strip the ["string keys"] and [1] array indexes
47                 locator = locator.
48                     replace(/\[(['"])(.*?)\1\]/g,
49                     function (x,$1,$2) {keys[i]=$2;return '.@'+(i++);}).
50                     replace(/\[(\d+)\]/g,
51                     function (x,$1) {keys[i]=parseInt($1,10)|0;return '.@'+(i++);}).
52                     replace(/^\./,''); // remove leading dot
53
54                 // Validate against problematic characters.
55                 if (!/[^\w\.\$@]/.test(locator)) {
56                     path = locator.split('.');
57                     for (i=path.length-1; i >= 0; --i) {
58                         if (path[i].charAt(0) === '@') {
59                             path[i] = keys[parseInt(path[i].substr(1),10)];
60                         }
61                     }
62                 }
63                 else {
64                 }
65             }
66             return path;
67         },
68
69         /**
70          * Utility function to walk a path and return the value located there.
71          *
72          * @method DataSchema.JSON.getLocationValue
73          * @param path {String[]} Locator path.
74          * @param data {String} Data to traverse.
75          * @return {Object} Data value at location.
76          * @static
77          */
78         getLocationValue: function (path, data) {
79             var i = 0,
80                 len = path.length;
81             for (;i<len;i++) {
82                 if(!LANG.isUndefined(data[path[i]])) {
83                     data = data[path[i]];
84                 }
85                 else {
86                     data = undefined;
87                     break;
88                 }
89             }
90             return data;
91         },
92
93         /**
94          * Applies a given schema to given JSON data.
95          *
96          * @method apply
97          * @param schema {Object} Schema to apply.
98          * @param data {Object} JSON data.
99          * @return {Object} Schema-parsed data.
100          * @static
101          */
102         apply: function(schema, data) {
103             var data_in = data,
104                 data_out = {results:[],meta:{}};
105
106             // Convert incoming JSON strings
107             if(!LANG.isObject(data)) {
108                 try {
109                     data_in = Y.JSON.parse(data);
110                 }
111                 catch(e) {
112                     data_out.error = e;
113                     return data_out;
114                 }
115             }
116
117             if(LANG.isObject(data_in) && schema) {
118                 // Parse results data
119                 if(!LANG.isUndefined(schema.resultListLocator)) {
120                     data_out = SchemaJSON._parseResults(schema, data_in, data_out);
121                 }
122
123                 // Parse meta data
124                 if(!LANG.isUndefined(schema.metaFields)) {
125                     data_out = SchemaJSON._parseMeta(schema.metaFields, data_in, data_out);
126                 }
127             }
128             else {
129                 data_out.error = new Error("JSON schema parse failure");
130             }
131
132             return data_out;
133         },
134
135         /**
136          * Schema-parsed list of results from full data
137          *
138          * @method _parseResults
139          * @param schema {Object} Schema to parse against.
140          * @param json_in {Object} JSON to parse.
141          * @param data_out {Object} In-progress parsed data to update.
142          * @return {Object} Parsed data object.
143          * @static
144          * @protected
145          */
146         _parseResults: function(schema, json_in, data_out) {
147             var results = [],
148                 path,
149                 error;
150
151             if(schema.resultListLocator) {
152                 path = SchemaJSON.getPath(schema.resultListLocator);
153                 if(path) {
154                     results = SchemaJSON.getLocationValue(path, json_in);
155                     if (results === undefined) {
156                         data_out.results = [];
157                         error = new Error("JSON results retrieval failure");
158                     }
159                     else {
160                         if(LANG.isArray(schema.resultFields) && LANG.isArray(results)) {
161                             data_out = SchemaJSON._getFieldValues(schema.resultFields, results, data_out);
162                         }
163                         else {
164                             data_out.results = [];
165                             error = new Error("JSON Schema fields retrieval failure");
166                         }
167                     }
168                 }
169                 else {
170                     error = new Error("JSON Schema results locator failure");
171                 }
172
173                 if (error) {
174                     data_out.error = error;
175                 }
176
177             }
178             return data_out;
179         },
180
181         /**
182          * Get field data values out of list of full results
183          *
184          * @method _getFieldValues
185          * @param fields {Array} Fields to find.
186          * @param array_in {Array} Results to parse.
187          * @param data_out {Object} In-progress parsed data to update.
188          * @return {Object} Parsed data object.
189          * @static
190          * @protected
191          */
192         _getFieldValues: function(fields, array_in, data_out) {
193             var results = [],
194                 len = fields.length,
195                 i, j,
196                 field, key, path, parser,
197                 simplePaths = [], complexPaths = [], fieldParsers = [],
198                 result, record;
199
200             // First collect hashes of simple paths, complex paths, and parsers
201             for (i=0; i<len; i++) {
202                 field = fields[i]; // A field can be a simple string or a hash
203                 key = field.key || field; // Find the key
204
205                 // Validate and store locators for later
206                 path = SchemaJSON.getPath(key);
207                 if (path) {
208                     if (path.length === 1) {
209                         simplePaths[simplePaths.length] = {key:key, path:path[0]};
210                     } else {
211                         complexPaths[complexPaths.length] = {key:key, path:path};
212                     }
213                 } else {
214                 }
215
216                 // Validate and store parsers for later
217                 //TODO: use Y.DataSchema.parse?
218                 parser = (LANG.isFunction(field.parser)) ? field.parser : Y.Parsers[field.parser+''];
219                 if (parser) {
220                     fieldParsers[fieldParsers.length] = {key:key, parser:parser};
221                 }
222             }
223
224             // Traverse list of array_in, creating records of simple fields,
225             // complex fields, and applying parsers as necessary
226             for (i=array_in.length-1; i>=0; --i) {
227                 record = {};
228                 result = array_in[i];
229                 if(result) {
230                     // Cycle through simpleLocators
231                     for (j=simplePaths.length-1; j>=0; --j) {
232                         // Bug 1777850: The result might be an array instead of object
233                         record[simplePaths[j].key] = Y.DataSchema.Base.parse(
234                                 (LANG.isUndefined(result[simplePaths[j].path]) ?
235                                 result[j] : result[simplePaths[j].path]), simplePaths[j]);
236                     }
237
238                     // Cycle through complexLocators
239                     for (j=complexPaths.length - 1; j>=0; --j) {
240                         record[complexPaths[j].key] = Y.DataSchema.Base.parse(
241                             (SchemaJSON.getLocationValue(complexPaths[j].path, result)), complexPaths[j] );
242                     }
243
244                     // Cycle through fieldParsers
245                     for (j=fieldParsers.length-1; j>=0; --j) {
246                         key = fieldParsers[j].key;
247                         record[key] = fieldParsers[j].parser(record[key]);
248                         // Safety net
249                         if (LANG.isUndefined(record[key])) {
250                             record[key] = null;
251                         }
252                     }
253                     results[i] = record;
254                 }
255             }
256             data_out.results = results;
257             return data_out;
258         },
259
260         /**
261          * Parses results data according to schema
262          *
263          * @method _parseMeta
264          * @param metaFields {Object} Metafields definitions.
265          * @param json_in {Object} JSON to parse.
266          * @param data_out {Object} In-progress parsed data to update.
267          * @return {Object} Schema-parsed meta data.
268          * @static
269          * @protected
270          */
271         _parseMeta: function(metaFields, json_in, data_out) {
272             if(LANG.isObject(metaFields)) {
273                 var key, path;
274                 for(key in metaFields) {
275                     if (metaFields.hasOwnProperty(key)) {
276                         path = SchemaJSON.getPath(metaFields[key]);
277                         if (path && json_in) {
278                             data_out.meta[key] = SchemaJSON.getLocationValue(path, json_in);
279                         }
280                     }
281                 }
282             }
283             else {
284                 data_out.error = new Error("JSON meta data retrieval failure");
285             }
286             return data_out;
287         }
288     };
289
290 Y.DataSchema.JSON = Y.mix(SchemaJSON, Y.DataSchema.Base);
291
292
293
294 }, '3.0.0' ,{requires:['json', 'dataschema-base']});