forked from primer/octicons
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathbuild.js
executable file
·141 lines (120 loc) · 4.04 KB
/
build.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
#!/usr/bin/env node
/* eslint-env node */
const fs = require('fs-extra')
const path = require('path')
const globby = require('globby')
const cheerio = require('cheerio')
const trimNewlines = require('trim-newlines')
const yargs = require('yargs')
const merge = require('lodash.merge')
const keywords = require('../keywords.json')
// This script generates a JSON file that contains
// information about input SVG files.
const {argv} = yargs
.usage('Usage: $0 --input <input filepaths> --output <output filepath>')
.example('$0 --input icons/**/*.svg --output build/data.json')
.option('input', {
alias: 'i',
type: 'array',
demandOption: true,
describe: 'Input SVG files'
})
.option('output', {
alias: 'o',
type: 'string',
describe: 'Ouput JSON file. Defaults to stdout if no output file is provided.'
})
// The `argv.input` array could contain globs (e.g. "**/*.svg").
const filepaths = globby.sync(argv.input)
const svgFilepaths = filepaths.filter(filepath => path.parse(filepath).ext === '.svg')
if (svgFilepaths.length === 0) {
// eslint-disable-next-line no-console
console.error('No input SVG file(s) found')
process.exit(1)
}
let exitCode = 0
const icons = svgFilepaths.map(filepath => {
try {
const filename = path.parse(filepath).base
const filenamePattern = /(.+)-([0-9]+).svg$/
if (!filenamePattern.test(filename)) {
throw new Error(
`${filename}: Invalid filename. Please append the height of the SVG to the end of the filename (e.g. alert-16.svg).`
)
}
const [, name, height] = filename.match(filenamePattern)
const svg = fs.readFileSync(path.resolve(filepath), 'utf8')
const svgElement = cheerio.load(svg)('svg')
const svgWidth = parseInt(svgElement.attr('width'))
const svgHeight = parseInt(svgElement.attr('height'))
const svgViewBox = svgElement.attr('viewBox')
const svgPath = trimNewlines(svgElement.html()).trim()
if (!svgWidth) {
throw new Error(`${filename}: Missing width attribute.`)
}
if (!svgHeight) {
throw new Error(`${filename}: Missing height attribute.`)
}
if (!svgViewBox) {
throw new Error(`${filename}: Missing viewBox attribute.`)
}
if (svgHeight !== parseInt(height)) {
throw new Error(`${filename}: Height in filename does not match height attribute of SVG`)
}
const viewBoxPattern = /0 0 ([0-9]+) ([0-9]+)/
if (!viewBoxPattern.test(svgViewBox)) {
throw new Error(
`${filename}: Invalid viewBox attribute. The viewBox attribute should be in the following format: "0 0 <width> <height>"`
)
}
const [, viewBoxWidth, viewBoxHeight] = svgViewBox.match(viewBoxPattern)
if (svgWidth !== parseInt(viewBoxWidth)) {
throw new Error(`${filename}: width attribute and viewBox width do not match.`)
}
if (svgHeight !== parseInt(viewBoxHeight)) {
throw new Error(`${filename}: height attribute and viewBox height do not match.`)
}
return {
name,
keywords: keywords[name] || [],
width: svgWidth,
height: svgHeight,
path: svgPath
}
} catch (error) {
// eslint-disable-next-line no-console
console.error(error)
// Instead of exiting immediately, we set exitCode to 1 and continue
// iterating through the rest of the SVGs. This allows us to identify all
// the SVGs that have errors, not just the first one. An exit code of 1
// indicates that an error occured.
// Reference: https://nodejs.org/api/process.html#process_exit_codes
exitCode = 1
return null
}
})
// Exit early if any errors occurred.
if (exitCode !== 0) {
process.exit(exitCode)
}
const iconsByName = icons.reduce(
(acc, icon) =>
merge(acc, {
[icon.name]: {
name: icon.name,
keywords: icon.keywords,
heights: {
[icon.height]: {
width: icon.width,
path: icon.path
}
}
}
}),
{}
)
if (argv.output) {
fs.outputJsonSync(path.resolve(argv.output), iconsByName)
} else {
process.stdout.write(JSON.stringify(iconsByName))
}