summaryrefslogtreecommitdiffstats
path: root/lib/output/website
diff options
context:
space:
mode:
Diffstat (limited to 'lib/output/website')
-rw-r--r--lib/output/website/copyPluginAssets.js115
-rw-r--r--lib/output/website/createTemplateEngine.js118
-rw-r--r--lib/output/website/index.js232
-rw-r--r--lib/output/website/listSearchPaths.js23
-rw-r--r--lib/output/website/onAsset.js27
-rw-r--r--lib/output/website/onFinish.js35
-rw-r--r--lib/output/website/onInit.js18
-rw-r--r--lib/output/website/onPage.js72
-rw-r--r--lib/output/website/options.js14
-rw-r--r--lib/output/website/prepareI18n.js30
-rw-r--r--lib/output/website/state.js12
-rw-r--r--lib/output/website/templateEnv.js95
-rw-r--r--lib/output/website/themeLoader.js127
13 files changed, 473 insertions, 445 deletions
diff --git a/lib/output/website/copyPluginAssets.js b/lib/output/website/copyPluginAssets.js
new file mode 100644
index 0000000..9dc876f
--- /dev/null
+++ b/lib/output/website/copyPluginAssets.js
@@ -0,0 +1,115 @@
+var path = require('path');
+
+var ASSET_FOLDER = require('../../constants/pluginAssetsFolder');
+var Promise = require('../../utils/promise');
+var fs = require('../../utils/fs');
+
+/**
+ Copy all assets from plugins.
+ Assets are files stored in "_assets"
+ nd resources declared in the plugin itself.
+
+ @param {Output}
+ @return {Promise}
+*/
+function copyPluginAssets(output) {
+ var book = output.getBook();
+
+ // Don't copy plugins assets for language book
+ // It'll be resolved to the parent folder
+ if (book.isLanguageBook()) {
+ return Promise(output);
+ }
+
+ var plugins = output.getPlugins()
+
+ // We reverse the order of plugins to copy
+ // so that first plugins can replace assets from other plugins.
+ .reverse();
+
+ return Promise.forEach(plugins, function(plugin) {
+ return copyAssets(output, plugin)
+ .then(function() {
+ return copyResources(output, plugin);
+ });
+ })
+ .thenResolve(output);
+}
+
+/**
+ Copy assets from a plugin
+
+ @param {Plugin}
+ @return {Promise}
+*/
+function copyAssets(output, plugin) {
+ var logger = output.getLogger();
+ var pluginRoot = plugin.getPath();
+ var options = output.getOptions();
+
+ var outputRoot = options.get('root');
+ var assetOutputFolder = path.join(outputRoot, 'gitbook');
+ var prefix = options.get('prefix');
+
+ var assetFolder = path.join(pluginRoot, ASSET_FOLDER, prefix);
+
+ if (!fs.existsSync(assetFolder)) {
+ return Promise();
+ }
+
+ logger.debug.ln('copy assets from theme', assetFolder);
+ return fs.copyDir(
+ assetFolder,
+ assetOutputFolder,
+ {
+ deleteFirst: false,
+ overwrite: true,
+ confirm: true
+ }
+ );
+}
+
+/**
+ Copy resources from a plugin
+
+ @param {Plugin}
+ @return {Promise}
+*/
+function copyResources(output, plugin) {
+ var logger = output.getLogger();
+
+ var options = output.getOptions();
+ var prefix = options.get('prefix');
+ var outputRoot = options.get('root');
+
+ var pluginRoot = plugin.getPath();
+ var resources = plugin.getResources(prefix);
+
+ var assetsFolder = resources.get('assets');
+ var assetOutputFolder = path.join(outputRoot, 'gitbook', plugin.getNpmID());
+
+ if (!assetsFolder) {
+ return Promise();
+ }
+
+ // Resolve assets folder
+ assetsFolder = path.resolve(pluginRoot, assetsFolder);
+ if (!fs.existsSync(assetsFolder)) {
+ logger.warn.ln('assets folder for plugin "' + plugin.getName() + '" doesn\'t exist');
+ return Promise();
+ }
+
+ logger.debug.ln('copy resources from plugin', assetsFolder);
+
+ return fs.copyDir(
+ assetsFolder,
+ assetOutputFolder,
+ {
+ deleteFirst: false,
+ overwrite: true,
+ confirm: true
+ }
+ );
+}
+
+module.exports = copyPluginAssets;
diff --git a/lib/output/website/createTemplateEngine.js b/lib/output/website/createTemplateEngine.js
new file mode 100644
index 0000000..334ec13
--- /dev/null
+++ b/lib/output/website/createTemplateEngine.js
@@ -0,0 +1,118 @@
+var path = require('path');
+var nunjucks = require('nunjucks');
+var DoExtension = require('nunjucks-do')(nunjucks);
+
+var Api = require('../../api');
+var JSONUtils = require('../../json');
+var LocationUtils = require('../../utils/location');
+var fs = require('../../utils/fs');
+var PathUtils = require('../../utils/path');
+var TemplateEngine = require('../../models/templateEngine');
+var templatesFolder = require('../../constants/templatesFolder');
+var defaultFilters = require('../../constants/defaultFilters');
+var Templating = require('../../templating');
+var listSearchPaths = require('./listSearchPaths');
+
+var fileToURL = require('../helper/fileToURL');
+var resolveFileToURL = require('../helper/resolveFileToURL');
+
+/**
+ Directory for a theme with the templates
+*/
+function templateFolder(dir) {
+ return path.join(dir, templatesFolder);
+}
+
+/**
+ Create templating engine to render themes
+
+ @param {Output} output
+ @param {String} currentFile
+ @return {TemplateEngine}
+*/
+function createTemplateEngine(output, currentFile) {
+ var book = output.getBook();
+ var state = output.getState();
+ var i18n = state.getI18n();
+ var config = book.getConfig();
+ var summary = book.getSummary();
+ var outputFolder = output.getRoot();
+
+ // Search paths for templates
+ var searchPaths = listSearchPaths(output);
+ var tplSearchPaths = searchPaths.map(templateFolder);
+
+ // Create loader
+ var loader = new Templating.ThemesLoader(tplSearchPaths);
+
+ // Get languages
+ var language = config.get('language');
+
+ // Create API context
+ var context = Api.encodeGlobal(output);
+
+ return TemplateEngine.create({
+ loader: loader,
+
+ context: context,
+
+ filters: defaultFilters.merge({
+ /**
+ Translate a sentence
+ */
+ t: function t(s) {
+ return i18n.t(language, s);
+ },
+
+ /**
+ Resolve an absolute file path into a
+ relative path.
+ it also resolve pages
+ */
+ resolveFile: function(filePath) {
+ filePath = resolveFileToURL(output, filePath);
+ return LocationUtils.relativeForFile(currentFile, filePath);
+ },
+
+ resolveAsset: function(filePath) {
+ filePath = LocationUtils.toAbsolute(filePath, '', '');
+ filePath = path.join('gitbook', filePath);
+ filePath = LocationUtils.relativeForFile(currentFile, filePath);
+
+ // Use assets from parent if language book
+ if (book.isLanguageBook()) {
+ filePath = path.join('../', filePath);
+ }
+
+ return LocationUtils.normalize(filePath);
+ },
+
+ /**
+ Check if a file exists
+ */
+ fileExists: function(fileName) {
+ var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
+ return fs.existsSync(filePath);
+ },
+
+ contentURL: function(filePath) {
+ return fileToURL(output, filePath);
+ },
+
+ /**
+ Return an article by its path
+ */
+ getArticleByPath: function(s) {
+ var article = summary.getByPath(s);
+ if (!article) return undefined;
+ return JSONUtils.encodeSummaryArticle(article);
+ }
+ }),
+
+ extensions: {
+ 'DoExtension': new DoExtension()
+ }
+ });
+}
+
+module.exports = createTemplateEngine;
diff --git a/lib/output/website/index.js b/lib/output/website/index.js
index 0a8618c..7818a28 100644
--- a/lib/output/website/index.js
+++ b/lib/output/website/index.js
@@ -1,225 +1,11 @@
-var _ = require('lodash');
-var path = require('path');
-var util = require('util');
-var I18n = require('i18n-t');
-var Promise = require('../../utils/promise');
-var location = require('../../utils/location');
-var fs = require('../../utils/fs');
-var conrefsLoader = require('../conrefs');
-var Output = require('../base');
-var setupTemplateEnv = require('./templateEnv');
-
-function _WebsiteOutput() {
- Output.apply(this, arguments);
-
- // Nunjucks environment
- this.env;
-
- // Plugin instance for the main theme
- this.theme;
-
- // Plugin instance for the default theme
- this.defaultTheme;
-
- // Resources loaded from plugins
- this.resources;
-
- // i18n for themes
- this.i18n = new I18n();
-}
-util.inherits(_WebsiteOutput, Output);
-
-var WebsiteOutput = conrefsLoader(_WebsiteOutput);
-
-// Name of the generator
-// It's being used as a prefix for templates
-WebsiteOutput.prototype.name = 'website';
-
-// Load and setup the theme
-WebsiteOutput.prototype.prepare = function() {
- var that = this;
-
- return Promise()
- .then(function() {
- return WebsiteOutput.super_.prototype.prepare.apply(that);
- })
-
- .then(function() {
- // This list is ordered to give priority to templates in the book
- var searchPaths = _.pluck(that.plugins.list(), 'root');
-
- // The book itself can contains a "_layouts" folder
- searchPaths.unshift(that.book.root);
-
- // Load i18n
- _.each(searchPaths.concat().reverse(), function(searchPath) {
- var i18nRoot = path.resolve(searchPath, '_i18n');
-
- if (!fs.existsSync(i18nRoot)) return;
- that.i18n.load(i18nRoot);
- });
-
- that.searchPaths = searchPaths;
- })
-
- // Copy assets from themes before copying files from book
- .then(function() {
- if (that.book.isLanguageBook()) return;
-
- // Assets from the book are already copied
- // Copy assets from plugins (start with default plugins)
- return Promise.serie(that.plugins.list().reverse(), function(plugin) {
- // Copy assets only if exists (don't fail otherwise)
- var assetFolder = path.join(plugin.root, '_assets', that.name);
- if (!fs.existsSync(assetFolder)) return;
-
- that.log.debug.ln('copy assets from theme', assetFolder);
- return fs.copyDir(
- assetFolder,
- that.resolve('gitbook'),
- {
- deleteFirst: false,
- overwrite: true,
- confirm: true
- }
- );
- });
- })
-
- // Load resources for plugins
- .then(function() {
- return that.plugins.getResources(that.name)
- .then(function(resources) {
- that.resources = resources;
- });
- });
-};
-
-// Write a page (parsable file)
-WebsiteOutput.prototype.onPage = function(page) {
- var that = this;
-
- // Parse the page
- return page.toHTML(this)
-
- // Render the page template with the same context as the json output
- .then(function() {
- return that.render('page', that.outputPath(page.path), page.getOutputContext(that));
- });
-};
-
-// Finish generation, create ebook using ebook-convert
-WebsiteOutput.prototype.finish = function() {
- var that = this;
-
- return Promise()
- .then(function() {
- return WebsiteOutput.super_.prototype.finish.apply(that);
- })
-
- // Copy assets from plugins
- .then(function() {
- if (that.book.isLanguageBook()) return;
- return that.plugins.copyResources(that.name, that.resolve('gitbook'));
- })
-
- // Generate homepage to select languages
- .then(function() {
- if (!that.book.isMultilingual()) return;
- return that.outputMultilingualIndex();
- });
-};
-
-// ----- Utilities ----
-
-// Write multi-languages index
-WebsiteOutput.prototype.outputMultilingualIndex = function() {
- var that = this;
-
- return that.render('languages', 'index.html', that.getContext());
-};
-
-/*
- Render a template as an HTML string
- Templates are stored in `_layouts` folders
-
-
- @param {String} tpl: template name (ex: "page")
- @param {String} outputFile: filename to write, relative to the output
- @param {Object} context: context for the page
- @return {Promise}
-*/
-WebsiteOutput.prototype.renderAsString = function(tpl, context) {
- // Calcul template name
- var filename = this.templateName(tpl);
-
- context = _.extend(context, {
- plugins: {
- resources: this.resources
- },
-
- options: this.opts
- });
-
- // Create environment
- var env = setupTemplateEnv(this, context);
-
- return Promise.nfcall(env.render.bind(env), filename, context);
+module.exports = {
+ name: 'website',
+ State: require('./state'),
+ Options: require('./options'),
+ onInit: require('./onInit'),
+ onFinish: require('./onFinish'),
+ onPage: require('./onPage'),
+ onAsset: require('./onAsset'),
+ createTemplateEngine: require('./createTemplateEngine')
};
-
-/*
- Render a template using nunjucks
- Templates are stored in `_layouts` folders
-
-
- @param {String} tpl: template name (ex: "page")
- @param {String} outputFile: filename to write, relative to the output
- @param {Object} context: context for the page
- @return {Promise}
-*/
-WebsiteOutput.prototype.render = function(tpl, outputFile, context) {
- var that = this;
-
- // Calcul relative path to the root
- var outputDirName = path.dirname(outputFile);
- var basePath = location.normalize(path.relative(outputDirName, './'));
-
- // Setup complete context
- context = _.extend(context, {
- basePath: basePath,
-
- template: {
- getJSContext: function() {
- return {
- page: _.omit(context.page, 'content'),
- config: context.config,
- file: context.file,
- gitbook: context.gitbook,
- basePath: basePath,
- book: {
- language: context.book.language
- }
- };
- }
- }
- });
-
- return this.renderAsString(tpl, context)
- .then(function(html) {
- return that.writeFile(
- outputFile,
- html
- );
- });
-};
-
-// Return a complete name for a template
-WebsiteOutput.prototype.templateName = function(name) {
- return path.join(this.name, name+'.html');
-};
-
-module.exports = WebsiteOutput;
-
-
-
diff --git a/lib/output/website/listSearchPaths.js b/lib/output/website/listSearchPaths.js
new file mode 100644
index 0000000..c45f39c
--- /dev/null
+++ b/lib/output/website/listSearchPaths.js
@@ -0,0 +1,23 @@
+
+/**
+ List search paths for templates / i18n, etc
+
+ @param {Output} output
+ @return {List<String>}
+*/
+function listSearchPaths(output) {
+ var book = output.getBook();
+ var plugins = output.getPlugins();
+
+ var searchPaths = plugins
+ .valueSeq()
+ .map(function(plugin) {
+ return plugin.getPath();
+ })
+ .toList();
+
+ return searchPaths.unshift(book.getContentRoot());
+}
+
+
+module.exports = listSearchPaths;
diff --git a/lib/output/website/onAsset.js b/lib/output/website/onAsset.js
new file mode 100644
index 0000000..17b6ba7
--- /dev/null
+++ b/lib/output/website/onAsset.js
@@ -0,0 +1,27 @@
+var path = require('path');
+var fs = require('../../utils/fs');
+
+/**
+ Copy an asset to the output folder
+
+ @param {Output} output
+ @param {Page} page
+*/
+function onAsset(output, asset) {
+ var book = output.getBook();
+ var options = output.getOptions();
+
+ var rootFolder = book.getContentRoot();
+ var outputFolder = options.get('root');
+
+ var filePath = path.resolve(rootFolder, asset);
+ var outputPath = path.resolve(outputFolder, asset);
+
+ return fs.ensureFile(outputPath)
+ .then(function() {
+ return fs.copy(filePath, outputPath);
+ })
+ .thenResolve(output);
+}
+
+module.exports = onAsset;
diff --git a/lib/output/website/onFinish.js b/lib/output/website/onFinish.js
new file mode 100644
index 0000000..e3560e2
--- /dev/null
+++ b/lib/output/website/onFinish.js
@@ -0,0 +1,35 @@
+var Promise = require('../../utils/promise');
+var JSONUtils = require('../../json');
+var Templating = require('../../templating');
+var writeFile = require('../helper/writeFile');
+var createTemplateEngine = require('./createTemplateEngine');
+
+/**
+ Finish the generation, write the languages index
+
+ @param {Output}
+ @return {Output}
+*/
+function onFinish(output) {
+ var book = output.getBook();
+ var options = output.getOptions();
+ var prefix = options.get('prefix');
+
+ if (!book.isMultilingual()) {
+ return Promise(output);
+ }
+
+ var filePath = 'index.html';
+ var engine = createTemplateEngine(output, filePath);
+ var context = JSONUtils.encodeOutput(output);
+
+ // Render the theme
+ return Templating.renderFile(engine, prefix + '/languages.html', context)
+
+ // Write it to the disk
+ .then(function(html) {
+ return writeFile(output, filePath, html);
+ });
+}
+
+module.exports = onFinish;
diff --git a/lib/output/website/onInit.js b/lib/output/website/onInit.js
new file mode 100644
index 0000000..979a90d
--- /dev/null
+++ b/lib/output/website/onInit.js
@@ -0,0 +1,18 @@
+var Promise = require('../../utils/promise');
+
+var copyPluginAssets = require('./copyPluginAssets');
+var prepareI18n = require('./prepareI18n');
+
+/**
+ Initialize the generator
+
+ @param {Output}
+ @return {Output}
+*/
+function onInit(output) {
+ return Promise(output)
+ .then(prepareI18n)
+ .then(copyPluginAssets);
+}
+
+module.exports = onInit;
diff --git a/lib/output/website/onPage.js b/lib/output/website/onPage.js
new file mode 100644
index 0000000..64b4e04
--- /dev/null
+++ b/lib/output/website/onPage.js
@@ -0,0 +1,72 @@
+var path = require('path');
+var omit = require('omit-keys');
+
+var Templating = require('../../templating');
+var Plugins = require('../../plugins');
+var JSONUtils = require('../../json');
+var LocationUtils = require('../../utils/location');
+var Modifiers = require('../modifiers');
+var writeFile = require('../helper/writeFile');
+var getModifiers = require('../getModifiers');
+var createTemplateEngine = require('./createTemplateEngine');
+var fileToOutput = require('../helper/fileToOutput');
+
+/**
+ Write a page as a json file
+
+ @param {Output} output
+ @param {Page} page
+*/
+function onPage(output, page) {
+ var options = output.getOptions();
+ var file = page.getFile();
+ var prefix = options.get('prefix');
+ var book = output.getBook();
+ var plugins = output.getPlugins();
+
+ var engine = createTemplateEngine(output, page.getPath());
+
+ // Output file path
+ var filePath = fileToOutput(output, file.getPath());
+
+ // Calcul relative path to the root
+ var outputDirName = path.dirname(filePath);
+ var basePath = LocationUtils.normalize(path.relative(outputDirName, './'));
+
+ return Modifiers.modifyHTML(page, getModifiers(output, page))
+ .then(function(resultPage) {
+ // Generate the context
+ var context = JSONUtils.encodeBookWithPage(output.getBook(), resultPage);
+ context.plugins = {
+ resources: Plugins.listResources(plugins, prefix).toJS()
+ };
+
+ context.template = {
+ getJSContext: function() {
+ return {
+ page: omit(context.page, 'content'),
+ config: context.config,
+ file: context.file,
+ gitbook: context.gitbook,
+ basePath: basePath,
+ book: {
+ language: book.getLanguage()
+ }
+ };
+ }
+ };
+
+ // We should probabbly move it to "template" or a "site" namespace
+ context.basePath = basePath;
+
+ // Render the theme
+ return Templating.renderFile(engine, prefix + '/page.html', context)
+
+ // Write it to the disk
+ .then(function(html) {
+ return writeFile(output, filePath, html);
+ });
+ });
+}
+
+module.exports = onPage;
diff --git a/lib/output/website/options.js b/lib/output/website/options.js
new file mode 100644
index 0000000..ac9cdad
--- /dev/null
+++ b/lib/output/website/options.js
@@ -0,0 +1,14 @@
+var Immutable = require('immutable');
+
+var Options = Immutable.Record({
+ // Root folder for the output
+ root: String(),
+
+ // Prefix for generation
+ prefix: String('website'),
+
+ // Use directory index url instead of "index.html"
+ directoryIndex: Boolean(true)
+});
+
+module.exports = Options;
diff --git a/lib/output/website/prepareI18n.js b/lib/output/website/prepareI18n.js
new file mode 100644
index 0000000..b57d178
--- /dev/null
+++ b/lib/output/website/prepareI18n.js
@@ -0,0 +1,30 @@
+var path = require('path');
+
+var fs = require('../../utils/fs');
+var Promise = require('../../utils/promise');
+var listSearchPaths = require('./listSearchPaths');
+
+/**
+ Prepare i18n, load translations from plugins and book
+
+ @param {Output}
+ @return {Promise<Output>}
+*/
+function prepareI18n(output) {
+ var state = output.getState();
+ var i18n = state.getI18n();
+ var searchPaths = listSearchPaths(output);
+
+ searchPaths
+ .reverse()
+ .forEach(function(searchPath) {
+ var i18nRoot = path.resolve(searchPath, '_i18n');
+
+ if (!fs.existsSync(i18nRoot)) return;
+ i18n.load(i18nRoot);
+ });
+
+ return Promise(output);
+}
+
+module.exports = prepareI18n;
diff --git a/lib/output/website/state.js b/lib/output/website/state.js
new file mode 100644
index 0000000..99e7f04
--- /dev/null
+++ b/lib/output/website/state.js
@@ -0,0 +1,12 @@
+var I18n = require('i18n-t');
+var Immutable = require('immutable');
+
+var GeneratorState = Immutable.Record({
+ i18n: I18n()
+});
+
+GeneratorState.prototype.getI18n = function() {
+ return this.get('i18n');
+};
+
+module.exports = GeneratorState;
diff --git a/lib/output/website/templateEnv.js b/lib/output/website/templateEnv.js
deleted file mode 100644
index d385108..0000000
--- a/lib/output/website/templateEnv.js
+++ /dev/null
@@ -1,95 +0,0 @@
-var _ = require('lodash');
-var nunjucks = require('nunjucks');
-var path = require('path');
-var fs = require('fs');
-var DoExtension = require('nunjucks-do')(nunjucks);
-
-
-var location = require('../../utils/location');
-var defaultFilters = require('../../template/filters');
-
-var ThemeLoader = require('./themeLoader');
-
-// Directory for a theme with the templates
-function templatesPath(dir) {
- return path.join(dir, '_layouts');
-}
-
-/*
- Create and setup at Nunjucks template environment
-
- @return {Nunjucks.Environment}
-*/
-function setupTemplateEnv(output, context) {
- context = _.defaults(context || {}, {
- // Required by ThemeLoader
- template: {}
- });
-
- var loader = new ThemeLoader(
- _.map(output.searchPaths, templatesPath)
- );
- var env = new nunjucks.Environment(loader);
-
- env.addExtension('DoExtension', new DoExtension());
-
- // Add context as global
- _.each(context, function(value, key) {
- env.addGlobal(key, value);
- });
-
- // Add GitBook default filters
- _.each(defaultFilters, function(fn, filter) {
- env.addFilter(filter, fn);
- });
-
- // Translate using _i18n locales
- env.addFilter('t', function t(s) {
- return output.i18n.t(output.book.config.get('language'), s);
- });
-
- // Transform an absolute path into a relative path
- // using this.ctx.page.path
- env.addFilter('resolveFile', function resolveFile(href) {
- return location.normalize(output.resolveForPage(context.file.path, href));
- });
-
- // Test if a file exists
- env.addFilter('fileExists', function fileExists(href) {
- return fs.existsSync(output.resolve(href));
- });
-
- // Transform a '.md' into a '.html' (README -> index)
- env.addFilter('contentURL', function contentURL(s) {
- return output.toURL(s);
- });
-
- // Get an article using its path
- env.addFilter('getArticleByPath', function getArticleByPath(s) {
- var article = output.book.summary.getArticle(s);
- if (!article) return undefined;
-
- return article.getContext();
- });
-
- // Relase path to an asset
- env.addFilter('resolveAsset', function resolveAsset(href) {
- href = path.join('gitbook', href);
-
- // Resolve for current file
- if (context.file) {
- href = output.resolveForPage(context.file.path, '/' + href);
- }
-
- // Use assets from parent
- if (output.book.isLanguageBook()) {
- href = path.join('../', href);
- }
-
- return location.normalize(href);
- });
-
- return env;
-}
-
-module.exports = setupTemplateEnv;
diff --git a/lib/output/website/themeLoader.js b/lib/output/website/themeLoader.js
deleted file mode 100644
index 774a39e..0000000
--- a/lib/output/website/themeLoader.js
+++ /dev/null
@@ -1,127 +0,0 @@
-var _ = require('lodash');
-var fs = require('fs');
-var path = require('path');
-var nunjucks = require('nunjucks');
-
-/*
- Nunjucks loader similar to FileSystemLoader, but avoid infinite looping
-*/
-
-/*
- Return true if a filename is relative.
-*/
-function isRelative(filename) {
- return (filename.indexOf('./') === 0 || filename.indexOf('../') === 0);
-}
-
-var ThemeLoader = nunjucks.Loader.extend({
- init: function(searchPaths) {
- this.searchPaths = _.map(searchPaths, 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 _.chain(this.searchPaths)
- .sortBy(function(s) {
- return -s.length;
- })
- .find(function(basePath) {
- return (filepath && filepath.indexOf(basePath) === 0);
- })
- .value();
- },
-
- /*
- 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 (isRelative(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 = _.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 = ThemeLoader;