Comparing version 0.1.0 to 1.0.0
@@ -5,4 +5,8 @@ #!/usr/bin/env node | ||
var path = require('path'); | ||
var findit = require('findit'); | ||
var color = require('cli-color'); | ||
var cErr = color.red; | ||
var cOk = color.green; | ||
var cInfo = color.blue; | ||
var Bolivar = require('../index.js'); | ||
@@ -12,8 +16,5 @@ | ||
.script('bolivar') | ||
.help('Get independant from external css, js and images'); | ||
parser.command('start') | ||
.help('Get independant from external css, js and images') | ||
.option('root', { | ||
abbr: 'r', | ||
default: process.cwd(), | ||
position: 0, | ||
help: 'The root directory to work on' | ||
@@ -53,37 +54,39 @@ }) | ||
}) | ||
.help('Start the replacing') | ||
.callback(function(options) { | ||
start(options); | ||
}) | ||
; | ||
parser.parse(); | ||
var options = parser.nom(); | ||
function start(options) { | ||
options.paths = { | ||
css: path.join(options.parent, options.css, options.child), | ||
js: path.join(options.parent, options.js, options.child), | ||
img: path.join(options.parent, options.img, options.child) | ||
}; | ||
if(!options.root) { | ||
parser.print(parser.getUsage()); | ||
process.exit(); | ||
} | ||
var bolivar = new Bolivar(options); | ||
options.paths = { | ||
css: path.join(options.parent, options.css, options.child), | ||
js: path.join(options.parent, options.js, options.child), | ||
img: path.join(options.parent, options.img, options.child) | ||
}; | ||
if(!options.silent) { | ||
console.log('Root ' + options.root); | ||
bolivar.on('file', function(data) { | ||
console.log('File: ' + data.name); | ||
}); | ||
options.root = path.resolve(options.root); | ||
var bolivar = new Bolivar(options); | ||
bolivar.on('url', function(data) { | ||
console.log('* ' + data.url); | ||
}); | ||
} | ||
if(!options.silent) { | ||
console.log(cInfo('Root: ' + options.root)); | ||
if(!options.force && !fs.existsSync(path.join(options.root, '.git'))) { | ||
console.error('No .git found in root. Use -f if you are sure what you are doing.'); | ||
process.exit(); | ||
} | ||
bolivar.on('file', function(data) { | ||
console.log('File: ' + data.name); | ||
}); | ||
bolivar.start(); | ||
bolivar.on('url', function(data) { | ||
console.log('\uD83C\uDF0E ' + data.url); | ||
console.log(' \u21B3 ' + cOk(data.path)); | ||
}); | ||
} | ||
if(!options.force && !fs.existsSync(path.join(options.root, '.git'))) { | ||
console.error(cErr('Warning: No .git found in root. Use -f if you are sure what you are doing.')); | ||
process.exit(); | ||
} | ||
bolivar.start(); |
166
index.js
var fs = require('fs'); | ||
var http = require('http'); | ||
var path = require('path'); | ||
var urlParse = require('url').parse; | ||
var util = require('util'); | ||
var EventEmitter = require('events').EventEmitter; | ||
var cheerio = require('cheerio'); | ||
var findit = require('findit'); | ||
var sar = require('search-act-replace'); | ||
var getAccepted = require('get-accepted'); | ||
var mkdir = require('mkdirp'); | ||
// Helper | ||
var isExternal = function(path) { | ||
return path && path.indexOf('//') > -1; | ||
}; | ||
var completeUrl = function(url) { | ||
@@ -31,67 +28,128 @@ // Assuming it is an URL not a local path | ||
if(!options.paths.img) options.paths.img = 'img'; | ||
if(!options.paths.fonts) options.paths.fonts = 'fonts'; | ||
options.filetypes = { | ||
css: { | ||
exts: ['.css'], | ||
mimes: ['text/css'] | ||
}, | ||
js: { | ||
exts: ['.js'], | ||
mimes: ['application/javascript', 'application/x-javascript', 'application/ecmascript'] | ||
}, | ||
img: { | ||
exts: ['.jpg', '.jpeg', '.png', '.gif'], | ||
mimes: ['image/gif', 'image/jpeg', 'image/png'] | ||
}, | ||
fonts: { | ||
exts: ['.ttf', '.eot', '.woff', '.svg'], | ||
mimes: ['application/x-font-ttf'] | ||
} | ||
} | ||
// This Url RegEx probably needs improvement... | ||
options.regex = /(https?:)?\/\/([\w\-]\.?)+(\/[\w\.\-]+)+\/?(\?(\w+(=\w+)?(\&\w+(=\w+)?)*)?)?/g; | ||
this.options = options; | ||
} | ||
Bolivar.prototype.start = function() { | ||
Bolivar.prototype.start = function () { | ||
var self = this; | ||
self.finder = findit(self.options.root); | ||
sar(self.options.root, self.options.regex, matchedUrl) | ||
.on('end',function () { | ||
self.emit('end'); | ||
}) | ||
; | ||
self.finder.on('directory', function (dir, stat, stop) { | ||
var base = path.basename(dir); | ||
if (base === '.git' || base === 'node_modules') stop(); | ||
}); | ||
self.finder.on('file', function (file, stat) { | ||
var relFile = path.relative(self.options.root, file); | ||
if(path.extname(file) === '.html') { | ||
self.emit('file', {name: relFile}); | ||
self.freeFile(self.options.root, relFile); | ||
function matchedUrl(match, file, replace) { | ||
var url = completeUrl(match[0]); | ||
var filetypes = self.options.filetypes; | ||
var fileExt = path.extname(urlParse(url).pathname); | ||
if (fileExt) { | ||
// by file extension | ||
for(filetype in filetypes) { | ||
var exts = filetypes[filetype].exts; | ||
if (exts.indexOf(fileExt) > -1) { | ||
self.extDownload(url, filetype, replace); | ||
return; | ||
} | ||
} | ||
}); | ||
replace(false); | ||
} else { | ||
// by mime type | ||
self.mimeDownload(url, replace); | ||
} | ||
} | ||
} | ||
self.finder.on('end', self.emit.bind(self, 'end')); | ||
}; | ||
Bolivar.prototype.stop = function() { | ||
this.finder.stop(); | ||
}; | ||
Bolivar.prototype.mimeDownload = function (url, replace) { | ||
var self = this; | ||
var filetypes = self.options.filetypes; | ||
var mimetypes = []; | ||
for(filetype in filetypes) { | ||
mimetypes = mimetypes.concat(filetypes[filetype].mimes); | ||
} | ||
getAccepted(url, mimetypes, function (res) { | ||
if(res) { | ||
var type; | ||
var mime = res.headers['content-type']; | ||
for(filetype in filetypes) { | ||
var mimes = filetypes[filetype].mimes; | ||
if (mimes.indexOf(mime) > -1) { | ||
type = filetype; | ||
} | ||
} | ||
self.saveLocally(url, res, type, replace); | ||
} else { | ||
replace(false); | ||
} | ||
}) | ||
} | ||
Bolivar.prototype.freeFile = function(root, relFile) { | ||
Bolivar.prototype.saveLocally = function (url, res, type, replace) { | ||
// Takes the FileStream and saves it | ||
this.emit('download', {url: url}); | ||
var self = this; | ||
var filepath = path.join(root, relFile); | ||
var file = fs.readFileSync(filepath); | ||
var $ = cheerio.load(file.toString()); | ||
var filename = url.split('/').pop(); | ||
var savePathRel = this.options.paths[type]; | ||
var savePathFull = path.join(this.options.root, savePathRel); | ||
mkdir(savePathFull); | ||
var intFile = fs.createWriteStream(path.join(savePathFull, filename)); | ||
if (savePathRel) { | ||
res | ||
.pipe(intFile) | ||
.on('finish', function () { | ||
var replacePath = path.join('/', savePathRel, filename); | ||
replace(replacePath); | ||
self.emit('url', {url: url, path: replacePath}); | ||
}) | ||
; | ||
} else { | ||
replace(false); | ||
} | ||
} | ||
var saveLocally = function(selector, attrName, type) { | ||
$(selector).each(function(i, elem) { | ||
var url = $(this).attr(attrName); | ||
localPath = self.downloadLocally(type, url); | ||
$(this).attr(attrName, localPath); | ||
}); | ||
}; | ||
Bolivar.prototype.extDownload = function(url, type, replace) { | ||
// checks before if it should download | ||
var self = this; | ||
saveLocally('link[rel=stylesheet]', 'href', 'css'); | ||
saveLocally('script', 'src', 'js'); | ||
saveLocally('img', 'src', 'img'); | ||
fs.writeFileSync(filepath, $.html()); | ||
}; | ||
if (!type) { | ||
replace(false); | ||
return; | ||
} | ||
url = completeUrl(url); | ||
Bolivar.prototype.downloadLocally = function(type, url) { | ||
if(isExternal(url)) { | ||
url = completeUrl(url); | ||
var filename = url.split('/').pop(); | ||
this.emit('url', {url: url}); | ||
var savePath = this.options.paths[type]; | ||
var intFile = fs.createWriteStream(path.join(this.options.root, savePath, filename)); | ||
http.get(url, function(extFile) { | ||
extFile.pipe(intFile); | ||
}); | ||
return path.join('/', savePath, filename); | ||
} else { | ||
return url; | ||
} | ||
http.get(url, function(res) { | ||
self.saveLocally(url, res, type, replace); | ||
}); | ||
}; | ||
module.exports = Bolivar; |
{ | ||
"name": "bolivar", | ||
"version": "0.1.0", | ||
"version": "1.0.0", | ||
"description": "Get independant from external css, js and images", | ||
@@ -10,3 +10,3 @@ "main": "index.js", | ||
"scripts": { | ||
"test": "mocha test/test.js" | ||
"test": "mocha -R spec test/test.js" | ||
}, | ||
@@ -21,10 +21,13 @@ "repository": { | ||
"dependencies": { | ||
"cheerio": "~0.15.0", | ||
"findit": "~1.1.1", | ||
"nomnom": "~1.6.2" | ||
"cli-color": "~0.3.2", | ||
"get-accepted": "0.0.1", | ||
"mkdirp": "^0.5.0", | ||
"nomnom": "~1.6.2", | ||
"search-act-replace": "0.1.0" | ||
}, | ||
"devDependencies": { | ||
"mocha": "~1.18.2", | ||
"mkdirp": "~0.5.0" | ||
"tmp": "0.0.23", | ||
"nock": "~0.31.1" | ||
} | ||
} |
# Bolivar | ||
[![Build Status](https://travis-ci.org/finnp/node-bolivar.svg?branch=master)](https://travis-ci.org/finnp/node-bolivar) | ||
> Get independant from external css, js and images | ||
@@ -36,3 +36,3 @@ | ||
You can also use bolivar via require. It will not `console.log` messages but emit | ||
`file` and `url` events as well as an `end` event. | ||
`file`, `url` and `download` events as well as an `end` event. | ||
```javascript | ||
@@ -39,0 +39,0 @@ var bolivar = require('bolivar'); |
@@ -8,5 +8,7 @@ http://ajax.googleapis.com/ajax/libs/angularjs/1.2.15/angular.min.js | ||
http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css | ||
http://fonts.googleapis.com/css?family=Roboto | ||
http://weloveiconfonts.com/api/?family=brandico | ||
http://cdn.jsdelivr.net/16pixels/0.1/16pixels.css | ||
http://farm8.staticflickr.com/7456/14154949784_3399df86ff_n.jpg | ||
http://weloveiconfonts.com/api/fonts/brandico/brandico.eot | ||
http://weloveiconfonts.com/api/fonts/brandico/brandico.eot? | ||
http://weloveiconfonts.com/api/fonts/brandico/brandico.woff | ||
http://weloveiconfonts.com/api/fonts/brandico/brandico.ttf |
154
test/test.js
var os = require('os'); | ||
var fs = require('fs'); | ||
var path = require('path'); | ||
var mocha = require('mocha'); | ||
var mkdir = require('mkdirp').sync; | ||
var tmpdir = require('tmp').dir; | ||
var nock = require('nock'); | ||
var bolivar = require('../index.js'); | ||
var urlParse = require('url').parse; | ||
describe('bolivar', function () { | ||
var tmp; | ||
function mockUrls(id) { | ||
var urls = fs.readFileSync(path.join(__dirname, id + '-urls.txt'), 'utf-8').trim().split('\n'); | ||
before(function () { | ||
tmp = os.tmpdir(); | ||
mkdir(tmp + 'css'); | ||
mkdir(tmp + 'js'); | ||
mkdir(tmp + 'img'); | ||
// mocking urls | ||
var mocks = []; | ||
urls.forEach(function (urlRaw) { | ||
url = urlParse(urlRaw); | ||
baseUrl = url.protocol + '//' + url.host; | ||
mocks.push(nock(baseUrl).get(url.path).reply(200, 'OK')); | ||
}); | ||
it('should detect the correct urls', function (done) { | ||
var urls = fs.readFileSync(__dirname + '/detect-urls.txt', 'utf-8').trim().split('\n'); | ||
return mocks; | ||
} | ||
fs.createReadStream(__dirname + '/detect.html') | ||
.pipe(fs.createWriteStream(tmp + 'detect.html')) | ||
describe('bolivar', function () { | ||
var tmp; | ||
before(function (done) { | ||
// Tempdir | ||
tmpdir({unsafeCleanup: true}, function (err, tmpPath) { | ||
if(err) throw err; | ||
mkdir(path.join(tmpPath, 'css')); // one already exists | ||
tmp = tmpPath; | ||
done(); | ||
}); | ||
// no real http calls here | ||
nock.disableNetConnect(); | ||
}); | ||
// files: detect.html detect-urls.txt | ||
it('should detect the correct urls', function (done) { | ||
// mocking urls | ||
var mocks = mockUrls('detect'); | ||
fs.createReadStream(path.join(__dirname, 'detect.html')) | ||
.pipe(fs.createWriteStream(path.join(tmp, 'detect.html'))) | ||
; | ||
bolivar({root: tmp}) | ||
.on('end', function () { | ||
var missed = mocks.filter(function (url) { | ||
return !url.isDone(); | ||
}) | ||
if (missed.length === 0) { | ||
done(); | ||
} else { | ||
done('Missed ' + missed.length + ' urls. One is ' + missed[0].pendingMocks()); | ||
} | ||
}) | ||
.start() | ||
; | ||
}); | ||
// files: replace-ref.html replace.html replace-urls.txt | ||
it('should replace the urls properly', function (done) { | ||
mockUrls('replace'); | ||
fs.createReadStream(path.join(__dirname, 'replace.html')) | ||
.pipe(fs.createWriteStream(path.join(tmp, 'replace.html'))) | ||
; | ||
bolivar({root: tmp}) | ||
.on('url', function (data) { | ||
var index = urls.indexOf(data.url); | ||
if(index > -1) { | ||
urls.splice(index, 1); | ||
} else { | ||
done('Matched ' + data.url + ' as URL.'); | ||
} | ||
}) | ||
.on('end', function () { | ||
if (urls.length === 0) { | ||
var file = fs.readFileSync(path.join(tmp, 'replace.html'), 'utf-8'); | ||
var fRef = fs.readFileSync(path.join(__dirname, 'replace-ref.html'), 'utf-8'); | ||
if (file === fRef) { | ||
done(); | ||
} else { | ||
done('Missed ' + urls.length + ' urls.'); | ||
done(new Error('Wrong content')); | ||
} | ||
@@ -42,23 +87,54 @@ }) | ||
; | ||
}); | ||
}); | ||
it('should replace the urls properly', function (done) { | ||
fs.createReadStream(__dirname + '/replace.html') | ||
.pipe(fs.createWriteStream(tmp + 'replace.html')) | ||
; | ||
// file: header.html | ||
it('should detect headers properly of files without ending', function (done) { | ||
var mocks = [ | ||
nock('http://fonts.googleapis.com') | ||
.get('/css?family=Roboto') | ||
.reply(200, 'OK', { 'Content-Type': 'text/css'}), | ||
nock('http://test.de') | ||
.get('/dadimg') | ||
.reply(200, 'OK', { 'Content-Type': 'image/jpeg'}), | ||
nock('http://www.google.de') | ||
.get('/test') | ||
.reply(200, 'OK', { 'Content-Type': 'text/html'}) | ||
]; | ||
bolivar({root: tmp}) | ||
.on('end', function () { | ||
var file = fs.readFileSync(tmp + 'replace.html', 'utf-8'); | ||
var fRef = fs.readFileSync(__dirname + '/replace-ref.html', 'utf-8'); | ||
if (file === fRef) { | ||
done(); | ||
} else { | ||
done('Wrong content'); | ||
} | ||
}) | ||
.start() | ||
; | ||
fs.createReadStream(path.join(__dirname, 'header.html')) | ||
.pipe(fs.createWriteStream(path.join(tmp, 'header.html'))) | ||
; | ||
}) | ||
var urls = [ | ||
'http://fonts.googleapis.com/css?family=Roboto', | ||
'http://test.de/dadimg' | ||
] | ||
bolivar({root: tmp}) | ||
.on('url', function (data) { | ||
var pos; | ||
if (pos = urls.indexOf(data.url) > -1) { | ||
urls = urls.splice(pos, 1); | ||
} else { | ||
done(new Error('False hit')); | ||
} | ||
}) | ||
.on('end', function () { | ||
var missed = mocks.filter(function (url) { | ||
return !url.isDone(); | ||
}) | ||
if (missed.length === 0) { | ||
if (urls.length === 0) { | ||
done(); | ||
} else { | ||
done(new Error('Miss')); | ||
} | ||
} else { | ||
done(new Error('Missed ' + missed.length + ' urls. One is ' + missed[0].pendingMocks())); | ||
} | ||
}) | ||
.start() | ||
; | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
17743
14
355
1
5
3
2
+ Addedcli-color@~0.3.2
+ Addedget-accepted@0.0.1
+ Addedmkdirp@^0.5.0
+ Addedsearch-act-replace@0.1.0
+ Addedcli-color@0.3.3(transitive)
+ Addedd@0.1.11.0.2(transitive)
+ Addedes5-ext@0.10.64(transitive)
+ Addedes6-iterator@0.1.32.0.3(transitive)
+ Addedes6-symbol@2.0.13.1.4(transitive)
+ Addedes6-weak-map@0.1.4(transitive)
+ Addedesniff@2.0.1(transitive)
+ Addedevent-emitter@0.3.5(transitive)
+ Addedext@1.7.0(transitive)
+ Addedfindit@1.2.0(transitive)
+ Addedget-accepted@0.0.1(transitive)
+ Addedignore@2.2.19(transitive)
+ Addedlru-queue@0.1.0(transitive)
+ Addedmemoizee@0.3.10(transitive)
+ Addedminimist@1.2.8(transitive)
+ Addedmkdirp@0.5.6(transitive)
+ Addednext-tick@0.2.21.1.0(transitive)
+ Addedsearch-act-replace@0.1.0(transitive)
+ Addedtimers-ext@0.1.8(transitive)
+ Addedtype@2.7.3(transitive)
- Removedcheerio@~0.15.0
- Removedfindit@~1.1.1
- RemovedCSSselect@0.4.1(transitive)
- RemovedCSSwhat@0.4.7(transitive)
- Removedcheerio@0.15.0(transitive)
- Removedcore-util-is@1.0.3(transitive)
- Removeddom-serializer@0.2.2(transitive)
- Removeddomelementtype@1.3.12.3.0(transitive)
- Removeddomhandler@2.2.1(transitive)
- Removeddomutils@1.4.31.5.1(transitive)
- Removedentities@1.0.02.2.0(transitive)
- Removedfindit@1.1.1(transitive)
- Removedhtmlparser2@3.7.3(transitive)
- Removedinherits@2.0.4(transitive)
- Removedisarray@0.0.1(transitive)
- Removedlodash@2.4.2(transitive)
- Removedreadable-stream@1.1.14(transitive)
- Removedstring_decoder@0.10.31(transitive)