blob: 61c34e065542e1639ffef8154b68bd22b9fbc7d0 [file] [log] [blame]
'use strict'
const fs = require('graceful-fs')
const mm = require('minimatch')
const isBinaryFile = require('isbinaryfile')
const _ = require('lodash')
const CryptoUtils = require('./utils/crypto-utils')
const log = require('./logger').create('preprocess')
function createNextProcessor (preprocessors, file, done) {
return function nextPreprocessor (error, content) {
// normalize B-C
if (arguments.length === 1 && typeof error === 'string') {
content = error
error = null
}
if (error) {
file.content = null
file.contentPath = null
return done(error)
}
if (!preprocessors.length) {
file.contentPath = null
file.content = content
file.sha = CryptoUtils.sha1(content)
return done()
}
preprocessors.shift()(content, file, nextPreprocessor)
}
}
function createPreprocessor (config, basePath, injector) {
const emitter = injector.get('emitter')
const alreadyDisplayedErrors = {}
const instances = {}
let patterns = Object.keys(config)
function instantiatePreprocessor (name) {
if (alreadyDisplayedErrors[name]) {
return
}
let p
try {
p = injector.get('preprocessor:' + name)
} catch (e) {
if (e.message.includes(`No provider for "preprocessor:${name}"`)) {
log.error(`Can not load "${name}", it is not registered!\n Perhaps you are missing some plugin?`)
} else {
log.error(`Can not load "${name}"!\n ` + e.stack)
}
alreadyDisplayedErrors[name] = true
emitter.emit('load_error', 'preprocessor', name)
}
return p
}
let allPreprocessors = []
patterns.forEach((pattern) => {
allPreprocessors = _.union(allPreprocessors, config[pattern])
})
allPreprocessors.forEach(instantiatePreprocessor)
return function preprocess (file, done) {
patterns = Object.keys(config)
let retryCount = 0
let maxRetries = 3
function readFileCallback (err, buffer) {
if (err) {
log.warn(err)
if (retryCount < maxRetries) {
retryCount++
log.warn('retrying ' + retryCount)
fs.readFile(file.originalPath, readFileCallback)
return
} else {
throw err
}
}
isBinaryFile(buffer, buffer.length, function (err, isBinary) {
if (err) {
throw err
}
let preprocessorNames = []
patterns.forEach((pattern) => {
if (mm(file.originalPath, pattern, { dot: true })) {
preprocessorNames = _.union(preprocessorNames, config[pattern])
}
})
let preprocessors = []
const nextPreprocessor = createNextProcessor(preprocessors, file, done)
preprocessorNames.forEach((name) => {
const p = instances[name] || instantiatePreprocessor(name)
if (p == null) {
if (!alreadyDisplayedErrors[name]) {
alreadyDisplayedErrors[name] = true
log.error(`Failed to instantiate preprocessor ${name}`)
emitter.emit('load_error', 'preprocessor', name)
}
return
}
instances[name] = p
if (!isBinary || p.handleBinaryFiles) {
preprocessors.push(p)
} else {
log.warn(`Ignored preprocessing ${file.originalPath} because ${name} has handleBinaryFiles=false.`)
}
})
nextPreprocessor(null, isBinary ? buffer : buffer.toString())
})
}
return fs.readFile(file.originalPath, readFileCallback)
}
}
createPreprocessor.$inject = ['config.preprocessors', 'config.basePath', 'injector']
exports.createPreprocessor = createPreprocessor