99 lines
3.8 KiB
JavaScript
99 lines
3.8 KiB
JavaScript
"use strict";
|
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
};
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
const immutable_1 = __importDefault(require("immutable"));
|
|
const nunjucks_1 = __importDefault(require("nunjucks"));
|
|
const fs_1 = __importDefault(require("fs"));
|
|
const path_1 = __importDefault(require("path"));
|
|
const path_2 = __importDefault(require("../utils/path"));
|
|
const ThemesLoader = nunjucks_1.default.Loader.extend({
|
|
// @ts-expect-error: Property 'extend' does not exist on type 'typeof Loader'.
|
|
init: function (searchPaths) {
|
|
this.searchPaths = immutable_1.default.List(searchPaths).map(path_1.default.normalize);
|
|
},
|
|
/**
|
|
* Read source of a resolved filepath
|
|
* @param {string}
|
|
* @return {Object}
|
|
*/
|
|
getSource: function (fullpath) {
|
|
if (!fullpath)
|
|
return null;
|
|
fullpath = this.resolve(null, fullpath);
|
|
const templateName = this.getTemplateName(fullpath);
|
|
if (!fullpath) {
|
|
return null;
|
|
}
|
|
let src = fs_1.default.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((s) => {
|
|
return -s.length;
|
|
})
|
|
.find((basePath) => {
|
|
return filepath && filepath.indexOf(basePath) === 0;
|
|
});
|
|
},
|
|
/**
|
|
* Get template name from a filepath
|
|
* @param {string} filepath
|
|
* @return {string} name
|
|
*/
|
|
getTemplateName: function (filepath) {
|
|
const originalSearchPath = this.getSearchPath(filepath);
|
|
return originalSearchPath ? path_1.default.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) {
|
|
let searchPaths = this.searchPaths;
|
|
// Relative template like "./test.html"
|
|
if (path_2.default.isPureRelative(to) && from) {
|
|
return path_1.default.resolve(path_1.default.dirname(from), to);
|
|
}
|
|
// Determine in which search folder we currently are
|
|
const originalSearchPath = this.getSearchPath(from);
|
|
const 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) {
|
|
const currentIndex = searchPaths.indexOf(originalSearchPath);
|
|
searchPaths = searchPaths.slice(currentIndex + 1);
|
|
}
|
|
// Absolute template to resolve in root folder
|
|
const resultFolder = searchPaths.find((basePath) => {
|
|
const p = path_1.default.resolve(basePath, to);
|
|
return p.indexOf(basePath) === 0 && fs_1.default.existsSync(p);
|
|
});
|
|
if (!resultFolder)
|
|
return null;
|
|
return path_1.default.resolve(resultFolder, to);
|
|
}
|
|
});
|
|
exports.default = ThemesLoader;
|