1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 |
|
9 |
|
10 | 'use strict';
|
11 |
|
12 |
|
13 |
|
14 | module.exports = function (grunt) {
|
15 |
|
16 | var path = require('path');
|
17 | var fs = require('fs');
|
18 | var chalk = require('chalk');
|
19 | var _ = require('lodash');
|
20 | var Applause = require('applause');
|
21 |
|
22 | grunt.registerMultiTask('replace', 'Replace text patterns with applause.', function () {
|
23 |
|
24 |
|
25 |
|
26 | var options = this.options({
|
27 | encoding: grunt.file.defaultEncoding,
|
28 |
|
29 | processContentExclude: [],
|
30 | mode: false,
|
31 | patterns: [],
|
32 | excludeBuiltins: false,
|
33 | force: true,
|
34 | silent: false
|
35 | });
|
36 |
|
37 |
|
38 |
|
39 | var patterns = options.patterns;
|
40 |
|
41 | if (options.excludeBuiltins !== true) {
|
42 | patterns.push({
|
43 | match: '__SOURCE_FILE__',
|
44 | replacement: function (match, offset, string, source, target) {
|
45 | return source;
|
46 | },
|
47 | builtin: true
|
48 | }, {
|
49 | match: '__SOURCE_PATH__',
|
50 | replacement: function (match, offset, string, source, target) {
|
51 | return path.dirname(source);
|
52 | },
|
53 | builtin: true
|
54 | }, {
|
55 | match: '__SOURCE_FILENAME__',
|
56 | replacement: function (match, offset, string, source, target) {
|
57 | return path.basename(source);
|
58 | },
|
59 | builtin: true
|
60 | }, {
|
61 | match: '__TARGET_FILE__',
|
62 | replacement: function (match, offset, string, source, target) {
|
63 | return target;
|
64 | },
|
65 | builtin: true
|
66 | }, {
|
67 | match: '__TARGET_PATH__',
|
68 | replacement: function (match, offset, string, source, target) {
|
69 | return path.dirname(target);
|
70 | },
|
71 | builtin: true
|
72 | }, {
|
73 | match: '__TARGET_FILENAME__',
|
74 | replacement: function (match, offset, string, source, target) {
|
75 | return path.basename(target);
|
76 | },
|
77 | builtin: true
|
78 | });
|
79 | }
|
80 |
|
81 |
|
82 |
|
83 | var applause = Applause.create(_.extend({}, options, {
|
84 |
|
85 | detail: true
|
86 | }));
|
87 |
|
88 |
|
89 |
|
90 | var tally = {
|
91 | dirs: 0,
|
92 | files: 0,
|
93 | replacements: 0,
|
94 | details: []
|
95 | };
|
96 |
|
97 | this.files.forEach(function (filePair) {
|
98 | var dest = filePair.dest;
|
99 | var isExpandedPair = filePair.orig.expand || false;
|
100 | filePair.src.forEach(function (src) {
|
101 | src = unixifyPath(src);
|
102 | dest = unixifyPath(dest);
|
103 | if (detectDestType(dest) === 'directory') {
|
104 | dest = (isExpandedPair) ? dest : path.join(dest, src);
|
105 | }
|
106 | if (grunt.file.isDir(src)) {
|
107 | grunt.file.mkdir(dest);
|
108 | tally.dirs++;
|
109 | } else {
|
110 | var res = replace(src, dest, options, applause);
|
111 | tally.details = tally.details.concat(res.detail);
|
112 | tally.replacements += res.count;
|
113 | tally.files++;
|
114 | }
|
115 | if (options.mode !== false) {
|
116 | fs.chmodSync(dest, (options.mode === true) ? fs.lstatSync(src).mode : options.mode);
|
117 | }
|
118 | });
|
119 | });
|
120 |
|
121 |
|
122 |
|
123 | if (options.silent !== true) {
|
124 | var count = 0;
|
125 | patterns.forEach(function (pattern) {
|
126 | if (pattern.builtin !== true) {
|
127 | var found = _.find(tally.details, 'source', pattern);
|
128 | if (!found) {
|
129 | count++;
|
130 | }
|
131 | }
|
132 | });
|
133 | if (count > 0) {
|
134 | var strWarn = [
|
135 | 'Unable to match ',
|
136 | count,
|
137 | count === 1 ? ' pattern' : ' patterns'
|
138 | ];
|
139 | if (applause.options.usePrefix === true) {
|
140 | strWarn.push(
|
141 | ', remember for simple matches (String) we are using the prefix ',
|
142 | applause.options.prefix,
|
143 | ' for replacement lookup'
|
144 | );
|
145 | }
|
146 | grunt.log.warn(strWarn.join(''));
|
147 | }
|
148 | var str = [
|
149 | chalk.cyan(tally.replacements),
|
150 | tally.replacements === 1 ? ' replacement' : ' replacements',
|
151 | ' in ',
|
152 | chalk.cyan(tally.files),
|
153 | tally.files === 1 ? ' file' : ' files'
|
154 | ];
|
155 | grunt.log.writeln(str.join(''));
|
156 | }
|
157 |
|
158 | });
|
159 |
|
160 | var detectDestType = function (dest) {
|
161 | if (_.endsWith(dest, '/')) {
|
162 | return 'directory';
|
163 | } else {
|
164 | return 'file';
|
165 | }
|
166 | };
|
167 |
|
168 | var unixifyPath = function (filepath) {
|
169 | if (process.platform === 'win32') {
|
170 | return filepath.replace(/\\/g, '/');
|
171 | } else {
|
172 | return filepath;
|
173 | }
|
174 | };
|
175 |
|
176 | var replace = function (source, target, options, applause) {
|
177 | var res;
|
178 | grunt.file.copy(source, target, {
|
179 | encoding: options.encoding,
|
180 | process: function (content) {
|
181 | res = applause.replace(content, [source, target]);
|
182 | var result = res.content;
|
183 |
|
184 | if (result === false && options.force === true) {
|
185 | result = content;
|
186 | }
|
187 | if (result !== false) {
|
188 | grunt.verbose.writeln('Replace ' + chalk.cyan(source) + ' → ' +
|
189 | chalk.green(target));
|
190 | }
|
191 | return result;
|
192 | },
|
193 | noProcess: options.noProcess || options.processContentExclude
|
194 | });
|
195 | return res;
|
196 | };
|
197 |
|
198 | };
|