| // 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) { |
| if (!source) throw(["error","not_found","missing function"]); |
| |
| var functionObject = null; |
| var 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 " + |
| (e.toSource ? e.toSource() : e.stack) |
| ]; |
| } |
| 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") { |
| functionObject = evalcx(source, sandbox, name); |
| } else { |
| var transpiled = CoffeeScript.compile(source, {bare: true}); |
| functionObject = evalcx(transpiled, sandbox, name); |
| } |
| } catch (err) { |
| throw([ |
| "error", |
| "compilation_error", |
| (err.toSource ? err.toSource() : err.stack) + " (" + source + ")" |
| ]); |
| }; |
| if (typeof(functionObject) == "function") { |
| return functionObject; |
| } else { |
| throw(["error","compilation_error", |
| "Expression does not eval to a function. (" + source.toString() + ")"]); |
| }; |
| }, |
| recursivelySeal : function(obj) { |
| // seal() is broken in current Spidermonkey |
| try { |
| seal(obj); |
| } catch (x) { |
| // Sealing of arrays broken in some SpiderMonkey versions. |
| // https://bugzilla.mozilla.org/show_bug.cgi?id=449657 |
| } |
| for (var propname in obj) { |
| if (typeof obj[propname] == "object") { |
| arguments.callee(obj[propname]); |
| } |
| } |
| } |
| }; |
| |
| // 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.toSource ? obj.toSource() : 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(message); |
| } |
| respond(["log", String(message)]); |
| }; |
| |
| function isArray(obj) { |
| return toString.call(obj) === "[object Array]"; |
| } |