index.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. const path = require('path')
  2. const log = require('./util/log')
  3. const report = require('./reports')
  4. const matcher = require('./util/matcher')
  5. const Group = report.Group
  6. const Backup = require('./backup')
  7. // Backup source directory
  8. var backupDirectory = path.join(process.env.HOME, '/Library/Application Support/MobileSync/Backup/')
  9. // Object containing all report modules
  10. var moduleCache = report.types
  11. // Array of plugin modules
  12. var plugins = []
  13. /**
  14. * Add an array of plugins to the plugins list.
  15. * @param {Array<Object>} array contains array of plugin objects.
  16. */
  17. function registerModule (array) {
  18. if (!(array instanceof Array)) {
  19. array = [ array ]
  20. }
  21. plugins.push(...array)
  22. moduleCache = getCompleteModuleList()
  23. }
  24. /**
  25. * Remove all non-default plugins.
  26. */
  27. function clearModules () {
  28. plugins = []
  29. moduleCache = getCompleteModuleList()
  30. }
  31. /**
  32. * Get all modules in a top-down manner.
  33. */
  34. function getCompleteModuleList () {
  35. let allModules = {}
  36. // Add all of the require()'d modules into the plugins list.
  37. plugins.forEach(function (plugin) {
  38. allModules = { ...allModules, ...plugin }
  39. })
  40. // Add all of the modules to a single object.
  41. // JS's behavior dictates that the items are added sequentially
  42. // So, the default reports overwrite any third party plugin.
  43. let result = {
  44. ...allModules,
  45. ...report.types
  46. }
  47. moduleCache = result
  48. return result
  49. }
  50. /**
  51. * Try to find a single report.
  52. * @param {string} query name to find.
  53. */
  54. function findReport (query) {
  55. return new Promise((resolve, reject) => {
  56. // Check there is no wildcard in the query.
  57. if (query.indexOf('*') > -1) {
  58. return reject(new Error('Cannot run a wildcard match here.'))
  59. }
  60. // Run matches.
  61. let matches = matcher(moduleCache, query, (el) => !(el instanceof Group))
  62. // If no report found, fail.
  63. if (matches.length === 0) {
  64. return reject(new Error(`No report found with name "${query}"`))
  65. }
  66. // If multiple matches, fail.
  67. if (matches.length > 1) {
  68. return reject(new Error(`Multiple report matches for name "${query}", not allowed.`))
  69. }
  70. // Resolve match
  71. resolve(matches[0])
  72. })
  73. }
  74. /**
  75. * Translate the raw output of a report to the correct result, based on the "raw" parameter.
  76. * @param {Object} report The report module
  77. * @param {Object} result Raw data output from the aforementioned report
  78. * @param {Object} params parameters object.
  79. */
  80. function compileReport (report, result, { raw }) {
  81. return new Promise((resolve, reject) => {
  82. if (!raw && report.output) {
  83. if (result instanceof Array) {
  84. log.verbose('compiling report (array)...')
  85. // if it's an array, translate each item.
  86. result = result.map(item => {
  87. // For each item, run the functions on the entry.
  88. let editedResult = {}
  89. for (let [key, value] of Object.entries(report.output)) {
  90. editedResult[key] = value(item)
  91. }
  92. return editedResult
  93. })
  94. resolve(result)
  95. } else {
  96. log.verbose('compiling report (single)...')
  97. // Otherwise, translate the object returned.
  98. let editedResult = {}
  99. for (let [key, value] of Object.entries(report.output)) {
  100. editedResult[key] = value(result)
  101. }
  102. resolve(editedResult)
  103. }
  104. } else {
  105. resolve(result)
  106. }
  107. })
  108. }
  109. /**
  110. * Run a named report and resolve to it's output.
  111. * The output is formatted based on the `report.output` key, if the params.raw option is NOT set to true.
  112. * @param {string} query report name
  113. * @param {Object=} params parameters.
  114. */
  115. function run (query, params) {
  116. params = params || {}
  117. return new Promise(async (resolve, reject) => {
  118. try {
  119. let report = await findReport(query)
  120. let result = await runReport(report, params)
  121. let compiled = await compileReport(report, result, params)
  122. resolve(compiled)
  123. } catch (e) {
  124. reject(e)
  125. }
  126. })
  127. }
  128. /**
  129. * Run a report
  130. * @param {object} report report module
  131. * @param {object=} params parameters
  132. */
  133. function runReport (report, params) {
  134. params = params || {}
  135. return new Promise((resolve, reject) => {
  136. var backup
  137. // Cannot run < v3 backups in this manner.
  138. if (!report.version || report.version < 3) {
  139. return reject(new Error(`Cannot call ${report.name} as a module, it is not updated to the v3 api`))
  140. }
  141. // If it requires a backup and none is provided, reject.
  142. if (report.requiresBackup) {
  143. if (!params.backup) {
  144. return reject(new Error('Please specify the `backup` parameter to run this report.'))
  145. }
  146. backup = new Backup(backupDirectory, params.backup)
  147. }
  148. // Input params to func
  149. let inputParams = {
  150. ...params,
  151. backup
  152. }
  153. report.run(module.exports, inputParams)
  154. .then(resolve)
  155. .catch(reject)
  156. })
  157. }
  158. module.exports = {
  159. // Exported Libraries
  160. Backup,
  161. Group,
  162. // Module management
  163. registerModule,
  164. clearModules,
  165. get modules () {
  166. return moduleCache
  167. },
  168. // Source directory
  169. set base (value) {
  170. backupDirectory = value
  171. },
  172. get base () {
  173. return backupDirectory
  174. },
  175. // Runners
  176. run,
  177. findReport,
  178. runReport,
  179. compileReport,
  180. // misc
  181. setLogLevel (lvl) {
  182. log.setVerbose(lvl)
  183. }
  184. }