Compare commits

..

416 Commits

Author SHA1 Message Date
Samy Pessé 856b222a61 Bump version to 4.0.0-alpha.3 🚀 2017-01-13 19:11:15 +01:00
Samy Pessé fade3740c1 Fix publish script 2017-01-13 19:10:49 +01:00
Samy Pessé 803d6218a7 Remove bump script from bootstrapping 2017-01-13 19:03:48 +01:00
Nicolas Gaborit 7128db842a Test and fix conversion of empty parts (#1675)
* Test and fix conversion of empty parts

* Cover case of last part empty
2017-01-13 18:56:32 +01:00
Nicolas Gaborit 0342a11da0 Fix and test Book.getDefaultExt() (#1674) 2017-01-13 17:55:22 +01:00
Samy Pessé af80cbcd7c Add script to publish a new version 2017-01-13 16:18:28 +01:00
Samy Pessé a84d02ece0 Bump version to 4.0.0-alpha.2 🚀 2017-01-13 16:07:41 +01:00
Nicolas Gaborit 45b9fc2094 Adding more tests for (summary <-> document) transformations (#1665)
* Add tests for summaryFromDocument

* Add tests for summaryToDocument

* Add tests for untitled parts (HR)
2017-01-12 11:45:03 +01:00
Nicolas Gaborit a96ef569bd Clarify the use of {{ book.var }} (#1652)
Fixes #1425
2017-01-11 17:41:47 +01:00
Samy Pessé 4b3ac4e827 Add tests to changelog 2017-01-06 17:17:14 +01:00
Samy Pessé 7029c01806 Switch to markup-it for parsing (#1659)
* Start new parsers in gitbook itself

* Update markup-it

* Fix eslint errors

* Adapt basic parsing for summary

* Start tests for summaryFromDocument

* Continue

* Add parsing of glossary

* Add back languages parsing

* Adapt most tests for parsing

* Adapt all tests 🙌

* Adapt travis tests

* Bootstrap lerna before running tests

* Fix lowercase in require (linux)

* Fix command gitbook init

* Fix generation of ready by init command

* Fix generation of summary

* Fix watch after serve

* Add trademark to sidebar

* Add back favicon to default theme

* Open trademark in new tab
2017-01-06 17:15:30 +01:00
Samy Pessé 11893255d1 Fix images in readme 2016-12-22 11:36:15 +01:00
Samy Pessé 53f94b317e Improve the readme 2016-12-22 11:26:08 +01:00
Samy Pessé 4717b0a17f Add banner and move images to docs folder 2016-12-22 11:08:47 +01:00
Samy Pessé 43ce7badb7 Change instruction in readme to mention "yarn" 2016-12-22 11:04:41 +01:00
Samy Pessé 9e399da06a Update lerna@2.0.0-beta.31 2016-12-22 10:59:22 +01:00
Julia Kulla-Mader 026b33227d Removing extra period (#1579) 2016-12-22 10:21:47 +01:00
AJ e94634bda5 Updated book.js link (#1591)
The book.js link was pointing to a 404 page. This commit updates the link.
2016-12-22 10:20:47 +01:00
Samy Pessé 194ebc3da9 Merge pull request #1543 from GitbookIO/dream
React for rendering website with plugins
2016-12-22 10:18:38 +01:00
Samy Pessé 16af264360 Merge branch 'master' into dream 2016-12-22 10:17:28 +01:00
Julia Kulla-Mader 64ccb6b00b Google Analytics spelling error (#1580) 2016-12-22 09:58:11 +01:00
Soreine 8bf3241b63 Remove fixed-size font effects in issue template 2016-12-21 15:39:32 +01:00
Nicolas Gaborit 6a4f6eadd2 Improve GitHub issue template (#1648)
It is now short and simple, and redirects to the feedback repo if
needed.
2016-12-21 15:12:48 +01:00
Marlon Bernardes 532df30db7 Minor grammar fix (#1642) 2016-12-19 17:06:28 +01:00
Jonathan Andrew Wolter fd1f7a5609 correct typo s/serie/series/ (#1638) 2016-12-17 22:01:33 +01:00
Samy Pesse febdd8a8bd Prevent null as location in history 2016-12-04 21:18:45 +01:00
Samy Pesse b04724ae0b Debounce scroll watcher in body 2016-12-04 20:55:40 +01:00
Samy Pesse 5dbd8f5740 History is activated with a setup location 2016-12-04 20:43:55 +01:00
Samy Pesse f3af207e6e Update url when scrolling in default theme 2016-12-04 20:27:44 +01:00
Samy Pesse 7d05f8cb89 Update ied@2.3.6 and ad trailing newline in package.json 2016-12-04 19:46:54 +01:00
Soreine 9d3c397446 plugin: Add more categories 2016-12-02 17:52:49 +01:00
Soreine 0681a51c2f plugin: Improve messages for create CLI 2016-12-02 17:50:03 +01:00
Soreine 36e548fd3c core: Remove unused Button.href prop 2016-12-02 17:35:40 +01:00
Soreine ec149e6112 plugin: Display help by default 2016-12-02 17:35:33 +01:00
Soreine e1bcb4ed7d plugin: Add CONTRIBUTING.md 2016-12-02 17:34:54 +01:00
Soreine 4aae18617b plugin-search: Remove react dependency 2016-12-02 16:01:35 +01:00
Soreine 6d00944576 Fixed React version 2016-12-02 15:59:01 +01:00
Soreine be8b11dcb4 ReactInjection was moved 2016-12-02 15:58:25 +01:00
Johan Preynat 1780435c4f Use fixed size for sidebar and provide animation 2016-10-31 17:13:19 +01:00
Johan Preynat ebf7a5cf50 Export ReactCSSTransitionGroup from gitbook-core 2016-10-31 17:12:47 +01:00
Guillermo Lengemann 5f0a81d18b GNU/Linux Calibre installation instruction for ebook (#1533)
Adding details to generating ebook an pdfs in GNU/Linux.
2016-10-19 18:01:59 +02:00
Hur jung ju b564ef6580 Add 'emphasis' in 'SUMMARY.md' and trimming (#1566) 2016-10-19 17:56:03 +02:00
Soreine 1d877db5f0 search: Clear search with Esc or button 2016-10-19 01:06:44 +02:00
Soreine 92678bb93f Clearer doc for File 2016-10-19 00:34:57 +02:00
Soreine 4f2c729d60 core: Fix HotKeys default keymap 2016-10-19 00:34:19 +02:00
Soreine 59079bc18d plugin-lunr: Fix reading page search attributes 2016-10-18 16:40:49 +02:00
Samy Pesse 66c2a6c076 Add roles "body:wrapper", "toolbar:wrapper", "page:wrapper" 2016-10-17 23:56:41 +02:00
Samy Pesse 182bb9eb86 Remove react dependencies from "gitbook" 2016-10-17 23:40:02 +02:00
Samy Pesse 9ab738e478 Use same react instance between server and gitbook
Fix injection of DOM properties not working on the browser
2016-10-17 23:39:40 +02:00
Samy Pesse d0555e2bd0 Add background to dropdown 2016-10-17 23:38:28 +02:00
Samy Pesse cdf9842d68 Fix display of button in left toolbar 2016-10-17 23:02:17 +02:00
Samy Pesse a1ae5c2295 Normalize action types in plugins 2016-10-17 20:50:09 +02:00
Samy Pesse 373a486a14 Replace GitBook.Shapes by GitBook.PropTypes 2016-10-17 18:24:29 +02:00
Samy Pesse f262a7cd89 Add languages to client side state, and add "current" to json repr 2016-10-14 23:05:37 +02:00
Samy Pesse b63b0cc50d Normalize Panel in gitbook-core 2016-10-14 11:09:24 +02:00
Samy Pesse 5839d4d8a8 Improve "gitbook-plugin create" to prompt for title/categories 2016-10-13 23:54:27 +02:00
Samy Pesse d9c3cb418a Add component tooltip from gitbook-core 2016-10-13 23:31:05 +02:00
Samy Pesse 12c7ac1498 Add roles "page:header" and "page:footer" 2016-10-13 21:53:15 +02:00
Samy Pesse 2c3072fd8a Fix update of page attributes in hook "page" 2016-10-13 21:53:15 +02:00
Johan Preynat bb14f48c39 Add tests for multiple inline template blocks 2016-10-13 21:07:23 +02:00
Samy Pesse d56019dc18 Hook "page" should not be able to edit content but attributes 2016-10-13 20:55:41 +02:00
Samy Pesse 0a6216a093 Limit size of text in search results 2016-10-13 20:25:46 +02:00
Samy Pesse 4c174f916e Add highlighting for search terms in results 2016-10-13 19:33:04 +02:00
Samy Pesse 4db57fe5c5 Fix rendering of search 2016-10-13 19:19:54 +02:00
Samy Pesse 2a78bcebab Search plugin should provide roles "search:results" and "search:result" 2016-10-13 18:08:48 +02:00
Samy Pesse be14a8ea4d Fix search input 2016-10-13 17:57:09 +02:00
Samy Pesse 37920c758b Normalize style of dropdown 2016-10-13 17:57:09 +02:00
Soreine 52f9409e24 gitbook-plugin: Add eslint as devDependency 2016-10-13 17:31:33 +02:00
Samy Pesse 05646996c0 Rename "navigation" to "history" and add loading bar 2016-10-13 16:17:00 +02:00
Samy Pesse c439cf8513 Increase content font-size 2016-10-13 15:46:18 +02:00
Soreine 1a3e4e8337 Small tweaks to doc 2016-10-13 15:45:19 +02:00
Soreine 631cebfd2f search: Document search handlers API 2016-10-13 15:45:19 +02:00
Samy Pesse f1f2024489 Add support for align HTML attribute 2016-10-13 15:22:52 +02:00
Samy Pesse 227b329e78 Start style for dropdowns 2016-10-13 14:47:06 +02:00
Samy Pesse da8c78b3c8 Refactor Backdrop, Hotkeys and Dropdown 2016-10-13 13:35:59 +02:00
Samy Pesse c42c5897fe Refactor code of plugin sharing 2016-10-13 13:23:19 +02:00
Nicolas Gaborit 3aea3e5d88 Adapt plugin sharing (#1553)
* Reuse old package config

* Add plugin config shape

* Add ButtonGroup to core components

* List all sharing sites

* Displaying buttons from config

* First iteration of Dropdown component (need CSS)

* Using Dropdown for sharing button

* Create HotKeys component

* Move Backdrop to its own file

* Trying a cleaner API for Dropdown

* Add README.md

* livereload: Add missing gitbook-plugin dependency

* sharing: Now use Immutable state

* sharing: Adapt quickly to new Dropdown

* sharing: Fix sharing from dropdown
2016-10-13 12:56:46 +02:00
Samy Pesse 95b3b4ebb7 Revert fontsettings plugin 2016-10-13 11:10:53 +02:00
Samy Pesse ba56801352 Add base for new fontsettings plugin 2016-10-13 00:18:47 +02:00
Samy Pesse 48ee0e35b0 Start changelog 2016-10-12 21:27:55 +02:00
Samy Pesse 2fff291cad Readme should always be generated as "index.html" 2016-10-12 20:56:36 +02:00
Johan Preynat baea45d924 Enhance display of headings 2016-10-12 19:49:58 +02:00
Samy Pesse 52d0384605 Improve some CSS for default theme 2016-10-12 16:07:28 +02:00
Samy Pesse 961b9d7031 Fix error for code blocks without language 2016-10-12 15:47:29 +02:00
Samy Pesse 5b0622014a Adapt test for listDependencies 2016-10-12 14:18:46 +02:00
Samy Pesse 7253dbc476 Use ied instead of npm for installation of plugins 2016-10-12 14:09:48 +02:00
Samy Pesse b4dd3e1ddc Adapt test for plugins.findForBook 2016-10-12 12:17:34 +02:00
Samy Pesse 4b6fc0ae2f Adapt tests for website rendering and render languages index 2016-10-12 12:12:08 +02:00
Samy Pesse 5d4dc499a5 Remove references to plugin resources 2016-10-12 11:56:31 +02:00
Samy Pesse 0e7aece96d Use a single instance of Git for output 2016-10-12 11:13:31 +02:00
Samy Pesse b7c245d75a Add yarn.lock to .gitignore 2016-10-12 11:04:56 +02:00
Samy Pesse 5fed4e1ced Adapt findInstalled for unit tests 2016-10-12 11:04:09 +02:00
Samy Pesse c71da9955e Improve performance of plugins listing 2016-10-11 11:36:17 +02:00
Samy Pesse 3a2abb870b gitbook-plugin create should add eslint config 2016-10-11 10:19:48 +02:00
Samy Pesse e8947a2c11 Update nunjucks@2.5.2 2016-10-11 10:11:35 +02:00
Samy Pesse 885a161d42 Update react-safe-html@0.4.0 2016-10-11 09:25:07 +02:00
Samy Pesse fe0d4bf024 Add timing logs for browser rendering 2016-10-11 00:11:17 +02:00
Samy Pesse aa39b8e71b Don't log deprecated when no plugins is using deprecated APIs 2016-10-10 23:18:38 +02:00
Samy Pesse 3000dcefe1 Add compiled plugin to gitignore for livereload plugin 2016-10-10 19:07:21 +02:00
Samy Pesse f1405d3958 remove compiledp lugin from git 2016-10-10 19:06:38 +02:00
Samy Pesse caeadd431b Adapt plugin livereload for new APIs 2016-10-10 17:43:27 +02:00
Samy Pesse d5796ccf04 Import plugin "livereload" from https://github.com/GitbookIO/plugin-livereload 2016-10-10 16:34:39 +02:00
David Graf 71cce33836 moved insertion of livereload script tag to the correct place 2016-10-10 16:18:35 +02:00
David Graf 9eeb7304c7 s/host/hostname 2016-10-10 16:18:35 +02:00
David Graf 3b5bea0eb5 typo 2016-10-10 16:18:35 +02:00
David Graf 17d921cb11 use current domain instead of localhost 2016-10-10 16:18:34 +02:00
David Graf 10ab06a32c initial commit 2016-10-10 16:18:34 +02:00
Samy Pesse 1bc802e4c8 Fix outline effect on summary articles 2016-10-10 13:07:24 +02:00
Samy Pesse 9a9b5a2621 Show "copied" text when clicking the copy button 2016-10-10 12:56:23 +02:00
Samy Pesse 66231f8b7f Add plugin "copy-code" to default 2016-10-10 12:45:18 +02:00
Samy Pesse 7037ac55bd Use URIIndex.resolve in resolveLinks modifiers 2016-10-09 18:25:54 +02:00
Samy Pesse cf35fef3b3 Use map.getIn for plugin heading 2016-10-09 17:23:24 +02:00
Samy Pesse 16800cc70a Adapt plugin headings to use normal links 2016-10-09 17:00:33 +02:00
Samy Pesse 417013a230 Resolve assets and lunr index before loading 2016-10-09 16:52:27 +02:00
Johan Preynat 5a57a2c62a Merge remote-tracking branch 'origin/dream' into dream
# Conflicts:
#	packages/gitbook-plugin-headings/package.json
2016-10-09 00:58:30 +02:00
Johan Preynat 4cfffb26f2 gitbook-plugin-headings: Add CSS 2016-10-09 00:55:13 +02:00
Johan Preynat 9d4221936e gitbook-plugin-headings: Update plugin to display anchors 2016-10-09 00:55:04 +02:00
Johan Preynat 34baae1a5d gitbook-plugin-headings: Add base default options 2016-10-09 00:54:37 +02:00
Johan Preynat cd0ed86589 Add classnames to dependencies for gitbook-plugin-headings 2016-10-09 00:54:04 +02:00
Samy Pesse 2d429b731b Fix scroll for content in default theme 2016-10-08 21:12:20 +02:00
Samy Pesse 03b89194d7 Prepare for multiple role rendering for ebooks 2016-10-08 18:19:49 +02:00
Samy Pesse 68ec88c620 Add script to bump version 2016-10-08 14:32:35 +02:00
Samy Pesse 47a27fc12d Remove templating blocks post process 2016-10-07 11:53:02 +02:00
Samy Pesse 9cedcc6b6e Adapt tests for TemplateBlock 2016-10-07 11:46:57 +02:00
jdaviescoates d6de8f4173 Update examples.md with Loomio guide (#1550) 2016-10-07 11:40:06 +02:00
Samy Pesse 1d291ff2f0 Fix style of toolbar and add title to it 2016-10-06 23:04:20 +02:00
Samy Pesse 58ae96b7f6 Add "url" to summary articles and files in json representation 2016-10-06 20:08:47 +02:00
Samy Pesse 1354582c4e Generate an url index for generation 2016-10-06 16:29:32 +02:00
Samy Pesse 4119917555 Add class URIIndex to store table path to url 2016-10-06 11:21:08 +02:00
Samy Pesse 9d20a9afa5 Store config as immutable in state 2016-10-06 09:41:47 +02:00
Samy Pesse 45683185a2 Add reducer for file in gitbook state 2016-10-05 23:19:11 +02:00
Samy Pesse 6ce4949df3 Add "url" to file 2016-10-05 23:12:00 +02:00
Soreine 0614613b84 Starting gitbook-plugin-sharing 2016-10-05 21:41:43 +02:00
Johan Preynat 6faf6a53f0 Replace plugin fontsettings by creating plugin headings 🔨 2016-10-05 20:14:08 +02:00
Samy Pesse bced415a50 Fix include of immutable in theme-default 2016-10-05 16:19:56 +02:00
Samy Pesse 805886e4a9 We trigger current url history only once the page has been mounted 2016-10-05 14:22:01 +02:00
Samy Pesse 83c98cf4d8 Fix search not refreshed when adding an handler 2016-10-05 14:01:22 +02:00
Samy Pesse 86848e7acb Fix format of lunr results 2016-10-05 13:36:38 +02:00
Samy Pesse 9ce3646d6e Add base for loading lunr index 2016-10-05 02:28:12 +02:00
Samy Pesse 45752fc79c Complete highlight plugin 2016-10-05 01:47:16 +02:00
Samy Pesse a863b55c79 Start new highlight.js plugin 2016-10-04 18:53:58 +02:00
Samy Pesse 16ca48b2c0 Correctly update page when url changed 2016-10-04 18:32:31 +02:00
Samy Pesse 87ae2481e4 Add style for plugin hint 2016-10-04 15:32:59 +02:00
Samy Pesse ccb5dcf559 Fix template of plugin to not mention theme 2016-10-04 15:30:34 +02:00
Samy Pesse 84315a99f1 First handling of templating blocks 2016-10-03 23:34:27 +02:00
Samy Pesse 026cc8304d Don't compile tests file with babel 2016-10-03 18:41:25 +02:00
Samy Pesse cefbfdc7b8 Clear query in url when search is cleared 2016-10-03 16:01:11 +02:00
Samy Pesse 4049279269 Emit current location when listening 2016-10-03 15:48:28 +02:00
Samy Pesse b04befd67c Use replace of url for search to avoid filling history 2016-10-03 15:21:40 +02:00
Samy Pesse d82032298d Fix new api for activate/deactivate 2016-10-03 14:56:55 +02:00
Samy Pesse 34eb35699d Change "init to "activate" 2016-10-03 10:35:24 +02:00
Samy Pesse 3ae72bb47c Sync search with querystring 2016-10-03 00:59:26 +02:00
Samy Pesse cd2d5e5101 Pass actions to thunk acitons 2016-10-02 15:28:25 +02:00
Samy Pesse 5abac3a79a Fix size of button in toolbar 2016-10-02 13:33:16 +02:00
Samy Pesse d22d090b05 Add style for search input in default theme 2016-10-02 01:04:25 +02:00
Samy Pesse 24b657f790 Fix font and buttons in default theme 2016-10-02 00:53:38 +02:00
Samy Pesse 649a6c980c Include font-awesome in default theme 2016-10-02 00:37:36 +02:00
Samy Pesse 24624f0d0e Fix clear of search 2016-10-02 00:15:59 +02:00
Samy Pesse 9aaf561c41 Complete i18n for search plugin 2016-10-01 23:11:50 +02:00
Samy Pesse 8be4cbc887 Add action I18n.registerLocales and locales for default theme 2016-10-01 23:11:50 +02:00
Johan Preynat 32556e6724 Add fix for handling parsing page errors 2016-10-01 22:48:47 +02:00
Johan Preynat ad425b9772 Bump version to 3.2.2 2016-10-01 22:35:54 +02:00
Johan Preynat 5238fa352c Rollback to use gitbook-markdown@1.3.2 2016-10-01 22:30:43 +02:00
Johan Preynat 32183b6650 Merge branch 'fix-3.1-version' 2016-10-01 21:49:06 +02:00
Johan Preynat cb3d6a7f01 Correctly handle page parsing errors 2016-10-01 21:47:25 +02:00
Johan Preynat c978f0ab21 Add comment 2016-10-01 21:47:08 +02:00
Samy Pesse 8753897edc Fix js error because of changing API 2016-10-01 14:39:09 +02:00
Samy Pesse da83d9e91d Change api for registering components 2016-10-01 14:14:30 +02:00
Samy Pesse 2cf507a807 Base api to use i18n 2016-09-30 14:16:48 +02:00
Samy Pesse 1489129407 Improve Gitbook.connect to accept a mapActionsToProps 2016-09-29 23:53:18 +02:00
Samy Pesse b5c407cf7b Start plugin "hints" 2016-09-29 19:38:55 +02:00
Samy Pesse 9d8dffb6f0 Fix query action for search 2016-09-29 19:04:56 +02:00
Samy Pesse 6015defe11 Integrate search in default theme 2016-09-29 17:20:29 +02:00
Samy Pesse 7f28379154 Fix dist command 2016-09-29 16:03:16 +02:00
Samy Pesse 6f98ee1846 Add npmignore and gitignore to plugin template 2016-09-29 13:17:24 +02:00
Samy Pesse 42d53ec032 Add gitbook-plugin command to create a plugin 2016-09-29 13:15:41 +02:00
Samy Pesse 287c80b2e1 Start search plugin 2016-09-28 18:14:35 +02:00
Samy Pessé 33ff60cee7 Add changes for 3.2.1 2016-09-28 15:56:36 +02:00
Samy Pesse 26fc021b90 Fix lerna bootstrap 2016-09-28 14:54:01 +02:00
Samy Pesse 33d7e022e6 Bump version to 3.2.1 2016-09-28 13:21:24 +02:00
Samy Pesse 09782b964b Update theme-default@1.0.6 2016-09-28 13:10:47 +02:00
Johan Preynat 7938ee8ec6 Use nunjucks@2.5.2 2016-09-28 10:32:14 +02:00
Samy Pesse c314281da0 Add CONTRIBUTING.md 2016-09-28 10:03:38 +02:00
Peter B Smith 2e8e4f63d7 fixing a typo of the word "publishing" (#1536) 2016-09-28 09:49:29 +02:00
Samy Pesse bc5df83846 Start designing toolbar 2016-09-27 17:08:34 +02:00
Samy Pesse f1ef1902f3 Style page with gitbook-markdown-css 2016-09-27 16:39:58 +02:00
Samy Pesse 748c46172b Fix reducers mutating the state instead of creating a new one 2016-09-27 16:12:58 +02:00
Samy Pesse 51f4cd6dae Fix link and navigation click 2016-09-26 18:45:12 +02:00
Samy Pesse 64ce8bcf42 Fix gitbook-plugin permission 2016-09-26 17:48:02 +02:00
Samy Pesse ff42b58f77 Add basic for pjax navigation 2016-09-26 17:26:36 +02:00
Samy Pesse 7fa3e34f9f Mark article as active in summary 2016-09-25 19:05:35 +02:00
Samy Pesse e46cd78f80 Fix core reducer destroying other reducers 2016-09-25 17:44:08 +02:00
Samy Pesse fab88bb47e Add flex box components 2016-09-24 23:24:47 +02:00
Samy Pesse fa7cf3a65f Start documenting components 2016-09-22 18:28:37 +02:00
Samy Pesse d0885491b7 Provide immutable proptypes 2016-09-22 11:08:57 +02:00
Samy Pesse 45c54d0cd7 Base tree rendering for summary 2016-09-22 10:54:54 +02:00
Samy Pesse f49089a7d3 Add immutable state for readme/summary
Add shapes for these states
2016-09-22 10:37:06 +02:00
Samy Pesse 0b1888e184 First working version in the browser 2016-09-22 09:54:24 +02:00
Samy Pesse 2257e42299 Add js scripts to html 2016-09-21 19:17:32 +02:00
Samy Pesse 0e0c1a473b Fix head extension by plugins 2016-09-21 17:29:52 +02:00
Samy Pesse a18370551a Prepare showing page html 2016-09-21 15:54:58 +02:00
Samy Pesse a8aeab17d6 Fix render of UnsafeComponent 2016-09-21 01:35:59 +02:00
Samy Pesse 2adca5deb9 Fix composition with plugin reducers 2016-09-21 01:05:40 +02:00
Samy Pesse 3b3f43a35d Fix rendering of unsafe injected components 2016-09-20 19:41:25 +02:00
Samy Pesse ced0be930d Working loading of plugin 2016-09-20 19:19:01 +02:00
Samy Pesse 6d58a90613 Prepare loading of plugin 2016-09-20 15:12:53 +02:00
Samy Pessé 2796065886 Add base for gitbook-plugin builder 2016-09-19 11:33:23 +02:00
jdaviescoates b9fa6c3051 Update examples.md (#1522)
By adding the Loomio and Enspiral handbook examples
2016-09-08 20:38:59 +02:00
Samy Pesse 82c2c214eb Fix build of gitbook.core.min.js 2016-09-05 22:29:41 +02:00
Samy Pesse ee35da4be5 Add task to build gitbook.core.min.js 2016-09-05 21:07:31 +02:00
Samy Pessé 24c4f41945 gitbook-core should also be compiled 2016-09-05 16:17:43 +02:00
Samy Pessé fe298f2a3f Fix error during fake rendering 2016-09-05 14:41:21 +02:00
Samy Pessé ab3d94a55d Fix regression in TemplateBlock 2016-09-05 14:15:33 +02:00
Samy Pessé ff31514c66 Start bootstraping rendering with react in GitBook 2016-09-05 14:02:49 +02:00
Samy Pessé 3f1ec310ca Add compilation ES6 with babel for "gitbook" 2016-09-05 12:36:53 +02:00
Samy Pessé b796069ade Move gitbook source code to es6 (linted) 2016-09-05 12:32:25 +02:00
Samy Pessé 839904a704 Start architecturing new default theme 2016-09-05 12:14:37 +02:00
Samy Pessé 0e74c9bad5 Add action to register a component 2016-09-05 11:59:40 +02:00
Samy Pessé d7e415b0b3 Add components for injections 2016-09-05 11:51:52 +02:00
Samy Pessé b170b4d197 Start basis of gitbook-core 2016-09-05 11:04:36 +02:00
Samy Pessé a14ca3e268 Switch to lerna 2016-09-05 11:04:18 +02:00
Samy Pessé 9c071dade5 Merge pull request #1481 from mcveat/patch-1
Fixed typo
2016-08-04 00:19:11 +02:00
Piotr Adamski 56e44651fa Fixed typo 2016-08-03 22:08:12 +02:00
Samy Pessé 42fac98992 Fix command for getting gitbook version 2016-08-01 09:47:31 +02:00
Samy Pessé 4f5513add0 Create template for GitHub issues 2016-07-25 20:39:31 +02:00
Samy Pesse 90cbfc0596 Add OSX testing on Travis 2016-07-15 11:38:58 +02:00
Samy Pessé 38ab9fa05a Bump version to 3.2.0 2016-07-11 16:48:13 +02:00
Samy Pessé 12e20c5fcc Update theme-default@1.0.5 2016-07-11 16:47:16 +02:00
Samy Pessé 6b103f4532 Fix #1408: fix i18n in website generator and add tests for it 2016-07-11 16:27:22 +02:00
Soreine d4fa5c18a8 editPlugin and getPluginConfig 2016-07-11 15:18:35 +02:00
Soreine 2a116dfdb0 Fix reducedObject when default property is undefined 2016-07-11 15:18:35 +02:00
Samy Pessé 0349f54f3c Export file model 2016-07-07 16:41:05 +02:00
Samy Pessé 695bda312c Bump version to 3.2.0-pre.1 2016-07-05 17:15:48 +02:00
Samy Pessé 144bd4c97a Update gitbook-markdown@2.0.1 2016-07-05 11:07:51 +02:00
Samy Pessé e105983cf8 Add back property "output" to page/template context 2016-07-04 18:08:44 +02:00
Soreine ea3afbed75 Update gitbook-plugin-lunr@1.2.0 2016-07-01 17:52:15 +02:00
Soreine d563abe3df Reduce size of logo to give room to version number 2016-06-30 15:37:31 +02:00
Soreine 70fd4ded29 Update theme-official for doc 2016-06-30 12:15:50 +02:00
Samy Pessé 9ce9388dfc Bump version to 3.2.0-pre.0 2016-06-30 11:09:18 +02:00
Samy Pessé c575ad83ae Update gitbook-markdown@2.0.0 2016-06-30 10:51:46 +02:00
Samy Pessé 936fa1545b Add tests for locationUtils.flatten 2016-06-29 10:32:49 +02:00
Samy Pessé c9c2dde2b6 Add method "isFile" and "isReadme" in SummaryArticle 2016-06-29 10:31:06 +02:00
Samy Pessé d9a1d387c7 Merge pull request #1397 from mpfeil/master
add open and browser args to serve command
2016-06-23 11:40:05 +02:00
Matthias Pfeil bf29d187c8 disable open by default 2016-06-20 17:24:08 +02:00
Matthias Pfeil d86f9b2667 add open and browser args to serve command 2016-06-17 16:00:53 +02:00
Samy Pesse aca4313fc3 Enable long stack support when process.env.CI is true 2016-06-11 12:38:19 +02:00
Samy Pesse 4cb5bb06fb Bump version to 3.1.1 2016-06-10 22:19:09 +02:00
Samy Pesse 24988b75ea Fix extsAsciidoc.js 2016-06-10 22:14:04 +02:00
Samy Pesse 775e858d05 Expose markdown/asciidoc extensions to gitbook module 2016-06-10 22:13:31 +02:00
Samy Pesse 1e3d871c1e Merge branch 'fix/plugins_loading' 2016-06-10 22:08:16 +02:00
Samy Pesse 94a4310c1e Adapt Plugins.loadForBook to use correct order 2016-06-10 22:04:19 +02:00
Samy Pessé e8ee57be83 Start fixing order of plugins in dependencies 2016-06-10 18:34:24 +02:00
Samy Pessé 50a132cb2c Add method "createChildLevel" to SummaryPart 2016-06-10 18:11:22 +02:00
Samy Pessé 59be32a54f Add method .createChildLevel for SummaryArticle 2016-06-10 18:08:56 +02:00
Soreine 4ae7cdb5d1 Mention autocover plugin in docs 2016-06-10 18:03:40 +02:00
Samy Pessé 990a4efeb5 Update gitbook-markdown and gitbook-asciidoc 2016-06-10 17:53:10 +02:00
Samy Pessé 9c927dcf13 Fix #1374 and #1360: apply transform of conrefsLoader using a string, not a buffer 2016-06-10 17:45:30 +02:00
Samy Pessé 7a08b3f109 Fix #1377: fix listing of plugins when using gitbook as a library 2016-06-10 17:15:04 +02:00
Samy Pessé 94d4234cb8 Merge branch 'fix/plugins_order' 2016-06-10 16:44:13 +02:00
Samy Pessé fbc851bc4e Fix listAll to add default plugins after normal ones 2016-06-10 16:43:32 +02:00
Samy Pessé e92b661a2a Adapt sortPlugins to only sort an ordered map of plugins 2016-06-10 16:37:44 +02:00
Soreine b9fe60915f Add tests for insertPart 2016-06-10 15:40:51 +02:00
Samy Pessé 1bf7d092f0 Merge pull request #1363 from todvora/master
Fixed target attribute for external links
2016-06-10 00:28:50 +02:00
Samy Pesse 826d472511 Fix documentation about themes 2016-06-08 20:06:50 +02:00
Samy Pessé a6b1f4bd87 Compare list of plugins sorted to array of names in tests 2016-06-08 15:08:11 +02:00
Samy Pessé 004f91f02c sortPlugins should not be async 2016-06-08 15:02:34 +02:00
Samy Pessé e6c6ec4293 Improve testing for sortPlugins 2016-06-08 14:57:54 +02:00
Soreine a1d3acf065 Fix serve cli using new ConfigModifier.addPlugin 2016-06-08 10:42:27 +02:00
Soreine a732660f59 docs: cover remove extraneous line 2016-06-08 10:35:12 +02:00
Nicolas Gaborit e1bb0638f8 docs: cover, fix formatting 2016-06-08 10:16:54 +02:00
Soreine 788c0c7e7e Adds cover.jpg info 2016-06-08 10:12:42 +02:00
Tomas Dvorak 762fe16a17 fixed target attribute for external links 2016-06-07 18:34:36 +02:00
Samy Pessé 15123805d1 Fix linting error 2016-06-07 16:24:22 +02:00
Samy Pessé 23aecb4f2b Improve output of page to text with frontmatter 2016-06-07 16:23:12 +02:00
Samy Pessé f1d200b81b Rollback frontmatter parsing to js-yaml to be browserify compatible 2016-06-07 14:32:12 +02:00
Samy Pessé b566711ee1 Add method toText to Page 2016-06-07 12:51:35 +02:00
Samy Pessé 22da5aac11 Switch frontmatter parsing to gray-matter 2016-06-07 12:47:16 +02:00
Samy Pessé f7b95102c5 Expose Page model 2016-06-07 12:36:32 +02:00
Samy Pessé ca70c934d6 Split page parsing into parsePageFromString and parsePage
Add tests for parsePageFromString
2016-06-07 12:31:21 +02:00
Samy Pessé 1cc48fa314 Use Immutable instead of lodash for mergeDefaults 2016-06-07 12:06:29 +02:00
Samy Pessé b63b5574d3 Only merge objects in mergeDefaults 2016-06-07 11:40:54 +02:00
Samy Pessé 67106e8698 Improve plugins config modifier 2016-06-07 11:06:53 +02:00
Samy Pessé dc2ab51a88 Update i18n-t and juice 2016-06-07 10:54:34 +02:00
Samy Pessé cedfa186f2 Remove merge-defaults dependency 2016-06-07 10:48:04 +02:00
Samy Pessé 80f0d1bfed Update gitbook-markdown and gitbook-asciidoc to use lodash@4 2016-06-07 10:36:01 +02:00
Samy Pessé 7178ab1f82 Improve Config.toText to return only the required fields 2016-06-07 10:26:28 +02:00
Samy Pesse bf895b707e Improve addPlugin to not append default plugins to the list 2016-06-07 00:56:24 +02:00
Samy Pesse 996170a4ad ConfigModifier.removePlugin should toggle off if default 2016-06-07 00:48:47 +02:00
Samy Pesse aa66a4f928 Expose DEFAULT_PLUGINS as a list of PluginDependency 2016-06-06 22:04:13 +02:00
Samy Pesse 23010fa54a Adapt tests for config modifiers 2016-06-06 21:22:44 +02:00
Samy Pesse 0baebc7979 Change config modifier to work on a config object 2016-06-06 21:20:00 +02:00
Samy Pesse 257158321c Bump version to 3.1.0 2016-06-06 19:51:44 +02:00
Samy Pesse ddf0a41e29 Add method editPlugin to config modifiers 2016-06-06 19:42:44 +02:00
Samy Pesse 357e1e8e96 Add unit tests for postRender 2016-06-06 19:24:12 +02:00
Samy Pesse 7a89f9869a Update gitbook-markdown@1.3.0 and gitbook-asciidoc@1.2.0 2016-06-06 18:07:31 +02:00
Samy Pesse 30fbd22efe Add modifier togglePlugin 2016-06-06 17:27:47 +02:00
Samy Pesse 29df73ba72 Add method "toText" to config 2016-06-06 17:16:53 +02:00
Soreine f8676483c1 Default paths are relative to the current book 2016-06-06 16:55:00 +02:00
Johan Preynat c79a6f2fba Use theme-default@1.0.4 2016-06-06 15:46:44 +02:00
Samy Pessé c38e67ea61 Merge pull request #1344 from GitbookIO/fix/readme-in-summary
Search for README file in whole summary before inserting as first article
2016-06-06 12:18:06 +02:00
Johan Preynat 97a5f8805e Use plugin-fontsettings@2.0.0 2016-06-02 10:24:12 +02:00
Johan Preynat 421fef6ebf Search for README file in whole summary before inserting as first article 2016-05-30 15:07:39 +02:00
Johan Preynat 33406c3082 Merge pull request #1336 from GitbookIO/loading/themes
Load plugins before themes
2016-05-28 11:56:34 +02:00
Johan Preynat c3851889b0 Throw an error if generateMock() cannot create the temp directory 2016-05-27 17:15:23 +02:00
Johan Preynat 4a5de2da6b Use sortPlugins() in loadForBook() 2016-05-27 15:06:20 +02:00
Johan Preynat 1afb23cada Add test file for sortPlugins() 2016-05-27 15:06:08 +02:00
Johan Preynat a3b0f3f868 Export plugins sorting method to load plugins before themes 2016-05-27 15:05:55 +02:00
Johan Preynat 0aa32916d6 Add prefix for theme plugins as constant 2016-05-27 15:05:33 +02:00
Samy Pessé ebe845d46c Bump version to 3.0.3 2016-05-27 12:16:56 +02:00
Samy Pessé edee8d2fc5 Update gitbook-theme-default@1.0.3 2016-05-27 12:07:35 +02:00
Samy Pessé 5f3de0876f Add header 'X-Current-Location' to serve and fix handling of directories 2016-05-27 12:01:28 +02:00
Samy Pessé 2ceab04d01 Increase timeout for tests of plugin installation 2016-05-27 11:40:05 +02:00
Samy Pessé de37de44e8 Add tests for installation of all plugins 2016-05-27 11:18:12 +02:00
Samy Pessé ccb87d5a13 Add unit tests for installPlugin 2016-05-27 11:10:39 +02:00
Samy Pessé e2e0ca3f05 Add test for plugin version resolution 2016-05-27 10:54:56 +02:00
Samy Pessé b33a79704b Switch plugin installation and resolveVersion to use PluginDependency instead of Plugin 2016-05-27 09:38:23 +02:00
Samy Pessé 6def174b84 Merge pull request #1334 from ryanswanson/master
Fixed two issues for handling git URLs for plugins
2016-05-27 09:27:11 +02:00
Samy Pessé 346a18b444 Merge pull request #1335 from GitbookIO/fix/1333
Fix #1333: fix invalid URLs for glossary annotations
2016-05-26 22:30:06 +02:00
Samy Pesse b32685c698 Add test for custom glossary file 2016-05-26 22:01:40 +02:00
Samy Pesse 09b3618da8 Annotate glossary terms before resolving links 2016-05-26 21:38:27 +02:00
Samy Pesse 901328f247 Complete basic tests for glossary 2016-05-26 21:37:10 +02:00
Samy Pesse b47ebaa9d9 Use real glossary name when annotating 2016-05-26 21:10:06 +02:00
Ryan Swanson 465e8d6c0a Fixed two issues for handling git URLs for plugins that are published to git repositories rather than on npmjs.org.
Fixed issue in pluginDependency to dereference 'name' and 'version' using Immutable Map.get(...) accessors since config values are now wrapped by Immutable.fromJS(...) in config.js > setValue(...).  Added associated unit test.

Fixed issue in resolveVersion where a plugin may be using a git URL rather than a semver for the version portion of the plugin config definition.  In addition, refactored the resolveVersion function into a new module to allow for unit testing.  Added associated unit test.
2016-05-26 14:30:29 -04:00
Samy Pessé ecd86ec877 Method for parsing glossary when not listed in summary 2016-05-26 17:26:11 +02:00
Samy Pessé 5d7864154c Start test for glossary generation 2016-05-26 17:25:49 +02:00
Samy Pessé 7b915428f7 Fix #1316: fix regression for supporting uppercase filenames in structure 2016-05-26 11:07:13 +02:00
Samy Pesse 0bce3517fd Bump version to 3.0.2 2016-05-25 21:50:38 +02:00
Samy Pesse 089815a8fd Fix #1328: fix crash when anchor links 2016-05-25 21:49:58 +02:00
Samy Pesse 7e8f1a9632 Bump version to 3.0.1 2016-05-25 20:00:04 +02:00
Samy Pesse 8469648241 Update theme-default@1.0.2 2016-05-25 17:14:15 +02:00
Samy Pessé e7a44358a5 Update Changelog 2016-05-24 15:38:26 +02:00
Samy Pessé fb930d889f Fix anchor breaking links resolution 2016-05-24 15:32:30 +02:00
Samy Pessé 721a75309b Fix #1316: adapt regexp to handle dot in filenames 2016-05-23 13:00:01 +02:00
Samy Pessé b856bff91b Add failing test for #1316 2016-05-23 12:48:46 +02:00
Samy Pesse 0744f000f9 Fix doc for conrefs 2016-05-22 19:59:53 +02:00
Samy Pesse d1e226dba5 Bump version to 3.0.0 2016-05-20 22:18:37 +02:00
Samy Pesse 1923d28d71 Update dependencies 2016-05-20 22:17:44 +02:00
Samy Pessé 484a306adb Fix error with isInRoot when empty root 2016-05-20 21:41:02 +02:00
Samy Pessé 5bfc9f2f56 Fix PathUtils.isInRoot on windows 2016-05-20 21:37:22 +02:00
Samy Pesse 86a65e5287 Improve appveyor configuration 2016-05-20 19:23:51 +02:00
Samy Pesse 956d301dd7 Add node v6 to appveyor matrix 2016-05-20 18:22:44 +02:00
Samy Pesse 00d1a7b5a6 Update theme-default@1.0.1 2016-05-20 18:17:34 +02:00
Samy Pessé 2718c9c017 Fix test command for windows 2016-05-19 10:45:25 +02:00
Samy Pesse 3234c1e03f Fix #1310: enforce language config in language books 2016-05-19 00:15:09 +02:00
Aaron O'Mullan c8f8eece92 Merge pull request #1308 from arebee/patch-1
Fix english phrasing for Node version.
2016-05-19 00:10:08 +02:00
Richard Burte 7394efa9dc Fix english phrasing for Node version. 2016-05-18 09:54:04 -07:00
Samy Pesse 3e4241fc88 Implement renderInline method and missing output methods for API 2016-05-17 19:45:48 +02:00
Samy Pesse a5ae79604c Implement renderBlock method for plugin API 2016-05-17 19:30:28 +02:00
Soreine fc4bdd68a1 Can only use file names 2016-05-17 16:47:52 +02:00
Soreine f83975b022 Mention the structure configuration variable 2016-05-17 16:37:13 +02:00
Soreine 167d3957bf Expose lookup method for parsable files 2016-05-17 12:48:03 +02:00
Samy Pessé a9571fd67d Bump version to 3.0.0-pre.15 2016-05-12 16:53:14 +02:00
Samy Pessé ac87f48ba5 Update theme-default@1.0.0 2016-05-12 16:52:19 +02:00
Samy Pessé 05403f527d Fix bug that can happen when configuration file doesn't exist 2016-05-12 16:45:09 +02:00
Samy Pessé 53c72f0806 Add api method getPageByPath for plugins 2016-05-12 16:29:36 +02:00
Samy Pessé c8c2a61f96 Fix #1289: add option to filter files when listing using fs.listAllFiles 2016-05-12 16:10:11 +02:00
Samy Pessé 08d780d1f6 Fix #1300: parse page frontmatter and content when listing pages 2016-05-12 15:48:02 +02:00
Samy Pessé 2e74fafa36 Add template method "getPageByPath" 2016-05-12 15:12:08 +02:00
Samy Pessé 28ac9ab88a Fix #1299: pass fileExists as global function for template, accept null/undefined as param 2016-05-12 15:04:30 +02:00
Samy Pessé 26acab4dfb Fix generation of ebook for multilingual book (gitbook pdf) 2016-05-12 14:29:25 +02:00
Samy Pessé d4b562e001 Fix get of cover for multilingual books 2016-05-12 14:12:43 +02:00
Soreine 61956e0646 Revert "Extend Book.getLanguageBook"
This reverts commit 7892259fe6.
2016-05-12 14:08:29 +02:00
Soreine 7892259fe6 Extend Book.getLanguageBook 2016-05-12 13:35:29 +02:00
Samy Pessé b97d1c7796 Fix languages not being added to json output 2016-05-12 13:25:09 +02:00
Samy Pessé a091c5b331 Fix path resolution when generating page with conrefs 2016-05-12 12:19:00 +02:00
Samy Pessé 784b3379b5 Improve logging when generating multilingual book 2016-05-12 11:20:27 +02:00
Johan Preynat 62446e75d2 Update book's root folder definition in Changelog 2016-05-12 11:18:00 +02:00
Samy Pessé 8aa2f3075c Fix #1294: multilingual book should extend the book's config 2016-05-12 11:15:13 +02:00
Samy Pessé 839ee0385a Add method "getLanguageBook" to book model 2016-05-12 11:02:37 +02:00
Samy Pesse d6b60c6116 Adapt eslint configuration for mocha 2016-05-11 16:56:18 +02:00
Samy Pesse 9013f02850 Add test for transform option of ConrefLoader 2016-05-11 15:08:10 +02:00
Samy Pesse 961d43f085 Fix #1293: replace block shortcuts when including files 2016-05-11 14:45:54 +02:00
Samy Pessé 7bd49606e3 Merge pull request #1291 from GitbookIO/summary-modifiers
Summary modifiers
2016-05-11 13:57:21 +02:00
Samy Pesse d7c8635350 Increase mocha timeout 2016-05-11 13:57:00 +02:00
Soreine 19e9ff81d2 Tweak insertPart signature 2016-05-11 13:11:32 +02:00
Soreine e137bf632a Adds editArticleRef 2016-05-11 13:11:32 +02:00
Soreine 2fef898a1e Modifier moveArticleAfter 2016-05-11 13:11:32 +02:00
Soreine 0945807184 Greatly simplify moveArticle's implementation 2016-05-11 13:11:32 +02:00
Soreine d85663b153 Tests remove/insert articles and update insert signature 2016-05-11 13:11:31 +02:00
Soreine 481a7d790c Insert/remove part 2016-05-11 13:11:31 +02:00
Samy Pesse ef589a6b13 Switch tests to mocha while keeping jest structure 2016-05-11 13:02:24 +02:00
Samy Pesse d5c4af3377 Add immutable ignore instance for book 2016-05-11 13:02:24 +02:00
Soreine 0b4df4cdf2 Precise h2 headings for Glossary 2016-05-11 10:55:34 +02:00
Samy Pessé d6814dc48e Don't copy config file as asset 2016-05-10 15:23:59 +02:00
Samy Pessé ce50a1d50f Bump version to 3.0.0-pre.14 2016-05-10 14:37:22 +02:00
Samy Pessé a76e018d36 Update theme-default@1.0.0-pre.10 2016-05-10 14:37:05 +02:00
Samy Pessé b06f1fd677 Fix article.depth starting at 2 2016-05-10 14:36:03 +02:00
Samy Pessé 3d8b1880dc Fix page's title in pdf header/footer 2016-05-10 14:25:50 +02:00
Samy Pessé 1a13c8c9bb Add option "--no-live" for command serve 2016-05-10 13:14:32 +02:00
Samy Pessé 852fae3a09 Fix #1232: add option "--no-watch" to disable watcher and live reloading 2016-05-10 13:08:19 +02:00
Samy Pessé d342d31c8e Fix error when summary contains entry without ref 2016-05-10 12:12:19 +02:00
Samy Pesse 5b3f54fbc8 Fix "gitbook init" when article has no ref 2016-05-10 09:55:22 +02:00
Samy Pessé 308ece784c Merge pull request #1288 from todvora/patch-1
Fixed summary encoding
2016-05-10 08:55:40 +02:00
Tomas Dvorak 0758ddf04e Fixed summary encoding 2016-05-10 08:17:52 +02:00
Samy Pesse f24d9aef73 Add test for block replaced with anchors 2016-05-09 22:17:46 +02:00
Samy Pesse f8bb55f258 Adapt unit tests for blocks 2016-05-09 22:01:25 +02:00
Samy Pesse 76daebeb84 Fix unit test for templateBlock using a removed method "getParse" 2016-05-09 18:41:21 +02:00
Samy Pesse b0d366b7e8 Fix linting warning in models/templateBlock.js 2016-05-08 22:45:26 +02:00
Samy Pesse 3d0054dd64 Fix #1286: by default blocks should not be parsable 2016-05-08 22:33:41 +02:00
Samy Pessé 13bc89ff44 Merge pull request #1285 from GitbookIO/api/summary
[WIP] Api for plugins to access summary
2016-05-08 22:28:15 +02:00
Samy Pesse bb910f984e Improve comment for API summary.walk 2016-05-08 22:26:46 +02:00
Samy Pessé e576fdea14 Merge pull request #1278 from dylang/patch-1
bump bash-color to version that has a license
2016-05-08 18:44:53 +02:00
Samy Pesse c7864927ec Add method summary.getArticleByPath to summary api 2016-05-08 11:08:27 +02:00
Samy Pesse 54956de59f Start API for plugins to access the summary 2016-05-08 10:33:45 +02:00
Samy Pesse 2cbd30d1f2 Fix command "gitbook init" 2016-05-07 00:24:12 +02:00
Dylan Greene 55614f1675 bump bash-color to version that has a license
Version currently being used does not have a license making it difficult for companies to use.
2016-05-06 09:56:43 -04:00
Samy Pesse 4f7421993f Bump version to 3.0.0-pre.13 2016-05-06 10:59:52 +02:00
Samy Pesse 32ad7b530e Fix #1266: don't fail on "a" tags without "href" 2016-05-06 10:57:41 +02:00
Samy Pesse ee5d5010f6 Correctly read assets using input fs when copying 2016-05-06 10:54:13 +02:00
Samy Pesse cf7e5884cd Add method readAsStream on fs model 2016-05-06 10:53:55 +02:00
Samy Pesse 11a0a64d9e Add failing test for #1272 2016-05-06 10:36:55 +02:00
Samy Pesse b6051babac Adapt unit tests for new templating post process 2016-05-05 11:09:35 +02:00
Samy Pesse 34947b5e20 Add mode TemplateOutput to represent {content + blocks} from template 2016-05-05 11:00:05 +02:00
Samy Pesse c621380b66 Add tests for replaceShortcuts 2016-05-04 20:18:48 +02:00
Samy Pesse c4b54033ce Fix #1268: fix shortcuts of template block not being applied 2016-05-04 19:01:31 +02:00
Samy Pesse 4d85d6eb6e Fix #1267: don't fail when "node_modules" folder doesn't exist 2016-05-04 17:41:15 +02:00
725 changed files with 22355 additions and 9881 deletions
+6 -15
View File
@@ -1,20 +1,11 @@
{
"rules": {
"indent": [ 2, 4 ],
"quotes": [ 2, "single" ],
"linebreak-style": [ 2, "unix" ],
"semi": [ 2, "always" ],
"no-unused-vars": [ 2, {
"vars": "all",
"args": "none"
} ],
"spaced-comment": [ 2, "always" ]
},
"env": {
"node": true,
"browser": true,
"jest": true,
"jasmine": true
"mocha": true
},
"extends": "eslint:recommended"
}
"globals": {
"expect": true
},
"extends": "gitbook"
}
+30
View File
@@ -0,0 +1,30 @@
<!--
IMPORTANT NOTICE
Only post things related to the gitbook CLI
For GitBook.com, the Editor, or anything else
please go to
https://github.com/GitbookIO/feedback/issues
Please open separate issues for each bug report.
-->
### What is the current behavior?
<!--
- For bugs, provide the steps to reproduce
- Provide the GitBook version being used (`gitbook -V`)
- Provide system informations (OS and version)
- Provide your username and the URL of the book
-->
### What is the expected behavior?
<!--
Thank you for giving us your feedback!
-- The GitBook Team
-->
+5 -2
View File
@@ -22,14 +22,17 @@ build/Release
# Dependency directory
# Deployed apps should consider commenting this line out:
# see https://npmjs.org/doc/faq.html#Should-I-check-my-node_modules-folder-into-git
/node_modules
node_modules
# vim swapfile
*.swp
# GitBook with babel
/packages/gitbook-core/lib
/packages/gitbook-plugin/lib
# Output of documentation
_book
book.pdf
book.epub
book.mobi
+5
View File
@@ -1,9 +1,14 @@
sudo: false
language: node_js
os:
- linux
- osx
node_js:
- "stable"
- "4.1"
before_install:
- npm install svgexport -g
before_script:
- npm run bootstrap
after_success:
- npm run lint
+58 -2
View File
@@ -2,7 +2,63 @@
All notable changes to this project will be documented in this file.
This project adheres to [Semantic Versioning](http://semver.org/).
## 3.0.0 (pre)
## 4.0.0
- **Breaking Changes:** Most plugins and themes should be incompatible with this version
- GitBook rendering is now done using React, which brings better APIs for plugins and a more interactive website.
- *Performances*: Installation of plugins is much faster thanks to `ied`
- *Performances*: Git conrefs are faster over large books
- *Website Feature:* new default plugin `copy-code` to copy code blocks content in one click
- *Website Feature:* new default plugin `heading-anchors` to have clickable headings
- *Website Feature:* `fontsettings` is now only controlling the font size, and can work on multiple themes
- *Plugin API*: hook `page` can no longer modify the content, only the page's attributes
- *Plugin API*: plugins can no longer export resources, instead use the `_assets` folder
- [ ] *Plugin API*: testing framework
- [ ] `gitbook init` creates `.gitignore` if not found
- [ ] Ignore files are no longer copied to the output
## 3.2.2
- Fix catching parsing errors leading to possible missing pages in generated book
- Rollback markdown parser to `kramed` until `markup-it` is stable enough
## 3.2.1
- Fix bug on Firefox when navigating to an url containing an hash
- Update nunjucks to fix JS error when page contains a lot of templating blocks
## 3.2.0
- Switch markdown parser from `kramed` to `markup-it`
- Fix support of `|` in tables
- Fix access to `output.name` in templating
- Fix i18n for website and PDF
- Fix minor scrolling issues on website
- Improve options of default search indexer (keywords, disabling per pages)
- Improve pertinence of search results
## 3.1.1
- Fix order of plugins during loading
- Fix error when using math and conrefs
- Fix target attribute for external links
- Fix serve command
## 3.1.0
- Always load themes after plugins
- README/Introduction doesn't require to be the first entry in the summary
- Highlight active entry in summary when scrolling a page with anchors
- Support empty parts in summary
## 3.0.3
- Fix redirection in `gitbook serve` when accessing a folder without trailing slash
- Fix links/annotations for glossary not being correctly resolved
- Fix regression for supporting uppercase filenames in structure files
- Fix `gitbook install` when using Git URLs for plugins
## 3.0.2
- Fix crash for anchor links
## 3.0.1
- Fix regression in link resolution when contain anchor
- Fix `structure.<name>` configuration not supporting filenames with dots
## 3.0.0
- Summary can contain external links and anchors (Fix [#776](https://github.com/GitbookIO/gitbook/issues/776))
- Summary can contain differents entitled sections
- Glossary is generated as a normal page
@@ -11,7 +67,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
- `links.sidebar` configuration is no longer supported, use summary sections instead
- `pdf.headerTemplate` and `pdf.footerTemplate` have been replaced by a template in theme/book: `_layout/ebook/pdf_header.html` and `_layout/ebook/pdf_footer.html`
- Markdown parser is now using CommonMark
- Root folder for the book can be specified in a `.gitbook` file
- Root folder for the book can be specified in the `"root"` property of the `book.json` file
- Multi-lingual books share assets folder
- YAML front matter is parsed and can extend page's properties
- Fix `uk` translation
+51
View File
@@ -0,0 +1,51 @@
# Contributing
Want to contribute to GitBook? That would be awesome!
- [Send feedback](#send-feedback)
- [Reporting Bugs](#reporting-bugs)
- [Asking Questions](#asking-questions)
- [Submitting Pull Requests](#submitting-pull-requests)
- [Running Tests](#running-tests)
## Send feedback
Weve done our best to test but your feedback is really important. If you encounter problems or have feedback about GitBook products (GitBook.com, GitBook Editor, or the Toolchain), please log an issue in the [GitbookIO/feedback](https://github.com/GitbookIO/feedback/issues) repository.
## Reporting Bugs
If you run into any weird behavior while using GitBook, feel free to open a new issue in this repository! To be most helpful, please include the steps to reproduce the bug as best you can, including the output of command `gitbook -V`.
## Asking Questions
Questions are very welcome :smile:! Previous questions that folks have asked are tagged with a [`question`](https://github.com/GitBookIO/gitbook/issues?q=is%3Aissue+is%3Aclosed+label%3Aquestion) label, so before opening a new issue double-check that someone hasn't asked it before. But if you don't see anything, or if you're not sure if it's the same, err on the side of asking!
We've also got a [GitBook Community Slack](https://slack.gitbook.com/) where you can ask questions and get answers from other people using GitBook.
## Submitting Pull Requests
All pull requests are super welcomed and greatly appreciated! Easy issues are marked with an [`easy-one`](https://github.com/GitBookIO/gitbook/issues?q=is%3Aopen+is%3Aissue+label%3Aeasy-one) label if you're looking for a simple place to get familiar with the code base.
Please include tests and docs with every pull request!
## Running Tests
To run the examples, you need to have the GitBook repository cloned to your computer. After that, you need to `cd` into the directory where you cloned it, and install the dependencies from `npm` using `yarn`.
```
$ yarn install
```
Then you'll need to bootstrap it:
```
$ npm run bootstrap
```
Which will also compile the source files. Then run the tests with:
```
$ npm test
```
+17 -9
View File
@@ -1,12 +1,22 @@
GitBook
=======
[![GitBook](https://raw.github.com/GitbookIO/gitbook/master/docs/images/banner.png)](https://www.gitbook.com)
[![NPM version](https://badge.fury.io/js/gitbook.svg)](http://badge.fury.io/js/gitbook)
[![Linux Build Status](https://travis-ci.org/GitbookIO/gitbook.png?branch=master)](https://travis-ci.org/GitbookIO/gitbook)
[![Windows Build status](https://ci.appveyor.com/api/projects/status/63nlflxcwmb2pue6?svg=true)](https://ci.appveyor.com/project/GitBook/gitbook)
[![Slack Status](https://slack.gitbook.com/badge.svg)](https://slack.gitbook.com)
<p align="center">A <em>modern</em> customizable documentation format and toolchain</p>
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). Here is an example: [Learn Javascript](https://www.gitbook.com/book/GitBookIO/javascript).
<p align="center"><a href="#features"><strong>Features</strong></a> · <a href="https://www.gitbook.com"><strong>Hosting</strong></a> · <a href="http://redux.js.org/"><strong>Example</strong></a> · <a href="https://www.gitbook.com/editor"><strong>Editor</strong></a> · <a href="https://toolchain.gitbook.com/"><strong>Documentation</strong></a> · <a href="./CONTRIBUTING.md"><strong>Contributing!</strong></a> · <a href="https://twitter.com/GitBookIO"><strong>Twitter</strong></a></p>
<br/>
![Preview](https://raw.github.com/GitbookIO/gitbook/master/docs/images/preview.png)
<p align="center">
<img src="https://badge.fury.io/js/gitbook.svg" />
<a href="https://travis-ci.org/GitbookIO/gitbook"><img src="https://travis-ci.org/GitbookIO/gitbook.png?branch=master" /></a>
<a href="https://ci.appveyor.com/project/GitBook/gitbook"><img src="https://ci.appveyor.com/api/projects/status/63nlflxcwmb2pue6?svg=true" /></a>
<a href="https://ci.appveyor.com/project/GitBook/gitbook"><img src="https://slack.gitbook.com/badge.svg" /></a>
</p>
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). Here is an example: [ReduxJS documentation](http://redux.js.org/).
You can publish and host books easily online using [gitbook.com](https://www.gitbook.com). A desktop editor is [also available](https://www.gitbook.com/editor).
@@ -14,8 +24,6 @@ Check out the [GitBook Community Slack Channel](https://slack.gitbook.com), Stay
Complete documentation is available at [toolchain.gitbook.com](http://toolchain.gitbook.com/).
![Image](https://raw.github.com/GitbookIO/gitbook/master/preview.png)
## Getting started
GitBook can be used either on your computer for building local books or on GitBook.com for hosting them. To get started, check out [the installation instructions in the documentation](docs/setup.md).
+9
View File
@@ -5,13 +5,18 @@ init:
# Test against these versions of Node.js.
environment:
matrix:
- nodejs_version: "6"
- nodejs_version: "5"
- nodejs_version: "4"
matrix:
fast_finish: true
# Install scripts. (runs after repo cloning)
install:
# Get the latest stable version of Node.js or io.js
- ps: Install-Product node $env:nodejs_version
- set CI=true
# install svgexport
- npm install svgexport -g
# install modules
@@ -27,3 +32,7 @@ test_script:
# Don't actually build.
build: off
# Clone only last commit
shallow_clone: true
clone_depth: 1
+1 -4
View File
@@ -5,11 +5,8 @@ module.exports = {
root: './docs',
title: 'GitBook Toolchain Documentation',
// Enforce use of GitBook v3
gitbook: '>=3.0.0-pre.0',
// Use the "official" theme
plugins: ['theme-official', 'sitemap'],
plugins: ['sitemap'],
variables: {
version: pkg.version
+2 -3
View File
@@ -4,7 +4,7 @@ This document aims to be a comprehensive guide to GitBook. It contains the full
### What is GitBook?
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). . This documentation has been generated using GitBook.
GitBook is a command line tool (and Node.js library) for building beautiful books using GitHub/Git and Markdown (or AsciiDoc). This documentation has been generated using GitBook.
GitBook can output your content as a website ([customizable](themes/README.md) and [extensibles](plugins/README.md)) or as an ebook (PDF, ePub or Mobi).
@@ -18,9 +18,8 @@ Check out the [GitBook Community Slack Channel](https://slack.gitbook.com), Stay
### FAQ
Some questions are frequently asked. If you have a problem you should [check this out](faq.md) first.
Some questions are frequently asked. If you have a problem you should [check this out](faq.md) first.
### Contribute to this documentation
You can contribute to improve this documentation on [GitHub](https://github.com/GitbookIO/gitbook) by signaling issues or proposing changes.
+8 -2
View File
@@ -15,6 +15,7 @@
* [Markdown](syntax/markdown.md)
* [Headings](syntax/markdown.md#headings)
* [Paragraphs](syntax/markdown.md#paragraphs)
* [Emphasis](syntax/markdown.md#emphasis)
* [Lists](syntax/markdown.md#lists)
* [Links](syntax/markdown.md#links)
* [Images](syntax/markdown.md#images)
@@ -41,10 +42,15 @@
* [Test your plugin](plugins/testing.md)
* [Theming](themes/README.md)
### Plugin Development
* [Introduction](./api/README.md)
* [Node](./api/node.md)
* [Connect to the context](./api/connect.md)
* [Components](./api/components.md)
--
* [FAQ](faq.md)
* [Examples](examples.md)
* [Release notes](https://github.com/GitbookIO/gitbook/blob/master/CHANGES.md)
-26
View File
@@ -1,26 +0,0 @@
{% extends template.self %}
{% block header_nav %}
<a href="https://github.com/GitbookIO/gitbook/blob/master/docs/{{ file.path }}" target="_blank" class="btn btn-link pull-right hidden-xs">
<i class="octicon octicon-mark-github"></i> Edit on GitHub
</a>
<a href="{{ "faq.md"|resolveFile }}" class="btn btn-link pull-right hidden-xs">
F.A.Q
</a>
<a href="https://github.com/GitbookIO/gitbook/blob/master/CHANGES.md" target="_blank" class="btn btn-link pull-right hidden-xs">
{{ book.version }}
</a>
{% endblock %}
{% block page %}
{{ super() }}
<hr>
<div class="btn-group btn-group-justified">
{% if page.previous and page.previous.path %}
<a class="btn" href="{{ page.previous.path|resolveFile }}"><b>Previous:</b> {{ page.previous.title }}</a>
{% endif %}
{% if page.next and page.next.path %}
<a class="btn" href="{{ page.next.path|resolveFile }}"><b>Next:</b> {{ page.next.title }}</a>
{% endif %}
</div>
{% endblock %}
+24
View File
@@ -0,0 +1,24 @@
# Plugin Architecture
A GitBook plugin is a NPM package that follows a defined convention.
`gitbook-plugin` is a command line utility to help you create, test and release plugins.
### Bootstrap your first plugin
Install `gitbook-plugin` from NPM:
```
$ npm install gitbook-plugin -g
```
Then create your plugin:
```
$ gitbook-plugin create
```
You will be asked for a plugin name, and a few other things to complete the creation process.
### Publish your plugin
+86
View File
@@ -0,0 +1,86 @@
# Components
## Injection
Plugins can inject components by registering React components to some roles.
#### Register a components
During the initialization phase of your plugin, dispatch the `GitBook.registerComponent` action:
```js
dispatch(GitBook.registerComponent(MyCustomButton, { role: 'toolbar:buttons:left' }));
```
#### Roles
Custom roles can be use for interopability with other plugins, but GitBook and the default theme set a convention for common roles:
| Role | Description | Props |
| ---- | ----------- | ----- |
| `page:container` | DIV container for the page's content | `{ page: Page }` |
| `summary:container` | DIV container for the whole summary | `{ summary: Summary }` |
| `summary:parts` | DIV container for summary's parts | `{ parts: List<SummaryPart> }` |
| `summary:part` | DIV for a specific part | `{ part: SummaryPart }` |
| `summary:articles` | UL container for a part's articles | `{ articles: List<SummaryArticle> }` |
| `summary:article` | LI for a specific article | `{ article: SummaryArticle }` |
## Default Components
#### `GitBook.Head`
Extends the meta tags of the page. This is an alias for [react-helmet](https://github.com/nfl/react-helmet).
```js
<GitBook.Head
title="My page"
/>
```
#### `GitBook.ImportCSS`
Import a CSS file by resolving the path correctly according to the current page:
```js
<GitBook.ImportCSS href="myfile.css" />
```
#### `GitBook.ImportJS`
Import a JS file by resolving the path correctly according to the current page:
```js
<GitBook.ImportJS src="mylib.js" />
```
#### `GitBook.InjectedComponent`
Inject a component matching a specific role:
```js
<GitBook.InjectedComponent matching={{ role: 'mycustomrole' }} props={{ someProp: 1 }}>
<b>Inner content</b>
</GitBook.InjectedComponent>
```
#### `GitBook.InjectedComponentSet`
Same API as `InjectedComponentSet` but render the matching components in chain instead of composed:
```js
<GitBook.InjectedComponentSet matching={{ role: 'mytoolbar' }} />
```
**Warning:** Children are discarded.
#### `GitBook.FlexLayout` and `GitBook.FlexBox`
A simple wrapper that provides a Flexbox layout with the given direction and style. Any additional props you set on the Flexbox are rendered.
```js
<GitBook.FlexLayout column>
<GitBook.FlexBox>First column</GitBook.FlexBox>
<GitBook.FlexBox>Second column</GitBook.FlexBox>
</GitBook.FlexLayout>
```
+33
View File
@@ -0,0 +1,33 @@
# Connect to the context
`GitBook.connect(Component, [mapStateToProps], [mapActionsToProps])` connects a react component to the GitBook context.
It does not modify the component class passed to it.
Instead, it returns a new, connected component class, for you to use.
### `mapStateToProps(state, [ownProps]): stateProps`
If specified, the component will subscribe to GitBook store updates. Any time it updates, `mapStateToProps` will be called. Its result must be a plain object, and it will be merged into the components props.
If you omit it, the component will not be subscribed to the GitBook store. If `ownProps` is specified as a second argument, its value will be the props passed to your component, and `mapStateToProps` will be additionally re-invoked whenever the component receives new props (e.g. if props received from a parent component have shallowly changed, and you use the `ownProps` argument, `mapStateToProps` is re-evaluated).
For example to render the title of the current page:
```js
const GitBook = require('gitbook-core');
let PageTitle = React.createClass({
render() {
const { page } = this.props;
return <h1>{page.title}</h1>;
}
});
function mapStateToProps(state) {
return { page: state.page };
}
PageTitle = GitBook.connect(PageTitle, mapStateToProps);
```
### `mapActionsToProps(actions, [dispatch])`
+44
View File
@@ -0,0 +1,44 @@
# Internationalize your plugin
GitBook has built-in support for internationalization. Plugins can register new languages and provide the right messages for different languages.
### Register locale and messages
The first step is to register messages for a language:
```js
module.exports = GitBook.createPlugin({
init: (dispatch, getState, { I18n }) => {
dispatch(I18n.registerLocale('en-US', {
MY_PLUGIN_MESSAGE: 'Hello World'
}));
}
});
```
### Render a message in a component
`GitBook.connect` adds a `i18n` prop to access the internationalization:
```js
const GitBook = require('gitbook-core');
const { React } = GitBook;
const MyButton = React.createClass({
propTypes: {
i18n: GitBook.Shapes.i18n
},
render() {
const { i18n } = this.props;
return (
<GitBook.Button>
{i18.t('MY_PLUGIN_MESSAGE')}
</GitBook.Button>
);
}
});
module.exports = GitBook.connect(MyButton);
```
+23
View File
@@ -0,0 +1,23 @@
# Navigation
### Listen to url change
Listen for changes to the current location:
```js
const onLocationChanged = (location) => {
console.log(location.pathname);
console.log(location.query);
console.log(location.hash);
};
module.exports = GitBook.createPlugin({
init: (dispatch, getState, { Navigation }) => {
dispatch(Navigation.listen(onLocationChanged));
}
});
```
The `onLocationChanged` will be triggered for initial state.
### Changing the url
+97
View File
@@ -0,0 +1,97 @@
# Node APIs
GitBooks provides different Node APIs and contexts to plugins. These APIs can vary according to the GitBook version being used, your plugin should specify the `engines.gitbook` field in `package.json` accordingly.
#### Book instance
The `Book` interface is the central point of GitBook, it centralize all access read methods.
```js
// Read configuration from book.json
var value = book.config.get('title', 'Default Value');
// Resolve a filename to an absolute path
var filepath = book.resolve('README.md');
// Render an inline markup string
book.renderInline('markdown', 'This is **Markdown**')
.then(function(str) { ... })
// Render a markup string (block mode)
book.renderBlock('markdown', '* This is **Markdown**')
.then(function(str) { ... })
```
#### Output instance
The `Output` class represent the output/write process.
```js
// Return root folder for the output
var root = output.root();
// Resolve a file in the output folder
var filepath = output.resolve('myimage.png');
// Convert a filename to an URL (returns a path to an html file)
var fileurl = output.toURL('mychapter/README.md');
// Write a file in the output folder
output.writeFile('hello.txt', 'Hello World')
.then(function() { ... });
// Copy a file to the output folder
output.copyFile('./myfile.jpg', 'cover.jpg')
.then(function() { ... });
// Verify that a file exists
output.hasFile('hello.txt')
.then(function(exists) { ... });
```
#### Page instance
A page instance represent the current parsed page.
```js
// Title of the page (from SUMMARY)
page.title
// Content of the page (Markdown/Asciidoc/HTML according to the stage)
page.content
// Relative path in the book
page.path
// Absolute path to the file
page.rawPath
// Type of parser used for this file
page.type ('markdown' or 'asciidoc')
```
#### Context for Blocks and Filters
Blocks and filters have access to the same context, this context is bind to the template engine execution:
```js
{
// Current templating syntax
"ctx": {
// For example, after a {% set message = "hello" %}
"message": "hello"
},
// Book instance
"book" <Book>,
// Output instance
"output": <Output>
}
```
For example a filter or block function can access the current book using: `this.book`.
#### Context for Hooks
Hooks only have access to the `<Book>` instance using `this.book`.
+10 -3
View File
@@ -7,6 +7,7 @@ GitBook allows you to customize your book using a flexible configuration. These
| Variable | Description |
| -------- | ----------- |
| `root` | Path to the root folder containing all the book's files, except `book.json`|
| `structure` | To specify paths for Readme, Summary, Glossary etc. See [Structure paragraph](#structure). |
| `title` | Title of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
| `description` | Description of your book, default value is extracted from the README. On GitBook.com this field is pre-filled. |
| `author` | Name of the author. On GitBook.com this field is pre-filled. |
@@ -19,18 +20,24 @@ GitBook allows you to customize your book using a flexible configuration. These
Plugins and their configurations are specified in the `book.json`. See [the plugins section](plugins/README.md) for more details.
Since version 3.0.0, GitBook can use themes. See [the theming section](themes/README.md) for more details.
| Variable | Description |
| -------- | ----------- |
| `plugins` | List of plugins to load |
| `pluginsConfig` |Configuration for plugins |
### Theme
### Structure
Since version 3.0.0, GitBook can use themes. See [the theming section](themes/README.md) for more details.
In addition to the `root` variable, you can tell Gitbook the name of the files for Readme, Summary, Glossary, Languages (instead of using the default names such as `README.md`).
These files must be at the root of your book (or the root of every language book). Paths such as `dir/MY_README.md` are not accepted.
| Variable | Description |
| -------- | ----------- |
| `theme` | The theme to use for the book |
| `structure.readme` | Readme file name (defaults to `README.md`) |
| `structure.summary` | Summary file name (defaults to `SUMMARY.md`) |
| `structure.glossary` | Glossary file name (defaults to `GLOSSARY.md`) |
| `structure.languages` | Languages file name (defaults to `LANGS.md`) |
### PDF Options
+18 -3
View File
@@ -17,6 +17,20 @@ $ gitbook mobi ./ ./mybook.mobi
`ebook-convert` is required to generate ebooks (epub, mobi, pdf).
##### GNU/Linux
Install the [Calibre application](https://calibre-ebook.com/download).
```
$ sudo aptitude install calibre
```
In some GNU/Linux distributions node is installed as nodejs, you need to manually create a symlink:
```
$sudo ln -s /usr/bin/nodejs /usr/bin/node
```
##### OS X
Download the [Calibre application](https://calibre-ebook.com/download). After moving the `calibre.app` to your Applications folder create a symbolic link to the ebook-convert tool:
@@ -29,12 +43,13 @@ You can replace `/usr/bin` with any directory that is in your $PATH.
### Cover
Covers are used for all the ebook formats. It's an important part of an ebook brandline.
Covers are used for all the ebook formats. You can either provide one yourself, or generate one using the [autocover plugin](https://plugins.gitbook.com/plugin/autocover).
To provide a cover, place a **`cover.jpg`** file at the root directory of your book. Adding a **`cover_small.jpg`** will specify a smaller version of the cover. The cover should be a **JPEG** file.
A good cover should respect the following guidelines:
* Size of 1800x2360 (pixels)
* Size of 1800x2360 pixels for `cover.jpg`, 200x262 for `cover_small.jpg`
* No border
* Clearly visible book title
* Any important text should be visible in the small version
+2 -1
View File
@@ -23,5 +23,6 @@ More than 50,000 books have been published on [GitBook.com](https://www.gitbook.
### Documentation
- [DuckDuckHack Documentation](http://docs.duckduckhack.com) by [DuckDuckGo](https://duckduckgo.com/about)
- [Loomio Handbook](http://loomio.coop/) and [guide to using Loomio](https://loomio.gitbooks.io/manual/content/en/index.html) both by [Loomio](https://www.loomio.org/)
- [Enspiral Handbook](http://handbook.enspiral.com/) by [Enspiral](http://enspiral.com/)
- This documentation
+2 -2
View File
@@ -18,7 +18,7 @@ Any text editor should work! But we advise using the [GitBook Editor](https://ww
The GitBook format supports right to left, and bi-directional writing. To enable it, you either need to specify a language (ex: `ar`), or force GitBook to use RTL in your `book.json`:
``` json
```json
{
"language": "ar",
"direction": "rtl"
@@ -34,7 +34,7 @@ You should always use paths and the `.md` extensions when linking to your files,
#### Can I create a GitBook in a sub-directory of my repository?
Yes, GitBooks can be created in [sub-directories](structure.md#subdirectory). GitBook.com and the CLI also looks by default in a serie of [folders](structure.md).
Yes, GitBooks can be created in [sub-directories](structure.md#subdirectory). GitBook.com and the CLI also looks by default in a series of [folders](structure.md).
#### Does GitBook supports RTL languages?
Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Before

Width:  |  Height:  |  Size: 227 KiB

After

Width:  |  Height:  |  Size: 227 KiB

+3 -3
View File
@@ -2,13 +2,13 @@
Allows you to specify terms and their respective definitions to be displayed as annotations. Based on those terms, GitBook will automatically build an index and highlight those terms in pages.
The `GLOSSARY.md` format is very simple :
The `GLOSSARY.md` format is a list of `h2` headings, along with a description paragraph:
```markdown
# Term
## Term
Definition for this term
# Another term
## Another term
With it's definition, this can contain bold text
and all other kinds of inline markup ...
```
+1 -2
View File
@@ -40,7 +40,6 @@ Chapters in the Table of Contents can be pointing to specific part of a file usi
* [Better tools for authors](part2/README.md#tools)
```
##### Parts
The Table of Contents can be divided into parts separated by headings or horizontal lines:
@@ -73,7 +72,7 @@ Most of the files for GitBook use the Markdown syntax by default. GitBook infers
##### Example of a chapter file
``` markdown
```markdown
# Title of the chapter
This is a great introduction.
+1 -1
View File
@@ -1,6 +1,6 @@
# Plugins
Plugins are the best way to extend GitBook functionalities (ebook and website). There exist plugins to do a lot of things: bring math formulas display support, track visits using Google Analytic, etc.
Plugins are the best way to extend GitBook functionalities (ebook and website). There exist plugins to do a lot of things: bring math formulas display support, track visits using Google Analytics, etc.
### How to find plugins?
+2 -2
View File
@@ -4,7 +4,7 @@ GitBooks provides different APIs and contexts to plugins. These APIs can vary ac
#### Book instance
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https://github.com/GitbookIO/gitbook/blob/master/lib/book.js).
The `Book` class is the central point of GitBook, it centralize all access read methods. This class is defined in [book.js](https://github.com/GitbookIO/gitbook/blob/master/book.js).
```js
// Read configuration from book.json
@@ -37,7 +37,7 @@ var filepath = output.resolve('myimage.png');
var fileurl = output.toURL('mychapter/README.md');
// Write a file in the output folder
output.write('hello.txt', 'Hello World')
output.writeFile('hello.txt', 'Hello World')
.then(function() { ... });
// Copy a file to the output folder
+1 -1
View File
@@ -54,4 +54,4 @@ module.exports = {
}
}
};
```
```
-1
View File
@@ -71,7 +71,6 @@ In the `page` hook, `page.content` is the HTML generated from the markdown/ascii
}
```
### Asynchronous Operations
Hooks callbacks can be asynchronous and return promises.
+2 -3
View File
@@ -2,7 +2,7 @@
### Testing your plugin locally
Testing your plugin on your book before plushing it is possible using [npm link](https://docs.npmjs.com/cli/link).
Testing your plugin on your book before publishing it is possible using [npm link](https://docs.npmjs.com/cli/link).
In the plugin's folder, run:
@@ -10,7 +10,7 @@ In the plugin's folder, run:
$ npm link
```
The nin your book's folder:
Then in your book's folder:
```
$ npm link gitbook-plugin-<plugin's name>
@@ -19,4 +19,3 @@ $ npm link gitbook-plugin-<plugin's name>
### Unit testing on Travis
[gitbook-tester](https://github.com/todvora/gitbook-tester) makes it easy to write **Node.js/Mocha** unit tests for your plugins. Using [Travis.org](https://travis.org), tests can be run on each commits/tags.
+1 -2
View File
@@ -14,7 +14,7 @@ It integrates well with the [GitBook Editor](https://www.gitbook.com/editor).
Installing GitBook is easy and straightforward. Your system just needs to meet these two requirements:
* NodeJS (v4.0.0 and above are adviced)
* NodeJS (v4.0.0 and above is recommended)
* Windows, Linux, Unix, or Mac OS X
##### Install with NPM
@@ -66,4 +66,3 @@ You can use the options `--log=debug` and `--debug` to get better error messages
```
$ gitbook build ./ --log=debug --debug
```
+4
View File
@@ -0,0 +1,4 @@
/* Reduce size of logo to allow long versions like 3.0.0-pre.1 */
.gb-page-header .container .logo h1 {
font-size: 24px ;
}
+3 -4
View File
@@ -12,7 +12,7 @@ This is the main entry of your book: the introduction. This file is **required**
### SUMMARY.adoc
This file defines the list of chapters and subchapters. Just like in Markdown, the `SUMMARY.adoc`'s format is simply a list of links, the name of the link is used as the chapter's name, and the target is a path to that chapter's file.
This file defines the list of chapters and subchapters. Just like in Markdown, the `SUMMARY.adoc`'s format is simply a list of links, the name of the link is used as the chapter's name, and the target is a path to that chapter's file.
Subchapters are defined simply by adding a nested list to a parent chapter.
@@ -60,6 +60,5 @@ observer producing a sense of wonder.
A popular web programming language, used by many large websites such
as Facebook. Rasmus Lerdorf originally created PHP in 1994 to power
his personal homepage (PHP originally stood for "Personal Home Page"
but now stands for "PHP: Hypertext Preprocessor"). ```
but now stands for "PHP: Hypertext Preprocessor").
```
+2 -2
View File
@@ -21,7 +21,7 @@ This looks up username from the context and displays it. Variable names can have
If a value is undefined, nothing is displayed. The following all output nothing if foo is undefined: `{{ foo }}`, `{{ foo.bar }}`, `{{ foo.bar.baz }}`.
GitBook provides a set of [predefined variables](variables.md) from the context.
GitBook provides a set of [predefined variables](variables.md) from the context.
### Filters
@@ -92,7 +92,7 @@ Inclusion and inheritance is detailled in the [Content References](conrefs.md) s
If you want GitBook to ignore any of the special templating tags, you can use raw and anything inside of it will be output as plain text.
``` twig
```twig
{% raw %}
this will {{ not be processed }}
{% endraw %}
+2 -1
View File
@@ -4,7 +4,8 @@ GitBook provides a serie of builtin filters and blocks to help you write templat
### Filters
`value|default(default, [boolean])`If value is strictly undefined, return default, otherwise value. If boolean is true, any JavaScript falsy value will return default (false, "", etc)
`value|default(default, [boolean])`
If value is strictly undefined, return default, otherwise value. If boolean is true, any JavaScript falsy value will return default (false, "", etc)
`arr|sort(reverse, caseSens, attr)`
Sort arr with JavaScript's arr.sort function. If reverse is true, result will be reversed. Sort is case-insensitive by default, but setting caseSens to true makes it case-sensitive. If attr is passed, will compare attr from each item.
+1 -1
View File
@@ -51,5 +51,5 @@ This is the default content
# License
{% import "./LICENSE" %}
{% include "./LICENSE" %}
```
+14 -2
View File
@@ -21,14 +21,26 @@ The following is a reference of the available data during book's parsing and the
| Variable | Description |
| -------- | ----------- |
| `book.[CONFIGURATION_DATA]` | All the `variables` set via the `book.json` are available through the book variable. |
| `book.language` | Current language for a multilingual book |
| `book.[value]` | All other values under `variables` in the `book.json` are accessible here |
For example, with this `book.json`:
```json
{
variables: {
hello: "everyone"
}
}
```
... the following text `{{ book.hello }}` will expand to `everyone`.
### GitBook Variables
| Variable | Description |
| -------- | ----------- |
| `gitbook.time` | The current time (when you run the `gitbook` command) . |
| `gitbook.time` | The current time (when you run the `gitbook` command). |
| `gitbook.version` | Version of GitBook used to generate the book |
### File Variables
+17 -2
View File
@@ -12,12 +12,27 @@ A theme is a plugin containing templates and assets. Overriding any individual t
| -------- | ----------- |
| `_layouts` | Main folder containing all the templates |
| `_layouts/website/page.html` | Template for a normal page |
| `_layouts/ebook/page.html` | Template for a normal page during ebook generation (PDF< ePub, Mobi) |
| `_layouts/ebook/page.html` | Template for a normal page during ebook generation (PDF, ePub, Mobi) |
### Extend/Customize theme in a book
Authors can extend the templates of a theme directly from their book's source (without creating an external theme). Templates will be resolved in the `_layouts` folder of the book first, then in
Authors can extend the templates of a theme directly from their book's source (without creating an external theme). Templates will be resolved in the `_layouts` folder of the book first, then in the installed plugins/themes.
### Extend instead of Forking
When you want to make your theme changes available to multiple books, instead of forking the default theme, you can extend it using the [templating syntax](../templating/README.md):
```html
{% extends template.self %}
{% block body %}
{{ super() }}
... This will be added to the "body" block
{% endblock %}
```
Take a look at the [API](https://github.com/GitbookIO/theme-api) theme for a more complete example.
### Publish a theme
-25
View File
@@ -1,25 +0,0 @@
var path = require('path');
var fs = require('fs');
var matchers = {
/**
Verify that a file exists in a directory
*/
toHaveFile: function () {
return {
compare: function (actual, expected) {
var filePath = path.join(actual, expected);
var exists = fs.existsSync(filePath);
return {
pass: exists
};
}
};
}
};
jasmine.getEnv().beforeEach(function () {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 20000;
jasmine.addMatchers(matchers);
});
+4
View File
@@ -0,0 +1,4 @@
{
"lerna": "2.0.0-beta.31",
"version": "4.0.0-alpha.3"
}
-9
View File
@@ -1,9 +0,0 @@
var gitbook = require('../gitbook');
describe('satisfies', function() {
it('should return true for *', function() {
expect(gitbook.satisfies('*')).toBe(true);
});
});
-16
View File
@@ -1,16 +0,0 @@
var tmp = require('tmp');
var initBook = require('../init');
describe('initBook', function() {
pit('should create a README and SUMMARY for empty book', function() {
var dir = tmp.dirSync();
return initBook(dir.name)
.then(function() {
expect(dir.name).toHaveFile('README.md');
expect(dir.name).toHaveFile('SUMMARY.md');
});
});
});
-6
View File
@@ -1,6 +0,0 @@
describe('GitBook', function() {
it('should correctly export', function() {
require('../');
});
});
-22
View File
@@ -1,22 +0,0 @@
var decodeConfig = require('./decodeConfig');
/**
Decode changes from a JS API to a output object.
Only the configuration can be edited by plugin's hooks
@param {Output} output
@param {Object} result: result from API
@return {Output}
*/
function decodeGlobal(output, result) {
var book = output.getBook();
var config = book.getConfig();
// Update config
config = decodeConfig(config, result.config);
book = book.set('config', config);
return output.set('book', book);
}
module.exports = decodeGlobal;
-44
View File
@@ -1,44 +0,0 @@
var deprecate = require('./deprecate');
/**
Decode changes from a JS API to a page object.
Only the content can be edited by plugin's hooks.
@param {Output} output
@param {Page} page: page instance to edit
@param {Object} result: result from API
@return {Page}
*/
function decodePage(output, page, result) {
var originalContent = page.getContent();
// No returned value
// Existing content will be used
if (!result) {
return page;
}
deprecate.disable('page.sections');
// GitBook 3
// Use returned page.content if different from original content
if (result.content != originalContent) {
page = page.set('content', result.content);
}
// GitBook 2 compatibility
// Finally, use page.sections
else if (result.sections) {
page = page.set('content',
result.sections.map(function(section) {
return section.content;
}).join('\n')
);
}
deprecate.enable('page.sections');
return page;
}
module.exports = decodePage;
-122
View File
@@ -1,122 +0,0 @@
var is = require('is');
var objectPath = require('object-path');
var logged = {};
var disabled = {};
/**
Log a deprecated notice
@param {Book|Output} book
@param {String} key
@param {String} message
*/
function logNotice(book, key, message) {
if (logged[key] || disabled[key]) return;
logged[key] = true;
var logger = book.getLogger();
logger.warn.ln(message);
}
/**
Deprecate a function
@param {Book|Output} book
@param {String} key: unique identitifer for the deprecated
@param {Function} fn
@param {String} msg: message to print when called
@return {Function}
*/
function deprecateMethod(book, key, fn, msg) {
return function() {
logNotice(book, key, msg);
return fn.apply(this, arguments);
};
}
/**
Deprecate a property of an object
@param {Book|Output} book
@param {String} key: unique identitifer for the deprecated
@param {Object} instance
@param {String|Function} property
@param {String} msg: message to print when called
@return {Function}
*/
function deprecateField(book, key, instance, property, value, msg) {
var store = undefined;
var prepare = function() {
if (!is.undefined(store)) return;
if (is.fn(value)) store = value();
else store = value;
};
var getter = function(){
prepare();
logNotice(book, key, msg);
return store;
};
var setter = function(v) {
prepare();
logNotice(book, key, msg);
store = v;
return store;
};
Object.defineProperty(instance, property, {
get: getter,
set: setter,
enumerable: true,
configurable: true
});
}
/**
Enable a deprecation
@param {String} key: unique identitifer
*/
function enableDeprecation(key) {
disabled[key] = false;
}
/**
Disable a deprecation
@param {String} key: unique identitifer
*/
function disableDeprecation(key) {
disabled[key] = true;
}
/**
Deprecate a method in favor of another one
@param {Book} book
@param {String} key
@param {Object} instance
@param {String} oldName
@param {String} newName
*/
function deprecateRenamedMethod(book, key, instance, oldName, newName, msg) {
msg = msg || ('"' + oldName + '" is deprecated, use "' + newName + '()" instead');
var fn = objectPath.get(instance, newName);
instance[oldName] = deprecateMethod(book, key, fn, msg);
}
module.exports = {
method: deprecateMethod,
renamedMethod: deprecateRenamedMethod,
field: deprecateField,
enable: enableDeprecation,
disable: disableDeprecation
};
-165
View File
@@ -1,165 +0,0 @@
var path = require('path');
var Promise = require('../utils/promise');
var PathUtils = require('../utils/path');
var fs = require('../utils/fs');
var Plugins = require('../plugins');
var deprecate = require('./deprecate');
var encodeConfig = require('./encodeConfig');
var encodeNavigation = require('./encodeNavigation');
var fileToURL = require('../output/helper/fileToURL');
var defaultBlocks = require('../constants/defaultBlocks');
var gitbook = require('../gitbook');
/**
Encode a global context into a JS object
It's the context for page's hook, etc
@param {Output} output
@return {Object}
*/
function encodeGlobal(output) {
var book = output.getBook();
var bookFS = book.getContentFS();
var logger = output.getLogger();
var outputFolder = output.getRoot();
var plugins = output.getPlugins();
var blocks = Plugins.listBlocks(plugins);
var result = {
log: logger,
config: encodeConfig(output, book.getConfig()),
/**
Check if the book is a multilingual book
@return {Boolean}
*/
isMultilingual: function() {
return book.isMultilingual();
},
/**
Check if the book is a language book for a multilingual book
@return {Boolean}
*/
isLanguageBook: function() {
return book.isLanguageBook();
},
/**
Read a file from the book
@param {String} fileName
@return {Promise<Buffer>}
*/
readFile: function(fileName) {
return bookFS.read(fileName);
},
/**
Read a file from the book as a string
@param {String} fileName
@return {Promise<String>}
*/
readFileAsString: function(fileName) {
return bookFS.readAsString(fileName);
},
/**
Resolve a file from the book root
@param {String} fileName
@return {String}
*/
resolve: function(fileName) {
return path.resolve(book.getContentRoot(), fileName);
},
template: {
/**
Apply a templating block and returns its result
@param {String} name
@param {Object} blockData
@return {Promise|Object}
*/
applyBlock: function(name, blockData) {
var block = blocks.get(name) || defaultBlocks.get(name);
return Promise(block.applyBlock(blockData, result));
}
},
output: {
/**
Name of the generator being used
{String}
*/
name: output.getGenerator(),
/**
Return absolute path to the root folder of output
@return {String}
*/
root: function() {
return outputFolder;
},
/**
Convert a filepath into an url
@return {String}
*/
toURL: function(filePath) {
return fileToURL(output, filePath);
},
/**
Write a file to the output folder,
It creates the required folder
@param {String} fileName
@param {Buffer} content
@return {Promise}
*/
writeFile: function(fileName, content) {
return Promise()
.then(function() {
var filePath = PathUtils.resolveInRoot(outputFolder, fileName);
return fs.ensureFile(filePath)
.then(function() {
return fs.writeFile(filePath, content);
});
});
}
},
gitbook: {
version: gitbook.version
}
};
// Deprecated properties
deprecate.renamedMethod(output, 'this.isSubBook', result, 'isSubBook', 'isLanguageBook');
deprecate.renamedMethod(output, 'this.contentLink', result, 'contentLink', 'output.toURL');
deprecate.field(output, 'this.generator', result, 'generator',
output.getGenerator(), '"this.generator" property is deprecated, use "this.output.name" instead');
deprecate.field(output, 'this.navigation', result, 'navigation', function() {
return encodeNavigation(output);
}, '"navigation" property is deprecated');
deprecate.field(output, 'this.book', result, 'book',
result, '"book" property is deprecated, use "this" directly instead');
deprecate.field(output, 'this.options', result, 'options',
result.config.values, '"options" property is deprecated, use config.get(key) instead');
return result;
}
module.exports = encodeGlobal;
-64
View File
@@ -1,64 +0,0 @@
var Immutable = require('immutable');
/**
Encode an article for next/prev
@param {Map<String:Page>}
@param {Article}
@return {Object}
*/
function encodeArticle(pages, article) {
var articlePath = article.getPath();
return {
path: articlePath,
title: article.getTitle(),
level: article.getLevel(),
exists: (articlePath && pages.has(articlePath)),
external: article.isExternal()
};
}
/**
this.navigation is a deprecated property from GitBook v2
@param {Output}
@return {Object}
*/
function encodeNavigation(output) {
var book = output.getBook();
var pages = output.getPages();
var summary = book.getSummary();
var articles = summary.getArticlesAsList();
var navigation = articles
.map(function(article, i) {
var ref = article.getRef();
if (!ref) {
return undefined;
}
var prev = articles.get(i - 1);
var next = articles.get(i + 1);
return [
ref,
{
index: i,
title: article.getTitle(),
introduction: (i === 0),
prev: prev? encodeArticle(pages, prev) : undefined,
next: next? encodeArticle(pages, next) : undefined,
level: article.getLevel()
}
];
})
.filter(function(e) {
return Boolean(e);
});
return Immutable.Map(navigation).toJS();
}
module.exports = encodeNavigation;
-8
View File
@@ -1,8 +0,0 @@
module.exports = {
encodePage: require('./encodePage'),
decodePage: require('./decodePage'),
encodeGlobal: require('./encodeGlobal'),
decodeGlobal: require('./decodeGlobal')
};
-15
View File
@@ -1,15 +0,0 @@
var Modifiers = require('./modifiers');
module.exports = {
Parse: require('./parse'),
// Models
Book: require('./models/book'),
FS: require('./models/fs'),
Summary: require('./models/summary'),
Glossary: require('./models/glossary'),
// Modifiers
SummaryModifier: Modifiers.Summary,
ConfigModifier: Modifiers.Config
};
-34
View File
@@ -1,34 +0,0 @@
var Parse = require('../parse');
var Output = require('../output');
var timing = require('../utils/timing');
var options = require('./options');
var getBook = require('./getBook');
var getOutputFolder = require('./getOutputFolder');
module.exports = {
name: 'build [book] [output]',
description: 'build a book',
options: [
options.log,
options.format,
options.timing
],
exec: function(args, kwargs) {
var book = getBook(args, kwargs);
var outputFolder = getOutputFolder(args);
var Generator = Output.getGenerator(kwargs.format);
return Parse.parseBook(book)
.then(function(resultBook) {
return Output.generate(Generator, resultBook, {
root: outputFolder
});
})
.fin(function() {
if (kwargs.timing) timing.dump(book.getLogger());
});
}
};
-23
View File
@@ -1,23 +0,0 @@
var path = require('path');
var Book = require('../models/book');
var createNodeFS = require('../fs/node');
/**
Return a book instance to work on from
command line args/kwargs
@param {Array} args
@param {Object} kwargs
@return {Book}
*/
function getBook(args, kwargs) {
var input = path.resolve(args[0] || process.cwd());
var logLevel = kwargs.log;
var fs = createNodeFS(input);
var book = Book.createForFS(fs);
return book.setLogLevel(logLevel);
}
module.exports = getBook;
-17
View File
@@ -1,17 +0,0 @@
var path = require('path');
/**
Return path to output folder
@param {Array} args
@return {String}
*/
function getOutputFolder(args) {
var bookRoot = path.resolve(args[0] || process.cwd());
var defaultOutputRoot = path.join(bookRoot, '_book');
var outputFolder = args[1]? path.resolve(process.cwd(), args[1]) : defaultOutputRoot;
return outputFolder;
}
module.exports = getOutputFolder;
-17
View File
@@ -1,17 +0,0 @@
var path = require('path');
var options = require('./options');
var initBook = require('../init');
module.exports = {
name: 'install [book]',
description: 'setup and create files for chapters',
options: [
options.log
],
exec: function(args, kwargs) {
var bookRoot = path.resolve(process.cwd(), args[0] || './');
return initBook(bookRoot);
}
};
-105
View File
@@ -1,105 +0,0 @@
/* eslint-disable no-console */
var tinylr = require('tiny-lr');
var Parse = require('../parse');
var Output = require('../output');
var ConfigModifier = require('../modifiers').Config;
var Promise = require('../utils/promise');
var options = require('./options');
var getBook = require('./getBook');
var getOutputFolder = require('./getOutputFolder');
var Server = require('./server');
var watch = require('./watch');
var server, lrServer, lrPath;
function generateBook(args, kwargs) {
var port = kwargs.port;
var outputFolder = getOutputFolder(args);
var book = getBook(args, kwargs);
var Generator = Output.getGenerator(kwargs.format);
// Stop server if running
if (server.isRunning()) console.log('Stopping server');
return server.stop()
.then(function() {
return Parse.parseBook(book)
.then(function(resultBook) {
// Enable livereload plugin
resultBook = ConfigModifier.addPlugin(resultBook, 'livereload');
return Output.generate(Generator, resultBook, {
root: outputFolder
});
});
})
.then(function() {
console.log();
console.log('Starting server ...');
return server.start(outputFolder, port);
})
.then(function() {
console.log('Serving book on http://localhost:'+port);
if (lrPath) {
// trigger livereload
lrServer.changed({
body: {
files: [lrPath]
}
});
}
})
.then(function() {
if (!kwargs.watch) return;
return watch(book.getRoot())
.then(function(filepath) {
// set livereload path
lrPath = filepath;
console.log('Restart after change in file', filepath);
console.log('');
return generateBook(args, kwargs);
});
});
}
module.exports = {
name: 'serve [book] [output]',
description: 'serve the book as a website for testing',
options: [
{
name: 'port',
description: 'Port for server to listen on',
defaults: 4000
},
{
name: 'lrport',
description: 'Port for livereload server to listen on',
defaults: 35729
},
{
name: 'watch',
description: 'Enable/disable file watcher',
defaults: true
},
options.log,
options.format
],
exec: function(args, kwargs) {
server = new Server();
lrServer = tinylr({});
return Promise.nfcall(lrServer.listen.bind(lrServer), kwargs.lrport)
.then(function() {
console.log('Live reload server started on port:', kwargs.lrport);
console.log('Press CTRL+C to quit ...');
console.log('');
return generateBook(args, kwargs);
});
}
};
-109
View File
@@ -1,109 +0,0 @@
var events = require('events');
var http = require('http');
var send = require('send');
var util = require('util');
var url = require('url');
var Promise = require('../utils/promise');
function Server() {
this.running = null;
this.dir = null;
this.port = 0;
this.sockets = [];
}
util.inherits(Server, events.EventEmitter);
/**
Return true if the server is running
@return {Boolean}
*/
Server.prototype.isRunning = function() {
return !!this.running;
};
/**
Stop the server
@return {Promise}
*/
Server.prototype.stop = function() {
var that = this;
if (!this.isRunning()) return Promise();
var d = Promise.defer();
this.running.close(function(err) {
that.running = null;
that.emit('state', false);
if (err) d.reject(err);
else d.resolve();
});
for (var i = 0; i < this.sockets.length; i++) {
this.sockets[i].destroy();
}
return d.promise;
};
/**
Start the server
@return {Promise}
*/
Server.prototype.start = function(dir, port) {
var that = this, pre = Promise();
port = port || 8004;
if (that.isRunning()) pre = this.stop();
return pre
.then(function() {
var d = Promise.defer();
that.running = http.createServer(function(req, res){
// Render error
function error(err) {
res.statusCode = err.status || 500;
res.end(err.message);
}
// Redirect to directory's index.html
function redirect() {
res.statusCode = 301;
res.setHeader('Location', req.url + '/');
res.end('Redirecting to ' + req.url + '/');
}
// Send file
send(req, url.parse(req.url).pathname, {
root: dir
})
.on('error', error)
.on('directory', redirect)
.pipe(res);
});
that.running.on('connection', function (socket) {
that.sockets.push(socket);
socket.setTimeout(4000);
socket.on('close', function () {
that.sockets.splice(that.sockets.indexOf(socket), 1);
});
});
that.running.listen(port, function(err) {
if (err) return d.reject(err);
that.port = port;
that.dir = dir;
that.emit('state', true);
d.resolve();
});
return d.promise;
});
};
module.exports = Server;
-46
View File
@@ -1,46 +0,0 @@
var path = require('path');
var chokidar = require('chokidar');
var Promise = require('../utils/promise');
var parsers = require('../parsers');
/**
Watch a folder and resolve promise once a file is modified
@param {String} dir
@return {Promise}
*/
function watch(dir) {
var d = Promise.defer();
dir = path.resolve(dir);
var toWatch = [
'book.json', 'book.js', '_layouts/**'
];
// Watch all parsable files
parsers.extensions.forEach(function(ext) {
toWatch.push('**/*'+ext);
});
var watcher = chokidar.watch(toWatch, {
cwd: dir,
ignored: '_book/**',
ignoreInitial: true
});
watcher.once('all', function(e, filepath) {
watcher.close();
d.resolve(filepath);
});
watcher.once('error', function(err) {
watcher.close();
d.reject(err);
});
return d.promise;
}
module.exports = watch;
-6
View File
@@ -1,6 +0,0 @@
var Immutable = require('immutable');
var jsonSchemaDefaults = require('json-schema-defaults');
var schema = require('./configSchema');
module.exports = Immutable.fromJS(jsonSchemaDefaults(schema));
-51
View File
@@ -1,51 +0,0 @@
var Immutable = require('immutable');
var TemplateBlock = require('../models/templateBlock');
module.exports = Immutable.Map({
html: TemplateBlock({
name: 'html',
process: function(blk) {
return blk;
}
}),
code: TemplateBlock({
name: 'code',
process: function(blk) {
return {
html: false,
body: blk.body
};
}
}),
markdown: TemplateBlock({
name: 'markdown',
process: function(blk) {
return this.book.renderInline('markdown', blk.body)
.then(function(out) {
return { body: out };
});
}
}),
asciidoc: TemplateBlock({
name: 'asciidoc',
process: function(blk) {
return this.book.renderInline('asciidoc', blk.body)
.then(function(out) {
return { body: out };
});
}
}),
markup: TemplateBlock({
name: 'markup',
process: function(blk) {
return this.book.renderInline(this.ctx.file.type, blk.body)
.then(function(out) {
return { body: out };
});
}
})
});
-14
View File
@@ -1,14 +0,0 @@
var Immutable = require('immutable');
/*
List of default plugins for all books,
default plugins should be installed in node dependencies of GitBook
*/
module.exports = Immutable.List([
'highlight',
'search',
'lunr',
'sharing',
'fontsettings',
'theme-default'
]);
-10
View File
@@ -1,10 +0,0 @@
var extend = require('extend');
var common = require('./browser');
module.exports = extend({
initBook: require('./init'),
createNodeFS: require('./fs/node'),
Output: require('./output'),
commands: require('./cli')
}, common);
-80
View File
@@ -1,80 +0,0 @@
var path = require('path');
var createNodeFS = require('./fs/node');
var fs = require('./utils/fs');
var Promise = require('./utils/promise');
var File = require('./models/file');
var Readme = require('./models/readme');
var Book = require('./models/book');
var Parse = require('./parse');
/**
Initialize folder structure for a book
Read SUMMARY to created the right chapter
@param {Book}
@param {String}
@return {Promise}
*/
function initBook(rootFolder) {
var extension = '.md';
return fs.mkdirp(rootFolder)
// Parse the summary and readme
.then(function() {
var fs = createNodeFS(rootFolder);
var book = Book.createForFS(fs);
return Parse.parseReadme(book)
// Setup default readme if doesn't found one
.fail(function() {
var readmeFile = File.createWithFilepath('README' + extension);
var readme = Readme.create(readmeFile);
return book.setReadme(readme);
});
})
.then(Parse.parseSummary)
.then(function(book) {
var logger = book.getLogger();
var summary = book.getSummary();
var summaryFile = summary.getFile();
var summaryFilename = summaryFile.getPath() || ('SUMMARY' + extension);
var articles = summary.getArticlesAsList();
// Write pages
return Promise.forEach(articles, function(article) {
var filePath = path.join(rootFolder, article.getPath());
if (!filePath) return;
return fs.assertFile(filePath, function() {
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create', article.getPath());
return fs.writeFile(filePath, '# ' + article.getTitle() + '\n\n');
});
});
})
// Write summary
.then(function() {
var filePath = path.join(rootFolder, summaryFilename);
return fs.ensureFile(filePath)
.then(function() {
logger.info.ln('create ' + path.basename(filePath));
return fs.writeFile(filePath, summary.toText(extension));
});
})
// Log end
.then(function() {
logger.info.ln('initialization is finished');
});
});
}
module.exports = initBook;
-35
View File
@@ -1,35 +0,0 @@
var extend = require('extend');
var gitbook = require('../gitbook');
var encodeSummary = require('./encodeSummary');
var encodeGlossary = require('./encodeGlossary');
var encodeReadme = require('./encodeReadme');
/**
Encode a book to JSON
@param {Book}
@return {Object}
*/
function encodeBookToJson(book) {
var config = book.getConfig();
var language = book.getLanguage();
var variables = config.getValue('variables', {});
return {
summary: encodeSummary(book.getSummary()),
glossary: encodeGlossary(book.getGlossary()),
readme: encodeReadme(book.getReadme()),
config: book.getConfig().getValues().toJS(),
gitbook: {
version: gitbook.version,
time: gitbook.START_TIME
},
book: extend({
language: language? language : undefined
}, variables.toJS())
};
}
module.exports = encodeBookToJson;
-22
View File
@@ -1,22 +0,0 @@
var encodeBook = require('./encodeBook');
var encodePage = require('./encodePage');
var encodeFile = require('./encodeFile');
/**
Return a JSON representation of a book with a specific file
@param {Book} output
@param {Page} page
@return {Object}
*/
function encodeBookWithPage(book, page) {
var file = page.getFile();
var result = encodeBook(book);
result.page = encodePage(page, book.getSummary());
result.file = encodeFile(file);
return result;
}
module.exports = encodeBookWithPage;
-21
View File
@@ -1,21 +0,0 @@
/**
Return a JSON representation of a file
@param {File} file
@return {Object}
*/
function encodeFileToJson(file) {
var filePath = file.getPath();
if (!filePath) {
return undefined;
}
return {
path: filePath,
mtime: file.getMTime(),
type: file.getType()
};
}
module.exports = encodeFileToJson;
-21
View File
@@ -1,21 +0,0 @@
var encodeFile = require('./encodeFile');
var encodeGlossaryEntry = require('./encodeGlossaryEntry');
/**
Encode a glossary to JSON
@param {Glossary}
@return {Object}
*/
function encodeGlossary(glossary) {
var file = glossary.getFile();
var entries = glossary.getEntries();
return {
file: encodeFile(file),
entries: entries
.map(encodeGlossaryEntry).toJS()
};
}
module.exports = encodeGlossary;
-25
View File
@@ -1,25 +0,0 @@
var encodeBook = require('./encodeBook');
/**
Encode an output to JSON
@param {Output}
@return {Object}
*/
function encodeOutputToJson(output) {
var book = output.getBook();
var generator = output.getGenerator();
var options = output.getOptions();
var result = encodeBook(book);
result.output = {
name: generator
};
result.options = options.toJS();
return result;
}
module.exports = encodeOutputToJson;
-39
View File
@@ -1,39 +0,0 @@
var encodeSummaryArticle = require('./encodeSummaryArticle');
/**
Return a JSON representation of a page
@param {Page} page
@param {Summary} summary
@return {Object}
*/
function encodePage(page, summary) {
var file = page.getFile();
var attributes = page.getAttributes();
var article = summary.getByPath(file.getPath());
var result = attributes.toJS();
if (article) {
result.title = article.getTitle();
result.level = article.getLevel();
result.depth = article.getDepth();
var nextArticle = summary.getNextArticle(article);
if (nextArticle) {
result.next = encodeSummaryArticle(nextArticle);
}
var prevArticle = summary.getPrevArticle(article);
if (prevArticle) {
result.previous = encodeSummaryArticle(prevArticle);
}
}
result.content = page.getContent();
result.dir = page.getDir();
return result;
}
module.exports = encodePage;
-17
View File
@@ -1,17 +0,0 @@
var encodeFile = require('./encodeFile');
/**
Encode a readme to JSON
@param {Readme}
@return {Object}
*/
function encodeReadme(readme) {
var file = readme.getFile();
return {
file: encodeFile(file)
};
}
module.exports = encodeReadme;
-20
View File
@@ -1,20 +0,0 @@
var encodeFile = require('./encodeFile');
var encodeSummaryPart = require('./encodeSummaryPart');
/**
Encode a summary to JSON
@param {Summary}
@return {Object}
*/
function encodeSummary(summary) {
var file = summary.getFile();
var parts = summary.getParts();
return {
file: encodeFile(file),
parts: parts.map(encodeSummaryPart).toJS()
};
}
module.exports = encodeSummary;
-27
View File
@@ -1,27 +0,0 @@
/**
Encode a SummaryArticle to JSON
@param {SummaryArticle}
@return {Object}
*/
function encodeSummaryArticle(article, recursive) {
var articles = undefined;
if (recursive !== false) {
articles = article.getArticles()
.map(encodeSummaryArticle)
.toJS();
}
return {
title: article.getTitle(),
level: article.getLevel(),
depth: article.getDepth(),
anchor: article.getAnchor(),
url: article.getUrl(),
path: article.getPath(),
articles: articles
};
}
module.exports = encodeSummaryArticle;
-17
View File
@@ -1,17 +0,0 @@
var encodeSummaryArticle = require('./encodeSummaryArticle');
/**
Encode a SummaryPart to JSON
@param {SummaryPart}
@return {Object}
*/
function encodeSummaryPart(part) {
return {
title: part.getTitle(),
articles: part.getArticles()
.map(encodeSummaryArticle).toJS()
};
}
module.exports = encodeSummaryPart;
-11
View File
@@ -1,11 +0,0 @@
module.exports = {
encodeOutput: require('./encodeOutput'),
encodeBookWithPage: require('./encodeBookWithPage'),
encodeBook: require('./encodeBook'),
encodeFile: require('./encodeFile'),
encodePage: require('./encodePage'),
encodeSummary: require('./encodeSummary'),
encodeSummaryArticle: require('./encodeSummaryArticle'),
encodeReadme: require('./encodeReadme')
};
-63
View File
@@ -1,63 +0,0 @@
jest.autoMockOff();
var Immutable = require('immutable');
describe('Config', function() {
var Config = require('../config');
var config = Config.createWithValues({
hello: {
world: 1,
test: 'Hello',
isFalse: false
}
});
describe('getValue', function() {
it('must return value as immutable', function() {
var value = config.getValue('hello');
expect(Immutable.Map.isMap(value)).toBeTruthy();
});
it('must return deep value', function() {
var value = config.getValue('hello.world');
expect(value).toBe(1);
});
it('must return default value if non existant', function() {
var value = config.getValue('hello.nonExistant', 'defaultValue');
expect(value).toBe('defaultValue');
});
it('must not return default value for falsy values', function() {
var value = config.getValue('hello.isFalse', 'defaultValue');
expect(value).toBe(false);
});
});
describe('setValue', function() {
it('must set value as immutable', function() {
var testConfig = config.setValue('hello', {
'cool': 1
});
var value = testConfig.getValue('hello');
expect(Immutable.Map.isMap(value)).toBeTruthy();
expect(value.size).toBe(1);
expect(value.has('cool')).toBeTruthy();
});
it('must set deep value', function() {
var testConfig = config.setValue('hello.world', 2);
var hello = testConfig.getValue('hello');
var world = testConfig.getValue('hello.world');
expect(Immutable.Map.isMap(hello)).toBeTruthy();
expect(hello.size).toBe(3);
expect(world).toBe(2);
});
});
});
-42
View File
@@ -1,42 +0,0 @@
jest.autoMockOff();
describe('Glossary', function() {
var File = require('../file');
var Glossary = require('../glossary');
var GlossaryEntry = require('../glossaryEntry');
var glossary = Glossary.createFromEntries(File(), [
{
name: 'Hello World',
description: 'Awesome!'
},
{
name: 'JavaScript',
description: 'This is a cool language'
}
]);
describe('createFromEntries', function() {
it('must add all entries', function() {
var entries = glossary.getEntries();
expect(entries.size).toBe(2);
});
it('must add entries as GlossaryEntries', function() {
var entries = glossary.getEntries();
var entry = entries.get('hello-world');
expect(entry instanceof GlossaryEntry).toBeTruthy();
});
});
describe('toText', function() {
pit('return as markdown', function() {
return glossary.toText('.md')
.then(function(text) {
expect(text).toContain('# Glossary');
});
});
});
});
-17
View File
@@ -1,17 +0,0 @@
jest.autoMockOff();
describe('GlossaryEntry', function() {
var GlossaryEntry = require('../glossaryEntry');
describe('getID', function() {
it('must return a normalized ID', function() {
var entry = new GlossaryEntry({
name: 'Hello World'
});
expect(entry.getID()).toBe('hello-world');
});
});
});
-27
View File
@@ -1,27 +0,0 @@
describe('Plugin', function() {
var Plugin = require('../plugin');
describe('createFromString', function() {
it('must parse name', function() {
var plugin = Plugin.createFromString('hello');
expect(plugin.getName()).toBe('hello');
expect(plugin.getVersion()).toBe('*');
});
it('must parse version', function() {
var plugin = Plugin.createFromString('hello@1.0.0');
expect(plugin.getName()).toBe('hello');
expect(plugin.getVersion()).toBe('1.0.0');
});
});
describe('isLoaded', function() {
it('must return false for empty plugin', function() {
var plugin = Plugin.createFromString('hello');
expect(plugin.isLoaded()).toBe(false);
});
});
});
-47
View File
@@ -1,47 +0,0 @@
describe('PluginDependency', function() {
var PluginDependency = require('../pluginDependency');
describe('createFromString', function() {
it('must parse name', function() {
var plugin = PluginDependency.createFromString('hello');
expect(plugin.getName()).toBe('hello');
expect(plugin.getVersion()).toBe('*');
});
it('must parse state', function() {
var plugin = PluginDependency.createFromString('-hello');
expect(plugin.getName()).toBe('hello');
expect(plugin.isEnabled()).toBe(false);
});
describe('Version', function() {
it('must parse version', function() {
var plugin = PluginDependency.createFromString('hello@1.0.0');
expect(plugin.getName()).toBe('hello');
expect(plugin.getVersion()).toBe('1.0.0');
});
it('must parse semver', function() {
var plugin = PluginDependency.createFromString('hello@>=4.0.0');
expect(plugin.getName()).toBe('hello');
expect(plugin.getVersion()).toBe('>=4.0.0');
});
});
describe('GIT Version', function() {
it('must handle HTTPS urls', function() {
var plugin = PluginDependency.createFromString('hello@git+https://github.com/GitbookIO/plugin-ga.git');
expect(plugin.getName()).toBe('hello');
expect(plugin.getVersion()).toBe('git+https://github.com/GitbookIO/plugin-ga.git');
});
it('must handle SSH urls', function() {
var plugin = PluginDependency.createFromString('hello@git+ssh://samy@github.com/GitbookIO/plugin-ga.git');
expect(plugin.getName()).toBe('hello');
expect(plugin.getVersion()).toBe('git+ssh://samy@github.com/GitbookIO/plugin-ga.git');
});
});
});
});
-81
View File
@@ -1,81 +0,0 @@
describe('Summary', function() {
var File = require('../file');
var Summary = require('../summary');
var summary = Summary.createFromParts(File(), [
{
articles: [
{
title: 'My First Article',
path: 'README.md'
},
{
title: 'My Second Article',
path: 'article.md'
}
]
},
{
title: 'Test'
}
]);
describe('createFromEntries', function() {
it('must add all parts', function() {
var parts = summary.getParts();
expect(parts.size).toBe(2);
});
});
describe('getByLevel', function() {
it('can return a Part', function() {
var part = summary.getByLevel('1');
expect(part).toBeDefined();
expect(part.getArticles().size).toBe(2);
});
it('can return a Part (2)', function() {
var part = summary.getByLevel('2');
expect(part).toBeDefined();
expect(part.getTitle()).toBe('Test');
expect(part.getArticles().size).toBe(0);
});
it('can return an Article', function() {
var article = summary.getByLevel('1.1');
expect(article).toBeDefined();
expect(article.getTitle()).toBe('My First Article');
});
});
describe('getByPath', function() {
it('return correct article', function() {
var article = summary.getByPath('README.md');
expect(article).toBeDefined();
expect(article.getTitle()).toBe('My First Article');
});
it('return correct article', function() {
var article = summary.getByPath('article.md');
expect(article).toBeDefined();
expect(article.getTitle()).toBe('My Second Article');
});
});
describe('toText', function() {
pit('return as markdown', function() {
return summary.toText('.md')
.then(function(text) {
expect(text).toContain('# Summary');
});
});
});
});
-129
View File
@@ -1,129 +0,0 @@
var nunjucks = require('nunjucks');
var Immutable = require('immutable');
var Promise = require('../../utils/promise');
describe('TemplateBlock', function() {
var TemplateBlock = require('../templateBlock');
describe('create', function() {
pit('must initialize a simple TemplateBlock from a function', function() {
var templateBlock = TemplateBlock.create('sayhello', function(block) {
return '<p>Hello, World!</p>';
});
// Check basic templateBlock properties
expect(templateBlock.getName()).toBe('sayhello');
expect(templateBlock.getPost()).toBeNull();
expect(templateBlock.getParse()).toBeTruthy();
expect(templateBlock.getEndTag()).toBe('endsayhello');
expect(templateBlock.getBlocks().size).toBe(0);
expect(templateBlock.getShortcuts().size).toBe(0);
expect(templateBlock.getExtensionName()).toBe('BlocksayhelloExtension');
// 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>');
});
});
});
describe('toNunjucksExt()', function() {
pit('must create a valid nunjucks extension', function() {
var templateBlock = TemplateBlock.create('sayhello', function(block) {
return '<p>Hello, World!</p>';
});
// Create a fresh Nunjucks environment
var env = new nunjucks.Environment(null, { autoescape: false });
// Add template block to environement
var Ext = templateBlock.toNunjucksExt();
env.addExtension(templateBlock.getExtensionName(), new Ext());
// Render a template using the block
var src = '{% sayhello %}{% endsayhello %}';
return Promise.nfcall(env.renderString.bind(env), src)
.then(function(res) {
expect(res).toBe('<p>Hello, World!</p>');
});
});
pit('must apply block arguments correctly', function() {
var templateBlock = TemplateBlock.create('sayhello', function(block) {
return '<'+block.kwargs.tag+'>Hello, '+block.kwargs.name+'!</'+block.kwargs.tag+'>';
});
// Create a fresh Nunjucks environment
var env = new nunjucks.Environment(null, { autoescape: false });
// Add template block to environement
var Ext = templateBlock.toNunjucksExt();
env.addExtension(templateBlock.getExtensionName(), new Ext());
// Render a template using the block
var 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>');
});
});
pit('must accept an async function', function() {
var templateBlock = TemplateBlock.create('sayhello', function(block) {
return Promise()
.then(function() {
return 'Hello ' + block.body;
});
});
// Create a fresh Nunjucks environment
var env = new nunjucks.Environment(null, { autoescape: false });
// Add template block to environement
var Ext = templateBlock.toNunjucksExt();
env.addExtension(templateBlock.getExtensionName(), new Ext());
// Render a template using the block
var src = '{% sayhello %}Samy{% endsayhello %}';
return Promise.nfcall(env.renderString.bind(env), src)
.then(function(res) {
expect(res).toBe('Hello Samy');
});
});
pit('must handle nested blocks', function() {
var templateBlock = new TemplateBlock({
name: 'yoda',
blocks: Immutable.List(['start', 'end']),
process: function(block) {
var nested = {};
block.blocks.forEach(function(blk) {
nested[blk.name] = blk.body.trim();
});
return '<p class="yoda">'+nested.end+' '+nested.start+'</p>';
}
});
// Create a fresh Nunjucks environment
var env = new nunjucks.Environment(null, { autoescape: false });
// Add template block to environement
var Ext = templateBlock.toNunjucksExt();
env.addExtension(templateBlock.getExtensionName(), new Ext());
// Render a template using the block
var 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>');
});
});
});
});
-51
View File
@@ -1,51 +0,0 @@
describe('TemplateBlock', function() {
var TemplateEngine = require('../templateEngine');
describe('create', function() {
it('must initialize with a list of filters', function() {
var engine = TemplateEngine.create({
filters: {
hello: function(name) {
return 'Hello ' + name + '!';
}
}
});
var env = engine.toNunjucks();
var res = env.renderString('{{ "Luke"|hello }}');
expect(res).toBe('Hello Luke!');
});
it('must initialize with a list of globals', function() {
var engine = TemplateEngine.create({
globals: {
hello: function(name) {
return 'Hello ' + name + '!';
}
}
});
var env = engine.toNunjucks();
var res = env.renderString('{{ hello("Luke") }}');
expect(res).toBe('Hello Luke!');
});
it('must pass context to filters and blocks', function() {
var engine = TemplateEngine.create({
filters: {
hello: function(name) {
return 'Hello ' + name + ' ' + this.lastName + '!';
}
},
context: {
lastName: 'Skywalker'
}
});
var env = engine.toNunjucks();
var res = env.renderString('{{ "Luke"|hello }}');
expect(res).toBe('Hello Luke Skywalker!');
});
});
});
-320
View File
@@ -1,320 +0,0 @@
var path = require('path');
var Immutable = require('immutable');
var Ignore = require('ignore');
var Logger = require('../utils/logger');
var FS = require('./fs');
var Config = require('./config');
var Readme = require('./readme');
var Summary = require('./summary');
var Glossary = require('./glossary');
var Languages = require('./languages');
var Book = Immutable.Record({
// Logger for outptu message
logger: Logger(),
// Filesystem binded to the book scope to read files/directories
fs: FS(),
// Ignore files parser
ignore: Ignore(),
// Structure files
config: Config(),
readme: Readme(),
summary: Summary(),
glossary: Glossary(),
languages: Languages(),
// ID of the language for language books
language: String(),
// List of children, if multilingual (String -> Book)
books: Immutable.OrderedMap()
});
Book.prototype.getLogger = function() {
return this.get('logger');
};
Book.prototype.getFS = function() {
return this.get('fs');
};
Book.prototype.getIgnore = function() {
return this.get('ignore');
};
Book.prototype.getConfig = function() {
return this.get('config');
};
Book.prototype.getReadme = function() {
return this.get('readme');
};
Book.prototype.getSummary = function() {
return this.get('summary');
};
Book.prototype.getGlossary = function() {
return this.get('glossary');
};
Book.prototype.getLanguages = function() {
return this.get('languages');
};
Book.prototype.getBooks = function() {
return this.get('books');
};
Book.prototype.getLanguage = function() {
return this.get('language');
};
/**
Return FS instance to access the content
@return {FS}
*/
Book.prototype.getContentFS = function() {
var fs = this.getFS();
var config = this.getConfig();
var rootFolder = config.getValue('root');
if (rootFolder) {
return FS.reduceScope(fs, rootFolder);
}
return fs;
};
/**
Return root of the book
@return {String}
*/
Book.prototype.getRoot = function() {
var fs = this.getFS();
return fs.getRoot();
};
/**
Return root for content of the book
@return {String}
*/
Book.prototype.getContentRoot = function() {
var fs = this.getContentFS();
return fs.getRoot();
};
/**
Check if a file is ignore (should not being parsed, etc)
@param {String} ref
@return {Page|undefined}
*/
Book.prototype.isFileIgnored = function(filename) {
var ignore = this.getIgnore();
var language = this.getLanguage();
// Ignore is always relative to the root of the main book
if (language) {
filename = path.join(language, filename);
}
return ignore.filter([filename]).length == 0;
};
/**
Check if a content file is ignore (should not being parsed, etc)
@param {String} ref
@return {Page|undefined}
*/
Book.prototype.isContentFileIgnored = function(filename) {
var config = this.getConfig();
var rootFolder = config.getValue('root');
if (rootFolder) {
filename = path.join(rootFolder, filename);
}
return this.isFileIgnored(filename);
};
/**
Return a page from a book by its path
@param {String} ref
@return {Page|undefined}
*/
Book.prototype.getPage = function(ref) {
return this.getPages().get(ref);
};
/**
Is this book the parent of language's books
@return {Boolean}
*/
Book.prototype.isMultilingual = function() {
return (this.getLanguages().getCount() > 0);
};
/**
Return true if book is associated to a language
@return {Boolean}
*/
Book.prototype.isLanguageBook = function() {
return Boolean(this.getLanguage());
};
/**
Add a new language book
@param {String} language
@param {Book} book
@return {Book}
*/
Book.prototype.addLanguageBook = function(language, book) {
var books = this.getBooks();
books = books.set(language, book);
return this.set('books', books);
};
/**
Set the summary for this book
@param {Summary}
@return {Book}
*/
Book.prototype.setSummary = function(summary) {
return this.set('summary', summary);
};
/**
Set the readme for this book
@param {Readme}
@return {Book}
*/
Book.prototype.setReadme = function(readme) {
return this.set('readme', readme);
};
/**
Set the configuration for this book
@param {Config}
@return {Book}
*/
Book.prototype.setConfig = function(config) {
return this.set('config', config);
};
/**
Change log level
@param {String} level
@return {Book}
*/
Book.prototype.setLogLevel = function(level) {
this.getLogger().setLevel(level);
return this;
};
/**
Create a book using a filesystem
@param {FS} fs
@return {Book}
*/
Book.createForFS = function createForFS(fs) {
return new Book({
fs: fs
});
};
/**
Infers the default extension for files
@return {String}
*/
Book.prototype.getDefaultExt = function() {
// Inferring sources
var clues = [
this.getReadme(),
this.getSummary(),
this.getGlossary()
];
// List their extensions
var exts = clues.map(function (clue) {
var file = clue.getFile();
if (file.exists()) {
return file.getParser().getExtensions().first();
} else {
return null;
}
});
// Adds the general default extension
exts.push('.md');
// Choose the first non null
return exts.find(function (e) { return e !== null; });
};
/**
Infer the default path for a Readme.
@return {String}
*/
Book.prototype.getDefaultReadmePath = function() {
return this.getContentRoot()+'README'+this.getDefaultExt();
};
/**
Infer the default path for a Summary.
@return {String}
*/
Book.prototype.getDefaultSummaryPath = function() {
return this.getContentRoot()+'SUMMARY'+this.getDefaultExt();
};
/**
Infer the default path for a Glossary.
@return {String}
*/
Book.prototype.getDefaultGlossaryPath = function() {
return this.getContentRoot()+'GLOSSARY'+this.getDefaultExt();
};
/**
Create a language book from a parent
@param {Book} parent
@param {String} language
@return {Book}
*/
Book.createFromParent = function createFromParent(parent, language) {
var ignore = parent.getIgnore();
return new Book({
// Inherits config. logegr and list of ignored files
logger: parent.getLogger(),
config: parent.getConfig(),
ignore: Ignore().add(ignore),
language: language,
fs: FS.reduceScope(parent.getContentFS(), language)
});
};
module.exports = Book;
-134
View File
@@ -1,134 +0,0 @@
var is = require('is');
var Immutable = require('immutable');
var File = require('./file');
var PluginDependency = require('./pluginDependency');
var configDefault = require('../constants/configDefault');
var Config = Immutable.Record({
file: File(),
values: configDefault
}, 'Config');
Config.prototype.getFile = function() {
return this.get('file');
};
Config.prototype.getValues = function() {
return this.get('values');
};
/**
Return a configuration value by its key path
@param {String} key
@return {Mixed}
*/
Config.prototype.getValue = function(keyPath, def) {
var values = this.getValues();
keyPath = Config.keyToKeyPath(keyPath);
if (!values.hasIn(keyPath)) {
return Immutable.fromJS(def);
}
return values.getIn(keyPath);
};
/**
Update a configuration value
@param {String} key
@param {Mixed} value
@return {Mixed}
*/
Config.prototype.setValue = function(keyPath, value) {
keyPath = Config.keyToKeyPath(keyPath);
value = Immutable.fromJS(value);
var values = this.getValues();
values = values.setIn(keyPath, value);
return this.set('values', values);
};
/**
Return a list of plugin dependencies
@return {List<PluginDependency>}
*/
Config.prototype.getPluginDependencies = function() {
var plugins = this.getValue('plugins');
if (is.string(plugins)) {
return PluginDependency.listFromString(plugins);
} else {
return PluginDependency.listFromArray(plugins);
}
};
/**
Update the list of plugins dependencies
@param {List<PluginDependency>}
@return {Config}
*/
Config.prototype.setPluginDependencies = function(deps) {
var plugins = PluginDependency.listFromArray(deps);
return this.setValue('plugins', plugins);
};
/**
Create a new config for a file
@param {File} file
@param {Object} values
@returns {Config}
*/
Config.create = function(file, values) {
return new Config({
file: file,
values: Immutable.fromJS(values)
});
};
/**
Create a new config
@param {Object} values
@returns {Config}
*/
Config.createWithValues = function(values) {
return new Config({
values: Immutable.fromJS(values)
});
};
/**
Update values for an existing configuration
@param {Config} config
@param {Object} values
@returns {Config}
*/
Config.updateValues = function(config, values) {
values = Immutable.fromJS(values);
return config.set('values', values);
};
/**
Convert a keyPath to an array of keys
@param {String|Array}
@return {Array}
*/
Config.keyToKeyPath = function(keyPath) {
if (is.string(keyPath)) keyPath = keyPath.split('.');
return keyPath;
};
module.exports = Config;
-89
View File
@@ -1,89 +0,0 @@
var path = require('path');
var Immutable = require('immutable');
var parsers = require('../parsers');
var File = Immutable.Record({
// Path of the file, relative to the FS
path: String(),
// Time when file data last modified
mtime: Date()
});
File.prototype.getPath = function() {
return this.get('path');
};
File.prototype.getMTime = function() {
return this.get('mtime');
};
/**
Does the file exists / is set
@return {Boolean}
*/
File.prototype.exists = function() {
return Boolean(this.getPath());
};
/**
Return type of file ('markdown' or 'asciidoc')
@return {String}
*/
File.prototype.getType = function() {
var parser = this.getParser();
if (parser) {
return parser.getName();
} else {
return undefined;
}
};
/**
Return extension of this file (lowercased)
@return {String}
*/
File.prototype.getExtension = function() {
return path.extname(this.getPath()).toLowerCase();
};
/**
Return parser for this file
@return {Parser}
*/
File.prototype.getParser = function() {
return parsers.getByExt(this.getExtension());
};
/**
Create a file from stats informations
@param {String} filepath
@param {Object|fs.Stats} stat
@return {File}
*/
File.createFromStat = function createFromStat(filepath, stat) {
return new File({
path: filepath,
mtime: stat.mtime
});
};
/**
Create a file with only a path
@param {String} filepath
@return {File}
*/
File.createWithFilepath = function createWithFilepath(filepath) {
return new File({
path: filepath
});
};
module.exports = File;
-274
View File
@@ -1,274 +0,0 @@
var path = require('path');
var Immutable = require('immutable');
var File = require('./file');
var Promise = require('../utils/promise');
var error = require('../utils/error');
var PathUtil = require('../utils/path');
var FS = Immutable.Record({
root: String(),
fsExists: Function(),
fsReadFile: Function(),
fsStatFile: Function(),
fsReadDir: Function(),
fsLoadObject: null
});
/**
Return path to the root
@return {String}
*/
FS.prototype.getRoot = function() {
return this.get('root');
};
/**
Verify that a file is in the fs scope
@param {String} filename
@return {Boolean}
*/
FS.prototype.isInScope = function(filename) {
var rootPath = this.getRoot();
filename = path.join(rootPath, filename);
return PathUtil.isInRoot(rootPath, filename);
};
/**
Resolve a file in this FS
@param {String}
@return {String}
*/
FS.prototype.resolve = function() {
var rootPath = this.getRoot();
var args = Array.prototype.slice.call(arguments);
var filename = path.join.apply(path, [rootPath].concat(args));
filename = path.normalize(filename);
if (!this.isInScope(filename)) {
throw error.FileOutOfScopeError({
filename: filename,
root: this.root
});
}
return filename;
};
/**
Check if a file exists, run a Promise(true) if that's the case, Promise(false) otherwise
@param {String} filename
@return {Promise<Boolean>}
*/
FS.prototype.exists = function(filename) {
var that = this;
return Promise()
.then(function() {
filename = that.resolve(filename);
var exists = that.get('fsExists');
return exists(filename);
});
};
/**
Read a file and returns a promise with the content as a buffer
@param {String} filename
@return {Promise<Buffer>}
*/
FS.prototype.read = function(filename) {
var that = this;
return Promise()
.then(function() {
filename = that.resolve(filename);
var read = that.get('fsReadFile');
return read(filename);
});
};
/**
Read a file as a string (utf-8)
@param {String} filename
@return {Promise<String>}
*/
FS.prototype.readAsString = function(filename, encoding) {
encoding = encoding || 'utf8';
return this.read(filename)
.then(function(buf) {
return buf.toString(encoding);
});
};
/**
Read stat infos about a file
@param {String} filename
@return {Promise<File>}
*/
FS.prototype.statFile = function(filename) {
var that = this;
return Promise()
.then(function() {
var filepath = that.resolve(filename);
var stat = that.get('fsStatFile');
return stat(filepath);
})
.then(function(stat) {
return File.createFromStat(filename, stat);
});
};
/**
List files/directories in a directory.
Directories ends with '/'
@param {String} dirname
@return {Promise<List<String>>}
*/
FS.prototype.readDir = function(dirname) {
var that = this;
return Promise()
.then(function() {
var dirpath = that.resolve(dirname);
var readDir = that.get('fsReadDir');
return readDir(dirpath);
})
.then(function(files) {
return Immutable.List(files);
});
};
/**
List only files in a diretcory
Directories ends with '/'
@param {String} dirname
@return {Promise<List<String>>}
*/
FS.prototype.listFiles = function(dirname) {
return this.readDir(dirname)
.then(function(files) {
return files.filterNot(pathIsFolder);
});
};
/**
List all files in a directory
@param {String} dirname
@return {Promise<List<String>>}
*/
FS.prototype.listAllFiles = function(folder) {
var that = this;
folder = folder || '.';
return this.readDir(folder)
.then(function(files) {
return Promise.reduce(files, function(out, file) {
var isDirectory = pathIsFolder(file);
if (!isDirectory) {
return out.push(path.join(folder, file));
}
return that.listAllFiles(path.join(folder, file))
.then(function(inner) {
return out.concat(inner);
});
}, Immutable.List());
});
};
/**
Find a file in a folder (case incensitive)
Return the found filename
@param {String} dirname
@param {String} filename
@return {Promise<String>}
*/
FS.prototype.findFile = function(dirname, filename) {
return this.listFiles(dirname)
.then(function(files) {
return files.find(function(file) {
return (file.toLowerCase() == filename.toLowerCase());
});
});
};
/**
Load a JSON file
By default, fs only supports JSON
@param {String} filename
@return {Promise<Object>}
*/
FS.prototype.loadAsObject = function(filename) {
var that = this;
var fsLoadObject = this.get('fsLoadObject');
return this.exists(filename)
.then(function(exists) {
if (!exists) {
var err = new Error('Module doesn\'t exist');
err.code = 'MODULE_NOT_FOUND';
throw err;
}
if (fsLoadObject) {
return fsLoadObject(that.resolve(filename));
} else {
return that.readAsString(filename)
.then(function(str) {
return JSON.parse(str);
});
}
});
};
/**
Create a FS instance
@param {Object} def
@return {FS}
*/
FS.create = function create(def) {
return new FS(def);
};
/**
Create a new FS instance with a reduced scope
@param {FS} fs
@param {String} scope
@return {FS}
*/
FS.reduceScope = function reduceScope(fs, scope) {
return fs.set('root', path.join(fs.getRoot(), scope));
};
// .readdir return files/folder as a list of string, folder ending with '/'
function pathIsFolder(filename) {
var lastChar = filename[filename.length - 1];
return lastChar == '/' || lastChar == '\\';
}
module.exports = FS;
-109
View File
@@ -1,109 +0,0 @@
var Immutable = require('immutable');
var error = require('../utils/error');
var File = require('./file');
var GlossaryEntry = require('./glossaryEntry');
var parsers = require('../parsers');
var Glossary = Immutable.Record({
file: File(),
entries: Immutable.OrderedMap()
});
Glossary.prototype.getFile = function() {
return this.get('file');
};
Glossary.prototype.getEntries = function() {
return this.get('entries');
};
/**
Return an entry by its name
@param {String} name
@return {GlossaryEntry}
*/
Glossary.prototype.getEntry = function(name) {
var entries = this.getEntries();
var id = GlossaryEntry.nameToID(name);
return entries.get(id);
};
/**
Render glossary as text
@return {Promise<String>}
*/
Glossary.prototype.toText = function(parser) {
var file = this.getFile();
var entries = this.getEntries();
parser = parser? parsers.getByExt(parser) : file.getParser();
if (!parser) {
throw error.FileNotParsableError({
filename: file.getPath()
});
}
return parser.renderGlossary(entries.toJS());
};
/**
Add/Replace an entry to a glossary
@param {Glossary} glossary
@param {GlossaryEntry} entry
@return {Glossary}
*/
Glossary.addEntry = function addEntry(glossary, entry) {
var id = entry.getID();
var entries = glossary.getEntries();
entries = entries.set(id, entry);
return glossary.set('entries', entries);
};
/**
Add/Replace an entry to a glossary by name/description
@param {Glossary} glossary
@param {GlossaryEntry} entry
@return {Glossary}
*/
Glossary.addEntryByName = function addEntryByName(glossary, name, description) {
var entry = new GlossaryEntry({
name: name,
description: description
});
return Glossary.addEntry(glossary, entry);
};
/**
Create a glossary from a list of entries
@param {String} filename
@param {Array|List} entries
@return {Glossary}
*/
Glossary.createFromEntries = function createFromEntries(file, entries) {
entries = entries.map(function(entry) {
if (!(entry instanceof GlossaryEntry)) {
entry = new GlossaryEntry(entry);
}
return [entry.getID(), entry];
});
return new Glossary({
file: file,
entries: Immutable.OrderedMap(entries)
});
};
module.exports = Glossary;
-43
View File
@@ -1,43 +0,0 @@
var Immutable = require('immutable');
var slug = require('github-slugid');
/*
A definition represents an entry in the glossary
*/
var GlossaryEntry = Immutable.Record({
name: String(),
description: String()
});
GlossaryEntry.prototype.getName = function() {
return this.get('name');
};
GlossaryEntry.prototype.getDescription = function() {
return this.get('description');
};
/**
Get identifier for this entry
@retrun {Boolean}
*/
GlossaryEntry.prototype.getID = function() {
return GlossaryEntry.nameToID(this.getName());
};
/**
Normalize a glossary entry name into a unique id
@param {String}
@return {String}
*/
GlossaryEntry.nameToID = function nameToID(name) {
return slug(name);
};
module.exports = GlossaryEntry;
-21
View File
@@ -1,21 +0,0 @@
var path = require('path');
var Immutable = require('immutable');
var Language = Immutable.Record({
title: String(),
path: String()
});
Language.prototype.getTitle = function() {
return this.get('title');
};
Language.prototype.getPath = function() {
return this.get('path');
};
Language.prototype.getID = function() {
return path.basename(this.getPath());
};
module.exports = Language;
-71
View File
@@ -1,71 +0,0 @@
var Immutable = require('immutable');
var File = require('./file');
var Language = require('./language');
var Languages = Immutable.Record({
file: File(),
list: Immutable.OrderedMap()
});
Languages.prototype.getFile = function() {
return this.get('file');
};
Languages.prototype.getList = function() {
return this.get('list');
};
/**
Get default languages
@return {Language}
*/
Languages.prototype.getDefaultLanguage = function() {
return this.getList().first();
};
/**
Get a language by its ID
@param {String} lang
@return {Language}
*/
Languages.prototype.getLanguage = function(lang) {
return this.getList().get(lang);
};
/**
Return count of langs
@return {Number}
*/
Languages.prototype.getCount = function() {
return this.getList().size;
};
/**
Create a languages list from a JS object
@param {File}
@param {Array}
@return {Language}
*/
Languages.createFromList = function(file, langs) {
var list = Immutable.OrderedMap();
langs.forEach(function(lang) {
lang = Language({
title: lang.title,
path: lang.ref
});
list = list.set(lang.getID(), lang);
});
return Languages({
file: file,
list: list
});
};
module.exports = Languages;
-93
View File
@@ -1,93 +0,0 @@
var Immutable = require('immutable');
var Book = require('./book');
var Output = Immutable.Record({
book: Book(),
// Name of the generator being used
generator: String(),
// Map of plugins to use (String -> Plugin)
plugins: Immutable.OrderedMap(),
// Map pages to generation (String -> Page)
pages: Immutable.OrderedMap(),
// List assets (String)
assets: Immutable.List(),
// Option for the generation
options: Immutable.Map(),
// Internal state for the generation
state: Immutable.Map()
});
Output.prototype.getBook = function() {
return this.get('book');
};
Output.prototype.getGenerator = function() {
return this.get('generator');
};
Output.prototype.getPlugins = function() {
return this.get('plugins');
};
Output.prototype.getPages = function() {
return this.get('pages');
};
Output.prototype.getOptions = function() {
return this.get('options');
};
Output.prototype.getAssets = function() {
return this.get('assets');
};
Output.prototype.getState = function() {
return this.get('state');
};
/**
Get root folder for output
@return {String}
*/
Output.prototype.getRoot = function() {
return this.getOptions().get('root');
};
/**
Update state of output
@param {Map} newState
@return {Output}
*/
Output.prototype.setState = function(newState) {
return this.set('state', newState);
};
/**
Update options
@param {Map} newOptions
@return {Output}
*/
Output.prototype.setOptions = function(newOptions) {
return this.set('options', newOptions);
};
/**
Return logegr for this output (same as book)
@return {Logger}
*/
Output.prototype.getLogger = function() {
return this.getBook().getLogger();
};
module.exports = Output;
-55
View File
@@ -1,55 +0,0 @@
var Immutable = require('immutable');
var File = require('./file');
var Page = Immutable.Record({
file: File(),
// Attributes extracted from the YAML header
attributes: Immutable.Map(),
// Content of the page
content: String(),
// Direction of the text
dir: String('ltr')
});
Page.prototype.getFile = function() {
return this.get('file');
};
Page.prototype.getAttributes = function() {
return this.get('attributes');
};
Page.prototype.getContent = function() {
return this.get('content');
};
Page.prototype.getDir = function() {
return this.get('dir');
};
/**
Return path of the page
@return {String}
*/
Page.prototype.getPath = function() {
return this.getFile().getPath();
};
/**
Create a page for a file
@param {File} file
@return {Page}
*/
Page.createForFile = function(file) {
return new Page({
file: file
});
};
module.exports = Page;
-117
View File
@@ -1,117 +0,0 @@
var Immutable = require('immutable');
var Promise = require('../utils/promise');
var Parser = Immutable.Record({
name: String(),
// List of extensions that can be processed using this parser
extensions: Immutable.List(),
// Parsing functions
readme: Function(),
langs: Function(),
summary: Function(),
glossary: Function(),
page: Function(),
inline: Function()
});
Parser.prototype.getName = function() {
return this.get('name');
};
Parser.prototype.getExtensions = function() {
return this.get('extensions');
};
// PARSE
Parser.prototype.parseReadme = function(content) {
var readme = this.get('readme');
return Promise(readme(content));
};
Parser.prototype.parseSummary = function(content) {
var summary = this.get('summary');
return Promise(summary(content));
};
Parser.prototype.parseGlossary = function(content) {
var glossary = this.get('glossary');
return Promise(glossary(content));
};
Parser.prototype.preparePage = function(content) {
var page = this.get('page');
if (!page.prepare) {
return Promise(content);
}
return Promise(page.prepare(content));
};
Parser.prototype.parsePage = function(content) {
var page = this.get('page');
return Promise(page(content));
};
Parser.prototype.parseLanguages = function(content) {
var langs = this.get('langs');
return Promise(langs(content));
};
Parser.prototype.parseInline = function(content) {
var inline = this.get('inline');
return Promise(inline(content));
};
// TO TEXT
Parser.prototype.renderLanguages = function(content) {
var langs = this.get('langs');
return Promise(langs.toText(content));
};
Parser.prototype.renderSummary = function(content) {
var summary = this.get('summary');
return Promise(summary.toText(content));
};
Parser.prototype.renderGlossary = function(content) {
var glossary = this.get('glossary');
return Promise(glossary.toText(content));
};
/**
Test if this parser matches an extension
@param {String} ext
@return {Boolean}
*/
Parser.prototype.matchExtension = function(ext) {
var exts = this.getExtensions();
return exts.includes(ext.toLowerCase());
};
/**
Create a new parser using a module (gitbook-markdown, etc)
@param {String} name
@param {Array<String>} extensions
@param {Object} module
@return {Parser}
*/
Parser.create = function(name, extensions, module) {
return new Parser({
name: name,
extensions: Immutable.List(extensions),
readme: module.readme,
langs: module.langs,
summary: module.summary,
glossary: module.glossary,
page: module.page,
inline: module.inline
});
};
module.exports = Parser;
-165
View File
@@ -1,165 +0,0 @@
var Immutable = require('immutable');
var TemplateBlock = require('./templateBlock');
var PREFIX = require('../constants/pluginPrefix');
var DEFAULT_VERSION = '*';
var Plugin = Immutable.Record({
name: String(),
// Requirement version (ex: ">1.0.0")
version: String(DEFAULT_VERSION),
// Path to load this plugin
path: String(),
// Depth of this plugin in the dependency tree
depth: Number(0),
// Content of the "package.json"
package: Immutable.Map(),
// Content of the package itself
content: Immutable.Map()
}, 'Plugin');
Plugin.prototype.getName = function() {
return this.get('name');
};
Plugin.prototype.getPath = function() {
return this.get('path');
};
Plugin.prototype.getVersion = function() {
return this.get('version');
};
Plugin.prototype.getPackage = function() {
return this.get('package');
};
Plugin.prototype.getContent = function() {
return this.get('content');
};
Plugin.prototype.getDepth = function() {
return this.get('depth');
};
/**
Return the ID on NPM for this plugin
@return {String}
*/
Plugin.prototype.getNpmID = function() {
return Plugin.nameToNpmID(this.getName());
};
/**
Check if a plugin is loaded
@return {Boolean}
*/
Plugin.prototype.isLoaded = function() {
return Boolean(this.getPackage().size > 0);
};
/**
Return map of hooks
@return {Map<String:Function>}
*/
Plugin.prototype.getHooks = function() {
return this.getContent().get('hooks') || Immutable.Map();
};
/**
Return infos about resources for a specific type
@param {String} type
@return {Map<String:Mixed>}
*/
Plugin.prototype.getResources = function(type) {
if (type != 'website' && type != 'ebook') {
throw new Error('Invalid assets type ' + type);
}
var content = this.getContent();
return (content.get(type)
|| (type == 'website'? content.get('book') : null)
|| Immutable.Map());
};
/**
Return map of filters
@return {Map<String:Function>}
*/
Plugin.prototype.getFilters = function() {
return this.getContent().get('filters');
};
/**
Return map of blocks
@return {Map<String:TemplateBlock>}
*/
Plugin.prototype.getBlocks = function() {
var blocks = this.getContent().get('blocks');
blocks = blocks || Immutable.Map();
return blocks
.map(function(block, blockName) {
return TemplateBlock.create(blockName, block);
});
};
/**
Return a specific hook
@param {String} name
@return {Function|undefined}
*/
Plugin.prototype.getHook = function(name) {
return this.getHooks().get(name);
};
/**
Create a plugin from a string
@param {String}
@return {Plugin}
*/
Plugin.createFromString = function(s) {
var parts = s.split('@');
var name = parts[0];
var version = parts.slice(1).join('@');
return new Plugin({
name: name,
version: version || DEFAULT_VERSION
});
};
/**
Create a plugin from a dependency
@param {PluginDependency}
@return {Plugin}
*/
Plugin.createFromDep = function(dep) {
return new Plugin({
name: dep.getName(),
version: dep.getVersion()
});
};
/**
Return NPM id for a plugin name
@param {String}
@return {String}
*/
Plugin.nameToNpmID = function(s) {
return PREFIX + s;
};
module.exports = Plugin;
-115
View File
@@ -1,115 +0,0 @@
var is = require('is');
var Immutable = require('immutable');
var DEFAULT_VERSION = '*';
/*
PluginDependency represents the informations about a plugin
stored in config.plugins
*/
var PluginDependency = Immutable.Record({
name: String(),
// Requirement version (ex: ">1.0.0")
version: String(DEFAULT_VERSION),
// Is this plugin enabled or disabled?
enabled: Boolean(true)
}, 'PluginDependency');
PluginDependency.prototype.getName = function() {
return this.get('name');
};
PluginDependency.prototype.getVersion = function() {
return this.get('version');
};
PluginDependency.prototype.isEnabled = function() {
return this.get('enabled');
};
/**
Create a plugin from a string
@param {String}
@return {Plugin|undefined}
*/
PluginDependency.createFromString = function(s) {
var parts = s.split('@');
var name = parts[0];
var version = parts.slice(1).join('@');
var enabled = true;
if (name[0] === '-') {
enabled = false;
name = name.slice(1);
}
return new PluginDependency({
name: name,
version: version || DEFAULT_VERSION,
enabled: enabled
});
};
/**
Create a PluginDependency from a string
@param {String}
@return {List<PluginDependency>}
*/
PluginDependency.listFromString = function(s) {
var parts = s.split(',');
return PluginDependency.listFromArray(parts);
};
/**
Create a PluginDependency from an array
@param {Array}
@return {List<PluginDependency>}
*/
PluginDependency.listFromArray = function(arr) {
return Immutable.List(arr)
.map(function(entry) {
if (is.string(entry)) {
return PluginDependency.createFromString(entry);
} else {
return PluginDependency({
name: entry.name,
version: entry.version
});
}
})
.filter(function(dep) {
return Boolean(dep.getName());
});
};
/**
Export plugin dependencies as an array
@param {List<PluginDependency>}
@return {Array<String>}
*/
PluginDependency.listToArray = function(arr) {
return arr
.map(function(dep) {
var result;
if (dep.isEnabled()) {
result += '-';
}
result += dep.getName();
if (dep.getVersion() !== DEFAULT_VERSION) {
result += '@' + dep.getVersion();
}
return result;
})
.toJS();
};
module.exports = PluginDependency;
-40
View File
@@ -1,40 +0,0 @@
var Immutable = require('immutable');
var File = require('./file');
var Readme = Immutable.Record({
file: File(),
title: String(),
description: String()
});
Readme.prototype.getFile = function() {
return this.get('file');
};
Readme.prototype.getTitle = function() {
return this.get('title');
};
Readme.prototype.getDescription = function() {
return this.get('description');
};
/**
Create a new readme
@param {File} file
@param {Object} def
@return {Readme}
*/
Readme.create = function(file, def) {
def = def || {};
return new Readme({
file: file,
title: def.title || '',
description: def.description || ''
});
};
module.exports = Readme;
-223
View File
@@ -1,223 +0,0 @@
var is = require('is');
var Immutable = require('immutable');
var error = require('../utils/error');
var LocationUtils = require('../utils/location');
var File = require('./file');
var SummaryPart = require('./summaryPart');
var SummaryArticle = require('./summaryArticle');
var parsers = require('../parsers');
var Summary = Immutable.Record({
file: File(),
parts: Immutable.List()
}, 'Summary');
Summary.prototype.getFile = function() {
return this.get('file');
};
Summary.prototype.getParts = function() {
return this.get('parts');
};
/**
Return a part by its index
@param {Number}
@return {Part}
*/
Summary.prototype.getPart = function(i) {
var parts = this.getParts();
return parts.get(i);
};
/**
Return an article using an iterator to find it.
if "partIter" is set, it can also return a Part.
@param {Function} iter
@param {Function} partIter
@return {Article|Part}
*/
Summary.prototype.getArticle = function(iter, partIter) {
var parts = this.getParts();
return parts.reduce(function(result, part) {
if (result) return result;
if (partIter && partIter(part)) return part;
return SummaryArticle.findArticle(part, iter);
}, null);
};
/**
Return a part/article by its level
@param {String} level
@return {Article|Part}
*/
Summary.prototype.getByLevel = function(level) {
function iterByLevel(article) {
return (article.getLevel() === level);
}
return this.getArticle(iterByLevel, iterByLevel);
};
/**
Return an article by its path
@param {String} filePath
@return {Article}
*/
Summary.prototype.getByPath = function(filePath) {
return this.getArticle(function(article) {
return (LocationUtils.areIdenticalPaths(article.getPath(), filePath));
});
};
/**
Return the first article
@return {Article}
*/
Summary.prototype.getFirstArticle = function() {
return this.getArticle(function(article) {
return true;
});
};
/**
Return next article of an article
@param {Article} current
@return {Article}
*/
Summary.prototype.getNextArticle = function(current) {
var level = is.string(current)? current : current.getLevel();
var wasPrev = false;
return this.getArticle(function(article) {
if (wasPrev) return true;
wasPrev = article.getLevel() == level;
return false;
});
};
/**
Return previous article of an article
@param {Article} current
@return {Article}
*/
Summary.prototype.getPrevArticle = function(current) {
var level = is.string(current)? current : current.getLevel();
var prev = undefined;
this.getArticle(function(article) {
if (article.getLevel() == level) {
return true;
}
prev = article;
return false;
});
return prev;
};
/**
Return the parent article, or parent part of an article
@param {String|Article} current
@return {Article|Part|Null}
*/
Summary.prototype.getParent = function (level) {
// Coerce to level
level = is.string(level)? level : level.getLevel();
// Get parent level
var parentLevel = getParentLevel(level);
if (!parentLevel) {
return null;
}
// Get parent of the position
var parentArticle = this.getByLevel(parentLevel);
return parentArticle || null;
};
/**
Render summary as text
@param {String} parseExt Extension of the parser to use
@return {Promise<String>}
*/
Summary.prototype.toText = function(parseExt) {
var file = this.getFile();
var parts = this.getParts();
var parser = parseExt? parsers.getByExt(parseExt) : file.getParser();
if (!parser) {
throw error.FileNotParsableError({
filename: file.getPath()
});
}
return parser.renderSummary({
parts: parts.toJS()
});
};
/**
Return all articles as a list
@return {List<Article>}
*/
Summary.prototype.getArticlesAsList = function() {
var accu = [];
this.getArticle(function(article) {
accu.push(article);
});
return Immutable.List(accu);
};
/**
Create a new summary for a list of parts
@param {Lust|Array} parts
@return {Summary}
*/
Summary.createFromParts = function createFromParts(file, parts) {
parts = parts.map(function(part, i) {
if (part instanceof SummaryPart) {
return part;
}
return SummaryPart.create(part, i + 1);
});
return new Summary({
file: file,
parts: new Immutable.List(parts)
});
};
/**
Returns parent level of a level
@param {String} level
@return {String}
*/
function getParentLevel(level) {
var parts = level.split('.');
return parts.slice(0, -1).join('.');
}
module.exports = Summary;
-150
View File
@@ -1,150 +0,0 @@
var Immutable = require('immutable');
var location = require('../utils/location');
/*
An article represents an entry in the Summary / table of Contents
*/
var SummaryArticle = Immutable.Record({
level: String(),
title: String(),
ref: String(),
articles: Immutable.List()
}, 'SummaryArticle');
SummaryArticle.prototype.getLevel = function() {
return this.get('level');
};
SummaryArticle.prototype.getTitle = function() {
return this.get('title');
};
SummaryArticle.prototype.getRef = function() {
return this.get('ref');
};
SummaryArticle.prototype.getArticles = function() {
return this.get('articles');
};
/**
Return how deep the article is
@return {Number}
*/
SummaryArticle.prototype.getDepth = function() {
return this.getLevel().split('.').length;
};
/**
Get path (without anchor) to the pointing file
@return {String}
*/
SummaryArticle.prototype.getPath = function() {
if (this.isExternal()) {
return undefined;
}
var ref = this.getRef();
if (!ref) {
return undefined;
}
var parts = ref.split('#');
var pathname = (parts.length > 1? parts.slice(0, -1).join('#') : ref);
// Normalize path to remove ('./', etc)
return location.normalize(pathname);
};
/**
Return url if article is external
@return {String}
*/
SummaryArticle.prototype.getUrl = function() {
return this.isExternal()? this.getRef() : undefined;
};
/**
Get anchor for this article (or undefined)
@return {String}
*/
SummaryArticle.prototype.getAnchor = function() {
var ref = this.getRef();
var parts = ref.split('#');
var anchor = (parts.length > 1? '#' + parts[parts.length - 1] : undefined);
return anchor;
};
/**
Is article pointing to a page of an absolute url
@return {Boolean}
*/
SummaryArticle.prototype.isPage = function() {
return !this.isExternal() && this.getRef();
};
/**
Is article pointing to aan absolute url
@return {Boolean}
*/
SummaryArticle.prototype.isExternal = function() {
return location.isExternal(this.getRef());
};
/**
Create a SummaryArticle
@param {Object} def
@return {SummaryArticle}
*/
SummaryArticle.create = function(def, level) {
var articles = (def.articles || []).map(function(article, i) {
if (article instanceof SummaryArticle) {
return article;
}
return SummaryArticle.create(article, [level, i + 1].join('.'));
});
return new SummaryArticle({
level: level,
title: def.title,
ref: def.ref || def.path || '',
articles: Immutable.List(articles)
});
};
/**
Find an article from a base one
@param {Article|Part} base
@param {Function(article)} iter
@return {Article}
*/
SummaryArticle.findArticle = function(base, iter) {
var articles = base.getArticles();
return articles.reduce(function(result, article) {
if (result) return result;
if (iter(article)) {
return article;
}
return SummaryArticle.findArticle(article, iter);
}, null);
};
module.exports = SummaryArticle;
-48
View File
@@ -1,48 +0,0 @@
var Immutable = require('immutable');
var SummaryArticle = require('./summaryArticle');
/*
A part represents a section in the Summary / table of Contents
*/
var SummaryPart = Immutable.Record({
level: String(),
title: String(),
articles: Immutable.List()
});
SummaryPart.prototype.getLevel = function() {
return this.get('level');
};
SummaryPart.prototype.getTitle = function() {
return this.get('title');
};
SummaryPart.prototype.getArticles = function() {
return this.get('articles');
};
/**
Create a SummaryPart
@param {Object} def
@return {SummaryPart}
*/
SummaryPart.create = function(def, level) {
var articles = (def.articles || []).map(function(article, i) {
if (article instanceof SummaryArticle) {
return article;
}
return SummaryArticle.create(article, [level, i + 1].join('.'));
});
return new SummaryPart({
level: String(level),
title: def.title,
articles: Immutable.List(articles)
});
};
module.exports = SummaryPart;
-310
View File
@@ -1,310 +0,0 @@
var is = require('is');
var extend = require('extend');
var Immutable = require('immutable');
var Promise = require('../utils/promise');
var genKey = require('../utils/genKey');
var NODE_ENDARGS = '%%endargs%%';
var blockBodies = {};
var TemplateBlock = Immutable.Record({
// Name of block, also the start tag
name: String(),
// End tag, default to "end<name>"
end: String(),
// Function to process the block content
process: Function(),
// List of String, for inner block tags
blocks: Immutable.List(),
// List of shortcuts to replace with this block
shortcuts: Immutable.List(),
// Function to execute in post processing
post: null,
parse: true
}, 'TemplateBlock');
TemplateBlock.prototype.getName = function() {
return this.get('name');
};
TemplateBlock.prototype.getPost = function() {
return this.get('post');
};
TemplateBlock.prototype.getParse = function() {
return this.get('parse');
};
TemplateBlock.prototype.getEndTag = function() {
return this.get('end') || ('end' + this.getName());
};
TemplateBlock.prototype.getProcess = function() {
return this.get('process');
};
TemplateBlock.prototype.getBlocks = function() {
return this.get('blocks');
};
TemplateBlock.prototype.getShortcuts = function() {
return this.get('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) {
var that = this;
var name = this.getName();
var endTag = this.getEndTag();
var blocks = this.getBlocks().toJS();
function Ext() {
this.tags = [name];
this.parse = function(parser, nodes) {
var lastBlockName = null;
var lastBlockArgs = null;
var allBlocks = blocks.concat([endTag]);
// Parse first block
var tok = parser.nextToken();
lastBlockArgs = parser.parseSignature(null, true);
parser.advanceAfterBlockEnd(tok.value);
var args = new nodes.NodeList();
var bodies = [];
var blockNamesNode = new nodes.Array(tok.lineno, tok.colno);
var blockArgCounts = new nodes.Array(tok.lineno, tok.colno);
// Parse while we found "end<block>"
do {
// Read body
var currentBody = parser.parseUntilBlocks.apply(parser, 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) {
var fnArgs = Array.prototype.slice.call(arguments, 1);
var args;
var blocks = [];
var bodies = [];
var blockNames;
var blockArgCounts;
var callback;
// Extract callback
callback = fnArgs.pop();
// Detect end of arguments
var endArgIndex = fnArgs.indexOf(NODE_ENDARGS);
// Extract arguments and bodies
args = fnArgs.slice(0, endArgIndex);
bodies = fnArgs.slice(endArgIndex + 1);
// Extract block counts
blockArgCounts = args.pop();
blockNames = args.pop();
// Recreate list of blocks
blockNames.forEach(function(name, i) {
var countArgs = blockArgCounts[i];
var blockBody = bodies.shift();
var blockArgs = countArgs > 0? args.slice(0, countArgs) : [];
args = args.slice(countArgs);
var blockKwargs = extractKwargs(blockArgs);
blocks.push({
name: name,
body: blockBody(),
args: blockArgs,
kwargs: blockKwargs
});
});
var mainBlock = blocks.shift();
mainBlock.blocks = blocks;
Promise()
.then(function() {
var ctx = extend({
ctx: context
}, mainContext || {});
return that.applyBlock(mainBlock, ctx);
})
.then(function(result) {
return that.blockResultToHtml(result);
})
.nodeify(callback);
};
}
return Ext;
};
/**
Apply a block to a content
@param {Object} inner
@param {Object} context
@return {Promise<String>|String}
*/
TemplateBlock.prototype.applyBlock = function(inner, context) {
var processFn = this.getProcess();
inner = inner || {};
inner.args = inner.args || [];
inner.kwargs = inner.kwargs || {};
inner.blocks = inner.blocks || [];
var r = processFn.call(context, inner);
if (Promise.isPromiseAlike(r)) {
return r.then(this.handleBlockResult.bind(this));
} else {
return this.handleBlockResult(r);
}
};
/**
Handle result from a block process function
@param {Object} result
@return {Object}
*/
TemplateBlock.prototype.handleBlockResult = function(result) {
if (is.string(result)) {
result = { body: result };
}
result.name = this.getName();
return result;
};
/**
Convert a block result to HTML
@param {Object} result
@return {String}
*/
TemplateBlock.prototype.blockResultToHtml = function(result) {
var parse = this.getParse();
var indexedKey;
var toIndex = (!parse) || (this.getPost() !== undefined);
if (toIndex) {
indexedKey = TemplateBlock.indexBlockResult(result);
}
// Parsable block, just return it
if (parse) {
return result.body;
}
// Return it as a position marker
return '{{-%' + indexedKey + '%-}}';
};
/**
Index a block result, and return the indexed key
@param {Object} blk
@return {String}
*/
TemplateBlock.indexBlockResult = function(blk) {
var key = genKey();
blockBodies[key] = blk;
return key;
};
/**
Get a block results indexed for a specific key
@param {String} key
@return {Object|undefined}
*/
TemplateBlock.getBlockResultByKey = function(key) {
return blockBodies[key];
};
/**
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 = block.set('name', blockName);
return new TemplateBlock(block);
};
/**
Extract kwargs from an arguments array
@param {Array} args
@return {Object}
*/
function extractKwargs(args) {
var last = args[args.length - 1];
return (is.object(last) && last.__keywords)? args.pop() : {};
}
module.exports = TemplateBlock;

Some files were not shown because too many files have changed in this diff Show More