diff options
author | Johan Preynat <johan.preynat@gmail.com> | 2016-10-09 00:58:30 +0200 |
---|---|---|
committer | Johan Preynat <johan.preynat@gmail.com> | 2016-10-09 00:58:30 +0200 |
commit | 5a57a2c62ad67210143bfe5dd96dd1605b3724f6 (patch) | |
tree | 94cef22779ea438a44eaf3fa3b201456652d7005 /packages | |
parent | 4cfffb26f265ce1af71e1f34dc0a9468ad0caaf1 (diff) | |
parent | 2d429b731b7ebbf6480f62efa379dad48ee7bdee (diff) | |
download | gitbook-5a57a2c62ad67210143bfe5dd96dd1605b3724f6.zip gitbook-5a57a2c62ad67210143bfe5dd96dd1605b3724f6.tar.gz gitbook-5a57a2c62ad67210143bfe5dd96dd1605b3724f6.tar.bz2 |
Merge remote-tracking branch 'origin/dream' into dream
# Conflicts:
# packages/gitbook-plugin-headings/package.json
Diffstat (limited to 'packages')
41 files changed, 992 insertions, 1260 deletions
diff --git a/packages/gitbook-core/package.json b/packages/gitbook-core/package.json index 4e3974e..0c444b7 100644 --- a/packages/gitbook-core/package.json +++ b/packages/gitbook-core/package.json @@ -1,49 +1,49 @@ { - "name": "gitbook-core", - "version": "0.0.0", - "description": "Core for GitBook plugins API", - "main": "./lib/index.js", - "dependencies": { - "bluebird": "^3.4.6", - "classnames": "^2.2.5", - "entities": "^1.1.1", - "history": "^4.3.0", - "html-tags": "^1.1.1", - "immutable": "^3.8.1", - "react": "^15.3.1", - "react-dom": "^15.3.1", - "react-helmet": "^3.1.0", - "react-immutable-proptypes": "^2.1.0", - "react-intl": "^2.1.5", - "react-redux": "^4.4.5", - "react-safe-html": "^0.3.0", - "redux": "^3.5.2", - "redux-thunk": "^2.1.0", - "reflexbox": "^2.2.2", - "whatwg-fetch": "^1.0.0" - }, - "devDependencies": { - "babel-cli": "^6.14.0", - "babel-preset-es2015": "^6.14.0", - "babel-preset-react": "^6.11.1", - "babel-preset-stage-2": "^6.13.0", - "browserify": "^13.1.0", - "envify": "^3.4.1", - "uglify-js": "^2.7.3" - }, - "scripts": { - "dist-lib": "rm -rf lib/ && babel -d lib/ src/", - "dist-standalone": "mkdir -p dist && browserify -r ./lib/index.js:gitbook-core -r react -r react-dom ./lib/index.js | uglifyjs -c > ./dist/gitbook.core.min.js", - "dist": "npm run dist-lib && npm run dist-standalone", - "prepublish": "npm run dist" - }, - "repository": { - "type": "git", - "url": "https://github.com/GitbookIO/gitbook.git" - }, - "author": "GitBook Inc. <contact@gitbook.com>", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/GitbookIO/gitbook/issues" - } -} + "name": "gitbook-core", + "version": "4.0.0", + "description": "Core for GitBook plugins API", + "main": "./lib/index.js", + "dependencies": { + "bluebird": "^3.4.6", + "classnames": "^2.2.5", + "entities": "^1.1.1", + "history": "^4.3.0", + "html-tags": "^1.1.1", + "immutable": "^3.8.1", + "react": "^15.3.1", + "react-dom": "^15.3.1", + "react-helmet": "^3.1.0", + "react-immutable-proptypes": "^2.1.0", + "react-intl": "^2.1.5", + "react-redux": "^4.4.5", + "react-safe-html": "^0.3.0", + "redux": "^3.5.2", + "redux-thunk": "^2.1.0", + "reflexbox": "^2.2.2", + "whatwg-fetch": "^1.0.0" + }, + "devDependencies": { + "babel-cli": "^6.14.0", + "babel-preset-es2015": "^6.14.0", + "babel-preset-react": "^6.11.1", + "babel-preset-stage-2": "^6.13.0", + "browserify": "^13.1.0", + "envify": "^3.4.1", + "uglify-js": "^2.7.3" + }, + "scripts": { + "dist-lib": "rm -rf lib/ && babel -d lib/ src/", + "dist-standalone": "mkdir -p dist && browserify -r ./lib/index.js:gitbook-core -r react -r react-dom ./lib/index.js | uglifyjs -c > ./dist/gitbook.core.min.js", + "dist": "npm run dist-lib && npm run dist-standalone", + "prepublish": "npm run dist" + }, + "repository": { + "type": "git", + "url": "https://github.com/GitbookIO/gitbook.git" + }, + "author": "GitBook Inc. <contact@gitbook.com>", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/GitbookIO/gitbook/issues" + } +}
\ No newline at end of file diff --git a/packages/gitbook-core/src/lib/bootstrap.js b/packages/gitbook-core/src/lib/bootstrap.js index f5183d1..f3c99b7 100644 --- a/packages/gitbook-core/src/lib/bootstrap.js +++ b/packages/gitbook-core/src/lib/bootstrap.js @@ -5,9 +5,10 @@ const createContext = require('./createContext'); const renderWithContext = require('./renderWithContext'); /** - * Bootstrap GitBook on the browser (this function should not be called on the server side) + * Bootstrap GitBook on the browser (this function should not be called on the server side). + * @param {Object} matching */ -function bootstrap() { +function bootstrap(matching) { const initialState = getPayload(window.document); const plugins = window.gitbookPlugins; @@ -19,7 +20,7 @@ function bootstrap() { window.gitbookContext = context; // Render with the store - const el = renderWithContext(context); + const el = renderWithContext(context, matching); ReactDOM.render(el, mountNode); } diff --git a/packages/gitbook-core/src/lib/renderWithContext.js b/packages/gitbook-core/src/lib/renderWithContext.js index 44f8ba4..f9a093c 100644 --- a/packages/gitbook-core/src/lib/renderWithContext.js +++ b/packages/gitbook-core/src/lib/renderWithContext.js @@ -9,7 +9,8 @@ const contextShape = require('../shapes/context'); const GitBookApplication = React.createClass({ propTypes: { - context: contextShape + context: contextShape, + matching: React.PropTypes.object }, componentDidMount() { @@ -23,13 +24,13 @@ const GitBookApplication = React.createClass({ }, render() { - const { context } = this.props; + const { context, matching } = this.props; return ( <ContextProvider context={context}> <PJAXWrapper> <I18nProvider> - <InjectedComponent matching={{ role: 'Body' }} /> + <InjectedComponent matching={matching} /> </I18nProvider> </PJAXWrapper> </ContextProvider> @@ -42,11 +43,12 @@ const GitBookApplication = React.createClass({ * Render the application for a GitBook context. * * @param {GitBookContext} context + * @param {Object} matching * @return {React.Element} element */ -function renderWithContext(context) { +function renderWithContext(context, matching) { return ( - <GitBookApplication context={context} /> + <GitBookApplication context={context} matching={matching} /> ); } diff --git a/packages/gitbook-plugin-headings/package.json b/packages/gitbook-plugin-headings/package.json index dc2fbcd..3eb8b76 100644 --- a/packages/gitbook-plugin-headings/package.json +++ b/packages/gitbook-plugin-headings/package.json @@ -3,13 +3,13 @@ "description": "Automatically add anchors to headings", "main": "index.js", "browser": "./_assets/plugin.js", - "version": "1.0.0", + "version": "4.0.0", "dependencies": { "classnames": "^2.2.5", - "gitbook-core": "^0.0.0" + "gitbook-core": "^4.0.0" }, "devDependencies": { - "gitbook-plugin": "*" + "gitbook-plugin": "4.0.0" }, "engines": { "gitbook": ">=3.0.0" diff --git a/packages/gitbook-plugin-highlight/package.json b/packages/gitbook-plugin-highlight/package.json index a174e6c..03d2af7 100644 --- a/packages/gitbook-plugin-highlight/package.json +++ b/packages/gitbook-plugin-highlight/package.json @@ -1,29 +1,29 @@ { - "name": "gitbook-plugin-highlight", - "description": "Syntax highlighter for Gitbook", - "main": "index.js", - "browser": "./_assets/plugin.js", - "version": "2.0.2", - "dependencies": { - "gitbook-core": "^0.0.0", - "highlight.js": "9.7.0" - }, - "devDependencies": { - "gitbook-plugin": "*" - }, - "engines": { - "gitbook": ">=3.0.0" - }, - "scripts": { - "build-js": "gitbook-plugin build ./src/index.js ./_assets/plugin.js", - "prepublish": "npm run build-js" - }, - "homepage": "https://github.com/GitbookIO/gitbook", - "repository": { - "type": "git", - "url": "https://github.com/GitbookIO/gitbook.git" - }, - "bugs": { - "url": "https://github.com/GitbookIO/gitbook/issues" - } -} + "name": "gitbook-plugin-highlight", + "description": "Syntax highlighter for Gitbook", + "main": "index.js", + "browser": "./_assets/plugin.js", + "version": "4.0.0", + "dependencies": { + "gitbook-core": "4.0.0", + "highlight.js": "9.7.0" + }, + "devDependencies": { + "gitbook-plugin": "4.0.0" + }, + "engines": { + "gitbook": ">=3.0.0" + }, + "scripts": { + "build-js": "gitbook-plugin build ./src/index.js ./_assets/plugin.js", + "prepublish": "npm run build-js" + }, + "homepage": "https://github.com/GitbookIO/gitbook", + "repository": { + "type": "git", + "url": "https://github.com/GitbookIO/gitbook.git" + }, + "bugs": { + "url": "https://github.com/GitbookIO/gitbook/issues" + } +}
\ No newline at end of file diff --git a/packages/gitbook-plugin-hints/package.json b/packages/gitbook-plugin-hints/package.json index 1635d36..66dedd0 100644 --- a/packages/gitbook-plugin-hints/package.json +++ b/packages/gitbook-plugin-hints/package.json @@ -1,29 +1,29 @@ { - "name": "gitbook-plugin-hints", - "description": "Defines four types of styled hint blocks: info, danger, tip, working.", - "main": "index.js", - "browser": "./_assets/plugin.js", - "version": "2.0.0", - "dependencies": { - "classnames": "^2.2.5", - "gitbook-core": "^0.0.0" - }, - "devDependencies": { - "gitbook-plugin": "*" - }, - "engines": { - "gitbook": ">=4.0.0" - }, - "scripts": { - "build-js": "gitbook-plugin build ./src/index.js ./_assets/plugin.js", - "prepublish": "npm run build-js" - }, - "homepage": "https://github.com/GitBookIO/gitbook", - "repository": { - "type": "git", - "url": "https://github.com/GitBookIO/gitbook.git" - }, - "bugs": { - "url": "https://github.com/GitBookIO/gitbook/issues" - } -} + "name": "gitbook-plugin-hints", + "description": "Defines four types of styled hint blocks: info, danger, tip, working.", + "main": "index.js", + "browser": "./_assets/plugin.js", + "version": "4.0.0", + "dependencies": { + "classnames": "^2.2.5", + "gitbook-core": "4.0.0" + }, + "devDependencies": { + "gitbook-plugin": "4.0.0" + }, + "engines": { + "gitbook": ">=4.0.0" + }, + "scripts": { + "build-js": "gitbook-plugin build ./src/index.js ./_assets/plugin.js", + "prepublish": "npm run build-js" + }, + "homepage": "https://github.com/GitBookIO/gitbook", + "repository": { + "type": "git", + "url": "https://github.com/GitBookIO/gitbook.git" + }, + "bugs": { + "url": "https://github.com/GitBookIO/gitbook/issues" + } +}
\ No newline at end of file diff --git a/packages/gitbook-plugin-lunr/package.json b/packages/gitbook-plugin-lunr/package.json index a5e5d61..7093e7f 100644 --- a/packages/gitbook-plugin-lunr/package.json +++ b/packages/gitbook-plugin-lunr/package.json @@ -1,44 +1,44 @@ { - "name": "gitbook-plugin-lunr", - "description": "Static and local index for search in GitBook", - "main": "index.js", - "browser": "./_assets/theme.js", - "version": "1.2.0", - "dependencies": { - "gitbook-core": "^0.0.0", - "html-entities": "1.2.0", - "lunr": "0.5.12" - }, - "devDependencies": { - "gitbook-plugin": "*" - }, - "engines": { - "gitbook": ">=3.0.0" - }, - "gitbook": { - "properties": { - "maxIndexSize": { + "name": "gitbook-plugin-lunr", + "description": "Static and local index for search in GitBook", + "main": "index.js", + "browser": "./_assets/theme.js", + "version": "4.0.0", + "dependencies": { + "gitbook-core": "4.0.0", + "html-entities": "1.2.0", + "lunr": "0.5.12" + }, + "devDependencies": { + "gitbook-plugin": "4.0.0" + }, + "engines": { + "gitbook": ">=3.0.0" + }, + "gitbook": { + "properties": { + "maxIndexSize": { "type": "number", "title": "Limit size for the index", "default": 1000000 - }, - "ignoreSpecialCharacters": { + }, + "ignoreSpecialCharacters": { "type": "boolean", "title": "Ignore special characters in words", "default": false - } - } - }, - "scripts": { - "build-js": "gitbook-plugin build ./src/index.js ./_assets/theme.js", - "prepublish": "npm run build-js" - }, - "homepage": "https://github.com/GitBookIO/gitbook", - "repository": { - "type": "git", - "url": "https://github.com/GitBookIO/gitbook.git" - }, - "bugs": { - "url": "https://github.com/GitBookIO/gitbook/issues" - } -} + } + } + }, + "scripts": { + "build-js": "gitbook-plugin build ./src/index.js ./_assets/theme.js", + "prepublish": "npm run build-js" + }, + "homepage": "https://github.com/GitBookIO/gitbook", + "repository": { + "type": "git", + "url": "https://github.com/GitBookIO/gitbook.git" + }, + "bugs": { + "url": "https://github.com/GitBookIO/gitbook/issues" + } +}
\ No newline at end of file diff --git a/packages/gitbook-plugin-search/package.json b/packages/gitbook-plugin-search/package.json index d6741c9..2a5c610 100644 --- a/packages/gitbook-plugin-search/package.json +++ b/packages/gitbook-plugin-search/package.json @@ -1,29 +1,29 @@ { - "name": "gitbook-plugin-search", - "description": "Search integration in GitBook", - "main": "index.js", - "browser": "./_assets/theme.js", - "version": "2.2.1", - "dependencies": { - "gitbook-core": "^0.0.0" - }, - "devDependencies": { - "gitbook-plugin": "*" - }, - "engines": { - "gitbook": ">=3.0.0" - }, - "scripts": { - "build-js": "gitbook-plugin build ./src/index.js ./_assets/theme.js", - "prepublish": "npm run build-js" - }, - "homepage": "https://github.com/GitbookIO/gitbook", - "repository": { - "type": "git", - "url": "https://github.com/GitbookIO/gitbook.git" - }, - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/GitbookIO/gitbook/issues" - } -} + "name": "gitbook-plugin-search", + "description": "Search integration in GitBook", + "main": "index.js", + "browser": "./_assets/theme.js", + "version": "4.0.0", + "dependencies": { + "gitbook-core": "4.0.0" + }, + "devDependencies": { + "gitbook-plugin": "4.0.0" + }, + "engines": { + "gitbook": ">=3.0.0" + }, + "scripts": { + "build-js": "gitbook-plugin build ./src/index.js ./_assets/theme.js", + "prepublish": "npm run build-js" + }, + "homepage": "https://github.com/GitbookIO/gitbook", + "repository": { + "type": "git", + "url": "https://github.com/GitbookIO/gitbook.git" + }, + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/GitbookIO/gitbook/issues" + } +}
\ No newline at end of file diff --git a/packages/gitbook-plugin-sharing/package.json b/packages/gitbook-plugin-sharing/package.json index 21fc038..9586ae3 100644 --- a/packages/gitbook-plugin-sharing/package.json +++ b/packages/gitbook-plugin-sharing/package.json @@ -1,28 +1,28 @@ { - "name": "gitbook-plugin-sharing", - "description": "Sharing buttons in the toolbar", - "main": "index.js", - "browser": "./_assets/plugin.js", - "version": "4.0.0", - "dependencies": { - "gitbook-core": "^0.0.0" - }, - "devDependencies": { - "gitbook-plugin": "*" - }, - "engines": { - "gitbook": ">=3.0.0" - }, - "scripts": { - "build-js": "gitbook-plugin build ./src/index.js ./_assets/plugin.js", - "prepublish": "npm run build-js" - }, - "homepage": "https://github.com/GitbookIO/gitbook", - "repository": { - "type": "git", - "url": "https://github.com/GitbookIO/gitbook.git" - }, - "bugs": { - "url": "https://github.com/GitbookIO/gitbook/issues" - } -} + "name": "gitbook-plugin-sharing", + "description": "Sharing buttons in the toolbar", + "main": "index.js", + "browser": "./_assets/plugin.js", + "version": "4.0.0", + "dependencies": { + "gitbook-core": "4.0.0" + }, + "devDependencies": { + "gitbook-plugin": "4.0.0" + }, + "engines": { + "gitbook": ">=3.0.0" + }, + "scripts": { + "build-js": "gitbook-plugin build ./src/index.js ./_assets/plugin.js", + "prepublish": "npm run build-js" + }, + "homepage": "https://github.com/GitbookIO/gitbook", + "repository": { + "type": "git", + "url": "https://github.com/GitbookIO/gitbook.git" + }, + "bugs": { + "url": "https://github.com/GitbookIO/gitbook/issues" + } +}
\ No newline at end of file diff --git a/packages/gitbook-plugin-theme-default/less/Body.less b/packages/gitbook-plugin-theme-default/less/Body.less new file mode 100644 index 0000000..7524a24 --- /dev/null +++ b/packages/gitbook-plugin-theme-default/less/Body.less @@ -0,0 +1,5 @@ +.Body { + overflow: auto; + width: 100%; + height: 100%; +} diff --git a/packages/gitbook-plugin-theme-default/less/main.less b/packages/gitbook-plugin-theme-default/less/main.less index 9858a2f..cb5d07d 100644 --- a/packages/gitbook-plugin-theme-default/less/main.less +++ b/packages/gitbook-plugin-theme-default/less/main.less @@ -12,6 +12,7 @@ @import "Page.less"; @import "Toolbar.less"; @import "Search.less"; +@import "Body.less"; * { .box-sizing(border-box); diff --git a/packages/gitbook-plugin-theme-default/package.json b/packages/gitbook-plugin-theme-default/package.json index d26b46a..599f64c 100644 --- a/packages/gitbook-plugin-theme-default/package.json +++ b/packages/gitbook-plugin-theme-default/package.json @@ -1,79 +1,79 @@ { - "name": "gitbook-plugin-theme-default", - "description": "Default theme for GitBook", - "main": "./index.js", - "browser": "./_assets/theme.js", - "version": "1.0.5", - "engines": { - "gitbook": ">=3.0.0" - }, - "dependencies": { - "gitbook-core": "^0.0.0" - }, - "devDependencies": { - "classnames": "^2.2.5", - "font-awesome": "^4.6.3", - "gitbook-markdown-css": "^1.0.1", - "gitbook-plugin": "*", - "less": "^2.7.1", - "less-plugin-clean-css": "^1.5.1", - "preboot": "git+https://github.com/mdo/preboot.git#4aab4edd85f076d50609cbe28e4fe66cc0771701" - }, - "scripts": { - "prepublish": "./prepublish.sh" - }, - "repository": { - "type": "git", - "url": "https://github.com/GitbookIO/gitbook.git" - }, - "author": "GitBook Inc. <contact@gitbook.com>", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/GitbookIO/gitbook/issues" - }, - "contributors": [ - { - "name": "Samy Pessé", - "email": "samy@gitbook.com" - } - ], - "gitbook": { - "properties": { - "styles": { - "type": "object", - "title": "Custom Stylesheets", - "properties": { - "website": { - "title": "Stylesheet for website output", - "default": "styles/website.css" - }, - "pdf": { - "title": "Stylesheet for PDF output", - "default": "styles/pdf.css" - }, - "epub": { - "title": "Stylesheet for ePub output", - "default": "styles/epub.css" - }, - "mobi": { - "title": "Stylesheet for Mobi output", - "default": "styles/mobi.css" - }, - "ebook": { - "title": "Stylesheet for ebook outputs (PDF, ePub, Mobi)", - "default": "styles/ebook.css" - }, - "print": { - "title": "Stylesheet to replace default ebook css", - "default": "styles/print.css" - } - } - }, - "showLevel": { - "type": "boolean", - "title": "Show level indicator in TOC", - "default": false + "name": "gitbook-plugin-theme-default", + "description": "Default theme for GitBook", + "main": "./index.js", + "browser": "./_assets/theme.js", + "version": "4.0.0", + "engines": { + "gitbook": ">=3.0.0" + }, + "dependencies": { + "gitbook-core": "4.0.0" + }, + "devDependencies": { + "classnames": "^2.2.5", + "font-awesome": "^4.6.3", + "gitbook-markdown-css": "^1.0.1", + "gitbook-plugin": "4.0.0", + "less": "^2.7.1", + "less-plugin-clean-css": "^1.5.1", + "preboot": "git+https://github.com/mdo/preboot.git#4aab4edd85f076d50609cbe28e4fe66cc0771701" + }, + "scripts": { + "prepublish": "./prepublish.sh" + }, + "repository": { + "type": "git", + "url": "https://github.com/GitbookIO/gitbook.git" + }, + "author": "GitBook Inc. <contact@gitbook.com>", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/GitbookIO/gitbook/issues" + }, + "contributors": [ + { + "name": "Samy Pessé", + "email": "samy@gitbook.com" } - } - } -} + ], + "gitbook": { + "properties": { + "styles": { + "type": "object", + "title": "Custom Stylesheets", + "properties": { + "website": { + "title": "Stylesheet for website output", + "default": "styles/website.css" + }, + "pdf": { + "title": "Stylesheet for PDF output", + "default": "styles/pdf.css" + }, + "epub": { + "title": "Stylesheet for ePub output", + "default": "styles/epub.css" + }, + "mobi": { + "title": "Stylesheet for Mobi output", + "default": "styles/mobi.css" + }, + "ebook": { + "title": "Stylesheet for ebook outputs (PDF, ePub, Mobi)", + "default": "styles/ebook.css" + }, + "print": { + "title": "Stylesheet to replace default ebook css", + "default": "styles/print.css" + } + } + }, + "showLevel": { + "type": "boolean", + "title": "Show level indicator in TOC", + "default": false + } + } + } +}
\ No newline at end of file diff --git a/packages/gitbook-plugin-theme-default/src/index.js b/packages/gitbook-plugin-theme-default/src/index.js index c391908..ad96175 100644 --- a/packages/gitbook-plugin-theme-default/src/index.js +++ b/packages/gitbook-plugin-theme-default/src/index.js @@ -7,7 +7,7 @@ const locales = require('./i18n'); module.exports = GitBook.createPlugin({ activate: (dispatch, state, { Components, I18n }) => { - dispatch(Components.registerComponent(Theme, { role: 'Body' })); + dispatch(Components.registerComponent(Theme, { role: 'website:body' })); dispatch(I18n.registerLocales(locales)); }, reduce: reduceState diff --git a/packages/gitbook-plugin/package.json b/packages/gitbook-plugin/package.json index c342eef..64cbf6b 100644 --- a/packages/gitbook-plugin/package.json +++ b/packages/gitbook-plugin/package.json @@ -1,39 +1,39 @@ { - "name": "gitbook-plugin", - "version": "0.0.0", - "description": "CLI for compiling and testing plugins", - "main": "./lib/index.js", - "dependencies": { - "babel-preset-es2015": "^6.14.0", - "babel-preset-react": "^6.11.1", - "babelify": "^7.3.0", - "browserify": "^13.1.0", - "commander": "^2.9.0", - "fs-extra": "^0.30.0", - "inquirer": "^1.1.3", - "q": "^1.4.1", - "winston": "^2.2.0" - }, - "devDependencies": { - "babel-cli": "^6.14.0", - "babel-preset-es2015": "^6.14.0", - "babel-preset-react": "^6.11.1", - "babel-preset-stage-2": "^6.13.0" - }, - "bin": { - "gitbook-plugin": "./lib/cli.js" - }, - "scripts": { - "dist": "rm -rf lib/ && babel -d lib/ src/ && chmod +x ./lib/cli.js", - "prepublish": "npm run dist" - }, - "repository": { - "type": "git", - "url": "https://github.com/GitbookIO/gitbook.git" - }, - "author": "GitBook Inc. <contact@gitbook.com>", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/GitbookIO/gitbook/issues" - } -} + "name": "gitbook-plugin", + "version": "4.0.0", + "description": "CLI for compiling and testing plugins", + "main": "./lib/index.js", + "dependencies": { + "babel-preset-es2015": "^6.14.0", + "babel-preset-react": "^6.11.1", + "babelify": "^7.3.0", + "browserify": "^13.1.0", + "commander": "^2.9.0", + "fs-extra": "^0.30.0", + "inquirer": "^1.1.3", + "q": "^1.4.1", + "winston": "^2.2.0" + }, + "devDependencies": { + "babel-cli": "^6.14.0", + "babel-preset-es2015": "^6.14.0", + "babel-preset-react": "^6.11.1", + "babel-preset-stage-2": "^6.13.0" + }, + "bin": { + "gitbook-plugin": "./lib/cli.js" + }, + "scripts": { + "dist": "rm -rf lib/ && babel -d lib/ src/ && chmod +x ./lib/cli.js", + "prepublish": "npm run dist" + }, + "repository": { + "type": "git", + "url": "https://github.com/GitbookIO/gitbook.git" + }, + "author": "GitBook Inc. <contact@gitbook.com>", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/GitbookIO/gitbook/issues" + } +}
\ No newline at end of file diff --git a/packages/gitbook/package.json b/packages/gitbook/package.json index 12b190a..01fa93e 100644 --- a/packages/gitbook/package.json +++ b/packages/gitbook/package.json @@ -1,110 +1,110 @@ { - "name": "gitbook", - "version": "4.0.0", - "homepage": "https://www.gitbook.com", - "description": "Library and cmd utility to generate GitBooks", - "main": "lib/index.js", - "browser": "./lib/browser.js", - "dependencies": { - "bash-color": "0.0.4", - "cheerio": "0.20.0", - "chokidar": "1.5.0", - "cp": "0.2.0", - "cpr": "1.1.1", - "crc": "3.4.0", - "destroy": "1.0.4", - "direction": "0.1.5", - "dom-serializer": "0.1.0", - "error": "7.0.2", - "escape-html": "^1.0.3", - "escape-string-regexp": "1.0.5", - "extend": "^3.0.0", - "fresh-require": "1.0.3", - "front-matter": "^2.1.0", - "gitbook-asciidoc": "1.2.2", - "gitbook-core": "*", - "gitbook-markdown": "1.3.2", - "gitbook-plugin-headings": "1.0.0", - "gitbook-plugin-highlight": "2.0.2", - "gitbook-plugin-livereload": "0.0.1", - "gitbook-plugin-lunr": "1.2.0", - "gitbook-plugin-search": "2.2.1", - "gitbook-plugin-sharing": "4.0.0", - "gitbook-plugin-theme-default": "1.0.5", - "gitbook-plugin-hints": "2.0.0", - "github-slugid": "1.0.1", - "graceful-fs": "4.1.4", - "i18n-t": "1.0.1", - "ignore": "3.1.2", - "immutable": "^3.8.1", - "is": "^3.1.0", - "js-yaml": "^3.6.1", - "json-schema-defaults": "0.1.1", - "jsonschema": "1.1.0", - "juice": "2.0.0", - "mkdirp": "0.5.1", - "moment": "2.13.0", - "npm": "3.9.2", - "npmi": "2.0.1", - "nunjucks": "2.4.2", - "nunjucks-do": "1.0.0", - "object-path": "^0.9.2", - "omit-keys": "^0.1.0", - "open": "0.0.5", - "q": "1.4.1", - "react": "^15.3.2", - "react-dom": "^15.3.2", - "react-redux": "^4.4.5", - "read-installed": "^4.0.3", - "redux": "^3.5.2", - "request": "2.72.0", - "resolve": "1.1.7", - "rmdir": "1.2.0", - "semver": "5.1.0", - "send": "0.13.2", - "spawn-cmd": "0.0.2", - "tiny-lr": "0.2.1", - "tmp": "0.0.28", - "urijs": "1.18.0" - }, - "scripts": { - "test": "./node_modules/.bin/mocha ./testing/setup.js \"./src/**/*/__tests__/*.js\" --bail --reporter=list --timeout=10000 --compilers js:babel-register", - "dist": "rm -rf lib/ && babel -d lib/ src/ --source-maps --ignore \"**/*/__tests__/*.js\"", - "prepublish": "npm run dist" - }, - "repository": { - "type": "git", - "url": "https://github.com/GitbookIO/gitbook.git" - }, - "bin": { - "gitbook": "./bin/gitbook.js" - }, - "keywords": [ - "git", - "book", - "gitbook" - ], - "author": "GitBook Inc. <contact@gitbook.com>", - "license": "Apache-2.0", - "bugs": { - "url": "https://github.com/GitbookIO/gitbook/issues" - }, - "contributors": [ - { - "name": "Aaron O'Mullan", - "email": "aaron@gitbook.com" - }, - { - "name": "Samy Pessé", - "email": "samy@gitbook.com" - } - ], - "devDependencies": { - "babel-cli": "^6.14.0", - "babel-preset-es2015": "^6.14.0", - "babel-preset-react": "^6.11.1", - "babel-preset-stage-2": "^6.13.0", - "babel-register": "^6.14.0", - "mocha": "^3.0.2" - } -} + "name": "gitbook", + "version": "4.0.0", + "homepage": "https://www.gitbook.com", + "description": "Library and cmd utility to generate GitBooks", + "main": "lib/index.js", + "browser": "./lib/browser.js", + "dependencies": { + "bash-color": "0.0.4", + "cheerio": "0.20.0", + "chokidar": "1.5.0", + "cp": "0.2.0", + "cpr": "1.1.1", + "crc": "3.4.0", + "destroy": "1.0.4", + "direction": "0.1.5", + "dom-serializer": "0.1.0", + "error": "7.0.2", + "escape-html": "^1.0.3", + "escape-string-regexp": "1.0.5", + "extend": "^3.0.0", + "fresh-require": "1.0.3", + "front-matter": "^2.1.0", + "gitbook-asciidoc": "1.2.2", + "gitbook-core": "4.0.0", + "gitbook-markdown": "1.3.2", + "gitbook-plugin-headings": "4.0.0", + "gitbook-plugin-highlight": "4.0.0", + "gitbook-plugin-livereload": "0.0.1", + "gitbook-plugin-lunr": "4.0.0", + "gitbook-plugin-search": "4.0.0", + "gitbook-plugin-sharing": "4.0.0", + "gitbook-plugin-theme-default": "4.0.0", + "gitbook-plugin-hints": "4.0.0", + "github-slugid": "1.0.1", + "graceful-fs": "4.1.4", + "i18n-t": "1.0.1", + "ignore": "3.1.2", + "immutable": "^3.8.1", + "is": "^3.1.0", + "js-yaml": "^3.6.1", + "json-schema-defaults": "0.1.1", + "jsonschema": "1.1.0", + "juice": "2.0.0", + "mkdirp": "0.5.1", + "moment": "2.13.0", + "npm": "3.9.2", + "npmi": "2.0.1", + "nunjucks": "2.4.2", + "nunjucks-do": "1.0.0", + "object-path": "^0.9.2", + "omit-keys": "^0.1.0", + "open": "0.0.5", + "q": "1.4.1", + "react": "^15.3.2", + "react-dom": "^15.3.2", + "react-redux": "^4.4.5", + "read-installed": "^4.0.3", + "redux": "^3.5.2", + "request": "2.72.0", + "resolve": "1.1.7", + "rmdir": "1.2.0", + "semver": "5.1.0", + "send": "0.13.2", + "spawn-cmd": "0.0.2", + "tiny-lr": "0.2.1", + "tmp": "0.0.28", + "urijs": "1.18.0" + }, + "scripts": { + "test": "./node_modules/.bin/mocha ./testing/setup.js \"./src/**/*/__tests__/*.js\" --bail --reporter=list --timeout=100000 --compilers js:babel-register", + "dist": "rm -rf lib/ && babel -d lib/ src/ --source-maps --ignore \"**/*/__tests__/*.js\"", + "prepublish": "npm run dist" + }, + "repository": { + "type": "git", + "url": "https://github.com/GitbookIO/gitbook.git" + }, + "bin": { + "gitbook": "./bin/gitbook.js" + }, + "keywords": [ + "git", + "book", + "gitbook" + ], + "author": "GitBook Inc. <contact@gitbook.com>", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/GitbookIO/gitbook/issues" + }, + "contributors": [ + { + "name": "Aaron O'Mullan", + "email": "aaron@gitbook.com" + }, + { + "name": "Samy Pessé", + "email": "samy@gitbook.com" + } + ], + "devDependencies": { + "babel-cli": "^6.14.0", + "babel-preset-es2015": "^6.14.0", + "babel-preset-react": "^6.11.1", + "babel-preset-stage-2": "^6.13.0", + "babel-register": "^6.14.0", + "mocha": "^3.0.2" + } +}
\ No newline at end of file diff --git a/packages/gitbook/src/browser/loadPlugins.js b/packages/gitbook/src/browser/loadPlugins.js index 0f26aae..bd8a195 100644 --- a/packages/gitbook/src/browser/loadPlugins.js +++ b/packages/gitbook/src/browser/loadPlugins.js @@ -1,18 +1,20 @@ const path = require('path'); /** - * Load all browser plugins + * Load all browser plugins. + * * @param {OrderedMap<Plugin>} plugins + * @param {String} type ('browser', 'ebook') * @return {Array} */ -function loadPlugins(plugins) { +function loadPlugins(plugins, type) { return plugins .valueSeq() - .filter(plugin => plugin.getPackage().has('browser')) + .filter(plugin => plugin.getPackage().has(type)) .map(plugin => { const browserFile = path.resolve( plugin.getPath(), - plugin.getPackage().get('browser') + plugin.getPackage().get(type) ); return require(browserFile); diff --git a/packages/gitbook/src/browser/render.js b/packages/gitbook/src/browser/render.js index 616b157..d5062c6 100644 --- a/packages/gitbook/src/browser/render.js +++ b/packages/gitbook/src/browser/render.js @@ -4,9 +4,7 @@ const GitBook = require('gitbook-core'); const loadPlugins = require('./loadPlugins'); -const BOOTSTRAP_CODE = '(function() { require("gitbook-core").bootstrap() })()'; - -function HTML({head, innerHTML, payload, scripts}) { +function HTML({head, innerHTML, payload, scripts, bootstrap}) { const attrs = head.htmlAttributes.toComponent(); return ( @@ -23,7 +21,7 @@ function HTML({head, innerHTML, payload, scripts}) { return <script key={script} src={script} />; })} <script type="application/payload+json" dangerouslySetInnerHTML={{__html: payload}} /> - <script type="application/javascript" dangerouslySetInnerHTML={{__html: BOOTSTRAP_CODE}} /> + <script type="application/javascript" dangerouslySetInnerHTML={{__html: bootstrap}} /> {head.script.toComponent()} </body> </html> @@ -33,27 +31,40 @@ HTML.propTypes = { head: React.PropTypes.object, innerHTML: React.PropTypes.string, payload: React.PropTypes.string, + bootstrap: React.PropTypes.string, scripts: React.PropTypes.arrayOf(React.PropTypes.string) }; /** - * Render a page + * Get bootstrap code for a role + * @param {String} role + * @return {String} + */ +function getBootstrapCode(role) { + return `(function() { require("gitbook-core").bootstrap({ role: "${role}" }) })()`; +} + +/** + * Render a view using plugins. + * * @param {OrderedMap<String:Plugin>} plugin * @param {Object} initialState + * @param {String} type ("ebook" or "browser") + * @param {String} role * @return {String} html */ -function render(plugins, initialState) { +function render(plugins, initialState, type, role) { // Load the plugins - const browserPlugins = loadPlugins(plugins); + const browserPlugins = loadPlugins(plugins, type); const payload = JSON.stringify(initialState); const context = GitBook.createContext(browserPlugins, initialState); const scripts = plugins.toList() - .filter(plugin => plugin.getPackage().has('browser')) + .filter(plugin => plugin.getPackage().has(type)) .map(plugin => 'gitbook/plugins/' + plugin.getName() + '.js') .toArray(); - const el = GitBook.renderWithContext(context); + const el = GitBook.renderWithContext(context, { role }); // We're done with the context context.deactivate(); @@ -69,6 +80,7 @@ function render(plugins, initialState) { head={head} innerHTML={innerHTML} payload={payload} + bootstrap={getBootstrapCode(role)} scripts={['gitbook/core.js'].concat(scripts)} />; diff --git a/packages/gitbook/src/json/encodeState.js b/packages/gitbook/src/json/encodeState.js index d264835..50e7880 100644 --- a/packages/gitbook/src/json/encodeState.js +++ b/packages/gitbook/src/json/encodeState.js @@ -11,13 +11,12 @@ const encodeFile = require('./encodeFile'); * This JSON representation is used as initial state for the redux store. * * @param {Output} output - * @param {Page} page + * @param {Page} page? * @return {JSON} */ function encodeStateToJSON(output, page) { const book = output.getBook(); const urls = output.getURLIndex(); - const file = page.getFile(); return { output: { @@ -34,8 +33,8 @@ function encodeStateToJSON(output, page) { config: book.getConfig().getValues().toJS(), languages: book.isMultilingual() ? encodeLanguages(book.getLanguages()) : undefined, - page: encodePage(page, book.getSummary(), urls), - file: encodeFile(file, urls) + page: page ? encodePage(page, book.getSummary(), urls) : undefined, + file: page ? encodeFile(page.getFile(), urls) : undefined }; } diff --git a/packages/gitbook/src/models/__tests__/page.js b/packages/gitbook/src/models/__tests__/page.js index ad9420e..b004121 100644 --- a/packages/gitbook/src/models/__tests__/page.js +++ b/packages/gitbook/src/models/__tests__/page.js @@ -5,7 +5,7 @@ describe('Page', function() { describe('toText', function() { it('must not prepend frontmatter if no attributes', function() { - const page = Page().merge({ + const page = (new Page()).merge({ content: 'Hello World' }); @@ -13,7 +13,7 @@ describe('Page', function() { }); it('must prepend frontmatter if attributes', function() { - const page = Page().merge({ + const page = (new Page()).merge({ content: 'Hello World', attributes: Immutable.fromJS({ hello: 'world' @@ -24,4 +24,3 @@ describe('Page', function() { }); }); }); - diff --git a/packages/gitbook/src/models/__tests__/templateBlock.js b/packages/gitbook/src/models/__tests__/templateBlock.js index 20511be..408b57e 100644 --- a/packages/gitbook/src/models/__tests__/templateBlock.js +++ b/packages/gitbook/src/models/__tests__/templateBlock.js @@ -5,49 +5,56 @@ const Promise = require('../../utils/promise'); describe('TemplateBlock', function() { const TemplateBlock = require('../templateBlock'); - describe('create', function() { + describe('.create', function() { it('must initialize a simple TemplateBlock from a function', function() { const templateBlock = TemplateBlock.create('sayhello', function(block) { - return { - body: '<p>Hello, World!</p>', - parse: true - }; + return { message: 'Hello World' }; }); - // Check basic templateBlock properties expect(templateBlock.getName()).toBe('sayhello'); expect(templateBlock.getEndTag()).toBe('endsayhello'); expect(templateBlock.getBlocks().size).toBe(0); expect(templateBlock.getExtensionName()).toBe('BlocksayhelloExtension'); + }); + }); + + describe('.toProps', function() { + it('must handle sync method', function() { + const templateBlock = TemplateBlock.create('sayhello', function(block) { + return { message: 'Hello World' }; + }); - // Check result of applying block - return Promise() - .then(function() { - return templateBlock.applyBlock(); - }) - .then(function(result) { - expect(result.name).toBe('sayhello'); - expect(result.body).toBe('<p>Hello, World!</p>'); + return templateBlock.toProps() + .then(function(props) { + expect(props).toEqual({ message: 'Hello World' }); + }); + }); + + it('must not fsil if return a string', function() { + const templateBlock = TemplateBlock.create('sayhello', function(block) { + return 'Hello World'; + }); + + return templateBlock.toProps() + .then(function(props) { + expect(props).toEqual({ children: 'Hello World' }); }); }); }); - describe('getShortcuts', function() { + describe('.getShortcuts', function() { it('must return undefined if no shortcuts', function() { const templateBlock = TemplateBlock.create('sayhello', function(block) { - return { - body: '<p>Hello, World!</p>', - parse: true - }; + return { message: 'Hello World' }; }); expect(templateBlock.getShortcuts()).toNotExist(); }); - it('must return complete shortcut', function() { + it('.must return complete shortcut', function() { const templateBlock = TemplateBlock.create('sayhello', { process(block) { - return '<p>Hello, World!</p>'; + return { message: 'Hello World' }; }, shortcuts: { parsers: ['markdown'], @@ -66,43 +73,30 @@ describe('TemplateBlock', function() { }); }); - describe('toNunjucksExt()', function() { - it('should replace by block anchor', function() { + describe('.toNunjucksExt()', function() { + it('should render children correctly', function() { const templateBlock = TemplateBlock.create('sayhello', function(block) { return 'Hello'; }); - let blocks = {}; - // Create a fresh Nunjucks environment const env = new nunjucks.Environment(null, { autoescape: false }); // Add template block to environement - const Ext = templateBlock.toNunjucksExt({}, blocks); + const Ext = templateBlock.toNunjucksExt(); env.addExtension(templateBlock.getExtensionName(), new Ext()); // Render a template using the block const src = '{% sayhello %}{% endsayhello %}'; return Promise.nfcall(env.renderString.bind(env), src) .then(function(res) { - blocks = Immutable.fromJS(blocks); - expect(blocks.size).toBe(1); - - const blockId = blocks.keySeq().get(0); - const block = blocks.get(blockId); - - expect(res).toBe('{{-%' + blockId + '%-}}'); - expect(block.get('body')).toBe('Hello'); - expect(block.get('name')).toBe('sayhello'); + expect(res).toBe('<xblock name="sayhello" props="{}">Hello</xblock>'); }); }); - it('must create a valid nunjucks extension', function() { + it('must handle HTML children', function() { const templateBlock = TemplateBlock.create('sayhello', function(block) { - return { - body: '<p>Hello, World!</p>', - parse: true - }; + return '<p>Hello, World!</p>'; }); // Create a fresh Nunjucks environment @@ -116,15 +110,14 @@ describe('TemplateBlock', function() { const src = '{% sayhello %}{% endsayhello %}'; return Promise.nfcall(env.renderString.bind(env), src) .then(function(res) { - expect(res).toBe('<p>Hello, World!</p>'); + expect(res).toBe('<xblock name="sayhello" props="{}"><p>Hello, World!</p></xblock>'); }); }); - it('must apply block arguments correctly', function() { + it('must inline props without children', function() { const templateBlock = TemplateBlock.create('sayhello', function(block) { return { - body: '<' + block.kwargs.tag + '>Hello, ' + block.kwargs.name + '!</' + block.kwargs.tag + '>', - parse: true + message: block.kwargs.tag + ' ' + block.kwargs.name }; }); @@ -139,17 +132,17 @@ describe('TemplateBlock', function() { const src = '{% sayhello name="Samy", tag="p" %}{% endsayhello %}'; return Promise.nfcall(env.renderString.bind(env), src) .then(function(res) { - expect(res).toBe('<p>Hello, Samy!</p>'); + expect(res).toBe('<xblock name="sayhello" props="{"message":"p Samy"}"></xblock>'); }); }); it('must accept an async function', function() { const templateBlock = TemplateBlock.create('sayhello', function(block) { return Promise() + .delay(1) .then(function() { return { - body: 'Hello ' + block.body, - parse: true + children: 'Hello ' + block.children }; }); }); @@ -165,7 +158,7 @@ describe('TemplateBlock', function() { const src = '{% sayhello %}Samy{% endsayhello %}'; return Promise.nfcall(env.renderString.bind(env), src) .then(function(res) { - expect(res).toBe('Hello Samy'); + expect(res).toBe('<xblock name="sayhello" props="{}">Hello Samy</xblock>'); }); }); @@ -177,13 +170,10 @@ describe('TemplateBlock', function() { const nested = {}; block.blocks.forEach(function(blk) { - nested[blk.name] = blk.body.trim(); + nested[blk.name] = blk.children.trim(); }); - return { - body: '<p class="yoda">' + nested.end + ' ' + nested.start + '</p>', - parse: true - }; + return '<p class="yoda">' + nested.end + ' ' + nested.start + '</p>'; } }); @@ -198,7 +188,7 @@ describe('TemplateBlock', function() { const src = '{% yoda %}{% start %}this sentence should be{% end %}inverted{% endyoda %}'; return Promise.nfcall(env.renderString.bind(env), src) .then(function(res) { - expect(res).toBe('<p class="yoda">inverted this sentence should be</p>'); + expect(res).toBe('<xblock name="yoda" props="{}"><p class="yoda">inverted this sentence should be</p></xblock>'); }); }); }); diff --git a/packages/gitbook/src/models/__tests__/uriIndex.js b/packages/gitbook/src/models/__tests__/uriIndex.js index db3b13c..4448683 100644 --- a/packages/gitbook/src/models/__tests__/uriIndex.js +++ b/packages/gitbook/src/models/__tests__/uriIndex.js @@ -1,6 +1,6 @@ const URIIndex = require('../uriIndex'); -describe.only('URIIndex', () => { +describe('URIIndex', () => { let index; before(() => { @@ -40,6 +40,18 @@ describe.only('URIIndex', () => { }); + describe('.resolveToURL', () => { + + it('should resolve a basic file path with directory index', () => { + expect(index.resolveToURL('README.md')).toBe('./'); + }); + + it('should resolve a basic file path with directory index', () => { + expect(index.resolveToURL('hello/README.md')).toBe('hello/'); + }); + + }); + describe('.resolveFrom', () => { it('should resolve correctly in same directory', () => { diff --git a/packages/gitbook/src/models/ignore.js b/packages/gitbook/src/models/ignore.js index 99ade9a..547f6b4 100644 --- a/packages/gitbook/src/models/ignore.js +++ b/packages/gitbook/src/models/ignore.js @@ -1,42 +1,43 @@ -const Immutable = require('immutable'); +const { Record } = require('immutable'); const IgnoreMutable = require('ignore'); /* Immutable version of node-ignore */ -const Ignore = Immutable.Record({ - ignore: new IgnoreMutable() -}, 'Ignore'); - -Ignore.prototype.getIgnore = function() { - return this.get('ignore'); -}; -/** - Test if a file is ignored by these rules - - @param {String} filePath - @return {Boolean} -*/ -Ignore.prototype.isFileIgnored = function(filename) { - const ignore = this.getIgnore(); - return ignore.filter([filename]).length == 0; +const DEFAULTS = { + ignore: new IgnoreMutable() }; -/** - Add rules - - @param {String} - @return {Ignore} -*/ -Ignore.prototype.add = function(rule) { - const ignore = this.getIgnore(); - const newIgnore = new IgnoreMutable(); - - newIgnore.add(ignore); - newIgnore.add(rule); - - return this.set('ignore', newIgnore); -}; +class Ignore extends Record(DEFAULTS) { + getIgnore() { + return this.get('ignore'); + } + + /** + * Test if a file is ignored by these rules. + * @param {String} filePath + * @return {Boolean} isIgnored + */ + isFileIgnored(filename) { + const ignore = this.getIgnore(); + return ignore.filter([filename]).length == 0; + } + + /** + * Add rules. + * @param {String} + * @return {Ignore} + */ + add(rule) { + const ignore = this.getIgnore(); + const newIgnore = new IgnoreMutable(); + + newIgnore.add(ignore); + newIgnore.add(rule); + + return this.set('ignore', newIgnore); + } +} module.exports = Ignore; diff --git a/packages/gitbook/src/models/templateBlock.js b/packages/gitbook/src/models/templateBlock.js index e8d2aae..61c006f 100644 --- a/packages/gitbook/src/models/templateBlock.js +++ b/packages/gitbook/src/models/templateBlock.js @@ -1,6 +1,6 @@ const is = require('is'); const extend = require('extend'); -const Immutable = require('immutable'); +const { Record, List, Map } = require('immutable'); const escape = require('escape-html'); const Promise = require('../utils/promise'); @@ -9,232 +9,236 @@ const TemplateShortcut = require('./templateShortcut'); const NODE_ENDARGS = '%%endargs%%'; const HTML_TAGNAME = 'xblock'; -const TemplateBlock = Immutable.Record({ +const DEFAULTS = { // Name of block, also the start tag - name: String(), - + name: String(), // End tag, default to "end<name>" - end: String(), - + end: String(), // Function to process the block content - process: Function(), - + process: Function(), // List of String, for inner block tags - blocks: Immutable.List(), - + blocks: List(), // List of shortcuts to replace with this block - shortcuts: Immutable.Map() -}, 'TemplateBlock'); - -TemplateBlock.prototype.getName = function() { - return this.get('name'); -}; - -TemplateBlock.prototype.getEndTag = function() { - return this.get('end') || ('end' + this.getName()); + shortcuts: Map() }; -TemplateBlock.prototype.getProcess = function() { - return this.get('process'); -}; - -TemplateBlock.prototype.getBlocks = function() { - return this.get('blocks'); -}; - - -/** - * Return shortcuts associated with this block or undefined - * @return {TemplateShortcut|undefined} - */ -TemplateBlock.prototype.getShortcuts = function() { - const shortcuts = this.get('shortcuts'); - if (shortcuts.size === 0) { - return undefined; +class TemplateBlock extends Record(DEFAULTS) { + getName() { + return this.get('name'); } - return TemplateShortcut.createForBlock(this, shortcuts); -}; - -/** - * Return name for the nunjucks extension - * @return {String} - */ -TemplateBlock.prototype.getExtensionName = function() { - return 'Block' + this.getName() + 'Extension'; -}; - -/** - * Return a nunjucks extension to represents this block - * @return {Nunjucks.Extension} - */ -TemplateBlock.prototype.toNunjucksExt = function(mainContext, blocksOutput) { - blocksOutput = blocksOutput || {}; - - const that = this; - const name = this.getName(); - const endTag = this.getEndTag(); - const blocks = this.getBlocks().toJS(); - - function Ext() { - this.tags = [name]; - - this.parse = function(parser, nodes) { - let lastBlockName = null; - let lastBlockArgs = null; - const allBlocks = blocks.concat([endTag]); - - // Parse first block - const tok = parser.nextToken(); - lastBlockArgs = parser.parseSignature(null, true); - parser.advanceAfterBlockEnd(tok.value); - - const args = new nodes.NodeList(); - const bodies = []; - const blockNamesNode = new nodes.Array(tok.lineno, tok.colno); - const blockArgCounts = new nodes.Array(tok.lineno, tok.colno); - - // Parse while we found "end<block>" - do { - // Read body - const currentBody = parser.parseUntilBlocks(...allBlocks); - - // Handle body with previous block name and args - blockNamesNode.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockName)); - blockArgCounts.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockArgs.children.length)); - bodies.push(currentBody); - - // Append arguments of this block as arguments of the run function - lastBlockArgs.children.forEach(function(child) { - args.addChild(child); - }); - - // Read new block - lastBlockName = parser.nextToken().value; - - // Parse signature and move to the end of the block - if (lastBlockName != endTag) { - lastBlockArgs = parser.parseSignature(null, true); - } - - parser.advanceAfterBlockEnd(lastBlockName); - } while (lastBlockName != endTag); - - args.addChild(blockNamesNode); - args.addChild(blockArgCounts); - args.addChild(new nodes.Literal(args.lineno, args.colno, NODE_ENDARGS)); - - return new nodes.CallExtensionAsync(this, 'run', args, bodies); - }; - - this.run = function(context, ...fnArgs) { - let args; - const blocks = []; - let bodies = []; + getEndTag() { + return this.get('end') || ('end' + this.getName()); + } - // Extract callback - const callback = fnArgs.pop(); + getProcess() { + return this.get('process'); + } - // Detect end of arguments - const endArgIndex = fnArgs.indexOf(NODE_ENDARGS); + getBlocks() { + return this.get('blocks'); + } - // Extract arguments and bodies - args = fnArgs.slice(0, endArgIndex); - bodies = fnArgs.slice(endArgIndex + 1); - // Extract block counts - const blockArgCounts = args.pop(); - const blockNames = args.pop(); + /** + * Return shortcuts associated with this block or undefined + * @return {TemplateShortcut|undefined} + */ + getShortcuts() { + const shortcuts = this.get('shortcuts'); + if (shortcuts.size === 0) { + return undefined; + } - // Recreate list of blocks - blockNames.forEach((blkName, i) => { - const countArgs = blockArgCounts[i]; - const blockBody = bodies.shift(); + return TemplateShortcut.createForBlock(this, shortcuts); + } - const blockArgs = countArgs > 0 ? args.slice(0, countArgs) : []; - args = args.slice(countArgs); - const blockKwargs = extractKwargs(blockArgs); + /** + * Return name for the nunjucks extension + * @return {String} + */ + getExtensionName() { + return 'Block' + this.getName() + 'Extension'; + } - blocks.push({ - name: blkName, - children: blockBody(), - args: blockArgs, - kwargs: blockKwargs + /** + * Return a nunjucks extension to represents this block + * @return {Nunjucks.Extension} + */ + toNunjucksExt(mainContext = {}) { + const that = this; + const name = this.getName(); + const endTag = this.getEndTag(); + const blocks = this.getBlocks().toJS(); + + function Ext() { + this.tags = [name]; + + this.parse = (parser, nodes) => { + let lastBlockName = null; + let lastBlockArgs = null; + const allBlocks = blocks.concat([endTag]); + + // Parse first block + const tok = parser.nextToken(); + lastBlockArgs = parser.parseSignature(null, true); + parser.advanceAfterBlockEnd(tok.value); + + const args = new nodes.NodeList(); + const bodies = []; + const blockNamesNode = new nodes.Array(tok.lineno, tok.colno); + const blockArgCounts = new nodes.Array(tok.lineno, tok.colno); + + // Parse while we found "end<block>" + do { + // Read body + const currentBody = parser.parseUntilBlocks(...allBlocks); + + // Handle body with previous block name and args + blockNamesNode.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockName)); + blockArgCounts.addChild(new nodes.Literal(args.lineno, args.colno, lastBlockArgs.children.length)); + bodies.push(currentBody); + + // Append arguments of this block as arguments of the run function + lastBlockArgs.children.forEach(function(child) { + args.addChild(child); + }); + + // Read new block + lastBlockName = parser.nextToken().value; + + // Parse signature and move to the end of the block + if (lastBlockName != endTag) { + lastBlockArgs = parser.parseSignature(null, true); + } + + parser.advanceAfterBlockEnd(lastBlockName); + } while (lastBlockName != endTag); + + args.addChild(blockNamesNode); + args.addChild(blockArgCounts); + args.addChild(new nodes.Literal(args.lineno, args.colno, NODE_ENDARGS)); + + return new nodes.CallExtensionAsync(this, 'run', args, bodies); + }; + + this.run = (context, ...fnArgs) => { + let args; + const blocks = []; + let bodies = []; + + // Extract callback + const callback = fnArgs.pop(); + + // Detect end of arguments + const endArgIndex = fnArgs.indexOf(NODE_ENDARGS); + + // Extract arguments and bodies + args = fnArgs.slice(0, endArgIndex); + bodies = fnArgs.slice(endArgIndex + 1); + + // Extract block counts + const blockArgCounts = args.pop(); + const blockNames = args.pop(); + + // Recreate list of blocks + blockNames.forEach((blkName, i) => { + const countArgs = blockArgCounts[i]; + const blockBody = bodies.shift(); + + const blockArgs = countArgs > 0 ? args.slice(0, countArgs) : []; + args = args.slice(countArgs); + const blockKwargs = extractKwargs(blockArgs); + + blocks.push({ + name: blkName, + children: blockBody(), + args: blockArgs, + kwargs: blockKwargs + }); }); - }); - const mainBlock = blocks.shift(); - mainBlock.blocks = blocks; - - Promise() - .then(function() { - const ctx = extend({ - ctx: context - }, mainContext || {}); - - return that.applyBlock(mainBlock, ctx); - }) - .then(function(props) { - return that.blockResultToHtml(props); - }) - .nodeify(callback); - }; + const mainBlock = blocks.shift(); + mainBlock.blocks = blocks; + + Promise() + .then(function() { + const ctx = extend({ + ctx: context + }, mainContext); + + return that.toProps(mainBlock, ctx); + }) + .then(function(props) { + return that.toHTML(props); + }) + .nodeify(callback); + }; + } + + return Ext; } - return Ext; -}; - -/** - * Apply a block to a content. - * - * @param {Object} inner - * @param {Object} context - * @return {Promise<Props>|Props} - */ -TemplateBlock.prototype.applyBlock = function(inner, context) { - const processFn = this.getProcess(); - - inner = inner || {}; - inner.args = inner.args || []; - inner.kwargs = inner.kwargs || {}; - inner.blocks = inner.blocks || []; - - return processFn.call(context, inner); -}; + /** + * Apply a block an return the props + * + * @param {Object} inner + * @param {Object} context + * @return {Promise<Props>} + */ + toProps(inner, context) { + const processFn = this.getProcess(); + + inner = inner || {}; + inner.args = inner.args || []; + inner.kwargs = inner.kwargs || {}; + inner.blocks = inner.blocks || []; + + return Promise() + .then(() => processFn.call(context, inner)) + .then(props => { + if (is.string(props)) { + return { children: props }; + } + + return props; + }); + } -/** - * Convert a block props to HTML. This HTML is then being - * parsed by gitbook-core during rendering, and binded to the right react components. - * - * @param {Object} props - * @return {String} - */ -TemplateBlock.prototype.blockResultToHtml = function(props) { - const { children, ...innerProps } = props; - const payload = escape(JSON.stringify(innerProps)); + /** + * Convert a block props to HTML. This HTML is then being + * parsed by gitbook-core during rendering, and binded to the right react components. + * + * @param {Object} props + * @return {String} + */ + toHTML(props) { + const { children, ...innerProps } = props; + const payload = escape(JSON.stringify(innerProps)); + + return ( + `<${HTML_TAGNAME} name="${this.name}" props="${payload}">${children || ''}</${HTML_TAGNAME}>` + ); + } - return ( - `<${HTML_TAGNAME} name="${this.name}" props="${payload}">${children}</${HTML_TAGNAME}>` - ); -}; + /** + * Create a template block from a function or an object + * @param {String} blockName + * @param {Object} block + * @return {TemplateBlock} + */ + static create(blockName, block) { + if (is.fn(block)) { + block = new Map({ + process: block + }); + } -/** - * Create a template block from a function or an object - * @param {String} blockName - * @param {Object} block - * @return {TemplateBlock} - */ -TemplateBlock.create = function(blockName, block) { - if (is.fn(block)) { - block = new Immutable.Map({ - process: block - }); + block = new TemplateBlock(block); + block = block.set('name', blockName); + return block; } - - block = new TemplateBlock(block); - block = block.set('name', blockName); - return block; -}; +} /** * Extract kwargs from an arguments array diff --git a/packages/gitbook/src/models/templateEngine.js b/packages/gitbook/src/models/templateEngine.js index b218a9d..0d0dcb6 100644 --- a/packages/gitbook/src/models/templateEngine.js +++ b/packages/gitbook/src/models/templateEngine.js @@ -1,139 +1,133 @@ const nunjucks = require('nunjucks'); -const Immutable = require('immutable'); - -const TemplateEngine = Immutable.Record({ - // Map of {TemplateBlock} - blocks: Immutable.Map(), +const { Record, Map, List } = require('immutable'); +const DEFAULTS = { + // List of {TemplateBlock} + blocks: List(), // Map of Extension - extensions: Immutable.Map(), - + extensions: Map(), // Map of filters: {String} name -> {Function} fn - filters: Immutable.Map(), - + filters: Map(), // Map of globals: {String} name -> {Mixed} - globals: Immutable.Map(), - + globals: Map(), // Context for filters / blocks context: Object(), - // Nunjucks loader loader: nunjucks.FileSystemLoader('views') -}, 'TemplateEngine'); - -TemplateEngine.prototype.getBlocks = function() { - return this.get('blocks'); -}; - -TemplateEngine.prototype.getGlobals = function() { - return this.get('globals'); }; -TemplateEngine.prototype.getFilters = function() { - return this.get('filters'); -}; - -TemplateEngine.prototype.getShortcuts = function() { - return this.get('shortcuts'); -}; - -TemplateEngine.prototype.getLoader = function() { - return this.get('loader'); -}; - -TemplateEngine.prototype.getContext = function() { - return this.get('context'); -}; - -TemplateEngine.prototype.getExtensions = function() { - return this.get('extensions'); -}; - -/** - Return a block by its name (or undefined) - - @param {String} name - @return {TemplateBlock} -*/ -TemplateEngine.prototype.getBlock = function(name) { - const blocks = this.getBlocks(); - return blocks.find(function(block) { - return block.getName() === name; - }); -}; - -/** - Return a nunjucks environment from this configuration - - @return {Nunjucks.Environment} -*/ -TemplateEngine.prototype.toNunjucks = function(blocksOutput) { - const loader = this.getLoader(); - const blocks = this.getBlocks(); - const filters = this.getFilters(); - const globals = this.getGlobals(); - const extensions = this.getExtensions(); - const context = this.getContext(); - - const env = new nunjucks.Environment( - loader, - { - // Escaping is done after by the asciidoc/markdown parser - autoescape: false, - - // Syntax - tags: { - blockStart: '{%', - blockEnd: '%}', - variableStart: '{{', - variableEnd: '}}', - commentStart: '{###', - commentEnd: '###}' +class TemplateEngine extends Record(DEFAULTS) { + getBlocks() { + return this.get('blocks'); + } + + getGlobals() { + return this.get('globals'); + } + + getFilters() { + return this.get('filters'); + } + + getShortcuts() { + return this.get('shortcuts'); + } + + getLoader() { + return this.get('loader'); + } + + getContext() { + return this.get('context'); + } + + getExtensions() { + return this.get('extensions'); + } + + /** + * Return a block by its name (or undefined). + * @param {String} name + * @return {TemplateBlock} block? + */ + getBlock(name) { + const blocks = this.getBlocks(); + return blocks.find(function(block) { + return block.getName() === name; + }); + } + + /** + * Return a nunjucks environment from this configuration + * @return {Nunjucks.Environment} env + */ + toNunjucks() { + const loader = this.getLoader(); + const blocks = this.getBlocks(); + const filters = this.getFilters(); + const globals = this.getGlobals(); + const extensions = this.getExtensions(); + const context = this.getContext(); + + const env = new nunjucks.Environment( + loader, + { + // Escaping is done after by the asciidoc/markdown parser + autoescape: false, + + // Syntax + tags: { + blockStart: '{%', + blockEnd: '%}', + variableStart: '{{', + variableEnd: '}}', + commentStart: '{###', + commentEnd: '###}' + } } - } - ); - - // Add filters - filters.forEach(function(filterFn, filterName) { - env.addFilter(filterName, filterFn.bind(context)); - }); - - // Add blocks - blocks.forEach(function(block) { - const extName = block.getExtensionName(); - const Ext = block.toNunjucksExt(context, blocksOutput); - - env.addExtension(extName, new Ext()); - }); - - // Add globals - globals.forEach(function(globalValue, globalName) { - env.addGlobal(globalName, globalValue); - }); - - // Add other extensions - extensions.forEach(function(ext, extName) { - env.addExtension(extName, ext); - }); - - return env; -}; - -/** - Create a template engine - - @param {Object} def - @return {TemplateEngine} -*/ -TemplateEngine.create = function(def) { - return new TemplateEngine({ - blocks: Immutable.List(def.blocks || []), - extensions: Immutable.Map(def.extensions || {}), - filters: Immutable.Map(def.filters || {}), - globals: Immutable.Map(def.globals || {}), - context: def.context, - loader: def.loader - }); -}; + ); + + // Add filters + filters.forEach(function(filterFn, filterName) { + env.addFilter(filterName, filterFn.bind(context)); + }); + + // Add blocks + blocks.forEach(function(block) { + const extName = block.getExtensionName(); + const Ext = block.toNunjucksExt(context); + + env.addExtension(extName, new Ext()); + }); + + // Add globals + globals.forEach(function(globalValue, globalName) { + env.addGlobal(globalName, globalValue); + }); + + // Add other extensions + extensions.forEach(function(ext, extName) { + env.addExtension(extName, ext); + }); + + return env; + } + + /** + * Create a template engine. + * @param {Object} def + * @return {TemplateEngine} engine + */ + static create(def) { + return new TemplateEngine({ + blocks: List(def.blocks || []), + extensions: Map(def.extensions || {}), + filters: Map(def.filters || {}), + globals: Map(def.globals || {}), + context: def.context, + loader: def.loader + }); + } +} module.exports = TemplateEngine; diff --git a/packages/gitbook/src/models/templateOutput.js b/packages/gitbook/src/models/templateOutput.js deleted file mode 100644 index c6ff730..0000000 --- a/packages/gitbook/src/models/templateOutput.js +++ /dev/null @@ -1,42 +0,0 @@ -const Immutable = require('immutable'); - -const TemplateOutput = Immutable.Record({ - // Text content of the template - content: String(), - - // Map of blocks to replace / post process - blocks: Immutable.Map() -}, 'TemplateOutput'); - -TemplateOutput.prototype.getContent = function() { - return this.get('content'); -}; - -TemplateOutput.prototype.getBlocks = function() { - return this.get('blocks'); -}; - -/** - * Update content of this output - * @param {String} content - * @return {TemplateContent} - */ -TemplateOutput.prototype.setContent = function(content) { - return this.set('content', content); -}; - -/** - * Create a TemplateOutput from a text content - * and an object containing block definition - * @param {String} content - * @param {Object} blocks - * @return {TemplateOutput} - */ -TemplateOutput.create = function(content, blocks) { - return new TemplateOutput({ - content, - blocks: Immutable.fromJS(blocks) - }); -}; - -module.exports = TemplateOutput; diff --git a/packages/gitbook/src/output/__tests__/generateMock.js b/packages/gitbook/src/output/__tests__/generateMock.js index a0be244..6ae1de2 100644 --- a/packages/gitbook/src/output/__tests__/generateMock.js +++ b/packages/gitbook/src/output/__tests__/generateMock.js @@ -29,7 +29,7 @@ function generateMock(Generator, files) { book = book.setLogLevel('disabled'); return parseBook(book) - .then(function(resultBook) { + .then((resultBook) => { return generateBook(Generator, resultBook, { root: dir.name }); diff --git a/packages/gitbook/src/output/ebook/getPDFTemplate.js b/packages/gitbook/src/output/ebook/getPDFTemplate.js index c0faed3..53c7a82 100644 --- a/packages/gitbook/src/output/ebook/getPDFTemplate.js +++ b/packages/gitbook/src/output/ebook/getPDFTemplate.js @@ -1,40 +1,35 @@ const juice = require('juice'); -const WebsiteGenerator = require('../website'); const JSONUtils = require('../../json'); -const Templating = require('../../templating'); +const render = require('../../browser/render'); const Promise = require('../../utils/promise'); - /** - Generate PDF header/footer templates - - @param {Output} output - @param {String} type - @return {String} -*/ + * Generate PDF header/footer templates + * + * @param {Output} output + * @param {String} type ("footer" or "header") + * @return {String} html + */ function getPDFTemplate(output, type) { - const filePath = 'pdf_' + type + '.html'; const outputRoot = output.getRoot(); - const engine = WebsiteGenerator.createTemplateEngine(output, filePath); + const plugins = output.getPlugins(); - // Generate context - const context = JSONUtils.encodeOutput(output); - context.page = { + // Generate initial state + const initialState = JSONUtils.encodeState(output); + initialState.page = { num: '_PAGENUM_', title: '_SECTION_' }; // Render the theme - return Templating.renderFile(engine, 'ebook/' + filePath, context) + const html = render(plugins, initialState, 'ebook', `pdf:${type}`); - // Inline css and assets - .then(function(tplOut) { - return Promise.nfcall(juice.juiceResources, tplOut.getContent(), { - webResources: { - relativeTo: outputRoot - } - }); + // Inline CSS + return Promise.nfcall(juice.juiceResources, html, { + webResources: { + relativeTo: outputRoot + } }); } diff --git a/packages/gitbook/src/output/ebook/onFinish.js b/packages/gitbook/src/output/ebook/onFinish.js index adff798..7db757f 100644 --- a/packages/gitbook/src/output/ebook/onFinish.js +++ b/packages/gitbook/src/output/ebook/onFinish.js @@ -1,45 +1,39 @@ const path = require('path'); -const WebsiteGenerator = require('../website'); const JSONUtils = require('../../json'); -const Templating = require('../../templating'); const Promise = require('../../utils/promise'); const error = require('../../utils/error'); const command = require('../../utils/command'); const writeFile = require('../helper/writeFile'); +const render = require('../../browser/render'); const getConvertOptions = require('./getConvertOptions'); const SUMMARY_FILE = 'SUMMARY.html'; /** - Write the SUMMARY.html - - @param {Output} - @return {Output} -*/ + * Write the SUMMARY.html + * + * @param {Output} output + * @return {Output} output + */ function writeSummary(output) { - const options = output.getOptions(); - const prefix = options.get('prefix'); + const plugins = output.getPlugins(); - const filePath = SUMMARY_FILE; - const engine = WebsiteGenerator.createTemplateEngine(output, filePath); - const context = JSONUtils.encodeOutput(output); + // Generate initial state + const initialState = JSONUtils.encodeState(output); - // Render the theme - return Templating.renderFile(engine, prefix + '/summary.html', context) + // Render using React + const html = render(plugins, initialState, 'ebook', 'ebook:summary'); - // Write it to the disk - .then(function(tplOut) { - return writeFile(output, filePath, tplOut.getContent()); - }); + return writeFile(output, SUMMARY_FILE, html); } /** - Generate the ebook file as "index.pdf" - - @param {Output} - @return {Output} -*/ + * Generate the ebook file as "index.pdf" + * + * @param {Output} output + * @return {Output} output + */ function runEbookConvert(output) { const logger = output.getLogger(); const options = output.getOptions(); @@ -78,11 +72,11 @@ function runEbookConvert(output) { } /** - Finish the generation, generates the SUMMARY.html - - @param {Output} - @return {Output} -*/ + * Finish the generation, generates the SUMMARY.html + * + * @param {Output} output + * @return {Output} output + */ function onFinish(output) { return writeSummary(output) .then(runEbookConvert); diff --git a/packages/gitbook/src/output/ebook/onPage.js b/packages/gitbook/src/output/ebook/onPage.js index 520d296..a7c2137 100644 --- a/packages/gitbook/src/output/ebook/onPage.js +++ b/packages/gitbook/src/output/ebook/onPage.js @@ -2,11 +2,12 @@ const WebsiteGenerator = require('../website'); const Modifiers = require('../modifiers'); /** - Write a page for ebook output - - @param {Output} output - @param {Output} -*/ + * Write a page for ebook output. It renders it just as the website generator + * except that it inline assets. + * + * @param {Output} output + * @param {Output} output + */ function onPage(output, page) { const options = output.getOptions(); diff --git a/packages/gitbook/src/output/ebook/options.js b/packages/gitbook/src/output/ebook/options.js index 4156fac..d192fd2 100644 --- a/packages/gitbook/src/output/ebook/options.js +++ b/packages/gitbook/src/output/ebook/options.js @@ -2,16 +2,13 @@ const Immutable = require('immutable'); const Options = Immutable.Record({ // Root folder for the output - root: String(), - + root: String(), // Prefix for generation - prefix: String('ebook'), - + prefix: String('ebook'), // Format to generate using ebook-convert - format: String(), - + format: String(), // Force use of absolute urls ("index.html" instead of "/") - directoryIndex: Boolean(false) + directoryIndex: Boolean(false) }); module.exports = Options; diff --git a/packages/gitbook/src/output/generateBook.js b/packages/gitbook/src/output/generateBook.js index e27d3ce..0e2c230 100644 --- a/packages/gitbook/src/output/generateBook.js +++ b/packages/gitbook/src/output/generateBook.js @@ -58,7 +58,7 @@ function processOutput(generator, startOutput) { ) ) - .then(function(output) { + .then((output) => { if (!generator.onInit) { return output; } @@ -69,7 +69,7 @@ function processOutput(generator, startOutput) { .then(generateAssets.bind(null, generator)) .then(generatePages.bind(null, generator)) - .tap(function(output) { + .tap((output) => { const book = output.getBook(); if (!book.isMultilingual()) { @@ -111,7 +111,7 @@ function processOutput(generator, startOutput) { ) ) - .then(function(output) { + .then((output) => { if (!generator.onFinish) { return output; } diff --git a/packages/gitbook/src/output/generatePage.js b/packages/gitbook/src/output/generatePage.js index 671ac54..7375f1d 100644 --- a/packages/gitbook/src/output/generatePage.js +++ b/packages/gitbook/src/output/generatePage.js @@ -39,37 +39,26 @@ function generatePage(output, page) { return callPageHook('page:before', output, resultPage) // Escape code blocks with raw tags - .then(function(currentPage) { + .then((currentPage) => { return parser.preparePage(currentPage.getContent()); }) // Render templating syntax - .then(function(content) { + .then((content) => { const absoluteFilePath = path.join(book.getContentRoot(), filePath); return Templating.render(engine, absoluteFilePath, content, context); }) - .then(function(output) { - const content = output.getContent(); - - return parser.parsePage(content) - .then(function(result) { - return output.setContent(result.content); - }); - }) - - // Post processing for templating syntax - .then(function(output) { - return Templating.postRender(engine, output); - }) + // Parse with markdown/asciidoc parser + .then((content) => parser.parsePage(content)) // Return new page - .then(function(content) { + .then(({content}) => { return resultPage.set('content', content); }) // Call final hook - .then(function(currentPage) { + .then((currentPage) => { return callPageHook('page', output, currentPage); }); }) diff --git a/packages/gitbook/src/output/website/onPage.js b/packages/gitbook/src/output/website/onPage.js index 7dd35f3..90eec63 100644 --- a/packages/gitbook/src/output/website/onPage.js +++ b/packages/gitbook/src/output/website/onPage.js @@ -24,7 +24,7 @@ function onPage(output, page) { const initialState = JSONUtils.encodeState(output, resultPage); // Render the theme - const html = render(plugins, initialState); + const html = render(plugins, initialState, 'browser', 'website:body'); // Write it to the disk return writeFile(output, filePath, html); diff --git a/packages/gitbook/src/parse/__tests__/parseURIIndexFromPages.js b/packages/gitbook/src/parse/__tests__/parseURIIndexFromPages.js index e3b9b55..755b225 100644 --- a/packages/gitbook/src/parse/__tests__/parseURIIndexFromPages.js +++ b/packages/gitbook/src/parse/__tests__/parseURIIndexFromPages.js @@ -3,7 +3,7 @@ const { OrderedMap } = require('immutable'); const parseURIIndexFromPages = require('../parseURIIndexFromPages'); const Page = require('../../models/page'); -describe.only('parseURIIndexFromPages', () => { +describe('parseURIIndexFromPages', () => { it('should map file to html', () => { const pages = OrderedMap({ @@ -14,24 +14,13 @@ describe.only('parseURIIndexFromPages', () => { expect(urls.resolve('page.md')).toBe('page.html'); }); - it('should map README to index.html (directoryIndex: false)', () => { - const pages = OrderedMap({ - 'hello/README.md': new Page() - }); - const urls = parseURIIndexFromPages(pages, { - directoryIndex: false - }); - - expect(urls.resolve('hello/README.md')).toBe('hello/index.html'); - }); - it('should map README to folder', () => { const pages = OrderedMap({ 'hello/README.md': new Page() }); const urls = parseURIIndexFromPages(pages); - expect(urls.resolve('hello/README.md')).toBe('hello/'); + expect(urls.resolveToURL('hello/README.md')).toBe('hello/'); }); }); diff --git a/packages/gitbook/src/templating/__tests__/conrefsLoader.js b/packages/gitbook/src/templating/__tests__/conrefsLoader.js index 431d0a3..18dd5dd 100644 --- a/packages/gitbook/src/templating/__tests__/conrefsLoader.js +++ b/packages/gitbook/src/templating/__tests__/conrefsLoader.js @@ -4,30 +4,34 @@ const TemplateEngine = require('../../models/templateEngine'); const renderTemplate = require('../render'); const ConrefsLoader = require('../conrefsLoader'); -describe('ConrefsLoader', function() { +describe('ConrefsLoader', () => { const dirName = __dirname + '/'; const fileName = path.join(dirName, 'test.md'); - describe('Git', function() { - const engine = TemplateEngine({ - loader: new ConrefsLoader(dirName) + describe('Git', () => { + let engine; + + before(() => { + engine = new TemplateEngine({ + loader: new ConrefsLoader(dirName) + }); }); - it('should include content from git', function() { + it('should include content from git', () => { return renderTemplate(engine, fileName, '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test.md" %}') .then(function(out) { expect(out.getContent()).toBe('Hello from git'); }); }); - it('should handle deep inclusion (1)', function() { + it('should handle deep inclusion (1)', () => { return renderTemplate(engine, fileName, '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test2.md" %}') .then(function(out) { expect(out.getContent()).toBe('First Hello. Hello from git'); }); }); - it('should handle deep inclusion (2)', function() { + it('should handle deep inclusion (2)', () => { return renderTemplate(engine, fileName, '{% include "git+https://gist.github.com/69ea4542e4c8967d2fa7.git/test3.md" %}') .then(function(out) { expect(out.getContent()).toBe('First Hello. Hello from git'); @@ -35,20 +39,24 @@ describe('ConrefsLoader', function() { }); }); - describe('Local', function() { - const engine = TemplateEngine({ - loader: new ConrefsLoader(dirName) + describe('Local', () => { + let engine; + + before(() => { + engine = new TemplateEngine({ + loader: new ConrefsLoader(dirName) + }); }); - describe('Relative', function() { - it('should resolve basic relative filepath', function() { + describe('Relative', () => { + it('should resolve basic relative filepath', () => { return renderTemplate(engine, fileName, '{% include "include.md" %}') .then(function(out) { expect(out.getContent()).toBe('Hello World'); }); }); - it('should resolve basic parent filepath', function() { + it('should resolve basic parent filepath', () => { return renderTemplate(engine, path.join(dirName, 'hello/test.md'), '{% include "../include.md" %}') .then(function(out) { expect(out.getContent()).toBe('Hello World'); @@ -57,23 +65,24 @@ describe('ConrefsLoader', function() { }); describe('Absolute', function() { - it('should resolve absolute filepath', function() { + it('should resolve absolute filepath', () => { return renderTemplate(engine, fileName, '{% include "/include.md" %}') .then(function(out) { expect(out.getContent()).toBe('Hello World'); }); }); - it('should resolve absolute filepath when in a directory', function() { + it('should resolve absolute filepath when in a directory', () => { return renderTemplate(engine, path.join(dirName, 'hello/test.md'), '{% include "/include.md" %}') .then(function(out) { expect(out.getContent()).toBe('Hello World'); }); }); }); + }); - describe('transform', function() { + describe('transform', () => { function transform(filePath, source) { expect(filePath).toBeA('string'); expect(source).toBeA('string'); @@ -83,11 +92,16 @@ describe('ConrefsLoader', function() { return 'test-' + source + '-endtest'; } - const engine = TemplateEngine({ - loader: new ConrefsLoader(dirName, transform) + + let engine; + + before(() => { + engine = new TemplateEngine({ + loader: new ConrefsLoader(dirName, transform) + }); }); - it('should transform included content', function() { + it('should transform included content', () => { return renderTemplate(engine, fileName, '{% include "include.md" %}') .then(function(out) { expect(out.getContent()).toBe('test-Hello World-endtest'); @@ -95,4 +109,3 @@ describe('ConrefsLoader', function() { }); }); }); - diff --git a/packages/gitbook/src/templating/__tests__/postRender.js b/packages/gitbook/src/templating/__tests__/postRender.js deleted file mode 100644 index ff5bb61..0000000 --- a/packages/gitbook/src/templating/__tests__/postRender.js +++ /dev/null @@ -1,51 +0,0 @@ -const TemplateEngine = require('../../models/templateEngine'); -const TemplateBlock = require('../../models/templateBlock'); - -const renderTemplate = require('../render'); -const postRender = require('../postRender'); - -describe('postRender', function() { - let testPost; - const engine = TemplateEngine.create({ - blocks: [ - TemplateBlock.create('lower', function(blk) { - return blk.body.toLowerCase(); - }), - TemplateBlock.create('prefix', function(blk) { - return { - body: '_' + blk.body + '_', - post() { - testPost = true; - } - }; - }) - ] - }); - - it('should correctly replace block', function() { - return renderTemplate(engine, 'README.md', 'Hello {% lower %}Samy{% endlower %}') - .then(function(output) { - expect(output.getContent()).toMatch(/Hello \{\{\-([\S]+)\-\}\}/); - expect(output.getBlocks().size).toBe(1); - - return postRender(engine, output); - }) - .then(function(result) { - expect(result).toBe('Hello samy'); - }); - }); - - it('should correctly replace blocks', function() { - return renderTemplate(engine, 'README.md', 'Hello {% lower %}Samy{% endlower %}{% prefix %}Pesse{% endprefix %}') - .then(function(output) { - expect(output.getContent()).toMatch(/Hello \{\{\-([\S]+)\-\}\}\{\{\-([\S]+)\-\}\}/); - expect(output.getBlocks().size).toBe(2); - return postRender(engine, output); - }) - .then(function(result) { - expect(result).toBe('Hello samy_Pesse_'); - expect(testPost).toBe(true); - }); - }); - -}); diff --git a/packages/gitbook/src/templating/index.js b/packages/gitbook/src/templating/index.js index bd74aca..5189eac 100644 --- a/packages/gitbook/src/templating/index.js +++ b/packages/gitbook/src/templating/index.js @@ -1,10 +1,7 @@ module.exports = { - render: require('./render'), - renderFile: require('./renderFile'), - postRender: require('./postRender'), - replaceShortcuts: require('./replaceShortcuts'), - - ConrefsLoader: require('./conrefsLoader'), - ThemesLoader: require('./themesLoader') + render: require('./render'), + renderFile: require('./renderFile'), + replaceShortcuts: require('./replaceShortcuts'), + ConrefsLoader: require('./conrefsLoader') }; diff --git a/packages/gitbook/src/templating/listShortcuts.js b/packages/gitbook/src/templating/listShortcuts.js index 5df88bb..099b709 100644 --- a/packages/gitbook/src/templating/listShortcuts.js +++ b/packages/gitbook/src/templating/listShortcuts.js @@ -1,4 +1,4 @@ -const Immutable = require('immutable'); +const { List } = require('immutable'); const parsers = require('../parsers'); /** @@ -7,13 +7,13 @@ const parsers = require('../parsers'); * * @param {List<TemplateBlock>} engine * @param {String} filePath - * @return {List<TemplateShortcut>} + * @return {List<TemplateShortcut>} shortcuts */ function listShortcuts(blocks, filePath) { const parser = parsers.getForFile(filePath); if (!parser) { - return Immutable.List(); + return List(); } return blocks diff --git a/packages/gitbook/src/templating/postRender.js b/packages/gitbook/src/templating/postRender.js deleted file mode 100644 index 7fdfbf4..0000000 --- a/packages/gitbook/src/templating/postRender.js +++ /dev/null @@ -1,53 +0,0 @@ -const Promise = require('../utils/promise'); - - -/** - * Replace position markers of blocks by body after processing - * This is done to avoid that markdown/asciidoc processer parse the block content - * - * @param {String} content - * @return {Object} {blocks: Set, content: String} - */ -function replaceBlocks(content, blocks) { - const newContent = content.replace(/\{\{\-\%([\s\S]+?)\%\-\}\}/g, function(match, key) { - let replacedWith = match; - - const block = blocks.get(key); - if (block) { - replacedWith = replaceBlocks(block.get('body'), blocks); - } - - return replacedWith; - }); - - return newContent; -} - -/** - * Post render a template: - * - Execute "post" for blocks - * - Replace block content - * - * @param {TemplateEngine} engine - * @param {TemplateOutput} content - * @return {Promise<String>} - */ -function postRender(engine, output) { - const content = output.getContent(); - const blocks = output.getBlocks(); - - const result = replaceBlocks(content, blocks); - - return Promise.forEach(blocks, function(block) { - const post = block.get('post'); - - if (!post) { - return; - } - - return post(); - }) - .thenResolve(result); -} - -module.exports = postRender; diff --git a/packages/gitbook/src/templating/render.js b/packages/gitbook/src/templating/render.js index 53ed546..945d6dc 100644 --- a/packages/gitbook/src/templating/render.js +++ b/packages/gitbook/src/templating/render.js @@ -1,6 +1,5 @@ const Promise = require('../utils/promise'); const timing = require('../utils/timing'); -const TemplateOutput = require('../models/templateOutput'); const replaceShortcuts = require('./replaceShortcuts'); /** @@ -10,7 +9,7 @@ const replaceShortcuts = require('./replaceShortcuts'); * @param {String} filePath: absolute path for the loader * @param {String} content * @param {Object} context (optional) - * @return {Promise<TemplateOutput>} + * @return {Promise<String>} */ function renderTemplate(engine, filePath, content, context) { context = context || {}; @@ -35,9 +34,6 @@ function renderTemplate(engine, filePath, content, context) { path: filePath } ) - .then(function(content) { - return TemplateOutput.create(content, blocks); - }) ); } diff --git a/packages/gitbook/src/templating/themesLoader.js b/packages/gitbook/src/templating/themesLoader.js deleted file mode 100644 index b1639c5..0000000 --- a/packages/gitbook/src/templating/themesLoader.js +++ /dev/null @@ -1,115 +0,0 @@ -const Immutable = require('immutable'); -const nunjucks = require('nunjucks'); -const fs = require('fs'); -const path = require('path'); - -const PathUtils = require('../utils/path'); - - -const ThemesLoader = nunjucks.Loader.extend({ - init(searchPaths) { - this.searchPaths = Immutable.List(searchPaths) - .map(path.normalize); - }, - - /** - * Read source of a resolved filepath - * @param {String} - * @return {Object} - */ - getSource(fullpath) { - if (!fullpath) return null; - - fullpath = this.resolve(null, fullpath); - const templateName = this.getTemplateName(fullpath); - - if (!fullpath) { - return null; - } - - let 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, - 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() { - return true; - }, - - /** - * Get original search path containing a template - * @param {String} filepath - * @return {String} searchPath - */ - getSearchPath(filepath) { - return this.searchPaths - .sortBy(function(s) { - return -s.length; - }) - .find(function(basePath) { - return (filepath && filepath.indexOf(basePath) === 0); - }); - }, - - /** - * Get template name from a filepath - * @param {String} filepath - * @return {String} name - */ - getTemplateName(filepath) { - const 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(from, to) { - let searchPaths = this.searchPaths; - - // Relative template like "./test.html" - if (PathUtils.isPureRelative(to) && from) { - return path.resolve(path.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(function(basePath) { - const p = path.resolve(basePath, to); - - return ( - p.indexOf(basePath) === 0 - && fs.existsSync(p) - ); - }); - if (!resultFolder) return null; - return path.resolve(resultFolder, to); - } -}); - -module.exports = ThemesLoader; |