-
Notifications
You must be signed in to change notification settings - Fork 18
/
wurfl.js
174 lines (136 loc) · 3.63 KB
/
wurfl.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
162
163
164
165
166
167
168
169
170
171
172
173
174
var fs = require('fs');
var path = require('path');
var expat = require('node-expat');
var parser = require('./parser');
var backgrounder = require("backgrounder");
var wurflFile = path.join(__dirname, '../wurfl.xml');
var userAgents = {};
var worker;
var callbacks = {watch: {}, load: {}};
function get(userAgent) {
return userAgents[userAgent];
}
function getAll() {
return userAgents;
}
function close() {
if (worker) worker.terminate();
}
// lazily load the worker
function getWorker() {
if (!worker) {
worker = new backgrounder.spawn(path.join(__dirname, './worker.js'));
worker.on('message', function(data) {
var method = data.method;
var file = data.file;
var devices = data.devices;
packageDevices(devices);
var callback = callbacks[method][file];
if (callback) callback();
});
worker.on('error', function(error) {
console.error(error);
});
}
return worker;
}
function watch(options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
if (typeof options === 'string') {
options = { file: options };
}
options = options || { file: options };
options.file = options.file || wurflFile;
if (callback) callbacks.watch[file] = callback;
getWorker().send({
method: 'watch',
file: options.file,
groups: options.groups
});
}
function load(options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
if (typeof options === 'string') {
options = { file: options };
}
options = options || { file: options };
options.file = options.file || wurflFile;
if (callback) callbacks.load[options.file] = callback;
getWorker().send({
method: 'load',
file: options.file,
groups: options.groups
});
}
function loadSync(options) {
if (typeof options === 'string') {
options = { file: options };
}
options = options || { file: options };
options.file = options.file || wurflFile;
var contents = fs.readFileSync(options.file);
packageDevices(parser.parse(contents, options.groups));
}
function packageDevices(devices) {
var agents = {};
// add the lookup first
devices.forEach(function(device) {
devices[device.id] = device;
});
// create device objects from each one
devices.forEach(function(device, i, array) {
if (device instanceof Device) return;
array[i] = createDevice(device, devices, agents);
});
userAgents = agents;
}
function createDevice(attr, lookup, agents) {
if (attr.fall_back !== 'root' && !(lookup[attr.fall_back] instanceof Device)) {
createDevice(lookup[attr.fall_back], lookup, agents);
}
var groups = attr.groups;
delete attr.groups;
var device = new Device(attr);
lookup[device.id] = device; // add a lookup by id
agents[device.user_agent] = device; // and a lookup by user agent
var parent = lookup[attr.fall_back];
if (parent) {
for (var i in parent) {
var group = parent[i];
if (group instanceof Group) {
device[i] = group;
}
}
}
for (var id in groups) {
group = device[id];
var GroupClass = function() {};
GroupClass.prototype = group ? new group.constructor() : new Group();
var groupProto = GroupClass.prototype;
groupProto.constructor = GroupClass;
groupProto.id = device.id + '.' + id;
device[id] = group = new GroupClass();
var capabilities = groups[id];
for (var name in capabilities) {
groupProto[name] = capabilities[name];
}
}
return device;
}
function Device(attr) {
for (var i in attr)
if (attr.hasOwnProperty(i)) this[i] = attr[i];
}
function Group() {}
exports.watch = watch;
exports.load = load;
exports.loadSync = loadSync;
exports.get = get;
exports.getAll = getAll;
exports.close = close;