├── src
├── strategies
│ ├── sass
│ │ ├── epub.css
│ │ ├── cover.jpg
│ │ ├── clean.js
│ │ ├── index.js
│ │ ├── scrapper.js
│ │ └── scrapperMd.js
│ ├── lodash
│ │ ├── epub.css
│ │ ├── cover.jpg
│ │ ├── clean.js
│ │ ├── index.js
│ │ ├── scrapper.js
│ │ └── scrapperMd.js
│ ├── react
│ │ ├── epub.css
│ │ ├── cover.jpg
│ │ ├── clean.js
│ │ ├── index.js
│ │ ├── scrapper.js
│ │ └── scrapperMd.js
│ ├── angular2
│ │ ├── cover.jpg
│ │ ├── clean.js
│ │ ├── index.js
│ │ └── scrapper.js
│ ├── express
│ │ ├── cover.jpg
│ │ ├── index.js
│ │ └── scrapper.js
│ ├── underscore
│ │ ├── cover.jpg
│ │ ├── index.js
│ │ └── scrapper.js
│ └── apollo-react
│ │ ├── cover.jpg
│ │ ├── index.js
│ │ └── scrapperMd.js
├── getAboutPage.js
├── run.js
├── tocObjToHtml.js
└── tocToArray.js
├── .gitignore
├── docs
├── og.jpg
├── ereader.jpg
├── gallery-bg.jpg
├── download
│ ├── elm.epub
│ ├── mobx.epub
│ ├── sass.epub
│ ├── vue.epub
│ ├── express.epub
│ ├── lodash.epub
│ ├── react.epub
│ ├── angular2.epub
│ ├── socketio.epub
│ ├── apolloreact.epub
│ └── underscore.epub
├── assets
│ ├── book_react.jpg
│ ├── book_sass.jpg
│ ├── book_express.jpg
│ ├── book_lodash.jpg
│ ├── book_angular2.jpg
│ ├── book_underscore.jpg
│ └── book_apolloreact.jpg
├── lib
│ └── cutereset.css
├── style.css
└── index.html
├── docs-assets
└── thumbnail.jpg
├── package.json
├── README.md
└── index.js
/src/strategies/sass/epub.css:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | _tmp
4 | *.log
5 |
--------------------------------------------------------------------------------
/docs/og.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/og.jpg
--------------------------------------------------------------------------------
/docs/ereader.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/ereader.jpg
--------------------------------------------------------------------------------
/src/strategies/lodash/epub.css:
--------------------------------------------------------------------------------
1 | .buttons-unit, iframe {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/src/strategies/react/epub.css:
--------------------------------------------------------------------------------
1 | .buttons-unit, iframe {
2 | display: none;
3 | }
4 |
--------------------------------------------------------------------------------
/docs/gallery-bg.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/gallery-bg.jpg
--------------------------------------------------------------------------------
/docs/download/elm.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/elm.epub
--------------------------------------------------------------------------------
/docs/download/mobx.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/mobx.epub
--------------------------------------------------------------------------------
/docs/download/sass.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/sass.epub
--------------------------------------------------------------------------------
/docs/download/vue.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/vue.epub
--------------------------------------------------------------------------------
/docs-assets/thumbnail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs-assets/thumbnail.jpg
--------------------------------------------------------------------------------
/docs/assets/book_react.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/assets/book_react.jpg
--------------------------------------------------------------------------------
/docs/assets/book_sass.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/assets/book_sass.jpg
--------------------------------------------------------------------------------
/docs/download/express.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/express.epub
--------------------------------------------------------------------------------
/docs/download/lodash.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/lodash.epub
--------------------------------------------------------------------------------
/docs/download/react.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/react.epub
--------------------------------------------------------------------------------
/docs/assets/book_express.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/assets/book_express.jpg
--------------------------------------------------------------------------------
/docs/assets/book_lodash.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/assets/book_lodash.jpg
--------------------------------------------------------------------------------
/docs/download/angular2.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/angular2.epub
--------------------------------------------------------------------------------
/docs/download/socketio.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/socketio.epub
--------------------------------------------------------------------------------
/docs/assets/book_angular2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/assets/book_angular2.jpg
--------------------------------------------------------------------------------
/docs/assets/book_underscore.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/assets/book_underscore.jpg
--------------------------------------------------------------------------------
/docs/download/apolloreact.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/apolloreact.epub
--------------------------------------------------------------------------------
/docs/download/underscore.epub:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/download/underscore.epub
--------------------------------------------------------------------------------
/src/strategies/lodash/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/src/strategies/lodash/cover.jpg
--------------------------------------------------------------------------------
/src/strategies/react/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/src/strategies/react/cover.jpg
--------------------------------------------------------------------------------
/src/strategies/sass/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/src/strategies/sass/cover.jpg
--------------------------------------------------------------------------------
/docs/assets/book_apolloreact.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/docs/assets/book_apolloreact.jpg
--------------------------------------------------------------------------------
/src/strategies/angular2/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/src/strategies/angular2/cover.jpg
--------------------------------------------------------------------------------
/src/strategies/express/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/src/strategies/express/cover.jpg
--------------------------------------------------------------------------------
/src/strategies/underscore/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/src/strategies/underscore/cover.jpg
--------------------------------------------------------------------------------
/src/strategies/apollo-react/cover.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/javierbyte/docs2epub/HEAD/src/strategies/apollo-react/cover.jpg
--------------------------------------------------------------------------------
/src/strategies/angular2/clean.js:
--------------------------------------------------------------------------------
1 | function htmlFilter (content) {
2 | return content.replace(/code-example/gi, 'code').replace(/code-pane/gi, 'code')
3 | }
4 |
5 | module.exports = htmlFilter
6 |
--------------------------------------------------------------------------------
/src/strategies/express/index.js:
--------------------------------------------------------------------------------
1 | var CONFIG = {
2 | title: 'Express',
3 | author: 'Express',
4 | cover: './src/strategies/express/cover.jpg',
5 |
6 | docsUrl: 'http://expressjs.com/en/4x/api.html',
7 | repoUrl: 'https://github.com/expressjs/express',
8 | licenceUrl: 'https://raw.githubusercontent.com/expressjs/express/master/LICENSE'
9 | }
10 |
11 | module.exports = CONFIG
12 |
--------------------------------------------------------------------------------
/src/strategies/angular2/index.js:
--------------------------------------------------------------------------------
1 | var CONFIG = {
2 | title: 'angular2',
3 | author: 'angular2',
4 | cover: './src/strategies/angular2/cover.jpg',
5 |
6 | docsUrl: 'https://angular.io/docs/ts/latest/',
7 | repoUrl: 'https://github.com/angular/angular',
8 | licenceUrl: 'https://raw.githubusercontent.com/angular/angular/master/LICENSE',
9 |
10 | cleanHtml: require('./clean')
11 | }
12 |
13 | module.exports = CONFIG
14 |
--------------------------------------------------------------------------------
/src/strategies/underscore/index.js:
--------------------------------------------------------------------------------
1 | var CONFIG = {
2 | title: 'Underscore',
3 | author: 'Underscore',
4 | cover: './src/strategies/underscore/cover.jpg',
5 |
6 | docsUrl: 'http://underscorejs.org/',
7 | repoUrl: 'https://github.com/jashkenas/underscore',
8 | licenceUrl: 'https://raw.githubusercontent.com/jashkenas/underscore/master/LICENSE'
9 |
10 | // cleanHtml: require('./clean')
11 | }
12 |
13 | module.exports = CONFIG
14 |
--------------------------------------------------------------------------------
/src/strategies/react/clean.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 | var cheerio = require('cheerio')
3 |
4 | function htmlFilter (content) {
5 | var $ = cheerio.load(content)
6 |
7 | var elToRemove = [
8 | '.hash-link',
9 | '.edit-page-link',
10 | '.want-to-skip-all-this-and-just-see-the-source'
11 | ]
12 |
13 | _.forEach(elToRemove, el => $(el).remove())
14 |
15 | return $.html()
16 | }
17 |
18 | module.exports = htmlFilter
19 |
--------------------------------------------------------------------------------
/src/strategies/sass/clean.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 | var cheerio = require('cheerio')
3 |
4 | function htmlFilter (content) {
5 | var $ = cheerio.load(content)
6 |
7 | var elToRemove = [
8 | '.hash-link',
9 | '.edit-page-link',
10 | '.want-to-skip-all-this-and-just-see-the-source'
11 | ]
12 |
13 | _.forEach(elToRemove, el => $(el).remove())
14 |
15 | return $.html()
16 | }
17 |
18 | module.exports = htmlFilter
19 |
--------------------------------------------------------------------------------
/src/strategies/lodash/clean.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 | var cheerio = require('cheerio')
3 |
4 | function htmlFilter (content) {
5 | var $ = cheerio.load(content)
6 |
7 | var elToRemove = [
8 | '.hash-link',
9 | '.edit-page-link',
10 | '.want-to-skip-all-this-and-just-see-the-source'
11 | ]
12 |
13 | _.forEach(elToRemove, el => $(el).remove())
14 |
15 | return $.html()
16 | }
17 |
18 | module.exports = htmlFilter
19 |
--------------------------------------------------------------------------------
/src/strategies/underscore/scrapper.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 | const CONFIG = require('./index.js')
3 |
4 | function strategy () {
5 | return new Promise(function (resolve, reject) {
6 | resolve(
7 | _.assign({}, CONFIG, {
8 | content: [{
9 | title: 'Underscore',
10 | level: 0,
11 | url: 'http://underscorejs.org/'
12 | }]
13 | })
14 | )
15 | })
16 | }
17 |
18 | module.exports = strategy
19 |
--------------------------------------------------------------------------------
/src/strategies/express/scrapper.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 | const CONFIG = require('./index.js')
3 |
4 | function strategy () {
5 | return new Promise(function (resolve, reject) {
6 | resolve(
7 | _.assign({}, CONFIG, {
8 | content: [{
9 | title: 'Express',
10 | level: 0,
11 | url: 'http://expressjs.com/en/api.html'
12 | }]
13 | })
14 | )
15 | })
16 | }
17 |
18 | module.exports = strategy
19 |
--------------------------------------------------------------------------------
/src/strategies/lodash/index.js:
--------------------------------------------------------------------------------
1 | var CONFIG = {
2 | title: 'Lodash',
3 | author: 'Lodash',
4 | cover: './src/strategies/lodash/cover.jpg',
5 |
6 | epubStylesheet: './src/strategies/lodash/epub.css',
7 | epubTOCDepth: false,
8 |
9 | docsUrl: 'https://lodash.com/docs/4.15.0',
10 | repoUrl: 'https://github.com/lodash/lodash',
11 | licenceUrl: 'https://raw.githubusercontent.com/lodash/lodash/master/LICENSE',
12 |
13 | type: 'MARKDOWN'
14 | }
15 |
16 | module.exports = CONFIG
17 |
--------------------------------------------------------------------------------
/src/strategies/sass/index.js:
--------------------------------------------------------------------------------
1 | var CONFIG = {
2 | title: 'Sass',
3 | author: 'Sass',
4 | cover: './src/strategies/sass/cover.jpg',
5 |
6 | epubStylesheet: './src/strategies/sass/epub.css',
7 | epubTOCDepth: 1,
8 |
9 | docsUrl: 'http://sass-lang.com/',
10 | repoUrl: 'https://github.com/sass/sass',
11 | licenceUrl: 'https://raw.githubusercontent.com/sass/sass/stable/MIT-LICENSE',
12 |
13 | type: 'MARKDOWN',
14 | cleanHtml: require('./clean')
15 | }
16 |
17 | module.exports = CONFIG
18 |
--------------------------------------------------------------------------------
/src/strategies/apollo-react/index.js:
--------------------------------------------------------------------------------
1 | var CONFIG = {
2 | title: 'ApolloReact',
3 | author: 'Apollo',
4 | cover: './src/strategies/apollo-react/cover.jpg',
5 |
6 | epubStylesheet: './src/strategies/react/epub.css',
7 | epubTOCDepth: 1,
8 |
9 | docsUrl: 'http://dev.apollodata.com/react/',
10 | repoUrl: 'https://github.com/apollographql/react-docs',
11 | licenceUrl: 'https://raw.githubusercontent.com/apollographql/apollo-client/master/LICENSE',
12 |
13 | type: 'MARKDOWN'
14 | }
15 |
16 | module.exports = CONFIG
17 |
--------------------------------------------------------------------------------
/src/strategies/react/index.js:
--------------------------------------------------------------------------------
1 | var CONFIG = {
2 | title: 'React',
3 | author: 'Facebook',
4 | cover: './src/strategies/react/cover.jpg',
5 |
6 | epubStylesheet: './src/strategies/react/epub.css',
7 | epubTOCDepth: 1,
8 |
9 | docsUrl: 'https://facebook.github.io/react/docs/getting-started.html',
10 | repoUrl: 'https://github.com/facebook/react',
11 | licenceUrl: 'https://raw.githubusercontent.com/facebook/react/master/LICENSE-docs',
12 |
13 | type: 'MARKDOWN',
14 | cleanHtml: require('./clean')
15 | }
16 |
17 | module.exports = CONFIG
18 |
--------------------------------------------------------------------------------
/src/getAboutPage.js:
--------------------------------------------------------------------------------
1 | function getAboutPageTemplate(tocObj) {
2 | return `
3 |
4 |
About this book.
5 |
6 | Documentation generated by docs2epub [http://javier.xyz/docs2epub/] on ${new Date()}, scrapped from ${tocObj.docsUrl}.
7 |
8 |
9 |
10 | Find more about this project on ${tocObj.repoUrl}.
11 | LICENCE of ${tocObj.title}: ${tocObj.licenceUrl}
12 |
13 |
14 | `;
15 | }
16 |
17 | function getAboutPage(tocObj) {
18 | return {
19 | title: `${tocObj.title} documentation`,
20 | level: 0,
21 | result: {
22 | title: `${tocObj.title} documentation`,
23 | content: getAboutPageTemplate(tocObj)
24 | }
25 | };
26 | }
27 |
28 | module.exports = getAboutPage;
29 |
--------------------------------------------------------------------------------
/src/run.js:
--------------------------------------------------------------------------------
1 | const tocToArray = require('./tocToArray');
2 |
3 | const strategies = {
4 | react: require('./strategies/react/scrapperMd'),
5 | apolloreact: require('./strategies/apollo-react/scrapperMd'),
6 | lodash: require('./strategies/lodash/scrapperMd'),
7 | underscore: require('./strategies/underscore/scrapper'),
8 | express: require('./strategies/express/scrapper'),
9 | angular2: require('./strategies/angular2/scrapper'),
10 | sass: require('./strategies/sass/scrapperMd')
11 | };
12 |
13 | function run(strategyId) {
14 | return new Promise(function(resolve, reject) {
15 | strategies
16 | [strategyId]()
17 | .then(tocToArray)
18 | .then(docArray => {
19 | resolve(docArray);
20 | })
21 | .catch(reject);
22 | });
23 | }
24 |
25 | module.exports = run;
26 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "docs2epub",
3 | "version": "0.1.0",
4 | "description": "ever wanted to have your favorite library docs on epub format? search no more ;)",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/javierbyte/docs2epub.git"
12 | },
13 | "author": "",
14 | "license": "MIT",
15 | "bugs": {
16 | "url": "https://github.com/javierbyte/docs2epub/issues"
17 | },
18 | "homepage": "https://github.com/javierbyte/docs2epub#readme",
19 | "dependencies": {
20 | "async": "^2.0.1",
21 | "axios": "^0.14.0",
22 | "cheerio": "^0.22.0",
23 | "epub-gen": "0.0.16",
24 | "express": "^4.14.0",
25 | "lodash": "^4.15.0",
26 | "moment": "^2.14.1",
27 | "node-readability": "^2.2.0",
28 | "pug": "^2.0.0-beta6",
29 | "slug": "^0.9.1"
30 | },
31 | "devDependencies": {
32 | "standard": "^8.0.0"
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/strategies/lodash/scrapper.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 |
3 | const cheerio = require('cheerio')
4 | const axios = require('axios')
5 | const url = require('url')
6 |
7 | const CONFIG = require('./index.js')
8 |
9 | const DOCURL = 'https://facebook.github.io/react/docs/getting-started.html'
10 |
11 | function strategy () {
12 | return new Promise(function (resolve, reject) {
13 | axios.get(DOCURL)
14 | .then(res => {
15 | var $ = cheerio.load(res.data)
16 | var tocArray = []
17 |
18 | $('.nav-docs-section').each(function (index, el) {
19 | var parentName = $(el).find('h3').text()
20 |
21 | if (parentName === 'Community Resources') return
22 |
23 | tocArray.push({
24 | title: parentName,
25 | level: 1
26 | })
27 |
28 | $(this).find('a').each(function (childIndex, childEl) {
29 | tocArray.push({
30 | parent: parentName,
31 | level: 2,
32 | title: $(childEl).text(),
33 | url: url.resolve(DOCURL, $(childEl).attr('href'))
34 | })
35 | })
36 | })
37 |
38 | resolve(
39 | _.assign({}, CONFIG, {
40 | type: 'HTML',
41 | content: tocArray
42 | })
43 | )
44 | })
45 | })
46 | }
47 |
48 | module.exports = strategy
49 |
--------------------------------------------------------------------------------
/src/strategies/react/scrapper.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 |
3 | const cheerio = require('cheerio')
4 | const axios = require('axios')
5 | const url = require('url')
6 |
7 | const CONFIG = require('./index.js')
8 |
9 | const DOCURL = 'https://facebook.github.io/react/docs/getting-started.html'
10 |
11 | function strategy () {
12 | return new Promise(function (resolve, reject) {
13 | axios.get(DOCURL)
14 | .then(res => {
15 | var $ = cheerio.load(res.data)
16 | var tocArray = []
17 |
18 | $('.nav-docs-section').each(function (index, el) {
19 | var parentName = $(el).find('h3').text()
20 |
21 | if (parentName === 'Community Resources') return
22 |
23 | tocArray.push({
24 | title: parentName,
25 | level: 1
26 | })
27 |
28 | $(this).find('a').each(function (childIndex, childEl) {
29 | tocArray.push({
30 | parent: parentName,
31 | level: 2,
32 | title: $(childEl).text(),
33 | url: url.resolve(DOCURL, $(childEl).attr('href'))
34 | })
35 | })
36 | })
37 |
38 | resolve(
39 | _.assign({}, CONFIG, {
40 | type: 'HTML',
41 | content: tocArray
42 | })
43 | )
44 | })
45 | })
46 | }
47 |
48 | module.exports = strategy
49 |
--------------------------------------------------------------------------------
/src/strategies/sass/scrapper.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 |
3 | const cheerio = require('cheerio')
4 | const axios = require('axios')
5 | const url = require('url')
6 |
7 | const CONFIG = require('./index.js')
8 |
9 | const DOCURL = 'https://facebook.github.io/react/docs/getting-started.html'
10 |
11 | function strategy () {
12 | return new Promise(function (resolve, reject) {
13 | axios.get(DOCURL)
14 | .then(res => {
15 | var $ = cheerio.load(res.data)
16 | var tocArray = []
17 |
18 | $('.nav-docs-section').each(function (index, el) {
19 | var parentName = $(el).find('h3').text()
20 |
21 | if (parentName === 'Community Resources') return
22 |
23 | tocArray.push({
24 | title: parentName,
25 | level: 1
26 | })
27 |
28 | $(this).find('a').each(function (childIndex, childEl) {
29 | tocArray.push({
30 | parent: parentName,
31 | level: 2,
32 | title: $(childEl).text(),
33 | url: url.resolve(DOCURL, $(childEl).attr('href'))
34 | })
35 | })
36 | })
37 |
38 | resolve(
39 | _.assign({}, CONFIG, {
40 | type: 'HTML',
41 | content: tocArray
42 | })
43 | )
44 | })
45 | })
46 | }
47 |
48 | module.exports = strategy
49 |
--------------------------------------------------------------------------------
/src/strategies/lodash/scrapperMd.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios')
2 | const _ = require('lodash')
3 | const async = require('async')
4 |
5 | const CONFIG = require('./index.js')
6 |
7 | var docList = [{
8 | title: 'Lodash',
9 | url: 'https://raw.githubusercontent.com/lodash/lodash/master/doc/README.md'
10 | }]
11 |
12 | docList = _.map(docList, (el, idx) => {
13 | el.index = ('000' + idx).slice(-3)
14 | return el
15 | })
16 |
17 | function requestUrl (doc, cb) {
18 | axios.get(doc.url).then(res => {
19 | console.log('READED', doc.url)
20 | cb(null, _.assign({}, doc, {
21 | result: {
22 | title: doc.title,
23 | content: res.data
24 | .replace(/
/g, '\n')
25 | .replace(/\[.*\[Ⓣ\]\[1\]/g, '')
26 | .replace(/([^#]|^)#### /g, '\n\n\n#### ')
27 | .replace(/\n\n/g, '\n')
28 | .replace(/(## `.*?`)/g, '\n$1')
29 | .replace(//g, 'h2>')
31 | }
32 | }))
33 | }, (err) => {
34 | cb(err)
35 | })
36 | }
37 |
38 | function strategy () {
39 | return new Promise(function (resolve, reject) {
40 | async.map(docList, requestUrl, function (asyncErr, asyncRes) {
41 | if (asyncErr) {
42 | reject(asyncErr)
43 | return
44 | }
45 |
46 | resolve(
47 | _.assign({}, CONFIG, {
48 | content: asyncRes
49 | })
50 | )
51 | })
52 | })
53 | }
54 |
55 | module.exports = strategy
56 |
--------------------------------------------------------------------------------
/src/tocObjToHtml.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash');
2 |
3 | var getHtml = function(content) {
4 | return `
5 |
6 |
7 |
8 |
9 |
10 |
11 |
37 |
38 |
39 |
40 | ${content}
41 |
42 |
43 |
44 | `;
45 | };
46 |
47 | function tocObjToHtml(tocObj) {
48 | return getHtml(
49 | _.map(tocObj.content, tocEl => {
50 | if (tocEl.result) {
51 | return `
52 |
53 | ${tocEl.result.title}
54 | ${tocEl.result.content}
55 |
56 | `;
57 | }
58 |
59 | if (tocEl.level === 0) return `${tocEl.title}
`;
60 | if (tocEl.level === 1) return `${tocEl.title}
`;
61 |
62 | return '';
63 | }).join('')
64 | );
65 | }
66 |
67 | module.exports = tocObjToHtml;
68 |
--------------------------------------------------------------------------------
/src/strategies/angular2/scrapper.js:
--------------------------------------------------------------------------------
1 | const _ = require('lodash')
2 |
3 | const cheerio = require('cheerio')
4 | const axios = require('axios')
5 | const url = require('url')
6 |
7 | const CONFIG = require('./index.js')
8 |
9 | const DOCURL = 'https://angular.io/docs/ts/latest/quickstart.html'
10 |
11 | function strategy () {
12 | return new Promise(function (resolve, reject) {
13 | axios.get(DOCURL)
14 | .then(res => {
15 | var $ = cheerio.load(res.data)
16 | var tocArray = []
17 |
18 | $('.nav-blocks').each(function (index, el) {
19 | var parentName = $(el).find('nav-title').first().text()
20 |
21 | if (parentName === 'API Reference') return
22 |
23 | tocArray.push({
24 | title: parentName,
25 | level: 1
26 | })
27 |
28 | $(this).find('.nav-unordered-lists a').each(function (childIndex, childEl) {
29 | tocArray.push({
30 | parent: parentName,
31 | level: 2,
32 | title: $(childEl).text(),
33 | url: url.resolve(DOCURL, $(childEl).attr('href'))
34 | })
35 | })
36 |
37 | $(this).find('.nav-ordered-lists a').each(function (childIndex, childEl) {
38 | tocArray.push({
39 | parent: parentName,
40 | level: 2,
41 | title: $(childEl).text(),
42 | url: url.resolve(DOCURL, $(childEl).attr('href'))
43 | })
44 | })
45 | })
46 |
47 | resolve(
48 | _.assign({}, CONFIG, {
49 | content: tocArray
50 | })
51 | )
52 | })
53 | })
54 | }
55 |
56 | module.exports = strategy
57 |
--------------------------------------------------------------------------------
/src/strategies/sass/scrapperMd.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios')
2 | const _ = require('lodash')
3 | const async = require('async')
4 |
5 | const CONFIG = require('./index.js')
6 |
7 | var docList = [{
8 | title: 'Sass reference',
9 | url: 'https://raw.githubusercontent.com/sass/sass/stable/doc-src/SASS_REFERENCE.md'
10 | }, {
11 | title: 'Indented syntax',
12 | url: 'https://raw.githubusercontent.com/sass/sass/stable/doc-src/INDENTED_SYNTAX.md'
13 | }, {
14 | title: 'SCSS for SASS Users',
15 | url: 'https://raw.githubusercontent.com/sass/sass/stable/doc-src/SCSS_FOR_SASS_USERS.md'
16 | }, {
17 | title: 'FAQ',
18 | url: 'https://raw.githubusercontent.com/sass/sass/stable/doc-src/FAQ.md'
19 | }, {
20 | title: 'Changelog',
21 | url: 'https://raw.githubusercontent.com/sass/sass/stable/doc-src/SASS_CHANGELOG.md'
22 | }]
23 |
24 | docList = _.map(docList, (el, idx) => {
25 | el.index = ('000' + idx).slice(-3)
26 | return el
27 | })
28 |
29 | function requestUrl (doc, cb) {
30 | axios.get(doc.url).then(res => {
31 | console.log('READED', doc.url)
32 | cb(null, _.assign({}, doc, {
33 | result: {
34 | title: doc.title,
35 | content: res.data
36 | }
37 | }))
38 | }, (err) => {
39 | cb(err)
40 | })
41 | }
42 |
43 | function strategy () {
44 | return new Promise(function (resolve, reject) {
45 | async.map(docList, requestUrl, function (asyncErr, asyncRes) {
46 | if (asyncErr) {
47 | reject(asyncErr)
48 | return
49 | }
50 |
51 | resolve(
52 | _.assign({}, CONFIG, {
53 | content: asyncRes
54 | })
55 | )
56 | })
57 | })
58 | }
59 |
60 | module.exports = strategy
61 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | Get your favorite docs as ebooks!
2 | Doc scraper and ebook generator.
3 |
4 | [](http://javier.xyz/docs2epub/)
5 |
6 | # Library
7 | List of precompiled ebooks created with docs2epub.
8 |
9 | * React [[epub]](http://javier.xyz/docs2epub/download/react.epub) [stable]
10 | * Lodash [[epub]](http://javier.xyz/docs2epub/download/lodash.epub) [stable]
11 | * Sass [[epub]](http://javier.xyz/docs2epub/download/sass.epub) [beta]
12 | * Underscore [[epub]](http://javier.xyz/docs2epub/download/underscore.epub) [beta]
13 | * express [[epub]](http://javier.xyz/docs2epub/download/express.epub) [beta]
14 | * angular2 [[epub]](http://javier.xyz/docs2epub/download/angular2.epub) [alpha]
15 |
16 | # Generate your own ebook form docs
17 | The objective of this tool is to be a ready to go documentation parser and ebook generator (from scraping documentation sites or markdown).
18 |
19 | It has a central processing and epub generator based on [strategies](https://github.com/javierbyte/docs2epub/tree/master/src/strategies).
20 |
21 | If you want to add your own ebook generator you'll have to add a 'strategy' to the the `/src/strategies/` dir that returns a `docObj` object as described on [tocToArray.js](https://github.com/javierbyte/docs2epub/blob/master/src/tocToArray.js). And then require it on [run.js](https://github.com/javierbyte/docs2epub/blob/master/src/run.js#L3).
22 |
23 | Then run
24 | ```
25 | node index.js --project
26 | ```
27 |
28 | With `yourprojectid` being the key on the `run.js` require.
29 |
30 | And you'll have your `.epub` on the `docs/downloads` directory!
31 |
32 | Remember to add the original documentation licence. And feel free to open an issue here or create a PR if you want to add your generated ebook to the library.
33 |
34 | # Features
35 | * Pluggable system to add more documentation sources.
36 | * Uses [epub-gen](https://github.com/cyrilis/epub-gen) tuned for code.
37 |
38 | # Future improvements
39 | * Easier and smarter way to add more documentation sources.
40 | * Cronjob to auto-update library.
41 |
42 | # Licence
43 | MIT.
44 |
--------------------------------------------------------------------------------
/src/tocToArray.js:
--------------------------------------------------------------------------------
1 | /*
2 | We should return a "dobObj" object, that looks like this:
3 |
4 | {
5 | title: 'React', // name
6 | author: 'Facebook', // author
7 | cover: './src/strategies/react/cover.jpg', // cover url, relative or absolute
8 |
9 | epubStylesheet: './src/strategies/react/epub.css', // custom css url
10 | epubTOCDepth: 1,
11 |
12 | docsUrl: 'https://facebook.github.io/react/docs/getting-started.html',
13 | repoUrl: 'https://github.com/facebook/react',
14 | licenceUrl: 'https://raw.githubusercontent.com/facebook/react/master/LICENSE-docs',
15 |
16 | type: 'MARKDOWN', // MARKDOWN or HTML
17 | content: [{
18 | title: 'something',
19 | url: 'http://javier.xyz'
20 | }]
21 | }
22 |
23 | The `content.url` property should be either a html website (server side rendering) or a markdown file.
24 | Remember to specify a `type` `MARKDOWN` o `HTML`.
25 | */
26 |
27 | var _ = require('lodash');
28 | var read = require('node-readability');
29 | var cheerio = require('cheerio');
30 |
31 | var getAboutPage = require('./getAboutPage');
32 |
33 | function htmlSafe(content) {
34 | var $ = cheerio.load(content);
35 |
36 | var elToRemove = ['script'];
37 |
38 | _.forEach(elToRemove, el => $(el).remove());
39 |
40 | return $.html();
41 | }
42 |
43 | function resolveTocEl(tocEl, tocObj) {
44 | var cleanHtml = tocObj.cleanHtml ||
45 | function(noop) {
46 | return noop;
47 | };
48 |
49 | return new Promise(function(resolve, reject) {
50 | read(tocEl.url, function(err, article) {
51 | console.log('READED', tocEl.url);
52 |
53 | console.log(article.content);
54 |
55 | if (err || !article) {
56 | reject(err);
57 | return;
58 | }
59 |
60 | var title = article.title;
61 | var content = htmlSafe(cleanHtml(article.content));
62 |
63 | article.close();
64 |
65 | resolve(
66 | _.assign(tocEl, {
67 | result: {
68 | title: title,
69 | content: content
70 | }
71 | })
72 | );
73 | });
74 | });
75 | }
76 |
77 | function getContent(tocContent, tocObj) {
78 | return new Promise(function(resolve, reject) {
79 | if (
80 | _.every(tocContent, toc => {
81 | return !toc.url || toc.result;
82 | })
83 | ) {
84 | resolve(tocContent);
85 | return;
86 | }
87 |
88 | var toSearchContentKey = _.findKey(tocContent, toc => {
89 | return !(!toc.url || toc.result);
90 | });
91 |
92 | resolveTocEl(tocContent[toSearchContentKey], tocObj)
93 | .then(res => {
94 | tocContent[toSearchContentKey] = res;
95 | resolve(getContent(tocContent, tocObj));
96 | })
97 | .catch(reject);
98 | });
99 | }
100 |
101 | function tocToArray(toc) {
102 | return new Promise(function(resolve, reject) {
103 | getContent(toc.content, toc)
104 | .then(res => {
105 | resolve(
106 | _.assign({}, toc, {
107 | content: res
108 | })
109 | );
110 | })
111 | .catch(reject);
112 | });
113 | }
114 |
115 | module.exports = tocToArray;
116 |
--------------------------------------------------------------------------------
/src/strategies/apollo-react/scrapperMd.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios')
2 | const _ = require('lodash')
3 | const async = require('async')
4 |
5 | const CONFIG = require('./index.js')
6 |
7 | var docList = [{
8 | title: 'Index',
9 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/index.md'
10 | }, {
11 | title: 'Initialization',
12 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/initialization.md'
13 | }, {
14 | title: 'Higher Order Components',
15 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/higher-order-components.md'
16 | }, {
17 | title: 'Example Schema',
18 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/example-schema.md'
19 | }, {
20 | title: 'Queries',
21 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/queries.md'
22 | }, {
23 | title: 'Mutations',
24 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/mutations.md'
25 | }, {
26 | title: 'Receiving Updates',
27 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/receiving-updates.md'
28 | }, {
29 | title: 'Cache Updates',
30 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/cache-updates.md'
31 | }, {
32 | title: 'Auth',
33 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/auth.md'
34 | }, {
35 | title: 'Pagination',
36 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/pagination.md'
37 | }, {
38 | title: 'Optimistic UI',
39 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/optimistic-ui.md'
40 | }, {
41 | title: 'Fragments',
42 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/fragments.md'
43 | }, {
44 | title: 'Prefetching',
45 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/prefetching.md'
46 | }, {
47 | title: 'React Native',
48 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/react-native.md'
49 | }, {
50 | title: 'Redux',
51 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/redux.md'
52 | }, {
53 | title: 'Webpack',
54 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/webpack.md'
55 | }, {
56 | title: 'Server Side Rendering',
57 | url: 'https://raw.githubusercontent.com/apollographql/react-docs/master/source/server-side-rendering.md'
58 | }]
59 |
60 | docList = _.map(docList, (el, idx) => {
61 | el.index = ('000' + idx).slice(-3)
62 | return el
63 | })
64 |
65 | function requestUrl (doc, cb) {
66 | axios.get(doc.url).then(res => {
67 | console.log('READED', doc.url)
68 | cb(null, _.assign({}, doc, {
69 | result: {
70 | title: doc.title,
71 | content: `\n# ${doc.title}\n\n` + res.data
72 | // .replace(/\]\(\/react\/img/g, '](https://raw.githubusercontent.com/facebook/react/master/docs/img')
73 | }
74 | }))
75 | }, (err) => {
76 | cb(err)
77 | })
78 | }
79 |
80 | function strategy () {
81 | return new Promise(function (resolve, reject) {
82 | async.map(docList, requestUrl, function (asyncErr, asyncRes) {
83 | if (asyncErr) {
84 | reject(asyncErr)
85 | return
86 | }
87 |
88 | resolve(
89 | _.assign({}, CONFIG, {
90 | content: asyncRes
91 | })
92 | )
93 | })
94 | })
95 | }
96 |
97 | module.exports = strategy
98 |
--------------------------------------------------------------------------------
/docs/lib/cutereset.css:
--------------------------------------------------------------------------------
1 | * {
2 | margin: 0;
3 | padding: 0;
4 | position: relative;
5 | text-rendering: optimizeLegibility;
6 | }
7 | *,
8 | *:before,
9 | *:after {
10 | box-sizing: inherit;
11 | }
12 | html {
13 | box-sizing: border-box;
14 | -webkit-tap-highlight-color: rgba(0, 0, 0, 0);
15 | }
16 | a {
17 | text-decoration: none;
18 | }
19 | ul,
20 | ol {
21 | padding-left: 1em;
22 | }
23 | img {
24 | max-width: 100%;
25 | height: auto;
26 | }
27 | .cf:before,
28 | .cf:after {
29 | content: " ";
30 | display: table;
31 | }
32 | .cf:after {
33 | clear: both;
34 | }
35 | .flex {
36 | display: flex;
37 | }
38 | .flex-wrap {
39 | flex-wrap: wrap;
40 | }
41 | .flex-1 {
42 | flex: 1;
43 | }
44 | .flex-2 {
45 | flex: 2;
46 | }
47 | .flex-direction-column {
48 | flex-direction: column;
49 | }
50 | .flex-align-center {
51 | align-items: center;
52 | }
53 | .flex-align-start {
54 | align-items: flex-start;
55 | }
56 | .flex-align-stretch {
57 | align-items: stretch;
58 | }
59 | .flex-content-center {
60 | flex-content: center;
61 | }
62 | .flex-justify-center {
63 | justify-content: center;
64 | }
65 | .margin-1 {
66 | margin: 1 rem;
67 | }
68 | .padding-1 {
69 | padding: 1rem;
70 | }
71 | .padding-top-1 {
72 | padding-top: 1rem;
73 | }
74 | .margin-top-1 {
75 | margin-top: 1rem;
76 | }
77 | .padding-left-1 {
78 | padding-left: 1rem;
79 | }
80 | .margin-left-1 {
81 | margin-left: 1rem;
82 | }
83 | .padding-right-1 {
84 | padding-right: 1rem;
85 | }
86 | .margin-right-1 {
87 | margin-right: 1rem;
88 | }
89 | .padding-bottom-1 {
90 | padding-bottom: 1rem;
91 | }
92 | .margin-bottom-1 {
93 | margin-bottom: 1rem;
94 | }
95 | .margin-2 {
96 | margin: 2 rem;
97 | }
98 | .padding-2 {
99 | padding: 2rem;
100 | }
101 | .padding-top-2 {
102 | padding-top: 2rem;
103 | }
104 | .margin-top-2 {
105 | margin-top: 2rem;
106 | }
107 | .padding-left-2 {
108 | padding-left: 2rem;
109 | }
110 | .margin-left-2 {
111 | margin-left: 2rem;
112 | }
113 | .padding-right-2 {
114 | padding-right: 2rem;
115 | }
116 | .margin-right-2 {
117 | margin-right: 2rem;
118 | }
119 | .padding-bottom-2 {
120 | padding-bottom: 2rem;
121 | }
122 | .margin-bottom-2 {
123 | margin-bottom: 2rem;
124 | }
125 | .margin-3 {
126 | margin: 3 rem;
127 | }
128 | .padding-3 {
129 | padding: 3rem;
130 | }
131 | .padding-top-3 {
132 | padding-top: 3rem;
133 | }
134 | .margin-top-3 {
135 | margin-top: 3rem;
136 | }
137 | .padding-left-3 {
138 | padding-left: 3rem;
139 | }
140 | .margin-left-3 {
141 | margin-left: 3rem;
142 | }
143 | .padding-right-3 {
144 | padding-right: 3rem;
145 | }
146 | .margin-right-3 {
147 | margin-right: 3rem;
148 | }
149 | .padding-bottom-3 {
150 | padding-bottom: 3rem;
151 | }
152 | .margin-bottom-3 {
153 | margin-bottom: 3rem;
154 | }
155 | .margin-4 {
156 | margin: 4 rem;
157 | }
158 | .padding-4 {
159 | padding: 4rem;
160 | }
161 | .padding-top-4 {
162 | padding-top: 4rem;
163 | }
164 | .margin-top-4 {
165 | margin-top: 4rem;
166 | }
167 | .padding-left-4 {
168 | padding-left: 4rem;
169 | }
170 | .margin-left-4 {
171 | margin-left: 4rem;
172 | }
173 | .padding-right-4 {
174 | padding-right: 4rem;
175 | }
176 | .margin-right-4 {
177 | margin-right: 4rem;
178 | }
179 | .padding-bottom-4 {
180 | padding-bottom: 4rem;
181 | }
182 | .margin-bottom-4 {
183 | margin-bottom: 4rem;
184 | }
185 | h1,
186 | h2,
187 | h3,
188 | h4,
189 | h5,
190 | h6 {
191 | line-height: 1.127;
192 | margin-top: 0;
193 | margin-bottom: 0.309rem;
194 | }
195 | h1 {
196 | font-size: 4.23em;
197 | }
198 | h2 {
199 | font-size: 2.617em;
200 | }
201 | h3 {
202 | font-size: 1.618em;
203 | }
204 | h4 {
205 | font-size: 1.272em;
206 | }
207 | h5 {
208 | font-size: 1.127em;
209 | }
210 | h6 {
211 | font-size: 1em;
212 | }
213 |
--------------------------------------------------------------------------------
/docs/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #fcfcfc;
3 | }
4 |
5 | body, input, textarea {
6 | font-family: Actor;
7 | color: #333;
8 | font-size: 18px;
9 | }
10 |
11 | h1, h2, h3, h4 {
12 | font-family: Roboto Slab;
13 | }
14 |
15 | h1, h2 {
16 | font-weight: 400;
17 | letter-spacing: -1px;
18 | }
19 |
20 | h1 {
21 | font-size: 3.8em;
22 | }
23 | h2 {
24 | font-size: 2em;
25 | }
26 |
27 | .w {
28 | margin: 0 auto;
29 | max-width: 980px;
30 | }
31 | .section {
32 | padding: 5vmin 0;
33 | }
34 |
35 | .slogan {
36 | font-size: 1.3em;
37 | }
38 |
39 | .txt-center {
40 | text-align: center;
41 | }
42 |
43 | .header {
44 | background: #fcfcfc;
45 | overflow: hidden;
46 | }
47 | .ereader {
48 | margin-bottom: -8rem;
49 | }
50 |
51 | .gallery {
52 | background: #555 url(gallery-bg.jpg) repeat;
53 | color: #ddd;
54 | }
55 | .gallery h1, .gallery h2 {
56 | color: #fff;
57 | }
58 | .gallery a {
59 | color: #ddd;
60 | text-decoration: underline;
61 | }
62 | .single-line {
63 | padding: 0.5rem;
64 | }
65 |
66 | .book-gallery {
67 | overflow: auto;
68 | }
69 | .book-container {
70 | min-width: 25%;
71 | float: left;
72 | margin-top: 1rem;
73 | }
74 | .book {
75 | width: 100%;
76 | height: 0;
77 | padding-bottom: 133.33%;
78 | background-size: cover;
79 | background-repeat: no-repeat;
80 | background-color: #808080;
81 | box-shadow: rgba(0, 0, 0, 0.1) 0 1px 0, rgba(0, 0, 0, 0.1) 0 1px 5px;
82 | }
83 | .book::after {
84 | display: block;
85 | position: absolute;
86 | bottom: 0.5rem;
87 | right: -0.5rem;
88 | text-transform: uppercase;
89 | color: #fff;
90 | line-height: 1;
91 | padding: 0.25rem 0.5rem;
92 | font-size: 0.7em;
93 | text-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0;
94 | }
95 | .book.-alpha::after {
96 | background: #C0392B;
97 | content: 'Alpha'
98 | }
99 | .book.-beta::after {
100 | background: #E67E22;
101 | content: 'Beta'
102 | }
103 | .book.-stable::after {
104 | background: #27AE60;
105 | content: 'Stable'
106 | }
107 |
108 | .badge-explication {
109 | padding-bottom: 1rem;
110 | }
111 | .badge-explication-item {
112 | padding: 0.25rem 0;
113 | font-size: 14px;
114 | line-height: 1;
115 | }
116 | .badge-explication-item-descriptor {
117 | padding: 0.25rem 0.5rem;
118 | }
119 | .badge {
120 | text-shadow: rgba(0, 0, 0, 0.2) 0 -1px 0;
121 | text-transform: uppercase;
122 | color: #fff;
123 | line-height: 1;
124 | padding: 0.25rem 0.5rem;
125 | margin-right: 0.25rem;
126 | }
127 | .badge.-alpha {
128 | background: #C0392B;
129 | }
130 | .badge.-beta {
131 | background: #E67E22;
132 | }
133 | .badge.-stable {
134 | background: #27AE60;
135 | }
136 |
137 | .book-title {
138 | font-weight: 700;
139 | margin-top: 1rem;
140 | }
141 | .book-date {
142 | font-size: 0.8em;
143 | font-weight: 400;
144 | }
145 | .book-controls {
146 | padding-top: 0.5rem;
147 | }
148 | .book-controls-control {
149 | padding: 0.33rem 0.8rem;
150 | border:1px solid #777;
151 | border-radius: 2rem;
152 | color: #eee;
153 | font-size: 0.75em;
154 | text-decoration: none !important;
155 | }
156 | .book-controls-control:hover {
157 | border-color: #fff;
158 | color: #fff;
159 | background: rgba(255, 255, 255, 0.05);
160 | }
161 |
162 | .github-corner {
163 | position: fixed;
164 | top: 0;
165 | right: 0;
166 | }
167 |
168 | .footer {
169 | background: #eee;
170 | }
171 |
172 | @media screen and (max-width: 980px) {
173 | body {
174 | font-size: 16px;
175 | }
176 | }
177 |
178 | @media screen and (max-width: 640px) {
179 | .hide-on-mobile {
180 | display: none;
181 | }
182 |
183 | .center-on-mobile {
184 | text-align: center;
185 | }
186 |
187 | h1 {
188 | font-size: 3em;
189 | }
190 |
191 | body {
192 | font-size: 14px;
193 | }
194 | }
195 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var run = require('./src/run');
2 |
3 | var _ = require('lodash');
4 | var epub = require('epub-gen');
5 | var fs = require('fs');
6 | var async = require('async');
7 | var slug = require('slug');
8 | var moment = require('moment');
9 |
10 | const tocObjToHtml = require('./src/tocObjToHtml');
11 |
12 | var strategyToRunId = Math.max(process.argv.indexOf('--project'), process.argv.indexOf('-p'));
13 | var strategyToRun = strategyToRunId !== -1 && _.get(process.argv, parseInt(strategyToRunId) + 1);
14 |
15 | if (!strategyToRun) {
16 | console.error('Please pass an --project argument with the ID of the project that you want to compile');
17 | process.exit(1);
18 | }
19 |
20 | console.log(`Scrapping ${strategyToRun}`);
21 |
22 | function getEpubOptions(tocObj) {
23 | return {
24 | title: tocObj.title,
25 | cover: tocObj.cover,
26 | author: tocObj.author,
27 | css: 'code,pre{font-size: 0.9em;background:#fafafa;padding:0.5em;display:block;margin:0.5rem 0}',
28 | content: _.chain(tocObj.content)
29 | .filter(el => el.result)
30 | .map(tocEl => {
31 | return {
32 | title: tocEl.title,
33 | data: tocEl.result ? tocEl.result.content : ''
34 | };
35 | })
36 | .value()
37 | };
38 | }
39 |
40 | function execCommand(command, cb) {
41 | var sys = require('sys');
42 | var exec = require('child_process').exec;
43 | function puts(error, stdout, stderr) {
44 | if (error) throw error;
45 | sys.puts(stdout);
46 | cb();
47 | }
48 | exec(command, puts);
49 | }
50 |
51 | // generations trategies
52 | function generateEpubFromHtml(tocArray) {
53 | var epubOptions = getEpubOptions(tocArray);
54 | new epub(epubOptions, 'docs/download/' + strategyToRun + '.epub');
55 | }
56 |
57 | function generateHtmlFromHtml(tocArray) {
58 | fs.writeFile('docs/download/' + strategyToRun + '.html', tocObjToHtml(tocArray), (err, res) => {
59 | // console.log({err, res})
60 | });
61 | }
62 |
63 | function generateEpubMetadata(docObj) {
64 | return new Promise(function(resolve, reject) {
65 | var epubMeta = `
66 |
67 | ---
68 | title:
69 | - type: main
70 | text: ${docObj.title}
71 | creator:
72 | - role: author
73 | text: ${docObj.author}
74 | rights: ${docObj.licenceUrl}
75 | include-before: Documentation for ${docObj.title} ([${docObj.docsUrl}](${docObj.docsUrl})) generated by docs2epub ([http://javier.xyz/docs2epub/](http://javier.xyz/docs2epub/)) on ${moment().format('YYYY/MM/DD')}.
76 | date: ${moment().format('YYYY/MM/DD')}
77 | description: Documentation for ${docObj.title} ([${docObj.docsUrl}](${docObj.docsUrl})) generated by docs2epub ([http://javier.xyz/docs2epub/](http://javier.xyz/docs2epub/)) on ${moment().format('YYYY/MM/DD')}.
78 | ...
79 |
80 | `;
81 | fs.writeFile(`_tmp/epub/${slug(docObj.title)}/meta.txt`, epubMeta, (err, res) => {
82 | if (err) {
83 | reject(err);
84 | return;
85 | }
86 | resolve(res);
87 | });
88 | });
89 | }
90 |
91 | function generateEpubFromMarkdown(docObj) {
92 | return new Promise(function(resolve, reject) {
93 | execCommand(`rm -rf _tmp/epub/${slug(docObj.title)} && mkdir -p _tmp/epub/${slug(docObj.title)}`, () => {
94 | async.map(
95 | docObj.content,
96 | (tocEl, cb) => {
97 | if (tocEl.result) {
98 | fs.writeFile(`_tmp/epub/${slug(docObj.title)}/${tocEl.index}.md`, tocEl.result.content, cb);
99 | }
100 | },
101 | (err, res) => {
102 | if (err) {
103 | reject(err);
104 | return;
105 | }
106 | var pandocCommand = `pandoc -s -o docs/download/${docObj.title.toLowerCase()}.epub _tmp/epub/${slug(docObj.title)}/meta.txt `;
107 | pandocCommand += _.map(docObj.content, tocEl => `_tmp/epub/${slug(docObj.title)}/${tocEl.index}.md `).join(
108 | ''
109 | );
110 |
111 | if (docObj.cover) {
112 | pandocCommand += `--epub-cover-image=${docObj.cover} `;
113 | }
114 |
115 | if (docObj.epubStylesheet) {
116 | pandocCommand += `--epub-stylesheet=${docObj.epubStylesheet} `;
117 | }
118 |
119 | if (docObj.epubTOCDepth) {
120 | pandocCommand += `--table-of-contents --toc-depth=${docObj.epubTOCDepth}`;
121 | }
122 |
123 | generateEpubMetadata(docObj).then(
124 | () => {
125 | execCommand(pandocCommand, () => {
126 | console.log('Done.');
127 | });
128 | },
129 | reject
130 | );
131 | }
132 | );
133 | });
134 | });
135 | }
136 |
137 | run(strategyToRun)
138 | .then(tocArray => {
139 | if (tocArray.type === 'MARKDOWN') {
140 | generateEpubFromMarkdown(tocArray).catch(err => console.log(err));
141 | } else {
142 | generateEpubFromHtml(tocArray);
143 | generateHtmlFromHtml(tocArray);
144 | }
145 | })
146 | .catch(err => {
147 | console.log(err.stack);
148 | });
149 |
--------------------------------------------------------------------------------
/src/strategies/react/scrapperMd.js:
--------------------------------------------------------------------------------
1 | const axios = require('axios')
2 | const _ = require('lodash')
3 | const async = require('async')
4 |
5 | const CONFIG = require('./index.js')
6 |
7 | var docList = [{
8 | title: 'Getting started',
9 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/getting-started.md'
10 | }, {
11 | title: 'Tutorial',
12 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/tutorial.md'
13 | }, {
14 | title: 'Thinking in react',
15 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/thinking-in-react.md'
16 | }, {
17 | title: 'Why react',
18 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/01-why-react.md'
19 | }, {
20 | title: 'Displaying data',
21 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/02-displaying-data.md'
22 | }, {
23 | title: 'JSX in depth',
24 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/02.1-jsx-in-depth.md'
25 | }, {
26 | title: 'JSX spread',
27 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/02.2-jsx-spread.md'
28 | }, {
29 | title: 'JSX gotchas',
30 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/02.3-jsx-gotchas.md'
31 | }, {
32 | title: 'Interactivity and dynamic uis',
33 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/03-interactivity-and-dynamic-uis.md'
34 | }, {
35 | title: 'Multiple components',
36 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/04-multiple-components.md'
37 | }, {
38 | title: 'Reusable components',
39 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/05-reusable-components.md'
40 | }, {
41 | title: 'Transferring props',
42 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/06-transferring-props.md'
43 | }, {
44 | title: 'Forms',
45 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/07-forms.md'
46 | }, {
47 | title: 'Working with the browser',
48 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/08-working-with-the-browser.md'
49 | }, {
50 | title: 'More about refs',
51 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/08.1-more-about-refs.md'
52 | }, {
53 | title: 'Tooling integration',
54 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/09-tooling-integration.md'
55 | }, {
56 | title: 'Language tooling',
57 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/09.1-language-tooling.md'
58 | }, {
59 | title: 'Package management',
60 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/09.2-package-management.md'
61 | }, {
62 | title: 'Environments',
63 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/09.3-environments.md'
64 | }, {
65 | title: 'Addons',
66 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10-addons.md'
67 | }, {
68 | title: 'Animation',
69 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.1-animation.md'
70 | }, {
71 | title: 'Form input binding sugar',
72 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.2-form-input-binding-sugar.md'
73 | }, {
74 | title: 'Class name manipulation',
75 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.3-class-name-manipulation.md'
76 | }, {
77 | title: 'Test utils',
78 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.4-test-utils.md'
79 | }, {
80 | title: 'Clone with props',
81 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.5-clone-with-props.md'
82 | }, {
83 | title: 'Create fragment',
84 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.6-create-fragment.md'
85 | }, {
86 | title: 'Update',
87 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.7-update.md'
88 | }, {
89 | title: 'Pure render mixin',
90 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.8-pure-render-mixin.md'
91 | }, {
92 | title: 'Perf',
93 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.9-perf.md'
94 | }, {
95 | title: 'Shallow compare',
96 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/10.10-shallow-compare.md'
97 | }, {
98 | title: 'Advanced performance',
99 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/11-advanced-performance.md'
100 | }, {
101 | title: 'Context',
102 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/12-context.md'
103 | }, {
104 | title: 'Top level api',
105 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-01-top-level-api.md'
106 | }, {
107 | title: 'Component api',
108 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-02-component-api.md'
109 | }, {
110 | title: 'Component specs',
111 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-03-component-specs.md'
112 | }, {
113 | title: 'Tags and attributes',
114 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-04-tags-and-attributes.md'
115 | }, {
116 | title: 'Events',
117 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-05-events.md'
118 | }, {
119 | title: 'Dom differences',
120 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-06-dom-differences.md'
121 | }, {
122 | title: 'Special non dom attributes',
123 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-07-special-non-dom-attributes.md'
124 | }, {
125 | title: 'Reconciliation',
126 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-08-reconciliation.md'
127 | }, {
128 | title: 'Webcomponents',
129 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-09-webcomponents.md'
130 | }, {
131 | title: 'Glossary',
132 | url: 'https://raw.githubusercontent.com/facebook/react/master/docs/docs/ref-10-glossary.md'
133 | }]
134 |
135 | docList = _.map(docList, (el, idx) => {
136 | el.index = ('000' + idx).slice(-3)
137 | return el
138 | })
139 |
140 | function requestUrl (doc, cb) {
141 | axios.get(doc.url).then(res => {
142 | console.log('READED', doc.url)
143 | cb(null, _.assign({}, doc, {
144 | result: {
145 | title: doc.title,
146 | content: `\n# ${doc.title}\n\n` + res.data
147 | .replace(/\]\(\/react\/img/g, '](https://raw.githubusercontent.com/facebook/react/master/docs/img')
148 | .replace(//, 'See [$1]($1)')
149 | }
150 | }))
151 | }, (err) => {
152 | cb(err)
153 | })
154 | }
155 |
156 | function strategy () {
157 | return new Promise(function (resolve, reject) {
158 | async.map(docList, requestUrl, function (asyncErr, asyncRes) {
159 | if (asyncErr) {
160 | reject(asyncErr)
161 | return
162 | }
163 |
164 | resolve(
165 | _.assign({}, CONFIG, {
166 | content: asyncRes
167 | })
168 | )
169 | })
170 | })
171 | }
172 |
173 | module.exports = strategy
174 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | docs2epub
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
45 |
46 |
47 |
48 |
Library
49 |
50 |
51 |
52 |
53 |
React
54 |
Updated 09/02/2016
55 |
58 |
59 |
60 |
61 |
62 |
Lodash
63 |
Updated 09/02/2016
64 |
67 |
68 |
69 |
70 |
71 |
Sass
72 |
Updated 09/04/2016
73 |
76 |
77 |
78 |
79 |
80 |
Underscore
81 |
Updated 09/02/2016
82 |
85 |
86 |
87 |
88 |
89 |
express
90 |
Updated 09/02/2016
91 |
94 |
95 |
96 |
97 |
98 |
Apollo - React
99 |
Updated 02/25/2017
100 |
103 |
104 |
105 |
106 |
107 |
angular2
108 |
Updated 09/02/2016
109 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
stable
119 |
You may not be able to tell that this was scrapped from a website!
120 |
121 |
122 |
beta
123 |
Probably not everything looks pretty, but you should be able to understand the complete docs.
124 |
125 |
126 |
alpha
127 |
Some stuff may not be present, or not be understandable at all.
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
Want to know about new ebooks?
138 |
139 |
140 |
141 |
146 |
157 |
158 |
159 |
160 | Max one email per week, promise 🙌
161 |
162 |
163 |
164 |
165 |
170 |
171 |
172 |
173 |
181 |
182 |
183 |
--------------------------------------------------------------------------------