summaryrefslogtreecommitdiffstats
path: root/lib/template/fs-loader.js
blob: 7f469bb2c59f8ef04ef21b556108d33e790af567 (plain)
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
var _ = require('lodash');
var fs = require('fs');
var path = require('path');
var nunjucks = require('nunjucks');

/*
    Nunjucks loader similar to FileSystemLoader, but avoid infinite looping
*/

function isRelative(filename) {
    return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0);
}

var Loader = nunjucks.Loader.extend({
    init: function(searchPaths) {
        this.searchPaths = _.map(searchPaths, path.normalize);
    },

    getSource: function(fullpath) {
        if (!fullpath) return null;

        fullpath = this.resolve(null, fullpath);

        if(!fullpath) {
            return null;
        }

        return {
            src: fs.readFileSync(fullpath, 'utf-8'),
            path: fullpath,
            noCache: true
        };
    },

    // We handle absolute paths ourselves in ".resolve"
    isRelative: function() {
        return true;
    },

    resolve: function(from, to) {
        var searchPaths = this.searchPaths;

        // Relative template like "./test.html"
        if (isRelative(to) && from) {
            return path.resolve(path.dirname(from), to);
        }

        // Determine in which search folder we currently are
        var originalSearchPath = _.chain(this.searchPaths)
            .sortBy(function(s) {
                return -s.length;
            })
            .find(function(basePath) {
                return (from && from.indexOf(basePath) === 0);
            })
            .value();
        var originalFilename = originalSearchPath? path.relative(originalSearchPath, from) : null;

        // 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 = _.find(searchPaths, 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 = Loader;