Skip to content

Commit

Permalink
a simpler script for generating octicons using the NPM package
Browse files Browse the repository at this point in the history
  • Loading branch information
shiftkey committed Nov 4, 2017
1 parent d26fd1e commit e85b5fa
Showing 1 changed file with 64 additions and 39 deletions.
103 changes: 64 additions & 39 deletions script/generate-octicons.ts
Original file line number Diff line number Diff line change
@@ -1,36 +1,75 @@
/* generate-octicons
*
* Utility script for generating a strongly typed representation of all
* octicons currently in the master branch of primer/octicons. Automatically
* downloads the latest version of the `sprite.octicons.svg` file.
* octicons distributed by the octicons NPM package. Enumerates the icons
* and generates the TypeScript class containing just what Desktop needs.
*/

import fs = require('fs')
import xml2js = require('xml2js')
import fs = require('fs')
import path = require('path')
import toCamelCase = require('to-camel-case')
import * as cp from 'child_process'

interface IXML2JSNode {
path: {
$: {
d: string
}
}
}

const filePath = path.resolve(
__dirname,
'..',
'node_modules',
'octicons',
'build',
'sprite.octicons.svg'
)
interface IOcticonData {
readonly jsFriendlyName: string
readonly pathData: string
readonly width: string
readonly height: string
}

const file = fs.readFileSync(filePath, 'utf-8') // eslint-disable-line no-sync
const viewBoxRe = /0 0 (\d+) (\d+)/

interface IXML2JSResult {
svg: { symbol: ReadonlyArray<IXML2JSNode> }
function readXml(xml: string): Promise<IXML2JSNode> {
return new Promise((resolve, reject) => {
xml2js.parseString(xml, function(err, result: IXML2JSNode) {
if (err) {
reject(err)
} else {
resolve(result)
}
})
})
}
interface IXML2JSNode {
$: { [key: string]: string }
path: ReadonlyArray<IXML2JSNode>

async function generateIconData(): Promise<ReadonlyArray<IOcticonData>> {
const octicons = require('octicons')

const results = new Array<IOcticonData>()

for (const name of Object.keys(octicons)) {
const octicon = octicons[name]

const id = octicon.symbol
const viewBox = octicon.options.viewBox
const viewBoxMatch = viewBoxRe.exec(viewBox)

if (!viewBoxMatch) {
throw new Error(`*** ERROR! Unexpected viewBox format for ${id}`)
}

const [, width, height] = viewBoxMatch

const path = octicon.path
const result = await readXml(path)
const pathData = result.path.$.d
const jsFriendlyName = toCamelCase(id)

results.push({ jsFriendlyName, width, height, pathData })
}

return results
}

xml2js.parseString(file, function(err, result: IXML2JSResult) {
const viewBoxRe = /0 0 (\d+) (\d+)/
generateIconData().then(result => {
const out = fs.createWriteStream(
path.resolve(__dirname, '../app/src/ui/octicons/octicons.generated.ts'),
{
Expand All @@ -50,32 +89,18 @@ xml2js.parseString(file, function(err, result: IXML2JSResult) {
out.write(
'\n public constructor(public w: number, public h: number, public d: string) { }\n\n'
)
let count = 0
result.svg.symbol.forEach(function(symbol) {
count++

const id = symbol.$.id
const viewBox = symbol.$.viewBox
const pathData = symbol.path[0].$.d

const viewBoxMatch = viewBoxRe.exec(viewBox)

if (!viewBoxMatch) {
console.error(`*** ERROR! Unexpected viewBox format for ${id}`)
process.exitCode = 1
return
}

const [, w, h] = viewBoxMatch
const jsFriendlyName = toCamelCase(id)

result.forEach(function(symbol) {
const { jsFriendlyName, pathData, width, height } = symbol
out.write(
` public static get ${jsFriendlyName}() { return new OcticonSymbol(${w}, ${h}, '${pathData}') }\n`
` public static get ${jsFriendlyName}() { return new OcticonSymbol(${width}, ${height}, '${pathData}') }\n`
)
})

out.write('}\n')
out.end()

console.log(`Wrote ${count} octicons`)
console.log(`Wrote ${result.length} octicons`)

cp.exec('yarn eslint:fix')
})

0 comments on commit e85b5fa

Please sign in to comment.