UNPKG

@braindev/pro-ffa

Version:

The iconic font, CSS, and SVG framework

175 lines (142 loc) 4.54 kB
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);