heroicons_helper 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/package.json ADDED
@@ -0,0 +1,13 @@
1
+ {
2
+ "name": "heroicons_helper",
3
+ "private": true,
4
+ "devDependencies": {
5
+ "cheerio": "1.0.0-rc.11",
6
+ "heroicons": "^1.0.6",
7
+ "fs-extra": "^7.0.1",
8
+ "globby": "11.0.0",
9
+ "lodash.merge": "4.6.2",
10
+ "trim-newlines": "3.0.1",
11
+ "yargs": "15.1.0"
12
+ }
13
+ }
@@ -0,0 +1,3 @@
1
+ {
2
+ "archive": ["box", "catalog"]
3
+ }
@@ -0,0 +1,169 @@
1
+ #!/usr/bin/env node
2
+ /* eslint-env node */
3
+ const fs = require("fs-extra");
4
+ const path = require("path");
5
+ const globby = require("globby");
6
+ const cheerio = require("cheerio");
7
+ const trimNewlines = require("trim-newlines");
8
+ const yargs = require("yargs");
9
+ const merge = require("lodash.merge");
10
+ const keywords = require("./keywords.json");
11
+
12
+ // This script generates a JSON file that contains
13
+ // information about input SVG files.
14
+ const { argv } = yargs
15
+ .usage("Usage: $0 --output <output filepath>")
16
+ .example("$0 --input icons/**/*.svg --output build/data.json")
17
+ .option("input", {
18
+ alias: "i",
19
+ type: "array",
20
+ describe: "Input SVG files",
21
+ default: [
22
+ "node_modules/heroicons/outline/*.svg",
23
+ "node_modules/heroicons/solid/*.svg",
24
+ ],
25
+ })
26
+ .option("output", {
27
+ alias: "o",
28
+ type: "string",
29
+ describe:
30
+ "Output JSON file. Defaults to stdout if no output file is provided.",
31
+ default: "lib/heroicons_helper/data.json",
32
+ });
33
+
34
+ const filepaths = globby.sync(argv.input);
35
+ const svgFilepaths = filepaths.filter(
36
+ (filepath) => path.parse(filepath).ext === ".svg"
37
+ );
38
+
39
+ if (svgFilepaths.length === 0) {
40
+ // eslint-disable-next-line no-console
41
+ console.error(`No input SVG file(s) found in ${icon_file_path.join(", ")}`);
42
+ process.exit(1);
43
+ }
44
+
45
+ let exitCode = 0;
46
+
47
+ const validTypes = ["solid", "outline"];
48
+ const defaultOutlineWidth = "24";
49
+ const defaultSolidWidth = "20";
50
+
51
+ const icons = svgFilepaths.map((filepath) => {
52
+ try {
53
+ let filename = path.parse(filepath).base;
54
+ const type = path.parse(filepath).dir.split("/").pop();
55
+ let widthSize;
56
+ switch (type) {
57
+ case "outline":
58
+ widthSize = defaultOutlineWidth;
59
+ break;
60
+ case "solid":
61
+ widthSize = defaultSolidWidth;
62
+ break;
63
+ default:
64
+ throw new Error(`Unknown icon type: ${type}`);
65
+ }
66
+
67
+ const filenamePattern = /(.+)(?:-[0-9]{1,2})?-([0-9]{2}).svg$/;
68
+ const filenameReplacePattern = /\.svg$/;
69
+
70
+ if (!filenamePattern.test(filename)) {
71
+ filename = filename.replace(filenameReplacePattern, `-${widthSize}.svg`);
72
+ }
73
+
74
+ const [, name, height] = filename.match(filenamePattern);
75
+
76
+ const svg = fs.readFileSync(path.resolve(filepath), "utf8");
77
+ const svgElement = cheerio.load(svg)("svg");
78
+ let svgWidth = parseInt(svgElement.attr("width"));
79
+ let svgHeight = parseInt(svgElement.attr("height"));
80
+ const svgViewBox = svgElement.attr("viewBox");
81
+ const svgPath = trimNewlines(svgElement.html()).trim();
82
+
83
+ if (!svgWidth) {
84
+ svgWidth = parseInt(widthSize);
85
+ svgElement.attr("width", svgWidth);
86
+ }
87
+
88
+ if (!svgHeight) {
89
+ svgHeight = parseInt(widthSize);
90
+ svgElement.attr("height", svgHeight);
91
+ }
92
+
93
+ if (!svgViewBox) {
94
+ throw new Error(`${filename}: Missing viewBox attribute.`);
95
+ }
96
+
97
+ if (svgHeight != parseInt(height)) {
98
+ throw new Error(
99
+ `${filename}: Height in filename (${height}) does not match height attribute of SVG (${svgHeight})`
100
+ );
101
+ }
102
+
103
+ const viewBoxPattern = /0 0 ([0-9]+) ([0-9]+)/;
104
+
105
+ if (!viewBoxPattern.test(svgViewBox)) {
106
+ throw new Error(
107
+ `${filename}: Invalid viewBox attribute. The viewBox attribute should be in the following format: "0 0 <width> <height>"`
108
+ );
109
+ }
110
+
111
+ const [, viewBoxWidth, viewBoxHeight] = svgViewBox.match(viewBoxPattern);
112
+
113
+ if (svgWidth !== parseInt(viewBoxWidth)) {
114
+ throw new Error(
115
+ `${filename}: width attribute and viewBox width do not match.`
116
+ );
117
+ }
118
+
119
+ if (svgHeight !== parseInt(viewBoxHeight)) {
120
+ throw new Error(
121
+ `${filename}: height attribute and viewBox height do not match.`
122
+ );
123
+ }
124
+
125
+ return {
126
+ name,
127
+ keywords: keywords[name] || [],
128
+ type: type,
129
+ width: svgWidth,
130
+ height: svgHeight,
131
+ path: svgPath,
132
+ };
133
+ } catch (error) {
134
+ // eslint-disable-next-line no-console
135
+ console.error(error);
136
+ // Instead of exiting immediately, we set exitCode to 1 and continue
137
+ // iterating through the rest of the SVGs. This allows us to identify all
138
+ // the SVGs that have errors, not just the first one. An exit code of 1
139
+ // indicates that an error occurred.
140
+ // Reference: https://nodejs.org/api/process.html#process_exit_codes
141
+ exitCode = 1;
142
+ return null;
143
+ }
144
+ });
145
+
146
+ // Exit early if any errors occurred.
147
+ if (exitCode !== 0) {
148
+ process.exit(exitCode);
149
+ }
150
+
151
+ const iconsByName = icons.reduce(
152
+ (acc, icon) =>
153
+ merge(acc, {
154
+ [icon.name]: {
155
+ name: icon.name,
156
+ keywords: icon.keywords,
157
+ variants: {
158
+ [icon.type]: {
159
+ width: icon.width,
160
+ height: icon.height,
161
+ path: icon.path,
162
+ },
163
+ },
164
+ },
165
+ }),
166
+ {}
167
+ );
168
+
169
+ fs.outputJsonSync(path.resolve(argv.output), iconsByName);
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: heroicons_helper
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Garen J. Torikian
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2022-06-09 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: A package that distributes Heroicons as a gem, for easy inclusion in
14
+ Ruby projects.
15
+ email:
16
+ - gjtorikian@users.noreply.github.com
17
+ executables: []
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - ".rubocop.yml"
22
+ - CHANGELOG.md
23
+ - Gemfile
24
+ - LICENSE.txt
25
+ - README.md
26
+ - Rakefile
27
+ - heroicons_helper.gemspec
28
+ - lib/heroicons_helper.rb
29
+ - lib/heroicons_helper/data.json
30
+ - lib/heroicons_helper/icon.rb
31
+ - lib/heroicons_helper/version.rb
32
+ - package-lock.json
33
+ - package.json
34
+ - script/keywords.json
35
+ - script/update_heroicons
36
+ homepage: https://github.com/gjtorikian/heroicons_helper
37
+ licenses:
38
+ - MIT
39
+ metadata:
40
+ homepage_uri: https://github.com/gjtorikian/heroicons_helper
41
+ source_code_uri: https://github.com/gjtorikian/heroicons_helper
42
+ post_install_message:
43
+ rdoc_options: []
44
+ require_paths:
45
+ - lib
46
+ required_ruby_version: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - ">="
49
+ - !ruby/object:Gem::Version
50
+ version: 2.7.0
51
+ - - "<"
52
+ - !ruby/object:Gem::Version
53
+ version: 4.0.0
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ requirements: []
60
+ rubygems_version: 3.3.13
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: Heroicons port for Ruby
64
+ test_files: []