big patcher overhaul, now correctly handling aliases and producing better CSS

master
Ondřej Hruška 6 years ago
parent 3fbac24759
commit 30d2922bf9
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 4
      .gitignore
  2. 15
      build.sh
  3. 9
      install.sh
  4. 1805
      package-lock.json
  5. 13
      package.json
  6. 1
      patcher/.gitignore
  7. 175
      patcher/apply-filter.js
  8. 40
      patcher/css-template.css
  9. 29
      patcher/patcher-init.js
  10. 34
      patcher/refresh-wanted-templates.js
  11. 157
      patcher/util.js

4
.gitignore vendored

@ -4,3 +4,7 @@ wanted.ini
fontcustom.yml
fontcustom.default.yml
/.idea
/node_modules
/vendor

@ -23,18 +23,3 @@ fi
echo "=== Starting a build... ==="
(cd patcher && node ./apply-filter.js)
(cd "./Fork-Awesome/src/icons/" && make)
echo -e "\x1b[33mIf the make target failed at a \"cp\" statement, that is most likely safe to ignore\x1b[m"
fontname=$(cat fontcustom.yml | head -n1 | sed "s/font_name: //")
if [ ! -f "./Fork-Awesome/src/icons/$fontname/$fontname-preview.html" ]; then
echo -e "\x1b[31;1mBuild failed, output directory is empty.\x1b[m"
exit
fi
rm ./output/*
cp "./Fork-Awesome/src/icons/$fontname/"* ./output
echo
echo -e "\x1b[32;1m=== Your font \"$fontname\" is ready in the output/ directory ===\x1b[m"

@ -6,6 +6,13 @@ if [ ! -f "./Fork-Awesome/.git" ]; then
exit
fi
npm install
if [ ! -d "./node_modules" ]; then
echo -e "\x1b[31;1mFnode_modules not found, did npm fail?\x1b[m"
exit
fi
cd Fork-Awesome
echo "=== Ensuring FA is up-to-date ==="
@ -33,5 +40,5 @@ cp "./Fork-Awesome/src/icons/fontcustom.yml" "./patcher/templates"
cp "./Fork-Awesome/src/icons/icons.yml" "./patcher/templates"
cp -R "./Fork-Awesome/src/icons/svg" "./patcher/templates"
(cd ./patcher && node ./refresh-wanted-templates.js)
(cd ./patcher && node ./patcher-init.js)

1805
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,13 @@
{
"name": "fork-awesome-customizer",
"version": "0.0.1",
"description": "Fork-Awesome subset builder",
"scripts": {},
"license": "MIT",
"dependencies": {
"js-yaml": "^3.12.0"
},
"devDependencies": {
"standard": "^11.0.1"
}
}

@ -0,0 +1 @@
.applied-aliases.json

@ -1,90 +1,149 @@
#!/usr/bin/env node
const fs = require('fs')
function rmInDir(dirPath) {
try { var files = fs.readdirSync(dirPath) }
catch(e) { return }
if (files.length > 0) {
for (var i = 0; i < files.length; i++) {
var filePath = dirPath + '/' + files[i]
if (fs.statSync(filePath).isFile())
fs.unlinkSync(filePath)
else
rmDir(filePath)
}
}
const util = require("./util")
let wanted_icons = util.fread('../wanted.ini').split('\n')
.filter((x) => x.length && x[0] !== '#')
.map((x) => x.trim().replace(/\s*#.*/, ''))
let iconsfile = util.fread('templates/icons.yml')
let fontcustom = util.fread('../fontcustom.yml')
if (!fontcustom.fonts_path_relative_to_css) {
fontcustom.fonts_path_relative_to_css = './'
}
function cp(src, dest) {
if (!fs.existsSync(src)) {
return false;
// find which aliases are defined
let alias_map = {}
iconsfile.icons.forEach((icon) => {
if (icon.aliases) {
icon.aliases.forEach((alias) => {
alias_map[alias] = icon.id
})
}
})
var data = fs.readFileSync(src, 'utf-8');
fs.writeFileSync(dest, data);
return true
}
console.log(`Including ${wanted_icons.length} icons out of ${iconsfile.icons.length}`)
console.log(`Found ${Object.keys(alias_map).length} aliases defined in the dictionary`)
console.log('Preparing icons.yml...')
// let manifest = JSON.parse(fs.readFileSync('templates/.fontcustom-manifest.json', 'utf-8'))
let fcyml = fs.readFileSync('../fontcustom.yml', 'utf-8')
let desired = fs.readFileSync('../wanted.ini', 'utf-8').split('\n')
.filter((x) => x.length && x[0] !== '#')
.map((x) => x.trim().replace(/\s*#.*/, ''))
let wanted_all = []
let applied_aliases = {}
for(let id of wanted_icons) {
wanted_all.push(id)
if (alias_map[id]) {
applied_aliases[id] = alias_map[id]
wanted_all.push(alias_map[id])
}
}
// TODO deal with aliases properly
let iconsfile_filtered = {
icons: iconsfile.icons.filter((x) => {
return wanted_all.indexOf(x.id) !== -1
})
}
console.log(`Including ${desired.length} icons`)
// store the result for the postprocessing script
util.fwrite('../Fork-Awesome/src/icons/icons.yml', iconsfile_filtered)
util.fwrite('../Fork-Awesome/src/icons/fontcustom.yml', fontcustom)
console.log('Preparing icons.yml...')
if (util.exists('../Fork-Awesome/src/icons/.fontcustom-manifest.json')) {
util.rm('../Fork-Awesome/src/icons/.fontcustom-manifest.json')
}
let font_name = fontcustom.font_name
let fa_output_dir = `../Fork-Awesome/src/icons/${font_name}`
util.rmInDir('../Fork-Awesome/src/icons/svg')
util.rmInDir(fa_output_dir)
util.rmInDir('../output')
console.log('Copying icons ...')
for (let a of wanted_all) {
if (typeof alias_map[a] !== 'undefined') {
console.log(`Skipping alias ${a}`)
continue;
}
// this would be prettier with some yaml module, but to avoid installing anything...
if (!util.cp(`./templates/svg/${a}.svg`,
`../Fork-Awesome/src/icons/svg/${a}.svg`,
false)) {
console.log(`- \x1b[31,1mFile "${a}.svg" not found!\x1b[m`)
}
}
let iconsy = fs.readFileSync('templates/icons.yml', 'utf-8')
console.log('Running builder script')
let pieces = iconsy.substring(iconsy.indexOf('\n')+1).split(' - name:')
pieces.shift() // remove first
// now we have the entries, without leading ' - name'
util.exec('bundle exec fontcustom compile', '../Fork-Awesome/src/icons/')
let pattern = /id:\s+([a-z_0-9-]+)\n/
if (!util.exists(`${fa_output_dir}/${font_name}.css`)) {
util.abort('\x1b[31;1mBuild failed, no CSS in output directory.\x1b[m')
}
pieces = pieces.filter((x) => {
let ar = pattern.exec(x)
return ar !== null && desired.indexOf(ar[1]) !== -1
let suffixes = ['.css', '.eot', '.svg', '.ttf', '.woff', '.woff2', '-preview.html']
suffixes.forEach((x) => {
util.cp(`${fa_output_dir}/${font_name}${x}`, `../output/${font_name}${x}`)
})
let combined = 'icons:\n - name:' + pieces.join(' - name:')
let cssfile = `../output/${font_name}.css`
let htmlfile = `../output/${font_name}-preview.html`
console.log('\x1b[32m[Writing]\x1b[m FA~icons.yml')
fs.writeFileSync('../Fork-Awesome/src/icons/icons.yml', combined)
console.log('Post-processing CSS')
let orig_css = util.fread(cssfile)
console.log('\x1b[32m[Writing]\x1b[m FA~fontcustom.yml')
fs.writeFileSync('../Fork-Awesome/src/icons/fontcustom.yml', fcyml)
let iconstyles_begin_token = 'antialiased;\n}\n'
let iconstyles = orig_css
.substr(orig_css.indexOf(iconstyles_begin_token) + iconstyles_begin_token.length)
let template = util.fread('./css-template.css')
console.log('Deleting FA~.fontcustom-manifest.json, to force a rebuilt ...')
if (fs.existsSync('../Fork-Awesome/src/icons/.fontcustom-manifest.json')) {
fs.unlinkSync('../Fork-Awesome/src/icons/.fontcustom-manifest.json')
let prefix = fontcustom.css_selector
if (!prefix.endsWith('{{glyph}}')) {
util.abort(`CSS selector must end with {{glyph}}`)
}
prefix = prefix.replace('{{glyph}}', '').replace('.', '')
let fa_packagejson = util.fread('../Fork-Awesome/package.json')
let fontpath = fontcustom.fonts_path_relative_to_css
if (!fontpath.endsWith('/')) fontpath += '/'
console.log('Deleting files in FA~svg/ ...')
rmInDir('../Fork-Awesome/src/icons/svg')
console.log('Collected information:')
console.log(` \x1b[36mFont name:\x1b[m ${font_name}`)
console.log(` \x1b[36mFont path:\x1b[m ${fontpath} (relative to CSS)`)
console.log(` \x1b[36mCSS class prefix:\x1b[m ${prefix}`)
console.log(` \x1b[36mFork-Awesome version:\x1b[m ${fa_packagejson.version}`)
let html_content = util.fread(htmlfile)
console.log('Copying desired files to FA~svg/ ...')
let any_bad = false
for (let a of desired) {
if (!cp(`./templates/svg/${a}.svg`, `../Fork-Awesome/src/icons/svg/${a}.svg`)) {
console.log(`- \x1b[33mFile \x1b[31m"${a}.svg"\x1b[33m not found, probably a typo or alias\x1b[m`)
any_bad = true
let css_header = template.replace(/\$prefix/g, prefix)
.replace(/\$fontname/g, font_name)
.replace(/\$fontpath/g, fontpath)
.replace(/\$version/g, fa_packagejson.version)
for (let alias in applied_aliases) {
if (applied_aliases.hasOwnProperty(alias)) {
let orig = `.${prefix}${applied_aliases[alias]}:before`
let added = `.${prefix}${alias}:before`
console.log(`Adding CSS alias ${added} -> ${orig}`)
iconstyles = iconstyles.replace(orig, `${orig}, ${added}`)
html_content = html_content.replace(
`value=".${prefix}${applied_aliases[alias]}" />`,
`value=".${prefix}${applied_aliases[alias]}" />
<input class="class" type="text" readonly="readonly" onClick="this.select();" value="${added.replace(':before','')}" />`
)
}
}
if (any_bad) {
console.log(`\x1b[31mSome files were not found. If you included their aliases (e.g. save -> floppy-o), this is correct.\x1b[m`)
}
util.fwrite(cssfile,
css_header + iconstyles.replace(/([^:]):before/g, '$1::before'))
util.fwrite(htmlfile, html_content)
console.log(`\x1b[32;1m=== Your font "${font_name}" is ready in the output directory ===\x1b[m`)

@ -0,0 +1,40 @@
/*!
* Based on Fork Awesome $version, originaly by Dave Gandy - http://forkawesome.github.io/Fork-Awesome/
* License - http://forkawesome.github.io/Fork-Awesome//license (Font: SIL OFL 1.1, CSS: MIT License)
*/
@font-face {
font-family: '$fontname';
src: url('$fontpath$fontname.eot?v=$version');
src: url('$fontpath$fontname.eot?#iefix&v=$version') format('embedded-opentype'),
url('$fontpath$fontname.woff2?v=$version') format('woff2'),
url('$fontpath$fontname.woff?v=$version') format('woff'),
url('$fontpath$fontname.ttf?v=$version') format('truetype'),
url('$fontpath$fontname.svg?v=$version#$fontname') format('svg');
font-weight: normal;
font-style: normal;
}
@media screen and (-webkit-min-device-pixel-ratio:0) {
@font-face {
font-family: "$fontname";
src: url("$fontpath$fontname.svg#$fontname") format("svg");
}
}
[data-icon]::before { content: attr(data-icon); }
[data-icon]::before, [class^="$prefix"]::before, [class*=" $prefix"]::before {
display: inline-block;
font-family: "$fontname";
font-style: normal;
font-weight: normal;
font-variant: normal;
line-height: 1;
text-decoration: inherit;
font-size: inherit;
text-rendering: optimizeLegibility;
text-transform: none;
-moz-osx-font-smoothing: grayscale;
-webkit-font-smoothing: antialiased;
font-smoothing: antialiased;
}

@ -0,0 +1,29 @@
#!/usr/bin/env node
const util = require("./util")
// the manifest file is easier to parse for us, but the actual source file is icons.yml
let manifest = util.fread('./templates/.fontcustom-manifest.json')
let all_enabled = []
let all_disabled = []
for (let key in manifest.glyphs){
if (manifest.glyphs.hasOwnProperty(key)) {
all_enabled.push(key)
all_disabled.push(`#${key}`)
}
}
console.log(`Found ${all_enabled.length} icons in manifest, writing template files`)
util.fwrite('../wanted.all.ini', all_enabled.join('\n') + '\n')
util.fwrite('../wanted.none.ini', all_disabled.join('\n') + '\n')
let fontcustom = util.fread('./templates/fontcustom.yml')
fontcustom.fonts_path_relative_to_css = './'
util.fwrite('../fontcustom.default.yml', fontcustom)
if (!util.exists('../fontcustom.yml')) {
util.cp('../fontcustom.default.yml', '../fontcustom.yml')
}

@ -1,34 +0,0 @@
#!/usr/bin/env node
const fs = require('fs')
// the manifest file is easier to parse for us, but the actual source file is icons.yml
let manifest = JSON.parse(fs.readFileSync('./templates/.fontcustom-manifest.json', 'utf-8'))
let fcyml = fs.readFileSync('./templates/fontcustom.yml', 'utf-8')
let all_enabled = []
let all_disabled = []
for (var key in manifest.glyphs){
if (manifest.glyphs.hasOwnProperty(key)) {
all_enabled.push(key)
all_disabled.push(`#${key}`)
}
}
console.log(`Found ${all_enabled.length} icons in manifest, writing template files`)
console.log(`\x1b[32m[Writing]\x1b[m wanted.all.ini`)
fs.writeFileSync('../wanted.all.ini', all_enabled.join('\n') + '\n')
console.log(`\x1b[32m[Writing]\x1b[m wanted.none.ini`)
fs.writeFileSync('../wanted.none.ini', all_disabled.join('\n') + '\n')
console.log(`\x1b[32m[Writing]\x1b[m fontcustom.default.yml`)
fs.writeFileSync('../fontcustom.default.yml', fcyml)
if (!fs.existsSync('../fontcustom.yml')) {
console.log(`\x1b[32m[Writing]\x1b[m fontcustom.yml (did not exist)`)
fs.writeFileSync('../fontcustom.yml', fcyml)
}

@ -0,0 +1,157 @@
const fs = require('fs')
const yaml = require('js-yaml')
const chproc = require('child_process')
/**
* Delete all files in a directory
*
* @param dirPath : string
*/
function rmInDir(dirPath) {
let files
console.log(`\x1b[32m[Clean]\x1b[m ${dirPath}`)
try {
files = fs.readdirSync(dirPath)
} catch (e) {
return
}
if (files.length > 0) {
for (let i = 0; i < files.length; i++) {
let filePath = dirPath + '/' + files[i]
if (filePath.endsWith('.gitignore') || filePath.endsWith('.gitkeep'))
continue // preserve special files
if (fs.statSync(filePath).isFile())
fs.unlinkSync(filePath)
else
rmInDir(filePath)
}
}
}
/**
* Copy a file
*
* @param src : string
* @param dest : string
* @param verbose : boolean, default true
* @returns {boolean}
*/
function cp(src, dest, verbose=true) {
if (!fs.existsSync(src)) {
return false;
}
if (verbose) console.log(`\x1b[32m[Copy]\x1b[m ${src} -> ${dest}`)
let data = fs.readFileSync(src);
fs.writeFileSync(dest, data);
return true
}
/**
* Write with automatic encoding to JSON or YAML
*
* @param path : string
* @param content : object|string
*/
function fwrite(path, content) {
let towrite = content
let format = 'plain'
if (typeof towrite !== 'string') {
if (path.endsWith('.json')) {
towrite = JSON.stringify(towrite, null, 4)
format = 'json'
}
else if (path.endsWith('.yaml') || path.endsWith('.yml')) {
towrite = yaml.safeDump(towrite)
format = 'yaml'
}
else {
throw `Can't figure out data encoding (at ${path})`
}
}
console.log(`\x1b[32m[Writing]\x1b[m ${path} (${format})`)
fs.writeFileSync(path, towrite)
}
/**
* Read with automatic decoding from JSON or YAML
*
* @param path : string
* @return string|object|array
*/
function fread(path) {
let content = fs.readFileSync(path, 'utf-8')
let format = 'plain'
if (path.endsWith('.json')) {
content = JSON.parse(content)
format = 'json'
} else if (path.endsWith('.yaml') || path.endsWith('.yml')) {
content = yaml.safeLoad(content)
format = 'yaml'
}
console.log(`\x1b[32m[Reading]\x1b[m ${path} (${format})`)
return content
}
/**
* Test if a file exists
*
* @param path : string
* @returns {boolean} exists
*/
function exists (path) {
return fs.existsSync(path)
}
/**
* Delete a file
*
* @param path : string
* @returns {boolean} success
*/
function rm (path) {
if (!exists(path)) {
return false
}
fs.unlinkSync(path)
return true
}
/**
* Execute a command
*
* @param command
* @param cwd
*/
function exec (command, cwd='.') {
return chproc.execSync(command, {
cwd: cwd,
stdio: [0,1,2]
})
}
module.exports = {
rmInDir,
cp,
fwrite,
fread,
exists,
rm,
exec,
abort: (msg) => {
console.log(`\x1b[31;1m${msg}\x1b[m`)
process.exit()
}
}
Loading…
Cancel
Save