1 | var fs = require('graceful-fs')
|
2 | var crypto = require('crypto')
|
3 | var mm = require('minimatch')
|
4 | var isBinaryFile = require('isbinaryfile')
|
5 | var combineLists = require('combine-lists')
|
6 |
|
7 | var log = require('./logger').create('preprocess')
|
8 |
|
9 | var sha1 = function (data) {
|
10 | var hash = crypto.createHash('sha1')
|
11 | hash.update(data)
|
12 | return hash.digest('hex')
|
13 | }
|
14 |
|
15 | var createNextProcessor = function (preprocessors, file, done) {
|
16 | return function nextPreprocessor (error, content) {
|
17 |
|
18 | if (arguments.length === 1 && typeof error === 'string') {
|
19 | content = error
|
20 | error = null
|
21 | }
|
22 |
|
23 | if (error) {
|
24 | file.content = null
|
25 | file.contentPath = null
|
26 | return done(error)
|
27 | }
|
28 |
|
29 | if (!preprocessors.length) {
|
30 | file.contentPath = null
|
31 | file.content = content
|
32 | file.sha = sha1(content)
|
33 | return done()
|
34 | }
|
35 |
|
36 | preprocessors.shift()(content, file, nextPreprocessor)
|
37 | }
|
38 | }
|
39 |
|
40 | var createPreprocessor = function (config, basePath, injector) {
|
41 | var alreadyDisplayedErrors = {}
|
42 | var instances = {}
|
43 | var patterns = Object.keys(config)
|
44 |
|
45 | var emitter = injector.get('emitter')
|
46 |
|
47 | var instantiatePreprocessor = function (name) {
|
48 | if (alreadyDisplayedErrors[name]) {
|
49 | return
|
50 | }
|
51 |
|
52 | var p
|
53 |
|
54 | try {
|
55 | p = injector.get('preprocessor:' + name)
|
56 | } catch (e) {
|
57 | if (e.message.indexOf('No provider for "preprocessor:' + name + '"') !== -1) {
|
58 | log.error('Can not load "%s", it is not registered!\n ' +
|
59 | 'Perhaps you are missing some plugin?', name)
|
60 | } else {
|
61 | log.error('Can not load "%s"!\n ' + e.stack, name)
|
62 | }
|
63 | alreadyDisplayedErrors[name] = true
|
64 | emitter.emit('load_error', 'preprocessor', name)
|
65 | }
|
66 |
|
67 | return p
|
68 | }
|
69 |
|
70 | var allPreprocessors = []
|
71 | patterns.forEach(function (pattern) {
|
72 | allPreprocessors = combineLists(allPreprocessors, config[pattern])
|
73 | })
|
74 | allPreprocessors.forEach(instantiatePreprocessor)
|
75 |
|
76 | return function preprocess (file, done) {
|
77 | patterns = Object.keys(config)
|
78 | var retryCount = 0
|
79 | var maxRetries = 3
|
80 | function readFileCallback (err, buffer) {
|
81 | if (err) {
|
82 | log.warn(err)
|
83 | if (retryCount < maxRetries) {
|
84 | retryCount++
|
85 | log.warn('retrying ' + retryCount)
|
86 | fs.readFile(file.originalPath, readFileCallback)
|
87 | return
|
88 | } else {
|
89 | throw err
|
90 | }
|
91 | }
|
92 |
|
93 | isBinaryFile(buffer, buffer.length, function (err, thisFileIsBinary) {
|
94 | if (err) {
|
95 | throw err
|
96 | }
|
97 |
|
98 | var preprocessorNames = []
|
99 | for (var i = 0; i < patterns.length; i++) {
|
100 | if (mm(file.originalPath, patterns[i], {dot: true})) {
|
101 | if (thisFileIsBinary) {
|
102 | log.warn('Ignoring preprocessing (%s) %s because it is a binary file.',
|
103 | config[patterns[i]].join(', '), file.originalPath)
|
104 | } else {
|
105 | preprocessorNames = combineLists(preprocessorNames, config[patterns[i]])
|
106 | }
|
107 | }
|
108 | }
|
109 |
|
110 | var preprocessors = []
|
111 | var nextPreprocessor = createNextProcessor(preprocessors, file, done)
|
112 | preprocessorNames.forEach(function (name) {
|
113 | var p = instances[name]
|
114 | if (p == null) {
|
115 | p = instantiatePreprocessor(name)
|
116 | }
|
117 |
|
118 | if (p == null) {
|
119 | if (!alreadyDisplayedErrors[name]) {
|
120 | alreadyDisplayedErrors[name] = true
|
121 | log.error('Failed to instantiate preprocessor %s', name)
|
122 | emitter.emit('load_error', 'preprocessor', name)
|
123 | }
|
124 | return
|
125 | }
|
126 |
|
127 | instances[name] = p
|
128 | preprocessors.push(p)
|
129 | })
|
130 |
|
131 | nextPreprocessor(null, thisFileIsBinary ? buffer : buffer.toString())
|
132 | })
|
133 | }
|
134 | return fs.readFile(file.originalPath, readFileCallback)
|
135 | }
|
136 | }
|
137 | createPreprocessor.$inject = ['config.preprocessors', 'config.basePath', 'injector']
|
138 |
|
139 | exports.createPreprocessor = createPreprocessor
|