mirror of
https://github.com/tupadr3/plantuml-icon-font-sprites.git
synced 2026-01-08 02:31:59 +00:00
feat: Integrate build into this repo
This commit is contained in:
21
.editorconfig
Normal file
21
.editorconfig
Normal file
@@ -0,0 +1,21 @@
|
||||
# EditorConfig helps developers define and maintain consistent
|
||||
# coding styles between different editors and IDEs
|
||||
# editorconfig.org
|
||||
|
||||
root = true
|
||||
|
||||
|
||||
[*]
|
||||
|
||||
# Change these settings to your own preference
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
|
||||
# We recommend you to keep these unchanged
|
||||
end_of_line = lf
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
4
.eslintignore
Normal file
4
.eslintignore
Normal file
@@ -0,0 +1,4 @@
|
||||
# and /bower_components/* ignored by default
|
||||
|
||||
# Ignore built files except build/index.js
|
||||
/node_modules/*
|
||||
18
.eslintrc.json
Normal file
18
.eslintrc.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"root": true,
|
||||
"extends": "eslint:recommended",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
},
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"rules": {
|
||||
"no-console": 0
|
||||
},
|
||||
"globals": {
|
||||
"console": true,
|
||||
"log": true
|
||||
}
|
||||
}
|
||||
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
||||
* text=auto
|
||||
41
.gitignore
vendored
41
.gitignore
vendored
@@ -1,2 +1,41 @@
|
||||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
testing
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# npm, yarn, build etc
|
||||
.vscode
|
||||
.sass-cache
|
||||
yarn.lock
|
||||
package-lock.json
|
||||
|
||||
# Bower dependency directory (https://bower.io/)
|
||||
bower_components
|
||||
|
||||
# Dependency directories
|
||||
node_modules/
|
||||
jspm_packages/
|
||||
|
||||
# Optional eslint cache
|
||||
.eslintcache
|
||||
|
||||
# Os
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
Desktop.ini
|
||||
.directory
|
||||
*~
|
||||
.DS_Store
|
||||
|
||||
# maven & eclipse
|
||||
target/
|
||||
.classpath
|
||||
.project
|
||||
|
||||
# project specific
|
||||
.tmp
|
||||
|
||||
6
.prettierrc
Normal file
6
.prettierrc
Normal file
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"printWidth": 100,
|
||||
"useTabs": true,
|
||||
"semi": true,
|
||||
"singleQuote": true
|
||||
}
|
||||
31
package.json
Normal file
31
package.json
Normal file
@@ -0,0 +1,31 @@
|
||||
{
|
||||
"name": "plantuml-icon-font-sprites",
|
||||
"version": "0.1.0",
|
||||
"author": "tupadr3",
|
||||
"description": "A usefull description",
|
||||
"license": "MIT",
|
||||
"scripts": {
|
||||
"devel": "node ./src/lib/index.js --devel",
|
||||
"build": "rm .tmp/build -rf && node ./src/lib/index.js -c 4 --release",
|
||||
"clean": "rm .tmp -rf"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"dependencies": {
|
||||
"bluebird": "^3.5.1",
|
||||
"command-line-args": "^5.1.1",
|
||||
"command-line-usage": "^6.0.2",
|
||||
"dateformat": "^3.0.3",
|
||||
"eslint": "^5.9.0",
|
||||
"extend": "^3.0.1",
|
||||
"fs-extra": "^6.0.1",
|
||||
"isomorphic-git": ">=1.8.2",
|
||||
"lodash": "^4.17.10",
|
||||
"minimist": "^1.2.0",
|
||||
"ncp": "^2.0.0",
|
||||
"os": "^0.1.1",
|
||||
"pngjs": "^3.3.3",
|
||||
"progress": "^2.0.0",
|
||||
"winston": "^2.4.2",
|
||||
"xml2js": "^0.4.19"
|
||||
}
|
||||
}
|
||||
BIN
src/assets/bin/plantuml.jar
Normal file
BIN
src/assets/bin/plantuml.jar
Normal file
Binary file not shown.
BIN
src/assets/bin/rsvg-convert.exe
Normal file
BIN
src/assets/bin/rsvg-convert.exe
Normal file
Binary file not shown.
114
src/lib/cliOptions.js
Normal file
114
src/lib/cliOptions.js
Normal file
@@ -0,0 +1,114 @@
|
||||
const os = require('os');
|
||||
|
||||
let cpuCount = os.cpus().length;
|
||||
|
||||
if (cpuCount > 2) {
|
||||
cpuCount = Number((cpuCount / 2).toFixed(0));
|
||||
if (cpuCount > 6) {
|
||||
cpuCount--;
|
||||
cpuCount--;
|
||||
}
|
||||
}
|
||||
|
||||
let binRsvgDft = os.platform() === 'linux' ? 'rsvg-convert' : 'src/assets/bin/rsvg-convert.exe';
|
||||
|
||||
module.exports = [
|
||||
{
|
||||
name: 'limit',
|
||||
type: Number,
|
||||
alias: 'l',
|
||||
defaultValue: 0,
|
||||
},
|
||||
{
|
||||
name: 'concurrency',
|
||||
type: Number,
|
||||
alias: 'c',
|
||||
defaultValue: cpuCount,
|
||||
},
|
||||
{
|
||||
name: 'progress',
|
||||
type: Boolean,
|
||||
alias: 'p',
|
||||
defaultValue: true,
|
||||
},
|
||||
{
|
||||
name: 'verbose',
|
||||
type: Boolean,
|
||||
alias: 'v',
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
name: 'formats',
|
||||
type: String,
|
||||
multiple: true,
|
||||
defaultValue: ['png', 'svg', 'puml'],
|
||||
typeLabel: '{underline format} ...',
|
||||
},
|
||||
{
|
||||
name: 'release',
|
||||
type: Boolean,
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
name: 'colors',
|
||||
type: String,
|
||||
multiple: true,
|
||||
defaultValue: ['black'],
|
||||
typeLabel: '{underline color} ...',
|
||||
},
|
||||
{
|
||||
name: 'sizes',
|
||||
type: Number,
|
||||
multiple: true,
|
||||
defaultValue: [48],
|
||||
typeLabel: '{underline size} ...',
|
||||
},
|
||||
{
|
||||
name: 'icons',
|
||||
type: String,
|
||||
multiple: true,
|
||||
defaultValue: [],
|
||||
typeLabel: '{underline icon} ...',
|
||||
},
|
||||
{
|
||||
name: 'fonts',
|
||||
type: String,
|
||||
multiple: true,
|
||||
defaultValue: [],
|
||||
typeLabel: '{underline font} ...',
|
||||
},
|
||||
{
|
||||
name: 'binPlantuml',
|
||||
type: String,
|
||||
defaultValue: 'src/assets/bin/plantuml.jar',
|
||||
description: 'The path to the PlantUML executable (.jar) to use',
|
||||
},
|
||||
{
|
||||
name: 'binRsvg',
|
||||
type: String,
|
||||
defaultValue: binRsvgDft,
|
||||
description: 'The path to the rsvg-convert executable to use',
|
||||
},
|
||||
{
|
||||
name: 'build',
|
||||
type: String,
|
||||
defaultValue: 'build',
|
||||
},
|
||||
{
|
||||
name: 'temp',
|
||||
type: String,
|
||||
defaultValue: '.tmp',
|
||||
},
|
||||
{
|
||||
name: 'devel',
|
||||
type: Boolean,
|
||||
defaultValue: false,
|
||||
},
|
||||
{
|
||||
name: 'help',
|
||||
alias: 'h',
|
||||
type: Boolean,
|
||||
description: 'Display this usage guide.',
|
||||
defaultValue: false,
|
||||
},
|
||||
];
|
||||
58
src/lib/config.js
Normal file
58
src/lib/config.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @authot tupadr3
|
||||
*/
|
||||
const cliArgs = require('command-line-args'),
|
||||
cliOptions = require('./cliOptions.js'),
|
||||
path = require('path');
|
||||
|
||||
function initConfig() {
|
||||
const cfg = cliArgs(cliOptions);
|
||||
const fontsDef = require('./fonts').def();
|
||||
let fonts = cfg.fonts;
|
||||
cfg.fonts = [];
|
||||
|
||||
// validate fonts
|
||||
if (fonts.length > 0) {
|
||||
fonts.forEach((item) => {
|
||||
const found = fontsDef.find(function (element) {
|
||||
return element.type === item;
|
||||
});
|
||||
if (found) {
|
||||
cfg.fonts.push(found);
|
||||
} else {
|
||||
throw new Error('Font ' + item + ' not found');
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cfg.fonts = fontsDef;
|
||||
}
|
||||
|
||||
cfg.png = false;
|
||||
cfg.puml = false;
|
||||
cfg.svg = false;
|
||||
|
||||
if (cfg.formats) {
|
||||
cfg.formats.forEach((item) => {
|
||||
if (item === 'png') {
|
||||
cfg.png = true;
|
||||
}
|
||||
if (item === 'puml') {
|
||||
cfg.puml = true;
|
||||
}
|
||||
if (item === 'svg') {
|
||||
cfg.svg = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// setup dirs
|
||||
cfg.dirs = {};
|
||||
cfg.dirs.temp = path.resolve(cfg.temp);
|
||||
cfg.dirs.project = path.resolve('./');
|
||||
cfg.dirs.generated = path.resolve(cfg.temp + '/generated');
|
||||
cfg.dirs.build = path.resolve(cfg.temp + '/' + cfg.build);
|
||||
cfg.dirs.fonts = path.resolve(cfg.temp + '/fonts');
|
||||
return cfg;
|
||||
}
|
||||
|
||||
module.exports = initConfig();
|
||||
340
src/lib/fonts.js
Normal file
340
src/lib/fonts.js
Normal file
@@ -0,0 +1,340 @@
|
||||
/**
|
||||
* @authot tupadr3
|
||||
*/
|
||||
const log = require('./logger'),
|
||||
fs = require('fs-extra'),
|
||||
git = require('isomorphic-git'),
|
||||
http = require('isomorphic-git/http/node'),
|
||||
PNG = require('pngjs').PNG;
|
||||
|
||||
function def() {
|
||||
const fontDefs = [
|
||||
{
|
||||
prefix: 'FA5',
|
||||
name: 'font-awesome-5',
|
||||
type: 'fa5',
|
||||
repo: 'https://github.com/FortAwesome/Font-Awesome.git',
|
||||
branch: '5.15.3',
|
||||
},
|
||||
{
|
||||
prefix: 'FA',
|
||||
name: 'font-awesome',
|
||||
type: 'fa',
|
||||
repo: 'https://github.com/FortAwesome/Font-Awesome.git',
|
||||
branch: 'fa-4',
|
||||
},
|
||||
{
|
||||
prefix: 'DEV',
|
||||
name: 'devicons',
|
||||
type: 'dev',
|
||||
repo: 'https://github.com/vorillaz/devicons.git',
|
||||
branch: 'master',
|
||||
},
|
||||
{
|
||||
prefix: 'GOV',
|
||||
name: 'govicons',
|
||||
type: 'gov',
|
||||
repo: 'https://github.com/540co/govicons.git',
|
||||
branch: '1.5.1',
|
||||
},
|
||||
{
|
||||
prefix: 'WEATHER',
|
||||
name: 'weather',
|
||||
type: 'weather',
|
||||
repo: 'https://github.com/erikflowers/weather-icons.git',
|
||||
branch: 'master',
|
||||
},
|
||||
{
|
||||
prefix: 'MATERIAL',
|
||||
name: 'material',
|
||||
type: 'material',
|
||||
repo: 'https://github.com/google/material-design-icons.git',
|
||||
branch: '3.0.2',
|
||||
},
|
||||
{
|
||||
prefix: 'DEV2',
|
||||
name: 'devicons2',
|
||||
type: 'dev2',
|
||||
repo: 'https://github.com/devicons/devicon.git',
|
||||
branch: 'v2.12.0',
|
||||
},
|
||||
];
|
||||
return fontDefs;
|
||||
}
|
||||
|
||||
async function load(cfg) {
|
||||
// Prep the folder structue
|
||||
let buildFolder = cfg.dirs.build;
|
||||
await fs.ensureDirSync(buildFolder);
|
||||
|
||||
let work = [];
|
||||
for (let item of cfg.fonts) {
|
||||
try {
|
||||
item.path = await repo(cfg, item);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
let buildSetFolder = buildFolder + '/' + item.type;
|
||||
await fs.ensureDirSync(buildSetFolder);
|
||||
await fs.ensureDirSync(cfg.dirs.generated);
|
||||
|
||||
if (cfg.svg) {
|
||||
await fs.ensureDirSync(buildSetFolder + '/svg');
|
||||
}
|
||||
if (cfg.puml) {
|
||||
await fs.ensureDirSync(buildSetFolder + '/puml');
|
||||
}
|
||||
if (cfg.png) {
|
||||
await fs.ensureDirSync(buildSetFolder + '/png');
|
||||
for (let index in cfg.sizes) {
|
||||
await fs.ensureDirSync(buildSetFolder + '/png/' + cfg.sizes[index]);
|
||||
}
|
||||
}
|
||||
|
||||
const fontHandler = require('./handler/' + item.type);
|
||||
let fontData = await fontHandler.load(cfg, item);
|
||||
|
||||
if (cfg.icons.length > 0) {
|
||||
log.debug(`Filtering selection to ${cfg.icons}`);
|
||||
fontData = fontData.filter((item) => {
|
||||
if (cfg.icons.includes(`${item.type}-${item.id}`)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
work = work.concat(fontData);
|
||||
}
|
||||
|
||||
if (cfg.limit > 0) {
|
||||
log.debug(`Trimming selection from ${work.length} to ${cfg.limit}`);
|
||||
work = work.slice(0, cfg.limit);
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
async function repo(cfg, item) {
|
||||
log.info('Loading repo ' + item.repo + ' into ' + cfg.dirs.fonts);
|
||||
|
||||
const repoDir = cfg.dirs.fonts + '/' + item.type,
|
||||
repoGitDir = cfg.dirs.fonts + '/' + item.type + '/.git';
|
||||
|
||||
try {
|
||||
await fs.ensureDirSync(repoDir);
|
||||
|
||||
// check if it already exists
|
||||
log.debug(`checking dir ${repoGitDir} for repo`);
|
||||
const repoExists = fs.existsSync(repoGitDir);
|
||||
|
||||
if (!repoExists) {
|
||||
await git.clone({
|
||||
fs,
|
||||
http,
|
||||
dir: repoDir,
|
||||
url: item.repo,
|
||||
singleBranch: true,
|
||||
ref: item.branch,
|
||||
depth: 10,
|
||||
});
|
||||
}
|
||||
|
||||
log.debug(`checkout ${item.repo} branch:${item.branch} completed to dir ${repoDir}`);
|
||||
} catch (err) {
|
||||
log.error('repo error', err);
|
||||
throw err;
|
||||
}
|
||||
return repoDir;
|
||||
}
|
||||
|
||||
async function generate(cfg, item) {
|
||||
if (cfg.svg) {
|
||||
try {
|
||||
await generateSvg(cfg, item);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
if (cfg.png) {
|
||||
for (let index in cfg.sizes) {
|
||||
try {
|
||||
await generatePng(cfg, item, cfg.sizes[index]);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cfg.puml) {
|
||||
try {
|
||||
await generatePuml(cfg, item);
|
||||
} catch (error) {
|
||||
log.error(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function generateSvg(cfg, item) {
|
||||
log.debug('Generating svg for ' + item.type + '-' + item.id);
|
||||
|
||||
return new Promise((resolve) => {
|
||||
var svgCode = getSvgCode(cfg, item);
|
||||
var filename = cfg.dirs.build + '/' + item.type + '/svg/' + item.id + '.svg';
|
||||
log.debug('Wrting svg for ' + item.type + '-' + item.id + ' to ' + filename);
|
||||
fs.writeFileSync(filename, svgCode);
|
||||
resolve(filename);
|
||||
});
|
||||
}
|
||||
|
||||
function getSvgCode(cfg, item) {
|
||||
const fontHandler = require('./handler/' + item.type);
|
||||
let svgCode = fontHandler.getSvgCode(cfg, item);
|
||||
return svgCode;
|
||||
}
|
||||
|
||||
function generatePng(cfg, item, size, path) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
let destPath = path;
|
||||
if (!destPath) {
|
||||
destPath = cfg.dirs.build + '/' + item.type + '/png/' + size + '/' + item.id + '.png';
|
||||
}
|
||||
|
||||
log.debug('Generating png for ' + item.type + '-' + item.id);
|
||||
|
||||
let cliparams = ['-a', '-w', size, '-h', size, '-f', 'png', '-o', destPath],
|
||||
error;
|
||||
log.debug(cfg.binRsvg, cliparams.join(' '));
|
||||
let rsvgConvert = require('child_process').spawn(cfg.binRsvg, cliparams);
|
||||
rsvgConvert.stderr.on('data', (data) => {
|
||||
error += data.toString();
|
||||
});
|
||||
rsvgConvert.once('close', function (code) {
|
||||
if (code > 0) {
|
||||
return reject(error);
|
||||
}
|
||||
resolve(destPath);
|
||||
});
|
||||
rsvgConvert.stdin.end(getSvgCode(cfg, item));
|
||||
});
|
||||
}
|
||||
|
||||
function generatePuml(cfg, item) {
|
||||
return new Promise(async function (resolve, reject) {
|
||||
log.debug('Generating plantuml for ' + item.type + '-' + item.id);
|
||||
|
||||
let pngInterFileName = cfg.dirs.generated + '/' + item.type + '-png-48-' + item.id + '.png';
|
||||
let pngFileName = await generatePng(cfg, item, 48, pngInterFileName);
|
||||
|
||||
// now we need to modify the png a little bit
|
||||
fs.createReadStream(pngFileName)
|
||||
.pipe(
|
||||
new PNG({
|
||||
colorType: 2,
|
||||
})
|
||||
)
|
||||
.on('error', function (err) {
|
||||
log.error(err);
|
||||
})
|
||||
.on('parsed', async function () {
|
||||
log.debug('Modifing for puml generation for icon ' + item.type + '-' + item.id);
|
||||
|
||||
for (var y = 0; y < this.height; y++) {
|
||||
for (var x = 0; x < this.width; x++) {
|
||||
var idx = (this.width * y + x) << 2;
|
||||
// invert color
|
||||
if (this.data[idx] > 0) {
|
||||
this.data[idx] = 0;
|
||||
this.data[idx + 1] = 0;
|
||||
this.data[idx + 2] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// i don't know if we have to wait
|
||||
this.pack().pipe(fs.createWriteStream(pngInterFileName));
|
||||
|
||||
let pumlCode;
|
||||
try {
|
||||
pumlCode = await getPumlCode(cfg, item, pngInterFileName);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var filename = cfg.dirs.build + '/' + item.type + '/puml/' + item.id + '.puml';
|
||||
await fs.writeFileSync(filename, pumlCode);
|
||||
resolve(filename);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function getPumlCode(cfg, item, pngPath) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var plantumlJar,
|
||||
result = '',
|
||||
error = '';
|
||||
|
||||
var template =
|
||||
'@startuml' +
|
||||
'\n' +
|
||||
'{sprite}' +
|
||||
'\n' +
|
||||
'!define {set}_{entity}(_alias) ENTITY(rectangle,black,{id},_alias,{set} {entity})' +
|
||||
'\n' +
|
||||
'!define {set}_{entity}(_alias, _label) ENTITY(rectangle,black,{id},_label, _alias,{set} {entity})' +
|
||||
'\n' +
|
||||
'!define {set}_{entity}(_alias, _label, _shape) ENTITY(_shape,black,{id},_label, _alias,{set} {entity})' +
|
||||
'\n' +
|
||||
'!define {set}_{entity}(_alias, _label, _shape, _color) ENTITY(_shape,_color,{id},_label, _alias,{set} {entity})' +
|
||||
'\n' +
|
||||
'skinparam folderBackgroundColor<<{set} {entity}>> White' +
|
||||
'\n' +
|
||||
'@enduml';
|
||||
|
||||
var plantumlParams = [
|
||||
'-Djava.awt.headless=true',
|
||||
'-jar',
|
||||
cfg.binPlantuml,
|
||||
'-encodesprite',
|
||||
'16',
|
||||
pngPath,
|
||||
];
|
||||
|
||||
log.debug('java ' + plantumlParams.join(' '));
|
||||
|
||||
plantumlJar = require('child_process').spawn('java', plantumlParams);
|
||||
plantumlJar.stdout.on('data', (data) => {
|
||||
result += data.toString();
|
||||
});
|
||||
plantumlJar.stderr.on('data', (data) => {
|
||||
error += data.toString();
|
||||
});
|
||||
plantumlJar.once('close', function (code) {
|
||||
if (code > 0) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
|
||||
var out = template.substr(0);
|
||||
|
||||
var params = {
|
||||
sprite: result.replace('$' + item.type, '$' + item.id.replace(/-/g, '_')),
|
||||
set: item.prefix.toUpperCase(),
|
||||
entity: item.id.replace(/-/g, '_').toUpperCase(),
|
||||
id: item.id.replace(/-/g, '_'),
|
||||
};
|
||||
|
||||
Object.keys(params).forEach(function (key) {
|
||||
out = out.replace(new RegExp('{' + key + '}', 'g'), params[key]);
|
||||
});
|
||||
resolve(out);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
def: def,
|
||||
load: load,
|
||||
generate: generate,
|
||||
};
|
||||
107
src/lib/handler/dev.js
Normal file
107
src/lib/handler/dev.js
Normal file
@@ -0,0 +1,107 @@
|
||||
const fs = require('fs-extra'),
|
||||
util = require('util'),
|
||||
log = require('./../logger'),
|
||||
readFile = util.promisify(fs.readFile),
|
||||
loadash = require('lodash'),
|
||||
parseXml = util.promisify(require('xml2js').parseString);
|
||||
|
||||
async function load(cfg, item) {
|
||||
let iconList = await loadIcons(cfg, item);
|
||||
let icons = await loadFontData(cfg, item, iconList);
|
||||
return icons;
|
||||
}
|
||||
|
||||
async function loadIcons(cfg, item) {
|
||||
log.debug("Loading devicons id's");
|
||||
|
||||
let content = await readFile(item.path + '/css/devicons.css');
|
||||
let lines = content.toString();
|
||||
|
||||
let match,
|
||||
result = [];
|
||||
|
||||
const regex = /devicons-([\w-]*).*\s.*"\S([0-9a-f]+)"/gm;
|
||||
while ((match = regex.exec(lines))) {
|
||||
result.push({
|
||||
id: match[1],
|
||||
unicodeHex: match[2],
|
||||
unicodeDec: parseInt(match[2], 16)
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function loadFontData(cfg, item, iconList) {
|
||||
log.debug('Loading devicons font-data');
|
||||
|
||||
let content = await readFile(item.path + '/fonts/devicons.svg');
|
||||
content = content.toString('utf-8');
|
||||
|
||||
let parsedXml = await parseXml(content),
|
||||
glyph = parsedXml.svg.defs[0].font[0].glyph,
|
||||
svghorz = parsedXml.svg.defs[0].font[0].$['horiz-adv-x'],
|
||||
offset = parsedXml.svg.defs[0].font[0]['font-face'][0].$['descent'],
|
||||
size = parsedXml.svg.defs[0].font[0]['font-face'][0].$['units-per-em'];
|
||||
|
||||
let fontData = glyph
|
||||
.filter(data => {
|
||||
if (!data.$.unicode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(data => {
|
||||
return {
|
||||
data: data.$,
|
||||
unicodeDec: data.$.unicode.charCodeAt(0)
|
||||
};
|
||||
});
|
||||
|
||||
let indexFontData = await loadash.keyBy(fontData, 'unicodeDec');
|
||||
|
||||
let icons = iconList.map(icon => {
|
||||
let iconConfig = {
|
||||
id: icon.id.split('-').join('_'),
|
||||
type: item.type,
|
||||
prefix: item.prefix,
|
||||
unicodeHex: icon.unicodeHex,
|
||||
unicodeDec: icon.unicodeDec,
|
||||
data: indexFontData[icon.unicodeDec].data
|
||||
};
|
||||
iconConfig.advWidth = parseInt(iconConfig.data['horiz-adv-x'] || svghorz);
|
||||
iconConfig.offset = parseInt(offset);
|
||||
iconConfig.size = parseInt(size);
|
||||
return iconConfig;
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
function getSvgCode(cfg, item) {
|
||||
log.debug('Getting svg code for ' + item.type + '-' + item.id);
|
||||
|
||||
let params = {
|
||||
color: cfg.color || 'black',
|
||||
path: item.data.d,
|
||||
width: item.advWidth,
|
||||
height: item.size,
|
||||
shiftX: 0,
|
||||
shiftY: -item.size - item.offset
|
||||
};
|
||||
|
||||
return (
|
||||
`<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.height} ${params.height}" preserveAspectRatio="xMinYMid slice">\n` +
|
||||
`\t<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.width} ${params.height}">\n` +
|
||||
`\t\t<g transform="scale(1 -1) translate(${params.shiftX} ${params.shiftY})">\n` +
|
||||
`\t\t\t<path d="${params.path}" fill="${params.color}" />\n` +
|
||||
`\t\t</g>\n` +
|
||||
`\t</svg>\n` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: load,
|
||||
getSvgCode: getSvgCode
|
||||
};
|
||||
108
src/lib/handler/dev2.js
Normal file
108
src/lib/handler/dev2.js
Normal file
@@ -0,0 +1,108 @@
|
||||
const fs = require('fs-extra'),
|
||||
util = require('util'),
|
||||
log = require('./../logger'),
|
||||
readFile = util.promisify(fs.readFile),
|
||||
lodash = require('lodash'),
|
||||
parseXml = util.promisify(require('xml2js').parseString);
|
||||
|
||||
async function load(cfg, item) {
|
||||
return await loadFontData(cfg, item, await loadIcons(cfg, item));
|
||||
}
|
||||
|
||||
async function loadIcons(cfg, item) {
|
||||
log.debug("Loading devicons2 id's");
|
||||
|
||||
let content = await readFile(item.path + '/devicon.css');
|
||||
let lines = content.toString();
|
||||
|
||||
let match,
|
||||
result = [];
|
||||
|
||||
const regex = /.devicon-([\w-]*):before\s?{\s*content:\s?"\\([\w|\d]*)";\s*}/;
|
||||
while ((match = regex.exec(lines))) {
|
||||
log.verbose('DEV2 - found ' + match[1]);
|
||||
result.push({
|
||||
id: match[1].replace('-plain', ''),
|
||||
unicodeHex: match[2],
|
||||
unicodeDec: parseInt(match[2], 16)
|
||||
});
|
||||
lines = lines.replace(match[0], '');
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function loadFontData(cfg, item, iconList) {
|
||||
log.debug('Loading devicons2 font-data');
|
||||
|
||||
let content = await readFile(item.path + '/fonts/devicon.svg');
|
||||
content = content.toString('utf-8');
|
||||
|
||||
let parsedXml = await parseXml(content),
|
||||
glyph = parsedXml.svg.defs[0].font[0].glyph,
|
||||
svghorz = parsedXml.svg.defs[0].font[0].$['horiz-adv-x'],
|
||||
offset = parsedXml.svg.defs[0].font[0]['font-face'][0].$['descent'],
|
||||
size = parsedXml.svg.defs[0].font[0]['font-face'][0].$['units-per-em'];
|
||||
|
||||
let fontData = glyph
|
||||
.filter(data => {
|
||||
if (!data.$.unicode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(data => {
|
||||
return {
|
||||
data: data.$,
|
||||
unicodeDec: data.$.unicode.charCodeAt(0)
|
||||
};
|
||||
});
|
||||
|
||||
let indexFontData = await lodash.keyBy(fontData, 'unicodeDec');
|
||||
|
||||
let icons = iconList.map(icon => {
|
||||
let iconConfig = {
|
||||
id: icon.id.split('-').join('_'),
|
||||
type: item.type,
|
||||
prefix: item.prefix,
|
||||
unicodeHex: icon.unicodeHex,
|
||||
unicodeDec: icon.unicodeDec,
|
||||
data: indexFontData[icon.unicodeDec].data
|
||||
};
|
||||
iconConfig.advWidth = parseInt(iconConfig.data['horiz-adv-x'] || svghorz);
|
||||
iconConfig.offset = parseInt(offset);
|
||||
iconConfig.size = parseInt(size);
|
||||
return iconConfig;
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
function getSvgCode(cfg, item) {
|
||||
log.debug('Getting svg code for ' + item.type + '-' + item.id);
|
||||
|
||||
let params = {
|
||||
color: cfg.color || 'black',
|
||||
path: item.data.d,
|
||||
width: item.advWidth,
|
||||
height: item.size,
|
||||
shiftX: 0,
|
||||
shiftY: -item.size - item.offset
|
||||
};
|
||||
|
||||
return (
|
||||
`<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.height} ${params.height}" preserveAspectRatio="xMinYMid slice">\n` +
|
||||
`\t<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.width} ${params.height}">\n` +
|
||||
`\t\t<g transform="scale(1 -1) translate(${params.shiftX} ${params.shiftY})">\n` +
|
||||
`\t\t\t<path d="${params.path}" fill="${params.color}" />\n` +
|
||||
`\t\t</g>\n` +
|
||||
`\t</svg>\n` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: load,
|
||||
getSvgCode: getSvgCode
|
||||
};
|
||||
108
src/lib/handler/fa.js
Normal file
108
src/lib/handler/fa.js
Normal file
@@ -0,0 +1,108 @@
|
||||
const fs = require('fs-extra'),
|
||||
util = require('util'),
|
||||
log = require('./../logger'),
|
||||
readFile = util.promisify(fs.readFile),
|
||||
loadash = require('lodash'),
|
||||
parseXml = util.promisify(require('xml2js').parseString),
|
||||
extend = require('extend');
|
||||
|
||||
async function load(cfg, item) {
|
||||
let iconList = await loadIcons(cfg, item);
|
||||
let icons = await loadFontData(cfg, item, iconList);
|
||||
return icons;
|
||||
}
|
||||
|
||||
async function loadIcons(cfg, item) {
|
||||
log.debug("Loading fa id's");
|
||||
let content = await readFile(item.path + '/less/variables.less');
|
||||
let lines = content.toString();
|
||||
|
||||
let match,
|
||||
result = [];
|
||||
|
||||
const regex = /@fa-var-([\w-]+):\s*"\\([0-9a-f]+)";/g;
|
||||
while ((match = regex.exec(lines))) {
|
||||
result.push({
|
||||
id: match[1],
|
||||
unicodeHex: match[2],
|
||||
unicodeDec: parseInt(match[2], 16)
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function loadFontData(cfg, item, iconList) {
|
||||
log.debug('Loading fa font-data');
|
||||
let content = await readFile(item.path + '/fonts/fontawesome-webfont.svg');
|
||||
content = content.toString('utf-8');
|
||||
|
||||
let parsedXml = await parseXml(content),
|
||||
glyph = parsedXml.svg.defs[0].font[0].glyph,
|
||||
svghorz = parsedXml.svg.defs[0].font[0].$['horiz-adv-x'],
|
||||
offset = parsedXml.svg.defs[0].font[0]['font-face'][0].$['descent'],
|
||||
size = parsedXml.svg.defs[0].font[0]['font-face'][0].$['units-per-em'];
|
||||
|
||||
let fontData = glyph
|
||||
.filter(data => {
|
||||
if (!data.$.unicode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(data => {
|
||||
return {
|
||||
data: data.$,
|
||||
unicodeDec: data.$.unicode.charCodeAt(0)
|
||||
};
|
||||
});
|
||||
|
||||
let indexFontData = await loadash.keyBy(fontData, 'unicodeDec');
|
||||
|
||||
let icons = iconList.map(icon => {
|
||||
let iconConfig = {
|
||||
id: icon.id.split('-').join('_'),
|
||||
type: item.type,
|
||||
prefix: item.prefix,
|
||||
unicodeHex: icon.unicodeHex,
|
||||
unicodeDec: icon.unicodeDec,
|
||||
data: indexFontData[icon.unicodeDec].data
|
||||
};
|
||||
iconConfig.advWidth = parseInt(iconConfig.data['horiz-adv-x'] || svghorz);
|
||||
iconConfig.offset = parseInt(offset);
|
||||
iconConfig.size = parseInt(size);
|
||||
return iconConfig;
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
function getSvgCode(cfg, item) {
|
||||
log.debug('Getting svg code for ' + item.type + '-' + item.id);
|
||||
|
||||
let params = {
|
||||
color: cfg.color || 'black',
|
||||
path: item.data.d,
|
||||
width: item.advWidth,
|
||||
height: item.size,
|
||||
shiftX: item.advWidth / 10 / 2,
|
||||
shiftY: -item.size - item.offset - item.size / 10 / 2
|
||||
};
|
||||
|
||||
return (
|
||||
`<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.height} ${params.height}" preserveAspectRatio="xMinYMid slice">\n` +
|
||||
`\t<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.width} ${params.height}">\n` +
|
||||
`\t\t<g transform="scale(1 -1) scale(0.9)` +
|
||||
` translate(${params.shiftX} ${params.shiftY})">\n` +
|
||||
`\t\t\t<path d="${params.path}" fill="${params.color}" />\n` +
|
||||
`\t\t</g>\n` +
|
||||
`\t</svg>\n` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: load,
|
||||
getSvgCode: getSvgCode
|
||||
};
|
||||
132
src/lib/handler/fa5.js
Normal file
132
src/lib/handler/fa5.js
Normal file
@@ -0,0 +1,132 @@
|
||||
const fs = require('fs-extra'),
|
||||
util = require('util'),
|
||||
log = require('./../logger'),
|
||||
readFile = util.promisify(fs.readFile),
|
||||
loadash = require('lodash'),
|
||||
parseXml = util.promisify(require('xml2js').parseString);
|
||||
|
||||
async function load(cfg, item) {
|
||||
let iconList = await loadIcons(cfg, item);
|
||||
let icons = await loadFontData(cfg, item, iconList);
|
||||
return icons;
|
||||
}
|
||||
|
||||
async function loadIcons(cfg, item) {
|
||||
log.debug("Loading fa id's");
|
||||
let content = await readFile(item.path + '/less/_variables.less');
|
||||
let lines = content.toString();
|
||||
|
||||
let match,
|
||||
result = [];
|
||||
|
||||
const regex = /@fa-var-([\w-]+):\s*"\\([0-9a-f]+)";/g;
|
||||
while ((match = regex.exec(lines))) {
|
||||
result.push({
|
||||
id: match[1],
|
||||
unicodeHex: match[2],
|
||||
unicodeDec: parseInt(match[2], 16)
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function loadFontData(cfg, item, iconList) {
|
||||
log.debug('Loading fa5 font-data');
|
||||
|
||||
let filesList = [
|
||||
item.path + '/webfonts/fa-regular-400.svg',
|
||||
item.path + '/webfonts/fa-brands-400.svg',
|
||||
item.path + '/webfonts/fa-solid-900.svg'
|
||||
];
|
||||
|
||||
let fontData = [];
|
||||
for (let key in filesList) {
|
||||
let item = filesList[key];
|
||||
let content = await readFile(item);
|
||||
content = content.toString('utf-8');
|
||||
|
||||
let parsedXml = await parseXml(content),
|
||||
glyph = parsedXml.svg.defs[0].font[0].glyph,
|
||||
svghorz = parsedXml.svg.defs[0].font[0].$['horiz-adv-x'],
|
||||
offset = parsedXml.svg.defs[0].font[0]['font-face'][0].$['descent'],
|
||||
size = parsedXml.svg.defs[0].font[0]['font-face'][0].$['units-per-em'];
|
||||
|
||||
let fontDataItem = glyph
|
||||
.filter(data => {
|
||||
if (!data.$.unicode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(data => {
|
||||
return {
|
||||
data: data.$,
|
||||
unicodeDec: data.$.unicode.charCodeAt(0),
|
||||
svghorz: svghorz,
|
||||
offset: -offset,
|
||||
size: size
|
||||
};
|
||||
});
|
||||
fontData = fontData.concat(fontDataItem);
|
||||
}
|
||||
|
||||
let indexFontData = await loadash.keyBy(fontData, 'unicodeDec');
|
||||
|
||||
let icons = iconList
|
||||
.filter(icon => {
|
||||
if (!indexFontData[icon.unicodeDec]) {
|
||||
log.debug(`Skipping ${icon.unicodeHex}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(icon => {
|
||||
let iconData = indexFontData[icon.unicodeDec];
|
||||
|
||||
let iconConfig = {
|
||||
id: icon.id.split('-').join('_'),
|
||||
type: item.type,
|
||||
prefix: item.prefix,
|
||||
unicodeHex: icon.unicodeHex,
|
||||
unicodeDec: icon.unicodeDec,
|
||||
data: iconData.data,
|
||||
offset: parseInt(iconData.offset),
|
||||
size: parseInt(iconData.size),
|
||||
advWidth: parseInt(iconData.data['horiz-adv-x'] || iconData.svghorz)
|
||||
};
|
||||
return iconConfig;
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
function getSvgCode(cfg, item) {
|
||||
log.debug('Getting svg code for ' + item.type + '-' + item.id);
|
||||
|
||||
let params = {
|
||||
color: cfg.color || 'black',
|
||||
path: item.data.d,
|
||||
width: item.advWidth,
|
||||
height: item.size,
|
||||
shiftX: item.advWidth / 10 / 2,
|
||||
shiftY: -item.size +item.offset -item.size / 10 / 2
|
||||
};
|
||||
|
||||
return (
|
||||
`<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.height} ${params.height}" preserveAspectRatio="xMinYMid slice">\n` +
|
||||
`\t<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.width} ${params.height}">\n` +
|
||||
`\t\t<g transform="scale(1 -1) scale(0.9)` +
|
||||
` translate(${params.shiftX} ${params.shiftY})">\n` +
|
||||
`\t\t\t<path d="${params.path}" fill="${params.color}" />\n` +
|
||||
`\t\t</g>\n` +
|
||||
`\t</svg>\n` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: load,
|
||||
getSvgCode: getSvgCode
|
||||
};
|
||||
128
src/lib/handler/gov.js
Normal file
128
src/lib/handler/gov.js
Normal file
@@ -0,0 +1,128 @@
|
||||
const fs = require('fs-extra'),
|
||||
util = require('util'),
|
||||
log = require('./../logger'),
|
||||
readFile = util.promisify(fs.readFile),
|
||||
loadash = require('lodash'),
|
||||
parseXml = util.promisify(require('xml2js').parseString);
|
||||
|
||||
async function load(cfg, item) {
|
||||
let iconList = await loadIcons(cfg, item);
|
||||
let icons = await loadFontData(cfg, item, iconList);
|
||||
return icons;
|
||||
}
|
||||
|
||||
async function loadIcons(cfg, item) {
|
||||
log.debug("Loading fa id's");
|
||||
let content = await readFile(item.path + '/less/variables.less');
|
||||
let lines = content.toString();
|
||||
|
||||
let match,
|
||||
result = [];
|
||||
|
||||
const regex = /@gi-([\w-]+):\s*"\\([0-9a-f]+)";/g;
|
||||
while ((match = regex.exec(lines))) {
|
||||
result.push({
|
||||
id: match[1],
|
||||
unicodeHex: match[2],
|
||||
unicodeDec: parseInt(match[2], 16)
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function loadFontData(cfg, item, iconList) {
|
||||
log.debug('Loading fa5 font-data');
|
||||
|
||||
let filesList = [item.path + '/fonts/govicons-webfont.svg'];
|
||||
|
||||
let fontData = [];
|
||||
for (let key in filesList) {
|
||||
let item = filesList[key];
|
||||
let content = await readFile(item);
|
||||
content = content.toString('utf-8');
|
||||
|
||||
let parsedXml = await parseXml(content),
|
||||
glyph = parsedXml.svg.defs[0].font[0].glyph,
|
||||
svghorz = parsedXml.svg.defs[0].font[0].$['horiz-adv-x'],
|
||||
offset = parsedXml.svg.defs[0].font[0]['font-face'][0].$['descent'],
|
||||
size = parsedXml.svg.defs[0].font[0]['font-face'][0].$['units-per-em'];
|
||||
|
||||
let fontDataItem = glyph
|
||||
.filter(data => {
|
||||
if (!data.$.unicode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(data => {
|
||||
return {
|
||||
data: data.$,
|
||||
unicodeDec: data.$.unicode.charCodeAt(0),
|
||||
svghorz: svghorz,
|
||||
offset: offset,
|
||||
size: size
|
||||
};
|
||||
});
|
||||
fontData = fontData.concat(fontDataItem);
|
||||
}
|
||||
|
||||
let indexFontData = await loadash.keyBy(fontData, 'unicodeDec');
|
||||
|
||||
let icons = iconList
|
||||
.filter(icon => {
|
||||
if (!indexFontData[icon.unicodeDec]) {
|
||||
log.debug(`Skipping ${icon.unicodeHex}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(icon => {
|
||||
let iconData = indexFontData[icon.unicodeDec];
|
||||
|
||||
let iconConfig = {
|
||||
id: icon.id.split('-').join('_'),
|
||||
type: item.type,
|
||||
prefix: item.prefix,
|
||||
unicodeHex: icon.unicodeHex,
|
||||
unicodeDec: icon.unicodeDec,
|
||||
data: iconData.data,
|
||||
offset: parseInt(iconData.offset),
|
||||
size: parseInt(iconData.size),
|
||||
advWidth: parseInt(iconData.data['horiz-adv-x'] || iconData.svghorz)
|
||||
};
|
||||
return iconConfig;
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
function getSvgCode(cfg, item) {
|
||||
log.debug('Getting svg code for ' + item.type + '-' + item.id);
|
||||
|
||||
let params = {
|
||||
color: cfg.color || 'black',
|
||||
path: item.data.d,
|
||||
width: item.advWidth,
|
||||
height: item.size,
|
||||
shiftX: item.advWidth / 10 / 2,
|
||||
shiftY: -item.size - item.offset - item.size / 10 / 2
|
||||
};
|
||||
|
||||
return (
|
||||
`<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.height} ${params.height}" preserveAspectRatio="xMinYMid slice">\n` +
|
||||
`\t<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.width} ${params.height}">\n` +
|
||||
`\t\t<g transform="scale(1 -1) scale(0.9)` +
|
||||
` translate(${params.shiftX} ${params.shiftY})">\n` +
|
||||
`\t\t\t<path d="${params.path}" fill="${params.color}" />\n` +
|
||||
`\t\t</g>\n` +
|
||||
`\t</svg>\n` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: load,
|
||||
getSvgCode: getSvgCode
|
||||
};
|
||||
106
src/lib/handler/material.js
Normal file
106
src/lib/handler/material.js
Normal file
@@ -0,0 +1,106 @@
|
||||
const fs = require('fs-extra'),
|
||||
util = require('util'),
|
||||
log = require('./../logger'),
|
||||
readFile = util.promisify(fs.readFile),
|
||||
parseXml = util.promisify(require('xml2js').parseString);
|
||||
|
||||
async function load(cfg, item) {
|
||||
let icons = await loadFontData(cfg, item);
|
||||
return icons;
|
||||
}
|
||||
|
||||
async function loadFontData(cfg, item) {
|
||||
log.debug(`Loading ${item.type} font-data`);
|
||||
|
||||
let filesList = [item.path + '/iconfont/MaterialIcons-Regular.svg'];
|
||||
|
||||
let fontData = [];
|
||||
for (let key in filesList) {
|
||||
let item = filesList[key];
|
||||
let content = await readFile(item);
|
||||
content = content.toString('utf-8');
|
||||
|
||||
let parsedXml = await parseXml(content),
|
||||
glyph = parsedXml.svg.defs[0].font[0].glyph,
|
||||
svghorz = parsedXml.svg.defs[0].font[0].$['horiz-adv-x'],
|
||||
offset = parsedXml.svg.defs[0].font[0]['font-face'][0].$['descent'],
|
||||
size = parsedXml.svg.defs[0].font[0]['font-face'][0].$['units-per-em'];
|
||||
|
||||
let fontDataItem = glyph
|
||||
.filter(data => {
|
||||
if (!data.$.unicode) {
|
||||
return false;
|
||||
}
|
||||
if (!data.$.d) {
|
||||
return false;
|
||||
}
|
||||
if (data.$.d === 'M0 0z') {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(data => {
|
||||
return {
|
||||
data: data.$,
|
||||
unicodeDec: data.$.unicode.charCodeAt(0),
|
||||
svghorz: svghorz,
|
||||
offset: offset,
|
||||
size: size
|
||||
};
|
||||
});
|
||||
|
||||
|
||||
fontData = fontData.concat(fontDataItem);
|
||||
}
|
||||
|
||||
let icons = fontData.map(icon => {
|
||||
let iconData = icon.data;
|
||||
|
||||
let iconConfig = {
|
||||
id: icon.data['glyph-name'].split('-').join('_'),
|
||||
type: item.type,
|
||||
prefix: item.prefix,
|
||||
unicodeHex: icon.unicodeHex,
|
||||
unicodeDec: icon.unicodeDec,
|
||||
data: iconData,
|
||||
offset: parseInt(icon.offset),
|
||||
size: parseInt(icon.size),
|
||||
advWidth: parseInt(iconData['horiz-adv-x'] || icon.svghorz)
|
||||
};
|
||||
|
||||
log.verbose('MATERIAL - found ' + iconConfig.id);
|
||||
return iconConfig;
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
function getSvgCode(cfg, item) {
|
||||
log.debug('Getting svg code for ' + item.type + '-' + item.id);
|
||||
|
||||
let params = {
|
||||
color: cfg.color || 'black',
|
||||
path: item.data.d,
|
||||
width: item.advWidth,
|
||||
height: item.size,
|
||||
shiftX: 0,
|
||||
shiftY: -item.size - item.offset
|
||||
};
|
||||
|
||||
return (
|
||||
`<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.height} ${params.height}" preserveAspectRatio="xMinYMid slice">\n` +
|
||||
`\t<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.width} ${params.height}">\n` +
|
||||
`\t\t<g transform="scale(1 -1) translate(${params.shiftX} ${params.shiftY})">\n` +
|
||||
`\t\t\t<path d="${params.path}" fill="${params.color}" />\n` +
|
||||
`\t\t</g>\n` +
|
||||
`\t</svg>\n` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: load,
|
||||
getSvgCode: getSvgCode
|
||||
};
|
||||
128
src/lib/handler/weather.js
Normal file
128
src/lib/handler/weather.js
Normal file
@@ -0,0 +1,128 @@
|
||||
const fs = require('fs-extra'),
|
||||
util = require('util'),
|
||||
log = require('./../logger'),
|
||||
readFile = util.promisify(fs.readFile),
|
||||
loadash = require('lodash'),
|
||||
parseXml = util.promisify(require('xml2js').parseString);
|
||||
|
||||
async function load(cfg, item) {
|
||||
let iconList = await loadIcons(cfg, item);
|
||||
let icons = await loadFontData(cfg, item, iconList);
|
||||
return icons;
|
||||
}
|
||||
|
||||
async function loadIcons(cfg, item) {
|
||||
log.debug("Loading fa id's");
|
||||
let content = await readFile(item.path + '/css/weather-icons.css');
|
||||
let lines = content.toString();
|
||||
|
||||
let match,
|
||||
result = [];
|
||||
|
||||
const regex = /wi-([\w-]*).*\s.*"\S([0-9a-f]+)"/g;
|
||||
while ((match = regex.exec(lines))) {
|
||||
result.push({
|
||||
id: match[1],
|
||||
unicodeHex: match[2],
|
||||
unicodeDec: parseInt(match[2], 16)
|
||||
});
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
async function loadFontData(cfg, item, iconList) {
|
||||
log.debug('Loading fa5 font-data');
|
||||
|
||||
let filesList = [item.path + '/font/weathericons-regular-webfont.svg'];
|
||||
|
||||
let fontData = [];
|
||||
for (let key in filesList) {
|
||||
let item = filesList[key];
|
||||
let content = await readFile(item);
|
||||
content = content.toString('utf-8');
|
||||
|
||||
let parsedXml = await parseXml(content),
|
||||
glyph = parsedXml.svg.defs[0].font[0].glyph,
|
||||
svghorz = parsedXml.svg.defs[0].font[0].$['horiz-adv-x'],
|
||||
offset = parsedXml.svg.defs[0].font[0]['font-face'][0].$['descent'],
|
||||
size = parsedXml.svg.defs[0].font[0]['font-face'][0].$['units-per-em'];
|
||||
|
||||
let fontDataItem = glyph
|
||||
.filter(data => {
|
||||
if (!data.$.unicode) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(data => {
|
||||
return {
|
||||
data: data.$,
|
||||
unicodeDec: data.$.unicode.charCodeAt(0),
|
||||
svghorz: svghorz,
|
||||
offset: offset,
|
||||
size: size
|
||||
};
|
||||
});
|
||||
fontData = fontData.concat(fontDataItem);
|
||||
}
|
||||
|
||||
let indexFontData = await loadash.keyBy(fontData, 'unicodeDec');
|
||||
|
||||
let icons = iconList
|
||||
.filter(icon => {
|
||||
if (!indexFontData[icon.unicodeDec]) {
|
||||
log.debug(`Skipping ${icon.unicodeHex}`);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
})
|
||||
.map(icon => {
|
||||
let iconData = indexFontData[icon.unicodeDec];
|
||||
|
||||
let iconConfig = {
|
||||
id: icon.id.split('-').join('_'),
|
||||
type: item.type,
|
||||
prefix: item.prefix,
|
||||
unicodeHex: icon.unicodeHex,
|
||||
unicodeDec: icon.unicodeDec,
|
||||
data: iconData.data,
|
||||
offset: parseInt(iconData.offset),
|
||||
size: parseInt(iconData.size),
|
||||
advWidth: parseInt(iconData.data['horiz-adv-x'] || iconData.svghorz)
|
||||
};
|
||||
return iconConfig;
|
||||
});
|
||||
|
||||
return icons;
|
||||
}
|
||||
|
||||
function getSvgCode(cfg, item) {
|
||||
log.debug('Getting svg code for ' + item.type + '-' + item.id);
|
||||
|
||||
let params = {
|
||||
color: cfg.color || 'black',
|
||||
path: item.data.d,
|
||||
width: item.advWidth,
|
||||
height: item.size,
|
||||
shiftX: item.advWidth / ((10 / 2) * 2),
|
||||
shiftY: -item.size - item.offset - item.size / ((10 / 2) * 2)
|
||||
};
|
||||
|
||||
return (
|
||||
`<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.height} ${params.height}" preserveAspectRatio="xMinYMid slice">\n` +
|
||||
`\t<svg width="${params.height}" height="${params.height}"` +
|
||||
` viewBox="0 0 ${params.width} ${params.height}">\n` +
|
||||
`\t\t<g transform="scale(1 -1) scale(0.8)` +
|
||||
` translate(${params.shiftX} ${params.shiftY})">\n` +
|
||||
`\t\t\t<path d="${params.path}" fill="${params.color}" />\n` +
|
||||
`\t\t</g>\n` +
|
||||
`\t</svg>\n` +
|
||||
`</svg>`
|
||||
);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
load: load,
|
||||
getSvgCode: getSvgCode
|
||||
};
|
||||
237
src/lib/index.js
Normal file
237
src/lib/index.js
Normal file
@@ -0,0 +1,237 @@
|
||||
const Bluebird = require('bluebird'),
|
||||
cliOptions = require('./cliOptions.js'),
|
||||
cliUsage = require('command-line-usage'),
|
||||
fs = require('fs-extra'),
|
||||
path = require('path'),
|
||||
ProgressBar = require('progress'),
|
||||
utils = require('./utils');
|
||||
|
||||
// config
|
||||
const cfg = require('./config');
|
||||
const log = require('./logger');
|
||||
|
||||
if (cfg.devel) {
|
||||
cfg.limit = cfg.limit == 0 ? 5 : cfg.limit;
|
||||
cfg.verbose = true;
|
||||
}
|
||||
|
||||
if (cfg.verbose) {
|
||||
log.level = 'debug';
|
||||
} else {
|
||||
log.level = 'warn';
|
||||
}
|
||||
|
||||
if (cfg.help) {
|
||||
const usage = cliUsage([
|
||||
{
|
||||
header: 'Options',
|
||||
optionList: cliOptions,
|
||||
},
|
||||
]);
|
||||
|
||||
process.stdout.write(usage);
|
||||
} else {
|
||||
printInfo();
|
||||
generate();
|
||||
}
|
||||
|
||||
async function generate() {
|
||||
const fonts = require('./fonts');
|
||||
let work = [],
|
||||
icons = [];
|
||||
|
||||
if (cfg.github) {
|
||||
cfg.png = true;
|
||||
cfg.puml = true;
|
||||
cfg.colors = ['black'];
|
||||
cfg.sizes = [48];
|
||||
}
|
||||
|
||||
if (cfg.devel) {
|
||||
cfg.png = true;
|
||||
cfg.puml = true;
|
||||
cfg.svg = true;
|
||||
cfg.limit = 25;
|
||||
cfg.sizes = [128];
|
||||
cfg.icons = [
|
||||
'fa5-user_alt',
|
||||
'fa5-gitlab',
|
||||
'fa5-server',
|
||||
'fa5-database',
|
||||
'fa-gears',
|
||||
'fa-fire',
|
||||
'fa-clock_o',
|
||||
'fa-lock',
|
||||
'fa-cloud',
|
||||
'fa-server',
|
||||
'dev-nginx',
|
||||
'dev-mysql',
|
||||
'dev-redis',
|
||||
'dev-docker',
|
||||
'dev-linux',
|
||||
'dev2-html5',
|
||||
'gov-ambulance',
|
||||
'weather-night_alt_thunderstorm',
|
||||
'material-3d_rotation',
|
||||
];
|
||||
}
|
||||
|
||||
try {
|
||||
icons = await fonts.load(cfg);
|
||||
} catch (err) {
|
||||
throw err;
|
||||
}
|
||||
|
||||
log.debug(`Starting work for ${icons.length} icons`);
|
||||
|
||||
let progressBar = new ProgressBar('working [:bar] :percent :etas :info', {
|
||||
complete: '=',
|
||||
incomplete: ' ',
|
||||
width: 50,
|
||||
total: icons.length,
|
||||
});
|
||||
|
||||
work.push(
|
||||
Bluebird.map(
|
||||
icons,
|
||||
(item) => {
|
||||
if (cfg.progress) {
|
||||
progressBar.tick({
|
||||
info: item.type + '-' + item.id,
|
||||
});
|
||||
}
|
||||
return fonts.generate(cfg, item);
|
||||
},
|
||||
{
|
||||
concurrency: cfg.concurrency,
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
await Promise.all(work);
|
||||
|
||||
if (cfg.release) {
|
||||
// copy icons to project
|
||||
for (let item of cfg.fonts) {
|
||||
log.debug('Copying ' + item.name);
|
||||
|
||||
let releasePath = cfg.dirs.project + '/' + item.name,
|
||||
pngPath = cfg.dirs.build + '/' + item.type + '/png/' + cfg.sizes[0],
|
||||
pumlPath = cfg.dirs.build + '/' + item.type + '/puml';
|
||||
|
||||
await fs.ensureDirSync(releasePath);
|
||||
await fs.emptyDirSync(releasePath);
|
||||
|
||||
let files = await utils.getFiles(pngPath);
|
||||
files = files
|
||||
.map((file) => {
|
||||
return {
|
||||
file: path.parse(file).name + path.parse(file).ext,
|
||||
name: path.parse(file).name,
|
||||
ext: path.parse(file).ext,
|
||||
path: file,
|
||||
};
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
return a.name > b.name ? 1 : b.name > a.name ? -1 : 0;
|
||||
});
|
||||
|
||||
log.debug('Found ' + item.name + ' ' + files.length);
|
||||
|
||||
let indexFileName = releasePath + '/index.md';
|
||||
let indexContent = `# ${item.name}\n\n\n`;
|
||||
indexContent += `### Overview\n`;
|
||||
indexContent += `| Name | Macro | Image | Url |\n`;
|
||||
indexContent += `|-------|--------|-------|-----|\n`;
|
||||
|
||||
for (let file of files) {
|
||||
await fs.copyFileSync(file.path, releasePath + '/' + file.file);
|
||||
|
||||
indexContent += `${file.name} |`;
|
||||
indexContent += `${item.type.toUpperCase()}_${file.name.toUpperCase()} |`;
|
||||
indexContent += ` |`;
|
||||
indexContent += `${file.name}.puml |\n`;
|
||||
}
|
||||
|
||||
fs.writeFileSync(indexFileName, indexContent);
|
||||
|
||||
let pumlFiles = await utils.getFiles(pumlPath);
|
||||
pumlFiles = pumlFiles
|
||||
.map((file) => {
|
||||
return {
|
||||
file: path.parse(file).name + path.parse(file).ext,
|
||||
name: path.parse(file).name,
|
||||
ext: path.parse(file).ext,
|
||||
path: file,
|
||||
};
|
||||
})
|
||||
.sort(function (a, b) {
|
||||
return a.name > b.name ? 1 : b.name > a.name ? -1 : 0;
|
||||
});
|
||||
|
||||
for (let file of pumlFiles) {
|
||||
await fs.copyFileSync(file.path, releasePath + '/' + file.file);
|
||||
}
|
||||
}
|
||||
// Render examples
|
||||
let examplesPath = cfg.dirs.project + '/examples';
|
||||
let exampleFiles = await utils.getFiles(examplesPath);
|
||||
exampleFiles = exampleFiles.filter((file) => path.parse(file).ext === '.puml');
|
||||
|
||||
for (let file of exampleFiles) {
|
||||
await renderPuml(file);
|
||||
}
|
||||
}
|
||||
|
||||
console.log('Done');
|
||||
}
|
||||
|
||||
function renderPuml(path) {
|
||||
return new Promise(function (resolve, reject) {
|
||||
var plantumlJar,
|
||||
error = '';
|
||||
|
||||
var plantumlParams = ['-Djava.awt.headless=true', '-jar', cfg.binPlantuml, path];
|
||||
|
||||
log.debug('java ' + plantumlParams.join(' '));
|
||||
|
||||
plantumlJar = require('child_process').spawn('java', plantumlParams);
|
||||
plantumlJar.stderr.on('data', (data) => {
|
||||
error += data.toString();
|
||||
});
|
||||
plantumlJar.once('close', function (code) {
|
||||
if (code > 0) {
|
||||
reject(error);
|
||||
return;
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function printInfo() {
|
||||
// info
|
||||
let msg = '\nSettings:\n';
|
||||
if (cfg.icons.length > 0) {
|
||||
msg += 'icons: ';
|
||||
cfg.icons.forEach((element) => (msg += ' ' + element));
|
||||
} else {
|
||||
msg += 'fonts: ';
|
||||
cfg.fonts.forEach((element) => (msg += ' ' + element.name));
|
||||
}
|
||||
|
||||
msg += '\nformats:';
|
||||
msg += cfg.puml ? ' puml' : '';
|
||||
msg += cfg.png ? ' png' : '';
|
||||
msg += cfg.svg ? ' svg' : '';
|
||||
|
||||
msg += cfg.limit > 0 ? ' \nlimit: ' + cfg.limit : '';
|
||||
|
||||
msg += '\ncolors: ';
|
||||
cfg.colors.forEach((element) => (msg += ' ' + element));
|
||||
|
||||
msg += '\nsizes: ';
|
||||
cfg.sizes.forEach((element) => (msg += ' ' + element));
|
||||
|
||||
log.debug(msg);
|
||||
}
|
||||
54
src/lib/logger.js
Normal file
54
src/lib/logger.js
Normal file
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Based on https://gist.github.com/spmason/1670196
|
||||
*/
|
||||
const util = require('util'),
|
||||
winston = require('winston'),
|
||||
logger = new winston.Logger(),
|
||||
env = (process.env.NODE_ENV || '').toLowerCase(),
|
||||
dateFormat = require('dateformat');
|
||||
|
||||
// Override the built-in console methods with winston hooks
|
||||
switch (env) {
|
||||
case 'production':
|
||||
logger.add(winston.transports.File, {
|
||||
filename: __dirname + '/application.log',
|
||||
handleExceptions: true,
|
||||
exitOnError: false
|
||||
});
|
||||
break;
|
||||
case 'test':
|
||||
// Don't set up the logger overrides
|
||||
return;
|
||||
default:
|
||||
logger.add(winston.transports.Console, {
|
||||
colorize: true,
|
||||
timestamp: function() {
|
||||
return dateFormat(new Date(), 'HH:MM:ss');
|
||||
}
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
function formatArgs(args) {
|
||||
return [util.format.apply(util.format, Array.prototype.slice.call(args))];
|
||||
}
|
||||
console.log = function() {
|
||||
logger.debug.apply(logger, formatArgs(arguments));
|
||||
};
|
||||
console.info = function() {
|
||||
logger.info.apply(logger, formatArgs(arguments));
|
||||
};
|
||||
console.warn = function() {
|
||||
logger.warn.apply(logger, formatArgs(arguments));
|
||||
};
|
||||
console.error = function() {
|
||||
logger.error.apply(logger, formatArgs(arguments));
|
||||
};
|
||||
console.debug = function() {
|
||||
logger.debug.apply(logger, formatArgs(arguments));
|
||||
};
|
||||
console.progress = function() {
|
||||
logger.debug.apply(logger, formatArgs(arguments));
|
||||
};
|
||||
|
||||
module.exports = logger;
|
||||
54
src/lib/utils.js
Normal file
54
src/lib/utils.js
Normal file
@@ -0,0 +1,54 @@
|
||||
const fs = require('fs-extra'),
|
||||
git = require('isomorphic-git'),
|
||||
http = require('isomorphic-git/http/node'),
|
||||
log = require('./logger'),
|
||||
{ promisify } = require('util'),
|
||||
{ resolve } = require('path'),
|
||||
readdir = promisify(fs.readdir),
|
||||
stat = promisify(fs.stat);
|
||||
|
||||
async function repo(repo, branch, target) {
|
||||
log.debug('Loading Repo ' + repo + ' into ' + target);
|
||||
|
||||
try {
|
||||
await fs.ensureDirSync(target);
|
||||
|
||||
// check if it already exists
|
||||
log.debug(`checking dir ${target}/.git for repo`);
|
||||
const repoExists = fs.existsSync(target + '/.git');
|
||||
|
||||
if (!repoExists) {
|
||||
await git.clone({
|
||||
fs,
|
||||
http,
|
||||
dir: target,
|
||||
url: repo,
|
||||
singleBranch: true,
|
||||
ref: branch,
|
||||
depth: 10,
|
||||
});
|
||||
}
|
||||
|
||||
log.info(`checkout ${repo} branch:${branch} completed to dir ${target}`);
|
||||
} catch (err) {
|
||||
log.error('repo error', err);
|
||||
throw err;
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
async function getFiles(dir) {
|
||||
const subdirs = await readdir(dir);
|
||||
const files = await Promise.all(
|
||||
subdirs.map(async (subdir) => {
|
||||
const res = resolve(dir, subdir);
|
||||
return (await stat(res)).isDirectory() ? getFiles(res) : res;
|
||||
})
|
||||
);
|
||||
return files.reduce((a, f) => a.concat(f), []);
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
repo: repo,
|
||||
getFiles: getFiles,
|
||||
};
|
||||
Reference in New Issue
Block a user