preprocessor.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. 'use strict'
  2. const fs = require('graceful-fs')
  3. const mm = require('minimatch')
  4. const isBinaryFile = require('isbinaryfile')
  5. const _ = require('lodash')
  6. const CryptoUtils = require('./utils/crypto-utils')
  7. const log = require('./logger').create('preprocess')
  8. function createNextProcessor (preprocessors, file, done) {
  9. return function nextPreprocessor (error, content) {
  10. // normalize B-C
  11. if (arguments.length === 1 && typeof error === 'string') {
  12. content = error
  13. error = null
  14. }
  15. if (error) {
  16. file.content = null
  17. file.contentPath = null
  18. return done(error)
  19. }
  20. if (!preprocessors.length) {
  21. file.contentPath = null
  22. file.content = content
  23. file.sha = CryptoUtils.sha1(content)
  24. return done()
  25. }
  26. preprocessors.shift()(content, file, nextPreprocessor)
  27. }
  28. }
  29. function createPreprocessor (config, basePath, injector) {
  30. const emitter = injector.get('emitter')
  31. const alreadyDisplayedErrors = {}
  32. const instances = {}
  33. let patterns = Object.keys(config)
  34. function instantiatePreprocessor (name) {
  35. if (alreadyDisplayedErrors[name]) {
  36. return
  37. }
  38. let p
  39. try {
  40. p = injector.get('preprocessor:' + name)
  41. } catch (e) {
  42. if (e.message.includes(`No provider for "preprocessor:${name}"`)) {
  43. log.error(`Can not load "${name}", it is not registered!\n Perhaps you are missing some plugin?`)
  44. } else {
  45. log.error(`Can not load "${name}"!\n ` + e.stack)
  46. }
  47. alreadyDisplayedErrors[name] = true
  48. emitter.emit('load_error', 'preprocessor', name)
  49. }
  50. return p
  51. }
  52. let allPreprocessors = []
  53. patterns.forEach((pattern) => {
  54. allPreprocessors = _.union(allPreprocessors, config[pattern])
  55. })
  56. allPreprocessors.forEach(instantiatePreprocessor)
  57. return function preprocess (file, done) {
  58. patterns = Object.keys(config)
  59. let retryCount = 0
  60. let maxRetries = 3
  61. function readFileCallback (err, buffer) {
  62. if (err) {
  63. log.warn(err)
  64. if (retryCount < maxRetries) {
  65. retryCount++
  66. log.warn('retrying ' + retryCount)
  67. fs.readFile(file.originalPath, readFileCallback)
  68. return
  69. } else {
  70. throw err
  71. }
  72. }
  73. isBinaryFile(buffer, buffer.length, function (err, isBinary) {
  74. if (err) {
  75. throw err
  76. }
  77. let preprocessorNames = []
  78. patterns.forEach((pattern) => {
  79. if (mm(file.originalPath, pattern, {dot: true})) {
  80. preprocessorNames = _.union(preprocessorNames, config[pattern])
  81. }
  82. })
  83. let preprocessors = []
  84. const nextPreprocessor = createNextProcessor(preprocessors, file, done)
  85. preprocessorNames.forEach((name) => {
  86. const p = instances[name] || instantiatePreprocessor(name)
  87. if (p == null) {
  88. if (!alreadyDisplayedErrors[name]) {
  89. alreadyDisplayedErrors[name] = true
  90. log.error(`Failed to instantiate preprocessor ${name}`)
  91. emitter.emit('load_error', 'preprocessor', name)
  92. }
  93. return
  94. }
  95. instances[name] = p
  96. if (!isBinary || p.handleBinaryFiles) {
  97. preprocessors.push(p)
  98. } else {
  99. log.warn(`Ignored preprocessing ${file.originalPath} because ${name} has handleBinaryFiles=false.`)
  100. }
  101. })
  102. nextPreprocessor(null, isBinary ? buffer : buffer.toString())
  103. })
  104. }
  105. return fs.readFile(file.originalPath, readFileCallback)
  106. }
  107. }
  108. createPreprocessor.$inject = ['config.preprocessors', 'config.basePath', 'injector']
  109. exports.createPreprocessor = createPreprocessor