This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
228 lines
9.1 KiB
228 lines
9.1 KiB
/* |
|
Copyright 2012-2015, Yahoo Inc. |
|
Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms. |
|
*/ |
|
var path = require('path'), |
|
vm = require('vm'), |
|
appendTransform = require('append-transform'), |
|
originalCreateScript = vm.createScript, |
|
originalRunInThisContext = vm.runInThisContext, |
|
originalRunInContext = vm.runInContext; |
|
|
|
function transformFn(matcher, transformer, verbose) { |
|
|
|
return function (code, options) { |
|
options = options || {}; |
|
if (typeof options === 'string') { |
|
options = { filename: options }; |
|
} |
|
|
|
var shouldHook = typeof options.filename === 'string' && matcher(path.resolve(options.filename)), |
|
transformed, |
|
changed = false; |
|
|
|
if (shouldHook) { |
|
if (verbose) { |
|
console.error('Module load hook: transform [' + options.filename + ']'); |
|
} |
|
try { |
|
transformed = transformer(code, options); |
|
changed = true; |
|
} catch (ex) { |
|
console.error('Transformation error for', options.filename, '; return original code'); |
|
console.error(ex.message || String(ex)); |
|
if (verbose) { |
|
console.error(ex.stack); |
|
} |
|
transformed = code; |
|
} |
|
} else { |
|
transformed = code; |
|
} |
|
return { code: transformed, changed: changed }; |
|
}; |
|
} |
|
/** |
|
* unloads the required caches, removing all files that would have matched |
|
* the supplied matcher. |
|
* @param {Function} matcher - the match function that accepts a file name and |
|
* returns if that file should be unloaded from the cache. |
|
*/ |
|
function unloadRequireCache(matcher) { |
|
/* istanbul ignore else: impossible to test */ |
|
if (matcher && typeof require !== 'undefined' && require && require.cache) { |
|
Object.keys(require.cache).forEach(function (filename) { |
|
if (matcher(filename)) { |
|
delete require.cache[filename]; |
|
} |
|
}); |
|
} |
|
} |
|
/** |
|
* hooks `require` to return transformed code to the node module loader. |
|
* Exceptions in the transform result in the original code being used instead. |
|
* @method hookRequire |
|
* @static |
|
* @param matcher {Function(filePath)} a function that is called with the absolute path to the file being |
|
* `require`-d. Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise |
|
* @param transformer {Function(code, filePath)} a function called with the original code and the associated path of the file |
|
* from where the code was loaded. Should return the transformed code. |
|
* @param options {Object} options Optional. |
|
* @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called |
|
* @param {Function} [options.postLoadHook] a function that is called with the name of the file being |
|
* required. This is called after the require is processed irrespective of whether it was transformed. |
|
* @returns {Function} a reset function that can be called to remove the hook |
|
*/ |
|
function hookRequire(matcher, transformer, options) { |
|
options = options || {}; |
|
var extensions, |
|
disable = false, |
|
fn = transformFn(matcher, transformer, options.verbose), |
|
postLoadHook = options.postLoadHook && |
|
typeof options.postLoadHook === 'function' ? options.postLoadHook : null; |
|
|
|
extensions = options.extensions || ['.js']; |
|
|
|
extensions.forEach(function(ext){ |
|
appendTransform(function (code, filename) { |
|
if (disable) { |
|
return code; |
|
} |
|
var ret = fn(code, filename); |
|
if (postLoadHook) { |
|
postLoadHook(filename); |
|
} |
|
return ret.code; |
|
}, ext); |
|
}); |
|
|
|
return function () { |
|
disable = true; |
|
}; |
|
} |
|
/** |
|
* hooks `vm.createScript` to return transformed code out of which a `Script` object will be created. |
|
* Exceptions in the transform result in the original code being used instead. |
|
* @method hookCreateScript |
|
* @static |
|
* @param matcher {Function(filePath)} a function that is called with the filename passed to `vm.createScript` |
|
* Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise |
|
* @param transformer {Function(code, filePath)} a function called with the original code and the filename passed to |
|
* `vm.createScript`. Should return the transformed code. |
|
* @param options {Object} options Optional. |
|
* @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called |
|
*/ |
|
function hookCreateScript(matcher, transformer, opts) { |
|
opts = opts || {}; |
|
var fn = transformFn(matcher, transformer, opts.verbose); |
|
vm.createScript = function (code, file) { |
|
var ret = fn(code, file); |
|
return originalCreateScript(ret.code, file); |
|
}; |
|
} |
|
/** |
|
* unhooks vm.createScript, restoring it to its original state. |
|
* @method unhookCreateScript |
|
* @static |
|
*/ |
|
function unhookCreateScript() { |
|
vm.createScript = originalCreateScript; |
|
} |
|
/** |
|
* hooks `vm.runInThisContext` to return transformed code. |
|
* @method hookRunInThisContext |
|
* @static |
|
* @param matcher {Function(filePath)} a function that is called with the filename passed to `vm.runInThisContext` |
|
* Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise |
|
* @param transformer {Function(code, options)} a function called with the original code and the filename passed to |
|
* `vm.runInThisContext`. Should return the transformed code. |
|
* @param opts {Object} [opts={}] options |
|
* @param {Boolean} [opts.verbose] write a line to standard error every time the transformer is called |
|
*/ |
|
function hookRunInThisContext(matcher, transformer, opts) { |
|
opts = opts || {}; |
|
var fn = transformFn(matcher, transformer, opts.verbose); |
|
vm.runInThisContext = function (code, options) { |
|
var ret = fn(code, options); |
|
return originalRunInThisContext(ret.code, options); |
|
}; |
|
} |
|
/** |
|
* unhooks vm.runInThisContext, restoring it to its original state. |
|
* @method unhookRunInThisContext |
|
* @static |
|
*/ |
|
function unhookRunInThisContext() { |
|
vm.runInThisContext = originalRunInThisContext; |
|
} |
|
/** |
|
* hooks `vm.runInContext` to return transformed code. |
|
* @method hookRunInContext |
|
* @static |
|
* @param matcher {Function(filePath)} a function that is called with the filename passed to `vm.createScript` |
|
* Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise |
|
* @param transformer {Function(code, filePath)} a function called with the original code and the filename passed to |
|
* `vm.createScript`. Should return the transformed code. |
|
* @param opts {Object} [opts={}] options |
|
* @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called |
|
*/ |
|
function hookRunInContext(matcher, transformer, opts) { |
|
opts = opts || {}; |
|
var fn = transformFn(matcher, transformer, opts.verbose); |
|
vm.runInContext = function (code, context, file) { |
|
var ret = fn(code, file); |
|
var coverageVariable = opts.coverageVariable || '__coverage__'; |
|
// Refer coverage variable in context to global coverage variable. |
|
// So that coverage data will be written in global coverage variable for unit tests run in vm.runInContext. |
|
// If all unit tests are run in vm.runInContext, no global coverage variable will be generated. |
|
// Thus initialize a global coverage variable here. |
|
if (!global[coverageVariable]) { |
|
global[coverageVariable] = {}; |
|
} |
|
context[coverageVariable] = global[coverageVariable]; |
|
return originalRunInContext(ret.code, context, file); |
|
}; |
|
|
|
} |
|
/** |
|
* unhooks vm.runInContext, restoring it to its original state. |
|
* @method unhookRunInContext |
|
* @static |
|
*/ |
|
function unhookRunInContext() { |
|
vm.runInContext = originalRunInContext; |
|
} |
|
/** |
|
* istanbul-lib-hook provides mechanisms to transform code in the scope of `require`, |
|
* `vm.createScript`, `vm.runInThisContext` etc. |
|
* |
|
* This mechanism is general and relies on a user-supplied `matcher` function that |
|
* determines when transformations should be performed and a user-supplied `transformer` |
|
* function that performs the actual transform. Instrumenting code for coverage is |
|
* one specific example of useful hooking. |
|
* |
|
* Note that both the `matcher` and `transformer` must execute synchronously. |
|
* |
|
* @module Exports |
|
* @example |
|
* var hook = require('istanbul-lib-hook'), |
|
* myMatcher = function (file) { return file.match(/foo/); }, |
|
* myTransformer = function (code, file) { |
|
* return 'console.log("' + file + '");' + code; |
|
* }; |
|
* |
|
* hook.hookRequire(myMatcher, myTransformer); |
|
* var foo = require('foo'); //will now print foo's module path to console |
|
*/ |
|
module.exports = { |
|
hookRequire: hookRequire, |
|
hookCreateScript: hookCreateScript, |
|
unhookCreateScript: unhookCreateScript, |
|
hookRunInThisContext : hookRunInThisContext, |
|
unhookRunInThisContext : unhookRunInThisContext, |
|
hookRunInContext : hookRunInContext, |
|
unhookRunInContext : unhookRunInContext, |
|
unloadRequireCache: unloadRequireCache |
|
}; |
|
|
|
|
|
|