/
webd.js
161 lines (149 loc) · 4.5 KB
/
webd.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
/**
* Default parsers
*/
var parsers =
{ 'webd:date': require('./date')
, 'webd:measure': require('./measure')
, 'webd:unit': require('./unit')
, 'webd:undefined': require('./undefined')
, 'webd:regexp': require('./regexp')
}
/**
* Register a new parsing function
*
* @param {String} uri An uri used to uniquely identify this format.
* The protocol of the URI should be either `webd:`,
* `http:` or `https:`. If the protocol is `http:`
* or `https:`, the provided uri MUST point to a valid resource.
* This resource MUST contain a human readable specification
* of the format. URIs with `webd:` protocol are reserved for
* standard formats, but are still useful if you want to
* specify a custom parser.
*
* @param {Function} parseFunction The function used to parse this format. It takes a
* single argument, the object being parsed, and is
* expected to return the result of the parsing.
*
* @api public
*/
exports.register = function(uri, parseFunction) {
parsers[uri] = parseFunction
}
/**
* Decode an object from WebD format.
* This function does not perform JSON parsing.
* If that's what you need, check out `webd.parse()`.
*
* @param {Object} obj The object being decoded
* @returns {Object} The decoded version of the object
*
* @api public
*/
var decode = exports.encode = function(obj) {
var newObj
if (obj === null) {
newObj = null
} else if (['number', 'string', 'boolean'].indexOf(typeof obj) != -1) {
newObj = obj
} else if (typeof obj == 'object') {
if (typeof obj._ !== 'undefined') {
var type
if (typeof obj._ === 'string') {
type = obj._
} else if (typeof obj._ === 'object' && typeof obj._.type === 'string') {
type = obj._.type
} else {
throw new Error('Invalid type: ' + obj._)
}
var parser = parsers[type]
if (!parser) {
throw new Error('Unknown type: ' + type)
}
newObj = parser.parse(obj)
} else {
if (obj instanceof Array) {
newObj = []
} else {
newObj = {}
}
// Copy properties
for (var property in obj) {
var newProperty = property
// Unescape property names made of only underscores
if (property.match(/^_+$/)) {
newProperty = property.substr(1)
}
newObj[newProperty] = decode(obj[property])
}
}
}
return newObj
}
/**
* Encode an object to WebD format (but don't stringify it)
*
* @param {Object} obj The object being encoded
* @returns {Object} The encoded version of the object
*
* @api public
*/
var encode = exports.encode = function(obj) {
var newObj
if (obj === null) {
newObj = null
} else if (['number', 'string', 'boolean'].indexOf(typeof obj) != -1) {
newObj = obj
} else if (typeof obj === 'object') {
if (obj.toWebD && obj.toWebD instanceof Function) {
newObj = obj.toWebD()
} else {
if (obj instanceof Array) {
newObj = []
} else {
newObj = {}
}
// Copy properties
for (var property in obj) {
var newProperty = property
// Escape property names made of only underscores
if (property.match(/^_+$/)) {
newProperty = '_' + property
}
newObj[newProperty] = encode(obj[property])
}
}
} else if (typeof obj === 'undefined') {
newObj = parsers['webd:undefined'].singleton
}
return newObj
}
/**
* Parse a JSON string representation of an object in WebD format.
*
* @param {String, Object} obj The Object being parsed
* @returns {Object} The result of the parsing
*
* @api public
*/
exports.parse = function(obj) {
if (typeof obj == "string" || obj instanceof String) {
obj = JSON.parse(obj)
}
return decode(obj)
}
/**
* Stringify an object to a JSON representation of WebD format.
*
* @param {Object} obj The Object being stringified
* @param {String} space The character or sequence of characters used to indent the output.
* (e.g. ' ' or '\t'). If provided, the function will produce pretty
* printed output.
* @returns {String} The string representing the Object in WebD format
*
* @api public
*/
exports.stringify = function(obj, space) {
return JSON.stringify(encode(obj), null, space)
}
exports.Unit = parsers['webd:unit']
exports.Measure = parsers['webd:measure']