1 | 'use strict';
|
2 |
|
3 | var fs = require('fs-extra'),
|
4 | path = require('path'),
|
5 | Plugin = require('broccoli-plugin'),
|
6 | hashStrings = require('broccoli-kitchen-sink-helpers').hashStrings;
|
7 |
|
8 | function ConfigReplace(inputNode, configNode, options) {
|
9 | options = options || {};
|
10 |
|
11 |
|
12 | Plugin.call(this, [inputNode, configNode], {
|
13 | annotation: options.annotation
|
14 | });
|
15 |
|
16 | this.options = options;
|
17 | this._cache = {};
|
18 | }
|
19 |
|
20 | ConfigReplace.prototype = Object.create(Plugin.prototype);
|
21 | ConfigReplace.prototype.constructor = ConfigReplace;
|
22 |
|
23 | ConfigReplace.prototype.build = function () {
|
24 | var inputPath = this.inputPaths[0],
|
25 | config = this.getConfig();
|
26 |
|
27 | this.options.files.forEach(function(file) {
|
28 | var key = this.deriveCacheKey(file),
|
29 | entry = this._cache[key.hash],
|
30 | contents, filePath;
|
31 |
|
32 | if (entry) {
|
33 | filePath = entry.file;
|
34 | contents = entry.contents
|
35 | } else {
|
36 | filePath = file;
|
37 | contents = this.processFile(config, filePath);
|
38 | this.updateCache(key, contents);
|
39 | }
|
40 |
|
41 | filePath = path.join(this.outputPath, filePath);
|
42 | this.writeFile(filePath, contents);
|
43 | }, this);
|
44 | };
|
45 |
|
46 | ConfigReplace.prototype.deriveCacheKey = function(file) {
|
47 | var stats = fs.statSync(this.getConfigPath());
|
48 |
|
49 | if (stats.isDirectory()) {
|
50 | throw new Error('Must provide a path for the config file, you supplied a directory');
|
51 | }
|
52 |
|
53 | var patterns = this.options.patterns.reduce(function(a, b) {
|
54 | return a + b.match;
|
55 | }, '');
|
56 |
|
57 | return {
|
58 | file: file,
|
59 | hash: hashStrings([
|
60 | file,
|
61 | this.configPath,
|
62 | patterns,
|
63 | stats.size,
|
64 | stats.mode,
|
65 | stats.mtime.getTime()
|
66 | ])
|
67 | };
|
68 | };
|
69 |
|
70 | ConfigReplace.prototype.processFile = function(config, filePath) {
|
71 | filePath = path.join(this.inputPaths[0], filePath);
|
72 | var contents = fs.readFileSync(filePath, { encoding: 'utf8' });
|
73 |
|
74 | this.options.patterns.forEach(function(pattern) {
|
75 | var replacement = pattern.replacement;
|
76 |
|
77 | if (typeof replacement === 'function') {
|
78 | replacement = function() {
|
79 | var args = Array.prototype.slice.call(arguments);
|
80 | return pattern.replacement.apply(null, [config].concat(args));
|
81 | }
|
82 | }
|
83 |
|
84 | contents = contents.replace(pattern.match, replacement);
|
85 | });
|
86 |
|
87 | return contents;
|
88 | };
|
89 |
|
90 | ConfigReplace.prototype.writeFile = function(destPath, contents) {
|
91 | if (!fs.existsSync(path.dirname(destPath))) {
|
92 | fs.mkdirSync(path.dirname(destPath));
|
93 | }
|
94 |
|
95 | fs.writeFileSync(destPath, contents, { encoding: 'utf8' });
|
96 | };
|
97 |
|
98 | ConfigReplace.prototype.updateCache = function(key, contents) {
|
99 | Object.keys(this._cache).forEach(function(hash) {
|
100 | if (this._cache[hash].file === key.file) {
|
101 | delete this._cache[hash];
|
102 | }
|
103 | }, this);
|
104 |
|
105 | this._cache[key.hash] = {
|
106 | file: key.file,
|
107 | contents: contents
|
108 | };
|
109 | };
|
110 |
|
111 | ConfigReplace.prototype.getConfigPath = function() {
|
112 | return path.join(this.inputPaths[1], this.options.configPath);
|
113 | };
|
114 |
|
115 | ConfigReplace.prototype.getConfig = function() {
|
116 | var contents = fs.readFileSync(this.getConfigPath(), { encoding: 'utf8' });
|
117 | return JSON.parse(contents);
|
118 | };
|
119 |
|
120 | module.exports = ConfigReplace;
|