index.js 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. 'use strict'
  2. function isFunction (funktion) {
  3. return typeof funktion === 'function'
  4. }
  5. // Default to complaining loudly when things don't go according to plan.
  6. var logger = console.error.bind(console)
  7. // Sets a property on an object, preserving its enumerability.
  8. // This function assumes that the property is already writable.
  9. function defineProperty (obj, name, value) {
  10. var enumerable = !!obj[name] && obj.propertyIsEnumerable(name)
  11. Object.defineProperty(obj, name, {
  12. configurable: true,
  13. enumerable: enumerable,
  14. writable: true,
  15. value: value
  16. })
  17. }
  18. // Keep initialization idempotent.
  19. function shimmer (options) {
  20. if (options && options.logger) {
  21. if (!isFunction(options.logger)) logger("new logger isn't a function, not replacing")
  22. else logger = options.logger
  23. }
  24. }
  25. function wrap (nodule, name, wrapper) {
  26. if (!nodule || !nodule[name]) {
  27. logger('no original function ' + name + ' to wrap')
  28. return
  29. }
  30. if (!wrapper) {
  31. logger('no wrapper function')
  32. logger((new Error()).stack)
  33. return
  34. }
  35. if (!isFunction(nodule[name]) || !isFunction(wrapper)) {
  36. logger('original object and wrapper must be functions')
  37. return
  38. }
  39. var original = nodule[name]
  40. var wrapped = wrapper(original, name)
  41. defineProperty(wrapped, '__original', original)
  42. defineProperty(wrapped, '__unwrap', function () {
  43. if (nodule[name] === wrapped) defineProperty(nodule, name, original)
  44. })
  45. defineProperty(wrapped, '__wrapped', true)
  46. defineProperty(nodule, name, wrapped)
  47. return wrapped
  48. }
  49. function massWrap (nodules, names, wrapper) {
  50. if (!nodules) {
  51. logger('must provide one or more modules to patch')
  52. logger((new Error()).stack)
  53. return
  54. } else if (!Array.isArray(nodules)) {
  55. nodules = [nodules]
  56. }
  57. if (!(names && Array.isArray(names))) {
  58. logger('must provide one or more functions to wrap on modules')
  59. return
  60. }
  61. nodules.forEach(function (nodule) {
  62. names.forEach(function (name) {
  63. wrap(nodule, name, wrapper)
  64. })
  65. })
  66. }
  67. function unwrap (nodule, name) {
  68. if (!nodule || !nodule[name]) {
  69. logger('no function to unwrap.')
  70. logger((new Error()).stack)
  71. return
  72. }
  73. if (!nodule[name].__unwrap) {
  74. logger('no original to unwrap to -- has ' + name + ' already been unwrapped?')
  75. } else {
  76. return nodule[name].__unwrap()
  77. }
  78. }
  79. function massUnwrap (nodules, names) {
  80. if (!nodules) {
  81. logger('must provide one or more modules to patch')
  82. logger((new Error()).stack)
  83. return
  84. } else if (!Array.isArray(nodules)) {
  85. nodules = [nodules]
  86. }
  87. if (!(names && Array.isArray(names))) {
  88. logger('must provide one or more functions to unwrap on modules')
  89. return
  90. }
  91. nodules.forEach(function (nodule) {
  92. names.forEach(function (name) {
  93. unwrap(nodule, name)
  94. })
  95. })
  96. }
  97. shimmer.wrap = wrap
  98. shimmer.massWrap = massWrap
  99. shimmer.unwrap = unwrap
  100. shimmer.massUnwrap = massUnwrap
  101. module.exports = shimmer