@hibi_10000/grunt-webfont 2.0.1 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/Gruntfile.ts ADDED
@@ -0,0 +1,370 @@
1
+ import path from 'node:path';
2
+ //@ts-expect-error
3
+ import clean from 'grunt-contrib-clean';
4
+ import webfont from './tasks/webfont.ts';
5
+
6
+ import type { Configs } from './tasks/types.ts';
7
+
8
+ const config = (grunt: IGrunt) => {
9
+ clean(grunt);
10
+
11
+ webfont(grunt);
12
+
13
+ grunt.initConfig({
14
+ webfont: {
15
+ test1: {
16
+ src: 'test/src/*.svg',
17
+ dest: 'test/tmp/test1',
18
+ options: {
19
+ hashes: false
20
+ }
21
+ },
22
+ test2: {
23
+ src: 'test/src/*.svg',
24
+ dest: 'test/tmp/test2/fonts',
25
+ destCss: 'test/tmp/test2',
26
+ options: {
27
+ font: 'myfont',
28
+ types: 'woff,svg',
29
+ syntax: 'bootstrap'
30
+ }
31
+ },
32
+ embed: {
33
+ src: 'test/src/*.svg',
34
+ dest: 'test/tmp/embed',
35
+ options: {
36
+ hashes: false,
37
+ embed: true
38
+ }
39
+ },
40
+ embed_woff: {
41
+ src: 'test/src/*.svg',
42
+ dest: 'test/tmp/embed_woff',
43
+ options: {
44
+ types: 'woff',
45
+ hashes: false,
46
+ embed: true
47
+ }
48
+ },
49
+ embed_ttf: {
50
+ src: 'test/src/*.svg',
51
+ dest: 'test/tmp/embed_ttf',
52
+ options: {
53
+ types: 'ttf',
54
+ hashes: false,
55
+ embed: 'ttf'
56
+ }
57
+ },
58
+ embed_ttf_woff: {
59
+ src: 'test/src/*.svg',
60
+ dest: 'test/tmp/embed_ttf_woff',
61
+ options: {
62
+ types: 'ttf,woff',
63
+ hashes: false,
64
+ embed: 'ttf,woff'
65
+ }
66
+ },
67
+ one: {
68
+ src: 'test/src_one/*.svg',
69
+ dest: 'test/tmp/one',
70
+ options: {
71
+ hashes: false
72
+ }
73
+ },
74
+ template: {
75
+ src: 'test/src/*.svg',
76
+ dest: 'test/tmp/template',
77
+ options: {
78
+ template: 'test/templates/template.css'
79
+ }
80
+ },
81
+ template_scss: {
82
+ src: 'test/src/*.svg',
83
+ dest: 'test/tmp/template_scss',
84
+ options: {
85
+ stylesheet: 'scss',
86
+ template: 'test/templates/template.scss'
87
+ }
88
+ },
89
+ template_sass: {
90
+ src: 'test/src/*.svg',
91
+ dest: 'test/tmp/template_sass',
92
+ options: {
93
+ template: 'test/templates/template.sass'
94
+ }
95
+ },
96
+ html_template: {
97
+ src: 'test/src/*.svg',
98
+ dest: 'test/tmp/html_template',
99
+ options: {
100
+ htmlDemoTemplate: 'test/templates/template.html'
101
+ }
102
+ },
103
+ html_filename: {
104
+ src: 'test/src/*.svg',
105
+ dest: 'test/tmp/html_filename',
106
+ options: {
107
+ htmlDemoFilename: 'index'
108
+ }
109
+ },
110
+ relative_path: {
111
+ src: 'test/src/*.svg',
112
+ dest: 'test/tmp/relative_path',
113
+ options: {
114
+ relativeFontPath: '../iamrelative',
115
+ hashes: false
116
+ }
117
+ },
118
+ sass: {
119
+ src: 'test/src/*.svg',
120
+ dest: 'test/tmp/sass',
121
+ options: {
122
+ stylesheet: 'sass'
123
+ }
124
+ },
125
+ less: {
126
+ src: 'test/src/*.svg',
127
+ dest: 'test/tmp/less',
128
+ options: {
129
+ stylesheet: 'less'
130
+ }
131
+ },
132
+ css_plus_scss: {
133
+ src: 'test/src/*.svg',
134
+ dest: 'test/tmp/sass',
135
+ destCss: 'test/tmp/css',
136
+ destScss: 'test/tmp/scss',
137
+ options: {
138
+ stylesheets: ['css', 'scss']
139
+ }
140
+ },
141
+ stylus_bem: {
142
+ src: 'test/src/*.svg',
143
+ dest: 'test/tmp/stylus_bem',
144
+ options: {
145
+ stylesheet: 'styl'
146
+ }
147
+ },
148
+ stylus_bootstrap: {
149
+ src: 'test/src/*.svg',
150
+ dest: 'test/tmp/stylus_bootstrap',
151
+ options: {
152
+ stylesheet: 'styl',
153
+ syntax: 'bootstrap'
154
+ }
155
+ },
156
+ spaces: {
157
+ src: 'test/src_space/*.svg',
158
+ dest: 'test/tmp/spaces'
159
+ },
160
+ disable_demo: {
161
+ src: 'test/src_one/*.svg',
162
+ dest: 'test/tmp/disable_demo',
163
+ options: {
164
+ htmlDemo: false
165
+ }
166
+ },
167
+ non_css_demo: {
168
+ src: 'test/src/*.svg',
169
+ dest: 'test/tmp/non_css_demo',
170
+ options: {
171
+ stylesheet: 'less',
172
+ relativeFontPath: '../iamrelative',
173
+ htmlDemo: true
174
+ }
175
+ },
176
+ parent_source: {
177
+ src: '../grunt-webfont/test/src/*.svg',
178
+ dest: 'test/tmp/parent_source',
179
+ options: {
180
+ hashes: false
181
+ }
182
+ },
183
+ // #167: Ligatures with hyphen don’t work
184
+ ligatures: {
185
+ src: 'test/src_ligatures/*.svg',
186
+ dest: 'test/tmp/ligatures',
187
+ options: {
188
+ hashes: false,
189
+ ligatures: true
190
+ }
191
+ },
192
+ duplicate_names: {
193
+ src: '../grunt-webfont/test/src_duplicate_names/**/*.svg',
194
+ dest: 'test/tmp/duplicate_names',
195
+ options: {
196
+ hashes: false,
197
+ rename: (name) => {
198
+ return [path.basename(path.dirname(name)), path.basename(name)].join('-');
199
+ }
200
+ }
201
+ },
202
+ order: {
203
+ src: 'test/src/*.svg',
204
+ dest: 'test/tmp/order',
205
+ options: {
206
+ types: 'woff,svg',
207
+ order: 'svg,woff',
208
+ hashes: false
209
+ }
210
+ },
211
+ template_options: {
212
+ src: 'test/src/*.svg',
213
+ dest: 'test/tmp/template_options',
214
+ options: {
215
+ hashes: false,
216
+ syntax: 'bem',
217
+ stylesheet: 'less',
218
+ templateOptions: {
219
+ baseClass: 'glyph-icon',
220
+ classPrefix: 'glyph_'
221
+ }
222
+ }
223
+ },
224
+ node: {
225
+ src: 'test/src/*.svg',
226
+ dest: 'test/tmp/node',
227
+ options: {
228
+ hashes: false,
229
+ engine: 'node'
230
+ }
231
+ },
232
+ ie7: {
233
+ src: 'test/src/*.svg',
234
+ dest: 'test/tmp/ie7',
235
+ options: {
236
+ hashes: false,
237
+ ie7: true,
238
+ syntax: 'bem'
239
+ }
240
+ },
241
+ ie7_bootstrap: {
242
+ src: 'test/src/*.svg',
243
+ dest: 'test/tmp/ie7_bootstrap',
244
+ options: {
245
+ hashes: false,
246
+ ie7: true,
247
+ syntax: 'bootstrap'
248
+ }
249
+ },
250
+ optimize_enabled: {
251
+ src: 'test/src/*.svg',
252
+ dest: 'test/tmp/optimize_enabled',
253
+ options: {
254
+ engine: 'node',
255
+ types: 'svg',
256
+ autoHint: false,
257
+ optimize: true
258
+ }
259
+ },
260
+ optimize_disabled: {
261
+ src: 'test/src/*.svg',
262
+ dest: 'test/tmp/optimize_disabled',
263
+ options: {
264
+ engine: 'node',
265
+ types: 'svg',
266
+ autoHint: false,
267
+ optimize: false
268
+ }
269
+ },
270
+ codepoints: {
271
+ src: 'test/src/*.svg',
272
+ dest: 'test/tmp/codepoints',
273
+ options: {
274
+ types: 'svg',
275
+ hashes: false,
276
+ startCodepoint: 0x41,
277
+ codepoints: {
278
+ single: 0x43
279
+ }
280
+ }
281
+ },
282
+ camel: {
283
+ src: 'test/camel/*.svg',
284
+ dest: 'test/tmp/camel',
285
+ options: {
286
+ hashes: false
287
+ }
288
+ },
289
+ folders: {
290
+ src: 'test/src_folders/**/*.svg',
291
+ dest: 'test/tmp/folders',
292
+ options: {
293
+ hashes: false
294
+ }
295
+ },
296
+ woff2: {
297
+ src: 'test/src/*.svg',
298
+ dest: 'test/tmp/woff2',
299
+ options: {
300
+ types: 'woff2,woff'
301
+ }
302
+ },
303
+ woff2_node: {
304
+ src: 'test/src/*.svg',
305
+ dest: 'test/tmp/woff2_node',
306
+ options: {
307
+ types: 'woff2,woff',
308
+ engine: 'node'
309
+ }
310
+ },
311
+ target_overrides: {
312
+ src: 'test/src/*.svg',
313
+ options: {
314
+ dest: 'test/tmp/target_overrides_icons',
315
+ destCss: 'test/tmp/target_overrides_css',
316
+ }
317
+ },
318
+ font_family_name: {
319
+ src: 'test/src/*.svg',
320
+ dest: 'test/tmp/font_family_name',
321
+ options: {
322
+ fontFamilyName: 'customName',
323
+ types: 'ttf',
324
+ }
325
+ },
326
+ custom_output: {
327
+ src: 'test/src/*.svg',
328
+ options: {
329
+ dest: 'test/tmp/custom_output_icons',
330
+ destCss: 'test/tmp/custom_output_css',
331
+ customOutputs: [{
332
+ template: 'test/templates/custom.js',
333
+ dest: 'test/tmp/custom_output/test-icon-config.js'
334
+ }, {
335
+ template: 'test/templates/custom.json',
336
+ dest: 'test/tmp/custom_output'
337
+ }, {
338
+ template: 'test/templates/context-test.html',
339
+ dest: 'test/tmp/custom_output',
340
+ context: {
341
+ testHeading: 'Hello, world!'
342
+ }
343
+ }]
344
+ }
345
+ },
346
+ enabled_template_variables: {
347
+ src: 'test/src/*.svg',
348
+ dest: 'test/tmp/enabled_template_variables',
349
+ options: {
350
+ relativeFontPath: '../iamrelative',
351
+ fontPathVariables: true,
352
+ stylesheets: ['css', 'scss', 'less']
353
+ }
354
+ },
355
+ filename_length: {
356
+ src: 'test/src_filename_length/*.svg',
357
+ dest: 'test/tmp/filename_length',
358
+ options: {
359
+ autoHint: false,
360
+ engine: 'node',
361
+ hashes: false,
362
+ types: 'woff'
363
+ }
364
+ },
365
+ } satisfies Configs,
366
+ clean: ['test/tmp']
367
+ });
368
+ };
369
+
370
+ export { config as "module.exports" }
@@ -2,6 +2,7 @@ The MIT License
2
2
  ===============
3
3
 
4
4
  Copyright © 2025 Hibi_10000
5
+
5
6
  Copyright © 2014 Artem Sapegin, http://sapegin.me
6
7
 
7
8
  Permission is hereby granted, free of charge, to any person obtaining
@@ -81,7 +81,7 @@ for dirname, dirnames, filenames in os.walk(args['inputDir']):
81
81
  if args['round']:
82
82
  glyph.round(int(args['round']))
83
83
 
84
- fontfile = args['dest'] + os.path.sep + args['fontFilename']
84
+ fontfile = args['dest'] + '/' + args['fontFilename']
85
85
 
86
86
  f.fontname = args['fontFilename']
87
87
  f.familyname = args['fontFamilyName']
@@ -5,8 +5,13 @@ import chalk from "chalk";
5
5
  import util from "node:util";
6
6
  import { exec } from "node:child_process";
7
7
  import temp from "temp";
8
-
9
8
  //#region tasks/engines/fontforge.ts
9
+ /**
10
+ * grunt-webfont: fontforge engine
11
+ *
12
+ * @requires fontforge, ttfautohint 1.00+ (optional), eotlitetool.py
13
+ * @author Artem Sapegin (http://sapegin.me), Hibi_10000
14
+ */
10
15
  var fontforge_default = async (o) => {
11
16
  const logger = o.logger || consolaLogger;
12
17
  temp.track();
@@ -30,7 +35,7 @@ var fontforge_default = async (o) => {
30
35
  });
31
36
  proc.on("exit", (code, signal) => {
32
37
  if (code !== 0) logger.log.info(`fontforge process has unexpectedly closed.
33
- 1. Try to run grunt in verbose mode to see fontforge output: ${chalk.bold("grunt --verbose webfont")}.\n2. If stderr maxBuffer exceeded try to increase ${chalk.bold("execMaxBuffer")}, see ${chalk.underline("https://github.com/sapegin/grunt-webfont#execMaxBuffer")}. `);
38
+ 1. Try to run grunt in verbose mode to see fontforge output: ${chalk.bold("grunt --verbose webfont")}.\n2. If stderr maxBuffer exceeded try to increase ${chalk.bold("execMaxBuffer")}, see ${chalk.underline("https://github.com/Hibi-10000/grunt-webfont#execMaxBuffer")}. `);
34
39
  });
35
40
  const params = Object.assign(o, { inputDir: tempDir });
36
41
  proc.stdin.write(JSON.stringify(params));
@@ -40,7 +45,7 @@ var fontforge_default = async (o) => {
40
45
  out = (await promise).stdout;
41
46
  } catch (err) {
42
47
  if (err instanceof Error && err.code === 127) {
43
- logger.log.error(`fontforge not found. Please install fontforge and all other requirements: ${chalk.underline("https://github.com/sapegin/grunt-webfont#installation")}`);
48
+ logger.log.error(`fontforge not found. Please install fontforge and all other requirements: ${chalk.underline("https://github.com/Hibi-10000/grunt-webfont#installation")}`);
44
49
  return false;
45
50
  }
46
51
  if (err instanceof Error) {
@@ -71,14 +76,14 @@ var fontforge_default = async (o) => {
71
76
  logger.log.verbose(`Webfont did not receive a proper JSON result from Python script: ${e}`);
72
77
  logger.log.error(`Something went wrong when running fontforge. Probably fontforge wasn’t installed correctly or one of your SVGs is too complicated for fontforge.
73
78
 
74
- 1. Try to run Grunt in verbose mode: ${chalk.bold("grunt --verbose webfont")} and see what fontforge says. Then search GitHub issues for the solution: ${chalk.underline("https://github.com/sapegin/grunt-webfont/issues")}.\n\n2. Try to use “node” engine instead of “fontforge”: ${chalk.underline("https://github.com/sapegin/grunt-webfont#engine")}\n\n3. To find “bad” icon try to remove SVGs one by one until error disappears. Then try to simplify this SVG in Sketch, Illustrator, etc.
79
+ 1. Try to run Grunt in verbose mode: ${chalk.bold("grunt --verbose webfont")} and see what fontforge says. Then search GitHub issues for the solution: ${chalk.underline("https://github.com/Hibi-10000/grunt-webfont/issues")}.\n\n2. Try to use “node” engine instead of “fontforge”: ${chalk.underline("https://github.com/Hibi-10000/grunt-webfont#engine")}\n\n3. To find “bad” icon try to remove SVGs one by one until error disappears. Then try to simplify this SVG in Sketch, Illustrator, etc.
75
80
 
76
81
  `);
77
82
  return false;
78
83
  }
79
84
  return { fontName: path.basename(result.file) };
80
85
  };
81
-
82
86
  //#endregion
83
87
  export { fontforge_default as default };
88
+
84
89
  //# sourceMappingURL=fontforge.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fontforge.js","names":["wf.consolaLogger","err: unknown","wf.generatedFontFiles","warn: string[]","result: { file: string }"],"sources":["../../tasks/engines/fontforge.ts"],"sourcesContent":["/**\n * grunt-webfont: fontforge engine\n *\n * @requires fontforge, ttfautohint 1.00+ (optional), eotlitetool.py\n * @author Artem Sapegin (http://sapegin.me), Hibi_10000\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport util from 'node:util';\nimport { exec, type ExecException } from 'node:child_process';\nimport temp from 'temp';\nimport chalk from 'chalk';\n\nimport * as wf from '../util/util.ts';\nimport type { OptionsInternal } from '../types.ts';\n\nexport default async (o: OptionsInternal): Promise<false | { fontName: string }> => {\n\tconst logger = o.logger || wf.consolaLogger;\n\n\t// Copy source files to temporary directory\n\ttemp.track();\n\tconst tempDir = temp.mkdirSync();\n\to.files.forEach((file) => {\n\t\tfs.writeFileSync(path.join(tempDir, o.rename(file)), fs.readFileSync(file));\n\t});\n\n\t// Run Fontforge\n\tconst args = [\n\t\t'fontforge',\n\t\t'-script',\n\t\t`\"${path.join(import.meta.dirname, '../../bin/fontforge/generate.py')}\"`,\n\t].join(' ');\n\n\tconst execPromise = util.promisify(exec);\n\tconst promise = execPromise(args, { maxBuffer: o.execMaxBuffer });\n\tconst proc = promise.child;\n\n\t// Send JSON with params\n\tif (!proc) throw new TypeError('process is null');\n\n\tproc.stderr.on('data', (data) => {\n\t\tlogger.log.verbose(data);\n\t});\n\tproc.stdout.on('data', (data) => {\n\t\tlogger.log.verbose(data);\n\t});\n\tproc.on('exit', (code, signal) => {\n\t\tif (code !== 0) {\n\t\t\tlogger.log.info( // cannot use error() because it will stop execution of callback of exec (which shows error message)\n\t\t\t\t\"fontforge process has unexpectedly closed.\\n\" +\n\t\t\t\t`1. Try to run grunt in verbose mode to see fontforge output: ${chalk.bold('grunt --verbose webfont')}.\\n` +\n\t\t\t\t`2. If stderr maxBuffer exceeded try to increase ${chalk.bold('execMaxBuffer')}, ` +\n\t\t\t\t`see ${chalk.underline('https://github.com/sapegin/grunt-webfont#execMaxBuffer')}. `\n\t\t\t);\n\t\t}\n\t});\n\n\tconst params = Object.assign(o, {\n\t\tinputDir: tempDir,\n\t});\n\tproc.stdin.write(JSON.stringify(params));\n\tproc.stdin.end();\n\n\tlet out;\n\ttry {\n\t\tout = (await promise).stdout;\n\t} catch (err: unknown) {\n\t\tif (err instanceof Error && (err as ExecException).code === 127) {\n\t\t\tlogger.log.error(`fontforge not found. Please install fontforge and all other requirements: ${chalk.underline('https://github.com/sapegin/grunt-webfont#installation')}`);\n\t\t\treturn false;\n\t\t}\n\t\tif (err instanceof Error) {\n\t\t\tlogger.log.error(err.message);\n\t\t\treturn false;\n\t\t}\n\t\tlogger.log.error(`probably an impossible error`);\n\n\t\t// Skip some fontforge output such as copyrights. Show warnings only when no font files was created\n\t\t// or in verbose mode.\n\t\tconst success = !!wf.generatedFontFiles(o);\n\t\tconst notError = /(Copyright|License |with many parts BSD |Executable based on sources from|Library based on sources from|Based on source from git)/;\n\t\t//const version = /(Executable based on sources from|Library based on sources from)/;\n\t\tconst lines = (err as string).split('\\n');\n\n\t\tconst warn: string[] = [];\n\t\tlines.forEach((line) => {\n\t\t\tif (!line.match(notError) && !success) {\n\t\t\t\twarn.push(line);\n\t\t\t} else {\n\t\t\t\tlogger.log.verbose(chalk.grey('fontforge: ') + line);\n\t\t\t}\n\t\t});\n\n\t\tif (warn.length) {\n\t\t\tlogger.log.error(warn.join('\\n'));\n\t\t\treturn false;\n\t\t}\n\t\tlogger.log.error(`impossible error: ${err}`);\n\t\treturn false;\n\t}\n\n\t// Trim fontforge result\n\tconst json = out.replace(/^[^{]+/, '').replace(/[^}]+$/, '');\n\n\t// Parse json\n\tlet result: { file: string };\n\ttry {\n\t\tresult = JSON.parse(json);\n\t} catch (e) {\n\t\tlogger.log.verbose(`Webfont did not receive a proper JSON result from Python script: ${e}`);\n\t\tlogger.log.error(\n\t\t\t'Something went wrong when running fontforge. Probably fontforge wasn’t installed correctly or one of your SVGs is too complicated for fontforge.\\n\\n' +\n\t\t\t`1. Try to run Grunt in verbose mode: ${chalk.bold('grunt --verbose webfont')} and see what fontforge says. Then search GitHub issues for the solution: ${chalk.underline('https://github.com/sapegin/grunt-webfont/issues')}.\\n\\n` +\n\t\t\t`2. Try to use “node” engine instead of “fontforge”: ${chalk.underline('https://github.com/sapegin/grunt-webfont#engine')}\\n\\n` +\n\t\t\t'3. To find “bad” icon try to remove SVGs one by one until error disappears. Then try to simplify this SVG in Sketch, Illustrator, etc.\\n\\n'\n\t\t);\n\t\treturn false;\n\t}\n\n\treturn {\n\t\tfontName: path.basename(result.file)\n\t};\n};\n"],"mappings":";;;;;;;;;AAiBA,wBAAe,OAAO,MAA8D;CACnF,MAAM,SAAS,EAAE,UAAUA;AAG3B,MAAK,OAAO;CACZ,MAAM,UAAU,KAAK,WAAW;AAChC,GAAE,MAAM,SAAS,SAAS;AACzB,KAAG,cAAc,KAAK,KAAK,SAAS,EAAE,OAAO,KAAK,CAAC,EAAE,GAAG,aAAa,KAAK,CAAC;GAC1E;CAGF,MAAM,OAAO;EACZ;EACA;EACA,IAAI,KAAK,KAAK,OAAO,KAAK,SAAS,kCAAkC,CAAC;EACtE,CAAC,KAAK,IAAI;CAGX,MAAM,UADc,KAAK,UAAU,KAAK,CACZ,MAAM,EAAE,WAAW,EAAE,eAAe,CAAC;CACjE,MAAM,OAAO,QAAQ;AAGrB,KAAI,CAAC,KAAM,OAAM,IAAI,UAAU,kBAAkB;AAEjD,MAAK,OAAO,GAAG,SAAS,SAAS;AAChC,SAAO,IAAI,QAAQ,KAAK;GACvB;AACF,MAAK,OAAO,GAAG,SAAS,SAAS;AAChC,SAAO,IAAI,QAAQ,KAAK;GACvB;AACF,MAAK,GAAG,SAAS,MAAM,WAAW;AACjC,MAAI,SAAS,EACZ,QAAO,IAAI,KACV;+DACgE,MAAM,KAAK,0BAA0B,CAAC,qDACnD,MAAM,KAAK,gBAAgB,CAAC,QACxE,MAAM,UAAU,yDAAyD,CAAC,IACjF;GAED;CAEF,MAAM,SAAS,OAAO,OAAO,GAAG,EAC/B,UAAU,SACV,CAAC;AACF,MAAK,MAAM,MAAM,KAAK,UAAU,OAAO,CAAC;AACxC,MAAK,MAAM,KAAK;CAEhB,IAAI;AACJ,KAAI;AACH,SAAO,MAAM,SAAS;UACdC,KAAc;AACtB,MAAI,eAAe,SAAU,IAAsB,SAAS,KAAK;AAChE,UAAO,IAAI,MAAM,6EAA6E,MAAM,UAAU,wDAAwD,GAAG;AACzK,UAAO;;AAER,MAAI,eAAe,OAAO;AACzB,UAAO,IAAI,MAAM,IAAI,QAAQ;AAC7B,UAAO;;AAER,SAAO,IAAI,MAAM,+BAA+B;EAIhD,MAAM,UAAU,CAAC,CAACC,mBAAsB,EAAE;EAC1C,MAAM,WAAW;EAEjB,MAAM,QAAS,IAAe,MAAM,KAAK;EAEzC,MAAMC,OAAiB,EAAE;AACzB,QAAM,SAAS,SAAS;AACvB,OAAI,CAAC,KAAK,MAAM,SAAS,IAAI,CAAC,QAC7B,MAAK,KAAK,KAAK;OAEf,QAAO,IAAI,QAAQ,MAAM,KAAK,cAAc,GAAG,KAAK;IAEpD;AAEF,MAAI,KAAK,QAAQ;AAChB,UAAO,IAAI,MAAM,KAAK,KAAK,KAAK,CAAC;AACjC,UAAO;;AAER,SAAO,IAAI,MAAM,qBAAqB,MAAM;AAC5C,SAAO;;CAIR,MAAM,OAAO,IAAI,QAAQ,UAAU,GAAG,CAAC,QAAQ,UAAU,GAAG;CAG5D,IAAIC;AACJ,KAAI;AACH,WAAS,KAAK,MAAM,KAAK;UACjB,GAAG;AACX,SAAO,IAAI,QAAQ,oEAAoE,IAAI;AAC3F,SAAO,IAAI,MACV;;uCACwC,MAAM,KAAK,0BAA0B,CAAC,4EAA4E,MAAM,UAAU,kDAAkD,CAAC,2DACtK,MAAM,UAAU,kDAAkD,CAAC;;EAE1H;AACD,SAAO;;AAGR,QAAO,EACN,UAAU,KAAK,SAAS,OAAO,KAAK,EACpC"}
1
+ {"version":3,"file":"fontforge.js","names":["wf.consolaLogger","wf.generatedFontFiles"],"sources":["../../tasks/engines/fontforge.ts"],"sourcesContent":["/**\n * grunt-webfont: fontforge engine\n *\n * @requires fontforge, ttfautohint 1.00+ (optional), eotlitetool.py\n * @author Artem Sapegin (http://sapegin.me), Hibi_10000\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport util from 'node:util';\nimport { exec, type ExecException } from 'node:child_process';\nimport temp from 'temp';\nimport chalk from 'chalk';\n\nimport * as wf from '../util/util.ts';\nimport type { OptionsInternal } from '../types.ts';\n\nexport default async (o: OptionsInternal): Promise<false | { fontName: string }> => {\n\tconst logger = o.logger || wf.consolaLogger;\n\n\t// Copy source files to temporary directory\n\ttemp.track();\n\tconst tempDir = temp.mkdirSync();\n\to.files.forEach((file) => {\n\t\tfs.writeFileSync(path.join(tempDir, o.rename(file)), fs.readFileSync(file));\n\t});\n\n\t// Run Fontforge\n\tconst args = [\n\t\t'fontforge',\n\t\t'-script',\n\t\t`\"${path.join(import.meta.dirname, '../../bin/fontforge/generate.py')}\"`,\n\t].join(' ');\n\n\tconst execPromise = util.promisify(exec);\n\tconst promise = execPromise(args, { maxBuffer: o.execMaxBuffer });\n\tconst proc = promise.child;\n\n\t// Send JSON with params\n\tif (!proc) throw new TypeError('process is null');\n\n\tproc.stderr.on('data', (data) => {\n\t\tlogger.log.verbose(data);\n\t});\n\tproc.stdout.on('data', (data) => {\n\t\tlogger.log.verbose(data);\n\t});\n\tproc.on('exit', (code, signal) => {\n\t\tif (code !== 0) {\n\t\t\tlogger.log.info( // cannot use error() because it will stop execution of callback of exec (which shows error message)\n\t\t\t\t\"fontforge process has unexpectedly closed.\\n\" +\n\t\t\t\t`1. Try to run grunt in verbose mode to see fontforge output: ${chalk.bold('grunt --verbose webfont')}.\\n` +\n\t\t\t\t`2. If stderr maxBuffer exceeded try to increase ${chalk.bold('execMaxBuffer')}, ` +\n\t\t\t\t`see ${chalk.underline('https://github.com/Hibi-10000/grunt-webfont#execMaxBuffer')}. `\n\t\t\t);\n\t\t}\n\t});\n\n\tconst params = Object.assign(o, {\n\t\tinputDir: tempDir,\n\t});\n\tproc.stdin.write(JSON.stringify(params));\n\tproc.stdin.end();\n\n\tlet out: string;\n\ttry {\n\t\tout = (await promise).stdout;\n\t} catch (err: unknown) {\n\t\tif (err instanceof Error && (err as ExecException).code === 127) {\n\t\t\tlogger.log.error(`fontforge not found. Please install fontforge and all other requirements: ${chalk.underline('https://github.com/Hibi-10000/grunt-webfont#installation')}`);\n\t\t\treturn false;\n\t\t}\n\t\tif (err instanceof Error) {\n\t\t\tlogger.log.error(err.message);\n\t\t\treturn false;\n\t\t}\n\t\tlogger.log.error(`probably an impossible error`);\n\n\t\t// Skip some fontforge output such as copyrights. Show warnings only when no font files was created\n\t\t// or in verbose mode.\n\t\tconst success = !!wf.generatedFontFiles(o);\n\t\tconst notError = /(Copyright|License |with many parts BSD |Executable based on sources from|Library based on sources from|Based on source from git)/;\n\t\t//const version = /(Executable based on sources from|Library based on sources from)/;\n\t\tconst lines = (err as string).split('\\n');\n\n\t\tconst warn: string[] = [];\n\t\tlines.forEach((line) => {\n\t\t\tif (!line.match(notError) && !success) {\n\t\t\t\twarn.push(line);\n\t\t\t} else {\n\t\t\t\tlogger.log.verbose(chalk.grey('fontforge: ') + line);\n\t\t\t}\n\t\t});\n\n\t\tif (warn.length) {\n\t\t\tlogger.log.error(warn.join('\\n'));\n\t\t\treturn false;\n\t\t}\n\t\tlogger.log.error(`impossible error: ${err}`);\n\t\treturn false;\n\t}\n\n\t// Trim fontforge result\n\tconst json = out.replace(/^[^{]+/, '').replace(/[^}]+$/, '');\n\n\t// Parse json\n\tlet result: { file: string };\n\ttry {\n\t\tresult = JSON.parse(json);\n\t} catch (e) {\n\t\tlogger.log.verbose(`Webfont did not receive a proper JSON result from Python script: ${e}`);\n\t\tlogger.log.error(\n\t\t\t'Something went wrong when running fontforge. Probably fontforge wasn’t installed correctly or one of your SVGs is too complicated for fontforge.\\n\\n' +\n\t\t\t`1. Try to run Grunt in verbose mode: ${chalk.bold('grunt --verbose webfont')} and see what fontforge says. Then search GitHub issues for the solution: ${chalk.underline('https://github.com/Hibi-10000/grunt-webfont/issues')}.\\n\\n` +\n\t\t\t`2. Try to use “node” engine instead of “fontforge”: ${chalk.underline('https://github.com/Hibi-10000/grunt-webfont#engine')}\\n\\n` +\n\t\t\t'3. To find “bad” icon try to remove SVGs one by one until error disappears. Then try to simplify this SVG in Sketch, Illustrator, etc.\\n\\n'\n\t\t);\n\t\treturn false;\n\t}\n\n\treturn {\n\t\tfontName: path.basename(result.file)\n\t};\n};\n"],"mappings":";;;;;;;;;;;;;;AAiBA,IAAA,oBAAe,OAAO,MAA8D;CACnF,MAAM,SAAS,EAAE,UAAUA;CAG3B,KAAK,MAAM;CACX,MAAM,UAAU,KAAK,UAAU;CAC/B,EAAE,MAAM,SAAS,SAAS;EACzB,GAAG,cAAc,KAAK,KAAK,SAAS,EAAE,OAAO,IAAI,CAAC,GAAG,GAAG,aAAa,IAAI,CAAC;CAC3E,CAAC;CAGD,MAAM,OAAO;EACZ;EACA;EACA,IAAI,KAAK,KAAK,YAAY,SAAS,iCAAiC,EAAE;CACvE,CAAC,CAAC,KAAK,GAAG;CAGV,MAAM,UADc,KAAK,UAAU,IACT,CAAC,CAAC,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC;CAChE,MAAM,OAAO,QAAQ;CAGrB,IAAI,CAAC,MAAM,MAAM,IAAI,UAAU,iBAAiB;CAEhD,KAAK,OAAO,GAAG,SAAS,SAAS;EAChC,OAAO,IAAI,QAAQ,IAAI;CACxB,CAAC;CACD,KAAK,OAAO,GAAG,SAAS,SAAS;EAChC,OAAO,IAAI,QAAQ,IAAI;CACxB,CAAC;CACD,KAAK,GAAG,SAAS,MAAM,WAAW;EACjC,IAAI,SAAS,GACZ,OAAO,IAAI,KACV;+DACgE,MAAM,KAAK,yBAAyB,EAAE,qDACnD,MAAM,KAAK,eAAe,EAAE,QACxE,MAAM,UAAU,2DAA2D,EAAE,GACrF;CAEF,CAAC;CAED,MAAM,SAAS,OAAO,OAAO,GAAG,EAC/B,UAAU,QACX,CAAC;CACD,KAAK,MAAM,MAAM,KAAK,UAAU,MAAM,CAAC;CACvC,KAAK,MAAM,IAAI;CAEf,IAAI;CACJ,IAAI;EACH,OAAO,MAAM,QAAA,CAAS;CACvB,SAAS,KAAc;EACtB,IAAI,eAAe,SAAU,IAAsB,SAAS,KAAK;GAChE,OAAO,IAAI,MAAM,6EAA6E,MAAM,UAAU,0DAA0D,GAAG;GAC3K,OAAO;EACR;EACA,IAAI,eAAe,OAAO;GACzB,OAAO,IAAI,MAAM,IAAI,OAAO;GAC5B,OAAO;EACR;EACA,OAAO,IAAI,MAAM,8BAA8B;EAI/C,MAAM,UAAU,CAAC,CAACC,mBAAsB,CAAC;EACzC,MAAM,WAAW;EAEjB,MAAM,QAAS,IAAe,MAAM,IAAI;EAExC,MAAM,OAAiB,CAAC;EACxB,MAAM,SAAS,SAAS;GACvB,IAAI,CAAC,KAAK,MAAM,QAAQ,KAAK,CAAC,SAC7B,KAAK,KAAK,IAAI;QAEd,OAAO,IAAI,QAAQ,MAAM,KAAK,aAAa,IAAI,IAAI;EAErD,CAAC;EAED,IAAI,KAAK,QAAQ;GAChB,OAAO,IAAI,MAAM,KAAK,KAAK,IAAI,CAAC;GAChC,OAAO;EACR;EACA,OAAO,IAAI,MAAM,qBAAqB,KAAK;EAC3C,OAAO;CACR;CAGA,MAAM,OAAO,IAAI,QAAQ,UAAU,EAAE,CAAC,CAAC,QAAQ,UAAU,EAAE;CAG3D,IAAI;CACJ,IAAI;EACH,SAAS,KAAK,MAAM,IAAI;CACzB,SAAS,GAAG;EACX,OAAO,IAAI,QAAQ,oEAAoE,GAAG;EAC1F,OAAO,IAAI,MACV;;uCACwC,MAAM,KAAK,yBAAyB,EAAE,4EAA4E,MAAM,UAAU,oDAAoD,EAAE,2DACzK,MAAM,UAAU,oDAAoD,EAAE;;CAE9H;EACA,OAAO;CACR;CAEA,OAAO,EACN,UAAU,KAAK,SAAS,OAAO,IAAI,EACpC;AACD"}
@@ -12,8 +12,13 @@ import ttf2woff from "ttf2woff";
12
12
  import ttf2eot from "ttf2eot";
13
13
  import * as svgo from "svgo";
14
14
  import which from "which";
15
-
16
15
  //#region tasks/engines/node.ts
16
+ /**
17
+ * grunt-webfont: Node.js engine
18
+ *
19
+ * @requires ttfautohint 1.00+ (optional)
20
+ * @author Artem Sapegin (http://sapegin.me), Hibi_10000
21
+ */
17
22
  var node_default = async (o) => {
18
23
  const logger = o.logger || consolaLogger;
19
24
  const fonts = {};
@@ -92,23 +97,21 @@ var node_default = async (o) => {
92
97
  function svgFilesToStreams(files) {
93
98
  try {
94
99
  return files.map((file) => {
95
- function fileStreamed(name$1, stream$1) {
100
+ function fileStreamed(name, stream) {
96
101
  return {
97
- codepoint: o.codepoints[name$1],
98
- name: name$1,
99
- stream: stream$1
102
+ codepoint: o.codepoints[name],
103
+ name,
104
+ stream
100
105
  };
101
106
  }
102
- function streamSVG(name$1, file$1) {
103
- const stream$1 = fs.createReadStream(file$1);
104
- return fileStreamed(name$1, stream$1);
107
+ function streamSVG(name, file) {
108
+ return fileStreamed(name, fs.createReadStream(file));
105
109
  }
106
- function streamSVGO(name$1, file$1) {
107
- const svg = fs.readFileSync(file$1, "utf8");
110
+ function streamSVGO(name, file) {
111
+ const svg = fs.readFileSync(file, "utf8");
108
112
  try {
109
113
  const optimized = svgo.optimize(svg).data;
110
- const strStream = stream.Readable.from(optimized);
111
- return fileStreamed(name$1, strStream);
114
+ return fileStreamed(name, stream.Readable.from(optimized));
112
115
  } catch (err) {
113
116
  logger.log.error("Can’t simplify SVG file with SVGO.\n\n" + err);
114
117
  throw err;
@@ -158,7 +161,7 @@ var node_default = async (o) => {
158
161
  return fs.readFileSync(hintedFilepath);
159
162
  }
160
163
  };
161
-
162
164
  //#endregion
163
165
  export { node_default as default };
166
+
164
167
  //# sourceMappingURL=node.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"node.js","names":["wf.consolaLogger","fonts: { svg?: string, ttf?: Uint8Array, woff?: Uint8Array, eot?: Uint8Array }","wf.getFontPath","name","stream","file"],"sources":["../../tasks/engines/node.ts"],"sourcesContent":["/**\n * grunt-webfont: Node.js engine\n *\n * @requires ttfautohint 1.00+ (optional)\n * @author Artem Sapegin (http://sapegin.me), Hibi_10000\n */\n\nimport fs from 'node:fs';\nimport stream from 'node:stream';\nimport path from 'node:path';\nimport util from 'node:util';\nimport { exec } from 'node:child_process';\nimport { StringDecoder } from 'node:string_decoder';\nimport temp from 'temp';\nimport { SVGIcons2SVGFontStream } from 'svgicons2svgfont';\nimport svg2ttf from 'svg2ttf';\nimport ttf2woff from 'ttf2woff';\nimport ttf2eot from 'ttf2eot';\nimport * as svgo from 'svgo';\nimport which from 'which';\n\nimport * as wf from '../util/util.ts';\nimport type { OptionsInternal, ReadableStreamWithMetadata } from '../types.ts';\n\nexport default async (o: OptionsInternal): Promise<false> => {\n\tconst logger = o.logger || wf.consolaLogger;\n\n\t// @todo Ligatures\n\n\tconst fonts: { svg?: string, ttf?: Uint8Array, woff?: Uint8Array, eot?: Uint8Array } = {};\n\n\tconst generators = {\n\t\tsvg: async () => {\n\t\t\tlet font = '';\n\t\t\tconst decoder = new StringDecoder('utf8');\n\t\t\tconst streams = svgFilesToStreams(o.files);\n\t\t\tconst fontStream = new SVGIcons2SVGFontStream({\n\t\t\t\tfontName: o.fontFamilyName,\n\t\t\t\tfontHeight: o.fontHeight,\n\t\t\t\tdescent: o.descent,\n\t\t\t\tnormalize: o.normalize,\n\t\t\t\tround: o.round,\n\t\t\t});\n\t\t\tfontStream.on('data', (chunk) => {\n\t\t\t\tfont += decoder.write(chunk);\n\t\t\t});\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tfontStream.on('end', () => {\n\t\t\t\t\tfonts.svg = font;\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t\tfor (const s of streams) {\n\t\t\t\t\tconst svgStream = s.stream as ReadableStreamWithMetadata;\n\t\t\t\t\tsvgStream.metadata = {\n\t\t\t\t\t\tunicode: [String.fromCodePoint(s.codepoint)],\n\t\t\t\t\t\tname: s.name,\n\t\t\t\t\t}\n\t\t\t\t\tfontStream.write(svgStream);\n\t\t\t\t}\n\t\t\t\tfontStream.end();\n\t\t\t});\n\t\t\treturn font;\n\t\t},\n\n\t\tttf: async () => {\n\t\t\tconst svgFont = await getFont('svg')\n\t\t\tlet font = svg2ttf(svgFont, {}).buffer;\n\t\t\tconst hintedFont = await autohintTtfFont(font)\n\t\t\t// ttfautohint is optional\n\t\t\tif (hintedFont) {\n\t\t\t\tfont = hintedFont;\n\t\t\t}\n\t\t\tfonts.ttf = font;\n\t\t\treturn font;\n\t\t},\n\n\t\twoff: async () => {\n\t\t\tconst ttfFont = await getFont('ttf')\n\t\t\tconst font = ttf2woff(ttfFont, {});\n\t\t\tfonts.woff = font;\n\t\t\treturn font;\n\t\t},\n\n\t\twoff2: async () => {\n\t\t\t// Will be converted from TTF later\n\t\t},\n\n\t\teot: async () => {\n\t\t\tconst ttfFont = await getFont('ttf')\n\t\t\tconst font = ttf2eot(ttfFont);\n\t\t\tfonts.eot = font;\n\t\t\treturn font;\n\t\t}\n\t};\n\n\t// Font types\n\tconst typesToGenerate = o.types.slice();\n\tif ((o.types.indexOf('woff2') !== -1) && (o.types.indexOf('ttf') === -1)) typesToGenerate.push('ttf');\n\ttry {\n\t\tfor (const type of typesToGenerate) {\n\t\t\tif (type === 'woff2') continue;\n\t\t\t//@ts-ignore\n\t\t\tawait createFontWriter(type);\n\t\t}\n\t} catch (e) {\n\t\treturn false;\n\t}\n\n\tasync function getFont(type: 'svg'): Promise<string>;\n\tasync function getFont(type: 'eot' | 'woff' | 'ttf'): Promise<Uint8Array>;\n\tasync function getFont(type: 'eot' | 'woff' | 'ttf' | 'svg'): Promise<string | Uint8Array>;\n\tasync function getFont(type: 'eot' | 'woff' | 'ttf' | 'svg') {\n\t\tif (fonts[type]) {\n\t\t\treturn fonts[type];\n\t\t} else {\n\t\t\treturn await generators[type]();\n\t\t}\n\t}\n\n\tasync function createFontWriter(type: 'eot' | 'woff' | 'ttf' | 'svg') {\n\t\tconst font = await getFont(type)\n\t\tfs.writeFileSync(wf.getFontPath(o, type), font);\n\t}\n\n\ttype Stream = { codepoint: number, name?: string, stream: NodeJS.ReadableStream };\n\tfunction svgFilesToStreams(files: string[]) {\n\t\ttry {\n\t\t\treturn files.map((file) => {\n\n\t\t\t\tfunction fileStreamed(name: string, stream: NodeJS.ReadableStream): Stream {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcodepoint: o.codepoints[name],\n\t\t\t\t\t\tname: name,\n\t\t\t\t\t\tstream: stream,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tfunction streamSVG(name: string, file: string) {\n\t\t\t\t\tconst stream = fs.createReadStream(file);\n\t\t\t\t\treturn fileStreamed(name, stream);\n\t\t\t\t}\n\n\t\t\t\tfunction streamSVGO(name: string, file: string) {\n\t\t\t\t\tconst svg = fs.readFileSync(file, 'utf8');\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst optimized = svgo.optimize(svg).data;\n\t\t\t\t\t\tconst strStream = stream.Readable.from(optimized);\n\t\t\t\t\t\treturn fileStreamed(name, strStream);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tlogger.log.error('Can’t simplify SVG file with SVGO.\\n\\n' + err);\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst idx = files.indexOf(file);\n\t\t\t\tconst name = o.glyphs[idx];\n\n\t\t\t\tif (o.optimize === true) {\n\t\t\t\t\treturn streamSVGO(name, file)\n\t\t\t\t} else {\n\t\t\t\t\treturn streamSVG(name, file);\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tlogger.log.error('Can’t stream SVG file.\\n\\n' + err);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tasync function autohintTtfFont(font: Uint8Array) {\n\t\tif (!which.sync('ttfautohint', { nothrow: true })) {\n\t\t\tlogger.log.verbose('Hinting skipped, ttfautohint not found.');\n\t\t\treturn false;\n\t\t}\n\n\t\ttemp.track();\n\t\tconst tempDir = temp.mkdirSync();\n\t\tconst originalFilepath = path.join(tempDir, 'font.ttf');\n\t\tconst hintedFilepath = path.join(tempDir, 'hinted.ttf');\n\n\t\tif (!o.autoHint){\n\t\t\treturn false;\n\t\t}\n\t\t// Save original font to temporary directory\n\t\tfs.writeFileSync(originalFilepath, font);\n\n\t\t// Run ttfautohint\n\t\tconst args = [\n\t\t\t'ttfautohint',\n\t\t\t'--symbol',\n\t\t\t'--fallback-script=latn',\n\t\t\t'--windows-compatibility',\n\t\t\t'--no-info',\n\t\t\toriginalFilepath,\n\t\t\thintedFilepath\n\t\t].join(' ');\n\n\t\tconst execPromise = util.promisify(exec);\n\t\ttry {\n\t\t\tawait execPromise(args, { maxBuffer: o.execMaxBuffer });\n\t\t} catch (err) {\n\t\t\tif (err.code === 127) {\n\t\t\t\tlogger.log.verbose('Hinting skipped, ttfautohint not found.');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tlogger.log.error('Can’t run ttfautohint.\\n\\n' + err.message);\n\t\t\treturn false;\n\t\t}\n\t\tconst hintedFont = fs.readFileSync(hintedFilepath);\n\t\treturn hintedFont;\n\t}\n\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"node.js","names":["wf.consolaLogger","wf.getFontPath"],"sources":["../../tasks/engines/node.ts"],"sourcesContent":["/**\n * grunt-webfont: Node.js engine\n *\n * @requires ttfautohint 1.00+ (optional)\n * @author Artem Sapegin (http://sapegin.me), Hibi_10000\n */\n\nimport fs from 'node:fs';\nimport stream from 'node:stream';\nimport path from 'node:path';\nimport util from 'node:util';\nimport { exec, type ExecException } from 'node:child_process';\nimport { StringDecoder } from 'node:string_decoder';\nimport temp from 'temp';\nimport { SVGIcons2SVGFontStream } from 'svgicons2svgfont';\nimport svg2ttf from 'svg2ttf';\nimport ttf2woff from 'ttf2woff';\nimport ttf2eot from 'ttf2eot';\nimport * as svgo from 'svgo';\nimport which from 'which';\n\nimport * as wf from '../util/util.ts';\nimport type { OptionsInternal, ReadableStreamWithMetadata } from '../types.ts';\n\nexport default async (o: OptionsInternal): Promise<false> => {\n\tconst logger = o.logger || wf.consolaLogger;\n\n\t// @todo Ligatures\n\n\tconst fonts: { svg?: string, ttf?: Uint8Array, woff?: Uint8Array, eot?: Uint8Array } = {};\n\n\tconst generators = {\n\t\tsvg: async () => {\n\t\t\tlet font = '';\n\t\t\tconst decoder = new StringDecoder('utf8');\n\t\t\tconst streams = svgFilesToStreams(o.files);\n\t\t\tconst fontStream = new SVGIcons2SVGFontStream({\n\t\t\t\tfontName: o.fontFamilyName,\n\t\t\t\tfontHeight: o.fontHeight,\n\t\t\t\tdescent: o.descent,\n\t\t\t\tnormalize: o.normalize,\n\t\t\t\tround: o.round,\n\t\t\t});\n\t\t\tfontStream.on('data', (chunk) => {\n\t\t\t\tfont += decoder.write(chunk);\n\t\t\t});\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tfontStream.on('end', () => {\n\t\t\t\t\tfonts.svg = font;\n\t\t\t\t\tresolve();\n\t\t\t\t});\n\t\t\t\tfor (const s of streams) {\n\t\t\t\t\tconst svgStream = s.stream as ReadableStreamWithMetadata;\n\t\t\t\t\tsvgStream.metadata = {\n\t\t\t\t\t\tunicode: [String.fromCodePoint(s.codepoint)],\n\t\t\t\t\t\tname: s.name,\n\t\t\t\t\t}\n\t\t\t\t\tfontStream.write(svgStream);\n\t\t\t\t}\n\t\t\t\tfontStream.end();\n\t\t\t});\n\t\t\treturn font;\n\t\t},\n\n\t\tttf: async () => {\n\t\t\tconst svgFont = await getFont('svg')\n\t\t\tlet font = svg2ttf(svgFont, {}).buffer;\n\t\t\tconst hintedFont = await autohintTtfFont(font)\n\t\t\t// ttfautohint is optional\n\t\t\tif (hintedFont) {\n\t\t\t\tfont = hintedFont;\n\t\t\t}\n\t\t\tfonts.ttf = font;\n\t\t\treturn font;\n\t\t},\n\n\t\twoff: async () => {\n\t\t\tconst ttfFont = await getFont('ttf')\n\t\t\tconst font = ttf2woff(ttfFont, {});\n\t\t\tfonts.woff = font;\n\t\t\treturn font;\n\t\t},\n\n\t\twoff2: async () => {\n\t\t\t// Will be converted from TTF later\n\t\t},\n\n\t\teot: async () => {\n\t\t\tconst ttfFont = await getFont('ttf')\n\t\t\tconst font = ttf2eot(ttfFont);\n\t\t\tfonts.eot = font;\n\t\t\treturn font;\n\t\t}\n\t};\n\n\t// Font types\n\tconst typesToGenerate = o.types.slice();\n\tif ((o.types.indexOf('woff2') !== -1) && (o.types.indexOf('ttf') === -1)) typesToGenerate.push('ttf');\n\ttry {\n\t\tfor (const type of typesToGenerate) {\n\t\t\tif (type === 'woff2') continue;\n\t\t\tawait createFontWriter(type);\n\t\t}\n\t} catch (e) {\n\t\treturn false;\n\t}\n\n\tasync function getFont(type: 'svg'): Promise<string>;\n\tasync function getFont(type: 'eot' | 'woff' | 'ttf'): Promise<Uint8Array>;\n\tasync function getFont(type: 'eot' | 'woff' | 'ttf' | 'svg'): Promise<string | Uint8Array>;\n\tasync function getFont(type: 'eot' | 'woff' | 'ttf' | 'svg') {\n\t\tif (fonts[type]) {\n\t\t\treturn fonts[type];\n\t\t} else {\n\t\t\treturn await generators[type]();\n\t\t}\n\t}\n\n\tasync function createFontWriter(type: 'eot' | 'woff' | 'ttf' | 'svg') {\n\t\tconst font = await getFont(type)\n\t\tfs.writeFileSync(wf.getFontPath(o, type), font);\n\t}\n\n\ttype Stream = { codepoint: number, name?: string, stream: NodeJS.ReadableStream };\n\tfunction svgFilesToStreams(files: string[]) {\n\t\ttry {\n\t\t\treturn files.map((file) => {\n\n\t\t\t\tfunction fileStreamed(name: string, stream: NodeJS.ReadableStream): Stream {\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcodepoint: o.codepoints[name],\n\t\t\t\t\t\tname: name,\n\t\t\t\t\t\tstream: stream,\n\t\t\t\t\t};\n\t\t\t\t}\n\n\t\t\t\tfunction streamSVG(name: string, file: string) {\n\t\t\t\t\tconst stream = fs.createReadStream(file);\n\t\t\t\t\treturn fileStreamed(name, stream);\n\t\t\t\t}\n\n\t\t\t\tfunction streamSVGO(name: string, file: string) {\n\t\t\t\t\tconst svg = fs.readFileSync(file, 'utf8');\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst optimized = svgo.optimize(svg).data;\n\t\t\t\t\t\tconst strStream = stream.Readable.from(optimized);\n\t\t\t\t\t\treturn fileStreamed(name, strStream);\n\t\t\t\t\t} catch (err) {\n\t\t\t\t\t\tlogger.log.error('Can’t simplify SVG file with SVGO.\\n\\n' + err);\n\t\t\t\t\t\tthrow err;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst idx = files.indexOf(file);\n\t\t\t\tconst name = o.glyphs[idx];\n\n\t\t\t\tif (o.optimize === true) {\n\t\t\t\t\treturn streamSVGO(name, file)\n\t\t\t\t} else {\n\t\t\t\t\treturn streamSVG(name, file);\n\t\t\t\t}\n\t\t\t});\n\t\t} catch (err) {\n\t\t\tlogger.log.error('Can’t stream SVG file.\\n\\n' + err);\n\t\t\tthrow err;\n\t\t}\n\t}\n\n\tasync function autohintTtfFont(font: Uint8Array) {\n\t\tif (!which.sync('ttfautohint', { nothrow: true })) {\n\t\t\tlogger.log.verbose('Hinting skipped, ttfautohint not found.');\n\t\t\treturn false;\n\t\t}\n\n\t\ttemp.track();\n\t\tconst tempDir = temp.mkdirSync();\n\t\tconst originalFilepath = path.join(tempDir, 'font.ttf');\n\t\tconst hintedFilepath = path.join(tempDir, 'hinted.ttf');\n\n\t\tif (!o.autoHint){\n\t\t\treturn false;\n\t\t}\n\t\t// Save original font to temporary directory\n\t\tfs.writeFileSync(originalFilepath, font);\n\n\t\t// Run ttfautohint\n\t\tconst args = [\n\t\t\t'ttfautohint',\n\t\t\t'--symbol',\n\t\t\t'--fallback-script=latn',\n\t\t\t'--windows-compatibility',\n\t\t\t'--no-info',\n\t\t\toriginalFilepath,\n\t\t\thintedFilepath\n\t\t].join(' ');\n\n\t\tconst execPromise = util.promisify(exec);\n\t\ttry {\n\t\t\tawait execPromise(args, { maxBuffer: o.execMaxBuffer });\n\t\t} catch (err) {\n\t\t\tif ((err as ExecException).code === 127) {\n\t\t\t\tlogger.log.verbose('Hinting skipped, ttfautohint not found.');\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tlogger.log.error('Can’t run ttfautohint.\\n\\n' + (err as Error).message);\n\t\t\treturn false;\n\t\t}\n\t\tconst hintedFont = fs.readFileSync(hintedFilepath);\n\t\treturn hintedFont;\n\t}\n\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;AAwBA,IAAA,eAAe,OAAO,MAAuC;CAC5D,MAAM,SAAS,EAAE,UAAUA;CAI3B,MAAM,QAAiF,CAAC;CAExF,MAAM,aAAa;EAClB,KAAK,YAAY;GAChB,IAAI,OAAO;GACX,MAAM,UAAU,IAAI,cAAc,MAAM;GACxC,MAAM,UAAU,kBAAkB,EAAE,KAAK;GACzC,MAAM,aAAa,IAAI,uBAAuB;IAC7C,UAAU,EAAE;IACZ,YAAY,EAAE;IACd,SAAS,EAAE;IACX,WAAW,EAAE;IACb,OAAO,EAAE;GACV,CAAC;GACD,WAAW,GAAG,SAAS,UAAU;IAChC,QAAQ,QAAQ,MAAM,KAAK;GAC5B,CAAC;GACD,MAAM,IAAI,SAAe,YAAY;IACpC,WAAW,GAAG,aAAa;KAC1B,MAAM,MAAM;KACZ,QAAQ;IACT,CAAC;IACD,KAAK,MAAM,KAAK,SAAS;KACxB,MAAM,YAAY,EAAE;KACpB,UAAU,WAAW;MACpB,SAAS,CAAC,OAAO,cAAc,EAAE,SAAS,CAAC;MAC3C,MAAM,EAAE;KACT;KACA,WAAW,MAAM,SAAS;IAC3B;IACA,WAAW,IAAI;GAChB,CAAC;GACD,OAAO;EACR;EAEA,KAAK,YAAY;GAChB,MAAM,UAAU,MAAM,QAAQ,KAAK;GACnC,IAAI,OAAO,QAAQ,SAAS,CAAC,CAAC,CAAC,CAAC;GAChC,MAAM,aAAa,MAAM,gBAAgB,IAAI;GAE7C,IAAI,YACH,OAAO;GAER,MAAM,MAAM;GACZ,OAAO;EACR;EAEA,MAAM,YAAY;GACjB,MAAM,UAAU,MAAM,QAAQ,KAAK;GACnC,MAAM,OAAO,SAAS,SAAS,CAAC,CAAC;GACjC,MAAM,OAAO;GACb,OAAO;EACR;EAEA,OAAO,YAAY,CAEnB;EAEA,KAAK,YAAY;GAChB,MAAM,UAAU,MAAM,QAAQ,KAAK;GACnC,MAAM,OAAO,QAAQ,OAAO;GAC5B,MAAM,MAAM;GACZ,OAAO;EACR;CACD;CAGA,MAAM,kBAAkB,EAAE,MAAM,MAAM;CACtC,IAAK,EAAE,MAAM,QAAQ,OAAO,MAAM,MAAQ,EAAE,MAAM,QAAQ,KAAK,MAAM,IAAK,gBAAgB,KAAK,KAAK;CACpG,IAAI;EACH,KAAK,MAAM,QAAQ,iBAAiB;GACnC,IAAI,SAAS,SAAS;GACtB,MAAM,iBAAiB,IAAI;EAC5B;CACD,SAAS,GAAG;EACX,OAAO;CACR;CAKA,eAAe,QAAQ,MAAsC;EAC5D,IAAI,MAAM,OACT,OAAO,MAAM;OAEb,OAAO,MAAM,WAAW,KAAK,CAAC;CAEhC;CAEA,eAAe,iBAAiB,MAAsC;EACrE,MAAM,OAAO,MAAM,QAAQ,IAAI;EAC/B,GAAG,cAAcC,YAAe,GAAG,IAAI,GAAG,IAAI;CAC/C;CAGA,SAAS,kBAAkB,OAAiB;EAC3C,IAAI;GACH,OAAO,MAAM,KAAK,SAAS;IAE1B,SAAS,aAAa,MAAc,QAAuC;KAC1E,OAAO;MACN,WAAW,EAAE,WAAW;MAClB;MACE;KACT;IACD;IAEA,SAAS,UAAU,MAAc,MAAc;KAE9C,OAAO,aAAa,MADL,GAAG,iBAAiB,IACJ,CAAC;IACjC;IAEA,SAAS,WAAW,MAAc,MAAc;KAC/C,MAAM,MAAM,GAAG,aAAa,MAAM,MAAM;KACxC,IAAI;MACH,MAAM,YAAY,KAAK,SAAS,GAAG,CAAC,CAAC;MAErC,OAAO,aAAa,MADF,OAAO,SAAS,KAAK,SACL,CAAC;KACpC,SAAS,KAAK;MACb,OAAO,IAAI,MAAM,2CAA2C,GAAG;MAC/D,MAAM;KACP;IACD;IAEA,MAAM,MAAM,MAAM,QAAQ,IAAI;IAC9B,MAAM,OAAO,EAAE,OAAO;IAEtB,IAAI,EAAE,aAAa,MAClB,OAAO,WAAW,MAAM,IAAI;SAE5B,OAAO,UAAU,MAAM,IAAI;GAE7B,CAAC;EACF,SAAS,KAAK;GACb,OAAO,IAAI,MAAM,+BAA+B,GAAG;GACnD,MAAM;EACP;CACD;CAEA,eAAe,gBAAgB,MAAkB;EAChD,IAAI,CAAC,MAAM,KAAK,eAAe,EAAE,SAAS,KAAK,CAAC,GAAG;GAClD,OAAO,IAAI,QAAQ,yCAAyC;GAC5D,OAAO;EACR;EAEA,KAAK,MAAM;EACX,MAAM,UAAU,KAAK,UAAU;EAC/B,MAAM,mBAAmB,KAAK,KAAK,SAAS,UAAU;EACtD,MAAM,iBAAiB,KAAK,KAAK,SAAS,YAAY;EAEtD,IAAI,CAAC,EAAE,UACN,OAAO;EAGR,GAAG,cAAc,kBAAkB,IAAI;EAGvC,MAAM,OAAO;GACZ;GACA;GACA;GACA;GACA;GACA;GACA;EACD,CAAC,CAAC,KAAK,GAAG;EAEV,MAAM,cAAc,KAAK,UAAU,IAAI;EACvC,IAAI;GACH,MAAM,YAAY,MAAM,EAAE,WAAW,EAAE,cAAc,CAAC;EACvD,SAAS,KAAK;GACb,IAAK,IAAsB,SAAS,KAAK;IACxC,OAAO,IAAI,QAAQ,yCAAyC;IAC5D,OAAO;GACR;GACA,OAAO,IAAI,MAAM,+BAAgC,IAAc,OAAO;GACtE,OAAO;EACR;EAEA,OADmB,GAAG,aAAa,cACnB;CACjB;AAED"}