@braindev/pro-ffa
Version:
The iconic font, CSS, and SVG framework
175 lines (142 loc) • 4.54 kB
JavaScript
const HttpsProxyAgent = require('https-proxy-agent')
const fetch = require("node-fetch")
const writeFile = require('write')
const path = require("path")
const del = require("del")
const urlLib = require("url")
const fs = require("fs")
const { pullAll } = require("lodash")
const config = {
disPath: 'dist/',
version: 'v5.8.1',
}
const defaultOptions = {
link: `https://pro.fontawesome.com/releases/${config.version}/`,
cssPath: "css/all.css",
cssHeaders: {
"DNT": 1,
"Referer": "https://fontawesome.com/icons?d=gallery",
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36"
},
fontsHeaders: {
"Origin": "https://fontawesome.com",
"Referer": `https://pro.fontawesome.com/releases/${config.version}/css/all.css`
},
agent: process.env.npm_config_proxy ? new HttpsProxyAgent(process.env.npm_config_proxy) : false
}
function fullDistPath() {
if(!this.mem)
this.mem = path.resolve(__dirname, '..', config.disPath)
return this.mem
}
function url(filename, link = defaultOptions.link) {
return urlLib.resolve(link, filename)
}
function dist(filename) {
return path.resolve(fullDistPath(), filename)
}
function getLocalFilePath(files) {
files = files ? files : []
return files.filter(f => f.indexOf('.css') > -1 && f.indexOf(fullDistPath()) > -1).shift()
}
function catchAndExit(err) {
console.error(err)
process.exit(0)
}
function write(filename, body) {
return new Promise((resolve, reject) => {
const distStream = writeFile.stream(dist(filename));
body.pipe(distStream);
body.on('error', err => {
reject(err);
});
distStream.on('finish', () => {
resolve(dist(filename));
});
distStream.on('error', err => {
reject(err);
});
}).catch(catchAndExit)
}
function getFonts(css) {
return new Promise((resolve, reject) => {
fs.readFile(css, 'utf8', (err, data) => {
if (err) {
return reject(err)
}
let RegEx = /url\(([^\)]+)\)/g,
matches = data.match(RegEx);
if(matches) {
matches = new Set(matches.map(text => text.replace(RegEx, "$1").replace(/(\?|\#).*$/, "").replace('../', '')))
return resolve([ ...matches ])
}
return resolve([])
});
}).catch(catchAndExit)
}
class Installer {
constructor(options = {}) {
this.options = Object.assign({}, defaultOptions, options)
}
check(filename) {
return new Promise((resolve, reject) => {
let { link } = this.options,
localFile = dist(filename),
remoteFile = url(filename, link)
fs.open(localFile, 'r', (err, fd) => {
if(err) {
if(err.code === 'ENOENT') {
this._files.push(remoteFile)
return resolve(false);
}
return reject(err);
}
this._files.push(localFile)
resolve(localFile)
});
}).catch(catchAndExit)
}
download(mute = false) {
let { agent, link, cssHeaders, fontsHeaders } = this.options,
toDownload = this._files.filter(fp => fp.includes(link));
if(toDownload.length) {
if(!mute) console.log(`Creating tasks for downloading files...`)
pullAll(this._files, toDownload);
toDownload = toDownload.map(urlPath => {
let localPath = urlPath.replace(link, ''),
headers = Object.assign({}, cssHeaders, (!urlPath.includes('all.css') ? fontsHeaders : {}))
return fetch(urlPath, { headers, agent })
.then(res => write(localPath, res.body))
.catch(err => {
console.error(`Error fetching url: ${urlPath}`)
console.error(err);
})
});
return Promise.all(toDownload).then(data => {
if(!mute) console.log(`Downloaded ${data.length} files`)
this._files = this._files.concat(data)
return data
}).catch(catchAndExit);
}
return false
}
async files() {
if(!this._files) {
this._files = []
let localFile = await this.check(this.options.cssPath)
if(!localFile) {
let downloadedFiles = await this.download(true);
localFile = getLocalFilePath(downloadedFiles);
}
if(localFile) {
let fonts = await getFonts(localFile)
await Promise.all(fonts.map(fp => this.check(fp)))
}
}
return Promise.resolve(this._files)
}
}
const model = new Installer()
model.files().then(files => model.download()).then(downloaded => {
console.log(`Done. ${(downloaded ? 'Current': 'Loaded')} version: ${config.version}`);
}).catch(catchAndExit);