-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathrefactor-webpack.js
314 lines (278 loc) · 8.63 KB
/
refactor-webpack.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
#!/usr/bin/env node
/**
* Module dependencies.
*/
var glob = require('glob');
const fs = require('fs');
const replace = require('replace-in-file');
const changeCase = require('change-case');
var child_process = require('child_process');
var program = require('commander');
const jsonfile = require('jsonfile');
// global state :/
var workingDir = ".";
var topNamespace = "App";
program.version('0.0.0', '-v, --version');
program.option('-d, --dry', 'Run dry without changing files');
program.arguments('<topNamespace> [path]').action(function (topNamespaceA, path = ".") {
topNamespace = topNamespaceA ? topNamespaceA : topNamespace;
workingDir = path;
})
program.parse(process.argv);
// traverse twig files in bundles
var files = glob.sync(workingDir + "/src/**/*.twig", {});
console.log("got " + files.length + " files");
files.forEach(file => {
//console.log("Handling file " + file);
handleFileAsset(file, "stylesheets", "link");
handleFileAsset(file, "javascripts", "script");
});
function handleFileAsset(file, assetTwigTag, assetHTMLTag) {
var jf = fs.readFileSync(file, 'utf8');
//# extract "@file" strings -> path
const tag = findTags(assetTwigTag, jf);
const endTag = findEndTags(assetTwigTag, jf);
if (!tag || !endTag) {
return;
}
const paths = findPaths(tag);
if (paths === null) {
console.log("Skipping " + assetTwigTag + " in " + file + " as null as paths was found.");
return;
}
//# replace href=/src={{ asset_url }} with href=/src={{ asset(path) }}
var oldLine = grep("\<" + assetHTMLTag + ".*asset_url", file);
if (oldLine.some(result => {
return (result["results"].length > 1);
})) {
console.warn("File " + file + " has more than one occurrence of tag " + assetHTMLTag + ". handle manually.");
return;
}
adabtLine(oldLine, paths, file);
// add paths to public/entries.json
if (!program.dry) {
submitPaths(assetTwigTag, paths);
}
//# delete {% tags
replaceInFile(file, tag, "");
// delete %} tags
replaceInFile(file, endTag, "");
}
console.log("handled " + files.length + " files");
/**
* Find tags ({% tagName ... %}) in file
*
* @param {string} tagName
* @param {string} source file to search
*/
function findTags(tagName, source) {
const tagRegexp = new RegExp("{%\\s*" + tagName + ".*[\\n]*(?:.*\"@([a-z./]*)\"[\\s\\n]*.*)*[\\s\\n]*.*%}", "gi");
const tags = source.match(tagRegexp);
// console.log("found tags: ", tags);
return tags;
}
/**
* Find End Tags ({% endTagName %}) in file
*
* @param {string} tagName
* @param {string} source
*/
function findEndTags(tagName, source) {
const tagRegexp = new RegExp("{%\\s*end" + tagName + "[\\s\\n]*.*%}", "gi");
const tags = source.match(tagRegexp);
// console.log("found endtags: ", tags);
return tags;
}
/**
* Find Paths formatted as \"@Path"\ in a string
*
* @param {string} tags
*/
function findPaths(tags) {
const pathRegexp = /\"(@[a-z./]*)\"/gi;
const paths = getMatches(tags, pathRegexp, 1);
// console.log("found paths: ", paths);
return parsePaths(paths);
}
/**
* Transform @Path strings to Path objects
*
* @param {array<string>} paths
*/
function parsePaths(paths) {
var new_paths = [];
paths.forEach(path => {
var prefix = path.split("/Resources/public/").shift();
if (prefix == path) {
// other @, e.g. @jquery – we do not handle these here
console.log("Skipping as path '" + path + "' will not be handled.");
return null;
}
new_paths.push({
source: path,
basename: removeExtension(path.split("/").pop()),
extension: path.split(".").pop(),
bundlename: changeCase.paramCase(prefix.replace("/", "-").replace("@", "")),
bundlepath: prefix.replace("@" + topNamespace, "/src/" + topNamespace + "/"),
internal: "./" + path.split("Resources/public/").pop()
});
});
return new_paths;
}
/**
* Remove the extension from a file name path
*
* @param {string} path
*/
function removeExtension(path) {
return path.replace(/\.[^/.]+$/, "");
}
/**
* Change <link> and <script> from the old asset_url to the "new" asset()
*
* @param {array} results the lines to change
* @param {array} newPaths the paths to adabt
* @param {string} file the file to write to
*/
function adabtLine(results, newPaths, file) {
if (!newPaths || !newPaths.length) {
//console.log("no paths for " + file);
return;
}
if (!results || !results.length) {
//console.log("no lines to change for " + file);
return;
}
results.forEach(result => {
if (result["results"].length > 1) {
console.warn("File " + file + " has more than one occurrence of a tag. handle manually");
} else {
var line = result["results"][0]['line'];
var new_line = "";
newPaths.forEach(path => {
ext = path.extension === "js" ? "js" : "css";
new_href = "{{ asset('build/" + path.bundlename + "-" + path.basename + "." + ext + "') }}"
new_line += line.replace(/{{\s*asset_url\s*}}/gi, new_href) + "\n";
});
const options = {
files: file,
from: line,
to: new_line,
};
try {
if (!program.dry) {
let changedFiles = replace.sync(options);
}
}
catch (error) {
console.error('Error occurred:', error);
}
}
});
// console.log("Changed one tag for " + file);
}
/**
* Save paths with names to entries.json file
*
* @param {string} type
* @param {array} paths
*/
function submitPaths(type, paths) {
switch (type) {
case "javascripts":
type = "entry";
break;
case "stylesheets":
type = "styleEntry"
break;
default:
throw new Exception("Expected 'javascripts' or 'stylesheets' as argument 1 in function submitPaths");
}
paths.forEach(path => {
var data = null;
var jsonFilePath = workingDir + path.bundlepath + "/Resources/public/entries.json";
try {
data = jsonfile.readFileSync(jsonFilePath, { flag: 'r+' });
} catch (e) {
console.warn("Failed to read " + jsonFilePath, e);
}
if (data === null) {
console.log("data null");
data = {};
}
if (!data[type]) {
data[type] = {};
console.log("unknown type: " + type);
}
data[type][path.bundlename + "-" + path.basename] = path.internal;
jsonfile.writeFileSync(jsonFilePath, data, {
flag: 'w'
});
});
}
/**
* Wrapper function for system grep
*
* @param {string} what
* @param {string} where
*/
function grep(what, where) {
try {
var out = child_process.execSync("grep '" + what + "' " + where + " -nrH", { 'encoding': 'utf8' });
} catch (e) {
// no resuls
//console.log(e);
var out = "\n";
}
var list = {};
//console.log(out);
var results = out.split('\n');
// remove last element (it’s an empty line)
results.pop();
// setup filename array
for (var i = 0; i < results.length; i++) {
var eachPart = results[i].split(':') //file:linenum:line
list[eachPart[0]] = [];
}
// fill filename arrays with results
for (var i = 0; i < results.length; i++) {
var eachPart = results[i].split(':'); //file:linenum:line
var details = {};
var filename = eachPart[0];
details['line_number'] = eachPart[1];
eachPart.shift();
eachPart.shift();
details['line'] = eachPart.join(':');
list[filename].push(details);
}
var results = [];
var files = Object.keys(list);
for (var i = 0; i < files.length; i++) {
results.push({ 'file': files[i], 'results': list[files[i]] });
}
return results;
}
function getMatches(string, regex, index = 0) {
index = index || (index = 1); // default to the first capturing group
var matches = [];
var match;
while ((match = regex.exec(string)) != null) {
matches.push(match[index]);
}
return matches;
}
function replaceInFile(file, source, target) {
const options = {
files: file,
from: source,
to: target,
};
try {
if (!program.dry) {
let changedFiles = replace.sync(options);
}
}
catch (error) {
console.error('Error occurred replacing tags: ', error);
}
}