diff --git a/.gitignore b/.gitignore index 9ca15fa..2d270a6 100644 --- a/.gitignore +++ b/.gitignore @@ -60,5 +60,5 @@ typings/ lib/ tests/index.html - -index.html \ No newline at end of file +index.html +.vscode \ No newline at end of file diff --git a/index.d.ts b/index.d.ts index 8f067ed..b737192 100644 --- a/index.d.ts +++ b/index.d.ts @@ -3,9 +3,14 @@ // Definitions by: Sam Pastoriza // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +interface Options { + removeLineNumbers: boolean; + removeFooter: footer; +} + /** * Comverts the gist or github link to html * @param type Either gist or github * @param link The link to the github file or gist link */ -export default function gistify(link: string): Promise; \ No newline at end of file +export default function gistify(link: string, options?: Options): Promise; \ No newline at end of file diff --git a/src/converters/gist.js b/src/converters/gist.js new file mode 100644 index 0000000..58cb958 --- /dev/null +++ b/src/converters/gist.js @@ -0,0 +1,85 @@ +'use strict'; + +import { minify } from 'html-minifier'; +import cheerio from 'cheerio'; + +function removeLines($, lineNumbers) { + const start = lineNumbers.startLine; + const end = lineNumbers.endLine; + const gistName = lineNumbers.gistName; + let i = 0; + + while (true) { + i++; + if (i >= start && i <= end) { + continue; + } + const line = $(`#${gistName}L${i}`).get(); + + if (line.length > 0) { + $(`#${gistName}L${i}`).remove(); + $(`#${gistName}LC${i}`).remove(); + } else { + break; + } + } +} + +function retrieveGist(response, options) { + return new Promise((resolve, reject) => { + try { + if (response && response.div) { + + if (response.stylesheet) { + + if (response.stylesheet.indexOf('`; + + resolve({ + html: minify(stylesheet + '\n' + file, { + conservativeCollapse: true + }), + file: minify(file, { + conservativeCollapse: true + }), + stylesheet: minify(stylesheet, { + conservativeCollapse: true + }) + }); + } else { + reject('Failed to load gist'); + } + } catch (e) { + reject('Failed to load gist'); + } + }); +} + +export default retrieveGist; diff --git a/src/converters/github.js b/src/converters/github.js new file mode 100644 index 0000000..e3f4407 --- /dev/null +++ b/src/converters/github.js @@ -0,0 +1,86 @@ +'use strict'; + +import { minify } from 'html-minifier'; +import cheerio from 'cheerio'; + +function removeLines($, lineNumbers) { + const start = lineNumbers.startLine; + const end = lineNumbers.endLine; + let i = 0; + + while (true) { + i++; + if (i >= start && i <= end) { + continue; + } + const line = $(`#L${i}`).get(); + + if (line.length > 0) { + $(`#L${i}`).remove(); + $(`#LC${i}`).remove(); + } else { + break; + } + } +} + +function convertGithubCode(body, url, filename, options) { + return new Promise((resolve, reject) => { + try { + const $ = cheerio.load(body); + let styles = ''; + let rawURL = $('#raw-url').attr('href'); + + rawURL = 'https://raw.githubusercontent.com' + rawURL.replace('/raw', ''); + + $('.file-header').remove(); + $('.BlobToolbar').remove(); + + if (options.removeLineNumbers) { + $('.blob-num').remove(); + } + if (options.lineNumbers) { + removeLines($, options.lineNumbers); + } + + let file = $('.file').html(); + + $('link[rel=stylesheet]').each(function (index, element) { + const href = $(this).attr('href'); + + if (href.indexOf('frameworks-') === -1) { + styles += $.html(this); + } + }); + styles = styles + ''; // eslint-disable-line + + if (options.removeFooter) { + file = `
${file}
`; + } else { + let meta = ` +
+ view raw + ${filename} hosted with ❤ by GitHub +
`; + + file = `
${file}${meta}
`; + } + + resolve({ + styles: minify(styles, { + conservativeCollapse: true + }), + file: minify(file, { + conservativeCollapse: true + }), + html: minify(styles + file, { + conservativeCollapse: true + }) + }); + } catch(e) { + reject('Failed to load github file. Please check the url'); + } + }); +} + +export default convertGithubCode; diff --git a/src/index.js b/src/index.js index 33f96c9..f29d335 100644 --- a/src/index.js +++ b/src/index.js @@ -1,104 +1,54 @@ 'use strict'; import request from 'request'; -import cheerio from 'cheerio'; -import { minify } from 'html-minifier'; import isUrl from 'is-url'; - -function retrieveGist(response) { - return new Promise((resolve, reject) => { - try { - // the html payload is in the div property - if (response && response.div) { - // github returns /assets/embed-id.css now, but let's be sure about that - if (response.stylesheet) { - // github passes down html instead of a url for the stylehsheet now - // parse off the href - if (response.stylesheet.indexOf('`; - - resolve({ - html: minify(stylesheet + '\n' + response.div, { - conservativeCollapse: true - }), - file: minify(response.div, { - conservativeCollapse: true - }), - stylesheet: minify(stylesheet, { - conservativeCollapse: true - }) - }); - } else { - reject('Failed to load gist'); +import retrieveGist from './converters/gist'; +import convertGithubCode from './converters/github'; + +// https://gist.github.com/pastorsj/dcb242de864e5d2b1c552783a7a00794#file-test-js-L1-L3 +// https://github.com/pastorsj/blog-api/blob/master/index.html#L15-L22 +function hasLineNumbers(link) { + const lineNumbers = link.split('#').slice(-1)[0]; + + if (lineNumbers) { + const linesExtractor = /L\d+-L\d+/g; + const lines = lineNumbers.match(linesExtractor); + + if (lines.length > 0) { + const lineExtractor = /L\d+/g; + const lineRange = lines[0]; + const gistName = lineNumbers.substring(0, lineNumbers.length - lineRange.length); + const lineArray = lineRange.match(lineExtractor); + + if (lineArray.length === 2) { + const startLine = lineArray[0].slice(1); + const endLine = lineArray[1].slice(1); + + return { + startLine: parseInt(startLine, 10), + endLine: parseInt(endLine, 10), + gistName + }; } - } catch (e) { - reject('Failed to load gist'); } - }); + } + return false; } -function convertGithubCode(body, url, filename) { - return new Promise((resolve, reject) => { - try { - const $ = cheerio.load(body); - let styles = ''; - let rawURL = $('#raw-url').attr('href'); - - rawURL = 'https://raw.githubusercontent.com' + rawURL.replace('/raw', '');; - $('.file-header').remove(); - $('.BlobToolbar').remove(); - let file = $('.file').html(); - - $('link[rel=stylesheet]').each(function (index, element) { - const href = $(this).attr('href'); - - if (href.indexOf('frameworks-') === -1) { - styles += $.html(this); - } - }); - styles = styles + ''; // eslint-disable-line - - let meta = `
- view raw - ${filename} hosted with ❤ by GitHub -
`; - - file = `
${file}${meta}
`; - - resolve({ - styles: minify(styles, { - conservativeCollapse: true - }), - file: minify(file, { - conservativeCollapse: true - }), - html: minify(styles + file, { - conservativeCollapse: true - }) - }); - } catch(e) { - reject('Failed to load github file. Please check the url'); - } - }); +function stripLineNumbers(link) { + return link.split('#')[0]; } -export default function gistify(link) { +function gistify(link, options = {}) { try { if (isUrl(link)) { if(link.includes('gist.github.com')) { + const lineNumbers = hasLineNumbers(link); + + if (lineNumbers) { + options.lineNumbers = lineNumbers; + link = stripLineNumbers(link); + } // It is a GIST url const id = link.split('/').slice(-1)[0]; @@ -111,7 +61,7 @@ export default function gistify(link) { reject('An error has occured', err); } if (body) { - retrieveGist(JSON.parse(body)) + retrieveGist(JSON.parse(body), options) .then((response) => resolve(response)) .catch((err) => reject(err)); } else { @@ -120,6 +70,12 @@ export default function gistify(link) { }); }); } else if (link.includes('github.com')) { + const lineNumbers = hasLineNumbers(link); + + if (lineNumbers) { + options.lineNumbers = lineNumbers; + link = stripLineNumbers(link); + } // It is a github link return new Promise((resolve, reject) => { const url = link; @@ -129,7 +85,7 @@ export default function gistify(link) { if (err) { reject(err); } - convertGithubCode(body, url, filename) + convertGithubCode(body, url, filename, options) .then(result => resolve(result)) .catch(err => reject(err)); }); @@ -151,7 +107,7 @@ export default function gistify(link) { try { const parsedBody = JSON.parse(body); - retrieveGist(parsedBody) + retrieveGist(parsedBody, options) .then((response) => resolve(response)) .catch((err) => reject(err)); } catch (e) { @@ -168,3 +124,5 @@ export default function gistify(link) { return Promise.reject('An error has occured', e); } } + +export default gistify; diff --git a/tests/test.js b/tests/test.js index cec24ff..bb78040 100644 --- a/tests/test.js +++ b/tests/test.js @@ -19,7 +19,7 @@ const fs = require('fs'); // console.error(err); // }); -// converter('https://gist.github.com/pastorsj/dcb242de864e5d2b1c552783a7a00794') +// converter('https://gist.github.com/pastorsj/dcb242de864e5d2b1c552783a7a00794#file-test-js-L1-L2') // .then((result) => { // fs.writeFileSync('index.html', result.html); // }) @@ -27,7 +27,7 @@ const fs = require('fs'); // console.error(err); // }); -converter('https://github.com/staltz/react-native-node/blob/master/android/build.gradle') +converter('https://github.com/pastorsj/blog-api/blob/master/index.html#L15-L22') .then((result) => { fs.writeFileSync('index.html', result.html); }) @@ -35,6 +35,14 @@ converter('https://github.com/staltz/react-native-node/blob/master/android/build console.error(err); }); +// converter('https://github.com/staltz/react-native-node/blob/master/android/build.gradle') +// .then((result) => { +// fs.writeFileSync('index.html', result.html); +// }) +// .catch((err) => { +// console.error(err); +// }); + // converter('fs;kladjfoj349jf;') // .then((result) => { // fs.writeFileSync('index.html', result.html);