Software zum Installieren eines Smart-Mirror Frameworks , zum Nutzen von hochschulrelevanten Informationen, auf einem Raspberry-Pi.
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.

hook.js 9.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. 'use strict';
  2. /*
  3. Copyright 2012-2015, Yahoo Inc.
  4. Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
  5. */
  6. const path = require('path');
  7. const vm = require('vm');
  8. const appendTransform = require('append-transform');
  9. const originalCreateScript = vm.createScript;
  10. const originalRunInThisContext = vm.runInThisContext;
  11. const originalRunInContext = vm.runInContext;
  12. function transformFn(matcher, transformer, verbose) {
  13. return function(code, options) {
  14. options = options || {};
  15. // prior to 2.x, hookRequire returned filename
  16. // rather than object.
  17. if (typeof options === 'string') {
  18. options = { filename: options };
  19. }
  20. const shouldHook =
  21. typeof options.filename === 'string' &&
  22. matcher(path.resolve(options.filename));
  23. let transformed;
  24. let changed = false;
  25. if (shouldHook) {
  26. if (verbose) {
  27. console.error(
  28. 'Module load hook: transform [' + options.filename + ']'
  29. );
  30. }
  31. try {
  32. transformed = transformer(code, options);
  33. changed = true;
  34. } catch (ex) {
  35. console.error(
  36. 'Transformation error for',
  37. options.filename,
  38. '; return original code'
  39. );
  40. console.error(ex.message || String(ex));
  41. if (verbose) {
  42. console.error(ex.stack);
  43. }
  44. transformed = code;
  45. }
  46. } else {
  47. transformed = code;
  48. }
  49. return { code: transformed, changed };
  50. };
  51. }
  52. /**
  53. * unloads the required caches, removing all files that would have matched
  54. * the supplied matcher.
  55. * @param {Function} matcher - the match function that accepts a file name and
  56. * returns if that file should be unloaded from the cache.
  57. */
  58. function unloadRequireCache(matcher) {
  59. /* istanbul ignore else: impossible to test */
  60. if (matcher && typeof require !== 'undefined' && require && require.cache) {
  61. Object.keys(require.cache).forEach(filename => {
  62. if (matcher(filename)) {
  63. delete require.cache[filename];
  64. }
  65. });
  66. }
  67. }
  68. /**
  69. * hooks `require` to return transformed code to the node module loader.
  70. * Exceptions in the transform result in the original code being used instead.
  71. * @method hookRequire
  72. * @static
  73. * @param matcher {Function(filePath)} a function that is called with the absolute path to the file being
  74. * `require`-d. Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise
  75. * @param transformer {Function(code, filePath)} a function called with the original code and the associated path of the file
  76. * from where the code was loaded. Should return the transformed code.
  77. * @param options {Object} options Optional.
  78. * @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called
  79. * @param {Function} [options.postLoadHook] a function that is called with the name of the file being
  80. * required. This is called after the require is processed irrespective of whether it was transformed.
  81. * @returns {Function} a reset function that can be called to remove the hook
  82. */
  83. function hookRequire(matcher, transformer, options) {
  84. options = options || {};
  85. let disable = false;
  86. const fn = transformFn(matcher, transformer, options.verbose);
  87. const postLoadHook =
  88. options.postLoadHook && typeof options.postLoadHook === 'function'
  89. ? options.postLoadHook
  90. : null;
  91. const extensions = options.extensions || ['.js'];
  92. extensions.forEach(ext => {
  93. appendTransform((code, filename) => {
  94. if (disable) {
  95. return code;
  96. }
  97. const ret = fn(code, filename);
  98. if (postLoadHook) {
  99. postLoadHook(filename);
  100. }
  101. return ret.code;
  102. }, ext);
  103. });
  104. return function() {
  105. disable = true;
  106. };
  107. }
  108. /**
  109. * hooks `vm.createScript` to return transformed code out of which a `Script` object will be created.
  110. * Exceptions in the transform result in the original code being used instead.
  111. * @method hookCreateScript
  112. * @static
  113. * @param matcher {Function(filePath)} a function that is called with the filename passed to `vm.createScript`
  114. * Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise
  115. * @param transformer {Function(code, filePath)} a function called with the original code and the filename passed to
  116. * `vm.createScript`. Should return the transformed code.
  117. * @param options {Object} options Optional.
  118. * @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called
  119. */
  120. function hookCreateScript(matcher, transformer, opts) {
  121. opts = opts || {};
  122. const fn = transformFn(matcher, transformer, opts.verbose);
  123. vm.createScript = function(code, file) {
  124. const ret = fn(code, file);
  125. return originalCreateScript(ret.code, file);
  126. };
  127. }
  128. /**
  129. * unhooks vm.createScript, restoring it to its original state.
  130. * @method unhookCreateScript
  131. * @static
  132. */
  133. function unhookCreateScript() {
  134. vm.createScript = originalCreateScript;
  135. }
  136. /**
  137. * hooks `vm.runInThisContext` to return transformed code.
  138. * @method hookRunInThisContext
  139. * @static
  140. * @param matcher {Function(filePath)} a function that is called with the filename passed to `vm.runInThisContext`
  141. * Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise
  142. * @param transformer {Function(code, options)} a function called with the original code and the filename passed to
  143. * `vm.runInThisContext`. Should return the transformed code.
  144. * @param opts {Object} [opts={}] options
  145. * @param {Boolean} [opts.verbose] write a line to standard error every time the transformer is called
  146. */
  147. function hookRunInThisContext(matcher, transformer, opts) {
  148. opts = opts || {};
  149. const fn = transformFn(matcher, transformer, opts.verbose);
  150. vm.runInThisContext = function(code, options) {
  151. const ret = fn(code, options);
  152. return originalRunInThisContext(ret.code, options);
  153. };
  154. }
  155. /**
  156. * unhooks vm.runInThisContext, restoring it to its original state.
  157. * @method unhookRunInThisContext
  158. * @static
  159. */
  160. function unhookRunInThisContext() {
  161. vm.runInThisContext = originalRunInThisContext;
  162. }
  163. /**
  164. * hooks `vm.runInContext` to return transformed code.
  165. * @method hookRunInContext
  166. * @static
  167. * @param matcher {Function(filePath)} a function that is called with the filename passed to `vm.createScript`
  168. * Should return a truthy value when transformations need to be applied to the code, a falsy value otherwise
  169. * @param transformer {Function(code, filePath)} a function called with the original code and the filename passed to
  170. * `vm.createScript`. Should return the transformed code.
  171. * @param opts {Object} [opts={}] options
  172. * @param {Boolean} [options.verbose] write a line to standard error every time the transformer is called
  173. */
  174. function hookRunInContext(matcher, transformer, opts) {
  175. opts = opts || {};
  176. const fn = transformFn(matcher, transformer, opts.verbose);
  177. vm.runInContext = function(code, context, file) {
  178. const ret = fn(code, file);
  179. const coverageVariable = opts.coverageVariable || '__coverage__';
  180. // Refer coverage variable in context to global coverage variable.
  181. // So that coverage data will be written in global coverage variable for unit tests run in vm.runInContext.
  182. // If all unit tests are run in vm.runInContext, no global coverage variable will be generated.
  183. // Thus initialize a global coverage variable here.
  184. if (!global[coverageVariable]) {
  185. global[coverageVariable] = {};
  186. }
  187. context[coverageVariable] = global[coverageVariable];
  188. return originalRunInContext(ret.code, context, file);
  189. };
  190. }
  191. /**
  192. * unhooks vm.runInContext, restoring it to its original state.
  193. * @method unhookRunInContext
  194. * @static
  195. */
  196. function unhookRunInContext() {
  197. vm.runInContext = originalRunInContext;
  198. }
  199. /**
  200. * istanbul-lib-hook provides mechanisms to transform code in the scope of `require`,
  201. * `vm.createScript`, `vm.runInThisContext` etc.
  202. *
  203. * This mechanism is general and relies on a user-supplied `matcher` function that
  204. * determines when transformations should be performed and a user-supplied `transformer`
  205. * function that performs the actual transform. Instrumenting code for coverage is
  206. * one specific example of useful hooking.
  207. *
  208. * Note that both the `matcher` and `transformer` must execute synchronously.
  209. *
  210. * @module Exports
  211. * @example
  212. * var hook = require('istanbul-lib-hook'),
  213. * myMatcher = function (file) { return file.match(/foo/); },
  214. * myTransformer = function (code, file) {
  215. * return 'console.log("' + file + '");' + code;
  216. * };
  217. *
  218. * hook.hookRequire(myMatcher, myTransformer);
  219. * var foo = require('foo'); //will now print foo's module path to console
  220. */
  221. module.exports = {
  222. hookRequire,
  223. hookCreateScript,
  224. unhookCreateScript,
  225. hookRunInThisContext,
  226. unhookRunInThisContext,
  227. hookRunInContext,
  228. unhookRunInContext,
  229. unloadRequireCache
  230. };