| '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 |