-
Notifications
You must be signed in to change notification settings - Fork 1.1k
/
Copy pathutil.js
200 lines (185 loc) · 6.36 KB
/
util.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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
var resolveModule = function(names, mod, root) {
if (names.length == 0) {
if (typeof mod.current != "string") {
throw ["error","invalid_require_path",
'Must require a JavaScript string, not: '+(typeof mod.current)];
}
return {
current : mod.current,
parent : mod.parent,
id : mod.id,
exports : {}
};
}
// we need to traverse the path
var n = names.shift();
if (n == '..') {
if (!(mod.parent && mod.parent.parent)) {
throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
}
return resolveModule(names, {
id : mod.id.slice(0, mod.id.lastIndexOf('/')),
parent : mod.parent.parent,
current : mod.parent.current
});
} else if (n == '.') {
if (!mod.parent) {
throw ["error", "invalid_require_path", 'Object has no parent '+JSON.stringify(mod.current)];
}
return resolveModule(names, {
parent : mod.parent,
current : mod.current,
id : mod.id
});
} else if (root) {
mod = {current : root};
}
if (mod.current[n] === undefined) {
throw ["error", "invalid_require_path", 'Object has no property "'+n+'". '+JSON.stringify(mod.current)];
}
return resolveModule(names, {
current : mod.current[n],
parent : mod,
id : mod.id ? mod.id + '/' + n : n
});
};
var Couch = {
// moving this away from global so we can move to json2.js later
compileFunction : function(source, ddoc, name, sandbox) {
if (!source) throw(["error","not_found","missing function"]);
var functionObject = null;
var sandbox = sandbox || create_sandbox();
var require = function(name, module) {
module = module || {};
var newModule = resolveModule(name.split('/'), module.parent, ddoc);
if (!ddoc._module_cache.hasOwnProperty(newModule.id)) {
// create empty exports object before executing the module,
// stops circular requires from filling the stack
ddoc._module_cache[newModule.id] = {};
var s = "(function (module, exports, require) { " + newModule.current + "\n });";
try {
var func = sandbox ? evalcx(s, sandbox, newModule.id) : eval(s);
func.apply(sandbox, [newModule, newModule.exports, function(name) {
return require(name, newModule);
}]);
} catch(e) {
throw [
"error",
"compilation_error",
"Module require('" +name+ "') raised error " + errstr(e)
];
}
ddoc._module_cache[newModule.id] = newModule.exports;
}
return ddoc._module_cache[newModule.id];
};
if (ddoc) {
sandbox.require = require;
if (!ddoc._module_cache) ddoc._module_cache = {};
}
try {
if(typeof CoffeeScript === "undefined") {
var rewrittenFun = rewriteFunInt(source);
functionObject = evalcx(rewrittenFun, sandbox, name);
} else {
var transpiled = CoffeeScript.compile(source, {bare: true});
functionObject = evalcx(transpiled, sandbox, name);
}
} catch (err) {
throw([
"error",
"compilation_error",
errstr(err) + " (" + source + ")"
]);
};
if (typeof(functionObject) == "function") {
return functionObject;
} else {
throw(["error","compilation_error",
"Expression does not eval to a function. (" + source.toString() + ")"]);
};
},
recursivelySeal: deepFreeze,
};
function errstr(e) {
// toSource() is a Spidermonkey "special"
return (e.toSource ? e.toSource() : e.toString());
};
// If we have an object which looks like an Error, then make it so it
// can be json stringified so it keeps the message and name,
// otherwise, most modern JS engine will stringify Error object as
// {}. Unfortnately, because of sandboxing we cannot use `e instanceof
// Error` as the Error object in the sandbox won't technically be the
// same error object as the one from our wrapper JS functions, so we
// use some "ducktyping" to detect the Error.
//
function error_to_json(e) {
if (typeof e === "object"
&& e != null
&& 'stack' in e
&& 'name' in e
&& 'message' in e
) {
return {'error': e.name, 'message': e.message}
};
return e;
}
// prints the object as JSON, and rescues and logs any JSON.stringify() related errors
function respond(obj) {
try {
print(JSON.stringify(obj));
} catch(e) {
log("Error converting object to JSON: " + e.toString());
log("error on obj: "+ obj.toString());
}
};
function log(message) {
// idea: query_server_config option for log level
if (typeof message == "xml") {
message = message.toXMLString();
} else if (typeof message != "string") {
message = JSON.stringify(error_to_json(message));
}
respond(["log", String(message)]);
};
function isArray(obj) {
return toString.call(obj) === "[object Array]";
}
function getPropNames(object) {
if (typeof Reflect === 'undefined') {
return Object.getOwnPropertyNames(object);
} else {
return Reflect.ownKeys(object);
}
}
function deepFreeze(object) {
if (Object.isFrozen(object)) {
return object;
}
Object.freeze(object);
// Retrieve the property names defined on object
// `Reflect.ownKeys()` gives us all own property name strings as well as
// symbols, so it is a bit more complete, but it is a newer JS API, so we
// fall back on `Object.getOwnPropertyNames()` in JS engines that don’t
// understand symbols yet (SpiderMonkey 1.8.5). It is a safe fallback
// because until then object keys can only be strings.
const propNames = getPropNames(object);
// Freeze properties before freezing self
for (var i in propNames) {
const value = object[propNames[i]];
if ((value && typeof value === "object") || typeof value === "function") {
deepFreeze(value);
}
}
}