mirror of
https://github.com/GitbookIO/gitbook.git
synced 2026-09-23 02:53:29 +00:00
Add "url" to file
This commit is contained in:
@@ -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'],
|
||||
|
||||
|
||||
@@ -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({
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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() {
|
||||
|
||||
Reference in New Issue
Block a user