Add "url" to file

This commit is contained in:
Samy Pesse
2016-10-05 23:11:57 +02:00
parent 0614613b84
commit 6ce4949df3
18 changed files with 67 additions and 391 deletions
-3
View File
@@ -5,9 +5,6 @@ module.exports = {
root: './docs',
title: 'GitBook Toolchain Documentation',
// Enforce use of GitBook v3
gitbook: '3.1.1',
// Use the "official" theme
plugins: ['sitemap'],
+3 -2
View File
@@ -4,13 +4,14 @@ const { Record } = require('immutable');
const DEFAULTS = {
type: '',
mtime: new Date(),
path: ''
path: '',
url: ''
};
class File extends Record(DEFAULTS) {
constructor(file = {}) {
if (typeof file === 'string') {
file = { path: file };
file = { path: file, url: file };
}
super({
+10 -8
View File
@@ -1,20 +1,22 @@
/**
Return a JSON representation of a file
@param {File} file
@return {Object}
*/
function encodeFileToJson(file) {
* Return a JSON representation of a file
*
* @param {File} file
* @param {String} url?
* @return {Object} json
*/
function encodeFileToJson(file, url) {
const filePath = file.getPath();
if (!filePath) {
return undefined;
}
return {
path: filePath,
path: filePath,
mtime: file.getMTime(),
type: file.getType()
type: file.getType(),
url
};
}
@@ -1,3 +1,5 @@
const resolveFileToURL = require('../output/helper/resolveFileToURL');
const encodeOutput = require('./encodeOutput');
const encodePage = require('./encodePage');
const encodeFile = require('./encodeFile');
@@ -15,7 +17,7 @@ function encodeOutputWithPage(output, page) {
const result = encodeOutput(output);
result.page = encodePage(page, book.getSummary());
result.file = encodeFile(file);
result.file = encodeFile(file, resolveFileToURL(output, file.getPath()));
return result;
}
+6 -6
View File
@@ -1,12 +1,12 @@
const encodeSummaryArticle = require('./encodeSummaryArticle');
/**
Return a JSON representation of a page
@param {Page} page
@param {Summary} summary
@return {Object}
*/
* Return a JSON representation of a page
*
* @param {Page} page
* @param {Summary} summary
* @return {Object} json
*/
function encodePage(page, summary) {
const file = page.getFile();
const attributes = page.getAttributes();
+11 -11
View File
@@ -4,17 +4,17 @@ const LocationUtils = require('../../utils/location');
const fileToOutput = require('./fileToOutput');
/**
Convert a filePath (absolute) to an url (without hostname).
It returns an absolute path.
"README.md" -> "/"
"test/hello.md" -> "test/hello.html"
"test/README.md" -> "test/"
@param {Output} output
@param {String} filePath
@return {String}
*/
* Convert a filePath (absolute) to an url (without hostname).
* It returns an absolute path.
*
* "README.md" -> "/"
* "test/hello.md" -> "test/hello.html"
* "test/README.md" -> "test/"
*
* @param {Output} output
* @param {String} filePath
* @return {String}
*/
function fileToURL(output, filePath) {
const options = output.getOptions();
const directoryIndex = options.get('directoryIndex');
@@ -1,38 +0,0 @@
const createMockOutput = require('../../__tests__/createMock');
const prepareI18n = require('../prepareI18n');
const createTemplateEngine = require('../createTemplateEngine');
const WebsiteGenerator = require('../');
describe('i18n', function() {
it('should correctly use english as default language', function() {
return createMockOutput(WebsiteGenerator, {
'README.md': 'Hello World'
})
.then(function(output) {
return prepareI18n(output);
})
.then(function(output) {
const engine = createTemplateEngine(output, 'README.md');
const t = engine.getFilters().get('t');
expect(t('SUMMARY_INTRODUCTION')).toEqual('Introduction');
});
});
it('should correctly use language from book.json', function() {
return createMockOutput(WebsiteGenerator, {
'README.md': 'Hello World',
'book.json': JSON.stringify({ language: 'fr' })
})
.then(function(output) {
return prepareI18n(output);
})
.then(function(output) {
const engine = createTemplateEngine(output, 'README.md');
const t = engine.getFilters().get('t');
expect(t('GITBOOK_LINK')).toEqual('Publié avec GitBook');
});
});
});
@@ -1,152 +0,0 @@
const path = require('path');
const nunjucks = require('nunjucks');
const DoExtension = require('nunjucks-do')(nunjucks);
const Api = require('../../api');
const deprecate = require('../../api/deprecate');
const JSONUtils = require('../../json');
const LocationUtils = require('../../utils/location');
const fs = require('../../utils/fs');
const PathUtils = require('../../utils/path');
const TemplateEngine = require('../../models/templateEngine');
const templatesFolder = require('../../constants/templatesFolder');
const defaultFilters = require('../../constants/defaultFilters');
const Templating = require('../../templating');
const listSearchPaths = require('./listSearchPaths');
const fileToURL = require('../helper/fileToURL');
const 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) {
const book = output.getBook();
const state = output.getState();
const i18n = state.getI18n();
const config = book.getConfig();
const summary = book.getSummary();
const outputFolder = output.getRoot();
// Search paths for templates
const searchPaths = listSearchPaths(output);
const tplSearchPaths = searchPaths.map(templateFolder);
// Create loader
const loader = new Templating.ThemesLoader(tplSearchPaths);
// Get languages
const language = config.getValue('language');
// Create API context
const context = Api.encodeGlobal(output);
/**
* Check if a file exists
* @param {String} fileName
* @return {Boolean}
*/
function fileExists(fileName) {
if (!fileName) {
return false;
}
const filePath = PathUtils.resolveInRoot(outputFolder, fileName);
return fs.existsSync(filePath);
}
/**
* Return an article by its path
* @param {String} filePath
* @return {Object|undefined}
*/
function getArticleByPath(filePath) {
const article = summary.getByPath(filePath);
if (!article) return undefined;
return JSONUtils.encodeSummaryArticle(article);
}
/**
* Return a page by its path
* @param {String} filePath
* @return {Object|undefined}
*/
function getPageByPath(filePath) {
const page = output.getPage(filePath);
if (!page) return undefined;
return JSONUtils.encodePage(page, summary);
}
return TemplateEngine.create({
loader,
context,
globals: {
getArticleByPath,
getPageByPath,
fileExists
},
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(filePath) {
filePath = resolveFileToURL(output, filePath);
return LocationUtils.relativeForFile(currentFile, filePath);
},
resolveAsset(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);
},
fileExists: deprecate.method(book, 'fileExists', fileExists, 'Filter "fileExists" is deprecated, use "fileExists(filename)" '),
getArticleByPath: deprecate.method(book, 'getArticleByPath', fileExists, 'Filter "getArticleByPath" is deprecated, use "getArticleByPath(filename)" '),
contentURL(filePath) {
return fileToURL(output, filePath);
}
}),
extensions: {
'DoExtension': new DoExtension()
}
});
}
module.exports = createTemplateEngine;
+7 -8
View File
@@ -1,11 +1,10 @@
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')
name: 'website',
State: require('./state'),
Options: require('./options'),
onInit: require('./onInit'),
onFinish: require('./onFinish'),
onPage: require('./onPage'),
onAsset: require('./onAsset')
};
@@ -1,23 +0,0 @@
/**
List search paths for templates / i18n, etc
@param {Output} output
@return {List<String>}
*/
function listSearchPaths(output) {
const book = output.getBook();
const plugins = output.getPlugins();
const searchPaths = plugins
.valueSeq()
.map(function(plugin) {
return plugin.getPath();
})
.toList();
return searchPaths.unshift(book.getContentRoot());
}
module.exports = listSearchPaths;
@@ -2,18 +2,19 @@ const path = require('path');
const fs = require('../../utils/fs');
/**
Copy an asset to the output folder
@param {Output} output
@param {Page} page
*/
* Copy an asset to the output folder
*
* @param {Output} output
* @param {Page} page
* @return {Output} output
*/
function onAsset(output, asset) {
const book = output.getBook();
const book = output.getBook();
const options = output.getOptions();
const bookFS = book.getContentFS();
const bookFS = book.getContentFS();
const outputFolder = options.get('root');
const outputPath = path.resolve(outputFolder, asset);
const outputPath = path.resolve(outputFolder, asset);
return fs.ensureFile(outputPath)
.then(function() {
@@ -1,35 +1,20 @@
const Promise = require('../../utils/promise');
const JSONUtils = require('../../json');
const Templating = require('../../templating');
const writeFile = require('../helper/writeFile');
const createTemplateEngine = require('./createTemplateEngine');
/**
Finish the generation, write the languages index
@param {Output}
@return {Output}
*/
* Finish the generation, write the languages index
*
* @param {Output}
* @return {Output}
*/
function onFinish(output) {
const book = output.getBook();
const options = output.getOptions();
const prefix = options.get('prefix');
if (!book.isMultilingual()) {
return Promise(output);
}
const filePath = 'index.html';
const engine = createTemplateEngine(output, filePath);
const context = JSONUtils.encodeOutput(output);
// Render the theme
return Templating.renderFile(engine, prefix + '/languages.html', context)
// Write it to the disk
.then(function(tplOut) {
return writeFile(output, filePath, tplOut.getContent());
});
// TODO: multilingual index
return Promise(output);
}
module.exports = onFinish;
+5 -10
View File
@@ -1,19 +1,14 @@
const Promise = require('../../utils/promise');
const copyPluginAssets = require('./copyPluginAssets');
const prepareI18n = require('./prepareI18n');
const prepareResources = require('./prepareResources');
/**
Initialize the generator
@param {Output}
@return {Output}
*/
* Initialize the generator
*
* @param {Output}
* @return {Output}
*/
function onInit(output) {
return Promise(output)
.then(prepareI18n)
.then(prepareResources)
.then(copyPluginAssets);
}
@@ -1,4 +1,3 @@
const Plugins = require('../../plugins');
const JSONUtils = require('../../json');
const Modifiers = require('../modifiers');
const writeFile = require('../helper/writeFile');
@@ -7,7 +6,7 @@ const getModifiers = require('../getModifiers');
const render = require('../../browser/render');
/**
* Write a page as a json file
* Generate a page using react and the plugins.
*
* @param {Output} output
* @param {Page} page
@@ -15,8 +14,6 @@ const render = require('../../browser/render');
function onPage(output, page) {
const file = page.getFile();
const plugins = output.getPlugins();
const state = output.getState();
const resources = state.getResources();
// Output file path
const filePath = fileToOutput(output, file.getPath());
@@ -25,9 +22,6 @@ function onPage(output, page) {
.then(function(resultPage) {
// Generate the context
const initialState = JSONUtils.encodeOutputWithPage(output, resultPage);
initialState.plugins = {
resources: Plugins.listResources(plugins, resources).toJS()
};
// Render the theme
const html = render(plugins, initialState);
@@ -2,13 +2,11 @@ const Immutable = require('immutable');
const Options = Immutable.Record({
// Root folder for the output
root: String(),
root: String(),
// Prefix for generation
prefix: String('website'),
prefix: String('website'),
// Use directory index url instead of "index.html"
directoryIndex: Boolean(true)
directoryIndex: Boolean(true)
});
module.exports = Options;
@@ -1,30 +0,0 @@
const path = require('path');
const fs = require('../../utils/fs');
const Promise = require('../../utils/promise');
const listSearchPaths = require('./listSearchPaths');
/**
* Prepare i18n, load translations from plugins and book
*
* @param {Output}
* @return {Promise<Output>}
*/
function prepareI18n(output) {
const state = output.getState();
const i18n = state.getI18n();
const searchPaths = listSearchPaths(output);
searchPaths
.reverse()
.forEach(function(searchPath) {
const i18nRoot = path.resolve(searchPath, '_i18n');
if (!fs.existsSync(i18nRoot)) return;
i18n.load(i18nRoot);
});
return Promise(output);
}
module.exports = prepareI18n;
@@ -1,54 +0,0 @@
const is = require('is');
const Immutable = require('immutable');
const Promise = require('../../utils/promise');
const Api = require('../../api');
/**
Prepare plugins resources, add all output corresponding type resources
@param {Output}
@return {Promise<Output>}
*/
function prepareResources(output) {
const plugins = output.getPlugins();
const options = output.getOptions();
const type = options.get('prefix');
let state = output.getState();
const context = Api.encodeGlobal(output);
let result = Immutable.Map();
return Promise.forEach(plugins, function(plugin) {
const pluginResources = plugin.getResources(type);
return Promise()
.then(function() {
// Apply resources if is a function
if (is.fn(pluginResources)) {
return Promise()
.then(pluginResources.bind(context));
}
else {
return pluginResources;
}
})
.then(function(resources) {
result = result.set(plugin.getName(), Immutable.Map(resources));
});
})
.then(function() {
// Set output resources
state = state.merge({
resources: result
});
output = output.merge({
state
});
return output;
});
}
module.exports = prepareResources;
+2 -3
View File
@@ -2,10 +2,9 @@ const I18n = require('i18n-t');
const Immutable = require('immutable');
const GeneratorState = Immutable.Record({
i18n: I18n(),
i18n: I18n(),
// List of plugins' resources
resources: Immutable.Map()
resources: Immutable.Map()
});
GeneratorState.prototype.getI18n = function() {