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
|
var Immutable = require('immutable');
var nunjucks = require('nunjucks');
var fs = require('fs');
var path = require('path');
var PathUtils = require('../utils/path');
var ThemesLoader = nunjucks.Loader.extend({
init: function(searchPaths) {
this.searchPaths = Immutable.List(searchPaths)
.map(path.normalize);
},
/**
* Read source of a resolved filepath
* @param {String}
* @return {Object}
*/
getSource: function(fullpath) {
if (!fullpath) return null;
fullpath = this.resolve(null, fullpath);
var templateName = this.getTemplateName(fullpath);
if(!fullpath) {
return null;
}
var src = fs.readFileSync(fullpath, 'utf-8');
src = '{% do %}var template = template || {}; template.stack = template.stack || []; template.stack.push(template.self); template.self = ' + JSON.stringify(templateName) + '{% enddo %}\n' +
src +
'\n{% do %}template.self = template.stack.pop();{% enddo %}';
return {
src: src,
path: fullpath,
noCache: true
};
},
/**
* Nunjucks calls "isRelative" to determine when to call "resolve".
* We handle absolute paths ourselves in ".resolve" so we always return true
*/
isRelative: function() {
return true;
},
/**
* Get original search path containing a template
* @param {String} filepath
* @return {String} searchPath
*/
getSearchPath: function(filepath) {
return this.searchPaths
.sortBy(function(s) {
return -s.length;
})
.find(function(basePath) {
return (filepath && filepath.indexOf(basePath) === 0);
});
},
/**
* Get template name from a filepath
* @param {String} filepath
* @return {String} name
*/
getTemplateName: function(filepath) {
var originalSearchPath = this.getSearchPath(filepath);
return originalSearchPath? path.relative(originalSearchPath, filepath) : null;
},
/**
* Resolve a template from a current template
* @param {String|null} from
* @param {String} to
* @return {String|null}
*/
resolve: function(from, to) {
var searchPaths = this.searchPaths;
// Relative template like "./test.html"
if (PathUtils.isPureRelative(to) && from) {
return path.resolve(path.dirname(from), to);
}
// Determine in which search folder we currently are
var originalSearchPath = this.getSearchPath(from);
var originalFilename = this.getTemplateName(from);
// If we are including same file from a different search path
// Slice the search paths to avoid including from previous ones
if (originalFilename == to) {
var currentIndex = searchPaths.indexOf(originalSearchPath);
searchPaths = searchPaths.slice(currentIndex + 1);
}
// Absolute template to resolve in root folder
var resultFolder = searchPaths.find(function(basePath) {
var p = path.resolve(basePath, to);
return (
p.indexOf(basePath) === 0
&& fs.existsSync(p)
);
});
if (!resultFolder) return null;
return path.resolve(resultFolder, to);
}
});
module.exports = ThemesLoader;
|