@hibi_10000/grunt-webfont 2.0.1
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/License.md +24 -0
- package/Readme.md +695 -0
- package/bin/eotlitetool.py +474 -0
- package/bin/fontforge/generate.py +133 -0
- package/dist/engines/fontforge.js +84 -0
- package/dist/engines/fontforge.js.map +1 -0
- package/dist/engines/node.js +164 -0
- package/dist/engines/node.js.map +1 -0
- package/dist/package.js +105 -0
- package/dist/package.js.map +1 -0
- package/dist/types.d.ts +158 -0
- package/dist/util/util.js +105 -0
- package/dist/util/util.js.map +1 -0
- package/dist/webfont.d.ts +8 -0
- package/dist/webfont.js +609 -0
- package/dist/webfont.js.map +1 -0
- package/package.json +86 -0
- package/tasks/engines/fontforge.ts +124 -0
- package/tasks/engines/node.ts +213 -0
- package/tasks/engines/nodedeps.d.ts +22 -0
- package/tasks/types.ts +169 -0
- package/tasks/util/util.ts +119 -0
- package/tasks/webfont.ts +833 -0
- package/templates/bem.css +56 -0
- package/templates/bem.json +4 -0
- package/templates/bootstrap.css +114 -0
- package/templates/bootstrap.json +4 -0
- package/templates/demo.html +97 -0
- package/tsconfig.json +31 -0
package/dist/webfont.js
ADDED
|
@@ -0,0 +1,609 @@
|
|
|
1
|
+
import { UNICODE_PUA_START, consolaLogger, cssFilePrefixes, fontFormats, fontSrcSeparators, fontsSrcsMap, generatedFontFiles, getFontPath } from "./util/util.js";
|
|
2
|
+
import fontforge_default from "./engines/fontforge.js";
|
|
3
|
+
import node_default from "./engines/node.js";
|
|
4
|
+
import package_default from "./package.js";
|
|
5
|
+
import fs from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
import crypto from "node:crypto";
|
|
8
|
+
import { globSync } from "glob";
|
|
9
|
+
import chalk from "chalk";
|
|
10
|
+
import _ from "lodash";
|
|
11
|
+
import ttf2woff2 from "ttf2woff2";
|
|
12
|
+
|
|
13
|
+
//#region tasks/webfont.ts
|
|
14
|
+
var webfont_default = (grunt) => {
|
|
15
|
+
grunt.registerMultiTask("webfont", "Compile separate SVG files to webfont", function() {
|
|
16
|
+
/**
|
|
17
|
+
* Consola to Grunt logger adapter.
|
|
18
|
+
*/
|
|
19
|
+
const logger = {
|
|
20
|
+
log: {
|
|
21
|
+
warn: (...args) => {
|
|
22
|
+
grunt.log.warn.apply(null, args);
|
|
23
|
+
},
|
|
24
|
+
error: (...args) => {
|
|
25
|
+
grunt.warn.apply(null, args);
|
|
26
|
+
},
|
|
27
|
+
info: (...args) => {
|
|
28
|
+
grunt.log.writeln.apply(null, args);
|
|
29
|
+
},
|
|
30
|
+
verbose: (...args) => {
|
|
31
|
+
grunt.log.verbose.writeln.apply(null, args);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
fail: { fatal: (...args) => {
|
|
35
|
+
grunt.fail.fatal.apply(null, args);
|
|
36
|
+
} }
|
|
37
|
+
};
|
|
38
|
+
const allDone = this.async();
|
|
39
|
+
const params = this.data;
|
|
40
|
+
const options = this.options(void 0);
|
|
41
|
+
this.requiresConfig([
|
|
42
|
+
this.name,
|
|
43
|
+
this.target,
|
|
44
|
+
"src"
|
|
45
|
+
].join("."));
|
|
46
|
+
webfont(this.name, this.target, this.filesSrc, params, options, logger).finally(allDone);
|
|
47
|
+
});
|
|
48
|
+
};
|
|
49
|
+
const webfont = async (name, target, filesSrc, params, options, logger) => {
|
|
50
|
+
if (!logger) logger = consolaLogger;
|
|
51
|
+
const md5 = crypto.createHash("md5");
|
|
52
|
+
if (params.dest === void 0 && options.dest === void 0) logger.log.warn(`Required property ${name}.${target}.dest or ${name}.${target}.options.dest missing.`);
|
|
53
|
+
if (options.skip) {
|
|
54
|
+
completeTask();
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const files = filesSrc.filter(isSvgFile);
|
|
58
|
+
if (!files.length) {
|
|
59
|
+
logger.log.warn("Specified empty list of source SVG files.");
|
|
60
|
+
completeTask();
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
if (typeof options.template !== "string") options.template = "";
|
|
64
|
+
let o = {
|
|
65
|
+
logger,
|
|
66
|
+
fontBaseName: options.font || "icons",
|
|
67
|
+
destCss: options.destCss || params.destCss || params.dest,
|
|
68
|
+
destScss: options.destScss || params.destScss || params.destCss || params.dest,
|
|
69
|
+
destSass: options.destSass || params.destSass || params.destCss || params.dest,
|
|
70
|
+
destLess: options.destLess || params.destLess || params.destCss || params.dest,
|
|
71
|
+
destStyl: options.destStyl || params.destStyl || params.destCss || params.dest,
|
|
72
|
+
dest: options.dest || params.dest,
|
|
73
|
+
relativeFontPath: options.relativeFontPath,
|
|
74
|
+
fontPathVariables: options.fontPathVariables || false,
|
|
75
|
+
addHashes: options.hashes !== false,
|
|
76
|
+
addLigatures: options.ligatures === true,
|
|
77
|
+
template: options.template,
|
|
78
|
+
syntax: options.syntax || "bem",
|
|
79
|
+
templateOptions: options.templateOptions || {},
|
|
80
|
+
stylesheets: options.stylesheets || [options.stylesheet || path.extname(options.template).replace(/^\./, "") || "css"],
|
|
81
|
+
htmlDemo: options.htmlDemo !== false,
|
|
82
|
+
htmlDemoTemplate: options.htmlDemoTemplate,
|
|
83
|
+
htmlDemoFilename: options.htmlDemoFilename,
|
|
84
|
+
styles: optionToArray(options.styles, "font,icon"),
|
|
85
|
+
types: optionToArray(options.types, "eot,woff,ttf"),
|
|
86
|
+
order: optionToArray(options.order, fontFormats),
|
|
87
|
+
embed: options.embed === true ? ["woff"] : optionToArray(options.embed, false),
|
|
88
|
+
rename: options.rename || path.basename,
|
|
89
|
+
engine: options.engine || "fontforge",
|
|
90
|
+
autoHint: options.autoHint !== false,
|
|
91
|
+
codepoints: options.codepoints,
|
|
92
|
+
codepointsFile: options.codepointsFile,
|
|
93
|
+
startCodepoint: options.startCodepoint || UNICODE_PUA_START,
|
|
94
|
+
ie7: options.ie7 === true,
|
|
95
|
+
normalize: options.normalize === true,
|
|
96
|
+
optimize: options.optimize === false ? false : true,
|
|
97
|
+
round: options.round !== void 0 ? options.round : 0x9184e72a000,
|
|
98
|
+
fontHeight: options.fontHeight !== void 0 ? options.fontHeight : 512,
|
|
99
|
+
descent: options.descent !== void 0 ? options.descent : 64,
|
|
100
|
+
version: options.version !== void 0 ? options.version : false,
|
|
101
|
+
cache: options.cache || path.join(import.meta.dirname, "..", ".cache"),
|
|
102
|
+
callback: options.callback,
|
|
103
|
+
customOutputs: options.customOutputs,
|
|
104
|
+
execMaxBuffer: options.execMaxBuffer || 1024 * 200
|
|
105
|
+
};
|
|
106
|
+
o = Object.assign(o, {
|
|
107
|
+
fontName: o.fontBaseName,
|
|
108
|
+
destCssPaths: {
|
|
109
|
+
css: o.destCss,
|
|
110
|
+
scss: o.destScss,
|
|
111
|
+
sass: o.destSass,
|
|
112
|
+
less: o.destLess,
|
|
113
|
+
styl: o.destStyl
|
|
114
|
+
},
|
|
115
|
+
relativeFontPath: o.relativeFontPath || path.relative(o.destCss, o.dest),
|
|
116
|
+
destHtml: options.destHtml || o.destCss,
|
|
117
|
+
fontfaceStyles: has(o.styles, "font"),
|
|
118
|
+
baseStyles: has(o.styles, "icon"),
|
|
119
|
+
extraStyles: has(o.styles, "extra"),
|
|
120
|
+
files,
|
|
121
|
+
glyphs: []
|
|
122
|
+
});
|
|
123
|
+
o.hash = getHash();
|
|
124
|
+
o.fontFilename = template(options.fontFilename || o.fontBaseName, o);
|
|
125
|
+
o.fontFamilyName = template(options.fontFamilyName || o.fontBaseName, o);
|
|
126
|
+
o.glyphs = o.files.map((file) => {
|
|
127
|
+
return o.rename(file).replace(path.extname(file), "");
|
|
128
|
+
});
|
|
129
|
+
let currentCodepoint = o.startCodepoint;
|
|
130
|
+
if (!o.codepoints) o.codepoints = {};
|
|
131
|
+
if (o.codepointsFile) o.codepoints = readCodepointsFromFile();
|
|
132
|
+
o.glyphs.forEach((name$1) => {
|
|
133
|
+
if (!o.codepoints[name$1]) o.codepoints[name$1] = getNextCodepoint();
|
|
134
|
+
});
|
|
135
|
+
if (o.codepointsFile) saveCodepointsToFile();
|
|
136
|
+
const previousHash = readHash(name, target);
|
|
137
|
+
logger.log.verbose("New hash:", o.hash, "- previous hash:", previousHash);
|
|
138
|
+
if (o.hash === previousHash) {
|
|
139
|
+
logger.log.verbose("Config and source files weren’t changed since last run, checking resulting files...");
|
|
140
|
+
let regenerationNeeded = false;
|
|
141
|
+
const generatedFiles = generatedFontFiles(o);
|
|
142
|
+
if (!generatedFiles.length) regenerationNeeded = true;
|
|
143
|
+
else {
|
|
144
|
+
generatedFiles.push(getDemoFilePath());
|
|
145
|
+
o.stylesheets.forEach((stylesheet) => {
|
|
146
|
+
generatedFiles.push(getCssFilePath(stylesheet));
|
|
147
|
+
});
|
|
148
|
+
regenerationNeeded = generatedFiles.some((filename) => {
|
|
149
|
+
if (!filename) return false;
|
|
150
|
+
if (!fs.existsSync(filename)) {
|
|
151
|
+
logger.log.verbose("File", filename, " is missed.");
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
return false;
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
if (!regenerationNeeded) {
|
|
158
|
+
logger.log.info(`Font ${chalk.cyan(o.fontName)} wasn’t changed since last run.`);
|
|
159
|
+
completeTask();
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
saveHash(name, target, o.hash);
|
|
164
|
+
try {
|
|
165
|
+
createOutputDirs();
|
|
166
|
+
cleanOutputDir();
|
|
167
|
+
await generateFont();
|
|
168
|
+
generateWoff2Font();
|
|
169
|
+
generateStylesheets();
|
|
170
|
+
await generateDemoHtml();
|
|
171
|
+
generateCustomOutputs();
|
|
172
|
+
printDone();
|
|
173
|
+
} finally {
|
|
174
|
+
completeTask();
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Call callback function if it was specified in the options.
|
|
178
|
+
*/
|
|
179
|
+
function completeTask() {
|
|
180
|
+
if (o && typeof o.callback === "function") o.callback(o.fontName, o.types, o.glyphs, o.hash);
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Calculate hash to flush browser cache.
|
|
184
|
+
* Hash is based on source SVG files contents, task options and grunt-webfont version.
|
|
185
|
+
*/
|
|
186
|
+
function getHash() {
|
|
187
|
+
o.files.forEach((file) => {
|
|
188
|
+
md5.update(fs.readFileSync(file, "utf8"));
|
|
189
|
+
});
|
|
190
|
+
md5.update(JSON.stringify(o));
|
|
191
|
+
md5.update(package_default.version);
|
|
192
|
+
if (o.template) md5.update(fs.readFileSync(o.template, "utf8"));
|
|
193
|
+
if (o.htmlDemoTemplate) md5.update(fs.readFileSync(o.htmlDemoTemplate, "utf8"));
|
|
194
|
+
return md5.digest("hex");
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Create output directory
|
|
198
|
+
*/
|
|
199
|
+
function createOutputDirs() {
|
|
200
|
+
o.stylesheets.forEach((stylesheet) => {
|
|
201
|
+
fs.mkdirSync(option(o.destCssPaths, stylesheet), { recursive: true });
|
|
202
|
+
});
|
|
203
|
+
fs.mkdirSync(o.dest, { recursive: true });
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Clean output directory
|
|
207
|
+
*/
|
|
208
|
+
function cleanOutputDir() {
|
|
209
|
+
const htmlDemoFileMask = path.posix.join(o.destCss, `${o.fontBaseName}*.{css,html}`);
|
|
210
|
+
globSync(htmlDemoFileMask).concat(generatedFontFiles(o)).forEach((file) => {
|
|
211
|
+
fs.unlinkSync(file);
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Generate font using selected engine
|
|
216
|
+
*/
|
|
217
|
+
async function generateFont() {
|
|
218
|
+
const result = await (o.engine === "node" ? node_default : fontforge_default)(o);
|
|
219
|
+
if (result === false) {
|
|
220
|
+
completeTask();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (result) o = Object.assign(o, result);
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Converts TTF font to WOFF2.
|
|
227
|
+
*/
|
|
228
|
+
function generateWoff2Font() {
|
|
229
|
+
if (!has(o.types, "woff2")) return;
|
|
230
|
+
const ttfFontPath = getFontPath(o, "ttf");
|
|
231
|
+
const ttfFont = fs.readFileSync(ttfFontPath);
|
|
232
|
+
if (!has(o.types, "ttf")) fs.unlinkSync(ttfFontPath);
|
|
233
|
+
const woffFont = ttf2woff2(ttfFont);
|
|
234
|
+
const woff2FontPath = getFontPath(o, "woff2");
|
|
235
|
+
fs.writeFileSync(woff2FontPath, woffFont);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Generate CSS
|
|
239
|
+
*/
|
|
240
|
+
function generateStylesheets() {
|
|
241
|
+
const codepoints = [];
|
|
242
|
+
o.glyphs.forEach((name$1) => {
|
|
243
|
+
codepoints.push(o.codepoints[name$1].toString(16));
|
|
244
|
+
});
|
|
245
|
+
o.codepoints = codepoints;
|
|
246
|
+
o.glyphs = o.glyphs.map(classnameize);
|
|
247
|
+
o.stylesheets.sort((a, b) => {
|
|
248
|
+
return a === "css" ? 1 : -1;
|
|
249
|
+
}).forEach(generateStylesheet);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* Generate CSS
|
|
253
|
+
*
|
|
254
|
+
* @param stylesheet type: css, scss, ...
|
|
255
|
+
*/
|
|
256
|
+
function generateStylesheet(stylesheet) {
|
|
257
|
+
o.relativeFontPath = normalizePath(o.relativeFontPath);
|
|
258
|
+
const fontSrcs = {
|
|
259
|
+
0: [],
|
|
260
|
+
1: []
|
|
261
|
+
};
|
|
262
|
+
o.order.forEach((type) => {
|
|
263
|
+
if (!has(o.types, type)) return;
|
|
264
|
+
const fontSrc1 = fontsSrcsMap[type][0];
|
|
265
|
+
if (fontSrc1) fontSrcs[0].push(generateFontSrc(type, fontSrc1, stylesheet));
|
|
266
|
+
fontSrcs[1].push(generateFontSrc(type, fontsSrcsMap[type][1], stylesheet));
|
|
267
|
+
});
|
|
268
|
+
const fontSrcSeparator = option(fontSrcSeparators, stylesheet);
|
|
269
|
+
o.fontSrc1 = fontSrcs[0].join(fontSrcSeparator);
|
|
270
|
+
o.fontSrc2 = fontSrcs[1].join(fontSrcSeparator);
|
|
271
|
+
o.fontRawSrcs = [fontSrcs[0], fontSrcs[1]];
|
|
272
|
+
const templateJson = readTemplate(o.template, o.syntax, ".json", true);
|
|
273
|
+
if (templateJson) o = Object.assign(o, JSON.parse(templateJson.template));
|
|
274
|
+
if (o.templateOptions) o = Object.assign(o, o.templateOptions);
|
|
275
|
+
const ext = path.extname(o.template) || ".css";
|
|
276
|
+
o.cssTemplate = readTemplate(o.template, o.syntax, ext);
|
|
277
|
+
const cssContext = Object.assign(o, {
|
|
278
|
+
iconsStyles: true,
|
|
279
|
+
stylesheet
|
|
280
|
+
});
|
|
281
|
+
let css = renderTemplate(o.cssTemplate, cssContext);
|
|
282
|
+
if (has([
|
|
283
|
+
"sass",
|
|
284
|
+
"scss",
|
|
285
|
+
"less",
|
|
286
|
+
"styl"
|
|
287
|
+
], stylesheet)) css = css.replace(/\/\* *(.*?) *\*\//g, "// $1");
|
|
288
|
+
fs.writeFileSync(getCssFilePath(stylesheet), css);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Gets the codepoints from the set filepath in o.codepointsFile
|
|
292
|
+
*/
|
|
293
|
+
function readCodepointsFromFile() {
|
|
294
|
+
if (!o.codepointsFile) return {};
|
|
295
|
+
if (!fs.existsSync(o.codepointsFile)) {
|
|
296
|
+
logger.log.verbose("Codepoints file not found");
|
|
297
|
+
return {};
|
|
298
|
+
}
|
|
299
|
+
const buffer = fs.readFileSync(o.codepointsFile);
|
|
300
|
+
return JSON.parse(buffer.toString());
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Saves the codespoints to the set file
|
|
304
|
+
*/
|
|
305
|
+
function saveCodepointsToFile() {
|
|
306
|
+
if (!o.codepointsFile) return;
|
|
307
|
+
const codepointsToString = JSON.stringify(o.codepoints, null, 4);
|
|
308
|
+
try {
|
|
309
|
+
fs.writeFileSync(o.codepointsFile, codepointsToString);
|
|
310
|
+
logger.log.verbose(`Codepoints saved to file "${o.codepointsFile}".`);
|
|
311
|
+
} catch (err) {
|
|
312
|
+
logger.log.error(err.message);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
function prepareBaseTemplateContext() {
|
|
316
|
+
return Object.assign({}, o);
|
|
317
|
+
}
|
|
318
|
+
function prepareHtmlTemplateContext() {
|
|
319
|
+
let context = prepareBaseTemplateContext();
|
|
320
|
+
let htmlStyles;
|
|
321
|
+
const relativeRe = new RegExp(_.escapeRegExp(o.relativeFontPath).replace(/[=!:\/]/g, "\\$&"), "g");
|
|
322
|
+
const htmlRelativeFontPath = normalizePath(path.relative(o.destHtml, o.dest));
|
|
323
|
+
const _fontSrc1 = o.fontSrc1.replace(relativeRe, htmlRelativeFontPath);
|
|
324
|
+
const _fontSrc2 = o.fontSrc2.replace(relativeRe, htmlRelativeFontPath);
|
|
325
|
+
context = Object.assign(context, {
|
|
326
|
+
fontSrc1: _fontSrc1,
|
|
327
|
+
fontSrc2: _fontSrc2,
|
|
328
|
+
fontfaceStyles: true,
|
|
329
|
+
baseStyles: true,
|
|
330
|
+
extraStyles: false,
|
|
331
|
+
iconsStyles: true,
|
|
332
|
+
stylesheet: "css"
|
|
333
|
+
});
|
|
334
|
+
htmlStyles = renderTemplate(o.cssTemplate, context);
|
|
335
|
+
context = Object.assign(context, { styles: htmlStyles });
|
|
336
|
+
return context;
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Iterator function used as callback by looping construct below to
|
|
340
|
+
* render "custom output" via mini configuration objects specified in
|
|
341
|
+
* the array `options.customOutputs`.
|
|
342
|
+
*
|
|
343
|
+
* @param outputConfig
|
|
344
|
+
*/
|
|
345
|
+
function generateCustomOutput(outputConfig) {
|
|
346
|
+
let context = prepareBaseTemplateContext();
|
|
347
|
+
context = Object.assign(context, outputConfig.context);
|
|
348
|
+
const templatePath = outputConfig.template;
|
|
349
|
+
const extension = path.extname(templatePath);
|
|
350
|
+
const syntax = outputConfig.syntax || "";
|
|
351
|
+
const template$1 = readTemplate(templatePath, syntax, extension);
|
|
352
|
+
const output = renderTemplate(template$1, context);
|
|
353
|
+
const dest = outputConfig.dest || o.dest;
|
|
354
|
+
let filepath;
|
|
355
|
+
let destParent;
|
|
356
|
+
let destName;
|
|
357
|
+
if (path.extname(dest) === "") {
|
|
358
|
+
destParent = dest;
|
|
359
|
+
destName = path.basename(outputConfig.template);
|
|
360
|
+
filepath = path.join(dest, destName);
|
|
361
|
+
} else {
|
|
362
|
+
destParent = path.dirname(dest);
|
|
363
|
+
filepath = dest;
|
|
364
|
+
}
|
|
365
|
+
fs.mkdirSync(destParent, { recursive: true });
|
|
366
|
+
fs.writeFileSync(filepath, output);
|
|
367
|
+
}
|
|
368
|
+
function generateCustomOutputs() {
|
|
369
|
+
if (!o.customOutputs || o.customOutputs.length < 1) return;
|
|
370
|
+
o.customOutputs.forEach(generateCustomOutput);
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* Generate HTML demo page
|
|
374
|
+
*/
|
|
375
|
+
async function generateDemoHtml() {
|
|
376
|
+
if (!o.htmlDemo) return;
|
|
377
|
+
const context = prepareHtmlTemplateContext();
|
|
378
|
+
const demoTemplate = readTemplate(o.htmlDemoTemplate, "demo", ".html");
|
|
379
|
+
const demo = renderTemplate(demoTemplate, context);
|
|
380
|
+
try {
|
|
381
|
+
await fs.promises.mkdir(getDemoPath(), { recursive: true });
|
|
382
|
+
} catch (err) {
|
|
383
|
+
if (err) {
|
|
384
|
+
logger.log.info(err);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
fs.writeFileSync(getDemoFilePath(), demo);
|
|
389
|
+
}
|
|
390
|
+
/**
|
|
391
|
+
* Print log
|
|
392
|
+
*/
|
|
393
|
+
function printDone() {
|
|
394
|
+
logger.log.info(`Font ${chalk.cyan(o.fontName)} with ${o.glyphs.length} glyphs created.`);
|
|
395
|
+
}
|
|
396
|
+
/**
|
|
397
|
+
* Helpers
|
|
398
|
+
*/
|
|
399
|
+
/**
|
|
400
|
+
* Convert a string of comma separated words into an array
|
|
401
|
+
*
|
|
402
|
+
* @param val Input string
|
|
403
|
+
* @param defVal Default value
|
|
404
|
+
*/
|
|
405
|
+
function optionToArray(val, defVal) {
|
|
406
|
+
if (val === void 0) val = defVal;
|
|
407
|
+
if (!val) return [];
|
|
408
|
+
if (typeof val !== "string") return val;
|
|
409
|
+
return val.split(",").map((value) => value.trim());
|
|
410
|
+
}
|
|
411
|
+
/**
|
|
412
|
+
* Check if a value exists in an array
|
|
413
|
+
*
|
|
414
|
+
* @param haystack Array to find the needle in
|
|
415
|
+
* @param needle Value to find
|
|
416
|
+
* @return Needle was found
|
|
417
|
+
*/
|
|
418
|
+
function has(haystack, needle) {
|
|
419
|
+
return haystack.indexOf(needle) !== -1;
|
|
420
|
+
}
|
|
421
|
+
/**
|
|
422
|
+
* Return a specified option if it exists in an object or `_default` otherwise
|
|
423
|
+
*
|
|
424
|
+
* @param map Options object
|
|
425
|
+
* @param key Option to find in the object
|
|
426
|
+
*/
|
|
427
|
+
function option(map, key) {
|
|
428
|
+
if (key in map) return map[key];
|
|
429
|
+
else return map._default;
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Find next unused codepoint.
|
|
433
|
+
*/
|
|
434
|
+
function getNextCodepoint() {
|
|
435
|
+
while (Object.values(o.codepoints).includes(currentCodepoint)) currentCodepoint++;
|
|
436
|
+
return currentCodepoint;
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Check whether file is SVG or not
|
|
440
|
+
*
|
|
441
|
+
* @param filepath File path
|
|
442
|
+
*/
|
|
443
|
+
function isSvgFile(filepath) {
|
|
444
|
+
return path.extname(filepath).toLowerCase() === ".svg";
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Convert font file to data:uri and remove source file
|
|
448
|
+
*
|
|
449
|
+
* @param fontFile Font file path
|
|
450
|
+
* @return Base64 encoded string
|
|
451
|
+
*/
|
|
452
|
+
function embedFont(fontFile) {
|
|
453
|
+
const dataUri = fs.readFileSync(fontFile, "base64");
|
|
454
|
+
const fontUrl = `data:application/x-font-${path.extname(fontFile).substring(1)};charset=utf-8;base64,${dataUri}`;
|
|
455
|
+
fs.unlinkSync(fontFile);
|
|
456
|
+
return fontUrl;
|
|
457
|
+
}
|
|
458
|
+
/**
|
|
459
|
+
* Append a slash to end of a filepath if it not exists and make all slashes forward
|
|
460
|
+
*
|
|
461
|
+
* @param filepath File path
|
|
462
|
+
*/
|
|
463
|
+
function normalizePath(filepath) {
|
|
464
|
+
if (!filepath.length) return filepath;
|
|
465
|
+
filepath = filepath.replace(/\\/g, "/");
|
|
466
|
+
if (!filepath.endsWith("/")) filepath += "/";
|
|
467
|
+
return filepath;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Generate URL for @font-face
|
|
471
|
+
*
|
|
472
|
+
* @param type Type of font
|
|
473
|
+
* @param font URL or Base64 string
|
|
474
|
+
* @param stylesheet type: css, scss, ...
|
|
475
|
+
*/
|
|
476
|
+
function generateFontSrc(type, font, stylesheet) {
|
|
477
|
+
const filename = template(`${o.fontFilename}${font.ext}`, o);
|
|
478
|
+
let fontPathVariableName = `${o.fontFamilyName}-font-path`;
|
|
479
|
+
let url;
|
|
480
|
+
if (font.embeddable && has(o.embed, type)) url = embedFont(path.join(o.dest, filename));
|
|
481
|
+
else {
|
|
482
|
+
if (o.fontPathVariables && stylesheet !== "css") {
|
|
483
|
+
if (stylesheet === "less") {
|
|
484
|
+
fontPathVariableName = `@${fontPathVariableName}`;
|
|
485
|
+
o.fontPathVariable = `${fontPathVariableName} : "${o.relativeFontPath}";`;
|
|
486
|
+
} else {
|
|
487
|
+
fontPathVariableName = `$${fontPathVariableName}`;
|
|
488
|
+
o.fontPathVariable = `${fontPathVariableName} : "${o.relativeFontPath}" !default;`;
|
|
489
|
+
}
|
|
490
|
+
url = filename;
|
|
491
|
+
} else url = `${o.relativeFontPath}${filename}`;
|
|
492
|
+
if (o.addHashes) if (url.indexOf("#iefix") === -1) url = url.replace(/(#|$)/, `?${o.hash}$1`);
|
|
493
|
+
else url = url.replace(/(#|$)/, `${o.hash}$1`);
|
|
494
|
+
}
|
|
495
|
+
let src = `url("${url}")`;
|
|
496
|
+
if (o.fontPathVariables && stylesheet !== "css") if (stylesheet === "less") src = `url("@{${fontPathVariableName.replace("@", "")}}${url}")`;
|
|
497
|
+
else src = `url(${fontPathVariableName} + "${url}")`;
|
|
498
|
+
if (font.format) src += ` format("${font.format}")`;
|
|
499
|
+
return src;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Read the template file
|
|
503
|
+
*
|
|
504
|
+
* @param template Template file path
|
|
505
|
+
* @param syntax Syntax (bem, bootstrap, etc.)
|
|
506
|
+
* @param ext Extension of the template
|
|
507
|
+
* @return \{filename: 'Template filename', template: 'Template code'}
|
|
508
|
+
*/
|
|
509
|
+
function readTemplate(template$1, syntax, ext, optional) {
|
|
510
|
+
const filename = template$1 ? path.resolve(template$1.replace(path.extname(template$1), ext)) : path.join(import.meta.dirname, `../templates/${syntax}${ext}`);
|
|
511
|
+
if (fs.existsSync(filename)) return {
|
|
512
|
+
filename,
|
|
513
|
+
template: fs.readFileSync(filename, "utf8")
|
|
514
|
+
};
|
|
515
|
+
else if (!optional) logger.fail.fatal(`Cannot find template at path: ${filename}`);
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* Render template with error reporting
|
|
519
|
+
*
|
|
520
|
+
* @param template {filename: 'Template filename', template: 'Template code'}
|
|
521
|
+
* @param context Template context
|
|
522
|
+
*/
|
|
523
|
+
function renderTemplate(template$1, context) {
|
|
524
|
+
try {
|
|
525
|
+
return _.template(template$1.template)(context);
|
|
526
|
+
} catch (e) {
|
|
527
|
+
logger.fail.fatal(`Error while rendering template ${template$1.filename}: ${e.message}`);
|
|
528
|
+
}
|
|
529
|
+
}
|
|
530
|
+
/**
|
|
531
|
+
* Basic template function: replaces {variables}
|
|
532
|
+
*
|
|
533
|
+
* @param tmpl Template code
|
|
534
|
+
* @param context Values object
|
|
535
|
+
*/
|
|
536
|
+
function template(tmpl, context) {
|
|
537
|
+
return tmpl.replace(/\{([^\}]+)\}/g, (m, key) => {
|
|
538
|
+
return context[key];
|
|
539
|
+
});
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Prepare string to use as CSS class name
|
|
543
|
+
*
|
|
544
|
+
* @param str
|
|
545
|
+
*/
|
|
546
|
+
function classnameize(str) {
|
|
547
|
+
return str.trim().replace(/\s+/g, "-");
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Return path of CSS file.
|
|
551
|
+
*
|
|
552
|
+
* @param stylesheet (css, scss, ...)
|
|
553
|
+
*/
|
|
554
|
+
function getCssFilePath(stylesheet) {
|
|
555
|
+
const cssFilePrefix = option(cssFilePrefixes, stylesheet);
|
|
556
|
+
return path.join(option(o.destCssPaths, stylesheet), `${cssFilePrefix}${o.fontBaseName}.${stylesheet}`);
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Return path of HTML demo file or `null` if its generation was disabled.
|
|
560
|
+
*/
|
|
561
|
+
function getDemoFilePath() {
|
|
562
|
+
if (!o.htmlDemo) return null;
|
|
563
|
+
const name$1 = o.htmlDemoFilename || o.fontBaseName;
|
|
564
|
+
return path.join(o.destHtml, `${name$1}.html`);
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Return path of HTML demo file or `null` if feature was disabled
|
|
568
|
+
*/
|
|
569
|
+
function getDemoPath() {
|
|
570
|
+
if (!o.htmlDemo) return null;
|
|
571
|
+
return o.destHtml;
|
|
572
|
+
}
|
|
573
|
+
/**
|
|
574
|
+
* Save hash to cache file.
|
|
575
|
+
*
|
|
576
|
+
* @param name Task name (webfont).
|
|
577
|
+
* @param target Task target name.
|
|
578
|
+
* @param hash Hash.
|
|
579
|
+
*/
|
|
580
|
+
function saveHash(name$1, target$1, hash) {
|
|
581
|
+
const filepath = getHashPath(name$1, target$1);
|
|
582
|
+
fs.mkdirSync(path.dirname(filepath), { recursive: true });
|
|
583
|
+
fs.writeFileSync(filepath, hash);
|
|
584
|
+
}
|
|
585
|
+
/**
|
|
586
|
+
* Read hash from cache file or `null` if file don’t exist.
|
|
587
|
+
*
|
|
588
|
+
* @param name Task name (webfont).
|
|
589
|
+
* @param target Task target name.
|
|
590
|
+
*/
|
|
591
|
+
function readHash(name$1, target$1) {
|
|
592
|
+
const filepath = getHashPath(name$1, target$1);
|
|
593
|
+
if (fs.existsSync(filepath)) return fs.readFileSync(filepath, "utf8");
|
|
594
|
+
return null;
|
|
595
|
+
}
|
|
596
|
+
/**
|
|
597
|
+
* Return path to cache file.
|
|
598
|
+
*
|
|
599
|
+
* @param name Task name (webfont).
|
|
600
|
+
* @param target Task target name.
|
|
601
|
+
*/
|
|
602
|
+
function getHashPath(name$1, target$1) {
|
|
603
|
+
return path.join(o.cache, name$1, target$1, "hash");
|
|
604
|
+
}
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
//#endregion
|
|
608
|
+
export { webfont_default as default, webfont };
|
|
609
|
+
//# sourceMappingURL=webfont.js.map
|